From 4c2214d7d4fa1774d687fb46d02d7808484354e5 Mon Sep 17 00:00:00 2001 From: Scott Pfeil Date: Thu, 14 Sep 2023 10:37:42 -0400 Subject: [PATCH 01/13] VDS Button to atomic beginning/ --- .../Atomic/Atoms/Buttons/ButtonModel.swift | 18 +- .../Atomic/Atoms/Buttons/PillButton.swift | 195 ++++++------------ .../Atomic/Extensions/VDS-Enums+Codable.swift | 2 + MVMCoreUI/Styles/Styler.swift | 36 ---- 4 files changed, 79 insertions(+), 172 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift b/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift index 08afefde..22ee9b8b 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift @@ -8,10 +8,10 @@ import UIKit import VDSColorTokens +import VDS public typealias FacadeElements = (fill: UIColor?, text: UIColor?, border: UIColor?) - open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWatcherFieldProtocol { //-------------------------------------------------- // MARK: - Properties @@ -26,13 +26,13 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat public var action: ActionModelProtocol public var enabled: Bool = true public var width: CGFloat? - public var style: Styler.Button.Style? { + public var style: Use? { didSet { guard let style = style else { return } setFacade(by: style) } } - public var size: Styler.Button.Size? = .standard + public var size: ButtonSize = .large public var groupName: String = "" public var inverted: Bool = false @@ -160,14 +160,14 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat disabledBorderColor_inverted = Color(uiColor: VDSColor.interactiveDisabledOndark) } - public func setFacade(by style: Styler.Button.Style) { - + public func setFacade(by style: VDS.Use) { switch style { case .primary: setPrimaryFacade() - case .secondary: setSecondaryFacade() + @unknown default: + setPrimaryFacade() } } @@ -211,17 +211,17 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat action = try typeContainer.decodeModel(codingKey: .action) ///Style captured from the JSON - if let style = try typeContainer.decodeIfPresent(Styler.Button.Style.self, forKey: .style){ + if let style = try typeContainer.decodeIfPresent(Use.self, forKey: .style) { self.style = style setFacade(by: style) - } else if let style = decoder.context?.value(forKey: CodingKeys.style.stringValue) as? Styler.Button.Style { ///Reading the style param from context which is set is molecules, ex: TwoButtonView + } else if let style = decoder.context?.value(forKey: CodingKeys.style.stringValue) as? Use { ///Reading the style param from context which is set is molecules, ex: TwoButtonView self.style = style setFacade(by: style) } else { ///Default style setFacade(by: .primary) } - if let size = try typeContainer.decodeIfPresent(Styler.Button.Size.self, forKey: .size) { + if let size = try typeContainer.decodeIfPresent(VDS.ButtonSize.self, forKey: .size) { self.size = size } diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift index e578fa51..56df2044 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift @@ -8,35 +8,19 @@ import UIKit import VDSColorTokens +import VDS -open class PillButton: Button, MVMCoreUIViewConstrainingProtocol { +open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeViewProtocol { + //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - /// Used to size the button. - var size = MVMCoreUIUtility.getWidth() - + var model: MoleculeModelProtocol? var buttonModel: ButtonModel? { get { model as? ButtonModel } } - /// Need to re-style on set. - open override var isEnabled: Bool { - didSet { style(with: buttonModel) } - } - - open var buttonSize: Styler.Button.Size = .standard { - didSet { buttonModel?.size = buttonSize } - } - - //-------------------------------------------------- - // MARK: - Constraints - //-------------------------------------------------- - - public var widthConstraint: NSLayoutConstraint? - public var minimumWidthConstraint: NSLayoutConstraint? - //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -44,127 +28,29 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol { @objc public convenience init(asPrimaryButton isPrimary: Bool, makeTiny istiny: Bool) { let model = ButtonModel(with: "", action: ActionNoopModel()) model.style = isPrimary ? .primary : .secondary - model.size = istiny ? .tiny : .standard + model.size = istiny ? .small : .large self.init(model: model, nil, nil) } - //-------------------------------------------------- - // MARK: - Computed Properties - //-------------------------------------------------- - - public var enabledTitleColor: UIColor? { - get { titleColor(for: .normal) } - set { setTitleColor(newValue, for: .normal) } - } - - public var disabledTitleColor: UIColor? { - get { titleColor(for: .disabled) } - set { setTitleColor(newValue, for: .disabled) } - } - - public var borderColor: UIColor? { - get { - guard let currentColor = layer.borderColor else { return nil } - return UIColor(cgColor: currentColor) - } - set { layer.borderColor = newValue?.cgColor } - } - - //-------------------------------------------------- - // MARK: - Methods - //-------------------------------------------------- - - /// The primary styling for a button. Should be used for main buttons - public func stylePrimary() { - let buttonModel = ButtonModel(primaryButtonWith: "", action: ActionNoopModel()) - style(with: buttonModel) - } - - /// The secondary styling for a button. Should be used for secondary buttons - public func styleSecondary() { - let buttonModel = ButtonModel(secondaryButtonWith: "", action: ActionNoopModel()) - style(with: buttonModel) - } - - /// Styles the button based on the model style - private func style(with model: ButtonModel?) { - - layer.borderWidth = model?.style == .secondary ? 1 : 0 - - if let titleColor = model?.enabledColors.text { - enabledTitleColor = titleColor - } - - if let disabledTitleColor = model?.disabledColors.text { - self.disabledTitleColor = disabledTitleColor - } - - #if DEBUG - // Useful to detect with isHittable when performing UI testing. - isAccessibilityElement = isEnabled - #endif - - if isEnabled { - if let fillColor = model?.enabledColors.fill { - backgroundColor = fillColor - } - - if let borderColor = model?.enabledColors.border { - self.borderColor = borderColor - } - } else { - if let fillColor = model?.disabledColors.fill { - backgroundColor = fillColor - } - - if let borderColor = model?.disabledColors.border { - self.borderColor = borderColor - } - } - } - - private func getInnerPadding() -> CGFloat { - buttonSize.getHeight() / 2.0 - } - - private func getContentEdgeInsets() -> UIEdgeInsets { - var verticalPadding = 0.0 - var horizontalPadding = 0.0 - switch buttonSize { - case .standard: - verticalPadding = Padding.Three - horizontalPadding = Padding.Five - break - case .small: - verticalPadding = Padding.Two - horizontalPadding = Padding.Four - break - case .tiny: - verticalPadding = Padding.One - horizontalPadding = Padding.Two - break - } - return UIEdgeInsets(top: verticalPadding, left: horizontalPadding, bottom: verticalPadding, right: horizontalPadding) - } - //-------------------------------------------------- // MARK: - MVMCoreViewProtocol //-------------------------------------------------- - open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { - // The button will get styled in the enable check in super. - super.set(with: model, delegateObject, additionalData) - + open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { guard let model = model as? ButtonModel else { return } + self.model = model + + if let accessibilityIdentifier = model.accessibilityIdentifier { + self.accessibilityIdentifier = accessibilityIdentifier + } setTitle(model.title, for: .normal) if let accessibilityText = model.accessibilityText { accessibilityLabel = accessibilityText } - if let size = model.size { - buttonSize = size - } + isEnabled = model.enabled + size = model.size model.updateUI = { [weak self] in MVMCoreDispatchUtility.performBlock(onMainThread: { @@ -173,7 +59,62 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol { } FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate) + + guard let model = model as? ButtonModelProtocol else { return } + //set(with: model.action, delegateObject: delegateObject, additionalData: additionalData) } +} + +open func reset() { + backgroundColor = .clear +} + +// MARK: Overridables +// Base classes need to implement these functions otherwise swift won't respect the subclass functions and use the ones in the protocol extension instead. +open class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { + model.moleculeName +} + +open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { nil } + +open class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { nil } + +//-------------------------------------------------- +// MARK: - Accessibility +//-------------------------------------------------- + +open override func accessibilityActivate() -> Bool { + guard isEnabled else { return false } + buttonAction?(self) + return buttonAction != nil +} + +} + +// MARK: - MVMCoreViewProtocol +extension Button: MVMCoreViewProtocol { + +open func updateView(_ size: CGFloat) { } + +/// Will be called only once. +open func setupView() { + isAccessibilityElement = true + accessibilityTraits = .button + translatesAutoresizingMaskIntoConstraints = false + insetsLayoutMarginsFromSafeArea = false + titleLabel?.numberOfLines = 0 + titleLabel?.lineBreakMode = .byWordWrapping +} +} + +// MARK: AppleGuidelinesProtocol +extension Button: AppleGuidelinesProtocol { + +override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool { + Self.acceptablyOutsideBounds(point: point, bounds: bounds) +} +} + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { return (model as? ButtonModel)?.size?.getHeight() diff --git a/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift b/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift index 6c143d9c..b2463ed1 100644 --- a/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift +++ b/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift @@ -16,3 +16,5 @@ extension Icon.Size: Codable {} extension TileContainer.BackgroundColor: Codable {} extension TileContainer.Padding: Codable {} extension TileContainer.AspectRatio: Codable {} +extension ButtonSize: Codable {} +extension Use: Codable {} diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift index 2cbc9a00..2daac86a 100644 --- a/MVMCoreUI/Styles/Styler.swift +++ b/MVMCoreUI/Styles/Styler.swift @@ -159,42 +159,6 @@ open class Styler { } } - public enum Button { - - public enum Style: String, Codable { - case primary - case secondary - } - ///MVA 3.0 - Button sizes are standard(default size), small, Tiny. Tiny button has been depricated as of Rebranding 3.0. - public enum Size: String, Codable { - case standard - case small - case tiny - - func getHeight() -> CGFloat { - switch self { - case .standard: - return 44 - case .small: - return 32 - case .tiny: - return 20 - } - } - - func minimumWidth() -> CGFloat { - switch self { - case .standard: - return 76 - case .small: - return 0 - case .tiny: - return 49 - } - } - } - } - //-------------------------------------------------- // MARK: - Functions //-------------------------------------------------- From 8e35e8036a5bd5a2b5a4bc12c4714d4ecd0a8c41 Mon Sep 17 00:00:00 2001 From: Scott Pfeil Date: Thu, 14 Sep 2023 13:55:17 -0400 Subject: [PATCH 02/13] Tiny button to small --- .../Atomic/Atoms/Buttons/ButtonModel.swift | 4 +- .../Atomic/Atoms/Buttons/PillButton.swift | 180 +++++++----------- .../Atomic/Extensions/VDS-Enums+Codable.swift | 21 +- .../ListDeviceComplexButtonMediumModel.swift | 2 +- .../ListDeviceComplexButtonSmallModel.swift | 2 +- ...htVariableButtonAllTextAndLinksModel.swift | 2 +- .../TwoButtonViewModel.swift | 6 +- .../NotificationMoleculeModel.swift | 2 +- .../BGImageHeadlineBodyButtonModel.swift | 2 +- .../HeadlineBodyButtonModel.swift | 2 +- 10 files changed, 105 insertions(+), 118 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift b/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift index 22ee9b8b..b15f8adb 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift @@ -32,7 +32,7 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat setFacade(by: style) } } - public var size: ButtonSize = .large + public var size: VDS.Button.Size = .large public var groupName: String = "" public var inverted: Bool = false @@ -221,7 +221,7 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat setFacade(by: .primary) } - if let size = try typeContainer.decodeIfPresent(VDS.ButtonSize.self, forKey: .size) { + if let size = try typeContainer.decodeIfPresent(VDS.Button.Size.self, forKey: .size) { self.size = size } diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift index 56df2044..4a812a57 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift @@ -9,8 +9,10 @@ import UIKit import VDSColorTokens import VDS +import MVMCore +import Combine -open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeViewProtocol { +open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeViewProtocol, MVMCoreViewProtocol, MFButtonProtocol { //-------------------------------------------------- // MARK: - Properties @@ -21,10 +23,33 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeVi get { model as? ButtonModel } } + var onClickCancellable: Cancellable? + //-------------------------------------------------- // 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) + } + + open override func setup() { + super.setup() + setupView() + } + + //-------------------------------------------------- + // MARK: - Convenience + //-------------------------------------------------- + @objc public convenience init(asPrimaryButton isPrimary: Bool, makeTiny istiny: Bool) { let model = ButtonModel(with: "", action: ActionNoopModel()) model.style = isPrimary ? .primary : .secondary @@ -32,8 +57,20 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeVi self.init(model: model, nil, nil) } + /// The primary styling for a button. Should be used for main buttons + public func stylePrimary() { + let buttonModel = ButtonModel(primaryButtonWith: "", action: ActionNoopModel()) + use = .primary + } + + /// The secondary styling for a button. Should be used for secondary buttons + public func styleSecondary() { + let buttonModel = ButtonModel(secondaryButtonWith: "", action: ActionNoopModel()) + use = .secondary + } + //-------------------------------------------------- - // MARK: - MVMCoreViewProtocol + // MARK: - MoleculeViewProtocol //-------------------------------------------------- open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { @@ -51,129 +88,60 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeVi isEnabled = model.enabled size = model.size +// if let backgroundColor = model.backgroundColor { +// self.backgroundColor = backgroundColor.uiColor +// } model.updateUI = { [weak self] in MVMCoreDispatchUtility.performBlock(onMainThread: { - self?.enableField(model.enabled) + self?.isEnabled = model.enabled }) } FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate) - guard let model = model as? ButtonModelProtocol else { return } - //set(with: model.action, delegateObject: delegateObject, additionalData: additionalData) - } -} - -open func reset() { - backgroundColor = .clear -} - -// MARK: Overridables -// Base classes need to implement these functions otherwise swift won't respect the subclass functions and use the ones in the protocol extension instead. -open class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { - model.moleculeName -} - -open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { nil } - -open class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { nil } - -//-------------------------------------------------- -// MARK: - Accessibility -//-------------------------------------------------- - -open override func accessibilityActivate() -> Bool { - guard isEnabled else { return false } - buttonAction?(self) - return buttonAction != nil -} - -} - -// MARK: - MVMCoreViewProtocol -extension Button: MVMCoreViewProtocol { - -open func updateView(_ size: CGFloat) { } - -/// Will be called only once. -open func setupView() { - isAccessibilityElement = true - accessibilityTraits = .button - translatesAutoresizingMaskIntoConstraints = false - insetsLayoutMarginsFromSafeArea = false - titleLabel?.numberOfLines = 0 - titleLabel?.lineBreakMode = .byWordWrapping -} -} - -// MARK: AppleGuidelinesProtocol -extension Button: AppleGuidelinesProtocol { - -override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool { - Self.acceptablyOutsideBounds(point: point, bounds: bounds) -} -} - - - open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { - return (model as? ButtonModel)?.size?.getHeight() + set(with: model.action, delegateObject: delegateObject, additionalData: additionalData) } - open override func updateView(_ size: CGFloat) { - super.updateView(size) - self.size = size - - switch buttonSize { - case .tiny: - titleLabel?.font = Styler.Font.BoldMicro.getFont(false) - case .small: - titleLabel?.font = Styler.Font.BoldBodySmall.getFont(false) - case .standard: - titleLabel?.font = Styler.Font.BoldBodyLarge.getFont(false) - } - - layer.cornerRadius = getInnerPadding() - contentEdgeInsets = getContentEdgeInsets() - - if let contraint = buttonModel?.width { - - if widthConstraint == nil { - widthConstraint = widthAnchor.constraint(equalToConstant: contraint) - } else if widthConstraint?.constant != contraint { - widthConstraint?.constant = contraint - } - widthConstraint?.isActive = true - minimumWidthConstraint?.isActive = false - } else { - - if minimumWidthConstraint == nil { - minimumWidthConstraint = widthAnchor.constraint(greaterThanOrEqualToConstant: buttonSize.minimumWidth()) - } else { - minimumWidthConstraint?.constant = buttonSize.minimumWidth() - } - minimumWidthConstraint?.isActive = true - widthConstraint?.isActive = false - } + //-------------------------------------------------- + // MARK: - MVMCoreViewProtocol + //-------------------------------------------------- + + open override func reset() { + super.reset() + //backgroundColor = .clear } - open override func setupView() { - super.setupView() - - titleLabel?.numberOfLines = 1 - titleLabel?.lineBreakMode = .byTruncatingTail - titleLabel?.textAlignment = .center - contentHorizontalAlignment = .center - stylePrimary() + open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return (model as? ButtonModel)?.size.height } + open func updateView(_ size: CGFloat) {} + + open func setupView() {} + //-------------------------------------------------- // MARK: - MVMCoreUIViewConstrainingProtocol //-------------------------------------------------- open func horizontalAlignment() -> UIStackView.Alignment { .center } - public func enableField(_ enable: Bool) { - isEnabled = enable + //-------------------------------------------------- + // MARK: - Action + //-------------------------------------------------- + + open func set(with actionModel: ActionModelProtocol?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + onClickCancellable = onClickSubscriber.publisher.sink { [weak self] _ in + guard let self = self, + let actionModel = self.buttonModel?.action else { return } + Task(priority: .userInitiated) { + try await Self.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: self.model) + } + } + } + + open class func performButtonAction(with model: ActionModelProtocol, button: MFButtonProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, sourceModel: MoleculeModelProtocol? = nil) async throws { + guard delegateObject?.buttonDelegate?.button?(button, shouldPerformActionWithMap: model.toJSON(), additionalData: additionalData) ?? true else { return } + try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: model, additionalData: MVMCoreUIActionHandler.add(sourceModel: sourceModel, to: additionalData), delegateObject: delegateObject) } } diff --git a/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift b/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift index b2463ed1..ea462930 100644 --- a/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift +++ b/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift @@ -16,5 +16,24 @@ extension Icon.Size: Codable {} extension TileContainer.BackgroundColor: Codable {} extension TileContainer.Padding: Codable {} extension TileContainer.AspectRatio: Codable {} -extension ButtonSize: Codable {} extension Use: Codable {} +extension VDS.Button.Size: Codable { + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + let string = try container.decode(String.self) + switch string { + case VDS.Button.Size.large.rawValue: + self = .large + case VDS.Button.Size.small.rawValue, "tiny": + self = .small + default: + self = .large + } + + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(self) + } +} diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMediumModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMediumModel.swift index 88f7fe97..54b313e6 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMediumModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMediumModel.swift @@ -42,7 +42,7 @@ public class ListDeviceComplexButtonMediumModel: ListItemModel, MoleculeModelPro override public func setDefaults() { super.setDefaults() - button.size = .tiny + button.size = .small button.style = .secondary } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmallModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmallModel.swift index 13be8c03..d06a3845 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmallModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmallModel.swift @@ -42,7 +42,7 @@ public class ListDeviceComplexButtonSmallModel: ListItemModel, MoleculeModelProt override public func setDefaults() { super.setDefaults() - button.size = .tiny + button.size = .small button.style = .secondary } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableButtonAllTextAndLinksModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableButtonAllTextAndLinksModel.swift index 21a4b08c..30856e55 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableButtonAllTextAndLinksModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableButtonAllTextAndLinksModel.swift @@ -32,7 +32,7 @@ public class ListRightVariableButtonAllTextAndLinksModel: ListItemModel, Molecul override public func setDefaults() { super.setDefaults() - self.button.size = .tiny + self.button.size = .small self.button.style = .secondary } diff --git a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonViewModel.swift b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonViewModel.swift index b5d07c4a..a7b4055c 100644 --- a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonViewModel.swift +++ b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonViewModel.swift @@ -7,7 +7,7 @@ // import UIKit - +import VDS public class TwoButtonViewModel: ParentMoleculeModelProtocol { //-------------------------------------------------- @@ -56,13 +56,13 @@ public class TwoButtonViewModel: ParentMoleculeModelProtocol { //set context value for 'primary' style to be set for the primaryButton in case the //property is not returned in the JSON and once decoded, this value is removed from the context - try decoder.setContext(value: Styler.Button.Style.primary, for: "style") { + try decoder.setContext(value: Use.primary, for: "style") { self.primaryButton = try typeContainer.decodeMoleculeIfPresent(codingKey: .primaryButton) } //set context value for 'secondary' style to be set for the primaryButton in case the //property is not returned in the JSON and once decoded, this value is removed from the context - try decoder.setContext(value: Styler.Button.Style.secondary, for: "style") { + try decoder.setContext(value: Use.secondary, for: "style") { self.secondaryButton = try typeContainer.decodeMoleculeIfPresent(codingKey: .secondaryButton) } } diff --git a/MVMCoreUI/Atomic/Molecules/TopNotification/NotificationMoleculeModel.swift b/MVMCoreUI/Atomic/Molecules/TopNotification/NotificationMoleculeModel.swift index d26bb06c..27ca95a8 100644 --- a/MVMCoreUI/Atomic/Molecules/TopNotification/NotificationMoleculeModel.swift +++ b/MVMCoreUI/Atomic/Molecules/TopNotification/NotificationMoleculeModel.swift @@ -89,7 +89,7 @@ open class NotificationMoleculeModel: ContainerModel, MoleculeModelProtocol { } } - button?.size = .tiny + button?.size = .small button?.style = .secondary switch style { case .error, .warning: diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/BGImageHeadlineBodyButtonModel.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/BGImageHeadlineBodyButtonModel.swift index 99ee1567..4e2d031a 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/BGImageHeadlineBodyButtonModel.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/BGImageHeadlineBodyButtonModel.swift @@ -54,7 +54,7 @@ public class BGImageHeadlineBodyButtonModel: ContainerModel, MoleculeModelProtoc image.height = BGImageHeadlineBodyButton.heightConstant } - button?.size = .tiny + button?.size = .small button?.style = .secondary } diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyButtonModel.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyButtonModel.swift index 1b713720..347277fd 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyButtonModel.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyButtonModel.swift @@ -38,7 +38,7 @@ public class HeadlineBodyButtonModel: MoleculeModelProtocol { /// Defaults to set public func setDefaults() { - button.size = .tiny + button.size = .small button.style = .secondary } From 741bf0501b2f739d8e3bdae9eb5ce6da498480fe Mon Sep 17 00:00:00 2001 From: Scott Pfeil Date: Thu, 14 Sep 2023 14:14:30 -0400 Subject: [PATCH 03/13] Updates to Button --- .../Atomic/Atoms/Buttons/PillButton.swift | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift index 4a812a57..e8105d3e 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift @@ -18,12 +18,12 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeVi // MARK: - Properties //-------------------------------------------------- - var model: MoleculeModelProtocol? - var buttonModel: ButtonModel? { + open var model: MoleculeModelProtocol? + public var buttonModel: ButtonModel? { get { model as? ButtonModel } } - var onClickCancellable: Cancellable? + internal var onClickCancellable: Cancellable? //-------------------------------------------------- // MARK: - Initializers @@ -58,14 +58,14 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeVi } /// The primary styling for a button. Should be used for main buttons - public func stylePrimary() { - let buttonModel = ButtonModel(primaryButtonWith: "", action: ActionNoopModel()) + open func stylePrimary() { + model = ButtonModel(primaryButtonWith: "", action: ActionNoopModel()) use = .primary } /// The secondary styling for a button. Should be used for secondary buttons - public func styleSecondary() { - let buttonModel = ButtonModel(secondaryButtonWith: "", action: ActionNoopModel()) + open func styleSecondary() { + model = ButtonModel(secondaryButtonWith: "", action: ActionNoopModel()) use = .secondary } @@ -81,26 +81,25 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeVi self.accessibilityIdentifier = accessibilityIdentifier } - setTitle(model.title, for: .normal) - if let accessibilityText = model.accessibilityText { - accessibilityLabel = accessibilityText - } - + text = model.title isEnabled = model.enabled size = model.size // if let backgroundColor = model.backgroundColor { // self.backgroundColor = backgroundColor.uiColor // } + if let accessibilityText = model.accessibilityText { + accessibilityLabel = accessibilityText + } + + FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate) + + set(with: model.action, delegateObject: delegateObject, additionalData: additionalData) model.updateUI = { [weak self] in MVMCoreDispatchUtility.performBlock(onMainThread: { self?.isEnabled = model.enabled }) } - - FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate) - - set(with: model.action, delegateObject: delegateObject, additionalData: additionalData) } //-------------------------------------------------- From c82a0cd4d60d2ab47aaf2049267d16b22662f841 Mon Sep 17 00:00:00 2001 From: Scott Pfeil Date: Thu, 14 Sep 2023 14:49:07 -0400 Subject: [PATCH 04/13] Make PillButton VDSMoleculeViewProtocol --- .../Atomic/Atoms/Buttons/PillButton.swift | 89 +++++++------------ .../Atomic/Extensions/VDS-Enums+Codable.swift | 2 +- 2 files changed, 32 insertions(+), 59 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift index e8105d3e..2c1c44e7 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift @@ -12,40 +12,18 @@ import VDS import MVMCore import Combine -open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeViewProtocol, MVMCoreViewProtocol, MFButtonProtocol { - +open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeViewProtocol, MVMCoreViewProtocol, MFButtonProtocol, VDSMoleculeViewProtocol { + //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - open var model: MoleculeModelProtocol? - public var buttonModel: ButtonModel? { - get { model as? ButtonModel } - } - + public var viewModel: ButtonModel! + public var delegateObject: MVMCoreUIDelegateObject? + public var additionalData: [AnyHashable: Any]? + internal var onClickCancellable: Cancellable? - //-------------------------------------------------- - // 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) - } - - open override func setup() { - super.setup() - setupView() - } - //-------------------------------------------------- // MARK: - Convenience //-------------------------------------------------- @@ -59,45 +37,45 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeVi /// The primary styling for a button. Should be used for main buttons open func stylePrimary() { - model = ButtonModel(primaryButtonWith: "", action: ActionNoopModel()) + viewModel = ButtonModel(primaryButtonWith: "", action: ActionNoopModel()) use = .primary } /// The secondary styling for a button. Should be used for secondary buttons open func styleSecondary() { - model = ButtonModel(secondaryButtonWith: "", action: ActionNoopModel()) + viewModel = ButtonModel(secondaryButtonWith: "", action: ActionNoopModel()) use = .secondary } + open override func setup() { + super.setup() + setupView() + } + //-------------------------------------------------- - // MARK: - MoleculeViewProtocol + // MARK: - VDSMoleculeViewProtocol //-------------------------------------------------- - open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { - guard let model = model as? ButtonModel else { return } - self.model = model - - if let accessibilityIdentifier = model.accessibilityIdentifier { + public func viewModelDidUpdate() { + if let accessibilityIdentifier = viewModel.accessibilityIdentifier { self.accessibilityIdentifier = accessibilityIdentifier } - text = model.title - isEnabled = model.enabled - size = model.size -// if let backgroundColor = model.backgroundColor { -// self.backgroundColor = backgroundColor.uiColor -// } - if let accessibilityText = model.accessibilityText { + text = viewModel.title + isEnabled = viewModel.enabled + size = viewModel.size + use = viewModel.style ?? .primary + if let accessibilityText = viewModel.accessibilityText { accessibilityLabel = accessibilityText } - FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate) + FormValidator.setupValidation(for: viewModel, delegate: delegateObject?.formHolderDelegate) - set(with: model.action, delegateObject: delegateObject, additionalData: additionalData) + set(with: viewModel.action, delegateObject: delegateObject, additionalData: additionalData) - model.updateUI = { [weak self] in + viewModel.updateUI = { [weak self] in MVMCoreDispatchUtility.performBlock(onMainThread: { - self?.isEnabled = model.enabled + self?.viewModelDidUpdate() }) } } @@ -106,11 +84,6 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeVi // MARK: - MVMCoreViewProtocol //-------------------------------------------------- - open override func reset() { - super.reset() - //backgroundColor = .clear - } - open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { return (model as? ButtonModel)?.size.height } @@ -130,13 +103,13 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeVi //-------------------------------------------------- open func set(with actionModel: ActionModelProtocol?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - onClickCancellable = onClickSubscriber.publisher.sink { [weak self] _ in - guard let self = self, - let actionModel = self.buttonModel?.action else { return } - Task(priority: .userInitiated) { - try await Self.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: self.model) + onClickSubscriber = publisher(for: .touchUpInside) + .sink {[weak self] control in + guard let self = self else { return } + Task(priority: .userInitiated) { + try await Self.performButtonAction(with: self.viewModel.action, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: self.viewModel) + } } - } } open class func performButtonAction(with model: ActionModelProtocol, button: MFButtonProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, sourceModel: MoleculeModelProtocol? = nil) async throws { diff --git a/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift b/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift index ea462930..369dbb18 100644 --- a/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift +++ b/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift @@ -22,7 +22,7 @@ extension VDS.Button.Size: Codable { let container = try decoder.singleValueContainer() let string = try container.decode(String.self) switch string { - case VDS.Button.Size.large.rawValue: + case VDS.Button.Size.large.rawValue, "standard": self = .large case VDS.Button.Size.small.rawValue, "tiny": self = .small From a925560ecbb463bad2eabb00a88a540ca7455368 Mon Sep 17 00:00:00 2001 From: Scott Pfeil Date: Thu, 14 Sep 2023 16:18:10 -0400 Subject: [PATCH 05/13] RawRepresentableCodable --- MVMCoreUI.xcodeproj/project.pbxproj | 4 ++ .../Atomic/Atoms/Buttons/PillButton.swift | 9 +++-- .../Atomic/Extensions/VDS-Enums+Codable.swift | 22 ++-------- .../Utility/RawRepresentableCodable.swift | 40 +++++++++++++++++++ 4 files changed, 52 insertions(+), 23 deletions(-) create mode 100644 MVMCoreUI/Utility/RawRepresentableCodable.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index acb13d9a..964bc30c 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -289,6 +289,7 @@ AF766D262A3CD4C600749099 /* UIAccessibilityTraits+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF766D252A3CD4C600749099 /* UIAccessibilityTraits+Codable.swift */; }; AF7E509829E477C1009DC2AD /* AlertHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF7E509629E477C0009DC2AD /* AlertHandler.swift */; }; AF7E509929E477C1009DC2AD /* AlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF7E509729E477C0009DC2AD /* AlertController.swift */; }; + AF8118302AB39B0900FAD1BA /* RawRepresentableCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF81182F2AB39B0900FAD1BA /* RawRepresentableCodable.swift */; }; AFA4932029E5CA73001A9663 /* AlertOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA4931F29E5CA73001A9663 /* AlertOperation.swift */; }; AFA4932229E5EF2E001A9663 /* NotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA4932129E5EF2E001A9663 /* NotificationHandler.swift */; }; AFA4933F29E874F0001A9663 /* MVMCoreUILoggingDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA4933E29E874F0001A9663 /* MVMCoreUILoggingDelegateProtocol.swift */; }; @@ -875,6 +876,7 @@ AF766D252A3CD4C600749099 /* UIAccessibilityTraits+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAccessibilityTraits+Codable.swift"; sourceTree = ""; }; AF7E509629E477C0009DC2AD /* AlertHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertHandler.swift; sourceTree = ""; }; AF7E509729E477C0009DC2AD /* AlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertController.swift; sourceTree = ""; }; + AF81182F2AB39B0900FAD1BA /* RawRepresentableCodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawRepresentableCodable.swift; sourceTree = ""; }; AFA4931F29E5CA73001A9663 /* AlertOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertOperation.swift; sourceTree = ""; }; AFA4932129E5EF2E001A9663 /* NotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationHandler.swift; sourceTree = ""; }; AFA4933E29E874F0001A9663 /* MVMCoreUILoggingDelegateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUILoggingDelegateProtocol.swift; sourceTree = ""; }; @@ -2152,6 +2154,7 @@ D29DF2A821E7B2F9003B2FB9 /* MVMCoreUIConstants.m */, 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */, 0AF60F0826B3316E00AC3DB4 /* MVMCoreUIUtility+Extension.swift */, + AF81182F2AB39B0900FAD1BA /* RawRepresentableCodable.swift */, ); path = Utility; sourceTree = ""; @@ -2746,6 +2749,7 @@ 0AE98BAF23FEF956004C5109 /* ExternalLink.swift in Sources */, 012A88C4238D86E600FE3DA1 /* CarouselItemModelProtocol.swift in Sources */, D2E2A9A123E095AB000B42E6 /* ButtonModelProtocol.swift in Sources */, + AF8118302AB39B0900FAD1BA /* RawRepresentableCodable.swift in Sources */, 94C2D9AB23872EB50006CF46 /* LabelAttributeActionModel.swift in Sources */, D22D8395241FB41200D3DF69 /* UIStackView+Extension.swift in Sources */, 52B201D324081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift index 2c1c44e7..d99b78f4 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift @@ -68,16 +68,17 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeVi if let accessibilityText = viewModel.accessibilityText { accessibilityLabel = accessibilityText } - - FormValidator.setupValidation(for: viewModel, delegate: delegateObject?.formHolderDelegate) - + set(with: viewModel.action, delegateObject: delegateObject, additionalData: additionalData) viewModel.updateUI = { [weak self] in MVMCoreDispatchUtility.performBlock(onMainThread: { - self?.viewModelDidUpdate() + guard let self = self else { return } + self.isEnabled = self.viewModel.enabled }) } + + FormValidator.setupValidation(for: viewModel, delegate: delegateObject?.formHolderDelegate) } //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift b/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift index 369dbb18..ee504e2f 100644 --- a/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift +++ b/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift @@ -17,23 +17,7 @@ extension TileContainer.BackgroundColor: Codable {} extension TileContainer.Padding: Codable {} extension TileContainer.AspectRatio: Codable {} extension Use: Codable {} -extension VDS.Button.Size: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - let string = try container.decode(String.self) - switch string { - case VDS.Button.Size.large.rawValue, "standard": - self = .large - case VDS.Button.Size.small.rawValue, "tiny": - self = .small - default: - self = .large - } - - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - try container.encode(self) - } +extension VDS.Button.Size: RawRepresentableCodable { + public static var mapping: [String : VDS.Button.Size] { ["standard": .large, "tiny": .small] } + public static var defaultValue: VDS.Button.Size? { nil } } diff --git a/MVMCoreUI/Utility/RawRepresentableCodable.swift b/MVMCoreUI/Utility/RawRepresentableCodable.swift new file mode 100644 index 00000000..09441add --- /dev/null +++ b/MVMCoreUI/Utility/RawRepresentableCodable.swift @@ -0,0 +1,40 @@ +// +// RawRepresentableCodable.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 9/14/23. +// Copyright © 2023 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol RawRepresentableCodable: RawRepresentable, Codable where RawValue: Hashable & Decodable { + static var mapping: [RawValue: Self] { get } + static var defaultValue: Self? { get } +} + +public enum RawRepresentableCodableError: Swift.Error { + case invalid(value: String) +} + +extension RawRepresentableCodable { + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + let rawValue = try container.decode(RawValue.self) + if let found = Self(rawValue: rawValue) { + self = found + } else if let found = Self.mapping[rawValue] { + self = found + } else if let defaultValue = Self.defaultValue { + self = defaultValue + } else { + throw RawRepresentableCodableError.invalid(value: "\(rawValue)") + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(self) + } +} From c2cc637c382f1bed8997c8e465aeebe21dab00c2 Mon Sep 17 00:00:00 2001 From: Scott Pfeil Date: Thu, 14 Sep 2023 16:35:44 -0400 Subject: [PATCH 06/13] remove old junk --- .../Atomic/Atoms/Buttons/PillButton.swift | 33 +++---------------- .../TwoButtonView.swift | 7 ++-- .../NotificationMoleculeView.swift | 2 +- .../HeadlineBodyButton.swift | 2 +- 4 files changed, 10 insertions(+), 34 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift index d99b78f4..ddffb179 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift @@ -24,34 +24,6 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeVi internal var onClickCancellable: Cancellable? - //-------------------------------------------------- - // MARK: - Convenience - //-------------------------------------------------- - - @objc public convenience init(asPrimaryButton isPrimary: Bool, makeTiny istiny: Bool) { - let model = ButtonModel(with: "", action: ActionNoopModel()) - model.style = isPrimary ? .primary : .secondary - model.size = istiny ? .small : .large - self.init(model: model, nil, nil) - } - - /// The primary styling for a button. Should be used for main buttons - open func stylePrimary() { - viewModel = ButtonModel(primaryButtonWith: "", action: ActionNoopModel()) - use = .primary - } - - /// The secondary styling for a button. Should be used for secondary buttons - open func styleSecondary() { - viewModel = ButtonModel(secondaryButtonWith: "", action: ActionNoopModel()) - use = .secondary - } - - open override func setup() { - super.setup() - setupView() - } - //-------------------------------------------------- // MARK: - VDSMoleculeViewProtocol //-------------------------------------------------- @@ -91,6 +63,11 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeVi open func updateView(_ size: CGFloat) {} + open override func setup() { + super.setup() + setupView() + } + open func setupView() {} //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonView.swift b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonView.swift index 5f846730..9a70c12e 100644 --- a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonView.swift +++ b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonView.swift @@ -7,7 +7,7 @@ // import UIKit - +import VDS @objcMembers open class TwoButtonView: View, MVMCoreUIViewConstrainingProtocol { //-------------------------------------------------- @@ -29,9 +29,8 @@ import UIKit //-------------------------------------------------- public func setDefaultAppearance() { - - primaryButton.stylePrimary() - secondaryButton.styleSecondary() + primaryButton.use = .primary + secondaryButton.use = .secondary } open override func updateView(_ size: CGFloat) { diff --git a/MVMCoreUI/Atomic/Molecules/TopNotification/NotificationMoleculeView.swift b/MVMCoreUI/Atomic/Molecules/TopNotification/NotificationMoleculeView.swift index c731f6d6..200dea16 100644 --- a/MVMCoreUI/Atomic/Molecules/TopNotification/NotificationMoleculeView.swift +++ b/MVMCoreUI/Atomic/Molecules/TopNotification/NotificationMoleculeView.swift @@ -15,7 +15,7 @@ import Foundation public let headline = Label(fontStyle: .BoldBodySmall) public let body = Label(fontStyle: .RegularBodySmall) - public let button = PillButton(asPrimaryButton: false, makeTiny: true) + public let button = PillButton() public let closeButton = NotificationXButton() public var labelStack: Stack! public var horizontalStack: Stack! diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyButton.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyButton.swift index a40066e2..d7fced36 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyButton.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyButton.swift @@ -64,7 +64,7 @@ headlineBody.headlineLabel.font = Styler.Font.BoldTitleMedium.getFont() headlineBody.messageLabel.font = Styler.Font.RegularMicro.getFont() - button.styleSecondary() + button.use = .secondary button.isHidden = false buttonHeadlinePadding = PaddingTwo } From 34d3386d36b240a7ff3a0399c32e1f4a73477d97 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 14 Sep 2023 16:02:15 -0500 Subject: [PATCH 07/13] updated onClick Signed-off-by: Matt Bruce --- MVMCoreUI/Atomic/Atoms/Views/Tilelet.swift | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Tilelet.swift b/MVMCoreUI/Atomic/Atoms/Views/Tilelet.swift index 41d68493..32c8015a 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Tilelet.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Tilelet.swift @@ -50,14 +50,13 @@ open class Tilelet: VDS.Tilelet, VDSMoleculeViewProtocol{ //setup action if let action = viewModel.action { //add the subscriber - onClickSubscriber = publisher(for: .touchUpInside) - .sink {[weak self] control in - guard let self else { return } - MVMCoreUIActionHandler.performActionUnstructured(with: action, - sourceModel: self.viewModel, - additionalData: self.additionalData, - delegateObject: self.delegateObject) - } + onClick = { [weak self] control in + guard let self, let viewModel = self.viewModel else { return } + MVMCoreUIActionHandler.performActionUnstructured(with: action, + sourceModel: viewModel, + additionalData: self.additionalData, + delegateObject: self.delegateObject) + } } } From fe580d12e4cca358ef6a0c9e4db19b8e0c961839 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 14 Sep 2023 16:02:26 -0500 Subject: [PATCH 08/13] updated onClick Signed-off-by: Matt Bruce --- MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift index ddffb179..c93a22db 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift @@ -12,7 +12,7 @@ import VDS import MVMCore import Combine -open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeViewProtocol, MVMCoreViewProtocol, MFButtonProtocol, VDSMoleculeViewProtocol { +open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MFButtonProtocol, VDSMoleculeViewProtocol { //-------------------------------------------------- // MARK: - Properties @@ -81,13 +81,12 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MoleculeVi //-------------------------------------------------- open func set(with actionModel: ActionModelProtocol?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - onClickSubscriber = publisher(for: .touchUpInside) - .sink {[weak self] control in - guard let self = self else { return } - Task(priority: .userInitiated) { - try await Self.performButtonAction(with: self.viewModel.action, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: self.viewModel) - } + onClick = { [weak self] control in + guard let self = self, let viewModel = self.viewModel else { return } + Task(priority: .userInitiated) { + try await Self.performButtonAction(with: viewModel.action, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: viewModel) } + } } open class func performButtonAction(with model: ActionModelProtocol, button: MFButtonProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, sourceModel: MoleculeModelProtocol? = nil) async throws { From 917a0f84806045af86189ba07be917146cb68a35 Mon Sep 17 00:00:00 2001 From: Scott Pfeil Date: Fri, 15 Sep 2023 12:13:02 -0400 Subject: [PATCH 09/13] PillButton inverted-> surface --- MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift | 1 + MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift | 1 + 2 files changed, 2 insertions(+) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift b/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift index b15f8adb..94a7778b 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift @@ -9,6 +9,7 @@ import UIKit import VDSColorTokens import VDS +import MVMCore public typealias FacadeElements = (fill: UIColor?, text: UIColor?, border: UIColor?) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift index c93a22db..645c6602 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift @@ -37,6 +37,7 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MFButtonPr isEnabled = viewModel.enabled size = viewModel.size use = viewModel.style ?? .primary + surface = viewModel.inverted ? .dark : .light if let accessibilityText = viewModel.accessibilityText { accessibilityLabel = accessibilityText } From 68ad6595595294b562bc993be60b26570fc44cde Mon Sep 17 00:00:00 2001 From: Scott Pfeil Date: Fri, 15 Sep 2023 12:13:44 -0400 Subject: [PATCH 10/13] pill button open --- MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift index c93a22db..0bfad746 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift @@ -18,7 +18,7 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MFButtonPr // MARK: - Properties //-------------------------------------------------- - public var viewModel: ButtonModel! + open var viewModel: ButtonModel! public var delegateObject: MVMCoreUIDelegateObject? public var additionalData: [AnyHashable: Any]? @@ -28,7 +28,7 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MFButtonPr // MARK: - VDSMoleculeViewProtocol //-------------------------------------------------- - public func viewModelDidUpdate() { + open func viewModelDidUpdate() { if let accessibilityIdentifier = viewModel.accessibilityIdentifier { self.accessibilityIdentifier = accessibilityIdentifier } From c8aac2e5d7056279496ad40bf2cdf5e8aa5f742b Mon Sep 17 00:00:00 2001 From: Scott Pfeil Date: Fri, 13 Oct 2023 14:21:22 -0400 Subject: [PATCH 11/13] Updated to get the upcoming view controller navigationBar model --- .../UINavigationController+Extension.swift | 2 +- MVMCoreUI/Utility/MVMCoreUIUtility+Extension.swift | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/MVMCoreUI/Containers/NavigationController/UINavigationController+Extension.swift b/MVMCoreUI/Containers/NavigationController/UINavigationController+Extension.swift index 3372c1ab..2909ce4a 100644 --- a/MVMCoreUI/Containers/NavigationController/UINavigationController+Extension.swift +++ b/MVMCoreUI/Containers/NavigationController/UINavigationController+Extension.swift @@ -119,7 +119,7 @@ public extension UINavigationController { setNavigationBarHidden(model.hidden, animated: true) } - @MainActor + @objc @MainActor func getViewController() -> UIViewController? { guard let topViewController = getViewControllers().last, let viewController = MVMCoreUIUtility.getViewControllerTraversingManagers(topViewController) else { return nil } diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility+Extension.swift b/MVMCoreUI/Utility/MVMCoreUIUtility+Extension.swift index e04de6bb..05cd9ae2 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility+Extension.swift +++ b/MVMCoreUI/Utility/MVMCoreUIUtility+Extension.swift @@ -57,9 +57,10 @@ public extension MVMCoreUIUtility { return findViews(by: type, views: queue) + matching } + @MainActor static func visibleNavigationBarStlye() -> NavigationItemStyle? { - if let vc = MVMCoreUIUtility.getCurrentVisibleController(), - let navController = NavigationController.navigationController(), + if let navController = NavigationController.navigationController(), + let vc = navController.getViewController(), let navigationBar = navController.getNavigationModel(from: vc) as? NavigationItemModel { return navigationBar.style } From b1da7aaeed03b28035f7c95d843a823647185ccd Mon Sep 17 00:00:00 2001 From: Scott Pfeil Date: Mon, 23 Oct 2023 16:41:08 -0400 Subject: [PATCH 12/13] Footer button filled for iphones --- .../Atomic/Molecules/HeadersAndFooters/FooterModel.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MVMCoreUI/Atomic/Molecules/HeadersAndFooters/FooterModel.swift b/MVMCoreUI/Atomic/Molecules/HeadersAndFooters/FooterModel.swift index bab51c2d..dd23035c 100644 --- a/MVMCoreUI/Atomic/Molecules/HeadersAndFooters/FooterModel.swift +++ b/MVMCoreUI/Atomic/Molecules/HeadersAndFooters/FooterModel.swift @@ -24,5 +24,9 @@ if bottomPadding == nil { bottomPadding = PaddingDefaultVerticalSpacing } + guard let _ = molecule as? ButtonModel, + !MVMCoreGetterUtility.isOnIPad(), + horizontalAlignment == nil else { return } + horizontalAlignment = .fill } } From e373aa3b086c8ec4128691319fa50eb77b7339fc Mon Sep 17 00:00:00 2001 From: Scott Pfeil Date: Mon, 23 Oct 2023 17:42:32 -0400 Subject: [PATCH 13/13] Full width foot pill button --- .../Molecules/HeadersAndFooters/FooterModel.swift | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/HeadersAndFooters/FooterModel.swift b/MVMCoreUI/Atomic/Molecules/HeadersAndFooters/FooterModel.swift index dd23035c..93e296f2 100644 --- a/MVMCoreUI/Atomic/Molecules/HeadersAndFooters/FooterModel.swift +++ b/MVMCoreUI/Atomic/Molecules/HeadersAndFooters/FooterModel.swift @@ -24,9 +24,14 @@ if bottomPadding == nil { bottomPadding = PaddingDefaultVerticalSpacing } - guard let _ = molecule as? ButtonModel, - !MVMCoreGetterUtility.isOnIPad(), - horizontalAlignment == nil else { return } - horizontalAlignment = .fill + guard !MVMCoreGetterUtility.isOnIPad(), + horizontalAlignment == nil else { return } + + if let _ = molecule as? ButtonModel { + horizontalAlignment = .fill + } else if let model = molecule as? TwoButtonViewModel, + model.primaryButton == nil || model.secondaryButton == nil { + horizontalAlignment = .fill + } } }