From aa233515a5478f4ff8cf6d1b6758f6bc5fb4ac08 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 29 Mar 2023 13:47:56 -0500 Subject: [PATCH] updated control and subcontrols Signed-off-by: Matt Bruce --- VDS/Classes/Control.swift | 6 +-- VDS/Components/Checkbox/Checkbox.swift | 26 +++++------- VDS/Components/Checkbox/CheckboxGroup.swift | 41 ++++++++---------- .../Notification/Notification.swift | 21 +++------- VDS/Components/RadioBox/RadioBox.swift | 26 +++++------- VDS/Components/RadioBox/RadioBoxGroup.swift | 29 ++++++------- VDS/Components/RadioButton/RadioButton.swift | 36 +++++----------- .../RadioButton/RadioButtonGroup.swift | 42 ++++++++++--------- VDS/Components/RadioSwatch/RadioSwatch.swift | 31 +++++--------- .../RadioSwatch/RadioSwatchGroup.swift | 30 +++++-------- .../TileContainer/TileContainer.swift | 13 ++++-- VDS/Components/Tilelet/Tilelet.swift | 7 +++- VDS/Components/Toggle/Toggle.swift | 32 ++++++-------- 13 files changed, 141 insertions(+), 199 deletions(-) diff --git a/VDS/Classes/Control.swift b/VDS/Classes/Control.swift index 9c8da789..0efbec97 100644 --- a/VDS/Classes/Control.swift +++ b/VDS/Classes/Control.swift @@ -17,7 +17,7 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab //-------------------------------------------------- public var subject = PassthroughSubject() public var subscribers = Set() - open var onClickSubscriber: AnyCancellable? { + internal var onClickSubscriber: AnyCancellable? { willSet { if let onClickSubscriber { onClickSubscriber.cancel() @@ -27,7 +27,7 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab enabledHighlight = onClickSubscriber != nil } } - + //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -109,7 +109,7 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab sendActions(for: .touchUpInside) return true } - + //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- diff --git a/VDS/Components/Checkbox/Checkbox.swift b/VDS/Components/Checkbox/Checkbox.swift index fc78cb7f..5bc4047b 100644 --- a/VDS/Components/Checkbox/Checkbox.swift +++ b/VDS/Components/Checkbox/Checkbox.swift @@ -12,22 +12,9 @@ import VDSFormControlsTokens import Combine /// Checkboxes are a multi-select component through which a customer indicates a choice. If a binary choice, the component is a checkbox. If the choice has multiple options, the component is a ``CheckboxGroup``. -@objc(VDSCheckbox) -public class Checkbox: CheckboxBase{} - -@objc(VDSSoloCheckbox) -public class SoloCheckbox: CheckboxBase{ - public override func initialSetup() { - super.initialSetup() - onClickSubscriber = publisher(for: .touchUpInside) - .sink { control in - control.toggle() - } - } -} - @objc(VDSCheckboxBase) -open class CheckboxBase: Control, Errorable { +open class Checkbox: Control, Errorable, Clickable { + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -76,6 +63,8 @@ open class CheckboxBase: Control, Errorable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var onClick: ((Checkbox) -> ())? { didSet { setupOnClick() }} + open var label = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.textPosition = .left @@ -164,6 +153,13 @@ open class CheckboxBase: Control, Errorable { //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- + open override func initialSetup() { + super.initialSetup() + onClick = { control in + control.toggle() + } + } + open override func setup() { super.setup() diff --git a/VDS/Components/Checkbox/CheckboxGroup.swift b/VDS/Components/Checkbox/CheckboxGroup.swift index 6b5412f0..d3e601c8 100644 --- a/VDS/Components/Checkbox/CheckboxGroup.swift +++ b/VDS/Components/Checkbox/CheckboxGroup.swift @@ -9,31 +9,24 @@ import Foundation import UIKit @objc(VDSCheckboxGroup) -public class CheckboxGroup: CheckboxGroupBase { - public override func didSelect(_ selectedControl: Checkbox) { - selectedControl.toggle() - if selectedControl.isSelected, showError{ - showError.toggle() - } - valueChanged() - } -} - -public class CheckboxGroupBase: SelectorGroupHandlerBase { +public class CheckboxGroup: SelectorGroupHandlerBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - - public override var selectorViews: [HandlerType] { + public var selectedHandlers: [Checkbox]? { + let selected = selectorViews.filter{ $0.isSelected == true } + guard selected.count > 0 else { return nil } + return selected + } + + public override var selectorViews: [Checkbox] { didSet { for selector in selectorViews { if !mainStackView.arrangedSubviews.contains(selector) { - selector - .publisher(for: .touchUpInside) - .sink { [weak self] handler in - self?.didSelect(handler) - }.store(in: &subscribers) + selector.onClick = { [weak self] handler in + self?.didSelect(handler) + } mainStackView.addArrangedSubview(selector) } } @@ -79,11 +72,13 @@ public class CheckboxGroupBase: SelectorGroupHandlerB mainStackView.pinToSuperView() } - - public var selectedHandlers: [HandlerType]? { - let selected = selectorViews.filter{ $0.isSelected == true } - guard selected.count > 0 else { return nil } - return selected + + public override func didSelect(_ selectedControl: Checkbox) { + selectedControl.toggle() + if selectedControl.isSelected, showError{ + showError.toggle() + } + valueChanged() } } diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index 7b6c358d..1d486322 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -106,6 +106,8 @@ public class Notification: View { $0.use = .secondary } + open var onCloseClick: ((Notification)->())? + //-------------------------------------------------- // MARK: - Modal Properties //-------------------------------------------------- @@ -163,7 +165,8 @@ public class Notification: View { mainStackView.addArrangedSubview(closeButton) closeButton.publisher(for: UITapGestureRecognizer()).sink { [weak self] _ in - self?.didClickOnCloseButton() + guard let self else { return } + self.onCloseClick?(self) }.store(in: &subscribers) //labels @@ -227,22 +230,14 @@ public class Notification: View { if let primaryButtonModel { primaryButton.text = primaryButtonModel.text primaryButton.surface = surface - primaryButton.onClickSubscriber = primaryButton - .publisher(for: .touchUpInside) - .sink(receiveValue: { button in - primaryButtonModel.onClick(button) - }) + primaryButton.onClick = primaryButtonModel.onClick buttons.append(primaryButton) } if let secondaryButtonModel { secondaryButton.text = secondaryButtonModel.text secondaryButton.surface = surface - secondaryButton.onClickSubscriber = secondaryButton - .publisher(for: .touchUpInside) - .sink(receiveValue: { button in - secondaryButtonModel.onClick(button) - }) + secondaryButton.onClick = secondaryButtonModel.onClick buttons.append(secondaryButton) } @@ -260,9 +255,5 @@ public class Notification: View { .pinTrailing() } } - - func didClickOnCloseButton() { - print("Notification close button clicked!!!") - } } diff --git a/VDS/Components/RadioBox/RadioBox.swift b/VDS/Components/RadioBox/RadioBox.swift index b655b03b..d9b93b07 100644 --- a/VDS/Components/RadioBox/RadioBox.swift +++ b/VDS/Components/RadioBox/RadioBox.swift @@ -12,22 +12,8 @@ import VDSFormControlsTokens import Combine @objc(VDSRadioBox) -public class RadioBox: RadioBoxBase{} - -@objc(VDSSoloRadioBox) -public class SoloRadioBox: RadioBoxBase{ +open class RadioBox: Control, Clickable { - public override func initialSetup() { - super.initialSetup() - onClickSubscriber = publisher(for: .touchUpInside) - .sink { control in - control.toggle() - } - } -} - -@objc(VDSRadioBoxBase) -open class RadioBoxBase: Control{ //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -70,6 +56,8 @@ open class RadioBoxBase: Control{ //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var onClick: ((RadioBox) -> ())? { didSet { setupOnClick() }} + open var textLabel = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.textPosition = .left @@ -138,7 +126,13 @@ open class RadioBoxBase: Control{ //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- - + open override func initialSetup() { + super.initialSetup() + onClick = { control in + control.toggle() + } + } + open override func setup() { super.setup() diff --git a/VDS/Components/RadioBox/RadioBoxGroup.swift b/VDS/Components/RadioBox/RadioBoxGroup.swift index e53a87c7..19f0358a 100644 --- a/VDS/Components/RadioBox/RadioBoxGroup.swift +++ b/VDS/Components/RadioBox/RadioBoxGroup.swift @@ -9,30 +9,18 @@ import Foundation import UIKit @objc(VDSRadioBoxGroup) -public class RadioBoxGroup: RadioBoxGroupBase { - - public override func didSelect(_ selectedControl: RadioBox) { - let oldSelectedControl = selectorViews.filter { $0.isSelected == true }.first - oldSelectedControl?.toggle() - selectedControl.toggle() - valueChanged() - } -} - -public class RadioBoxGroupBase: SelectorGroupSelectedHandlerBase { +public class RadioBoxGroup: SelectorGroupSelectedHandlerBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - public override var selectorViews: [HandlerType] { + public override var selectorViews: [RadioBox] { didSet { for selector in selectorViews { if !mainStackView.arrangedSubviews.contains(selector) { - selector - .publisher(for: .touchUpInside) - .sink { [weak self] handler in - self?.didSelect(handler) - }.store(in: &subscribers) + selector.onClick = { [weak self] handler in + self?.didSelect(handler) + } mainStackView.addArrangedSubview(selector) } } @@ -84,4 +72,11 @@ public class RadioBoxGroupBase: SelectorGroupSelected } }.store(in: &subscribers) } + + open override func didSelect(_ selectedControl: RadioBox) { + let oldSelectedControl = selectorViews.filter { $0.isSelected == true }.first + oldSelectedControl?.toggle() + selectedControl.toggle() + valueChanged() + } } diff --git a/VDS/Components/RadioButton/RadioButton.swift b/VDS/Components/RadioButton/RadioButton.swift index edc2fdc0..83606b05 100644 --- a/VDS/Components/RadioButton/RadioButton.swift +++ b/VDS/Components/RadioButton/RadioButton.swift @@ -11,30 +11,8 @@ import VDSColorTokens import VDSFormControlsTokens @objc(VDSRadioButton) -public class RadioButton: RadioButtonBase { - //for groups allows "toggle" - open override func toggle() { - //removed error - if showError && isSelected == false { - showError.toggle() - } - isSelected.toggle() - } -} - -@objc(VDSSoloRadioButton) -public class SoloRadioButton: RadioButtonBase { - public override func initialSetup() { - super.initialSetup() - onClickSubscriber = publisher(for: .touchUpInside) - .sink { control in - control.toggle() - } - } -} - -@objc(VDSRadioButtonBase) -open class RadioButtonBase: Control, Errorable { +open class RadioButton: Control, Errorable, Clickable { + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -83,6 +61,8 @@ open class RadioButtonBase: Control, Errorable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var onClick: ((RadioButton) -> ())? { didSet { setupOnClick() } } + open var label = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.textPosition = .left @@ -158,7 +138,13 @@ open class RadioButtonBase: Control, Errorable { //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- - + open override func initialSetup() { + super.initialSetup() + onClick = { control in + control.toggle() + } + } + open override func setup() { super.setup() diff --git a/VDS/Components/RadioButton/RadioButtonGroup.swift b/VDS/Components/RadioButton/RadioButtonGroup.swift index 136dbe6e..0ab6b06b 100644 --- a/VDS/Components/RadioButton/RadioButtonGroup.swift +++ b/VDS/Components/RadioButton/RadioButtonGroup.swift @@ -9,32 +9,18 @@ import Foundation import UIKit @objc(VDSRadioButtonGroup) -public class RadioButtonGroup: RadioButtonGroupBase { - - public override func didSelect(_ selectedControl: RadioButton) { - selectedHandler?.toggle() - selectedControl.toggle() - if showError { - showError = false - } - valueChanged() - } -} - -public class RadioButtonGroupBase: SelectorGroupSelectedHandlerBase { +public class RadioButtonGroup: SelectorGroupSelectedHandlerBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - public override var selectorViews: [HandlerType] { + public override var selectorViews: [RadioButton] { didSet { for selector in selectorViews { if !mainStackView.arrangedSubviews.contains(selector) { - selector - .publisher(for: .touchUpInside) - .sink { [weak self] handler in - self?.didSelect(handler) - }.store(in: &subscribers) + selector.onClick = { [weak self] handler in + self?.didSelect(handler) + } mainStackView.addArrangedSubview(selector) } } @@ -81,4 +67,22 @@ public class RadioButtonGroupBase: SelectorGroupSe mainStackView.pinToSuperView() } + + public override func didSelect(_ selectedControl: RadioButton) { + if let selectedHandler { + updateToggle(selectedHandler) + } + updateToggle(selectedControl) + if showError { + showError = false + } + valueChanged() + } + + private func updateToggle(_ radioButton: RadioButton) { + if radioButton.showError && radioButton.isSelected == false { + radioButton.showError.toggle() + } + radioButton.isSelected.toggle() + } } diff --git a/VDS/Components/RadioSwatch/RadioSwatch.swift b/VDS/Components/RadioSwatch/RadioSwatch.swift index 105e0dea..967a824c 100644 --- a/VDS/Components/RadioSwatch/RadioSwatch.swift +++ b/VDS/Components/RadioSwatch/RadioSwatch.swift @@ -12,26 +12,7 @@ import VDSFormControlsTokens import Combine @objc(VDSRadioSwatch) -public class RadioSwatch: RadioSwatchBase{ - //for groups allows "toggle" - open override func toggle() { - isSelected.toggle() - } -} - -@objc(VDSSoloRadioSwatch) -public class SolorRadioSwatch: RadioSwatchBase{ - public override func initialSetup() { - super.initialSetup() - onClickSubscriber = publisher(for: .touchUpInside) - .sink { control in - control.toggle() - } - } -} - -@objc(VDSRadioSwatchBase) -open class RadioSwatchBase: Control { +open class RadioSwatch: Control, Clickable { //-------------------------------------------------- // MARK: - Initializers @@ -51,6 +32,8 @@ open class RadioSwatchBase: Control { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- + open var onClick: ((RadioSwatch) -> ())? { didSet { setupOnClick() } } + public var selectorView = UIView().with { $0.translatesAutoresizingMaskIntoConstraints = false } @@ -78,7 +61,13 @@ open class RadioSwatchBase: Control { //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- - + open override func initialSetup() { + super.initialSetup() + onClick = { control in + control.toggle() + } + } + open override func setup() { super.setup() diff --git a/VDS/Components/RadioSwatch/RadioSwatchGroup.swift b/VDS/Components/RadioSwatch/RadioSwatchGroup.swift index 751d11b3..f3a86449 100644 --- a/VDS/Components/RadioSwatch/RadioSwatchGroup.swift +++ b/VDS/Components/RadioSwatch/RadioSwatchGroup.swift @@ -10,24 +10,12 @@ import UIKit import Combine @objc(VDSRadioSwatchGroup) -public class RadioSwatchGroup: RadioSwatchGroupBase { - - public override func didSelect(selector: RadioSwatch) { - selectedHandler?.toggle() - selector.toggle() - label.text = selector.text - didChange() - valueChanged() - } - -} - -public class RadioSwatchGroupBase: SelectorGroupSelectedHandlerBase, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate { +public class RadioSwatchGroup: SelectorGroupSelectedHandlerBase, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - public override var selectorViews: [HandlerType] { + public override var selectorViews: [RadioSwatch] { didSet { collectionView.reloadData() } @@ -160,18 +148,20 @@ public class RadioSwatchGroupBase: SelectorGroupSe public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) let handler = selectorViews[indexPath.row] - handler.subscribers.forEach{ $0.cancel() } - handler.subscribers.removeAll() - handler.publisher(for: .touchUpInside).sink { [weak self] handler in + handler.onClick = { [weak self] handler in self?.didSelect(selector: handler) - }.store(in: &handler.subscribers) + } cell.subviews.forEach { $0.removeFromSuperview() } cell.addSubview(handler) handler.pinToSuperView() return cell } - open func didSelect(selector: HandlerType) { - fatalError("Must override didSelect") + public func didSelect(selector: RadioSwatch) { + selectedHandler?.toggle() + selector.toggle() + label.text = selector.text + didChange() + valueChanged() } } diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index bf0d24a9..371e5bc3 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -11,7 +11,12 @@ import VDSFormControlsTokens import UIKit @objc(VDSTileContainer) -open class TileContainer: Control { +open class TileContainer: TileContainerBase, Clickable { + public var onClick: ((TileContainer) -> ())? { didSet { setupOnClick() } } +} + +@objc(VDSTileContainerBase) +open class TileContainerBase: Control { //-------------------------------------------------- // MARK: - Initializers @@ -310,13 +315,13 @@ open class TileContainer: Control { } } -extension TileContainer { +extension TileContainerBase { class BackgroundColorConfiguration: ObjectColorable { - typealias ObjectType = TileContainer + typealias ObjectType = TileContainerBase required init() { } - func getColor(_ object: TileContainer) -> UIColor { + func getColor(_ object: TileContainerBase) -> UIColor { switch object.color { case .white: diff --git a/VDS/Components/Tilelet/Tilelet.swift b/VDS/Components/Tilelet/Tilelet.swift index 12f940e3..09a59499 100644 --- a/VDS/Components/Tilelet/Tilelet.swift +++ b/VDS/Components/Tilelet/Tilelet.swift @@ -12,7 +12,8 @@ import UIKit import Combine @objc(VDSTilelet) -open class Tilelet: TileContainer { +open class Tilelet: TileContainerBase, Clickable { + //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- @@ -62,7 +63,9 @@ open class Tilelet: TileContainer { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - open override var onClickSubscriber: AnyCancellable? { + open var onClick: ((Tilelet) -> ())? { didSet { setupOnClick() } } + + internal override var onClickSubscriber: AnyCancellable? { didSet { isAccessibilityElement = onClickSubscriber != nil } diff --git a/VDS/Components/Toggle/Toggle.swift b/VDS/Components/Toggle/Toggle.swift index 499d394d..b9e13b6b 100644 --- a/VDS/Components/Toggle/Toggle.swift +++ b/VDS/Components/Toggle/Toggle.swift @@ -18,18 +18,7 @@ import Combine Knob: The circular indicator that slides on the container. */ @objc(VDSToggle) -public class Toggle: ToggleBase{ - public override func initialSetup() { - super.initialSetup() - publisher(for: .touchUpInside) - .sink { control in - control.toggle() - }.store(in: &subscribers) - } -} - -@objc(VDSToggleBase) -open class ToggleBase: Control { +open class Toggle: Control, Clickable { //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- @@ -64,6 +53,7 @@ open class ToggleBase: Control { // MARK: - Private Properties //-------------------------------------------------- private var stackView = UIStackView().with { + $0.isUserInteractionEnabled = false $0.translatesAutoresizingMaskIntoConstraints = false $0.axis = .horizontal $0.distribution = .fill @@ -81,6 +71,8 @@ open class ToggleBase: Control { //-------------------------------------------------- // MARK: - Configuration Properties //-------------------------------------------------- + open var onClick: ((Toggle) -> ())? { didSet { setupOnClick() } } + // Sizes are from InVision design specs. public let toggleSize = CGSize(width: 52, height: 24) public let toggleContainerSize = CGSize(width: 52, height: 44) @@ -223,14 +215,16 @@ open class ToggleBase: Control { //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- + open override func initialSetup() { + super.initialSetup() + onClick = { control in + control.toggle() + } + } + open override func setup() { super.setup() - - //add tapGesture to self - publisher(for: UITapGestureRecognizer()).sink { [weak self] _ in - self?.sendActions(for: .touchUpInside) - }.store(in: &subscribers) - + isAccessibilityElement = true accessibilityTraits = .button addSubview(stackView) @@ -288,7 +282,7 @@ open class ToggleBase: Control { toggleView.backgroundColor = toggleColorConfiguration.getColor(self) knobView.backgroundColor = knobColorConfiguration.getColor(self) } - + /// This will toggle the state of the Toggle and execute the actionBlock if provided. open func toggle() { isOn.toggle()