Adds `UIBindingObserver`.
This commit is contained in:
parent
e0555a05a5
commit
2aebe1499f
|
|
@ -912,6 +912,10 @@
|
|||
C8FA89201C30424000CD3A17 /* VirtualTimeConverterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8FA89121C30405400CD3A17 /* VirtualTimeConverterType.swift */; };
|
||||
C8FA89211C30424000CD3A17 /* VirtualTimeConverterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8FA89121C30405400CD3A17 /* VirtualTimeConverterType.swift */; };
|
||||
C8FA89221C30424100CD3A17 /* VirtualTimeConverterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8FA89121C30405400CD3A17 /* VirtualTimeConverterType.swift */; };
|
||||
C8FD21AE1C67E14C00863EC3 /* UIBindingObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8FD21AD1C67E14C00863EC3 /* UIBindingObserver.swift */; };
|
||||
C8FD21AF1C67E14C00863EC3 /* UIBindingObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8FD21AD1C67E14C00863EC3 /* UIBindingObserver.swift */; };
|
||||
C8FD21B01C67E14C00863EC3 /* UIBindingObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8FD21AD1C67E14C00863EC3 /* UIBindingObserver.swift */; };
|
||||
C8FD21B11C67E14C00863EC3 /* UIBindingObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8FD21AD1C67E14C00863EC3 /* UIBindingObserver.swift */; };
|
||||
CB255BD71BC46A9C00798A4C /* RetryWhen.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB255BD61BC46A9C00798A4C /* RetryWhen.swift */; };
|
||||
CB255BD81BC46A9C00798A4C /* RetryWhen.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB255BD61BC46A9C00798A4C /* RetryWhen.swift */; };
|
||||
CB255BD91BC46A9C00798A4C /* RetryWhen.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB255BD61BC46A9C00798A4C /* RetryWhen.swift */; };
|
||||
|
|
@ -1639,6 +1643,7 @@
|
|||
C8FA89131C30405400CD3A17 /* VirtualTimeScheduler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VirtualTimeScheduler.swift; sourceTree = "<group>"; };
|
||||
C8FA89161C30409900CD3A17 /* HistoricalScheduler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoricalScheduler.swift; sourceTree = "<group>"; };
|
||||
C8FA891B1C30412A00CD3A17 /* HistoricalSchedulerTimeConverter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoricalSchedulerTimeConverter.swift; sourceTree = "<group>"; };
|
||||
C8FD21AD1C67E14C00863EC3 /* UIBindingObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIBindingObserver.swift; sourceTree = "<group>"; };
|
||||
CB255BD61BC46A9C00798A4C /* RetryWhen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RetryWhen.swift; sourceTree = "<group>"; };
|
||||
CB30D9E81BF0E3500084C1C0 /* SingleAsync.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleAsync.swift; sourceTree = "<group>"; };
|
||||
CB883B3A1BE24355000AC2EE /* Window.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Window.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -2119,6 +2124,7 @@
|
|||
C80DDE8C1BCE69BA006A1832 /* Driver */,
|
||||
C80D33931B922FB00014629D /* ControlEvent.swift */,
|
||||
C80D33941B922FB00014629D /* ControlProperty.swift */,
|
||||
C8FD21AD1C67E14C00863EC3 /* UIBindingObserver.swift */,
|
||||
);
|
||||
path = CocoaUnits;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -3273,6 +3279,7 @@
|
|||
C88254301B8A752B00B02D69 /* UISearchBar+Rx.swift in Sources */,
|
||||
C88254181B8A752B00B02D69 /* ItemEvents.swift in Sources */,
|
||||
C8DB96881BF756F40084BD53 /* KVORepresentable+CoreGraphics.swift in Sources */,
|
||||
C8FD21AE1C67E14C00863EC3 /* UIBindingObserver.swift in Sources */,
|
||||
C882541B1B8A752B00B02D69 /* RxTableViewDataSourceType.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
@ -3291,6 +3298,7 @@
|
|||
C8DB967F1BF7496C0084BD53 /* KVORepresentable.swift in Sources */,
|
||||
C8093EFE1B8A732E0088E94D /* RxTarget.swift in Sources */,
|
||||
C8093ED21B8A732E0088E94D /* _RX.m in Sources */,
|
||||
C8FD21AF1C67E14C00863EC3 /* UIBindingObserver.swift in Sources */,
|
||||
C8093EFC1B8A732E0088E94D /* RxCocoa.swift in Sources */,
|
||||
C8DB968E1BF7595D0084BD53 /* KVORepresentable+Swift.swift in Sources */,
|
||||
C80D33991B922FB00014629D /* ControlEvent.swift in Sources */,
|
||||
|
|
@ -4162,6 +4170,7 @@
|
|||
C8F0C03B1BBBFBB9001B112F /* UISearchBar+Rx.swift in Sources */,
|
||||
C8F0C03C1BBBFBB9001B112F /* ItemEvents.swift in Sources */,
|
||||
C8DB968B1BF756F40084BD53 /* KVORepresentable+CoreGraphics.swift in Sources */,
|
||||
C8FD21B11C67E14C00863EC3 /* UIBindingObserver.swift in Sources */,
|
||||
C8F0C03D1BBBFBB9001B112F /* RxTableViewDataSourceType.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
@ -4253,6 +4262,7 @@
|
|||
D203C4FD1BB9C53700D02D00 /* RxSearchBarDelegateProxy.swift in Sources */,
|
||||
D2138C8A1BB9BEBE00339B5C /* Logging.swift in Sources */,
|
||||
C8DB968A1BF756F40084BD53 /* KVORepresentable+CoreGraphics.swift in Sources */,
|
||||
C8FD21B01C67E14C00863EC3 /* UIBindingObserver.swift in Sources */,
|
||||
D203C50F1BB9C53E00D02D00 /* UIStepper+Rx.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// UIBindingObserver.swift
|
||||
// Rx
|
||||
//
|
||||
// Created by Krunoslav Zaher on 2/7/16.
|
||||
// Copyright © 2016 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
#if !RX_NO_MODULE
|
||||
import RxSwift
|
||||
#endif
|
||||
|
||||
/**
|
||||
Observer that enforces interface binding rules:
|
||||
* can't bind errors (in debug builds binding of errors causes `fatalError` in release builds errors are being logged)
|
||||
* ensures binding is performed on main thread
|
||||
|
||||
`InterfaceBindingObserver` doesn't retain target interface and in case owned interface element is released, element isn't bound.
|
||||
*/
|
||||
public class UIBindingObserver<UIElementType, Value where UIElementType: AnyObject> : ObserverType {
|
||||
public typealias E = Value
|
||||
|
||||
weak var UIElement: UIElementType?
|
||||
|
||||
let binding: (UIElementType, Value) -> Void
|
||||
|
||||
/**
|
||||
Initializes `ViewBindingObserver` using
|
||||
*/
|
||||
public init(UIElement: UIElementType, binding: (UIElementType, Value) -> Void) {
|
||||
self.UIElement = UIElement
|
||||
self.binding = binding
|
||||
}
|
||||
|
||||
/**
|
||||
Binds next element to owner view as described in `binding`.
|
||||
*/
|
||||
public func on(event: Event<Value>) {
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch event {
|
||||
case .Next(let element):
|
||||
if let view = self.UIElement {
|
||||
binding(view, element)
|
||||
}
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Erases type of observer.
|
||||
|
||||
- returns: type erased observer.
|
||||
*/
|
||||
public func asObserver() -> AnyObserver<Value> {
|
||||
return AnyObserver(eventHandler: on)
|
||||
}
|
||||
}
|
||||
|
|
@ -223,7 +223,7 @@ extension ObservableType {
|
|||
-> Disposable {
|
||||
let proxy = proxyForObject(P.self, object)
|
||||
let disposable = installDelegate(proxy, delegate: dataSource, retainDelegate: retainDataSource, onProxyForObject: object)
|
||||
|
||||
|
||||
let subscription = self.asObservable()
|
||||
// source can't ever end, otherwise it will release the subscriber
|
||||
.concat(Observable.never())
|
||||
|
|
|
|||
|
|
@ -25,10 +25,13 @@ extension NSButton {
|
|||
Reactive wrapper for `state` property`.
|
||||
*/
|
||||
public var rx_state: ControlProperty<Int> {
|
||||
return rx_value(getter: { [weak self] in
|
||||
return self?.state ?? 0
|
||||
}, setter: { [weak self] state in
|
||||
self?.state = state
|
||||
})
|
||||
return NSButton.rx_value(
|
||||
self,
|
||||
getter: { control in
|
||||
return control.state
|
||||
}, setter: { control, state in
|
||||
control.state = state
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -43,57 +43,41 @@ extension NSControl {
|
|||
return ControlEvent(events: source)
|
||||
}
|
||||
|
||||
func rx_value<T: Equatable>(getter getter: () -> T, setter: T -> Void) -> ControlProperty<T> {
|
||||
static func rx_value<C: NSControl, T: Equatable>(control: C, getter: (C) -> T, setter: (C, T) -> Void) -> ControlProperty<T> {
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
let source = rx_lazyInstanceObservable(&rx_value_key) { () -> Observable<T> in
|
||||
return Observable.create { [weak self] observer in
|
||||
guard let control = self else {
|
||||
let source = control.rx_lazyInstanceObservable(&rx_value_key) { () -> Observable<T> in
|
||||
return Observable.create { [weak weakControl = control] (observer: AnyObserver<T>) in
|
||||
guard let control = weakControl else {
|
||||
observer.on(.Completed)
|
||||
return NopDisposable.instance
|
||||
}
|
||||
|
||||
observer.on(.Next(getter()))
|
||||
observer.on(.Next(getter(control)))
|
||||
|
||||
let observer = ControlTarget(control: control) { control in
|
||||
observer.on(.Next(getter()))
|
||||
let observer = ControlTarget(control: control) { _ in
|
||||
if let control = weakControl {
|
||||
observer.on(.Next(getter(control)))
|
||||
}
|
||||
}
|
||||
|
||||
return observer
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.takeUntil(self.rx_deallocated)
|
||||
.distinctUntilChanged()
|
||||
.takeUntil(control.rx_deallocated)
|
||||
}
|
||||
|
||||
let bindingObserver = UIBindingObserver(UIElement: control, binding: setter)
|
||||
|
||||
return ControlProperty(values: source, valueSink: AnyObserver { event in
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
setter(value)
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
})
|
||||
return ControlProperty(values: source, valueSink: bindingObserver)
|
||||
}
|
||||
|
||||
/**
|
||||
Bindable sink for `enabled` property.
|
||||
*/
|
||||
public var rx_enabled: AnyObserver<Bool> {
|
||||
return AnyObserver { [weak self] event in
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
self?.enabled = value
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
}
|
||||
return UIBindingObserver(UIElement: self) { (owner, value) in
|
||||
owner.enabled = value
|
||||
}.asObserver()
|
||||
}
|
||||
}
|
||||
|
|
@ -27,31 +27,21 @@ extension NSImageView {
|
|||
- parameter transitionType: Optional transition type while setting the image (kCATransitionFade, kCATransitionMoveIn, ...)
|
||||
*/
|
||||
public func rx_imageAnimated(transitionType: String?) -> AnyObserver<NSImage?> {
|
||||
return AnyObserver { [weak self] event in
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
if let transitionType = transitionType {
|
||||
if value != nil {
|
||||
let transition = CATransition()
|
||||
transition.duration = 0.25
|
||||
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
|
||||
transition.type = transitionType
|
||||
self?.layer?.addAnimation(transition, forKey: kCATransition)
|
||||
}
|
||||
return UIBindingObserver(UIElement: self) { control, value in
|
||||
if let transitionType = transitionType {
|
||||
if value != nil {
|
||||
let transition = CATransition()
|
||||
transition.duration = 0.25
|
||||
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
|
||||
transition.type = transitionType
|
||||
control.layer?.addAnimation(transition, forKey: kCATransition)
|
||||
}
|
||||
else {
|
||||
self?.layer?.removeAllAnimations()
|
||||
}
|
||||
self?.image = value
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
}
|
||||
else {
|
||||
control.layer?.removeAllAnimations()
|
||||
}
|
||||
control.image = value
|
||||
}.asObserver()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,11 +18,15 @@ extension NSSlider {
|
|||
Reactive wrapper for `value` property.
|
||||
*/
|
||||
public var rx_value: ControlProperty<Double> {
|
||||
return rx_value(getter: { [weak self] in
|
||||
return self?.doubleValue ?? 0
|
||||
}, setter: { [weak self] value in
|
||||
self?.doubleValue = value
|
||||
})
|
||||
return NSControl.rx_value(
|
||||
self,
|
||||
getter: { control in
|
||||
return control.doubleValue
|
||||
},
|
||||
setter: { control, value in
|
||||
control.doubleValue = value
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -105,20 +105,12 @@ extension NSTextField {
|
|||
let source = Observable.deferred { [weak self] in
|
||||
delegate.textSubject.startWith(self?.stringValue ?? "")
|
||||
}.takeUntil(rx_deallocated)
|
||||
|
||||
return ControlProperty(values: source, valueSink: AnyObserver { [weak self] event in
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
self?.stringValue = value
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
let observer = UIBindingObserver(UIElement: self) { control, value in
|
||||
control.stringValue = value
|
||||
}
|
||||
|
||||
return ControlProperty(values: source, valueSink: observer.asObserver())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,37 +17,17 @@ extension NSView {
|
|||
Bindable sink for `hidden` property.
|
||||
*/
|
||||
public var rx_hidden: AnyObserver<Bool> {
|
||||
return AnyObserver { [weak self] event in
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
self?.hidden = value
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
}
|
||||
return UIBindingObserver(UIElement: self) { view, value in
|
||||
view.hidden = value
|
||||
}.asObserver()
|
||||
}
|
||||
|
||||
/**
|
||||
Bindable sink for `alphaValue` property.
|
||||
*/
|
||||
public var rx_alpha: AnyObserver<CGFloat> {
|
||||
return AnyObserver { [weak self] event in
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
self?.alphaValue = value
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
}
|
||||
return UIBindingObserver(UIElement: self) { view, value in
|
||||
view.alphaValue = value
|
||||
}.asObserver()
|
||||
}
|
||||
}
|
||||
|
|
@ -19,22 +19,13 @@ extension UIActivityIndicatorView {
|
|||
Bindable sink for `startAnimating()`, `stopAnimating()` methods.
|
||||
*/
|
||||
public var rx_animating: AnyObserver<Bool> {
|
||||
return AnyObserver {event in
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch (event) {
|
||||
case .Next(let value):
|
||||
if value {
|
||||
self.startAnimating()
|
||||
} else {
|
||||
self.stopAnimating()
|
||||
}
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
case .Completed:
|
||||
break
|
||||
return UIBindingObserver(UIElement: self) { activityIndicator, active in
|
||||
if active {
|
||||
self.startAnimating()
|
||||
} else {
|
||||
self.stopAnimating()
|
||||
}
|
||||
}
|
||||
}.asObserver()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,19 +21,9 @@ extension UIBarButtonItem {
|
|||
Bindable sink for `enabled` property.
|
||||
*/
|
||||
public var rx_enabled: AnyObserver<Bool> {
|
||||
return AnyObserver { [weak self] event in
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
self?.enabled = value
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
}
|
||||
return UIBindingObserver(UIElement: self) { UIElement, value in
|
||||
UIElement.enabled = value
|
||||
}.asObserver()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -20,19 +20,9 @@ extension UIControl {
|
|||
Bindable sink for `enabled` property.
|
||||
*/
|
||||
public var rx_enabled: AnyObserver<Bool> {
|
||||
return AnyObserver { [weak self] event in
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
self?.enabled = value
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
}
|
||||
return UIBindingObserver(UIElement: self) { control, value in
|
||||
control.enabled = value
|
||||
}.asObserver()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -62,39 +52,31 @@ extension UIControl {
|
|||
return ControlEvent(events: source)
|
||||
}
|
||||
|
||||
func rx_value<T: Equatable>(getter getter: () -> T, setter: T -> Void) -> ControlProperty<T> {
|
||||
let source: Observable<T> = Observable.create { [weak self] observer in
|
||||
guard let control = self else {
|
||||
observer.on(.Completed)
|
||||
return NopDisposable.instance
|
||||
}
|
||||
static func rx_value<C: UIControl, T: Equatable>(control: C, getter: (C) -> T, setter: (C, T) -> Void) -> ControlProperty<T> {
|
||||
let source: Observable<T> = Observable.create { [weak weakControl = control] observer in
|
||||
guard let control = weakControl else {
|
||||
observer.on(.Completed)
|
||||
return NopDisposable.instance
|
||||
}
|
||||
|
||||
observer.on(.Next(getter()))
|
||||
observer.on(.Next(getter(control)))
|
||||
|
||||
let controlTarget = ControlTarget(control: control, controlEvents: [.AllEditingEvents, .ValueChanged]) { control in
|
||||
observer.on(.Next(getter()))
|
||||
let controlTarget = ControlTarget(control: control, controlEvents: [.AllEditingEvents, .ValueChanged]) { _ in
|
||||
if let control = weakControl {
|
||||
observer.on(.Next(getter(control)))
|
||||
}
|
||||
}
|
||||
|
||||
return AnonymousDisposable {
|
||||
controlTarget.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
return AnonymousDisposable {
|
||||
controlTarget.dispose()
|
||||
}
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.takeUntil(rx_deallocated)
|
||||
|
||||
return ControlProperty<T>(values: source, valueSink: AnyObserver { event in
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
.takeUntil(control.rx_deallocated)
|
||||
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
setter(value)
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
})
|
||||
let bindingObserver = UIBindingObserver(UIElement: control, binding: setter)
|
||||
|
||||
return ControlProperty<T>(values: source, valueSink: bindingObserver)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,11 +20,14 @@ extension UIDatePicker {
|
|||
Reactive wrapper for `date` property.
|
||||
*/
|
||||
public var rx_date: ControlProperty<NSDate> {
|
||||
return rx_value(getter: { [weak self] in
|
||||
self?.date ?? NSDate()
|
||||
}, setter: { [weak self] value in
|
||||
self?.date = value
|
||||
})
|
||||
return UIControl.rx_value(
|
||||
self,
|
||||
getter: { datePicker in
|
||||
datePicker.date
|
||||
}, setter: { datePicker, value in
|
||||
datePicker.date = value
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,31 +29,21 @@ extension UIImageView {
|
|||
- parameter transitionType: Optional transition type while setting the image (kCATransitionFade, kCATransitionMoveIn, ...)
|
||||
*/
|
||||
public func rx_imageAnimated(transitionType: String?) -> AnyObserver<UIImage?> {
|
||||
return AnyObserver { [weak self] event in
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
if let transitionType = transitionType {
|
||||
if value != nil {
|
||||
let transition = CATransition()
|
||||
transition.duration = 0.25
|
||||
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
|
||||
transition.type = transitionType
|
||||
self?.layer.addAnimation(transition, forKey: kCATransition)
|
||||
}
|
||||
return UIBindingObserver(UIElement: self) { imageView, image in
|
||||
if let transitionType = transitionType {
|
||||
if image != nil {
|
||||
let transition = CATransition()
|
||||
transition.duration = 0.25
|
||||
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
|
||||
transition.type = transitionType
|
||||
imageView.layer.addAnimation(transition, forKey: kCATransition)
|
||||
}
|
||||
else {
|
||||
self?.layer.removeAllAnimations()
|
||||
}
|
||||
self?.image = value
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
}
|
||||
else {
|
||||
imageView.layer.removeAllAnimations()
|
||||
}
|
||||
imageView.image = image
|
||||
}.asObserver()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,38 +20,18 @@ extension UILabel {
|
|||
Bindable sink for `text` property.
|
||||
*/
|
||||
public var rx_text: AnyObserver<String> {
|
||||
return AnyObserver { [weak self] event in
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
self?.text = value
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
}
|
||||
return UIBindingObserver(UIElement: self) { label, text in
|
||||
label.text = text
|
||||
}.asObserver()
|
||||
}
|
||||
|
||||
/**
|
||||
Bindable sink for `attributedText` property.
|
||||
*/
|
||||
public var rx_attributedText: AnyObserver<NSAttributedString?> {
|
||||
return AnyObserver { [weak self] event in
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
self?.attributedText = value
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
}
|
||||
return UIBindingObserver(UIElement: self) { label, text in
|
||||
label.attributedText = text
|
||||
}.asObserver()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,23 +19,13 @@ extension UIRefreshControl {
|
|||
Bindable sink for `beginRefreshing()`, `endRefreshing()` methods.
|
||||
*/
|
||||
public var rx_refreshing: AnyObserver<Bool> {
|
||||
return AnyObserver {event in
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch (event) {
|
||||
case .Next(let value):
|
||||
if value {
|
||||
self.beginRefreshing()
|
||||
} else {
|
||||
self.endRefreshing()
|
||||
}
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
return UIBindingObserver(UIElement: self) { refreshControl, refresh in
|
||||
if refresh {
|
||||
self.beginRefreshing()
|
||||
} else {
|
||||
self.endRefreshing()
|
||||
}
|
||||
}
|
||||
}.asObserver()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,17 +39,12 @@ extension UIScrollView {
|
|||
*/
|
||||
public var rx_contentOffset: ControlProperty<CGPoint> {
|
||||
let proxy = proxyForObject(RxScrollViewDelegateProxy.self, self)
|
||||
|
||||
return ControlProperty(values: proxy.contentOffsetSubject, valueSink: AnyObserver { [weak self] event in
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
self?.contentOffset = value
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
let bindingObserver = UIBindingObserver(UIElement: self) { scrollView, contentOffset in
|
||||
scrollView.contentOffset = contentOffset
|
||||
}
|
||||
|
||||
return ControlProperty(values: proxy.contentOffsetSubject, valueSink: bindingObserver)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -40,17 +40,12 @@ extension UISearchBar {
|
|||
}
|
||||
.startWith(text)
|
||||
}
|
||||
|
||||
let bindingObserver = UIBindingObserver(UIElement: self) { (searchBar, text: String) in
|
||||
searchBar.text = text
|
||||
}
|
||||
|
||||
return ControlProperty(values: source, valueSink: AnyObserver { [weak self] event in
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
self?.text = value
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
})
|
||||
return ControlProperty(values: source, valueSink: bindingObserver)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,11 +20,14 @@ extension UISegmentedControl {
|
|||
Reactive wrapper for `selectedSegmentIndex` property.
|
||||
*/
|
||||
public var rx_value: ControlProperty<Int> {
|
||||
return rx_value(getter: { [weak self] in
|
||||
self?.selectedSegmentIndex ?? 0
|
||||
}, setter: { [weak self] value in
|
||||
self?.selectedSegmentIndex = value
|
||||
})
|
||||
return UIControl.rx_value(
|
||||
self,
|
||||
getter: { segmentedControl in
|
||||
segmentedControl.selectedSegmentIndex
|
||||
}, setter: { segmentedControl, value in
|
||||
segmentedControl.selectedSegmentIndex = value
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,11 +20,14 @@ extension UISlider {
|
|||
Reactive wrapper for `value` property.
|
||||
*/
|
||||
public var rx_value: ControlProperty<Float> {
|
||||
return rx_value(getter: { [weak self] in
|
||||
self?.value ?? 0.0
|
||||
}, setter: { [weak self] value in
|
||||
self?.value = value
|
||||
})
|
||||
return UIControl.rx_value(
|
||||
self,
|
||||
getter: { slider in
|
||||
slider.value
|
||||
}, setter: { slider, value in
|
||||
slider.value = value
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,11 +20,14 @@ extension UIStepper {
|
|||
Reactive wrapper for `value` property.
|
||||
*/
|
||||
public var rx_value: ControlProperty<Double> {
|
||||
return rx_value(getter: { [weak self] in
|
||||
self?.value ?? 0
|
||||
}, setter: { [weak self] value in
|
||||
self?.value = value
|
||||
})
|
||||
return UIControl.rx_value(
|
||||
self,
|
||||
getter: { stepper in
|
||||
stepper.value
|
||||
}, setter: { stepper, value in
|
||||
stepper.value = value
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,11 +20,14 @@ extension UISwitch {
|
|||
Reactive wrapper for `on` property.
|
||||
*/
|
||||
public var rx_value: ControlProperty<Bool> {
|
||||
return rx_value(getter: { [weak self] in
|
||||
self?.on ?? false
|
||||
}, setter: { [weak self] value in
|
||||
self?.on = value
|
||||
})
|
||||
return UIControl.rx_value(
|
||||
self,
|
||||
getter: { uiSwitch in
|
||||
uiSwitch.on
|
||||
}, setter: { uiSwitch, value in
|
||||
uiSwitch.on = value
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,11 +20,14 @@ extension UITextField {
|
|||
Reactive wrapper for `text` property.
|
||||
*/
|
||||
public var rx_text: ControlProperty<String> {
|
||||
return rx_value(getter: { [weak self] in
|
||||
self?.text ?? ""
|
||||
}, setter: { [weak self] value in
|
||||
self?.text = value
|
||||
})
|
||||
return UIControl.rx_value(
|
||||
self,
|
||||
getter: { textField in
|
||||
textField.text ?? ""
|
||||
}, setter: { textField, value in
|
||||
textField.text = value
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,17 +45,12 @@ extension UITextView {
|
|||
.startWith(text)
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
let bindingObserver = UIBindingObserver(UIElement: self) { (textView, text: String) in
|
||||
textView.text = text
|
||||
}
|
||||
|
||||
return ControlProperty(values: source, valueSink: AnyObserver { [weak self] event in
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
self?.text = value
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
})
|
||||
return ControlProperty(values: source, valueSink: bindingObserver)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,38 +19,18 @@ extension UIView {
|
|||
Bindable sink for `hidden` property.
|
||||
*/
|
||||
public var rx_hidden: AnyObserver<Bool> {
|
||||
return AnyObserver { [weak self] event in
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
self?.hidden = value
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
}
|
||||
return UIBindingObserver(UIElement: self) { view, hidden in
|
||||
view.hidden = hidden
|
||||
}.asObserver()
|
||||
}
|
||||
|
||||
/**
|
||||
Bindable sink for `alpha` property.
|
||||
*/
|
||||
public var rx_alpha: AnyObserver<CGFloat> {
|
||||
return AnyObserver { [weak self] event in
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch event {
|
||||
case .Next(let value):
|
||||
self?.alpha = value
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
}
|
||||
}
|
||||
return UIBindingObserver(UIElement: self) { view, alpha in
|
||||
view.alpha = alpha
|
||||
}.asObserver()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,22 +20,15 @@ struct Colors {
|
|||
|
||||
extension UINavigationController {
|
||||
var rx_serviceState: AnyObserver<ServiceState?> {
|
||||
return AnyObserver { event in
|
||||
switch event {
|
||||
case .Next(let maybeServiceState):
|
||||
// if nil is being bound, then don't change color, it's not perfect, but :)
|
||||
if let serviceState = maybeServiceState {
|
||||
let isOffline = serviceState ?? .Online == .Offline
|
||||
return UIBindingObserver(owner: self) { navigationController, maybeServiceState in
|
||||
// if nil is being bound, then don't change color, it's not perfect, but :)
|
||||
if let serviceState = maybeServiceState {
|
||||
let isOffline = serviceState ?? .Online == .Offline
|
||||
|
||||
self.navigationBar.backgroundColor = isOffline
|
||||
? Colors.OfflineColor
|
||||
: Colors.OnlineColor
|
||||
}
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
case .Completed:
|
||||
break
|
||||
self.navigationBar.backgroundColor = isOffline
|
||||
? Colors.OfflineColor
|
||||
: Colors.OnlineColor
|
||||
}
|
||||
}
|
||||
}.asObserver()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,34 +21,21 @@ extension UIImageView{
|
|||
}
|
||||
|
||||
func rxex_downloadableImageAnimated(transitionType:String?) -> AnyObserver<DownloadableImage> {
|
||||
|
||||
return AnyObserver { [weak self] event in
|
||||
|
||||
guard let strongSelf = self else { return }
|
||||
MainScheduler.ensureExecutingOnScheduler()
|
||||
|
||||
switch event{
|
||||
case .Next(let value):
|
||||
for subview in strongSelf.subviews {
|
||||
subview.removeFromSuperview()
|
||||
}
|
||||
switch value{
|
||||
case .Content(let image):
|
||||
strongSelf.rx_image.onNext(image)
|
||||
case .OfflinePlaceholder:
|
||||
let label = UILabel(frame: strongSelf.bounds)
|
||||
label.textAlignment = .Center
|
||||
label.font = UIFont.systemFontOfSize(35)
|
||||
label.text = "⚠️"
|
||||
strongSelf.addSubview(label)
|
||||
}
|
||||
case .Error(let error):
|
||||
bindingErrorToInterface(error)
|
||||
break
|
||||
case .Completed:
|
||||
break
|
||||
return UIBindingObserver(UIElement: self) { imageView, image in
|
||||
for subview in strongSelf.subviews {
|
||||
subview.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
switch value{
|
||||
case .Content(let image):
|
||||
strongSelf.rx_image.onNext(image)
|
||||
case .OfflinePlaceholder:
|
||||
let label = UILabel(frame: strongSelf.bounds)
|
||||
label.textAlignment = .Center
|
||||
label.font = UIFont.systemFontOfSize(35)
|
||||
label.text = "⚠️"
|
||||
strongSelf.addSubview(label)
|
||||
}
|
||||
}.asObserver()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue