Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Bindings! #84

Open
wants to merge 35 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
dbdb5fc
Adding a bunch of Mac-side control bindings
liscio Jan 7, 2016
17387bc
Merge remote-tracking branch 'upstream/master'
liscio Jan 30, 2016
0cd6c70
Adding my work on control bindings
liscio Feb 2, 2016
ae9def8
Adding more NSControl extensions for Mac
liscio Feb 2, 2016
49257a6
Public most of the things!
liscio Feb 2, 2016
4317b1a
Forgot to include a source file
liscio Feb 2, 2016
20a7890
Missed another public var
liscio Feb 2, 2016
7f3012a
Fix compilation with latest RAC, Xcode 7.3
liscio Mar 23, 2016
2df4b4b
Swift 3 enablement.
andersio Jul 10, 2016
46f9e0d
Update the test cases.
andersio Jul 10, 2016
98364ee
Update CI config.
andersio Jul 10, 2016
9ebd18a
Rename a few more APIs.
andersio Jul 11, 2016
7d8958f
Mark a few APIs unavailable.
andersio Jul 11, 2016
356d839
Update `UIViewController`.
andersio Jul 11, 2016
830088f
Share `Data`'s implementation of `rex_data` with `NSData`.
andersio Jul 11, 2016
e164c88
Targets the `RAC5` branch of ReactiveCocoa.
andersio Jul 12, 2016
70e1455
Update dependencies.
andersio Jul 14, 2016
0cb7ad3
Update for the latest `RAC5` commit.
andersio Jul 14, 2016
8889b27
Update the resolved Cartfile.
andersio Jul 16, 2016
5f076e4
Update tvOS specific implementation.
andersio Jul 18, 2016
b04ec84
Updated for the latest RAC5 changes.
andersio Jul 22, 2016
15dca56
Partial support for Xcode8b4
Aug 5, 2016
c2404eb
Fix Build on Xcode8b4
Aug 5, 2016
b3a207e
Update ReactiveCocoa Dependency (damm branch fuckers)
Aug 8, 2016
012e519
fix remaining warning on Xcode8b4
Aug 9, 2016
bd373ea
Merge pull request #153 from sebastianvarela/RAC5-swift3
andersio Aug 23, 2016
ac1f1eb
Merge branch 'master' into RAC5-swift3
andersio Aug 23, 2016
ee70b74
Updated for the ReactiveSwift spin-off.
andersio Sep 12, 2016
42522ce
Fixed the failing `UIButton.rex_pressed` test.
andersio Sep 12, 2016
e95b087
Updated for Swift 3 GM.
andersio Sep 12, 2016
d035327
Merge remote-tracking branch 'upstream/RAC5-swift3'
liscio Sep 15, 2016
cdac8dd
Leverage existing BindingTarget, try an alternate validation approach
liscio Sep 15, 2016
648bfc2
Add bridgeable value support
liscio Sep 16, 2016
4a27fe5
Remove unnecessary TypedDynamicProperty, fix PropertyBinding
liscio Sep 16, 2016
bbfbdfc
Expose value typealias
liscio Sep 16, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
language: objective-c
matrix:
include:
- osx_image: xcode7.3
env: PLATFORM=Mac
- osx_image: xcode7.3
env: PLATFORM=iOS
- osx_image: xcode7.3
env: PLATFORM=tvOS
- osx_image: xcode7.3
env: PLATFORM=watchOS
- osx_image: xcode7.3
env: PLATFORM=CocoaPods
- osx_image: xcode8
env: PLATFORM=Mac TEST_ACTION="build-for-testing test-without-building"
- osx_image: xcode8
Expand Down
2 changes: 1 addition & 1 deletion Cartfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
github "ReactiveCocoa/ReactiveCocoa" ~> 4.2.2
github "ReactiveCocoa/ReactiveCocoa" "master"
5 changes: 3 additions & 2 deletions Cartfile.resolved
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
github "antitypical/Result" "2.1.3"
github "ReactiveCocoa/ReactiveCocoa" "v4.2.2"
github "antitypical/Result" "3.0.0"
github "ReactiveCocoa/ReactiveSwift" "d4de1ff81c12124d148f726b8b44dd6887b41ae0"
github "ReactiveCocoa/ReactiveCocoa" "e7443157ad1257e93c660586c41e1da710547676"
46 changes: 46 additions & 0 deletions Deprecations+Removals.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// MARK: Renamed APIs in Swift 3.0
import ReactiveSwift
import ReactiveCocoa
import enum Result.NoError

extension SignalProtocol {
@available(*, unavailable, renamed:"mute(for:clock:)")
public func muteFor(_ interval: TimeInterval, clock: DateSchedulerProtocol) -> Signal<Value, Error> { fatalError() }

@available(*, unavailable, renamed:"timeout(after:with:on:)")
public func timeoutAfter(_ interval: TimeInterval, withEvent event: Event<Value, Error>, onScheduler scheduler: DateSchedulerProtocol) -> Signal<Value, Error> { fatalError() }
}

extension SignalProducerProtocol {
@available(*, unavailable, renamed:"mute(for:clock:)")
public func muteFor(_ interval: TimeInterval, clock: DateSchedulerProtocol) -> SignalProducer<Value, Error> { fatalError() }

@available(*, unavailable, renamed:"timeout(after:with:on:)")
public func timeoutAfter(_ interval: TimeInterval, withEvent event: Event<Value, Error>, onScheduler scheduler: DateSchedulerProtocol) -> SignalProducer<Value, Error> { fatalError() }

@available(*, unavailable, renamed:"group(by:)")
public func groupBy<Key: Hashable>(_ grouping: (Value) -> Key) -> SignalProducer<(Key, SignalProducer<Value, Error>), Error> { fatalError() }

@available(*, unavailable, renamed:"defer(by:on:)")
public func deferred(_ interval: TimeInterval, onScheduler scheduler: DateSchedulerProtocol) -> SignalProducer<Value, Error> { fatalError() }
}

extension UserDefaults {
@available(*, unavailable, renamed:"rex_value(forKey:)")
public func rex_valueForKey(_ key: String) -> SignalProducer<AnyObject?, NoError> { fatalError() }
}

extension NSObject {
@available(*, unavailable, renamed:"rex_producer(forKeyPath:)")
public func rex_producerForKeyPath<T>(_ keyPath: String) -> SignalProducer<T, NoError> { fatalError() }
}

extension Data {
@available(*, unavailable, renamed:"rex_data(contentsOf:options:)")
public static func rex_dataWithContentsOfURL(_ url: URL, options: Data.ReadingOptions = []) -> SignalProducer<Data, NSError> { fatalError() }
}

extension Data {
@available(*, unavailable, renamed:"rex_data(contentsOf:options:)")
public static func rex_dataWithContentsOfURL(_ url: URL, options: NSData.ReadingOptions = []) -> SignalProducer<NSData, NSError> { fatalError() }
}
276 changes: 220 additions & 56 deletions Rex.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

18 changes: 9 additions & 9 deletions Rex.xcodeproj/xcshareddata/xcschemes/Rex-Mac.xcscheme
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand All @@ -16,7 +16,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "D8003E8D1AFEC3D400D7D3C5"
BuildableName = "Rex.framework"
BlueprintName = "Rex-Mac"
BlueprintName = "Rex-macOS"
ReferencedContainer = "container:Rex.xcodeproj">
</BuildableReference>
</BuildActionEntry>
Expand All @@ -29,8 +29,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D8003E981AFEC3D400D7D3C5"
BuildableName = "RexTests-Mac.xctest"
BlueprintName = "RexTests-Mac"
BuildableName = "RexTests-macOS.xctest"
BlueprintName = "RexTests-macOS"
ReferencedContainer = "container:Rex.xcodeproj">
</BuildableReference>
</BuildActionEntry>
Expand All @@ -47,8 +47,8 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D8003E981AFEC3D400D7D3C5"
BuildableName = "RexTests-Mac.xctest"
BlueprintName = "RexTests-Mac"
BuildableName = "RexTests-macOS.xctest"
BlueprintName = "RexTests-macOS"
ReferencedContainer = "container:Rex.xcodeproj">
</BuildableReference>
</TestableReference>
Expand All @@ -58,7 +58,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "D8003E8D1AFEC3D400D7D3C5"
BuildableName = "Rex.framework"
BlueprintName = "Rex-Mac"
BlueprintName = "Rex-macOS"
ReferencedContainer = "container:Rex.xcodeproj">
</BuildableReference>
</MacroExpansion>
Expand All @@ -80,7 +80,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "D8003E8D1AFEC3D400D7D3C5"
BuildableName = "Rex.framework"
BlueprintName = "Rex-Mac"
BlueprintName = "Rex-macOS"
ReferencedContainer = "container:Rex.xcodeproj">
</BuildableReference>
</MacroExpansion>
Expand All @@ -98,7 +98,7 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "D8003E8D1AFEC3D400D7D3C5"
BuildableName = "Rex.framework"
BlueprintName = "Rex-Mac"
BlueprintName = "Rex-macOS"
ReferencedContainer = "container:Rex.xcodeproj">
</BuildableReference>
</MacroExpansion>
Expand Down
2 changes: 1 addition & 1 deletion Rex.xcodeproj/xcshareddata/xcschemes/Rex-iOS.xcscheme
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
2 changes: 1 addition & 1 deletion Rex.xcodeproj/xcshareddata/xcschemes/Rex-tvOS.xcscheme
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0720"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
2 changes: 1 addition & 1 deletion Rex.xcodeproj/xcshareddata/xcschemes/Rex-watchOS.xcscheme
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0720"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
11 changes: 6 additions & 5 deletions Source/Action.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,27 @@
// Copyright (c) 2015 Neil Pankey. All rights reserved.
//

import ReactiveSwift
import ReactiveCocoa
import enum Result.NoError

extension Action {
/// Creates an always disabled action.
public static var rex_disabled: Action {
return Action(enabledIf: ConstantProperty(false)) { _ in .empty }
return Action(enabledIf: Property(value: false)) { _ in .empty }
}

/// Whether the action execution was started.
public var rex_started: Signal<Void, NoError> {
return self.executing.signal
return self.isExecuting.signal
.filterMap { $0 ? () : nil }
}

/// Whether the action execution was completed successfully.
public var rex_completed: Signal<Void, NoError> {
return events
.filterMap { event -> Void? in
if case .Completed = event {
if case .completed = event {
return ()
} else {
return nil
Expand All @@ -43,11 +44,11 @@ extension CocoaAction {

/// Creates a producer for the `enabled` state of a CocoaAction.
public var rex_enabledProducer: SignalProducer<Bool, NoError> {
return rex_producerForKeyPath("enabled")
return rex_producer(forKeyPath: #keyPath(CocoaAction.isEnabled))
}

/// Creates a producer for the `executing` state of a CocoaAction.
public var rex_executingProducer: SignalProducer<Bool, NoError> {
return rex_producerForKeyPath("executing")
return rex_producer(forKeyPath: #keyPath(CocoaAction.isExecuting))
}
}
28 changes: 28 additions & 0 deletions Source/AppKit/NSButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// NSButton+ReactiveExtensions.swift
// FuzzMeasure
//
// Created by Christopher Liscio on 2016-01-11.
// Copyright © 2016 SuperMegaUltraGroovy, Inc. All rights reserved.
//

import Foundation
import ReactiveSwift
import ReactiveCocoa
import Result

extension NSButton {
public var rex_stateAction: Action<NSButton, Int, NoError> {
return associatedObject(self, key: &stateActionKey) { _ in Action<NSButton, Int, NoError> { SignalProducer(value: $0.state) } }
}

public var rex_states: Signal<Int, NoError> {
let cocoaAction = associatedObject(self, key: &stateCocoaActionKey) { CocoaAction($0.rex_stateAction) { $0 as! NSButton } }
rex_action.value = cocoaAction

return rex_stateAction.values
}
}

private var stateActionKey: UInt8 = 0
private var stateCocoaActionKey: UInt8 = 0
54 changes: 54 additions & 0 deletions Source/AppKit/NSControl.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// NSControl.swift
// Rex
//
// Created by Christopher Liscio on 1/7/16.
// Copyright © 2016 Neil Pankey. All rights reserved.
//

import Foundation
import AppKit
import ReactiveSwift
import ReactiveCocoa
import Result

extension NSControl {
/// Exposes a property that binds an action to the control's target/action. The action
/// is set as a target of the control's events. For instance, an NSButton would trigger
/// its action when pressed, a NSSlider would trigger its action when the value
/// changes, a NSTextField triggers when its value changes, and so on. When property
/// changes occur the previous action is overwritten as a target. This also binds the
/// enabled state of the action to the `rex_enabled` property on the button.
public var rex_action: MutableProperty<CocoaAction> {
return associatedObject(self, key: &actionKey, initial: { [weak self] _ in
let initial = CocoaAction.rex_disabled
let property = MutableProperty(initial)

property.producer
.startWithNext { next in
self?.target = next
self?.action = CocoaAction.selector
}

if let strongSelf = self {
strongSelf.rex_enabled <~ property.producer.flatMap(.latest) { $0.rex_enabledProducer }
}

return property
})
}

/// Wraps a control's `enabled` state in a bindable property.
public var rex_enabled: MutableProperty<Bool> {
return associatedProperty(self, key: &enabledKey, initial: { $0.isEnabled }, setter: { $0.isEnabled = $1 })
}

/// Wraps a control's alpha value in a bindable property.
public var rex_alphaValue: MutableProperty<CGFloat> {
return associatedProperty(self, key: &alphaValueKey, initial: { $0.alphaValue }, setter: { $0.alphaValue = $1 })
}
}

private var enabledKey: UInt8 = 0
private var alphaValueKey: UInt8 = 0
private var actionKey: UInt8 = 0
63 changes: 63 additions & 0 deletions Source/AppKit/NSPopUpButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// NSPopUpButton.swift
// Rex
//
// Created by Christopher Liscio on 1/7/16.
// Copyright © 2016 Neil Pankey. All rights reserved.
//

import Foundation
import AppKit
import ReactiveSwift
import ReactiveCocoa
import Result

extension NSPopUpButton {
public var rex_indexOfSelectedItem: MutableProperty<Int> {
return associatedProperty(self, key: &indexOfSelectedItemKey, initial: { $0.indexOfSelectedItem }, setter: { $0.selectItem(at: $1) } )
}

public var rex_title: MutableProperty<String> {
return associatedProperty(self, key: &titleKey, initial: { $0.title }, setter: { $0.setTitle($1) })
}

public var rex_attributedTitle: MutableProperty<NSAttributedString> {
return associatedProperty(self, key: &attributedTitleKey,
initial: { $0.attributedTitle },
setter: {
let menuItem = NSMenuItem(title: $1.string, action: nil, keyEquivalent: "")
menuItem.attributedTitle = $1
($0.cell as? NSPopUpButtonCell)?.menuItem = menuItem
})
}

public var rex_selectedIndexAction: Action<NSPopUpButton, Int, NoError> {
return associatedObject(self, key: &selectedIndexActionKey) { _ in Action<NSPopUpButton, Int, NoError> { SignalProducer(value: $0.indexOfSelectedItem) } }
}

public var rex_selectedIndexes: Signal<Int, NoError> {
let cocoaAction = associatedObject(self, key: &selectedIndexKey) { CocoaAction($0.rex_selectedIndexAction) { $0 as! NSPopUpButton } }
rex_action.value = cocoaAction

return rex_selectedIndexAction.values
}

public var rex_selectedTagAction: Action<NSPopUpButton, Int, NoError> {
return associatedObject(self, key: &selectedTagActionKey) { _ in Action<NSPopUpButton, Int, NoError> { SignalProducer(value: $0.selectedTag()) } }
}

public var rex_selectedTags: Signal<Int, NoError> {
let cocoaAction = associatedObject(self, key: &selectedTagKey) { CocoaAction($0.rex_selectedTagAction) { $0 as! NSPopUpButton } }
rex_action.value = cocoaAction

return rex_selectedTagAction.values
}
}

private var indexOfSelectedItemKey: UInt8 = 0
private var titleKey: UInt8 = 0
private var attributedTitleKey: UInt8 = 0
private var selectedIndexKey: UInt8 = 0
private var selectedIndexActionKey: UInt8 = 0
private var selectedTagKey: UInt8 = 0
private var selectedTagActionKey: UInt8 = 0
28 changes: 28 additions & 0 deletions Source/AppKit/NSSlider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// NSSlider+ReactiveExtensions.swift
// FuzzMeasure
//
// Created by Christopher Liscio on 1/6/16.
// Copyright © 2016 SuperMegaUltraGroovy, Inc. All rights reserved.
//

import Foundation
import ReactiveSwift
import ReactiveCocoa
import Result

extension NSSlider {
public var rex_doubleValueAction: Action<NSSlider, Double, NoError> {
return associatedObject(self, key: &doubleValueActionKey) { _ in Action<NSSlider, Double, NoError> { SignalProducer(value: $0.doubleValue) } }
}

public var rex_doubleValues: Signal<Double, NoError> {
let cocoaAction = associatedObject(self, key: &doubleValueCocoaActionKey) { CocoaAction($0.rex_doubleValueAction) { $0 as! NSSlider } }
rex_action.value = cocoaAction

return rex_doubleValueAction.values
}
}

private var doubleValueActionKey: UInt8 = 0
private var doubleValueCocoaActionKey: UInt8 = 0
Loading