|
import Result |
|
import ReactiveCocoa |
|
import ReactiveSwift |
|
import UIKit |
|
import XCPlayground |
|
|
|
struct ViewModel { |
|
|
|
// do not expose the implementation detail |
|
private let (codeSignal, codeSink) = Signal<String, NoError>.pipe() |
|
|
|
// change mutable to read-only |
|
// this will not let the changes outside of VM |
|
// and only through the `setCode` method |
|
let code: Property<String> |
|
|
|
let openAction: Action<String, String, NoError> |
|
|
|
init() { |
|
code = Property(initial: "", then: codeSignal) |
|
let validCodes = Property(capturing: code.map { $0.characters.count > 4}) |
|
openAction = Action<String, String, NoError>(enabledIf: validCodes, { code -> SignalProducer<String, NoError> in |
|
return SignalProducer<String, NoError> { observer, _ in |
|
print("Code \(code) will be sent.") |
|
observer.send(value: code) |
|
observer.sendCompleted() |
|
} |
|
}) |
|
} |
|
|
|
public func setCode(_ code: String) { |
|
codeSink.send(value: code) |
|
} |
|
} |
|
|
|
// UI Declarations |
|
let textField = UITextField(frame: CGRect(x: 0, y: 0, width: 360, height: 44)) |
|
textField.textColor = .white |
|
textField.text = "P2525" |
|
|
|
let button = UIButton(frame: CGRect(x: 0, y: 50, width: 360, height: 44)) |
|
button.setTitle("Open", for: .normal) |
|
|
|
// Bindings |
|
let viewModel = ViewModel() |
|
|
|
// add the `setCode(_:)` function as |
|
// the observer to code text field changes |
|
textField.reactive.continuousTextValues |
|
.skipNil() |
|
.observeValues(viewModel.setCode) |
|
|
|
// When button is pressed, trigger viewModel action with the property value |
|
button.reactive.pressed = CocoaAction(viewModel.openAction, { _ in |
|
return viewModel.code.value |
|
}) |
|
|
|
// bind button's isEnabled to action's isEnabled and action's executing |
|
button.reactive.isEnabled <~ Signal.merge(viewModel.openAction.isEnabled.signal, viewModel.openAction.isExecuting.signal) |
|
|
|
// Let's assume the user types and then presses the button, for playground use. |
|
textField.sendActions(for: .allEditingEvents) |
|
button.sendActions(for: .touchUpInside) |
Revisions have been made thanks to @eimantas and @sharplet, slack archive for better reference.