From 513ab3f73415ff8e7defa2d438b8232e88cb6ffb Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Wed, 15 Mar 2023 23:06:58 +0530 Subject: [PATCH 01/20] Creating Notification component --- VDS.xcodeproj/project.pbxproj | 12 ++ .../Notification/Notification.swift | 204 ++++++++++++++++++ 2 files changed, 216 insertions(+) create mode 100644 VDS/Components/Notification/Notification.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 4d1107f5..1a695824 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; }; 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */; }; @@ -120,6 +121,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = ""; }; 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroup.swift; sourceTree = ""; }; @@ -245,6 +247,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 445BA07629C07ABA0036A7C5 /* Notification */ = { + isa = PBXGroup; + children = ( + 445BA07729C07B3D0036A7C5 /* Notification.swift */, + ); + path = Notification; + sourceTree = ""; + }; 5FC35BE128D513EB004EBEAC /* Button */ = { isa = PBXGroup; children = ( @@ -349,6 +359,7 @@ EA985BF3296C609E00F2FF2E /* Icon */, EA1F265F28B945070033E859 /* RadioSwatch */, EA3362412892EF700071C351 /* Label */, + 445BA07629C07ABA0036A7C5 /* Notification */, EA89200B28B530F0006B9984 /* RadioBox */, EAF7F11428A1470D00B287F5 /* RadioButton */, EAC925852911C9DE00091998 /* TextFields */, @@ -747,6 +758,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */, EAF7F0B5289C126F00B287F5 /* UILabel.swift in Sources */, EA5E304C294CBDD00082B959 /* TileContainer.swift in Sources */, EAF7F0A6289B0CE000B287F5 /* Resetable.swift in Sources */, diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift new file mode 100644 index 00000000..39c7b04f --- /dev/null +++ b/VDS/Components/Notification/Notification.swift @@ -0,0 +1,204 @@ +// +// Notification.swift +// VDS +// +// Created by Nadigadda, Sumanth on 14/03/23. +// + +import Foundation +import UIKit +import VDSColorTokens + +@objc(VDSNotification) +/// A VDS Component that will render a view with information +public class Notification: View { + + //-------------------------------------------------- + // MARK: - Enums + //-------------------------------------------------- + + public enum NotificationStyle: String, CaseIterable { + case info, success, warning, error + + func styleIconName() -> Icon.Name { + switch self { + case .info: + return .infoBold + case .success: + return .checkmarkAltBold + case .warning: + return .warningBold + case .error: + return .errorBold + } + } + } + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + + private var mainStackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.alignment = .top + $0.axis = .horizontal + $0.spacing = VDSLayout.Spacing.space2X.value + } + + private var labelsView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.alignment = .top + $0.axis = .vertical + } + + private var edgeSpacing: CGFloat { + return UIDevice.isIPad ? VDSLayout.Spacing.space5X.value : VDSLayout.Spacing.space4X.value + } + + //-------------------------------------------------- + // MARK: - View Properties + //-------------------------------------------------- + + open var typeIcon = Icon().with { + $0.name = .infoBold + } + + open var closeButton = Icon().with { + $0.name = .close + } + + open var titleLabel = Label().with { + $0.textStyle = .boldBodySmall + } + + open var subTitleLabel = Label().with { + $0.textStyle = .bodySmall + } + + open var buttonsView = ButtonGroup() + + //-------------------------------------------------- + // MARK: - Modal Properties + //-------------------------------------------------- + + open var type: NotificationStyle = .info { didSet{didChange()}} + + //-------------------------------------------------- + // MARK: - Configuration + //-------------------------------------------------- + private var backgroundColorConfiguration: StateColorConfiguration = { + let config = StateColorConfiguration() + config.setSurfaceColors(VDSColor.feedbackInformationBackgroundOnlight, VDSColor.feedbackInformationBackgroundOndark, forState: .info) + config.setSurfaceColors(VDSColor.feedbackWarningBackgroundOnlight, VDSColor.feedbackWarningBackgroundOndark, forState: .warning) + config.setSurfaceColors(VDSColor.feedbackSuccessBackgroundOnlight, VDSColor.feedbackSuccessBackgroundOndark, forState: .success) + config.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) + return config + }() + + private var textColorConfig = ViewColorConfiguration() + public func updateTextColorConfig() { + textColorConfig.reset() + + switch type { + case .info, .success, .warning, .error: + textColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false) + textColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: true) + } + } + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + required public init() { + super.init(frame: .zero) + } + + public override init(frame: CGRect) { + super.init(frame: .zero) + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + + open override func setup() { + super.setup() + addSubview(mainStackView) + mainStackView.pinToSuperView(.init(top: edgeSpacing, left: edgeSpacing, bottom: edgeSpacing, right: edgeSpacing)) + + mainStackView.addArrangedSubview(typeIcon) + mainStackView.addArrangedSubview(labelsView) + mainStackView.addArrangedSubview(closeButton) + + labelsView.addArrangedSubview(titleLabel) + labelsView.addArrangedSubview(subTitleLabel) + labelsView.addArrangedSubview(buttonsView) + + publisher(for: UITapGestureRecognizer()).sink { [weak self] _ in + self?.didClickOnCloseButton() + }.store(in: &subscribers) + } + + open override func reset() { + super.reset() + } + + //-------------------------------------------------- + // MARK: - State + //-------------------------------------------------- + open override func updateView() { + updateTextColorConfig() + + backgroundColor = backgroundColorConfiguration.getColor(surface, forState: type) + typeIcon.name = type.styleIconName() + typeIcon.color = surface == .dark ? Icon.Color.white : Icon.Color.black + closeButton.color = surface == .dark ? Icon.Color.white : Icon.Color.black + titleLabel.textColorConfiguration = textColorConfig.eraseToAnyColorable() + subTitleLabel.textColorConfiguration = textColorConfig.eraseToAnyColorable() + + titleLabel.surface = surface + subTitleLabel.surface = surface + + } + + func didClickOnCloseButton() { + print("Notification close button clicked!!!") + } + + ///Temporary Place holder + public struct TitleModel { + public var text: String + public var textAttributes: [any LabelAttributeModel]? + public var textStyle: TextStyle = .boldBodySmall + public var numberOfLines: Int + + public init(text: String, + textAttributes: [any LabelAttributeModel]? = nil, + numberOfLines: Int = 0) { + self.text = text + self.textAttributes = textAttributes + self.numberOfLines = numberOfLines + } + } + + public struct SubTitleModel { + public var text: String + public var textAttributes: [any LabelAttributeModel]? + public var textStyle: TextStyle = .bodySmall + public var numberOfLines: Int + + public init(text: String, + textColor: Use = .primary, + textAttributes: [any LabelAttributeModel]? = nil, + numberOfLines: Int = 0) { + self.text = text + self.textAttributes = textAttributes + self.numberOfLines = numberOfLines + } + } +} + From fd512cc38c8b53cfed7ed31b0cbfe28b5c6394ad Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Thu, 16 Mar 2023 23:38:55 +0530 Subject: [PATCH 02/20] notification background color changes --- VDS/Components/Notification/Notification.swift | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index 39c7b04f..f15f99f2 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -86,12 +86,12 @@ public class Notification: View { //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- - private var backgroundColorConfiguration: StateColorConfiguration = { - let config = StateColorConfiguration() - config.setSurfaceColors(VDSColor.feedbackInformationBackgroundOnlight, VDSColor.feedbackInformationBackgroundOndark, forState: .info) - config.setSurfaceColors(VDSColor.feedbackWarningBackgroundOnlight, VDSColor.feedbackWarningBackgroundOndark, forState: .warning) - config.setSurfaceColors(VDSColor.feedbackSuccessBackgroundOnlight, VDSColor.feedbackSuccessBackgroundOndark, forState: .success) - config.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forState: .error) + private var backgroundColorConfiguration: KeyedColorConfiguration = { + let config = KeyedColorConfiguration(keyName: "type") + config.setSurfaceColors(VDSColor.feedbackInformationBackgroundOnlight, VDSColor.feedbackInformationBackgroundOndark, forKey: .info) + config.setSurfaceColors(VDSColor.feedbackWarningBackgroundOnlight, VDSColor.feedbackWarningBackgroundOndark, forKey: .warning) + config.setSurfaceColors(VDSColor.feedbackSuccessBackgroundOnlight, VDSColor.feedbackSuccessBackgroundOndark, forKey: .success) + config.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forKey: .error) return config }() @@ -145,6 +145,10 @@ public class Notification: View { open override func reset() { super.reset() + type = .info + typeIcon.name = .infoBold + closeButton.name = .close + } //-------------------------------------------------- @@ -153,7 +157,7 @@ public class Notification: View { open override func updateView() { updateTextColorConfig() - backgroundColor = backgroundColorConfiguration.getColor(surface, forState: type) + backgroundColor = backgroundColorConfiguration.getColor(self) typeIcon.name = type.styleIconName() typeIcon.color = surface == .dark ? Icon.Color.white : Icon.Color.black closeButton.color = surface == .dark ? Icon.Color.white : Icon.Color.black From c3ba748728d02b121c1b8bb6f13573d939d78916 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Fri, 17 Mar 2023 11:42:05 +0530 Subject: [PATCH 03/20] color configuration updates --- VDS/Components/Notification/Notification.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index f15f99f2..483d7f9c 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -86,13 +86,13 @@ public class Notification: View { //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- - private var backgroundColorConfiguration: KeyedColorConfiguration = { - let config = KeyedColorConfiguration(keyName: "type") + private var backgroundColorConfiguration: AnyColorable = { + let config = KeyedColorConfiguration(keyPath: \.type) config.setSurfaceColors(VDSColor.feedbackInformationBackgroundOnlight, VDSColor.feedbackInformationBackgroundOndark, forKey: .info) config.setSurfaceColors(VDSColor.feedbackWarningBackgroundOnlight, VDSColor.feedbackWarningBackgroundOndark, forKey: .warning) config.setSurfaceColors(VDSColor.feedbackSuccessBackgroundOnlight, VDSColor.feedbackSuccessBackgroundOndark, forKey: .success) config.setSurfaceColors(VDSColor.feedbackErrorBackgroundOnlight, VDSColor.feedbackErrorBackgroundOndark, forKey: .error) - return config + return config.eraseToAnyColorable() }() private var textColorConfig = ViewColorConfiguration() From 2920559d84275997d3daa95ee109ff352f0136e7 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Sat, 18 Mar 2023 00:25:29 +0530 Subject: [PATCH 04/20] Minor change to the notification view --- .../Notification/Notification.swift | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index 483d7f9c..527ff307 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -55,6 +55,14 @@ public class Notification: View { return UIDevice.isIPad ? VDSLayout.Spacing.space5X.value : VDSLayout.Spacing.space4X.value } + private var minViewHeight: CGFloat { + return UIDevice.isIPad ? VDSLayout.Spacing.space16X.value : VDSLayout.Spacing.space12X.value + } + + private var minContentHeight: CGFloat { + return UIDevice.isIPad ? VDSLayout.Spacing.space5X.value : VDSLayout.Spacing.space4X.value + } + //-------------------------------------------------- // MARK: - View Properties //-------------------------------------------------- @@ -75,7 +83,9 @@ public class Notification: View { $0.textStyle = .bodySmall } - open var buttonsView = ButtonGroup() + open var buttonsView = ButtonGroup().with { + $0.buttonPosition = .left + } //-------------------------------------------------- // MARK: - Modal Properties @@ -130,15 +140,41 @@ public class Notification: View { addSubview(mainStackView) mainStackView.pinToSuperView(.init(top: edgeSpacing, left: edgeSpacing, bottom: edgeSpacing, right: edgeSpacing)) + NSLayoutConstraint.activate([ + heightAnchor.constraint(greaterThanOrEqualToConstant: minViewHeight), + mainStackView.heightAnchor.constraint(greaterThanOrEqualToConstant: minContentHeight) + ]) + mainStackView.addArrangedSubview(typeIcon) mainStackView.addArrangedSubview(labelsView) mainStackView.addArrangedSubview(closeButton) labelsView.addArrangedSubview(titleLabel) labelsView.addArrangedSubview(subTitleLabel) + labelsView.setCustomSpacing(VDSLayout.Spacing.space3X.value, after: subTitleLabel) + + let firstButton = Button().with { + $0.text = "Button 1" + $0.use = .secondary + $0.size = .small + } + + firstButton.publisher(for: .touchUpInside).sink { button in + print("\(button.text) has been pressed") + }.store(in: &subscribers) + + + #warning("Upon adding the button into the stack view, button is visible. Where as ButtonGroup with a single button is not rendered") + + ///This below doesn't work + buttonsView.buttons = [firstButton] labelsView.addArrangedSubview(buttonsView) - publisher(for: UITapGestureRecognizer()).sink { [weak self] _ in + ///This below works + //labelsView.addArrangedSubview(firstButton) + + + closeButton.publisher(for: UITapGestureRecognizer()).sink { [weak self] _ in self?.didClickOnCloseButton() }.store(in: &subscribers) } From 2eee432ac0786e6c90f02bf96bbf629637a7159a Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 17 Mar 2023 14:23:05 -0500 Subject: [PATCH 05/20] updated button for onClickPublisher Signed-off-by: Matt Bruce --- VDS/Components/Buttons/Button/ButtonBase.swift | 18 +++++++++++++++--- VDS/Publishers/UIControlPublisher.swift | 5 ++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/VDS/Components/Buttons/Button/ButtonBase.swift b/VDS/Components/Buttons/Button/ButtonBase.swift index 3ced2661..61b628ce 100644 --- a/VDS/Components/Buttons/Button/ButtonBase.swift +++ b/VDS/Components/Buttons/Button/ButtonBase.swift @@ -29,6 +29,16 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab //-------------------------------------------------- public var subject = PassthroughSubject() public var subscribers = Set() + open var onClickSubscriber: AnyCancellable? { + willSet { + if let onClickSubscriber { + onClickSubscriber.cancel() + } + } + didSet { + enabledHighlight = onClickSubscriber != nil + } + } //-------------------------------------------------- // MARK: - Private Properties @@ -50,10 +60,13 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab open var userInfo = [String: Primitive]() - var isHighlightAnimating = false + internal var enabledHighlight: Bool = false + + internal var isHighlightAnimating = false + open override var isHighlighted: Bool { didSet { - if isHighlightAnimating == false { + if isHighlightAnimating == false && enabledHighlight { isHighlightAnimating = true UIView.animate(withDuration: 0.1, animations: { [weak self] in self?.updateView() @@ -227,4 +240,3 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab } } - diff --git a/VDS/Publishers/UIControlPublisher.swift b/VDS/Publishers/UIControlPublisher.swift index dca48c3f..c7ccfa0c 100644 --- a/VDS/Publishers/UIControlPublisher.swift +++ b/VDS/Publishers/UIControlPublisher.swift @@ -23,8 +23,9 @@ public final class UIControlSubscription Date: Fri, 17 Mar 2023 14:23:20 -0500 Subject: [PATCH 06/20] added onClickPublisher Signed-off-by: Matt Bruce --- VDS/Components/Notification/Notification.swift | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index 527ff307..19dca1c7 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -159,11 +159,10 @@ public class Notification: View { $0.size = .small } - firstButton.publisher(for: .touchUpInside).sink { button in + firstButton.onClickSubscriber = firstButton.publisher(for: .touchUpInside).sink { button in print("\(button.text) has been pressed") - }.store(in: &subscribers) - - + } + #warning("Upon adding the button into the stack view, button is visible. Where as ButtonGroup with a single button is not rendered") ///This below doesn't work From d866a4e3c387ebea863c9c834b44d71663d69038 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 17 Mar 2023 15:35:55 -0500 Subject: [PATCH 07/20] updated buttongroup Signed-off-by: Matt Bruce --- VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift index 7b6c8bdd..ae46f80b 100644 --- a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift +++ b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift @@ -172,9 +172,7 @@ open class ButtonGroup: View, UICollectionViewDataSource, UICollectionViewDelega cell.subviews.forEach { $0.removeFromSuperview() } cell.addSubview(button) cell.buttonable = button - button.pinLeading() - button.pinTrailing() - button.centerYAnchor.constraint(equalTo: cell.centerYAnchor).isActive = true + button.pinToSuperView() return cell } From 05e23f7d58077f107cf9cbb847656c58d0288d56 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 17 Mar 2023 15:36:06 -0500 Subject: [PATCH 08/20] refactored text into properties Signed-off-by: Matt Bruce --- .../Notification/Notification.swift | 119 +++++++++++------- 1 file changed, 75 insertions(+), 44 deletions(-) diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index 19dca1c7..8d422345 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -86,6 +86,16 @@ public class Notification: View { open var buttonsView = ButtonGroup().with { $0.buttonPosition = .left } + + //Text + open var titleText: String? { didSet{didChange()}} + + open var subTitleText: String? { didSet{didChange()}} + + //Buttons (will need to think about this one, probably create a model and follow how Tilelet is working) + open var primaryButton: Button? { didSet{didChange()}} + + open var secondaryButton: Button? { didSet{didChange()}} //-------------------------------------------------- // MARK: - Modal Properties @@ -105,17 +115,11 @@ public class Notification: View { return config.eraseToAnyColorable() }() - private var textColorConfig = ViewColorConfiguration() - public func updateTextColorConfig() { - textColorConfig.reset() - - switch type { - case .info, .success, .warning, .error: - textColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false) - textColorConfig.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: true) - } + private var textColorConfig = ViewColorConfiguration().with { + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false) + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: true) } - + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -134,7 +138,7 @@ public class Notification: View { //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- - + open override func setup() { super.setup() addSubview(mainStackView) @@ -148,34 +152,14 @@ public class Notification: View { mainStackView.addArrangedSubview(typeIcon) mainStackView.addArrangedSubview(labelsView) mainStackView.addArrangedSubview(closeButton) - - labelsView.addArrangedSubview(titleLabel) - labelsView.addArrangedSubview(subTitleLabel) - labelsView.setCustomSpacing(VDSLayout.Spacing.space3X.value, after: subTitleLabel) - - let firstButton = Button().with { - $0.text = "Button 1" - $0.use = .secondary - $0.size = .small - } - - firstButton.onClickSubscriber = firstButton.publisher(for: .touchUpInside).sink { button in - print("\(button.text) has been pressed") - } - #warning("Upon adding the button into the stack view, button is visible. Where as ButtonGroup with a single button is not rendered") - - ///This below doesn't work - buttonsView.buttons = [firstButton] - labelsView.addArrangedSubview(buttonsView) - - ///This below works - //labelsView.addArrangedSubview(firstButton) - - closeButton.publisher(for: UITapGestureRecognizer()).sink { [weak self] _ in self?.didClickOnCloseButton() }.store(in: &subscribers) + + //labels + titleLabel.textColorConfiguration = textColorConfig.eraseToAnyColorable() + subTitleLabel.textColorConfiguration = textColorConfig.eraseToAnyColorable() } open override func reset() { @@ -183,25 +167,72 @@ public class Notification: View { type = .info typeIcon.name = .infoBold closeButton.name = .close - } - + //-------------------------------------------------- // MARK: - State //-------------------------------------------------- open override func updateView() { - updateTextColorConfig() - backgroundColor = backgroundColorConfiguration.getColor(self) + updateIcons() + updateLabels() + updateButtons() + } + + private func updateIcons() { + let iconColor = surface == .dark ? Icon.Color.white : Icon.Color.black typeIcon.name = type.styleIconName() - typeIcon.color = surface == .dark ? Icon.Color.white : Icon.Color.black - closeButton.color = surface == .dark ? Icon.Color.white : Icon.Color.black - titleLabel.textColorConfiguration = textColorConfig.eraseToAnyColorable() - subTitleLabel.textColorConfiguration = textColorConfig.eraseToAnyColorable() - + typeIcon.color = iconColor + closeButton.color = iconColor + } + + private func updateLabels() { titleLabel.surface = surface subTitleLabel.surface = surface + if let titleText { + titleLabel.text = titleText + labelsView.addArrangedSubview(titleLabel) + } else { + titleLabel.removeFromSuperview() + } + + if let subTitleText { + subTitleLabel.text = subTitleText + labelsView.addArrangedSubview(subTitleLabel) + } else { + subTitleLabel.removeFromSuperview() + } + + } + + private func updateButtons() { + var buttons: [Button] = [] + if let primaryButton { + primaryButton.size = .small + primaryButton.use = .primary + buttons.append(primaryButton) + } + + if let secondaryButton { + secondaryButton.size = .small + secondaryButton.use = .secondary + buttons.append(secondaryButton) + } + + if buttons.isEmpty { + labelsView.setCustomSpacing(0, after: subTitleLabel) + buttonsView.removeFromSuperview() + } else { + labelsView.setCustomSpacing(VDSLayout.Spacing.space3X.value, after: subTitleLabel) + ///This below doesn't work + buttonsView.buttons = buttons + labelsView.addArrangedSubview(buttonsView) + + buttonsView + .pinLeading() + .pinTrailing() + } } func didClickOnCloseButton() { From 684a343b0f3e4ff219496905e076f222c9367b48 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 17 Mar 2023 15:55:33 -0500 Subject: [PATCH 09/20] added temp ButtonModel Signed-off-by: Matt Bruce --- .../Notification/Notification.swift | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index 8d422345..607bcc02 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -13,6 +13,15 @@ import VDSColorTokens /// A VDS Component that will render a view with information public class Notification: View { + public struct ButtonModel { + public var text: String + public var onClick: (Button) -> () + public init(text: String, onClick: @escaping (Button) -> Void) { + self.text = text + self.onClick = onClick + } + } + //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- @@ -87,15 +96,25 @@ public class Notification: View { $0.buttonPosition = .left } + #warning("we want to add only the things that are needed, everything else should be hidden, meaning don't access controls directly") //Text open var titleText: String? { didSet{didChange()}} open var subTitleText: String? { didSet{didChange()}} - //Buttons (will need to think about this one, probably create a model and follow how Tilelet is working) - open var primaryButton: Button? { didSet{didChange()}} + #warning("will need to think about this one, probably create a model that has 2 props - text, onClick = (Button) -> () so we are not accessing the button directly. The only reason why I leave it open is for things like accessibility, but not for setting properties outside of this class. More or less follow how Tilelet is working, look at that, below is a temp fix until we can discuss with the guys") + //Buttons + open var primaryButtonModel: ButtonModel? { didSet{didChange()}} + open var primaryButton = Button().with { + $0.size = .small + $0.use = .primary + } - open var secondaryButton: Button? { didSet{didChange()}} + open var secondaryButtonModel: ButtonModel? { didSet{didChange()}} + open var secondaryButton = Button().with { + $0.size = .small + $0.use = .secondary + } //-------------------------------------------------- // MARK: - Modal Properties @@ -208,15 +227,23 @@ public class Notification: View { private func updateButtons() { var buttons: [Button] = [] - if let primaryButton { - primaryButton.size = .small - primaryButton.use = .primary + if let primaryButtonModel { + primaryButton.text = primaryButtonModel.text + primaryButton.onClickSubscriber = primaryButton + .publisher(for: .touchUpInside) + .sink(receiveValue: { button in + primaryButtonModel.onClick(button) + }) buttons.append(primaryButton) } - if let secondaryButton { - secondaryButton.size = .small - secondaryButton.use = .secondary + if let secondaryButtonModel { + secondaryButton.text = secondaryButtonModel.text + secondaryButton.onClickSubscriber = secondaryButton + .publisher(for: .touchUpInside) + .sink(receiveValue: { button in + secondaryButtonModel.onClick(button) + }) buttons.append(secondaryButton) } From cc3d65bd0bd19f5755b9f0d5096230296351f581 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Mon, 20 Mar 2023 12:19:18 +0530 Subject: [PATCH 10/20] Setting surface parameter to buttons --- VDS/Components/Notification/Notification.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index 607bcc02..0e17f313 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -107,7 +107,7 @@ public class Notification: View { open var primaryButtonModel: ButtonModel? { didSet{didChange()}} open var primaryButton = Button().with { $0.size = .small - $0.use = .primary + $0.use = .secondary } open var secondaryButtonModel: ButtonModel? { didSet{didChange()}} @@ -229,6 +229,7 @@ public class Notification: View { var buttons: [Button] = [] if let primaryButtonModel { primaryButton.text = primaryButtonModel.text + primaryButton.surface = surface primaryButton.onClickSubscriber = primaryButton .publisher(for: .touchUpInside) .sink(receiveValue: { button in @@ -239,6 +240,7 @@ public class Notification: View { if let secondaryButtonModel { secondaryButton.text = secondaryButtonModel.text + secondaryButton.surface = surface secondaryButton.onClickSubscriber = secondaryButton .publisher(for: .touchUpInside) .sink(receiveValue: { button in From d04f138da466d44945ab2217f5c69da6eba765b1 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Fri, 24 Mar 2023 23:13:37 +0530 Subject: [PATCH 11/20] updating notification reset components --- VDS.xcodeproj/project.pbxproj | 12 +++++ .../Notification/Notification.swift | 53 ++++--------------- .../NotificationButtonModel.swift | 19 +++++++ .../NotificationSubTitleModel.swift | 26 +++++++++ .../Notification/NotificationTitleModel.swift | 25 +++++++++ 5 files changed, 91 insertions(+), 44 deletions(-) create mode 100644 VDS/Components/Notification/NotificationButtonModel.swift create mode 100644 VDS/Components/Notification/NotificationSubTitleModel.swift create mode 100644 VDS/Components/Notification/NotificationTitleModel.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 1a695824..e62e7761 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -8,6 +8,9 @@ /* Begin PBXBuildFile section */ 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; + 44604AD029CE17EC00E62B51 /* NotificationTitleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604ACF29CE17EC00E62B51 /* NotificationTitleModel.swift */; }; + 44604AD229CE180F00E62B51 /* NotificationSubTitleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD129CE180F00E62B51 /* NotificationSubTitleModel.swift */; }; + 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; }; 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; }; 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */; }; @@ -122,6 +125,9 @@ /* Begin PBXFileReference section */ 445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; + 44604ACF29CE17EC00E62B51 /* NotificationTitleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationTitleModel.swift; sourceTree = ""; }; + 44604AD129CE180F00E62B51 /* NotificationSubTitleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSubTitleModel.swift; sourceTree = ""; }; + 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = ""; }; 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = ""; }; 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroup.swift; sourceTree = ""; }; @@ -251,6 +257,9 @@ isa = PBXGroup; children = ( 445BA07729C07B3D0036A7C5 /* Notification.swift */, + 44604ACF29CE17EC00E62B51 /* NotificationTitleModel.swift */, + 44604AD129CE180F00E62B51 /* NotificationSubTitleModel.swift */, + 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */, ); path = Notification; sourceTree = ""; @@ -775,6 +784,7 @@ EA33622E2891EA3C0071C351 /* DispatchQueue+Once.swift in Sources */, EA4DB2FD28D3D0CA00103EE3 /* AnyEquatable.swift in Sources */, EAA5EEB728ECC03A003B3210 /* ToolTipLabelAttribute.swift in Sources */, + 44604AD029CE17EC00E62B51 /* NotificationTitleModel.swift in Sources */, EA5E305A29510F8B0082B959 /* EnumSubset.swift in Sources */, EA985BF7296C665E00F2FF2E /* IconName.swift in Sources */, EAF7F0AF289B144C00B287F5 /* UnderlineLabelAttribute.swift in Sources */, @@ -801,6 +811,7 @@ EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */, EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */, EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */, + 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */, EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */, EAF7F0B9289C139800B287F5 /* ColorConfiguration.swift in Sources */, EA3361BD288B2C760071C351 /* TypeAlias.swift in Sources */, @@ -808,6 +819,7 @@ EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */, EAF7F0A2289AFB3900B287F5 /* Errorable.swift in Sources */, EA985C7D297DAED300F2FF2E /* Primitive.swift in Sources */, + 44604AD229CE180F00E62B51 /* NotificationSubTitleModel.swift in Sources */, EAB5FEF829393A7200998C17 /* ButtonGroupConstants.swift in Sources */, EA3361AF288B26310071C351 /* FormFieldable.swift in Sources */, EA5E3058295105A40082B959 /* Tilelet.swift in Sources */, diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index 0e17f313..46a15ad9 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -12,16 +12,7 @@ import VDSColorTokens @objc(VDSNotification) /// A VDS Component that will render a view with information public class Notification: View { - - public struct ButtonModel { - public var text: String - public var onClick: (Button) -> () - public init(text: String, onClick: @escaping (Button) -> Void) { - self.text = text - self.onClick = onClick - } - } - + //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- @@ -95,8 +86,7 @@ public class Notification: View { open var buttonsView = ButtonGroup().with { $0.buttonPosition = .left } - - #warning("we want to add only the things that are needed, everything else should be hidden, meaning don't access controls directly") + //Text open var titleText: String? { didSet{didChange()}} @@ -183,6 +173,13 @@ public class Notification: View { open override func reset() { super.reset() + + titleLabel.reset() + subTitleLabel.reset() + buttonsView.reset() + primaryButton.reset() + secondaryButton.reset() + type = .info typeIcon.name = .infoBold closeButton.name = .close @@ -267,37 +264,5 @@ public class Notification: View { func didClickOnCloseButton() { print("Notification close button clicked!!!") } - - ///Temporary Place holder - public struct TitleModel { - public var text: String - public var textAttributes: [any LabelAttributeModel]? - public var textStyle: TextStyle = .boldBodySmall - public var numberOfLines: Int - - public init(text: String, - textAttributes: [any LabelAttributeModel]? = nil, - numberOfLines: Int = 0) { - self.text = text - self.textAttributes = textAttributes - self.numberOfLines = numberOfLines - } - } - - public struct SubTitleModel { - public var text: String - public var textAttributes: [any LabelAttributeModel]? - public var textStyle: TextStyle = .bodySmall - public var numberOfLines: Int - - public init(text: String, - textColor: Use = .primary, - textAttributes: [any LabelAttributeModel]? = nil, - numberOfLines: Int = 0) { - self.text = text - self.textAttributes = textAttributes - self.numberOfLines = numberOfLines - } - } } diff --git a/VDS/Components/Notification/NotificationButtonModel.swift b/VDS/Components/Notification/NotificationButtonModel.swift new file mode 100644 index 00000000..6876aa7c --- /dev/null +++ b/VDS/Components/Notification/NotificationButtonModel.swift @@ -0,0 +1,19 @@ +// +// NotificationButtonModel.swift +// VDS +// +// Created by Nadigadda, Sumanth on 24/03/23. +// + +import Foundation + +extension Notification { + public struct ButtonModel { + public var text: String + public var onClick: (Button) -> () + public init(text: String, onClick: @escaping (Button) -> Void) { + self.text = text + self.onClick = onClick + } + } +} diff --git a/VDS/Components/Notification/NotificationSubTitleModel.swift b/VDS/Components/Notification/NotificationSubTitleModel.swift new file mode 100644 index 00000000..19d4c810 --- /dev/null +++ b/VDS/Components/Notification/NotificationSubTitleModel.swift @@ -0,0 +1,26 @@ +// +// NotificationSubTitleModel.swift +// VDS +// +// Created by Nadigadda, Sumanth on 24/03/23. +// + +import Foundation + +extension Notification { + public struct SubTitleModel { + public var text: String + public var textAttributes: [any LabelAttributeModel]? + public var textStyle: TextStyle = .bodySmall + public var numberOfLines: Int + + public init(text: String, + textColor: Use = .primary, + textAttributes: [any LabelAttributeModel]? = nil, + numberOfLines: Int = 0) { + self.text = text + self.textAttributes = textAttributes + self.numberOfLines = numberOfLines + } + } +} diff --git a/VDS/Components/Notification/NotificationTitleModel.swift b/VDS/Components/Notification/NotificationTitleModel.swift new file mode 100644 index 00000000..31048b4d --- /dev/null +++ b/VDS/Components/Notification/NotificationTitleModel.swift @@ -0,0 +1,25 @@ +// +// NotificationTitleModel.swift +// VDS +// +// Created by Nadigadda, Sumanth on 24/03/23. +// + +import Foundation + +extension Notification { + public struct TitleModel { + public var text: String + public var textAttributes: [any LabelAttributeModel]? + public var textStyle: TextStyle = .boldBodySmall + public var numberOfLines: Int + + public init(text: String, + textAttributes: [any LabelAttributeModel]? = nil, + numberOfLines: Int = 0) { + self.text = text + self.textAttributes = textAttributes + self.numberOfLines = numberOfLines + } + } +} From ee3cd0c3b985dd47f43839ebc50572499af0e424 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 28 Mar 2023 15:27:02 -0500 Subject: [PATCH 12/20] updated font Signed-off-by: Matt Bruce --- VDS/Components/Notification/Notification.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index 46a15ad9..7b6c358d 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -76,11 +76,11 @@ public class Notification: View { } open var titleLabel = Label().with { - $0.textStyle = .boldBodySmall + $0.textStyle = .boldBodyLarge } open var subTitleLabel = Label().with { - $0.textStyle = .bodySmall + $0.textStyle = .bodyLarge } open var buttonsView = ButtonGroup().with { From 02a5c1022d6e010949c27d6b9150d112fc6ae07f Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 29 Mar 2023 11:13:05 -0500 Subject: [PATCH 13/20] fixed bug in drawing Signed-off-by: Matt Bruce --- VDS/Components/RadioButton/RadioButton.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/VDS/Components/RadioButton/RadioButton.swift b/VDS/Components/RadioButton/RadioButton.swift index a8938ad6..edc2fdc0 100644 --- a/VDS/Components/RadioButton/RadioButton.swift +++ b/VDS/Components/RadioButton/RadioButton.swift @@ -335,8 +335,8 @@ open class RadioButtonBase: Control, Errorable { self.shapeLayer = nil } - let bounds = selectorView.bounds - let length = max(bounds.size.height, bounds.size.width) + let bounds = radioButtonSize + let length = max(bounds.height, bounds.width) guard length > 0.0, shapeLayer == nil else { return } //get the colors @@ -346,7 +346,7 @@ open class RadioButtonBase: Control, Errorable { selectorView.backgroundColor = backgroundColor selectorView.layer.borderColor = borderColor.cgColor - selectorView.layer.cornerRadius = selectorView.bounds.width * 0.5 + selectorView.layer.cornerRadius = bounds.width * 0.5 selectorView.layer.borderWidth = VDSFormControls.widthBorder if shapeLayer == nil { @@ -357,7 +357,7 @@ open class RadioButtonBase: Control, Errorable { height: radioButtonSelectedSize.height)) let shapeLayer = CAShapeLayer() self.shapeLayer = shapeLayer - shapeLayer.frame = bounds + shapeLayer.frame = selectorView.bounds layer.addSublayer(shapeLayer) shapeLayer.fillColor = radioSelectedColor.cgColor shapeLayer.path = bezierPath.cgPath From 01725e634f46ea2c722ead214343c7afea9526e4 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 29 Mar 2023 13:46:55 -0500 Subject: [PATCH 14/20] added clickable removed old code Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 34 ++++++++--------- VDS/Protocols/Clickable.swift | 49 +++++++++++++++++++++++++ VDS/Publishers/Publisher+Bind.swift | 24 ------------ VDS/Publishers/UIButton+Publisher.swift | 17 --------- 4 files changed, 64 insertions(+), 60 deletions(-) create mode 100644 VDS/Protocols/Clickable.swift delete mode 100644 VDS/Publishers/Publisher+Bind.swift delete mode 100644 VDS/Publishers/UIButton+Publisher.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index fbdf5c5c..3b468221 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -7,11 +7,11 @@ objects = { /* Begin PBXBuildFile section */ - 44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; }; 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; 44604AD029CE17EC00E62B51 /* NotificationTitleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604ACF29CE17EC00E62B51 /* NotificationTitleModel.swift */; }; 44604AD229CE180F00E62B51 /* NotificationSubTitleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD129CE180F00E62B51 /* NotificationSubTitleModel.swift */; }; 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; }; + 44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; }; 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; }; 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */; }; @@ -48,7 +48,6 @@ EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E30522950DDA60082B959 /* TitleLockup.swift */; }; EA5E3058295105A40082B959 /* Tilelet.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E3057295105A40082B959 /* Tilelet.swift */; }; EA5E305A29510F8B0082B959 /* EnumSubset.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E305929510F8B0082B959 /* EnumSubset.swift */; }; - EA89200228AECF2A006B9984 /* UIButton+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200128AECF2A006B9984 /* UIButton+Publisher.swift */; }; EA89200428AECF4B006B9984 /* UITextField+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */; }; EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200528B526D6006B9984 /* CheckboxGroup.swift */; }; EA89201328B568D8006B9984 /* RadioBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89201228B568D8006B9984 /* RadioBox.swift */; }; @@ -80,7 +79,6 @@ EAB1D29C28A5618900DAE764 /* RadioButtonGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D29B28A5618900DAE764 /* RadioButtonGroup.swift */; }; EAB1D2CD28ABE76100DAE764 /* Withable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D2CC28ABE76000DAE764 /* Withable.swift */; }; EAB1D2CF28ABEF2B00DAE764 /* Typography.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D2CE28ABEF2B00DAE764 /* Typography.swift */; }; - EAB1D2E628AE842000DAE764 /* Publisher+Bind.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D2E328AE842000DAE764 /* Publisher+Bind.swift */; }; EAB1D2EA28AE84AA00DAE764 /* UIControlPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D2E928AE84AA00DAE764 /* UIControlPublisher.swift */; }; EAB5FED429267EB300998C17 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FED329267EB300998C17 /* UIView.swift */; }; EAB5FEED2927E1B200998C17 /* ButtonGroupPositionLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEEC2927E1B200998C17 /* ButtonGroupPositionLayout.swift */; }; @@ -95,6 +93,7 @@ EAC9258C2911C9DE00091998 /* InputField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925872911C9DE00091998 /* InputField.swift */; }; EAC9258F2911C9DE00091998 /* EntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC9258B2911C9DE00091998 /* EntryField.swift */; }; EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */; }; + EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9829D4850E00101452 /* Clickable.swift */; }; EAF7F0952899861000B287F5 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0932899861000B287F5 /* Checkbox.swift */; }; EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0992899B17200B287F5 /* CATransaction.swift */; }; EAF7F09E289AAEC000B287F5 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F09D289AAEC000B287F5 /* Constants.swift */; }; @@ -125,11 +124,11 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; 445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 44604ACF29CE17EC00E62B51 /* NotificationTitleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationTitleModel.swift; sourceTree = ""; }; 44604AD129CE180F00E62B51 /* NotificationSubTitleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSubTitleModel.swift; sourceTree = ""; }; 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = ""; }; + 44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = ""; }; 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; EA0FC2C52914222900DF80B4 /* ButtonGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroup.swift; sourceTree = ""; }; @@ -167,7 +166,6 @@ EA5E30522950DDA60082B959 /* TitleLockup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockup.swift; sourceTree = ""; }; EA5E3057295105A40082B959 /* Tilelet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tilelet.swift; sourceTree = ""; }; EA5E305929510F8B0082B959 /* EnumSubset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnumSubset.swift; sourceTree = ""; }; - EA89200128AECF2A006B9984 /* UIButton+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+Publisher.swift"; sourceTree = ""; }; EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextField+Publisher.swift"; sourceTree = ""; }; EA89200528B526D6006B9984 /* CheckboxGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxGroup.swift; sourceTree = ""; }; EA89201228B568D8006B9984 /* RadioBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioBox.swift; sourceTree = ""; }; @@ -200,7 +198,6 @@ EAB1D29B28A5618900DAE764 /* RadioButtonGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonGroup.swift; sourceTree = ""; }; EAB1D2CC28ABE76000DAE764 /* Withable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Withable.swift; sourceTree = ""; }; EAB1D2CE28ABEF2B00DAE764 /* Typography.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Typography.swift; sourceTree = ""; }; - EAB1D2E328AE842000DAE764 /* Publisher+Bind.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Publisher+Bind.swift"; sourceTree = ""; }; EAB1D2E928AE84AA00DAE764 /* UIControlPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControlPublisher.swift; sourceTree = ""; }; EAB5FED329267EB300998C17 /* UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = ""; }; EAB5FEEC2927E1B200998C17 /* ButtonGroupPositionLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupPositionLayout.swift; sourceTree = ""; }; @@ -214,6 +211,7 @@ EAC925872911C9DE00091998 /* InputField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputField.swift; sourceTree = ""; }; EAC9258B2911C9DE00091998 /* EntryField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntryField.swift; sourceTree = ""; }; EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIGestureRecognizer+Publisher.swift"; sourceTree = ""; }; + EAF1FE9829D4850E00101452 /* Clickable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clickable.swift; sourceTree = ""; }; EAF7F0932899861000B287F5 /* Checkbox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = ""; }; EAF7F0992899B17200B287F5 /* CATransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CATransaction.swift; sourceTree = ""; }; EAF7F09D289AAEC000B287F5 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; @@ -255,14 +253,6 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 44604AD529CE195300E62B51 /* Line */ = { - isa = PBXGroup; - children = ( - 44604AD629CE196600E62B51 /* Line.swift */, - ); - path = Line; - sourceTree = ""; - }; 445BA07629C07ABA0036A7C5 /* Notification */ = { isa = PBXGroup; children = ( @@ -274,6 +264,14 @@ path = Notification; sourceTree = ""; }; + 44604AD529CE195300E62B51 /* Line */ = { + isa = PBXGroup; + children = ( + 44604AD629CE196600E62B51 /* Line.swift */, + ); + path = Line; + sourceTree = ""; + }; 5FC35BE128D513EB004EBEAC /* Button */ = { isa = PBXGroup; children = ( @@ -376,12 +374,12 @@ EA0FC2BE2912D18200DF80B4 /* Buttons */, EAF7F092289985E200B287F5 /* Checkbox */, EA985BF3296C609E00F2FF2E /* Icon */, - EA1F265F28B945070033E859 /* RadioSwatch */, EA3362412892EF700071C351 /* Label */, 44604AD529CE195300E62B51 /* Line */, 445BA07629C07ABA0036A7C5 /* Notification */, EA89200B28B530F0006B9984 /* RadioBox */, EAF7F11428A1470D00B287F5 /* RadioButton */, + EA1F265F28B945070033E859 /* RadioSwatch */, EAC925852911C9DE00091998 /* TextFields */, EA5E304A294CBDBB0082B959 /* TileContainer */, EA5E3056295105930082B959 /* Tilelet */, @@ -420,6 +418,7 @@ isa = PBXGroup; children = ( EA4DB2FC28D3D0CA00103EE3 /* AnyEquatable.swift */, + EAF1FE9829D4850E00101452 /* Clickable.swift */, EAA5EEDF28F49DB3003B3210 /* Colorable.swift */, EA3361A9288B25E40071C351 /* Disabling.swift */, EA5E305929510F8B0082B959 /* EnumSubset.swift */, @@ -577,8 +576,6 @@ EAB1D2E228AE842000DAE764 /* Publishers */ = { isa = PBXGroup; children = ( - EAB1D2E328AE842000DAE764 /* Publisher+Bind.swift */, - EA89200128AECF2A006B9984 /* UIButton+Publisher.swift */, EAB1D2E928AE84AA00DAE764 /* UIControlPublisher.swift */, EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */, EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */, @@ -830,6 +827,7 @@ EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */, EAF7F0A2289AFB3900B287F5 /* Errorable.swift in Sources */, EA985C7D297DAED300F2FF2E /* Primitive.swift in Sources */, + EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */, 44604AD229CE180F00E62B51 /* NotificationSubTitleModel.swift in Sources */, EAB5FEF829393A7200998C17 /* ButtonGroupConstants.swift in Sources */, EA3361AF288B26310071C351 /* FormFieldable.swift in Sources */, @@ -841,7 +839,6 @@ EA985C1D296CD13600F2FF2E /* BundleManager.swift in Sources */, EA1F266528B945070033E859 /* RadioSwatch.swift in Sources */, EA4DB18528CA967F00103EE3 /* SelectorGroupHandlerBase.swift in Sources */, - EA89200228AECF2A006B9984 /* UIButton+Publisher.swift in Sources */, EAF7F0AB289B13FD00B287F5 /* TextStyleLabelAttribute.swift in Sources */, EAB1D29C28A5618900DAE764 /* RadioButtonGroup.swift in Sources */, EA985BE629688F6A00F2FF2E /* TileletBadgeModel.swift in Sources */, @@ -850,7 +847,6 @@ EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */, EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */, EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */, - EAB1D2E628AE842000DAE764 /* Publisher+Bind.swift in Sources */, EA985BF5296C60C000F2FF2E /* Icon.swift in Sources */, EA3361AA288B25E40071C351 /* Disabling.swift in Sources */, EA3361B6288B2A410071C351 /* Control.swift in Sources */, diff --git a/VDS/Protocols/Clickable.swift b/VDS/Protocols/Clickable.swift new file mode 100644 index 00000000..3ce3eed6 --- /dev/null +++ b/VDS/Protocols/Clickable.swift @@ -0,0 +1,49 @@ +// +// Clickable.swift +// VDS +// +// Created by Matt Bruce on 3/29/23. +// + +import Foundation +import UIKit + +public protocol Clickable where Self: UIControl { + var onClick: ((Self) -> ())? { get set } + func setupOnClick() +} + +extension Clickable where Self: Handlerable { + public func addEvent(event: UIControl.Event, block: @escaping (Self)->()) { + publisher(for: event) + .sink(receiveValue: { c in + block(c) + }).store(in: &subscribers) + } +} + +extension Clickable where Self: Control { + public func setupOnClick() { + if let onClick { + onClickSubscriber = publisher(for: .touchUpInside) + .sink(receiveValue: { c in + onClick(c) + }) + } else { + onClickSubscriber = nil + } + } +} + +extension Clickable where Self: ButtonBase { + public func setupOnClick() { + if let onClick { + onClickSubscriber = publisher(for: .touchUpInside) + .sink(receiveValue: { c in + onClick(c) + }) + } else { + onClickSubscriber = nil + } + } +} diff --git a/VDS/Publishers/Publisher+Bind.swift b/VDS/Publishers/Publisher+Bind.swift deleted file mode 100644 index 33fcaa94..00000000 --- a/VDS/Publishers/Publisher+Bind.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// Publisher+Bind.swift -// VDS -// -// Created by Matt Bruce on 8/18/22. -// - -import Foundation -import Combine - -public typealias Binding = Subscriber - -public extension Publisher where Failure == Never { - func bind(subscriber: B) -> AnyCancellable - where B.Failure == Never, B.Input == Output { - - handleEvents(receiveSubscription: { subscription in - subscriber.receive(subscription: subscription) - }) - .sink { value in - _ = subscriber.receive(value) - } - } -} diff --git a/VDS/Publishers/UIButton+Publisher.swift b/VDS/Publishers/UIButton+Publisher.swift deleted file mode 100644 index 6d669dfd..00000000 --- a/VDS/Publishers/UIButton+Publisher.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// Button+Publisher.swift -// VDS -// -// Created by Matt Bruce on 8/18/22. -// - -import Foundation -import UIKit -import Combine - -extension UIButton { - public var tapPublisher: AnyPublisher { - publisher(for: .touchUpInside) - .eraseToAnyPublisher() - } -} From aa233515a5478f4ff8cf6d1b6758f6bc5fb4ac08 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 29 Mar 2023 13:47:56 -0500 Subject: [PATCH 15/20] 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() From ac8d4e707ba6ba4c672240a10fdebb2f55878caa Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 29 Mar 2023 13:48:09 -0500 Subject: [PATCH 16/20] updated buttonbase other buttons Signed-off-by: Matt Bruce --- VDS/Components/Buttons/Button/Button.swift | 4 +++- VDS/Components/Buttons/Button/ButtonBase.swift | 2 +- VDS/Components/Buttons/TextLink/TextLink.swift | 4 +++- VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift | 4 +++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/VDS/Components/Buttons/Button/Button.swift b/VDS/Components/Buttons/Button/Button.swift index 0b52e0fe..13823178 100644 --- a/VDS/Components/Buttons/Button/Button.swift +++ b/VDS/Components/Buttons/Button/Button.swift @@ -17,7 +17,7 @@ public enum ButtonSize: String, CaseIterable { } @objc(VDSButton) -open class Button: ButtonBase, Useable { +open class Button: ButtonBase, Useable, Clickable { //-------------------------------------------------- // MARK: - Private Properties @@ -30,6 +30,8 @@ open class Button: ButtonBase, Useable { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- + open var onClick: ((Button) -> ())? { didSet { setupOnClick() } } + open override var availableSizes: [ButtonSize] { [.large, .small] } open var use: Use = .primary { didSet { didChange() }} diff --git a/VDS/Components/Buttons/Button/ButtonBase.swift b/VDS/Components/Buttons/Button/ButtonBase.swift index 61b628ce..b8f2d098 100644 --- a/VDS/Components/Buttons/Button/ButtonBase.swift +++ b/VDS/Components/Buttons/Button/ButtonBase.swift @@ -29,7 +29,7 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab //-------------------------------------------------- public var subject = PassthroughSubject() public var subscribers = Set() - open var onClickSubscriber: AnyCancellable? { + internal var onClickSubscriber: AnyCancellable? { willSet { if let onClickSubscriber { onClickSubscriber.cancel() diff --git a/VDS/Components/Buttons/TextLink/TextLink.swift b/VDS/Components/Buttons/TextLink/TextLink.swift index a253a406..3d0ec706 100644 --- a/VDS/Components/Buttons/TextLink/TextLink.swift +++ b/VDS/Components/Buttons/TextLink/TextLink.swift @@ -12,7 +12,7 @@ import VDSFormControlsTokens import Combine @objc(VDSTextLink) -open class TextLink: ButtonBase { +open class TextLink: ButtonBase, Clickable { //-------------------------------------------------- // MARK: - Private Properties @@ -22,6 +22,8 @@ open class TextLink: ButtonBase { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- + open var onClick: ((TextLink) -> ())? { didSet { setupOnClick() } } + open var size: ButtonSize = .large { didSet { didChange() }} open override var availableSizes: [ButtonSize] { [.large, .small] } diff --git a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift index f6ba09a0..a5521a4e 100644 --- a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift +++ b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift @@ -12,7 +12,7 @@ import VDSFormControlsTokens import Combine @objc(VDSTextLinkCaret) -open class TextLinkCaret: ButtonBase { +open class TextLinkCaret: ButtonBase, Clickable { //-------------------------------------------------- // MARK: - Enums @@ -24,6 +24,8 @@ open class TextLinkCaret: ButtonBase { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- + open var onClick: ((TextLinkCaret) -> ())? { didSet { setupOnClick() } } + open override var textStyle: TextStyle { TextStyle.boldBodyLarge } From 94d44c5d5476ec5c85ff978aaf091c27d75cdb68 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 29 Mar 2023 15:37:32 -0500 Subject: [PATCH 17/20] refactored clickable removed old clickable code Signed-off-by: Matt Bruce --- VDS/Classes/Control.swift | 2 +- VDS/Components/Buttons/Button/Button.swift | 4 +- .../Buttons/Button/ButtonBase.swift | 2 +- .../Buttons/TextLink/TextLink.swift | 4 +- .../Buttons/TextLinkCaret/TextLinkCaret.swift | 4 +- VDS/Components/Checkbox/Checkbox.swift | 4 +- VDS/Components/RadioBox/RadioBox.swift | 4 +- VDS/Components/RadioButton/RadioButton.swift | 4 +- VDS/Components/RadioSwatch/RadioSwatch.swift | 6 +-- .../TileContainer/TileContainer.swift | 13 ++--- VDS/Components/Tilelet/Tilelet.swift | 6 +-- VDS/Components/Toggle/Toggle.swift | 6 +-- VDS/Protocols/Clickable.swift | 47 ++++++++++--------- 13 files changed, 43 insertions(+), 63 deletions(-) diff --git a/VDS/Classes/Control.swift b/VDS/Classes/Control.swift index 0efbec97..49ab79b4 100644 --- a/VDS/Classes/Control.swift +++ b/VDS/Classes/Control.swift @@ -10,7 +10,7 @@ import UIKit import Combine @objc(VDSControl) -open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoable { +open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoable, Clickable { //-------------------------------------------------- // MARK: - Combine Properties diff --git a/VDS/Components/Buttons/Button/Button.swift b/VDS/Components/Buttons/Button/Button.swift index 13823178..0b52e0fe 100644 --- a/VDS/Components/Buttons/Button/Button.swift +++ b/VDS/Components/Buttons/Button/Button.swift @@ -17,7 +17,7 @@ public enum ButtonSize: String, CaseIterable { } @objc(VDSButton) -open class Button: ButtonBase, Useable, Clickable { +open class Button: ButtonBase, Useable { //-------------------------------------------------- // MARK: - Private Properties @@ -30,8 +30,6 @@ open class Button: ButtonBase, Useable, Clickable { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - open var onClick: ((Button) -> ())? { didSet { setupOnClick() } } - open override var availableSizes: [ButtonSize] { [.large, .small] } open var use: Use = .primary { didSet { didChange() }} diff --git a/VDS/Components/Buttons/Button/ButtonBase.swift b/VDS/Components/Buttons/Button/ButtonBase.swift index b8f2d098..335722b2 100644 --- a/VDS/Components/Buttons/Button/ButtonBase.swift +++ b/VDS/Components/Buttons/Button/ButtonBase.swift @@ -18,7 +18,7 @@ public protocol Buttonable: UIControl, Surfaceable, Disabling { } @objc(VDSButtonBase) -open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettable, UserInfoable { +open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettable, UserInfoable, Clickable { //-------------------------------------------------- // MARK: - Configuration Properties //-------------------------------------------------- diff --git a/VDS/Components/Buttons/TextLink/TextLink.swift b/VDS/Components/Buttons/TextLink/TextLink.swift index 3d0ec706..a253a406 100644 --- a/VDS/Components/Buttons/TextLink/TextLink.swift +++ b/VDS/Components/Buttons/TextLink/TextLink.swift @@ -12,7 +12,7 @@ import VDSFormControlsTokens import Combine @objc(VDSTextLink) -open class TextLink: ButtonBase, Clickable { +open class TextLink: ButtonBase { //-------------------------------------------------- // MARK: - Private Properties @@ -22,8 +22,6 @@ open class TextLink: ButtonBase, Clickable { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - open var onClick: ((TextLink) -> ())? { didSet { setupOnClick() } } - open var size: ButtonSize = .large { didSet { didChange() }} open override var availableSizes: [ButtonSize] { [.large, .small] } diff --git a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift index a5521a4e..f6ba09a0 100644 --- a/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift +++ b/VDS/Components/Buttons/TextLinkCaret/TextLinkCaret.swift @@ -12,7 +12,7 @@ import VDSFormControlsTokens import Combine @objc(VDSTextLinkCaret) -open class TextLinkCaret: ButtonBase, Clickable { +open class TextLinkCaret: ButtonBase { //-------------------------------------------------- // MARK: - Enums @@ -24,8 +24,6 @@ open class TextLinkCaret: ButtonBase, Clickable { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - open var onClick: ((TextLinkCaret) -> ())? { didSet { setupOnClick() } } - open override var textStyle: TextStyle { TextStyle.boldBodyLarge } diff --git a/VDS/Components/Checkbox/Checkbox.swift b/VDS/Components/Checkbox/Checkbox.swift index 5bc4047b..cfff406e 100644 --- a/VDS/Components/Checkbox/Checkbox.swift +++ b/VDS/Components/Checkbox/Checkbox.swift @@ -13,7 +13,7 @@ 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(VDSCheckboxBase) -open class Checkbox: Control, Errorable, Clickable { +open class Checkbox: Control, Errorable { //-------------------------------------------------- // MARK: - Initializers @@ -63,8 +63,6 @@ open class Checkbox: Control, Errorable, Clickable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - open var onClick: ((Checkbox) -> ())? { didSet { setupOnClick() }} - open var label = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.textPosition = .left diff --git a/VDS/Components/RadioBox/RadioBox.swift b/VDS/Components/RadioBox/RadioBox.swift index d9b93b07..b71c0342 100644 --- a/VDS/Components/RadioBox/RadioBox.swift +++ b/VDS/Components/RadioBox/RadioBox.swift @@ -12,7 +12,7 @@ import VDSFormControlsTokens import Combine @objc(VDSRadioBox) -open class RadioBox: Control, Clickable { +open class RadioBox: Control { //-------------------------------------------------- // MARK: - Initializers @@ -56,8 +56,6 @@ open class RadioBox: Control, Clickable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - open var onClick: ((RadioBox) -> ())? { didSet { setupOnClick() }} - open var textLabel = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.textPosition = .left diff --git a/VDS/Components/RadioButton/RadioButton.swift b/VDS/Components/RadioButton/RadioButton.swift index 83606b05..76d29b46 100644 --- a/VDS/Components/RadioButton/RadioButton.swift +++ b/VDS/Components/RadioButton/RadioButton.swift @@ -11,7 +11,7 @@ import VDSColorTokens import VDSFormControlsTokens @objc(VDSRadioButton) -open class RadioButton: Control, Errorable, Clickable { +open class RadioButton: Control, Errorable { //-------------------------------------------------- // MARK: - Initializers @@ -61,8 +61,6 @@ open class RadioButton: Control, Errorable, Clickable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - open var onClick: ((RadioButton) -> ())? { didSet { setupOnClick() } } - open var label = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.textPosition = .left diff --git a/VDS/Components/RadioSwatch/RadioSwatch.swift b/VDS/Components/RadioSwatch/RadioSwatch.swift index 967a824c..211a3ff5 100644 --- a/VDS/Components/RadioSwatch/RadioSwatch.swift +++ b/VDS/Components/RadioSwatch/RadioSwatch.swift @@ -12,7 +12,7 @@ import VDSFormControlsTokens import Combine @objc(VDSRadioSwatch) -open class RadioSwatch: Control, Clickable { +open class RadioSwatch: Control { //-------------------------------------------------- // MARK: - Initializers @@ -31,9 +31,7 @@ open class RadioSwatch: Control, Clickable { //-------------------------------------------------- // MARK: - Public Properties - //-------------------------------------------------- - open var onClick: ((RadioSwatch) -> ())? { didSet { setupOnClick() } } - + //-------------------------------------------------- public var selectorView = UIView().with { $0.translatesAutoresizingMaskIntoConstraints = false } diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index 371e5bc3..bf0d24a9 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -11,12 +11,7 @@ import VDSFormControlsTokens import UIKit @objc(VDSTileContainer) -open class TileContainer: TileContainerBase, Clickable { - public var onClick: ((TileContainer) -> ())? { didSet { setupOnClick() } } -} - -@objc(VDSTileContainerBase) -open class TileContainerBase: Control { +open class TileContainer: Control { //-------------------------------------------------- // MARK: - Initializers @@ -315,13 +310,13 @@ open class TileContainerBase: Control { } } -extension TileContainerBase { +extension TileContainer { class BackgroundColorConfiguration: ObjectColorable { - typealias ObjectType = TileContainerBase + typealias ObjectType = TileContainer required init() { } - func getColor(_ object: TileContainerBase) -> UIColor { + func getColor(_ object: TileContainer) -> UIColor { switch object.color { case .white: diff --git a/VDS/Components/Tilelet/Tilelet.swift b/VDS/Components/Tilelet/Tilelet.swift index 09a59499..1a956680 100644 --- a/VDS/Components/Tilelet/Tilelet.swift +++ b/VDS/Components/Tilelet/Tilelet.swift @@ -12,7 +12,7 @@ import UIKit import Combine @objc(VDSTilelet) -open class Tilelet: TileContainerBase, Clickable { +open class Tilelet: TileContainer { //-------------------------------------------------- // MARK: - Enums @@ -62,9 +62,7 @@ open class Tilelet: TileContainerBase, Clickable { //-------------------------------------------------- // MARK: - Public Properties - //-------------------------------------------------- - 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 b9e13b6b..05349779 100644 --- a/VDS/Components/Toggle/Toggle.swift +++ b/VDS/Components/Toggle/Toggle.swift @@ -18,7 +18,7 @@ import Combine Knob: The circular indicator that slides on the container. */ @objc(VDSToggle) -open class Toggle: Control, Clickable { +open class Toggle: Control { //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- @@ -70,9 +70,7 @@ open class Toggle: Control, Clickable { //-------------------------------------------------- // 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) diff --git a/VDS/Protocols/Clickable.swift b/VDS/Protocols/Clickable.swift index 3ce3eed6..62c771ce 100644 --- a/VDS/Protocols/Clickable.swift +++ b/VDS/Protocols/Clickable.swift @@ -8,10 +8,7 @@ import Foundation import UIKit -public protocol Clickable where Self: UIControl { - var onClick: ((Self) -> ())? { get set } - func setupOnClick() -} +public protocol Clickable where Self: UIControl {} extension Clickable where Self: Handlerable { public func addEvent(event: UIControl.Event, block: @escaping (Self)->()) { @@ -22,28 +19,34 @@ extension Clickable where Self: Handlerable { } } -extension Clickable where Self: Control { - public func setupOnClick() { - if let onClick { - onClickSubscriber = publisher(for: .touchUpInside) - .sink(receiveValue: { c in - onClick(c) - }) - } else { - onClickSubscriber = nil +extension Clickable where Self: ButtonBase { + public var onClick: ((Self) -> ())? { + get { return nil } + set { + if let newValue { + onClickSubscriber = publisher(for: .touchUpInside) + .sink { c in + newValue(c) + } + } else { + onClickSubscriber = nil + } } } } -extension Clickable where Self: ButtonBase { - public func setupOnClick() { - if let onClick { - onClickSubscriber = publisher(for: .touchUpInside) - .sink(receiveValue: { c in - onClick(c) - }) - } else { - onClickSubscriber = nil +extension Clickable where Self: Control { + public var onClick: ((Self) -> ())? { + get { return nil } + set { + if let newValue { + onClickSubscriber = publisher(for: .touchUpInside) + .sink { c in + newValue(c) + } + } else { + onClickSubscriber = nil + } } } } From f164429ece9b4cfcbbe0be877c7c5318b2fd848a Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 29 Mar 2023 15:48:21 -0500 Subject: [PATCH 18/20] updated onCloseClick Signed-off-by: Matt Bruce --- .../Notification/Notification.swift | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index 1d486322..1ca2422a 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -8,6 +8,7 @@ import Foundation import UIKit import VDSColorTokens +import Combine @objc(VDSNotification) /// A VDS Component that will render a view with information @@ -88,7 +89,7 @@ public class Notification: View { } //Text - open var titleText: String? { didSet{didChange()}} + open var titleText: String = "" { didSet{didChange()}} open var subTitleText: String? { didSet{didChange()}} @@ -106,8 +107,20 @@ public class Notification: View { $0.use = .secondary } - open var onCloseClick: ((Notification)->())? - + open var onCloseClick: ((Notification)->())? { + didSet { + if let onCloseClick { + onCloseSubscriber = closeButton + .publisher(for: UITapGestureRecognizer()) + .sink { _ in + onCloseClick(self) + } + } else { + onCloseSubscriber = nil + } + } + } + internal var onCloseSubscriber: AnyCancellable? //-------------------------------------------------- // MARK: - Modal Properties //-------------------------------------------------- @@ -163,12 +176,7 @@ public class Notification: View { mainStackView.addArrangedSubview(typeIcon) mainStackView.addArrangedSubview(labelsView) mainStackView.addArrangedSubview(closeButton) - - closeButton.publisher(for: UITapGestureRecognizer()).sink { [weak self] _ in - guard let self else { return } - self.onCloseClick?(self) - }.store(in: &subscribers) - + //labels titleLabel.textColorConfiguration = textColorConfig.eraseToAnyColorable() subTitleLabel.textColorConfiguration = textColorConfig.eraseToAnyColorable() @@ -209,7 +217,7 @@ public class Notification: View { titleLabel.surface = surface subTitleLabel.surface = surface - if let titleText { + if !titleText.isEmpty { titleLabel.text = titleText labelsView.addArrangedSubview(titleLabel) } else { From 248caeb480b044fd5bd3407e7a738914157cc633 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 30 Mar 2023 08:43:55 -0500 Subject: [PATCH 19/20] updated for maintaining a clickable count Signed-off-by: Matt Bruce --- VDS/Classes/Control.swift | 9 +++---- .../Buttons/Button/ButtonBase.swift | 10 +++---- .../TextFields/EntryField/EntryField.swift | 1 - VDS/Components/Tilelet/Tilelet.swift | 2 +- VDS/Protocols/Clickable.swift | 27 +++++++------------ VDS/Publishers/UIControlPublisher.swift | 12 +++------ 6 files changed, 21 insertions(+), 40 deletions(-) diff --git a/VDS/Classes/Control.swift b/VDS/Classes/Control.swift index 49ab79b4..2131df8c 100644 --- a/VDS/Classes/Control.swift +++ b/VDS/Classes/Control.swift @@ -17,15 +17,12 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab //-------------------------------------------------- public var subject = PassthroughSubject() public var subscribers = Set() - internal var onClickSubscriber: AnyCancellable? { + public var onClickSubscriber: AnyCancellable? { willSet { if let onClickSubscriber { onClickSubscriber.cancel() } } - didSet { - enabledHighlight = onClickSubscriber != nil - } } //-------------------------------------------------- @@ -41,12 +38,12 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab open override var isSelected: Bool { didSet { didChange() } } - internal var enabledHighlight: Bool = false + public var touchUpInsideCount: Int = 0 var isHighlightAnimating = false open override var isHighlighted: Bool { didSet { - if isHighlightAnimating == false && enabledHighlight { + if isHighlightAnimating == false && isClickable { isHighlightAnimating = true UIView.animate(withDuration: 0.1, animations: { [weak self] in self?.updateView() diff --git a/VDS/Components/Buttons/Button/ButtonBase.swift b/VDS/Components/Buttons/Button/ButtonBase.swift index 335722b2..322f1250 100644 --- a/VDS/Components/Buttons/Button/ButtonBase.swift +++ b/VDS/Components/Buttons/Button/ButtonBase.swift @@ -19,6 +19,7 @@ public protocol Buttonable: UIControl, Surfaceable, Disabling { @objc(VDSButtonBase) open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettable, UserInfoable, Clickable { + //-------------------------------------------------- // MARK: - Configuration Properties //-------------------------------------------------- @@ -29,15 +30,12 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab //-------------------------------------------------- public var subject = PassthroughSubject() public var subscribers = Set() - internal var onClickSubscriber: AnyCancellable? { + public var onClickSubscriber: AnyCancellable? { willSet { if let onClickSubscriber { onClickSubscriber.cancel() } } - didSet { - enabledHighlight = onClickSubscriber != nil - } } //-------------------------------------------------- @@ -60,13 +58,13 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab open var userInfo = [String: Primitive]() - internal var enabledHighlight: Bool = false + public var touchUpInsideCount: Int = 0 internal var isHighlightAnimating = false open override var isHighlighted: Bool { didSet { - if isHighlightAnimating == false && enabledHighlight { + if isHighlightAnimating == false && isClickable { isHighlightAnimating = true UIView.animate(withDuration: 0.1, animations: { [weak self] in self?.updateView() diff --git a/VDS/Components/TextFields/EntryField/EntryField.swift b/VDS/Components/TextFields/EntryField/EntryField.swift index 321aa074..a773ac43 100644 --- a/VDS/Components/TextFields/EntryField/EntryField.swift +++ b/VDS/Components/TextFields/EntryField/EntryField.swift @@ -172,7 +172,6 @@ open class EntryField: Control { open override func setup() { super.setup() - enabledHighlight = false isAccessibilityElement = true accessibilityTraits = .button addSubview(stackView) diff --git a/VDS/Components/Tilelet/Tilelet.swift b/VDS/Components/Tilelet/Tilelet.swift index 1a956680..c6d36858 100644 --- a/VDS/Components/Tilelet/Tilelet.swift +++ b/VDS/Components/Tilelet/Tilelet.swift @@ -63,7 +63,7 @@ open class Tilelet: TileContainer { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - internal override var onClickSubscriber: AnyCancellable? { + public override var onClickSubscriber: AnyCancellable? { didSet { isAccessibilityElement = onClickSubscriber != nil } diff --git a/VDS/Protocols/Clickable.swift b/VDS/Protocols/Clickable.swift index 62c771ce..1bf454f6 100644 --- a/VDS/Protocols/Clickable.swift +++ b/VDS/Protocols/Clickable.swift @@ -7,8 +7,12 @@ import Foundation import UIKit +import Combine -public protocol Clickable where Self: UIControl {} +public protocol Clickable where Self: UIControl { + var touchUpInsideCount: Int { get set } + var onClickSubscriber: AnyCancellable? { get set } +} extension Clickable where Self: Handlerable { public func addEvent(event: UIControl.Event, block: @escaping (Self)->()) { @@ -17,25 +21,11 @@ extension Clickable where Self: Handlerable { block(c) }).store(in: &subscribers) } + + internal var isClickable: Bool { return touchUpInsideCount > 0 } } -extension Clickable where Self: ButtonBase { - public var onClick: ((Self) -> ())? { - get { return nil } - set { - if let newValue { - onClickSubscriber = publisher(for: .touchUpInside) - .sink { c in - newValue(c) - } - } else { - onClickSubscriber = nil - } - } - } -} - -extension Clickable where Self: Control { +extension Clickable { public var onClick: ((Self) -> ())? { get { return nil } set { @@ -45,6 +35,7 @@ extension Clickable where Self: Control { newValue(c) } } else { + onClickSubscriber?.cancel() onClickSubscriber = nil } } diff --git a/VDS/Publishers/UIControlPublisher.swift b/VDS/Publishers/UIControlPublisher.swift index c7ccfa0c..6b8fa45d 100644 --- a/VDS/Publishers/UIControlPublisher.swift +++ b/VDS/Publishers/UIControlPublisher.swift @@ -21,10 +21,8 @@ public final class UIControlSubscription 0 { + c.touchUpInsideCount -= 1 } } From 334f9b798c32641a5f46983d2da944150a36ca3e Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 30 Mar 2023 09:06:24 -0500 Subject: [PATCH 20/20] refactored more on clickable Signed-off-by: Matt Bruce --- VDS/Classes/Control.swift | 2 +- VDS/Components/Buttons/Button/ButtonBase.swift | 2 +- VDS/Protocols/Clickable.swift | 8 ++------ 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/VDS/Classes/Control.swift b/VDS/Classes/Control.swift index 2131df8c..13f50e7f 100644 --- a/VDS/Classes/Control.swift +++ b/VDS/Classes/Control.swift @@ -43,7 +43,7 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab var isHighlightAnimating = false open override var isHighlighted: Bool { didSet { - if isHighlightAnimating == false && isClickable { + if isHighlightAnimating == false && touchUpInsideCount > 0 { isHighlightAnimating = true UIView.animate(withDuration: 0.1, animations: { [weak self] in self?.updateView() diff --git a/VDS/Components/Buttons/Button/ButtonBase.swift b/VDS/Components/Buttons/Button/ButtonBase.swift index 322f1250..41633216 100644 --- a/VDS/Components/Buttons/Button/ButtonBase.swift +++ b/VDS/Components/Buttons/Button/ButtonBase.swift @@ -64,7 +64,7 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab open override var isHighlighted: Bool { didSet { - if isHighlightAnimating == false && isClickable { + if isHighlightAnimating == false && touchUpInsideCount > 0 { isHighlightAnimating = true UIView.animate(withDuration: 0.1, animations: { [weak self] in self?.updateView() diff --git a/VDS/Protocols/Clickable.swift b/VDS/Protocols/Clickable.swift index 1bf454f6..4ffecf2b 100644 --- a/VDS/Protocols/Clickable.swift +++ b/VDS/Protocols/Clickable.swift @@ -9,23 +9,19 @@ import Foundation import UIKit import Combine -public protocol Clickable where Self: UIControl { +public protocol Clickable: Handlerable where Self: UIControl { var touchUpInsideCount: Int { get set } var onClickSubscriber: AnyCancellable? { get set } } -extension Clickable where Self: Handlerable { +extension Clickable { public func addEvent(event: UIControl.Event, block: @escaping (Self)->()) { publisher(for: event) .sink(receiveValue: { c in block(c) }).store(in: &subscribers) } - - internal var isClickable: Bool { return touchUpInsideCount > 0 } -} -extension Clickable { public var onClick: ((Self) -> ())? { get { return nil } set {