From 80b9f985b178a172c178d2c2341c90be47a77ccc Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 30 Apr 2020 14:26:25 -0400 Subject: [PATCH] latest updated for color inversion --- MVMCoreUI.xcodeproj/project.pbxproj | 4 + .../Atomic/Atoms/Buttons/ButtonModel.swift | 108 +++++++---- .../Atomic/Atoms/Buttons/PillButton.swift | 118 +++++++----- .../TwoButtonView.swift | 52 ++++- .../TwoButtonViewModel.swift | 22 ++- .../Templates/MoleculeListTemplate.swift | 1 + .../Atomic/Templates/TemplateModel.swift | 19 ++ .../Atomic/Templates/ThreeLayerTemplate.swift | 18 +- .../BaseControllers/ViewController.swift | 2 +- MVMCoreUI/Styles/Facade.swift | 177 ++++++++++++++++++ 10 files changed, 414 insertions(+), 107 deletions(-) create mode 100644 MVMCoreUI/Styles/Facade.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 58eea2d8..de055ff7 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -102,6 +102,7 @@ 0A7EF86323D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86223D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift */; }; 0A7EF86523D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */; }; 0A7EF86723D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */; }; + 0A96140B245B06F0006FA18B /* Facade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A96140A245B06F0006FA18B /* Facade.swift */; }; 0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B392398524F0067DD0F /* Toggle.swift */; }; 0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */; }; 0AB764D324460FA400E7FE72 /* UIPickerView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB764D224460FA400E7FE72 /* UIPickerView+Extension.swift */; }; @@ -558,6 +559,7 @@ 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryFieldModel.swift; sourceTree = ""; }; 0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryFieldModel.swift; sourceTree = ""; }; 0A8321AE2355FE9500CB7F00 /* DigitBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitBox.swift; sourceTree = ""; }; + 0A96140A245B06F0006FA18B /* Facade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Facade.swift; sourceTree = ""; }; 0AA33B33239813C50067DD0F /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = ""; }; 0AA33B392398524F0067DD0F /* Toggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toggle.swift; sourceTree = ""; }; 0AB764D024460F6300E7FE72 /* UIDatePicker+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDatePicker+Extension.swift"; sourceTree = ""; }; @@ -1715,6 +1717,7 @@ D29DF13921E68637003B2FB9 /* MFStyler.m */, 0A6682A92435125F00AD3CA1 /* Styler.swift */, 0A6682AB243531C300AD3CA1 /* Padding.swift */, + 0A96140A245B06F0006FA18B /* Facade.swift */, ); path = Styles; sourceTree = ""; @@ -2239,6 +2242,7 @@ 012A88C4238D86E600FE3DA1 /* CarouselItemModelProtocol.swift in Sources */, D2E2A9A123E095AB000B42E6 /* ButtonModelProtocol.swift in Sources */, 94C2D9AB23872EB50006CF46 /* LabelAttributeActionModel.swift in Sources */, + 0A96140B245B06F0006FA18B /* Facade.swift in Sources */, D22D8395241FB41200D3DF69 /* UIStackView+Extension.swift in Sources */, 52B201D324081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift in Sources */, 525239C02407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift b/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift index 22969196..ca90db94 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/ButtonModel.swift @@ -26,20 +26,52 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupW public static var identifier: String = "button" public var backgroundColor: Color? - public var isInverted: Bool = false public var title: String public var action: ActionModelProtocol public var enabled: Bool = true - public var style: ButtonStyle? + public var isInverted: Bool = false { + didSet { facade?.isInverted = isInverted } + } + public var facade: Facade? + public var style: ButtonStyle = .primary { + didSet { + switch style { + case .primary: + facade = primaryFacade + case .secondary: + facade = secondaryFacade + } + } + } public var size: ButtonSize? = .standard - public var fillColor: Color? - public var textColor: Color? - public var borderColor: Color? - public var disabledFillColor: Color? - public var disabledTextColor: Color? - public var disabledBorderColor: Color? public var groupName: String = "" - + + //-------------------------------------------------- + // MARK: - Default Button Facades + //-------------------------------------------------- + + private var primaryFacade = Facade(enabledFillColor: Color(uiColor: .mvmBlack), + enabledTextColor: Color(uiColor: .mvmWhite), + disabledFillColor: Color(uiColor: .mvmCoolGray6), + disabledTextColor: Color(uiColor: .mvmWhite), + enabledFillColor_inverted: Color(uiColor: .mvmWhite), + enabledTextColor_inverted: Color(uiColor: .mvmBlack), + disabledFillColor_inverted: Color(uiColor: .mvmCoolGray6), + disabledTextColor_inverted: Color(uiColor: .mvmBlack)) + + private var secondaryFacade = Facade(enabledFillColor: Color(uiColor: .mvmWhite), + enabledTextColor: Color(uiColor: .mvmBlack), + enabledBorderColor: Color(uiColor: .mvmBlack), + disabledFillColor: Color(uiColor: .mvmWhite), + disabledTextColor: Color(uiColor: .mvmCoolGray6), + disabledBorderColor: Color(uiColor: .mvmCoolGray6), + enabledFillColor_inverted: Color(uiColor: .mvmBlack), + enabledTextColor_inverted: Color(uiColor: .mvmWhite), + enabledBorderColor_inverted: Color(uiColor: .mvmWhite), + disabledFillColor_inverted: Color(uiColor: .mvmWhite), + disabledTextColor_inverted: Color(uiColor: .mvmCoolGray6), + disabledBorderColor_inverted: Color(uiColor: .mvmCoolGray6)) + //-------------------------------------------------- // MARK: - Methods //-------------------------------------------------- @@ -48,10 +80,10 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupW enabled = valid updateUI?() } - + /// Temporary binding mechanism for the view to update on enable changes. - public var updateUI: (() -> ())? - + public var updateUI: ActionBlock? + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -66,7 +98,7 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupW self.action = action style = .secondary } - + public init(primaryButtonWith title: String, action: ActionModelProtocol) { self.title = title self.action = action @@ -80,21 +112,16 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupW private enum CodingKeys: String, CodingKey { case moleculeName case backgroundColor - case isInverted = "inverted" case title + case inverted case action case enabled case style case size - case fillColor - case textColor - case borderColor - case disabledFillColor - case disabledTextColor - case disabledBorderColor + case facade case groupName } - + //-------------------------------------------------- // MARK: - Codec //-------------------------------------------------- @@ -102,10 +129,6 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupW required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - if let isInverted = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { - self.isInverted = isInverted - } - backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) title = try typeContainer.decode(String.self, forKey: .title) action = try typeContainer.decodeModel(codingKey: .action) @@ -126,30 +149,33 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupW self.enabled = enabled } - fillColor = try typeContainer.decodeIfPresent(Color.self, forKey: .fillColor) - textColor = try typeContainer.decodeIfPresent(Color.self, forKey: .textColor) - borderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .borderColor) - disabledFillColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledFillColor) - disabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledTextColor) - disabledBorderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledBorderColor) - } + if let facade = try typeContainer.decodeIfPresent(Facade.self, forKey: .facade) { + self.facade = facade + switch style { + case .primary: + primaryFacade = facade + case .secondary: + secondaryFacade = facade + } + } + + if let isInverted = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) { + self.isInverted = isInverted + } + } + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(moleculeName, forKey: .moleculeName) try container.encode(title, forKey: .title) - try container.encode(isInverted, forKey: .isInverted) - try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) - try container.encodeModel(action, forKey: .action) + try container.encode(isInverted, forKey: .inverted) try container.encode(enabled, forKey: .enabled) + try container.encodeModel(action, forKey: .action) + try container.encodeIfPresent(facade, forKey: .facade) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(style, forKey: .style) try container.encodeIfPresent(size, forKey: .size) - try container.encodeIfPresent(fillColor, forKey: .fillColor) - try container.encodeIfPresent(textColor, forKey: .textColor) - try container.encodeIfPresent(borderColor, forKey: .borderColor) - try container.encodeIfPresent(disabledFillColor, forKey: .disabledFillColor) - try container.encodeIfPresent(disabledTextColor, forKey: .disabledTextColor) - try container.encodeIfPresent(disabledBorderColor, forKey: .disabledBorderColor) try container.encodeIfPresent(groupName, forKey: .groupName) } } diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift index 19f032fc..3cea7765 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/PillButton.swift @@ -8,78 +8,93 @@ import UIKit + open class PillButton: Button, MVMCoreUIViewConstrainingProtocol { - // Used to size the button. + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + /// Used to size the button. var size = MVMCoreUIUtility.getWidth() var buttonModel: ButtonModel? { get { return model as? ButtonModel } } - // Need to re-style on set. + /// Need to re-style on set. open override var isEnabled: Bool { - didSet { - style() - } + didSet { style() } } - private enum ButtonHeight: CGFloat { + private enum Height: CGFloat { case tiny = 20 case standard = 42 } + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + /// The primary styling for a button. Should be used for main buttons public func stylePrimary() { - setTitleColor(.white, for: .normal) - setTitleColor(.white, for: .disabled) + + buttonModel?.style = .primary + setTitleColor(buttonModel?.facade?.enabled.text ?? .mvmWhite, for: .normal) + setTitleColor(buttonModel?.facade?.disabled.text ?? .mvmWhite, for: .disabled) layer.borderWidth = 0 - if isEnabled { - backgroundColor = .black - } else { - backgroundColor = .mvmCoolGray6 - } + backgroundColor = isEnabled ? buttonModel?.facade?.enabled.fill ?? .mvmBlack : buttonModel?.facade?.enabled.fill ?? .mvmCoolGray6 } /// The secondary styling for a button. Should be used for secondary buttons public func styleSecondary() { - setTitleColor(.black, for: .normal) - setTitleColor(.mvmCoolGray6, for: .disabled) + + buttonModel?.style = .secondary + setTitleColor(buttonModel?.facade?.enabled.text ?? .mvmBlack, for: .normal) + setTitleColor(buttonModel?.facade?.disabled.text ?? .mvmCoolGray6, for: .disabled) backgroundColor = .clear layer.borderWidth = 1 + if isEnabled { - layer.borderColor = UIColor.black.cgColor + layer.borderColor = buttonModel?.facade?.enabled.border?.cgColor ?? UIColor.mvmBlack.cgColor } else { - layer.borderColor = UIColor.mvmCoolGray6.cgColor + layer.borderColor = buttonModel?.facade?.enabled.border?.cgColor ?? UIColor.mvmCoolGray6.cgColor } } /// Styles the button based on the model style private func style() { + switch buttonModel?.style { case .secondary: styleSecondary() + default: stylePrimary() } - if let titleColor = buttonModel?.textColor { - setTitleColor(titleColor.uiColor, for: .normal) + + if let titleColor = buttonModel?.facade?.enabled.text { + setTitleColor(titleColor, for: .normal) } - if let disabledTitleColor = buttonModel?.disabledTextColor { - setTitleColor(disabledTitleColor.uiColor, for: .disabled) + + if let disabledTitleColor = buttonModel?.facade?.disabled.text { + setTitleColor(disabledTitleColor, for: .disabled) } + if isEnabled { - if let fillColor = buttonModel?.fillColor { - backgroundColor = fillColor.uiColor + if let fillColor = buttonModel?.facade?.enabled.fill { + backgroundColor = fillColor } - if let borderColor = buttonModel?.borderColor { + + if let borderColor = buttonModel?.facade?.enabled.border { layer.borderWidth = 1 layer.borderColor = borderColor.cgColor } } else { - if let fillColor = buttonModel?.disabledFillColor { - backgroundColor = fillColor.uiColor + if let fillColor = buttonModel?.facade?.disabled.fill { + backgroundColor = fillColor } - if let borderColor = buttonModel?.disabledBorderColor { + + if let borderColor = buttonModel?.facade?.disabledBorderColor { layer.borderWidth = 1 layer.borderColor = borderColor.cgColor } @@ -87,7 +102,7 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol { } private func getInnerPadding() -> CGFloat { - return getHeight() / 2.0 + return getHeight() / 2 } private func getHeight() -> CGFloat { @@ -95,78 +110,95 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol { } public static func getHeight(for buttonSize: ButtonSize?, size: CGFloat) -> CGFloat { + switch buttonSize { case .tiny: - return MFSizeObject(standardSize: ButtonHeight.tiny.rawValue, standardiPadPortraitSize: 34, iPadProLandscapeSize: 38)?.getValueBased(onSize: size) ?? ButtonHeight.tiny.rawValue + return MFSizeObject(standardSize: Height.tiny.rawValue, standardiPadPortraitSize: 34, iPadProLandscapeSize: 38)?.getValueBased(onSize: size) ?? Height.tiny.rawValue + default: - return MFSizeObject(standardSize: ButtonHeight.standard.rawValue, standardiPadPortraitSize: 46, iPadProLandscapeSize: 50)?.getValueBased(onSize: size) ?? ButtonHeight.standard.rawValue + return MFSizeObject(standardSize: Height.standard.rawValue, standardiPadPortraitSize: 46, iPadProLandscapeSize: 50)?.getValueBased(onSize: size) ?? Height.standard.rawValue } } - + private func getMinimumWidth() -> CGFloat { + switch buttonModel?.size { case .tiny: - return MFSizeObject(standardSize: 49.0, standardiPadPortraitSize: 90.0, iPadProLandscapeSize: 135.0)?.getValueBased(onSize: size) ?? 49.0 + return MFSizeObject(standardSize: 49, standardiPadPortraitSize: 90, iPadProLandscapeSize: 135)?.getValueBased(onSize: size) ?? 49 + default: - return 151.0 + return 151 } } open override var intrinsicContentSize: CGSize { + let size = super.intrinsicContentSize let width = size.width + (2 * getInnerPadding()) return CGSize(width: max(width, getMinimumWidth()), height: getHeight()) } - // MARK: - MoleculeViewProtocol + //-------------------------------------------------- + // 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) - + guard let model = model as? ButtonModel else { return } setTitle(model.title, for: .normal) - + model.updateUI = { [weak self] in MVMCoreDispatchUtility.performBlock(onMainThread: { self?.enableField(model.enabled) }) } + style() + FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate) } - + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { PillButton.getHeight(for: (model as? ButtonModel)?.size, size: MVMCoreUIUtility.getWidth()) } - // MARK: - MVMCoreViewProtocol open override func updateView(_ size: CGFloat) { super.updateView(size) self.size = size + invalidateIntrinsicContentSize() + switch buttonModel?.size { case .tiny: - titleLabel?.font = MFFonts.mfFont75Bd(11 * (intrinsicContentSize.height / ButtonHeight.tiny.rawValue)) + titleLabel?.font = MFFonts.mfFont75Bd(11 * (intrinsicContentSize.height / Height.tiny.rawValue)) + default: - titleLabel?.font = MFFonts.mfFont75Bd(13 * (intrinsicContentSize.height / ButtonHeight.standard.rawValue)) + titleLabel?.font = MFFonts.mfFont75Bd(13 * (intrinsicContentSize.height / Height.standard.rawValue)) } + layer.cornerRadius = getInnerPadding() } - + open override func setupView() { super.setupView() + titleLabel?.numberOfLines = 1 titleLabel?.lineBreakMode = .byTruncatingTail titleLabel?.textAlignment = .center contentHorizontalAlignment = .center stylePrimary() } - + + //-------------------------------------------------- // MARK: - MVMCoreUIViewConstrainingProtocol + //-------------------------------------------------- + open func horizontalAlignment() -> UIStackView.Alignment { return .center } - + public func enableField(_ enable: Bool) { isEnabled = enable } diff --git a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonView.swift b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonView.swift index 285c429c..a789eebb 100644 --- a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonView.swift +++ b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonView.swift @@ -9,11 +9,24 @@ import UIKit @objcMembers open class TwoButtonView: View, MVMCoreUIViewConstrainingProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + open var primaryButton: PillButton = PillButton() open var secondaryButton: PillButton = PillButton() private var stack = UIStackView() + + //-------------------------------------------------- + // MARK: - Constraints + //-------------------------------------------------- + private var equalWidthConstraint: NSLayoutConstraint? - + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + public init() { super.init(frame: .zero) } @@ -26,12 +39,15 @@ import UIKit super.init(frame: frame) } + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + public func setDefault() { primaryButton.stylePrimary() secondaryButton.styleSecondary() } - // MARK: - MVMCoreViewProtocol open override func updateView(_ size: CGFloat) { super.updateView(size) self.primaryButton.updateView(size) @@ -52,58 +68,68 @@ import UIKit equalWidthConstraint?.isActive = true } + //-------------------------------------------------- // MARK: - Stack Manipulation + //-------------------------------------------------- + public func showPrimaryButton() { + if !stack.arrangedSubviews.contains(primaryButton) { stack.addArrangedSubview(primaryButton) primaryButton.isHidden = false } + if secondaryButton.superview != nil { equalWidthConstraint?.isActive = true } } public func showSecondaryButton() { + if !stack.arrangedSubviews.contains(secondaryButton) { stack.insertArrangedSubview(secondaryButton, at: 0) secondaryButton.isHidden = false } + if primaryButton.superview != nil { equalWidthConstraint?.isActive = true } } public func hidePrimaryButton() { + if primaryButton.superview != nil { stack.removeArrangedSubview(primaryButton) primaryButton.isHidden = true } + equalWidthConstraint?.isActive = false } public func hideSecondaryButton() { + if secondaryButton.superview != nil { stack.removeArrangedSubview(secondaryButton) secondaryButton.isHidden = true } + equalWidthConstraint?.isActive = false } + //-------------------------------------------------- // MARK: - MoleculeViewProtocol + //-------------------------------------------------- + open override func reset() { super.reset() setDefault() } - - // MARK: - MVMCoreUIViewConstrainingProtocol - open func horizontalAlignment() -> UIStackView.Alignment { - return .center - } - // MARK: - MoleculeViewProtocol public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { guard let model = model as? TwoButtonViewModel, - let buttonModel = model.primaryButton ?? model.secondaryButton else { return 0 } + let buttonModel = model.primaryButton ?? model.secondaryButton + else { return 0 } + return PillButton.estimatedHeight(with: buttonModel, delegateObject) } @@ -118,6 +144,7 @@ import UIKit } else { hideSecondaryButton() } + if let primaryModel = model.primaryButton { showPrimaryButton() primaryButton.set(with: primaryModel, delegateObject, additionalData) @@ -125,4 +152,11 @@ import UIKit hidePrimaryButton() } } + //-------------------------------------------------- + // MARK: - MVMCoreUIViewConstrainingProtocol + //-------------------------------------------------- + + open func horizontalAlignment() -> UIStackView.Alignment { + return .center + } } diff --git a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonViewModel.swift b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonViewModel.swift index 057203e9..4e0c8363 100644 --- a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonViewModel.swift +++ b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonViewModel.swift @@ -8,12 +8,21 @@ import UIKit + public class TwoButtonViewModel: MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "twoButtonView" public var backgroundColor: Color? public var primaryButton: ButtonModel? public var secondaryButton: ButtonModel? + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case backgroundColor @@ -21,20 +30,25 @@ public class TwoButtonViewModel: MoleculeModelProtocol { case secondaryButton } + //-------------------------------------------------- + // MARK: - Initialzer + //-------------------------------------------------- + public init(_ primaryButton: ButtonModel?, _ secondaryButton: ButtonModel?) { self.primaryButton = primaryButton self.secondaryButton = secondaryButton } + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) primaryButton = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .primaryButton) secondaryButton = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .secondaryButton) - // Default value - if secondaryButton?.style == nil { - secondaryButton?.style = .secondary - } + secondaryButton?.style = .secondary } public func encode(to encoder: Encoder) throws { diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift index e40fbc33..09ca1b41 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift @@ -12,6 +12,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol //-------------------------------------------------- // MARK: - Stored Properties //-------------------------------------------------- + public var moleculesInfo: [(identifier: String, class: AnyClass, molecule: (ListItemModelProtocol & MoleculeModelProtocol))]? var observer: NSKeyValueObservation? diff --git a/MVMCoreUI/Atomic/Templates/TemplateModel.swift b/MVMCoreUI/Atomic/Templates/TemplateModel.swift index 86da1981..3dcf3964 100644 --- a/MVMCoreUI/Atomic/Templates/TemplateModel.swift +++ b/MVMCoreUI/Atomic/Templates/TemplateModel.swift @@ -8,24 +8,39 @@ import Foundation + @objcMembers public class TemplateModel: MVMControllerModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public class var identifier: String { return "" } + public var pageType: String public var template: String { // Although this is done in the extension, it is needed for the encoding. return Self.identifier } + public var backgroundColor: Color? public var screenHeading: String? public var navigationItem: (NavigationItemModelProtocol & MoleculeModelProtocol)? public var formRules: [FormGroupRule]? + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(pageType: String) { self.pageType = pageType } + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case pageType case template @@ -34,6 +49,10 @@ import Foundation case formRules case navigationItem } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) diff --git a/MVMCoreUI/Atomic/Templates/ThreeLayerTemplate.swift b/MVMCoreUI/Atomic/Templates/ThreeLayerTemplate.swift index 4884d5b1..cc305ee5 100644 --- a/MVMCoreUI/Atomic/Templates/ThreeLayerTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/ThreeLayerTemplate.swift @@ -24,25 +24,25 @@ import UIKit open override func viewForTop() -> UIView? { guard let headerModel = templateModel?.header, - let molecule = MoleculeObjectMapping.shared()?.createMolecule(headerModel, delegateObject: delegateObjectIVar) else { - return nil - } + let molecule = MoleculeObjectMapping.shared()?.createMolecule(headerModel, delegateObject: delegateObjectIVar) + else { return nil } + return molecule } open override func viewForMiddle() -> UIView? { guard let middleModel = templateModel?.middle, - let molecule = MoleculeObjectMapping.shared()?.createMolecule(middleModel, delegateObject: delegateObjectIVar) else { - return nil - } + let molecule = MoleculeObjectMapping.shared()?.createMolecule(middleModel, delegateObject: delegateObjectIVar) + else { return nil } + return molecule } override open func viewForBottom() -> UIView? { guard let footerModel = templateModel?.footer, - let molecule = MoleculeObjectMapping.shared()?.createMolecule(footerModel, delegateObject: delegateObjectIVar) else { - return nil - } + let molecule = MoleculeObjectMapping.shared()?.createMolecule(footerModel, delegateObject: delegateObjectIVar) + else { return nil } + return molecule } diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index ade66d03..6dede18f 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -257,7 +257,7 @@ import UIKit viewRespectsSystemMinimumLayoutMargins = false // Presents from the bottom. - modalPresentationStyle = MVMCoreGetterUtility.isOnIPad() ? UIModalPresentationStyle.formSheet : UIModalPresentationStyle.overCurrentContext + modalPresentationStyle = MVMCoreGetterUtility.isOnIPad() ? .formSheet : .overCurrentContext // Create the default delegate object. delegateObjectIVar = MVMCoreUIDelegateObject.create(withDelegateForAll: self) diff --git a/MVMCoreUI/Styles/Facade.swift b/MVMCoreUI/Styles/Facade.swift new file mode 100644 index 00000000..6940b92f --- /dev/null +++ b/MVMCoreUI/Styles/Facade.swift @@ -0,0 +1,177 @@ +// +// Facade.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 4/30/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public typealias FacadeElements = (fill: UIColor?, text: UIColor?, border: UIColor?) + + +public class Facade: Codable { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public var isInverted: Bool = false + + public lazy var enabled: FacadeElements = (fill: enabled_fillColor(), + text: enabled_textColor(), + border: enabled_borderColor()) + + public lazy var disabled: FacadeElements = (fill: disabled_fillColor(), + text: disabled_textColor(), + border: disabled_borderColor()) + + public var backgroundColor_standard: Color? + public var backgroundColor_inverted: Color? + + public var enabledFillColor: Color? + public var enabledTextColor: Color? + public var enabledBorderColor: Color? + + public var enabledFillColor_inverted: Color? + public var enabledTextColor_inverted: Color? + public var enabledBorderColor_inverted: Color? + + public var disabledFillColor: Color? + public var disabledTextColor: Color? + public var disabledBorderColor: Color? + + public var disabledFillColor_inverted: Color? + public var disabledTextColor_inverted: Color? + public var disabledBorderColor_inverted: Color? + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + + public init(isInverted: Bool = false, + backgroundColor_standard: Color? = nil, + backgroundColor_inverted: Color? = nil, + enabledFillColor: Color? = nil, + enabledTextColor: Color? = nil, + enabledBorderColor: Color? = nil, + disabledFillColor: Color? = nil, + disabledTextColor: Color? = nil, + disabledBorderColor: Color? = nil, + enabledFillColor_inverted: Color? = nil, + enabledTextColor_inverted: Color? = nil, + enabledBorderColor_inverted: Color? = nil, + disabledFillColor_inverted: Color? = nil, + disabledTextColor_inverted: Color? = nil, + disabledBorderColor_inverted: Color? = nil) { + + self.isInverted = isInverted + self.backgroundColor_standard = backgroundColor_standard + self.backgroundColor_inverted = backgroundColor_inverted + self.enabledFillColor = enabledFillColor + self.enabledTextColor = enabledTextColor + self.enabledBorderColor = enabledBorderColor + self.disabledFillColor = disabledFillColor + self.disabledTextColor = disabledTextColor + self.disabledBorderColor = disabledBorderColor + self.enabledFillColor_inverted = enabledFillColor_inverted + self.enabledTextColor_inverted = enabledTextColor_inverted + self.enabledBorderColor_inverted = enabledBorderColor_inverted + self.disabledFillColor_inverted = disabledFillColor_inverted + self.disabledTextColor_inverted = disabledTextColor_inverted + self.disabledBorderColor_inverted = disabledBorderColor_inverted + } + + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + + public func backgroundColor() -> UIColor? { + return (isInverted ? backgroundColor_inverted : backgroundColor_standard)?.uiColor + } + + public func enabled_fillColor() -> UIColor? { + return (isInverted ? enabledFillColor_inverted : enabledFillColor)?.uiColor + } + + public func enabled_textColor() -> UIColor? { + return (isInverted ? enabledTextColor_inverted : enabledTextColor)?.uiColor + } + + public func enabled_borderColor() -> UIColor? { + return (isInverted ? enabledBorderColor_inverted : enabledBorderColor)?.uiColor + } + + public func disabled_fillColor() -> UIColor? { + return (isInverted ? disabledFillColor_inverted : disabledFillColor)?.uiColor + } + + public func disabled_textColor() -> UIColor? { + return (isInverted ? disabledTextColor_inverted : disabledTextColor)?.uiColor + } + + public func disabled_borderColor() -> UIColor? { + return (isInverted ? disabledBorderColor_inverted : disabledBorderColor)?.uiColor + } + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case backgroundColor_standard + case backgroundColor_inverted + case enabledFillColor + case enabledTextColor + case enabledBorderColor + case enabledFillColor_inverted + case enabledTextColor_inverted + case enabledBorderColor_inverted + case disabledFillColor + case disabledTextColor + case disabledBorderColor + case disabledFillColor_inverted + case disabledTextColor_inverted + case disabledBorderColor_inverted + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + backgroundColor_standard = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor_standard) + backgroundColor_inverted = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor_inverted) + enabledFillColor = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledFillColor) + enabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledTextColor) + enabledBorderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledBorderColor) + enabledFillColor_inverted = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledFillColor_inverted) + enabledTextColor_inverted = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledTextColor_inverted) + enabledBorderColor_inverted = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledBorderColor_inverted) + disabledFillColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledFillColor) + disabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledTextColor) + disabledBorderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledBorderColor) + disabledFillColor_inverted = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledFillColor_inverted) + disabledTextColor_inverted = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledTextColor_inverted) + disabledBorderColor_inverted = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledBorderColor_inverted) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(backgroundColor_standard, forKey: .backgroundColor_standard) + try container.encodeIfPresent(backgroundColor_inverted, forKey: .backgroundColor_inverted) + try container.encodeIfPresent(enabledFillColor, forKey: .enabledFillColor) + try container.encodeIfPresent(enabledTextColor, forKey: .enabledTextColor) + try container.encodeIfPresent(enabledBorderColor, forKey: .enabledBorderColor) + try container.encodeIfPresent(enabledFillColor_inverted, forKey: .enabledFillColor_inverted) + try container.encodeIfPresent(enabledTextColor_inverted, forKey: .enabledTextColor_inverted) + try container.encodeIfPresent(enabledBorderColor_inverted, forKey: .enabledBorderColor_inverted) + try container.encodeIfPresent(disabledFillColor, forKey: .disabledFillColor) + try container.encodeIfPresent(disabledTextColor, forKey: .disabledTextColor) + try container.encodeIfPresent(disabledBorderColor, forKey: .disabledBorderColor) + try container.encodeIfPresent(disabledFillColor_inverted, forKey: .disabledFillColor_inverted) + try container.encodeIfPresent(disabledTextColor_inverted, forKey: .disabledTextColor_inverted) + try container.encodeIfPresent(disabledBorderColor_inverted, forKey: .disabledBorderColor_inverted) + } +}