updated for model binding
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
parent
11ad080a69
commit
f2fc171914
@ -1,8 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21179.7" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21169.4"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
@ -487,7 +488,7 @@
|
||||
<rect key="frame" x="0.0" y="115" width="382" height="671"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillProportionally" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="Hmj-Yn-sy0">
|
||||
<rect key="frame" x="16" y="20" width="350" height="254"/>
|
||||
<rect key="frame" x="16" y="20" width="350" height="210"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="sp0-qf-Npb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="350" height="31"/>
|
||||
@ -594,25 +595,6 @@
|
||||
</switch>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="eSa-mA-9Ph">
|
||||
<rect key="frame" x="0.0" y="220" width="350" height="34"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Error Text" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9EW-kc-8cA">
|
||||
<rect key="frame" x="0.0" y="0.0" width="175" height="34"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="baM-I1-jMF">
|
||||
<rect key="frame" x="175" y="0.0" width="175" height="34"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
<connections>
|
||||
<action selector="onErrorTextDidEnd:" destination="h42-mH-KC1" eventType="editingDidEnd" id="ImV-fK-60i"/>
|
||||
</connections>
|
||||
</textField>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
@ -645,7 +627,6 @@
|
||||
<outlet property="childTextField" destination="G5B-ka-c0V" id="weU-KZ-YAB"/>
|
||||
<outlet property="componentContainerView" destination="jWf-eh-zqg" id="1KC-GB-6bt"/>
|
||||
<outlet property="disabledSwitch" destination="9XX-VQ-7L8" id="z36-Tq-9ER"/>
|
||||
<outlet property="errorTextField" destination="baM-I1-jMF" id="Yam-GG-fRI"/>
|
||||
<outlet property="labelTextField" destination="J94-IQ-J53" id="lfR-Ez-6H2"/>
|
||||
<outlet property="picker" destination="JpA-y5-M2q" id="hqU-6W-iK0"/>
|
||||
<outlet property="showErrorSwitch" destination="Fm6-Ej-sVV" id="MiC-BD-a4I"/>
|
||||
|
||||
@ -26,12 +26,11 @@ class RadioButtonViewController: UIViewController, StoryboardInitable {
|
||||
@IBOutlet weak var labelTextField: UITextField!
|
||||
@IBOutlet weak var childTextField: UITextField!
|
||||
@IBOutlet weak var showErrorSwitch: UISwitch!
|
||||
@IBOutlet weak var errorTextField: UITextField!
|
||||
|
||||
// var radioButton: RadioButton!
|
||||
// var radioButton2: RadioButton!
|
||||
var radioButtonGroup = RadioButtonGroup()
|
||||
@Published public var model = DefaultRadioButtonGroupModel()
|
||||
public var model = DefaultRadioButtonGroupModel()
|
||||
public var subscribers = Set<AnyCancellable>()
|
||||
|
||||
override func viewDidLoad() {
|
||||
@ -59,30 +58,33 @@ class RadioButtonViewController: UIViewController, StoryboardInitable {
|
||||
labelTextField.text = model1.labelText
|
||||
childTextField.text = model1.childText
|
||||
showErrorSwitch.isOn = model1.hasError
|
||||
errorTextField.text = model1.errorText
|
||||
|
||||
model.selectors = [model1, model2]
|
||||
|
||||
radioButtonGroup.set(with: model)
|
||||
|
||||
componentContainerView.addSubview(radioButtonGroup)
|
||||
|
||||
//create the subject
|
||||
let modelSubject = CurrentValueSubject<DefaultRadioButtonGroupModel, Never>(model)
|
||||
|
||||
$model.debounce(for: .seconds(Constants.ModelStateDebounce), scheduler: RunLoop.main).sink { viewModel in
|
||||
guard let selectedModel = viewModel.selectedModel else { return }
|
||||
print("RadioButtonViewController selectedModel Id: \(selectedModel.id)")
|
||||
//assign - this will auto overwrite any changes
|
||||
modelSubject.debounce(for: .seconds(Constants.ModelStateDebounce), scheduler: RunLoop.main).assign(to: \.model, on: self).store(in: &subscribers)
|
||||
|
||||
//bind
|
||||
radioButtonGroup.createBinding(with: modelSubject, storeIn: &subscribers)
|
||||
|
||||
//print out on subject changes
|
||||
modelSubject.sink { [weak self] model in
|
||||
|
||||
self?.showErrorSwitch.isOn = model.hasError
|
||||
print("RadioButtonViewController hasError: \(model.hasError)")
|
||||
|
||||
if let selectedModel = model.selectedModel {
|
||||
print("RadioButtonViewController selectedModel Id: \(selectedModel.id)")
|
||||
}
|
||||
}.store(in: &subscribers)
|
||||
|
||||
radioButtonGroup.modelPublisher.debounce(for: .seconds(Constants.ModelStateDebounce), scheduler: RunLoop.main).sink { viewModel in
|
||||
guard let selectedModel = viewModel.selectedModel else { return }
|
||||
print("radioButtonGroup.modelPublisher selectedModel Id: \(selectedModel.id)")
|
||||
print("RadioButtonViewController selectedModel Id: \(self.model.selectedModel?.id)")
|
||||
}.store(in: &subscribers)
|
||||
|
||||
// radioButtonGroup.modelSubject.sink { [weak self] model in
|
||||
// print("RadioButtonViewController model: \(model.selectedModel?.id)")
|
||||
// print("RadioButtonViewController local.model: \(self?.model.selectedModel?.id)")
|
||||
// }.store(in: &subscribers)
|
||||
|
||||
|
||||
radioButtonGroup.leadingAnchor.constraint(equalTo: componentContainerView.leadingAnchor, constant: 10).isActive = true
|
||||
radioButtonGroup.topAnchor.constraint(equalTo: componentContainerView.topAnchor, constant: 20).isActive = true
|
||||
radioButtonGroup.bottomAnchor.constraint(equalTo: componentContainerView.bottomAnchor, constant: -20).isActive = true
|
||||
@ -114,11 +116,6 @@ class RadioButtonViewController: UIViewController, StoryboardInitable {
|
||||
radioButtonGroup.hasError = sender.isOn
|
||||
}
|
||||
|
||||
@IBAction func onErrorTextDidEnd(_ sender: UITextField) {
|
||||
radioButton?.errorText = sender.text
|
||||
sender.resignFirstResponder()
|
||||
}
|
||||
|
||||
@IBAction func surfaceClick(_ sender: Any) {
|
||||
pickerType = .surface
|
||||
}
|
||||
|
||||
@ -8,8 +8,9 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Combine
|
||||
import VDS
|
||||
|
||||
class User: ObservableObject {
|
||||
struct User {
|
||||
var firstName: String
|
||||
var lastName: String
|
||||
|
||||
@ -19,20 +20,29 @@ class User: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
class TextFieldCell: UIView {
|
||||
public protocol Bindable {
|
||||
associatedtype ModelType
|
||||
var model: ModelType { get set }
|
||||
var subject: CurrentValueSubject<ModelType, Never>? { get set }
|
||||
func createBinding(with subject: CurrentValueSubject<ModelType, Never>, storeIn subscriptions: inout Set<AnyCancellable>)
|
||||
}
|
||||
|
||||
extension Bindable {
|
||||
public func send() {
|
||||
subject?.send(model)
|
||||
}
|
||||
}
|
||||
|
||||
class TextFieldBindingCell: UIView, Bindable {
|
||||
//bindable
|
||||
var model: User
|
||||
var subject: CurrentValueSubject<User, Never>?
|
||||
|
||||
let firstNameTextField = TextField()
|
||||
let lastNameTextField = TextField()
|
||||
var subject: CurrentValueSubject<User, Never>
|
||||
private var subscriptions = Set<AnyCancellable>()
|
||||
var model: User
|
||||
|
||||
private func send() {
|
||||
subject.send(model)
|
||||
}
|
||||
|
||||
init(subject: CurrentValueSubject<User, Never>) {
|
||||
self.model = subject.value
|
||||
self.subject = subject
|
||||
|
||||
init(model: User) {
|
||||
self.model = model
|
||||
super.init(frame: .zero)
|
||||
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
@ -54,6 +64,16 @@ class TextFieldCell: UIView {
|
||||
lastNameTextField.heightAnchor.constraint(equalToConstant: 50).isActive = true
|
||||
lastNameTextField.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
|
||||
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func createBinding(with subject: CurrentValueSubject<User, Never>, storeIn subscriptions: inout Set<AnyCancellable>) {
|
||||
self.model = subject.value
|
||||
self.subject = subject
|
||||
|
||||
//add the logic
|
||||
let firstNameSubject = CurrentValueSubject<String, Never>(model.firstName)
|
||||
firstNameTextField.createBinding(with: firstNameSubject, storeIn: &subscriptions)
|
||||
@ -71,18 +91,12 @@ class TextFieldCell: UIView {
|
||||
}.store(in: &subscriptions)
|
||||
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objcMembers class TestViewController: UIViewController, Initable {
|
||||
|
||||
var user = User(firstName: "Joe", lastName: "User")
|
||||
var nameTextField: TextFieldCell!
|
||||
var button = UIButton()
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
private var subscriptions = Set<AnyCancellable>()
|
||||
|
||||
required init() {
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
@ -97,8 +111,12 @@ class TextFieldCell: UIView {
|
||||
view.backgroundColor = .white
|
||||
|
||||
let subject = CurrentValueSubject<User, Never>(user)
|
||||
subject.assign(to: \.user, on: self).store(in: &cancellables)
|
||||
nameTextField = TextFieldCell(subject: subject)
|
||||
subject.assign(to: \.user, on: self).store(in: &subscriptions)
|
||||
|
||||
let nameTextField = TextFieldBindingCell(model: user)
|
||||
nameTextField.createBinding(with: subject, storeIn: &subscriptions)
|
||||
|
||||
let button = UIButton()
|
||||
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
@ -120,21 +138,19 @@ class TextFieldCell: UIView {
|
||||
}
|
||||
}), for: .touchUpInside)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
extension UITextField {
|
||||
|
||||
func textPublisher() -> AnyPublisher<String, Never> {
|
||||
public func textPublisher() -> AnyPublisher<String, Never> {
|
||||
NotificationCenter.default
|
||||
.publisher(for: UITextField.textDidChangeNotification, object: self)
|
||||
.compactMap({ ($0.object as? UITextField)?.text })
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func createBinding(with subject: CurrentValueSubject<String, Never>,
|
||||
public func createBinding(with subject: CurrentValueSubject<String, Never>,
|
||||
storeIn subscriptions: inout Set<AnyCancellable>) {
|
||||
|
||||
subject.sink { [weak self] (value) in
|
||||
|
||||
Loading…
Reference in New Issue
Block a user