From 6c7c683b2783142cff3d8729e39e4f75480b1c05 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 7 Jan 2022 12:53:06 -0600 Subject: [PATCH 01/17] added readOnly to models Signed-off-by: Matt Bruce --- .../TextFields/EntryFieldModel.swift | 8 ++++++-- .../Atoms/Selectors/CheckboxModel.swift | 13 +++++++------ .../Atomic/Atoms/Selectors/HeartModel.swift | 11 ++++++----- .../Atoms/Selectors/RadioBoxModel.swift | 8 +++++--- .../Atoms/Selectors/RadioBoxesModel.swift | 10 ++++++---- .../Atoms/Selectors/RadioButtonModel.swift | 11 ++++++----- .../Atomic/Atoms/Selectors/RadioSwatch.swift | 14 +++++++++++--- .../Atoms/Selectors/RadioSwatchModel.swift | 11 ++++++----- .../Atoms/Selectors/RadioSwatchesModel.swift | 11 +++++++---- .../Atomic/Atoms/Selectors/ToggleModel.swift | 9 +++++---- .../Molecules/Items/CarouselItemModel.swift | 11 +++++++++++ .../Organisms/Carousel/CarouselModel.swift | 19 +++++++++++++++---- .../FormUIHelpers/FormFieldProtocol.swift | 7 +++++++ 13 files changed, 98 insertions(+), 45 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryFieldModel.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryFieldModel.swift index 9520406f..2c4cc80c 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryFieldModel.swift @@ -29,6 +29,7 @@ import Foundation public var errorMessage: String? public var errorTextColor: Color? public var enabled: Bool = true + public var readOnly: Bool = false public var showError: Bool? public var hideBorders = false public var locked: Bool? @@ -73,6 +74,7 @@ import Foundation case accessibilityIdentifier case title case enabled + case readOnly case feedback case errorMessage case errorTextColor @@ -134,6 +136,7 @@ import Foundation errorMessage = try typeContainer.decodeIfPresent(String.self, forKey: .errorMessage) errorTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .errorTextColor) enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true + readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false locked = try typeContainer.decodeIfPresent(Bool.self, forKey: .locked) selected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected) text = try typeContainer.decodeIfPresent(String.self, forKey: .text) @@ -145,8 +148,8 @@ import Foundation if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) { self.groupName = groupName } - - //Setup the stateLabelModels + + //Setup the stateLabelModels if let titleLabel = titleLabel { self.titleStateLabel = StateLabelModel(model: titleLabel) } else { @@ -178,6 +181,7 @@ import Foundation try container.encodeIfPresent(fieldKey, forKey: .fieldKey) try container.encodeIfPresent(groupName, forKey: .groupName) + try container.encode(readOnly, forKey: .readOnly) try container.encode(enabled, forKey: .enabled) try container.encode(hideBorders, forKey: .hideBorders) } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift index 69f026ef..063c322a 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift @@ -23,7 +23,8 @@ public var backgroundColor: Color? public var accessibilityIdentifier: String? public var selected: Bool = false - public var enabled: Bool = true + public var enabled: Bool = true + public var readOnly: Bool = false public var animated: Bool = true public var inverted: Bool = false public var round: Bool = false @@ -54,6 +55,7 @@ case accessibilityIdentifier case checked case enabled + case readOnly case inverted case animated case round @@ -158,10 +160,8 @@ self.inverted = inverted } - if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { - self.enabled = enabled - } - + enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true + readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false action = try typeContainer.decodeModelIfPresent(codingKey: .action) fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey) @@ -191,7 +191,8 @@ try container.encodeIfPresent(disabledCheckColor, forKey: .disabledCheckColor) try container.encodeIfPresent(animated, forKey: .animated) try container.encodeIfPresent(round, forKey: .round) - try container.encodeIfPresent(enabled, forKey: .enabled) + try container.encode(enabled, forKey: .enabled) + try container.encode(readOnly, forKey: .readOnly) try container.encodeModelIfPresent(action, forKey: .action) try container.encodeIfPresent(groupName, forKey: .groupName) try container.encodeModelIfPresent(offAction, forKey: .offAction) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift index aea065ef..c03a7302 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift @@ -21,8 +21,8 @@ open class HeartModel: MoleculeModelProtocol, EnableableModelProtocol { public var inActiveColor: Color = Color(uiColor: .clear) public var action: ActionModelProtocol = ActionNoopModel() public var enabled: Bool = true - - //-------------------------------------------------- + public var readOnly: Bool = false + // MARK: - Keys //-------------------------------------------------- @@ -35,6 +35,7 @@ open class HeartModel: MoleculeModelProtocol, EnableableModelProtocol { case inActiveColor case action case enabled + case readOnly } //-------------------------------------------------- @@ -61,9 +62,8 @@ open class HeartModel: MoleculeModelProtocol, EnableableModelProtocol { if let action: ActionModelProtocol = try typeContainer.decodeModelIfPresent(codingKey: .action) { self.action = action } - if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { - self.enabled = enabled - } + enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true + readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false } public func encode(to encoder: Encoder) throws { @@ -76,5 +76,6 @@ open class HeartModel: MoleculeModelProtocol, EnableableModelProtocol { try container.encode(inActiveColor, forKey: .inActiveColor) try container.encodeModel(action, forKey: .action) try container.encode(enabled, forKey: .enabled) + try container.encode(readOnly, forKey: .readOnly) } } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioBoxModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioBoxModel.swift index f1b22dc3..fc299b50 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioBoxModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioBoxModel.swift @@ -19,6 +19,7 @@ public var selectedAccentColor: Color? public var selected: Bool = false public var enabled: Bool = true + public var readOnly: Bool = false public var strikethrough: Bool = false public var fieldValue: String? public var action: ActionModelProtocol? @@ -39,6 +40,7 @@ case strikethrough case fieldValue case action + case readOnly } //-------------------------------------------------- @@ -57,9 +59,8 @@ selected = isSelected } - if let isEnabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { - enabled = isEnabled - } + enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true + readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false if let isStrikeTrough = try typeContainer.decodeIfPresent(Bool.self, forKey: .strikethrough) { strikethrough = isStrikeTrough @@ -79,6 +80,7 @@ try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier) try container.encode(selected, forKey: .selected) try container.encode(enabled, forKey: .enabled) + try container.encode(readOnly, forKey: .readOnly) try container.encode(strikethrough, forKey: .strikethrough) try container.encodeIfPresent(fieldValue, forKey: .fieldValue) try container.encodeModelIfPresent(action, forKey: .action) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioBoxesModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioBoxesModel.swift index 1614f3ec..7e919553 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioBoxesModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioBoxesModel.swift @@ -21,7 +21,7 @@ public var groupName: String = FormValidator.defaultGroupName public var baseValue: AnyHashable? public var enabled: Bool = true - + public var readOnly: Bool = false //-------------------------------------------------- // MARK: - Methods //-------------------------------------------------- @@ -42,6 +42,7 @@ private enum CodingKeys: String, CodingKey { case moleculeName case enabled + case readOnly case selectedAccentColor case backgroundColor case accessibilityIdentifier @@ -66,9 +67,8 @@ if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) { self.groupName = groupName } - if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { - self.enabled = enabled - } + enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true + readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false baseValue = formFieldValue() } @@ -81,5 +81,7 @@ try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier) try container.encodeIfPresent(fieldKey, forKey: .fieldKey) try container.encode(groupName, forKey: .groupName) + try container.encode(enabled, forKey: .enabled) + try container.encode(readOnly, forKey: .readOnly) } } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonModel.swift index 445fd2a3..79fcb9cb 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonModel.swift @@ -19,6 +19,7 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol { public var accessibilityIdentifier: String? public var state: Bool = false public var enabled: Bool = true + public var readOnly: Bool = false /// The specific value to send to server. TODO: update this to be more generic. public var fieldValue: String? @@ -42,6 +43,7 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol { case fieldKey case groupName case action + case readOnly } //-------------------------------------------------- @@ -72,11 +74,9 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol { if let state = try typeContainer.decodeIfPresent(Bool.self, forKey: .state) { self.state = state } - - if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { - self.enabled = enabled - } - + + enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true + readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier) @@ -96,6 +96,7 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol { try container.encode(moleculeName, forKey: .moleculeName) try container.encode(state, forKey: .state) try container.encode(enabled, forKey: .enabled) + try container.encode(readOnly, forKey: .readOnly) try container.encodeIfPresent(fieldKey, forKey: .fieldKey) try container.encodeIfPresent(groupName, forKey: .groupName) try container.encodeIfPresent(fieldValue, forKey: .fieldValue) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift index e80f8813..f927f7e9 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift @@ -39,6 +39,12 @@ open class RadioSwatch: Control, MFButtonProtocol { } } + public override var isReadOnly: Bool { + didSet { + updateAccessibility() + } + } + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -65,6 +71,7 @@ open class RadioSwatch: Control, MFButtonProtocol { bottomText.text = model.text isSelected = model.selected isEnabled = model.enabled + isReadOnly = model.readOnly } public override func reset() { @@ -72,6 +79,7 @@ open class RadioSwatch: Control, MFButtonProtocol { bottomText.text = nil isSelected = false isEnabled = true + isReadOnly = false } //------------------------------------------------------ @@ -106,7 +114,7 @@ open class RadioSwatch: Control, MFButtonProtocol { //Handle Mask maskLayer?.removeFromSuperlayer() - if !isEnabled { + if !isEnabled || isReadOnly { let mask = getMaskLayer() layer.mask = mask maskLayer = mask @@ -120,7 +128,7 @@ open class RadioSwatch: Control, MFButtonProtocol { } @objc open func selectSwatch() { - guard isEnabled, !isSelected else { return } + guard isEnabled, !isReadOnly, !isSelected else { return } isSelected = true radioSwatchModel?.selected = isSelected if let radioSwatchModel = radioSwatchModel, let actionModel = radioSwatchModel.action { @@ -193,7 +201,7 @@ open class RadioSwatch: Control, MFButtonProtocol { if isSelected { accessibilityTraits.insert(.selected) } - if !isEnabled { + if !isEnabled || isReadOnly { accessibilityTraits.insert(.notEnabled) } } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchModel.swift index 100e2311..059dd2c8 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchModel.swift @@ -19,6 +19,7 @@ public var text: String? public var selected: Bool = false public var enabled: Bool = true + public var readOnly: Bool = false public var strikethrough: Bool = false public var fieldValue: String? public var action: ActionModelProtocol? @@ -38,6 +39,7 @@ case strikethrough case fieldValue case action + case readOnly } //-------------------------------------------------- @@ -58,17 +60,15 @@ if let selected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected) { self.selected = selected } - - if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { - self.enabled = enabled - } - + if let strikethrough = try typeContainer.decodeIfPresent(Bool.self, forKey: .strikethrough) { self.strikethrough = strikethrough } fieldValue = try typeContainer.decodeIfPresent(String.self, forKey: .fieldValue) action = try typeContainer.decodeModelIfPresent(codingKey: .action) + enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true + readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false } public func encode(to encoder: Encoder) throws { @@ -83,5 +83,6 @@ try container.encode(strikethrough, forKey: .strikethrough) try container.encodeIfPresent(fieldValue, forKey: .fieldValue) try container.encodeModelIfPresent(action, forKey: .action) + try container.encode(readOnly, forKey: .readOnly) } } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchesModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchesModel.swift index 3fb6ec19..7e475081 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchesModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchesModel.swift @@ -20,7 +20,8 @@ public var groupName: String = FormValidator.defaultGroupName public var baseValue: AnyHashable? public var enabled: Bool = true - + public var readOnly: Bool = false + //-------------------------------------------------- // MARK: - Methods //-------------------------------------------------- @@ -46,6 +47,7 @@ case fieldKey case groupName case enabled + case readOnly } //-------------------------------------------------- @@ -61,9 +63,8 @@ if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) { self.groupName = groupName } - if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { - self.enabled = enabled - } + enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true + readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false baseValue = formFieldValue() } @@ -75,5 +76,7 @@ try container.encode(swatches, forKey: .swatches) try container.encodeIfPresent(fieldKey, forKey: .fieldKey) try container.encode(groupName, forKey: .groupName) + try container.encode(enabled, forKey: .enabled) + try container.encode(readOnly, forKey: .readOnly) } } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift index 22961e3f..4c860342 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift @@ -18,6 +18,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol { public var selected: Bool = false public var animated: Bool = true public var enabled: Bool = true + public var readOnly: Bool = false public var action: ActionModelProtocol? public var alternateAction: ActionModelProtocol? public var accessibilityText: String? @@ -39,6 +40,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol { case state case animated case enabled + case readOnly case action case backgroundColor case accessibilityIdentifier @@ -81,10 +83,6 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol { self.selected = state } - if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { - self.enabled = enabled - } - if let animated = try typeContainer.decodeIfPresent(Bool.self, forKey: .animated) { self.animated = animated } @@ -117,6 +115,8 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol { if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) { self.groupName = groupName } + enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true + readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false } public func encode(to encoder: Encoder) throws { @@ -136,5 +136,6 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol { try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText) try container.encodeIfPresent(fieldKey, forKey: .fieldKey) try container.encodeIfPresent(groupName, forKey: .groupName) + try container.encode(readOnly, forKey: .readOnly) } } diff --git a/MVMCoreUI/Atomic/Molecules/Items/CarouselItemModel.swift b/MVMCoreUI/Atomic/Molecules/Items/CarouselItemModel.swift index f2122901..9858190d 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/CarouselItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/CarouselItemModel.swift @@ -20,6 +20,7 @@ public var analyticsData: JSONValueDictionary? public var fieldValue: String? public var enabled: Bool = true + public var readOnly: Bool = false public var fieldKey: String? public var groupName: String = FormValidator.defaultGroupName public var baseValue: AnyHashable? @@ -40,6 +41,8 @@ case fieldValue case fieldKey case groupName + case enabled + case readOnly } //-------------------------------------------------- @@ -57,6 +60,12 @@ self.groupName = groupName } baseValue = fieldValue + if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { + self.enabled = enabled + } + if let readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) { + self.readOnly = readOnly + } try super.init(from: decoder) } @@ -67,5 +76,7 @@ try container.encodeIfPresent(peakingArrowColor, forKey: .peakingArrowColor) try container.encodeIfPresent(analyticsData, forKey: .analyticsData) try container.encodeIfPresent(fieldValue, forKey: .fieldValue) + try container.encode(enabled, forKey: .enabled) + try container.encode(readOnly, forKey: .readOnly) } } diff --git a/MVMCoreUI/Atomic/Organisms/Carousel/CarouselModel.swift b/MVMCoreUI/Atomic/Organisms/Carousel/CarouselModel.swift index 35d29020..ed22696c 100644 --- a/MVMCoreUI/Atomic/Organisms/Carousel/CarouselModel.swift +++ b/MVMCoreUI/Atomic/Organisms/Carousel/CarouselModel.swift @@ -38,7 +38,8 @@ import UIKit public var fieldKey: String? public var groupName: String = FormValidator.defaultGroupName public var enabled: Bool = true - + public var readOnly: Bool = false + public var selectable = false public var selectedIndex: Int? @@ -87,6 +88,8 @@ import UIKit case fieldKey case selectable case selectedIndex + case enabled + case readOnly } //-------------------------------------------------- @@ -120,10 +123,16 @@ import UIKit if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) { self.groupName = groupName } + if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { + self.enabled = enabled + } + if let readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) { + self.readOnly = readOnly + } baseValue = formFieldValue() - } - - public func encode(to encoder: Encoder) throws { + } + + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(moleculeName, forKey: .moleculeName) try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) @@ -145,6 +154,8 @@ import UIKit try container.encode(index, forKey: .index) try container.encode(selectable, forKey: .selectable) try container.encode(selectedIndex, forKey: .selectedIndex) + try container.encode(enabled, forKey: .enabled) + try container.encode(enabled, forKey: .enabled) } } diff --git a/MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift b/MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift index afdde887..0a501440 100644 --- a/MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift +++ b/MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift @@ -16,11 +16,18 @@ public protocol FormFieldProtocol: FormItemProtocol { /// A place to store the initial value of the field for checking if the value has changed. var baseValue: AnyHashable? { get set } + ///Bool to determine a state that is different from disabled. Readonly values will be sent + ///to the server where disabled fields are not + var readOnly: Bool { get set } + /// Returns the value of the field. Used for validations and possibly for sending to server. func formFieldValue() -> AnyHashable? + } extension FormFieldProtocol { var baseValue: AnyHashable? { nil } + + var readOnly: Bool { false } } From 05674a67980a7dc89aec4671c4428c6fb430523f Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 7 Jan 2022 12:54:28 -0600 Subject: [PATCH 02/17] added isReadOnly to views/helpers to read the model.readOnly property and update the UI similarly to disabled state Signed-off-by: Matt Bruce --- .../TextFields/DigitEntryField.swift | 8 ++++++++ .../BaseDropdownEntryField.swift | 8 ++++++++ .../FormFields/TextFields/EntryField.swift | 14 +++++++++++++ .../TextFields/TextEntryField.swift | 16 ++++++++++++++- .../TextFields/TextViewEntryField.swift | 20 ++++++++++++++++++- .../Atomic/Atoms/Selectors/Checkbox.swift | 20 +++++++++++++++++-- MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift | 9 +++++---- .../Atomic/Atoms/Selectors/RadioBox.swift | 11 +++++++--- .../Atomic/Atoms/Selectors/RadioButton.swift | 5 +++-- .../RadioButtonSelectionHelper.swift | 4 +++- MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift | 13 ++++++++++-- .../CarouselIndicator/BarsIndicatorView.swift | 16 +++++++++++++-- .../NumericIndicatorView.swift | 6 +++++- MVMCoreUI/BaseClasses/Control.swift | 9 ++++++++- .../Views/EntryFieldContainer.swift | 15 ++++++++++++++ 15 files changed, 154 insertions(+), 20 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/DigitEntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/DigitEntryField.swift index c70d458e..f3fa96ba 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/DigitEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/DigitEntryField.swift @@ -90,6 +90,14 @@ import UIKit } } + public override var isReadOnly: Bool { + get { super.isReadOnly } + set (readOnly){ + digitBoxes.forEach { $0.isReadOnly = readOnly } + super.isReadOnly = readOnly + } + } + public override var showError: Bool { get { super.showError } set (error) { diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/BaseDropdownEntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/BaseDropdownEntryField.swift index d9b42a41..f70b0ce0 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/BaseDropdownEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/BaseDropdownEntryField.swift @@ -45,6 +45,14 @@ import UIKit } } + @objc public override var isReadOnly: Bool { + get { super.isReadOnly } + set (readOnly) { + dropDownCaretView.isEnabled = !readOnly + super.isReadOnly = readOnly + } + } + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift index 147f6f5f..c858fbda 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift @@ -66,6 +66,19 @@ import UIKit } } + /// Toggles readOnly (original) or disabled UI. + public var isReadOnly: Bool { + get { entryFieldContainer.isReadOnly } + set (readOnly) { + if(entryFieldContainer.isReadOnly != readOnly){ + titleLabel.isEnabled = !readOnly + feedbackLabel.isEnabled = !readOnly + entryFieldContainer.isReadOnly = readOnly + entryFieldModel?.readOnly = readOnly + } + } + } + /// Toggles error or original UI. public var showError: Bool { get { entryFieldContainer.showError } @@ -315,6 +328,7 @@ import UIKit defaultText = model.text ?? "" isEnabled = model.enabled + isReadOnly = model.readOnly model.updateUI = { [weak self] in MVMCoreDispatchUtility.performBlock(onMainThread: { guard let self = self else { return } diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift index 7973d652..6c8d8116 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift @@ -69,7 +69,21 @@ import UIKit guard let self = self else { return } self.textField.isEnabled = enabled - self.textField.textColor = enabled ? self.textEntryFieldModel?.enabledTextColor.uiColor : self.textEntryFieldModel?.disabledTextColor.uiColor + self.textField.textColor = enabled && !self.isReadOnly ? self.textEntryFieldModel?.enabledTextColor.uiColor : self.textEntryFieldModel?.disabledTextColor.uiColor + } + } + } + + public override var isReadOnly: Bool { + get { super.isReadOnly } + set (readOnly) { + super.isReadOnly = readOnly + + DispatchQueue.main.async { [weak self] in + guard let self = self else { return } + + self.textField.isEnabled = !readOnly + self.textField.textColor = !readOnly ? self.textEntryFieldModel?.enabledTextColor.uiColor : self.textEntryFieldModel?.disabledTextColor.uiColor } } } diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextViewEntryField.swift index 543469c1..8c1cafa8 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextViewEntryField.swift @@ -46,7 +46,25 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele if self.textView.isShowingPlaceholder { self.textView.textColor = self.textView.placeholderTextColor } else { - self.textView.textColor = (enabled ? self.textViewEntryFieldModel?.enabledTextColor : self.textViewEntryFieldModel?.disabledTextColor)?.uiColor + self.textView.textColor = (enabled && !self.isReadOnly ? self.textViewEntryFieldModel?.enabledTextColor : self.textViewEntryFieldModel?.disabledTextColor)?.uiColor + } + } + } + } + + public override var isReadOnly: Bool { + get { super.isReadOnly } + set (readOnly) { + super.isReadOnly = readOnly + + DispatchQueue.main.async { [weak self] in + guard let self = self else { return } + + self.textView.isEnabled = !readOnly + if self.textView.isShowingPlaceholder { + self.textView.textColor = self.textView.placeholderTextColor + } else { + self.textView.textColor = (!readOnly ? self.textViewEntryFieldModel?.enabledTextColor : self.textViewEntryFieldModel?.disabledTextColor)?.uiColor } } } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift index 4481411e..8fbb2bea 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift @@ -84,7 +84,7 @@ import MVMCore isUserInteractionEnabled = isEnabled - if isEnabled { + if isEnabled && !self.isReadOnly { layer.borderColor = borderColor.cgColor backgroundColor = isSelected ? checkedBackgroundColor : unCheckedBackgroundColor setShapeLayerStrokeColor(checkColor) @@ -96,6 +96,20 @@ import MVMCore } } + public override var isReadOnly: Bool { + didSet{ + if isReadOnly { + layer.borderColor = disabledBorderColor.cgColor + backgroundColor = disabledBackgroundColor + setShapeLayerStrokeColor(disabledCheckColor) + } else { + layer.borderColor = borderColor.cgColor + backgroundColor = isSelected ? checkedBackgroundColor : unCheckedBackgroundColor + setShapeLayerStrokeColor(checkColor) + } + } + } + public var disabledBackgroundColor: UIColor = .clear public var disabledBorderColor: UIColor = .mvmCoolGray3 public var disabledCheckColor: UIColor = .mvmCoolGray3 @@ -239,7 +253,7 @@ import MVMCore self.shapeLayer = shapeLayer shapeLayer.frame = bounds layer.addSublayer(shapeLayer) - shapeLayer.strokeColor = isEnabled ? checkColor.cgColor : disabledCheckColor.cgColor + shapeLayer.strokeColor = isEnabled || !isReadOnly ? checkColor.cgColor : disabledCheckColor.cgColor shapeLayer.fillColor = UIColor.clear.cgColor shapeLayer.path = checkMarkPath() shapeLayer.lineJoin = .miter @@ -368,6 +382,7 @@ import MVMCore super.reset() isEnabled = true + isReadOnly = false shapeLayer?.removeAllAnimations() shapeLayer?.removeFromSuperlayer() shapeLayer = nil @@ -431,6 +446,7 @@ import MVMCore } isEnabled = model.enabled + isReadOnly = model.readOnly if (model.action != nil || model.offAction != nil) { actionBlock = { [weak self] in diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift index e694e194..cd423dca 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift @@ -62,7 +62,7 @@ import UIKit heartPath.close() heart.path = heartPath.cgPath heart.fillColor = isSelected ? heartModel?.activeColor.cgColor : heartModel?.inActiveColor.cgColor - heart.opacity = 1.0 + heart.opacity = isEnabled || !isReadOnly ? 1.0 : 0.5 heart.lineWidth = 1 heart.strokeColor = isSelected ? UIColor.clear.cgColor : UIColor.mvmBlack.cgColor return heart @@ -89,6 +89,7 @@ import UIKit guard let model = model as? HeartModel else { return } isSelected = model.isActive isEnabled = model.enabled + isReadOnly = model.readOnly updateAccessibilityLabel() } @@ -97,13 +98,13 @@ import UIKit //-------------------------------------------------- /// Adjust accessibility label based on selection of Heart. func updateAccessibilityLabel() { - accessibilityHint = isEnabled ? MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_unfavorite_action_hint" : "heart_favorite_action_hint") : nil - accessibilityTraits = isEnabled ? .button : .none + accessibilityHint = isEnabled || !isReadOnly ? MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_unfavorite_action_hint" : "heart_favorite_action_hint") : nil + accessibilityTraits = isEnabled || !isReadOnly ? .button : .none accessibilityLabel = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_selected_state" : "heart_not_selected_state") } func tapAction() { - guard isEnabled else { return } + guard isEnabled, !isReadOnly else { return } isSelected = !isSelected if let heartModel = heartModel { Button.performButtonAction(with: heartModel.action, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: heartModel) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioBox.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioBox.swift index 1d8c6960..693fe2a4 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioBox.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioBox.swift @@ -40,6 +40,10 @@ open class RadioBox: Control, MFButtonProtocol { didSet { updateAccessibility() } } + public override var isReadOnly: Bool { + didSet { updateAccessibility() } + } + //-------------------------------------------------- // MARK: - MVMCoreViewProtocol //-------------------------------------------------- @@ -90,6 +94,7 @@ open class RadioBox: Control, MFButtonProtocol { } isSelected = model.selected isEnabled = model.enabled + isReadOnly = model.readOnly } open override func reset() { @@ -124,7 +129,7 @@ open class RadioBox: Control, MFButtonProtocol { // Handle Mask maskLayer?.removeFromSuperlayer() - if !isEnabled { + if !isEnabled || isReadOnly { let mask = getMaskLayer() layer.mask = mask maskLayer = mask @@ -138,7 +143,7 @@ open class RadioBox: Control, MFButtonProtocol { } @objc open func selectBox() { - guard isEnabled, !isSelected else { return } + guard isEnabled, !isReadOnly, !isSelected else { return } isSelected = true radioBoxModel?.selected = isSelected if let radioBoxModel = radioBoxModel, let actionModel = radioBoxModel.action { @@ -237,7 +242,7 @@ open class RadioBox: Control, MFButtonProtocol { accessibilityTraits.insert(.selected) } - if !isEnabled { + if !isEnabled || isReadOnly { accessibilityTraits.insert(.notEnabled) } } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift index c6e1e049..11b917b0 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift @@ -66,7 +66,7 @@ import UIKit open override func draw(_ rect: CGRect) { guard let context = UIGraphicsGetCurrentContext() else { return } - let color = isEnabled ? enabledColor.cgColor : disabledColor.cgColor + let color = (isReadOnly == true || isEnabled == false) ? disabledColor.cgColor : enabledColor.cgColor layer.cornerRadius = bounds.width * 0.5 layer.borderColor = color layer.borderWidth = bounds.width * 0.0333 @@ -88,7 +88,7 @@ import UIKit /// The action performed when tapped. func tapAction() { - if !isEnabled { + if !isEnabled || isReadOnly { return } @@ -164,6 +164,7 @@ import UIKit isSelected = model.state isEnabled = model.enabled + isReadOnly = model.readOnly RadioButtonSelectionHelper.setupForRadioButtonGroup(model, self, delegateObject: delegateObject) } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonSelectionHelper.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonSelectionHelper.swift index 41f709c0..da7ef0c2 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonSelectionHelper.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonSelectionHelper.swift @@ -18,7 +18,8 @@ private var selectedRadioButtonModel: RadioButtonModel? public var baseValue: AnyHashable? public var enabled: Bool = true - + public var readOnly: Bool = false + //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- @@ -41,6 +42,7 @@ radioButton.isSelected = false } self.enabled = radioButtonModel.enabled + self.readOnly = radioButtonModel.readOnly } //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift index 3513a03b..a76424f0 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift @@ -67,6 +67,14 @@ public typealias ActionBlockConfirmation = () -> (Bool) } } + public override var isReadOnly: Bool { + didSet{ + changeStateNoAnimation(!isReadOnly ? isOn : false) + setToggleAppearanceFromState() + accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: !isReadOnly ? "AccToggleHint" : "AccDisabled") + } + } + /// Simple means to prevent user interaction with the toggle. public var isLocked: Bool = false { didSet { isUserInteractionEnabled = !isLocked } @@ -350,8 +358,8 @@ public typealias ActionBlockConfirmation = () -> (Bool) public func setToggleAppearanceFromState() { - backgroundColor = isEnabled ? isOn ? containerTintColor.on : containerTintColor.off : disabledTintColor.container - knobView.backgroundColor = isEnabled ? isOn ? knobTintColor.on : knobTintColor.off : disabledTintColor.knob + backgroundColor = isEnabled || !isReadOnly ? isOn ? containerTintColor.on : containerTintColor.off : disabledTintColor.container + knobView.backgroundColor = isEnabled || !isReadOnly ? isOn ? knobTintColor.on : knobTintColor.off : disabledTintColor.knob } public func knobReformAnimation() { @@ -385,6 +393,7 @@ public typealias ActionBlockConfirmation = () -> (Bool) changeStateNoAnimation(isOn) isAnimated = model.animated isEnabled = model.enabled + isReadOnly = model.readOnly if let accessibileString = model.accessibilityText { accessibilityLabel = accessibileString diff --git a/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/BarsIndicatorView.swift b/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/BarsIndicatorView.swift index 975c7ebb..1f2e7346 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/BarsIndicatorView.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/BarsIndicatorView.swift @@ -72,9 +72,21 @@ open class BarsIndicatorView: CarouselIndicator { didSet { for (i, indicatorBar) in barReferences.enumerated() { if i == currentIndex { - indicatorBar.backgroundColor = isEnabled ? currentIndicatorColor : disabledIndicatorColor + indicatorBar.backgroundColor = isEnabled && !isReadOnly ? currentIndicatorColor : disabledIndicatorColor } else { - indicatorBar.backgroundColor = isEnabled ? indicatorColor : disabledIndicatorColor + indicatorBar.backgroundColor = isEnabled && !isReadOnly ? indicatorColor : disabledIndicatorColor + } + } + } + } + + open override var isReadOnly: Bool { + didSet { + for (i, indicatorBar) in barReferences.enumerated() { + if i == currentIndex { + indicatorBar.backgroundColor = !isReadOnly ? currentIndicatorColor : disabledIndicatorColor + } else { + indicatorBar.backgroundColor = !isReadOnly ? indicatorColor : disabledIndicatorColor } } } diff --git a/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/NumericIndicatorView.swift b/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/NumericIndicatorView.swift index eb3a8ebd..e888fff8 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/NumericIndicatorView.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/NumericIndicatorView.swift @@ -42,7 +42,11 @@ open class NumericIndicatorView: CarouselIndicator { //-------------------------------------------------- open override var isEnabled: Bool { - didSet { setViewColor(isEnabled ? indicatorColor : disabledIndicatorColor) } + didSet { setViewColor(isEnabled && !isReadOnly ? indicatorColor : disabledIndicatorColor) } + } + + open override var isReadOnly: Bool { + didSet { setViewColor(!isReadOnly ? indicatorColor : disabledIndicatorColor) } } /// Sets the color for pageCount text, left arrow and right arrow. diff --git a/MVMCoreUI/BaseClasses/Control.swift b/MVMCoreUI/BaseClasses/Control.swift index a8fde2e5..3aebaf7e 100644 --- a/MVMCoreUI/BaseClasses/Control.swift +++ b/MVMCoreUI/BaseClasses/Control.swift @@ -13,7 +13,14 @@ import UIKit //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - + public var isReadOnly: Bool = false{ + didSet{ + //don't allow touches + isUserInteractionEnabled = !isReadOnly + setNeedsDisplay() + } + } + open var model: MoleculeModelProtocol? private var initialSetupPerformed = false diff --git a/MVMCoreUI/Containers/Views/EntryFieldContainer.swift b/MVMCoreUI/Containers/Views/EntryFieldContainer.swift index 9ccd1d25..f567d01f 100644 --- a/MVMCoreUI/Containers/Views/EntryFieldContainer.swift +++ b/MVMCoreUI/Containers/Views/EntryFieldContainer.swift @@ -55,6 +55,7 @@ import UIKit private var _showError: Bool = false private var _isLocked: Bool = false private var _isSelected: Bool = false + private var _isReadOnly: Bool = false public var isEnabled: Bool { get { return _isEnabled } @@ -69,6 +70,20 @@ import UIKit } } + public var isReadOnly: Bool { + get { return _isReadOnly } + set (readOnly) { + + _isEnabled = true + _isLocked = false + _isSelected = false + _showError = false + _isReadOnly = readOnly + + fieldState = readOnly ? .disabled : .original + } + } + public var showError: Bool { get { return _showError } set (error) { From cb3811f4ea5d5aac7b627444857f54c1c4eff7bd Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 10 Jan 2022 13:54:55 -0600 Subject: [PATCH 03/17] update readOnly didSet to only effect the FormField only and not title/feedback labels Signed-off-by: Matt Bruce --- .../Atoms/FormFields/TextFields/EntryField.swift | 2 -- .../FormFields/TextFields/TextEntryField.swift | 14 -------------- 2 files changed, 16 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift index c858fbda..6271c44a 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift @@ -71,8 +71,6 @@ import UIKit get { entryFieldContainer.isReadOnly } set (readOnly) { if(entryFieldContainer.isReadOnly != readOnly){ - titleLabel.isEnabled = !readOnly - feedbackLabel.isEnabled = !readOnly entryFieldContainer.isReadOnly = readOnly entryFieldModel?.readOnly = readOnly } diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift index 6c8d8116..cd0adf61 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift @@ -74,20 +74,6 @@ import UIKit } } - public override var isReadOnly: Bool { - get { super.isReadOnly } - set (readOnly) { - super.isReadOnly = readOnly - - DispatchQueue.main.async { [weak self] in - guard let self = self else { return } - - self.textField.isEnabled = !readOnly - self.textField.textColor = !readOnly ? self.textEntryFieldModel?.enabledTextColor.uiColor : self.textEntryFieldModel?.disabledTextColor.uiColor - } - } - } - public override var showError: Bool { get { super.showError } set (error) { From 63a23033cc37c901386d704e9e502d038443b0fa Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 11 Jan 2022 10:17:10 -0600 Subject: [PATCH 04/17] added ClearableModelProtocol Signed-off-by: Matt Bruce --- MVMCoreUI.xcodeproj/project.pbxproj | 4 ++ .../ClearFormFieldEffectModel.swift | 68 +++++++++++++++++++ .../OtherHandlers/CoreUIModelMapping.swift | 1 + 3 files changed, 73 insertions(+) create mode 100644 MVMCoreUI/FormUIHelpers/FormFieldEffect/ClearFormFieldEffectModel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index e2235ca3..fd0d814f 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -569,6 +569,7 @@ DBC4391922442197001AB423 /* DashLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391722442197001AB423 /* DashLine.swift */; }; DBC4391B224421A0001AB423 /* CaretLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391A224421A0001AB423 /* CaretLink.swift */; }; DBEFFA04225A829700230692 /* Label.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB891E822253FA8500022516 /* Label.swift */; }; + EA05EFA9278DDE2C00828819 /* ClearFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA05EFA8278DDE2C00828819 /* ClearFormFieldEffectModel.swift */; }; EA5124FD243601600051A3A4 /* BGImageHeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FC243601600051A3A4 /* BGImageHeadlineBodyButton.swift */; }; EA5124FF2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */; }; EA7E67742758310500ABF773 /* EnableFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7E67732758310500ABF773 /* EnableFormFieldEffectModel.swift */; }; @@ -1146,6 +1147,7 @@ DBC4391622442196001AB423 /* CaretView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretView.swift; sourceTree = ""; }; DBC4391722442197001AB423 /* DashLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashLine.swift; sourceTree = ""; }; DBC4391A224421A0001AB423 /* CaretLink.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretLink.swift; sourceTree = ""; }; + EA05EFA8278DDE2C00828819 /* ClearFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearFormFieldEffectModel.swift; sourceTree = ""; }; EA5124FC243601600051A3A4 /* BGImageHeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButton.swift; sourceTree = ""; }; EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButtonModel.swift; sourceTree = ""; }; EA7E67732758310500ABF773 /* EnableFormFieldEffectModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnableFormFieldEffectModel.swift; sourceTree = ""; }; @@ -2425,6 +2427,7 @@ EA7E67732758310500ABF773 /* EnableFormFieldEffectModel.swift */, EAA0CFB2275E831E00D65EB0 /* DisableFormFieldEffectModel.swift */, EAA0CFB0275E823A00D65EB0 /* HideFormFieldEffectModel.swift */, + EA05EFA8278DDE2C00828819 /* ClearFormFieldEffectModel.swift */, ); path = FormFieldEffect; sourceTree = ""; @@ -3013,6 +3016,7 @@ 52267A0723FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift in Sources */, D2ED2812254B0EB800A1C293 /* MVMCoreTopAlertObject.m in Sources */, 0AA4D2E125CAEC72008DB32D /* AccessibilityModelProtocol.swift in Sources */, + EA05EFA9278DDE2C00828819 /* ClearFormFieldEffectModel.swift in Sources */, C003506123AA94CD00B6AC29 /* Button.swift in Sources */, DBC4391B224421A0001AB423 /* CaretLink.swift in Sources */, D29C559025C095210082E7D6 /* Video.swift in Sources */, diff --git a/MVMCoreUI/FormUIHelpers/FormFieldEffect/ClearFormFieldEffectModel.swift b/MVMCoreUI/FormUIHelpers/FormFieldEffect/ClearFormFieldEffectModel.swift new file mode 100644 index 00000000..07810fe6 --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/FormFieldEffect/ClearFormFieldEffectModel.swift @@ -0,0 +1,68 @@ +// +// ClearFormFieldEffectModel.swift +// MVMCoreUI +// +// Created by Matt Bruce on 1/11/22. +// Copyright © 2022 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol ClearableModelProtocol { + func clear() +} + +public class ClearFormFieldEffectModel: FormFieldEffectProtocol { + + + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public static var identifier: String = "clearFormFieldEffect" + public var fieldKey: String = "" + public var activatedRuleIds: [String]? + public var rules: [RulesProtocol] + + init(_ fieldKey: String, activatedRuleIds: [String], rules: [RulesProtocol]) { + self.fieldKey = fieldKey + self.activatedRuleIds = activatedRuleIds + self.rules = rules + } + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case fieldKey + case activatedRuleIds + case rules + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + self.fieldKey = try typeContainer.decode(String.self, forKey: .fieldKey) + self.activatedRuleIds = try typeContainer.decodeIfPresent([String].self, forKey: .activatedRuleIds) + self.rules = try typeContainer.decodeModels(codingKey: .rules) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(fieldKey, forKey: .fieldKey) + try container.encode(activatedRuleIds, forKey: .activatedRuleIds) + try container.encodeModels(rules, forKey: .rules) + } + + public func setEffect(validity: Bool, field: FormFieldProtocol,form: FormValidator, group: FormGroupRule) { + guard let field = field as? ClearableModelProtocol, validity else { return } + field.clear() + if let updateField = field as? UIUpdatableModelProtocol { + updateField.updateUI?() + } + } +} diff --git a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift index 11328440..45021394 100644 --- a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift +++ b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift @@ -246,5 +246,6 @@ open class CoreUIModelMapping: ModelMapping { ModelRegistry.register(EnableFormFieldEffectModel.self) ModelRegistry.register(DisableFormFieldEffectModel.self) ModelRegistry.register(HideFormFieldEffectModel.self) + ModelRegistry.register(ClearFormFieldEffectModel.self) } } From 95b32491d1cf4e5ac05faf44b3114c67b2cf2df6 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 11 Jan 2022 10:19:12 -0600 Subject: [PATCH 05/17] moved clearablemodelprotocol out of the formfieldeffect Signed-off-by: Matt Bruce --- MVMCoreUI.xcodeproj/project.pbxproj | 4 ++++ .../ModelProtocols/ClearableModelProtocol.swift | 13 +++++++++++++ .../FormFieldEffect/ClearFormFieldEffectModel.swift | 4 ---- 3 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 MVMCoreUI/Atomic/Protocols/ModelProtocols/ClearableModelProtocol.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index fd0d814f..4468b193 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -570,6 +570,7 @@ DBC4391B224421A0001AB423 /* CaretLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391A224421A0001AB423 /* CaretLink.swift */; }; DBEFFA04225A829700230692 /* Label.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB891E822253FA8500022516 /* Label.swift */; }; EA05EFA9278DDE2C00828819 /* ClearFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA05EFA8278DDE2C00828819 /* ClearFormFieldEffectModel.swift */; }; + EA05EFAB278DE53600828819 /* ClearableModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA05EFAA278DE53600828819 /* ClearableModelProtocol.swift */; }; EA5124FD243601600051A3A4 /* BGImageHeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FC243601600051A3A4 /* BGImageHeadlineBodyButton.swift */; }; EA5124FF2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */; }; EA7E67742758310500ABF773 /* EnableFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7E67732758310500ABF773 /* EnableFormFieldEffectModel.swift */; }; @@ -1148,6 +1149,7 @@ DBC4391722442197001AB423 /* DashLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashLine.swift; sourceTree = ""; }; DBC4391A224421A0001AB423 /* CaretLink.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretLink.swift; sourceTree = ""; }; EA05EFA8278DDE2C00828819 /* ClearFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearFormFieldEffectModel.swift; sourceTree = ""; }; + EA05EFAA278DE53600828819 /* ClearableModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearableModelProtocol.swift; sourceTree = ""; }; EA5124FC243601600051A3A4 /* BGImageHeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButton.swift; sourceTree = ""; }; EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButtonModel.swift; sourceTree = ""; }; EA7E67732758310500ABF773 /* EnableFormFieldEffectModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnableFormFieldEffectModel.swift; sourceTree = ""; }; @@ -1181,6 +1183,7 @@ D23EA7FA2475F09800D60C34 /* CarouselItemProtocol.swift */, 012A88C3238D86E600FE3DA1 /* CarouselItemModelProtocol.swift */, 012A88B0238C880100FE3DA1 /* CarouselPagingModelProtocol.swift */, + EA05EFAA278DE53600828819 /* ClearableModelProtocol.swift */, 01EB3683236097C0006832FA /* MoleculeModelProtocol.swift */, 012A889B23889E8400FE3DA1 /* TemplateModelProtocol.swift */, D28A837823C7D5BC00DFE4FC /* PageModelProtocol.swift */, @@ -2851,6 +2854,7 @@ D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */, 011B58F223A2AE2C0085F53C /* DropDownListItemModel.swift in Sources */, D2509ED12472ED9B001BFB9D /* NavigationItemModelProtocol.swift in Sources */, + EA05EFAB278DE53600828819 /* ClearableModelProtocol.swift in Sources */, 8D448E5524050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift in Sources */, BBC0C4FD24811DBC0087C44F /* Tag.swift in Sources */, 94C2D9842386F3F80006CF46 /* LabelAttributeModel.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/ClearableModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/ClearableModelProtocol.swift new file mode 100644 index 00000000..046e23d5 --- /dev/null +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/ClearableModelProtocol.swift @@ -0,0 +1,13 @@ +// +// ClearableModelProtocol.swift +// MVMCoreUI +// +// Created by Matt Bruce on 1/11/22. +// Copyright © 2022 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol ClearableModelProtocol { + func clear() +} diff --git a/MVMCoreUI/FormUIHelpers/FormFieldEffect/ClearFormFieldEffectModel.swift b/MVMCoreUI/FormUIHelpers/FormFieldEffect/ClearFormFieldEffectModel.swift index 07810fe6..fefe8499 100644 --- a/MVMCoreUI/FormUIHelpers/FormFieldEffect/ClearFormFieldEffectModel.swift +++ b/MVMCoreUI/FormUIHelpers/FormFieldEffect/ClearFormFieldEffectModel.swift @@ -8,10 +8,6 @@ import Foundation -public protocol ClearableModelProtocol { - func clear() -} - public class ClearFormFieldEffectModel: FormFieldEffectProtocol { From 8444ad15ebaccac366b6f2a0d0f43f6e37853a39 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 11 Jan 2022 15:47:37 -0600 Subject: [PATCH 06/17] refactored StateLabelModel/StateLabel to FormLabelModel/FormLabel removed state (error/disabled/error) replace with enabled (model) / isEnabled (view) Signed-off-by: Matt Bruce --- MVMCoreUI.xcodeproj/project.pbxproj | 16 +++--- .../{StateLabel.swift => FormLabel.swift} | 39 +++++--------- ...eLabelModel.swift => FormLabelModel.swift} | 54 ++++++++----------- 3 files changed, 44 insertions(+), 65 deletions(-) rename MVMCoreUI/Atomic/Atoms/Views/Label/{StateLabel.swift => FormLabel.swift} (61%) rename MVMCoreUI/Atomic/Atoms/Views/Label/{StateLabelModel.swift => FormLabelModel.swift} (55%) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 4468b193..0ad937c6 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -578,8 +578,8 @@ EAA0CFAF275E7D8000D65EB0 /* FormFieldEffectProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA0CFAE275E7D8000D65EB0 /* FormFieldEffectProtocol.swift */; }; EAA0CFB1275E823A00D65EB0 /* HideFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA0CFB0275E823A00D65EB0 /* HideFormFieldEffectModel.swift */; }; EAA0CFB3275E831E00D65EB0 /* DisableFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA0CFB2275E831E00D65EB0 /* DisableFormFieldEffectModel.swift */; }; - EABFC1412763BB8D00E78B40 /* StateLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC1402763BB8D00E78B40 /* StateLabel.swift */; }; - EABFC152276913E800E78B40 /* StateLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC151276913E800E78B40 /* StateLabelModel.swift */; }; + EABFC1412763BB8D00E78B40 /* FormLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC1402763BB8D00E78B40 /* FormLabel.swift */; }; + EABFC152276913E800E78B40 /* FormLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC151276913E800E78B40 /* FormLabelModel.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -1157,8 +1157,8 @@ EAA0CFAE275E7D8000D65EB0 /* FormFieldEffectProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormFieldEffectProtocol.swift; sourceTree = ""; }; EAA0CFB0275E823A00D65EB0 /* HideFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HideFormFieldEffectModel.swift; sourceTree = ""; }; EAA0CFB2275E831E00D65EB0 /* DisableFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisableFormFieldEffectModel.swift; sourceTree = ""; }; - EABFC1402763BB8D00E78B40 /* StateLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateLabel.swift; sourceTree = ""; }; - EABFC151276913E800E78B40 /* StateLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateLabelModel.swift; sourceTree = ""; }; + EABFC1402763BB8D00E78B40 /* FormLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormLabel.swift; sourceTree = ""; }; + EABFC151276913E800E78B40 /* FormLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormLabelModel.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1449,8 +1449,8 @@ 94C2D9A823872E5E0006CF46 /* LabelAttributeImageModel.swift */, 94C2D9AA23872EB50006CF46 /* LabelAttributeActionModel.swift */, DB891E822253FA8500022516 /* Label.swift */, - EABFC151276913E800E78B40 /* StateLabelModel.swift */, - EABFC1402763BB8D00E78B40 /* StateLabel.swift */, + EABFC151276913E800E78B40 /* FormLabelModel.swift */, + EABFC1402763BB8D00E78B40 /* FormLabel.swift */, ); path = Label; sourceTree = ""; @@ -2573,7 +2573,7 @@ 324FB6AA249366F3002552C7 /* ListLeftVariableNumberedListBodyTextModel.swift in Sources */, 5248BFED23F12E350059236A /* ListThreeColumnPlanDataDividerModel.swift in Sources */, AA0A257824766C8A00862F64 /* ListLeftVariableIconWithRightCaretBodyTextModel.swift in Sources */, - EABFC152276913E800E78B40 /* StateLabelModel.swift in Sources */, + EABFC152276913E800E78B40 /* FormLabelModel.swift in Sources */, 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */, 0AF60F0926B3316E00AC3DB4 /* MVMCoreUIUtility+Extension.swift in Sources */, 8D070BB0241B56530099AC56 /* ListRightVariableTotalDataModel.swift in Sources */, @@ -2998,7 +2998,7 @@ 013F801923FB4A8E00AD8013 /* UIContentMode+Extension.swift in Sources */, AA104AC724472DB0004D2810 /* HeadersH1Button.swift in Sources */, 525239C22407BD1000454969 /* ListTwoColumnPriceDetails.swift in Sources */, - EABFC1412763BB8D00E78B40 /* StateLabel.swift in Sources */, + EABFC1412763BB8D00E78B40 /* FormLabel.swift in Sources */, AA997252247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift in Sources */, D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */, D23EA7FB2475F09800D60C34 /* CarouselItemProtocol.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/StateLabel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/FormLabel.swift similarity index 61% rename from MVMCoreUI/Atomic/Atoms/Views/Label/StateLabel.swift rename to MVMCoreUI/Atomic/Atoms/Views/Label/FormLabel.swift index d20755c7..08b7267e 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/StateLabel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/FormLabel.swift @@ -9,35 +9,31 @@ import Foundation /// Subclass of label that helps with different states -public class StateLabel: Label { +public class FormLabel: Label { //properties used in setting label private var delegateObject: MVMCoreUIDelegateObject? private var additionalData: [AnyHashable: Any]? //models that drive the label UI - private var stateModel: StateLabelModel! + private var formModel: FormLabelModel! //public properties public override var isEnabled: Bool { didSet{ - self.state = isEnabled ? .enabled : .disabled + self.formModel.enabled = isEnabled + self.set(with: isRequired ? formModel.model : formModel.requiredModel, delegateObject, additionalData) + } + } + + public var isRequired: Bool = true { + didSet{ + self.set(with: isRequired ? formModel.model : formModel.requiredModel, delegateObject, additionalData) } } public override func reset(){ super.reset() - self.state = .enabled - } - - //current mode of label - public var state: StateLabelModel.State { - get { - return self.stateModel.state - } - set { - self.stateModel.state = newValue - self.set(with: stateModel.model, delegateObject, additionalData) - } + self.isEnabled = true } /// Used in setting up the Label for use @@ -46,25 +42,18 @@ public class StateLabel: Label { /// - model: Model takes priority over a text value. The model has its own text value that will be looked at to draw the screen, this model is used for both enabled/disabled models /// - delegateObject: passed in from the creator /// - additionalData: passed in from the creator - public func setup(model: StateLabelModel, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?){ + public func setup(model: FormLabelModel, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?){ self.additionalData = additionalData self.delegateObject = delegateObject - self.stateModel = model + self.formModel = model //default to enabled state self.reset() } - /// Use this to switch the label into a error state - /// - Parameter message: message to show in the errorModel - public func showError(message: String){ - self.stateModel.set(text: message, for: .error) - self.state = .error - } - /// Text change that will update both enabledModel and disabledModel text values /// - Parameter text: text you want to see public func set(text: String?){ - self.stateModel.set(text: text ?? "", for: .enabled) + self.formModel.set(text: text ?? "") } } diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/StateLabelModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/FormLabelModel.swift similarity index 55% rename from MVMCoreUI/Atomic/Atoms/Views/Label/StateLabelModel.swift rename to MVMCoreUI/Atomic/Atoms/Views/Label/FormLabelModel.swift index ae6bc317..c7552047 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/StateLabelModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/FormLabelModel.swift @@ -8,37 +8,23 @@ import Foundation -public class StateLabelModel { +public class FormLabelModel: EnableableModelProtocol { static let defaultFontStyle = Styler.Font.RegularMicro static let defaultEnabledTextColor = Color(uiColor: .mvmBlack) static let defaultDisabledTextColor = Color(uiColor: .mvmCoolGray3) - static let defaultErrorTextColor = Color(uiColor: .mvmBlack) + static let defaultRequiredTextColor = Color(uiColor: .mvmCoolGray6) private var enabledModel: LabelModel - private var disabledModel = LabelModel(fontStyle: StateLabelModel.defaultFontStyle, textColor: StateLabelModel.defaultDisabledTextColor) - private var errorLabelModel = LabelModel(fontStyle: StateLabelModel.defaultFontStyle, textColor: StateLabelModel.defaultErrorTextColor) + private var disabledModel = LabelModel(fontStyle: FormLabelModel.defaultFontStyle, textColor: FormLabelModel.defaultDisabledTextColor) - public enum State { - case enabled - case disabled - case error - } - //current state - public var state: State = .enabled + public var enabled: Bool = true //model is based on current state public var model: LabelModel { - switch state { - case .enabled: - return enabledModel - case .disabled: - return disabledModel - case .error: - return errorLabelModel - } + return enabled ? enabledModel: disabledModel } - + //init public init(model: LabelModel){ @@ -48,13 +34,13 @@ public class StateLabelModel { if let modelFontStyle = model.fontStyle { self.disabledModel.fontStyle = modelFontStyle } else { - model.fontStyle = StateLabelModel.defaultFontStyle + model.fontStyle = FormLabelModel.defaultFontStyle } //ensure the textColor is set //otherwise use the defaultEnabledTextColor if model.textColor == nil { - model.textColor = StateLabelModel.defaultEnabledTextColor + model.textColor = FormLabelModel.defaultEnabledTextColor } //set the enabledModel to the model passed in @@ -66,26 +52,30 @@ public class StateLabelModel { public init(text: String){ //create the enabled model - self.enabledModel = LabelModel(fontStyle: StateLabelModel.defaultFontStyle, textColor: StateLabelModel.defaultEnabledTextColor) + self.enabledModel = LabelModel(fontStyle: FormLabelModel.defaultFontStyle, textColor: FormLabelModel.defaultEnabledTextColor) self.enabledModel.text = text //make sure the enabled & disabled text match self.disabledModel.text = self.enabledModel.text } + public var requiredModel: LabelModel { + let required = LabelModel(fontStyle: model.fontStyle!, textColor: model.textColor!) + if enabled { + required.attributes = [LabelAttributeColorModel(FormLabelModel.defaultRequiredTextColor, model.text.count + 1, 8)] + } + required.text = "\(model.text) Optional" + return required + } + //methods public func reset(){ - self.state = .enabled + self.enabled = true } //set text for state - public func set(text:String, for state: State){ - switch state { - case .enabled, .disabled: - self.enabledModel.text = text - self.disabledModel.text = text - case .error: - self.errorLabelModel.text = text - } + public func set(text:String){ + self.enabledModel.text = text + self.disabledModel.text = text } } From 083d76774088e80a87a943cdea5435b320559b9e Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 11 Jan 2022 15:48:34 -0600 Subject: [PATCH 07/17] updated model with: removed: titleLabel, feedbackLabel added: required Signed-off-by: Matt Bruce --- .../TextFields/EntryFieldModel.swift | 56 ++++++++----------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryFieldModel.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryFieldModel.swift index 2c4cc80c..3fed121a 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryFieldModel.swift @@ -9,7 +9,7 @@ import Foundation -@objcMembers open class EntryFieldModel: MoleculeModelProtocol, FormFieldProtocol, FormRuleWatcherFieldProtocol, UIUpdatableModelProtocol { +@objcMembers open class EntryFieldModel: MoleculeModelProtocol, FormFieldProtocol, FormRuleWatcherFieldProtocol, UIUpdatableModelProtocol, ClearableModelProtocol { //-------------------------------------------------- // MARK: - Properties @@ -29,6 +29,7 @@ import Foundation public var errorMessage: String? public var errorTextColor: Color? public var enabled: Bool = true + public var required: Bool = true public var readOnly: Bool = false public var showError: Bool? public var hideBorders = false @@ -39,20 +40,12 @@ import Foundation public var groupName: String = FormValidator.defaultGroupName public var baseValue: AnyHashable? public var wasInitiallySelected: Bool = false - - //text only - //Used for re-encoding what was decoded - private var title: String? - private var feedback: String? - - //label models - //Used for re-encoding what was decoded - private var titleLabel: LabelModel? - private var feedbackLabel: LabelModel? + public var title: String? + public var feedback: String? //used to drive the EntryFieldView UI - public var titleStateLabel: StateLabelModel - public var feedbackStateLabel: StateLabelModel + public var titleStateLabel: FormLabelModel + public var feedbackStateLabel: FormLabelModel public var isValid: Bool? = true { didSet { updateUI?() } @@ -85,8 +78,7 @@ import Foundation case text case fieldKey case groupName - case titleLabel - case feedbackLabel + case required } //-------------------------------------------------- @@ -119,8 +111,15 @@ import Foundation public init(with text: String) { self.text = text baseValue = text - self.titleStateLabel = StateLabelModel(text: "") - self.feedbackStateLabel = StateLabelModel(text: "") + self.titleStateLabel = FormLabelModel(text: "") + self.feedbackStateLabel = FormLabelModel(text: "") + } + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + public func clear() { + self.text = "" } //-------------------------------------------------- @@ -136,6 +135,7 @@ import Foundation errorMessage = try typeContainer.decodeIfPresent(String.self, forKey: .errorMessage) errorTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .errorTextColor) enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true + required = try typeContainer.decodeIfPresent(Bool.self, forKey: .required) ?? true readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false locked = try typeContainer.decodeIfPresent(Bool.self, forKey: .locked) selected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected) @@ -143,24 +143,13 @@ import Foundation hideBorders = try typeContainer.decodeIfPresent(Bool.self, forKey: .hideBorders) ?? false baseValue = text fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey) - titleLabel = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .titleLabel) - feedbackLabel = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .feedbackLabel) if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) { self.groupName = groupName } - - //Setup the stateLabelModels - if let titleLabel = titleLabel { - self.titleStateLabel = StateLabelModel(model: titleLabel) - } else { - self.titleStateLabel = StateLabelModel(text: title ?? "") - } - - if let feedBackLabel = feedbackLabel { - self.feedbackStateLabel = StateLabelModel(model: feedBackLabel) - } else { //feedback is the model for the error - self.feedbackStateLabel = StateLabelModel(text: feedback ?? "") - } + self.titleStateLabel = FormLabelModel(text: title ?? "") + self.feedbackStateLabel = FormLabelModel(model: LabelModel(text: feedback ?? "", + fontStyle: FormLabelModel.defaultFontStyle, + textColor: Color(uiColor: .mvmCoolGray6))) } public func encode(to encoder: Encoder) throws { @@ -169,9 +158,7 @@ import Foundation try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier) try container.encodeIfPresent(title, forKey: .title) - try container.encodeIfPresent(titleLabel, forKey: .titleLabel) try container.encodeIfPresent(feedback, forKey: .feedback) - try container.encodeIfPresent(feedbackLabel, forKey: .feedbackLabel) try container.encodeIfPresent(text, forKey: .text) try container.encodeIfPresent(locked, forKey: .locked) try container.encodeIfPresent(showError, forKey: .showError) @@ -183,6 +170,7 @@ import Foundation try container.encode(readOnly, forKey: .readOnly) try container.encode(enabled, forKey: .enabled) + try container.encode(required, forKey: .required) try container.encode(hideBorders, forKey: .hideBorders) } } From d3f4f21b02dc3ace1deadc13cfdedb2c34406941 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 11 Jan 2022 15:51:57 -0600 Subject: [PATCH 08/17] refactored StateLabel to FormLabel add errorLabel removed all constraints and replaced with UIStackView show/hide errorLabel within showError Signed-off-by: Matt Bruce --- .../FormFields/TextFields/EntryField.swift | 114 +++++++++--------- 1 file changed, 54 insertions(+), 60 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift index 6271c44a..1a64a0a5 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift @@ -17,8 +17,8 @@ import UIKit //-------------------------------------------------- // MARK: - Outlets //-------------------------------------------------- - public private(set) var titleLabel: StateLabel = { - let label = StateLabel() + public private(set) var titleLabel: FormLabel = { + let label = FormLabel() label.setContentCompressionResistancePriority(.required, for: .vertical) return label }() @@ -26,12 +26,33 @@ import UIKit public private(set) var entryFieldContainer = EntryFieldContainer() /// Provides contextual information on the TextField. - public private(set) var feedbackLabel: StateLabel = { - let label = StateLabel() + public private(set) var feedbackLabel: FormLabel = { + let label = FormLabel() label.setContentCompressionResistancePriority(.required, for: .vertical) return label }() - + + public private(set) var errorLabel: Label = { + let label = Label() + label.setFontStyle(.RegularMicro) + label.textColor = .mvmBlack + label.setContentCompressionResistancePriority(.required, for: .vertical) + return label + }() + + public lazy var stack: UIStackView = { + errorLabel.isHidden = true + let s = UIStackView(arrangedSubviews: [titleLabel, entryFieldContainer, errorLabel, feedbackLabel]) + s.axis = .vertical + s.alignment = .fill + s.distribution = .fill + s.setCustomSpacing(Padding.One, after: titleLabel) + s.setCustomSpacing(Padding.Two, after: entryFieldContainer) + s.setCustomSpacing(Padding.One, after: errorLabel) + s.translatesAutoresizingMaskIntoConstraints = false + return s + }() + //-------------------------------------------------- // MARK: - Delegate //-------------------------------------------------- @@ -59,13 +80,17 @@ import UIKit feedbackLabel.isEnabled = enabled entryFieldContainer.isEnabled = enabled entryFieldModel?.enabled = enabled - if !enabled { - self.text = defaultText - } } } } + /// Toggles enabled (original) or disabled UI. + public var isRequired: Bool = true { + didSet{ + titleLabel.isRequired = isRequired + } + } + /// Toggles readOnly (original) or disabled UI. public var isReadOnly: Bool { get { entryFieldContainer.isReadOnly } @@ -82,9 +107,10 @@ import UIKit get { entryFieldContainer.showError } set (error) { if error { - feedbackLabel.showError(message: self.errorMessage ?? "") + errorLabel.text = self.errorMessage ?? "" + errorLabel.isHidden = false } else { - feedbackLabel.reset() + errorLabel.isHidden = true } entryFieldContainer.showError = error entryFieldModel?.showError = error @@ -141,25 +167,6 @@ import UIKit model as? EntryFieldModel } - ///This is the value of the entryFieldModel.text on set - ///This is used to update the text value on a reset or when enabled is set to false - private var defaultText: String = "" - //-------------------------------------------------- - // MARK: - Constraints - //-------------------------------------------------- - - public var entryFieldContainerLeading: NSLayoutConstraint? - public var entryFieldContainerTrailing: NSLayoutConstraint? - - public var feedbackLabelTrailing: NSLayoutConstraint? - public var feedbackLabelLeading: NSLayoutConstraint? - - public var titleLabelLeading: NSLayoutConstraint? - public var titleLabelTrailing: NSLayoutConstraint? - - public var titleContainerDistance: NSLayoutConstraint? - public var feedbackContainerDistance: NSLayoutConstraint? - //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -199,37 +206,18 @@ import UIKit isAccessibilityElement = false setContentCompressionResistancePriority(.required, for: .vertical) - accessibilityElements = [titleLabel, feedbackLabel] + accessibilityElements = [titleLabel, errorLabel, feedbackLabel] backgroundColor = .mvmWhite - - addSubview(titleLabel) - - titleLabel.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true - titleLabelLeading = titleLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor) - titleLabelLeading?.isActive = true - titleLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor) - titleLabelLeading?.isActive = true - - addSubview(entryFieldContainer) + + addSubview(stack) + entryFieldContainer.setContentCompressionResistancePriority(.required, for: .vertical) setupFieldContainerContent(entryFieldContainer) - - titleContainerDistance = entryFieldContainer.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: Padding.One) - titleContainerDistance?.isActive = true - entryFieldContainerLeading = entryFieldContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor) - entryFieldContainerLeading?.isActive = true - entryFieldContainerTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: entryFieldContainer.trailingAnchor) - entryFieldContainerTrailing?.isActive = true - - addSubview(feedbackLabel) - - feedbackContainerDistance = feedbackLabel.topAnchor.constraint(equalTo: entryFieldContainer.bottomAnchor, constant: Padding.Two) - feedbackContainerDistance?.isActive = true - feedbackLabelLeading = feedbackLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor) - feedbackLabelLeading?.isActive = true - feedbackLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: feedbackLabel.trailingAnchor) - feedbackLabelTrailing?.isActive = true - layoutMarginsGuide.bottomAnchor.constraint(equalTo: feedbackLabel.bottomAnchor).isActive = true + + stack.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true + stack.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true + stack.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor).isActive = true + stack.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor).isActive = true } @objc open override func layoutSubviews() { @@ -247,8 +235,10 @@ import UIKit super.updateView(size) titleLabel.updateView(size) + errorLabel.updateView(size) feedbackLabel.updateView(size) entryFieldContainer.updateView(size) + stack.updateView(size) } //-------------------------------------------------- @@ -306,6 +296,9 @@ import UIKit titleLabel.textColor = .mvmBlack feedbackLabel.font = Styler.Font.RegularMicro.getFont() feedbackLabel.textColor = .mvmBlack + errorLabel.font = Styler.Font.RegularMicro.getFont() + errorLabel.textColor = .mvmBlack + errorLabel.text = nil entryFieldContainer.disableAllBorders = false feedbackLabel.text = nil entryFieldContainer.reset() @@ -324,9 +317,9 @@ import UIKit titleLabel.setup(model: model.titleStateLabel, delegateObject, additionalData) feedbackLabel.setup(model: model.feedbackStateLabel, delegateObject, additionalData) - defaultText = model.text ?? "" isEnabled = model.enabled isReadOnly = model.readOnly + isRequired = model.required model.updateUI = { [weak self] in MVMCoreDispatchUtility.performBlock(onMainThread: { guard let self = self else { return } @@ -338,6 +331,7 @@ import UIKit self.showError = false } self.isEnabled = model.enabled + self.text = model.text }) } @@ -388,8 +382,8 @@ extension EntryField { } extension LabelModel { - public convenience init(fontStyle: Styler.Font, textColor: Color) { - self.init(text: "") + public convenience init(text: String = "", fontStyle: Styler.Font, textColor: Color) { + self.init(text: text) self.fontStyle = fontStyle self.textColor = textColor } From 1fe73feb1f6bc3abb7f9d00382ac445842c6aba3 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 11 Jan 2022 15:52:27 -0600 Subject: [PATCH 09/17] added init Signed-off-by: Matt Bruce --- .../Atomic/Atoms/Views/Label/LabelAttributeColorModel.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeColorModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeColorModel.swift index 94579d02..8fa1aa58 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeColorModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeColorModel.swift @@ -24,10 +24,14 @@ case textColor } + public init(_ textColor: Color?, _ location: Int, _ length: Int){ + self.textColor = textColor + super.init(location, length) + } + //-------------------------------------------------- // MARK: - Codec //-------------------------------------------------- - required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) textColor = try typeContainer.decodeIfPresent(Color.self, forKey: .textColor) From df2b6b4db297a74edfa6fcecd1b8981f694680ed Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 12 Jan 2022 15:53:43 -0600 Subject: [PATCH 10/17] removed setting the form field validity within a validation Signed-off-by: Matt Bruce --- .../Rules/Rules/RuleEqualsIgnoreCaseModel.swift | 5 ----- MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift | 5 ++--- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift index dd02070b..25e21d4f 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift @@ -51,15 +51,10 @@ public class RuleEqualsIgnoreCaseModel: RulesProtocol { fieldValidity = false } - for formKey in fields { - guard let formField = fieldMolecules[formKey] else { continue } - (formField as? FormRuleWatcherFieldProtocol)?.setValidity(true, rule: self) - } break } previousValidity[formKey] = valid - (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) } return (valid: valid, fieldValidity: previousValidity) } diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift index fae81358..70b787bf 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift @@ -43,8 +43,6 @@ public class RuleEqualsModel: RulesProtocol { if compareValue != formField.formFieldValue() { valid = false - previousValidity[formKey] = valid - (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) break } else { var fieldValidity = valid @@ -52,8 +50,9 @@ public class RuleEqualsModel: RulesProtocol { if let validity = previousFieldValidity[formKey], !validity, fieldValidity { fieldValidity = false } - (formField as? FormRuleWatcherFieldProtocol)?.setValidity(fieldValidity, rule: self) } + previousValidity[formKey] = valid + } return (valid: valid, fieldValidity: previousValidity) } From 7c05d9fcc75a67cd1c45bcaa8939eb98bc4bd0f4 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 12 Jan 2022 15:54:36 -0600 Subject: [PATCH 11/17] refactored out setting form field validity within validation refactored validate method to return tuple and again not mess with setting formfield validity Signed-off-by: Matt Bruce --- .../Rules/Rules/RulesProtocol.swift | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift index 37cd1828..1727cbe2 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift @@ -53,7 +53,6 @@ public extension RulesProtocol { if let validity = previousFieldValidity[formKey], !validity, fieldValidity { fieldValidity = false } - (formField as? FormRuleWatcherFieldProtocol)?.setValidity(fieldValidity, rule: self) valid = valid && fieldValidity previousValidity[formKey] = fieldValidity } @@ -66,19 +65,28 @@ public protocol RulesContainerProtocol{ } public extension RulesContainerProtocol { - func validate(_ fields: [String: FormFieldProtocol]) -> Bool { + /// This validation for Rules for the Validation or for Effects. + /// - Parameters: + /// - fields: Fields for the group + /// - setValidity: Since this function is for validation, this bool determines if you should set the FormFields.setValidity for a rule. + /// this method can be called for Form Validation and Effect Validation (this doesn't affect the submital of the form) + /// - Returns: Tuple(valid, fieldValidity) + /// - valid: bool for all rules + /// - fieldValidity: accumulation of all fieldKey: valid + func validate(_ fields: [String: FormFieldProtocol]) -> (valid: Bool, fieldValidity: [String:Bool] ) { // Validate each rule. var valid = true var previousValidity: [String: Bool] = [:] for rule in self.rules { - //validate the rule against the fields let tuple = rule.validate(fields, previousValidity) - + if let ruleId = rule.ruleId { + print("validation ruleId: \(ruleId) value: \(tuple) \nfields: \(rule.fields)" ) + } //merge the fieldValidity previousValidity = previousValidity.merging(tuple.fieldValidity) { (_, new) in new } valid = valid && tuple.valid } - return valid + return (valid: valid, fieldValidity: previousValidity) } } From 3fa1be0582f545ec30559e93404673117d6fe3c3 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 12 Jan 2022 15:55:23 -0600 Subject: [PATCH 12/17] refactored validate group with new valid that returns tuple update to set formfield validity after the group.validate occurs Signed-off-by: Matt Bruce --- MVMCoreUI/FormUIHelpers/FormValidator.swift | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/FormUIHelpers/FormValidator.swift b/MVMCoreUI/FormUIHelpers/FormValidator.swift index f991926b..4a1d36c7 100644 --- a/MVMCoreUI/FormUIHelpers/FormValidator.swift +++ b/MVMCoreUI/FormUIHelpers/FormValidator.swift @@ -111,11 +111,19 @@ import MVMCore /// - counter: keeps track of how many times causes another group validation /// - Returns: validity for the FormGroupRule.rules public func validateGroup(_ group: FormGroupRule, counter: Int = 0) throws -> Bool { - let valid = group.validate(fields) + let tuple = group.validate(fields) + + group.rules.forEach { rule in + for formKey in rule.fields { + guard let formField = fields[formKey] as? FormRuleWatcherFieldProtocol, + let fieldValidity = tuple.fieldValidity[formKey] else { continue } + formField.setValidity(fieldValidity, rule: rule) + } + } // Notify the group watchers of validity. for watcher in groupWatchers.filter({$0.groupName == group.groupName}) { - watcher.setValidity(valid) + watcher.setValidity(tuple.valid) } var ruleChange = false @@ -125,14 +133,14 @@ import MVMCore //get the fieldKey for the effect if let effected = fields[effect.fieldKey] { //get the validity - let validity = effect.validate(fields) + let effectTuple = effect.validate(fields) //set the effect with the validation - effect.setEffect(validity: validity, field: effected, form: self, group: group) + effect.setEffect(validity: effectTuple.valid, field: effected, form: self, group: group) //update the group form rules if let ruleIds = effect.activatedRuleIds { - let didChange = self.updateRules(for: group, with: validity, for: effect.fieldKey, and: ruleIds) + let didChange = self.updateRules(for: group, with: effectTuple.valid, for: effect.fieldKey, and: ruleIds) if(didChange) { ruleChange = didChange } @@ -147,7 +155,7 @@ import MVMCore return try self.validateGroup(group, counter: counter + 1) } } else { - return valid + return tuple.valid } } From 143ebccb3410be3ea0990e06b5bcd149d5d40a4c Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 13 Jan 2022 10:57:18 -0600 Subject: [PATCH 13/17] remove readOnly from the Views and now using the isEnabled and model is controlling this based off enabled & readOnly Signed-off-by: Matt Bruce --- .../TextFields/DigitEntryField.swift | 8 ------- .../BaseDropdownEntryField.swift | 10 +------- .../FormFields/TextFields/EntryField.swift | 16 ++----------- .../TextFields/TextEntryField.swift | 2 +- .../TextFields/TextViewEntryField.swift | 23 +----------------- .../Atomic/Atoms/Selectors/Checkbox.swift | 24 ++++--------------- MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift | 11 ++++----- .../Atomic/Atoms/Selectors/RadioBox.swift | 15 ++++-------- .../Atomic/Atoms/Selectors/RadioButton.swift | 7 +++--- .../Atomic/Atoms/Selectors/RadioSwatch.swift | 18 ++++---------- MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift | 17 ++++--------- .../CarouselIndicator/BarsIndicatorView.swift | 18 +++----------- .../NumericIndicatorView.swift | 8 ++----- MVMCoreUI/BaseClasses/Control.swift | 8 ------- .../Views/EntryFieldContainer.swift | 15 ------------ 15 files changed, 36 insertions(+), 164 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/DigitEntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/DigitEntryField.swift index f3fa96ba..c70d458e 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/DigitEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/DigitEntryField.swift @@ -90,14 +90,6 @@ import UIKit } } - public override var isReadOnly: Bool { - get { super.isReadOnly } - set (readOnly){ - digitBoxes.forEach { $0.isReadOnly = readOnly } - super.isReadOnly = readOnly - } - } - public override var showError: Bool { get { super.showError } set (error) { diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/BaseDropdownEntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/BaseDropdownEntryField.swift index f70b0ce0..6e8be5f1 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/BaseDropdownEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/BaseDropdownEntryField.swift @@ -44,15 +44,7 @@ import UIKit super.isEnabled = enabled } } - - @objc public override var isReadOnly: Bool { - get { super.isReadOnly } - set (readOnly) { - dropDownCaretView.isEnabled = !readOnly - super.isReadOnly = readOnly - } - } - + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift index 1a64a0a5..891594a4 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift @@ -90,18 +90,7 @@ import UIKit titleLabel.isRequired = isRequired } } - - /// Toggles readOnly (original) or disabled UI. - public var isReadOnly: Bool { - get { entryFieldContainer.isReadOnly } - set (readOnly) { - if(entryFieldContainer.isReadOnly != readOnly){ - entryFieldContainer.isReadOnly = readOnly - entryFieldModel?.readOnly = readOnly - } - } - } - + /// Toggles error or original UI. public var showError: Bool { get { entryFieldContainer.showError } @@ -317,8 +306,7 @@ import UIKit titleLabel.setup(model: model.titleStateLabel, delegateObject, additionalData) feedbackLabel.setup(model: model.feedbackStateLabel, delegateObject, additionalData) - isEnabled = model.enabled - isReadOnly = model.readOnly + isEnabled = model.enabled && !model.readOnly isRequired = model.required model.updateUI = { [weak self] in MVMCoreDispatchUtility.performBlock(onMainThread: { diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift index cd0adf61..7973d652 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift @@ -69,7 +69,7 @@ import UIKit guard let self = self else { return } self.textField.isEnabled = enabled - self.textField.textColor = enabled && !self.isReadOnly ? self.textEntryFieldModel?.enabledTextColor.uiColor : self.textEntryFieldModel?.disabledTextColor.uiColor + self.textField.textColor = enabled ? self.textEntryFieldModel?.enabledTextColor.uiColor : self.textEntryFieldModel?.disabledTextColor.uiColor } } } diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextViewEntryField.swift index 8c1cafa8..3221f043 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextViewEntryField.swift @@ -46,25 +46,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele if self.textView.isShowingPlaceholder { self.textView.textColor = self.textView.placeholderTextColor } else { - self.textView.textColor = (enabled && !self.isReadOnly ? self.textViewEntryFieldModel?.enabledTextColor : self.textViewEntryFieldModel?.disabledTextColor)?.uiColor - } - } - } - } - - public override var isReadOnly: Bool { - get { super.isReadOnly } - set (readOnly) { - super.isReadOnly = readOnly - - DispatchQueue.main.async { [weak self] in - guard let self = self else { return } - - self.textView.isEnabled = !readOnly - if self.textView.isShowingPlaceholder { - self.textView.textColor = self.textView.placeholderTextColor - } else { - self.textView.textColor = (!readOnly ? self.textViewEntryFieldModel?.enabledTextColor : self.textViewEntryFieldModel?.disabledTextColor)?.uiColor + self.textView.textColor = (self.textView.isEnabled ? self.textViewEntryFieldModel?.enabledTextColor : self.textViewEntryFieldModel?.disabledTextColor)?.uiColor } } } @@ -300,8 +282,5 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele adjustMarginConstraints(constant: 0) } - if !model.enabled { - isEnabled = false - } } } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift index 8fbb2bea..4bd64c7c 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift @@ -84,7 +84,7 @@ import MVMCore isUserInteractionEnabled = isEnabled - if isEnabled && !self.isReadOnly { + if isEnabled { layer.borderColor = borderColor.cgColor backgroundColor = isSelected ? checkedBackgroundColor : unCheckedBackgroundColor setShapeLayerStrokeColor(checkColor) @@ -95,21 +95,7 @@ import MVMCore } } } - - public override var isReadOnly: Bool { - didSet{ - if isReadOnly { - layer.borderColor = disabledBorderColor.cgColor - backgroundColor = disabledBackgroundColor - setShapeLayerStrokeColor(disabledCheckColor) - } else { - layer.borderColor = borderColor.cgColor - backgroundColor = isSelected ? checkedBackgroundColor : unCheckedBackgroundColor - setShapeLayerStrokeColor(checkColor) - } - } - } - + public var disabledBackgroundColor: UIColor = .clear public var disabledBorderColor: UIColor = .mvmCoolGray3 public var disabledCheckColor: UIColor = .mvmCoolGray3 @@ -253,7 +239,7 @@ import MVMCore self.shapeLayer = shapeLayer shapeLayer.frame = bounds layer.addSublayer(shapeLayer) - shapeLayer.strokeColor = isEnabled || !isReadOnly ? checkColor.cgColor : disabledCheckColor.cgColor + shapeLayer.strokeColor = isEnabled ? checkColor.cgColor : disabledCheckColor.cgColor shapeLayer.fillColor = UIColor.clear.cgColor shapeLayer.path = checkMarkPath() shapeLayer.lineJoin = .miter @@ -382,7 +368,6 @@ import MVMCore super.reset() isEnabled = true - isReadOnly = false shapeLayer?.removeAllAnimations() shapeLayer?.removeFromSuperlayer() shapeLayer = nil @@ -445,8 +430,7 @@ import MVMCore }) } - isEnabled = model.enabled - isReadOnly = model.readOnly + isEnabled = model.enabled && !model.readOnly if (model.action != nil || model.offAction != nil) { actionBlock = { [weak self] in diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift index cd423dca..eb0b0b4c 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift @@ -62,7 +62,7 @@ import UIKit heartPath.close() heart.path = heartPath.cgPath heart.fillColor = isSelected ? heartModel?.activeColor.cgColor : heartModel?.inActiveColor.cgColor - heart.opacity = isEnabled || !isReadOnly ? 1.0 : 0.5 + heart.opacity = isEnabled ? 1.0 : 0.5 heart.lineWidth = 1 heart.strokeColor = isSelected ? UIColor.clear.cgColor : UIColor.mvmBlack.cgColor return heart @@ -88,8 +88,7 @@ import UIKit self.additionalData = additionalData guard let model = model as? HeartModel else { return } isSelected = model.isActive - isEnabled = model.enabled - isReadOnly = model.readOnly + isEnabled = model.enabled && !model.readOnly updateAccessibilityLabel() } @@ -98,13 +97,13 @@ import UIKit //-------------------------------------------------- /// Adjust accessibility label based on selection of Heart. func updateAccessibilityLabel() { - accessibilityHint = isEnabled || !isReadOnly ? MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_unfavorite_action_hint" : "heart_favorite_action_hint") : nil - accessibilityTraits = isEnabled || !isReadOnly ? .button : .none + accessibilityHint = isEnabled ? MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_unfavorite_action_hint" : "heart_favorite_action_hint") : nil + accessibilityTraits = isEnabled ? .button : .none accessibilityLabel = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_selected_state" : "heart_not_selected_state") } func tapAction() { - guard isEnabled, !isReadOnly else { return } + guard isEnabled else { return } isSelected = !isSelected if let heartModel = heartModel { Button.performButtonAction(with: heartModel.action, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: heartModel) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioBox.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioBox.swift index 693fe2a4..27323048 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioBox.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioBox.swift @@ -39,11 +39,7 @@ open class RadioBox: Control, MFButtonProtocol { public override var isEnabled: Bool { didSet { updateAccessibility() } } - - public override var isReadOnly: Bool { - didSet { updateAccessibility() } - } - + //-------------------------------------------------- // MARK: - MVMCoreViewProtocol //-------------------------------------------------- @@ -93,8 +89,7 @@ open class RadioBox: Control, MFButtonProtocol { accentColor = color } isSelected = model.selected - isEnabled = model.enabled - isReadOnly = model.readOnly + isEnabled = model.enabled && !model.readOnly } open override func reset() { @@ -129,7 +124,7 @@ open class RadioBox: Control, MFButtonProtocol { // Handle Mask maskLayer?.removeFromSuperlayer() - if !isEnabled || isReadOnly { + if !isEnabled { let mask = getMaskLayer() layer.mask = mask maskLayer = mask @@ -143,7 +138,7 @@ open class RadioBox: Control, MFButtonProtocol { } @objc open func selectBox() { - guard isEnabled, !isReadOnly, !isSelected else { return } + guard isEnabled, !isSelected else { return } isSelected = true radioBoxModel?.selected = isSelected if let radioBoxModel = radioBoxModel, let actionModel = radioBoxModel.action { @@ -242,7 +237,7 @@ open class RadioBox: Control, MFButtonProtocol { accessibilityTraits.insert(.selected) } - if !isEnabled || isReadOnly { + if !isEnabled { accessibilityTraits.insert(.notEnabled) } } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift index 11b917b0..1854f943 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift @@ -66,7 +66,7 @@ import UIKit open override func draw(_ rect: CGRect) { guard let context = UIGraphicsGetCurrentContext() else { return } - let color = (isReadOnly == true || isEnabled == false) ? disabledColor.cgColor : enabledColor.cgColor + let color = isEnabled == false ? disabledColor.cgColor : enabledColor.cgColor layer.cornerRadius = bounds.width * 0.5 layer.borderColor = color layer.borderWidth = bounds.width * 0.0333 @@ -88,7 +88,7 @@ import UIKit /// The action performed when tapped. func tapAction() { - if !isEnabled || isReadOnly { + if !isEnabled { return } @@ -163,8 +163,7 @@ import UIKit guard let model = model as? RadioButtonModel else { return } isSelected = model.state - isEnabled = model.enabled - isReadOnly = model.readOnly + isEnabled = model.enabled && !model.readOnly RadioButtonSelectionHelper.setupForRadioButtonGroup(model, self, delegateObject: delegateObject) } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift index f927f7e9..eb569810 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift @@ -38,13 +38,7 @@ open class RadioSwatch: Control, MFButtonProtocol { updateAccessibility() } } - - public override var isReadOnly: Bool { - didSet { - updateAccessibility() - } - } - + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -70,8 +64,7 @@ open class RadioSwatch: Control, MFButtonProtocol { self.additionalData = additionalData bottomText.text = model.text isSelected = model.selected - isEnabled = model.enabled - isReadOnly = model.readOnly + isEnabled = model.enabled && !model.readOnly } public override func reset() { @@ -79,7 +72,6 @@ open class RadioSwatch: Control, MFButtonProtocol { bottomText.text = nil isSelected = false isEnabled = true - isReadOnly = false } //------------------------------------------------------ @@ -114,7 +106,7 @@ open class RadioSwatch: Control, MFButtonProtocol { //Handle Mask maskLayer?.removeFromSuperlayer() - if !isEnabled || isReadOnly { + if !isEnabled { let mask = getMaskLayer() layer.mask = mask maskLayer = mask @@ -128,7 +120,7 @@ open class RadioSwatch: Control, MFButtonProtocol { } @objc open func selectSwatch() { - guard isEnabled, !isReadOnly, !isSelected else { return } + guard isEnabled, !isSelected else { return } isSelected = true radioSwatchModel?.selected = isSelected if let radioSwatchModel = radioSwatchModel, let actionModel = radioSwatchModel.action { @@ -201,7 +193,7 @@ open class RadioSwatch: Control, MFButtonProtocol { if isSelected { accessibilityTraits.insert(.selected) } - if !isEnabled || isReadOnly { + if !isEnabled { accessibilityTraits.insert(.notEnabled) } } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift index a76424f0..04c34da2 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift @@ -66,15 +66,7 @@ public typealias ActionBlockConfirmation = () -> (Bool) accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: isEnabled ? "AccToggleHint" : "AccDisabled") } } - - public override var isReadOnly: Bool { - didSet{ - changeStateNoAnimation(!isReadOnly ? isOn : false) - setToggleAppearanceFromState() - accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: !isReadOnly ? "AccToggleHint" : "AccDisabled") - } - } - + /// Simple means to prevent user interaction with the toggle. public var isLocked: Bool = false { didSet { isUserInteractionEnabled = !isLocked } @@ -358,8 +350,8 @@ public typealias ActionBlockConfirmation = () -> (Bool) public func setToggleAppearanceFromState() { - backgroundColor = isEnabled || !isReadOnly ? isOn ? containerTintColor.on : containerTintColor.off : disabledTintColor.container - knobView.backgroundColor = isEnabled || !isReadOnly ? isOn ? knobTintColor.on : knobTintColor.off : disabledTintColor.knob + backgroundColor = isEnabled ? isOn ? containerTintColor.on : containerTintColor.off : disabledTintColor.container + knobView.backgroundColor = isEnabled ? isOn ? knobTintColor.on : knobTintColor.off : disabledTintColor.knob } public func knobReformAnimation() { @@ -392,8 +384,7 @@ public typealias ActionBlockConfirmation = () -> (Bool) isOn = model.selected changeStateNoAnimation(isOn) isAnimated = model.animated - isEnabled = model.enabled - isReadOnly = model.readOnly + isEnabled = model.enabled && !model.readOnly if let accessibileString = model.accessibilityText { accessibilityLabel = accessibileString diff --git a/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/BarsIndicatorView.swift b/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/BarsIndicatorView.swift index 1f2e7346..381b8112 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/BarsIndicatorView.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/BarsIndicatorView.swift @@ -72,26 +72,14 @@ open class BarsIndicatorView: CarouselIndicator { didSet { for (i, indicatorBar) in barReferences.enumerated() { if i == currentIndex { - indicatorBar.backgroundColor = isEnabled && !isReadOnly ? currentIndicatorColor : disabledIndicatorColor + indicatorBar.backgroundColor = isEnabled ? currentIndicatorColor : disabledIndicatorColor } else { - indicatorBar.backgroundColor = isEnabled && !isReadOnly ? indicatorColor : disabledIndicatorColor + indicatorBar.backgroundColor = isEnabled ? indicatorColor : disabledIndicatorColor } } } } - - open override var isReadOnly: Bool { - didSet { - for (i, indicatorBar) in barReferences.enumerated() { - if i == currentIndex { - indicatorBar.backgroundColor = !isReadOnly ? currentIndicatorColor : disabledIndicatorColor - } else { - indicatorBar.backgroundColor = !isReadOnly ? indicatorColor : disabledIndicatorColor - } - } - } - } - + /// Colors the currently selected index, unique from other indicators public var currentIndicatorColor: UIColor { get { barsCarouselIndicatorModel?.currentIndicatorColor.uiColor ?? indicatorColor } diff --git a/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/NumericIndicatorView.swift b/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/NumericIndicatorView.swift index e888fff8..f07fe123 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/NumericIndicatorView.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/NumericIndicatorView.swift @@ -42,13 +42,9 @@ open class NumericIndicatorView: CarouselIndicator { //-------------------------------------------------- open override var isEnabled: Bool { - didSet { setViewColor(isEnabled && !isReadOnly ? indicatorColor : disabledIndicatorColor) } + didSet { setViewColor(isEnabled ? indicatorColor : disabledIndicatorColor) } } - - open override var isReadOnly: Bool { - didSet { setViewColor(!isReadOnly ? indicatorColor : disabledIndicatorColor) } - } - + /// Sets the color for pageCount text, left arrow and right arrow. public override var indicatorColor: UIColor { get { super.indicatorColor } diff --git a/MVMCoreUI/BaseClasses/Control.swift b/MVMCoreUI/BaseClasses/Control.swift index 3aebaf7e..865e3a8e 100644 --- a/MVMCoreUI/BaseClasses/Control.swift +++ b/MVMCoreUI/BaseClasses/Control.swift @@ -13,14 +13,6 @@ import UIKit //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - public var isReadOnly: Bool = false{ - didSet{ - //don't allow touches - isUserInteractionEnabled = !isReadOnly - setNeedsDisplay() - } - } - open var model: MoleculeModelProtocol? private var initialSetupPerformed = false diff --git a/MVMCoreUI/Containers/Views/EntryFieldContainer.swift b/MVMCoreUI/Containers/Views/EntryFieldContainer.swift index f567d01f..9ccd1d25 100644 --- a/MVMCoreUI/Containers/Views/EntryFieldContainer.swift +++ b/MVMCoreUI/Containers/Views/EntryFieldContainer.swift @@ -55,7 +55,6 @@ import UIKit private var _showError: Bool = false private var _isLocked: Bool = false private var _isSelected: Bool = false - private var _isReadOnly: Bool = false public var isEnabled: Bool { get { return _isEnabled } @@ -70,20 +69,6 @@ import UIKit } } - public var isReadOnly: Bool { - get { return _isReadOnly } - set (readOnly) { - - _isEnabled = true - _isLocked = false - _isSelected = false - _showError = false - _isReadOnly = readOnly - - fieldState = readOnly ? .disabled : .original - } - } - public var showError: Bool { get { return _showError } set (error) { From 0dce42fb37357b479b1c803e13f957eb8ed8e509 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 13 Jan 2022 11:04:10 -0600 Subject: [PATCH 14/17] refactored code for stack Signed-off-by: Matt Bruce --- .../FormFields/TextFields/EntryField.swift | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift index 891594a4..4b84e8a1 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryField.swift @@ -42,15 +42,15 @@ import UIKit public lazy var stack: UIStackView = { errorLabel.isHidden = true - let s = UIStackView(arrangedSubviews: [titleLabel, entryFieldContainer, errorLabel, feedbackLabel]) - s.axis = .vertical - s.alignment = .fill - s.distribution = .fill - s.setCustomSpacing(Padding.One, after: titleLabel) - s.setCustomSpacing(Padding.Two, after: entryFieldContainer) - s.setCustomSpacing(Padding.One, after: errorLabel) - s.translatesAutoresizingMaskIntoConstraints = false - return s + let stack = UIStackView(arrangedSubviews: [titleLabel, entryFieldContainer, errorLabel, feedbackLabel]) + stack.axis = .vertical + stack.alignment = .fill + stack.distribution = .fill + stack.setCustomSpacing(Padding.One, after: titleLabel) + stack.setCustomSpacing(Padding.Two, after: entryFieldContainer) + stack.setCustomSpacing(Padding.One, after: errorLabel) + stack.translatesAutoresizingMaskIntoConstraints = false + return stack }() //-------------------------------------------------- @@ -205,8 +205,8 @@ import UIKit stack.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true stack.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true - stack.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor).isActive = true - stack.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor).isActive = true + layoutMarginsGuide.trailingAnchor.constraint(equalTo: stack.trailingAnchor).isActive = true + layoutMarginsGuide.bottomAnchor.constraint(equalTo: stack.bottomAnchor).isActive = true } @objc open override func layoutSubviews() { @@ -222,11 +222,6 @@ import UIKit @objc open override func updateView(_ size: CGFloat) { super.updateView(size) - - titleLabel.updateView(size) - errorLabel.updateView(size) - feedbackLabel.updateView(size) - entryFieldContainer.updateView(size) stack.updateView(size) } From 52844cd5e155922cace5a74fa6e6fb813cf697a1 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 13 Jan 2022 11:35:24 -0600 Subject: [PATCH 15/17] fixed to add readOnly Signed-off-by: Matt Bruce --- MVMCoreUI/Atomic/Organisms/Carousel/CarouselModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Organisms/Carousel/CarouselModel.swift b/MVMCoreUI/Atomic/Organisms/Carousel/CarouselModel.swift index ed22696c..857984cf 100644 --- a/MVMCoreUI/Atomic/Organisms/Carousel/CarouselModel.swift +++ b/MVMCoreUI/Atomic/Organisms/Carousel/CarouselModel.swift @@ -155,7 +155,7 @@ import UIKit try container.encode(selectable, forKey: .selectable) try container.encode(selectedIndex, forKey: .selectedIndex) try container.encode(enabled, forKey: .enabled) - try container.encode(enabled, forKey: .enabled) + try container.encode(readOnly, forKey: .readOnly) } } From 9c34ea267e14c9b67f39f767ef49a6e300429ad7 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 13 Jan 2022 11:36:15 -0600 Subject: [PATCH 16/17] fixed encodeIfPresent Signed-off-by: Matt Bruce --- .../FormFieldEffect/ClearFormFieldEffectModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/FormUIHelpers/FormFieldEffect/ClearFormFieldEffectModel.swift b/MVMCoreUI/FormUIHelpers/FormFieldEffect/ClearFormFieldEffectModel.swift index fefe8499..173c0e33 100644 --- a/MVMCoreUI/FormUIHelpers/FormFieldEffect/ClearFormFieldEffectModel.swift +++ b/MVMCoreUI/FormUIHelpers/FormFieldEffect/ClearFormFieldEffectModel.swift @@ -50,7 +50,7 @@ public class ClearFormFieldEffectModel: FormFieldEffectProtocol { public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(fieldKey, forKey: .fieldKey) - try container.encode(activatedRuleIds, forKey: .activatedRuleIds) + try container.encodeIfPresent(activatedRuleIds, forKey: .activatedRuleIds) try container.encodeModels(rules, forKey: .rules) } From e5d27cd423d7c3132f165cd3e4c648d67aa0a35b Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 13 Jan 2022 11:37:08 -0600 Subject: [PATCH 17/17] remove print Signed-off-by: Matt Bruce --- MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift index 1727cbe2..8e158676 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift @@ -80,9 +80,7 @@ public extension RulesContainerProtocol { for rule in self.rules { //validate the rule against the fields let tuple = rule.validate(fields, previousValidity) - if let ruleId = rule.ruleId { - print("validation ruleId: \(ruleId) value: \(tuple) \nfields: \(rule.fields)" ) - } + //merge the fieldValidity previousValidity = previousValidity.merging(tuple.fieldValidity) { (_, new) in new } valid = valid && tuple.valid