From 14bedf6f315f936cf9ed73b258a31aaf656b4430 Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Tue, 10 Mar 2020 12:12:45 +0530 Subject: [PATCH 01/67] 19216(Headers - H2 - Buttons) initial commit Created model and molecule class. --- MVMCoreUI.xcodeproj/project.pbxproj | 8 +++ .../DesignedComponents/HeadersH2Buttons.swift | 57 +++++++++++++++++++ .../HeadersH2ButtonsModel.swift | 56 ++++++++++++++++++ .../OtherHandlers/MoleculeObjectMapping.swift | 1 + 4 files changed, 122 insertions(+) create mode 100644 MVMCoreUI/Molecules/DesignedComponents/HeadersH2Buttons.swift create mode 100644 MVMCoreUI/Molecules/DesignedComponents/HeadersH2ButtonsModel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 8de69762..0dae59fe 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -154,6 +154,8 @@ 94FB966323D797DA003D482B /* MFTextButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 94FB966123D797DA003D482B /* MFTextButton.m */; }; AA11A41F23F15D3100D7962F /* ListRightVariablePayments.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11A41E23F15D3100D7962F /* ListRightVariablePayments.swift */; }; AA11A42123F15D7000D7962F /* ListRightVariablePaymentsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11A42023F15D7000D7962F /* ListRightVariablePaymentsModel.swift */; }; + AA2D8157241766AC00857570 /* HeadersH2Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA2D8156241766AC00857570 /* HeadersH2Buttons.swift */; }; + AA2D8159241766CC00857570 /* HeadersH2ButtonsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA2D8158241766CC00857570 /* HeadersH2ButtonsModel.swift */; }; C003506123AA94CD00B6AC29 /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = C003506023AA94CD00B6AC29 /* Button.swift */; }; C07065C42395677300FBF997 /* Link.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07065C32395677300FBF997 /* Link.swift */; }; C695A67F23C9830600BFB94E /* UnOrderedListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C695A67E23C9830600BFB94E /* UnOrderedListModel.swift */; }; @@ -505,6 +507,8 @@ 94FB966123D797DA003D482B /* MFTextButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFTextButton.m; sourceTree = ""; }; AA11A41E23F15D3100D7962F /* ListRightVariablePayments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariablePayments.swift; sourceTree = ""; }; AA11A42023F15D7000D7962F /* ListRightVariablePaymentsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariablePaymentsModel.swift; sourceTree = ""; }; + AA2D8156241766AC00857570 /* HeadersH2Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2Buttons.swift; sourceTree = ""; }; + AA2D8158241766CC00857570 /* HeadersH2ButtonsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2ButtonsModel.swift; sourceTree = ""; }; C003506023AA94CD00B6AC29 /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; C07065C32395677300FBF997 /* Link.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Link.swift; sourceTree = ""; }; C695A67E23C9830600BFB94E /* UnOrderedListModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnOrderedListModel.swift; sourceTree = ""; }; @@ -1054,6 +1058,8 @@ 525239C32407FFCC00454969 /* LockUps */, D22B38EC23F4E10700490EF6 /* SectionDividers */, D22B38EA23F4E08B00490EF6 /* List */, + AA2D8156241766AC00857570 /* HeadersH2Buttons.swift */, + AA2D8158241766CC00857570 /* HeadersH2ButtonsModel.swift */, ); path = DesignedComponents; sourceTree = ""; @@ -1876,6 +1882,7 @@ D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */, 011B58F223A2AE2C0085F53C /* DropDownListItemModel.swift in Sources */, 8D448E5524050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift in Sources */, + AA2D8157241766AC00857570 /* HeadersH2Buttons.swift in Sources */, 94C2D9842386F3F80006CF46 /* LabelAttributeModel.swift in Sources */, 944589212385D6E900DE9FD4 /* DashLineModel.swift in Sources */, D2E2A99623D8CF85000B42E6 /* HeadlineBodyLinkToggleModel.swift in Sources */, @@ -1915,6 +1922,7 @@ D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */, 0AE14F64238315D2005417F8 /* TextField.swift in Sources */, D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */, + AA2D8159241766CC00857570 /* HeadersH2ButtonsModel.swift in Sources */, 017BEB4A236235BA0024EF95 /* ModelMoleculeViewProtocol.swift in Sources */, C695A68123C9830D00BFB94E /* NumberedListModel.swift in Sources */, 012CA99A2384A687003F810F /* MFTextField+ModelExtension.swift in Sources */, diff --git a/MVMCoreUI/Molecules/DesignedComponents/HeadersH2Buttons.swift b/MVMCoreUI/Molecules/DesignedComponents/HeadersH2Buttons.swift new file mode 100644 index 00000000..00521edf --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/HeadersH2Buttons.swift @@ -0,0 +1,57 @@ +// +// HeadersH2Buttons.swift +// MVMCoreUI +// +// Created by Lekshmi S on 10/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers open class HeadersH2Buttons: View { + //-------------------------------------------------- + // MARK: - Outlets + //-------------------------------------------------- + let headlineBody = HeadlineBody(frame: .zero) + let buttons = TwoButtonView(frame: .zero) + var stack = Stack(frame: .zero) + var spacingBetwenHeadlineBodyAndButton: CGFloat = 24.0 + + //------------------------------------------------------- + // MARK: - View Lifecycle + //------------------------------------------------------- + open override func setupView() { + super.setupView() + stack = Stack.createStack(with: [(view: headlineBody, model: StackItemModel(horizontalAlignment: .leading)), + (view: buttons, model: StackItemModel(spacing: spacingBetwenHeadlineBodyAndButton, horizontalAlignment: .leading))], axis: .vertical) + headlineBody.stylePageHeader() + addSubview(stack) + NSLayoutConstraint.constraintPinSubview(toSuperview: stack) + } + + open override func updateView(_ size: CGFloat) { + super.updateView(size) + stack.updateView(size) + } + + //---------------------------------------------------- + // MARK: - Molecule + //------------------------------------------------------ + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + super.set(with: model, delegateObject, additionalData) + guard let model = model as? HeadersH2ButtonsModel else { return } + headlineBody.set(with: model.headlineBody, delegateObject, additionalData) + buttons.set(with: model.buttons, delegateObject, additionalData) + stack.restack() + } + + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return 121 + } + + open override func reset() { + super.reset() + headlineBody.stylePageHeader() + buttons.reset() + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/HeadersH2ButtonsModel.swift b/MVMCoreUI/Molecules/DesignedComponents/HeadersH2ButtonsModel.swift new file mode 100644 index 00000000..fb03fefc --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/HeadersH2ButtonsModel.swift @@ -0,0 +1,56 @@ +// +// HeadersH2ButtonsModel.swift +// MVMCoreUI +// +// Created by Lekshmi S on 10/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class HeadersH2ButtonsModel: MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public static var identifier: String = "headerH2Btns" + public var backgroundColor: Color? + public var headlineBody: HeadlineBodyModel + public var buttons: TwoButtonViewModel + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(headlineBody: HeadlineBodyModel, buttons: TwoButtonViewModel) { + self.headlineBody = headlineBody + self.buttons = buttons + } + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { + case moleculeName + case backgroundColor + case headlineBody + case buttons + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + headlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .headlineBody) + buttons = try typeContainer.decode(TwoButtonViewModel.self, forKey: .buttons) + } + + 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) + try container.encode(headlineBody, forKey: .headlineBody) + try container.encode(buttons, forKey: .buttons) + } +} diff --git a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift index 003b5d03..7aad3786 100644 --- a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift +++ b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift @@ -109,6 +109,7 @@ import Foundation // Designed Section Dividers MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListFourColumnDataUsageDivider.self, viewModelClass: ListFourColumnDataUsageDividerModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListThreeColumnPlanDataDivider.self, viewModelClass: ListThreeColumnPlanDataDividerModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: HeadersH2Buttons.self, viewModelClass: HeadersH2ButtonsModel.self) // TODO: Need model MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping.setObject(DigitEntryField.self, forKey: "digitTextField" as NSString) From d161fbf9fb5f027d4c48e5afb439a31588daa943 Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Thu, 19 Mar 2020 11:26:25 +0530 Subject: [PATCH 02/67] Folder structure changes and conforming to headerView and headermodel. --- MVMCoreUI.xcodeproj/project.pbxproj | 12 ++++++------ .../{ => Headers}/HeadersH2Buttons.swift | 15 ++++----------- .../{ => Headers}/HeadersH2ButtonsModel.swift | 17 +++++++++++------ 3 files changed, 21 insertions(+), 23 deletions(-) rename MVMCoreUI/Molecules/DesignedComponents/{ => Headers}/HeadersH2Buttons.swift (80%) rename MVMCoreUI/Molecules/DesignedComponents/{ => Headers}/HeadersH2ButtonsModel.swift (80%) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 9da3f293..afc44643 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -175,6 +175,8 @@ 94FB966323D797DA003D482B /* MFTextButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 94FB966123D797DA003D482B /* MFTextButton.m */; }; AA11A41F23F15D3100D7962F /* ListRightVariablePayments.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11A41E23F15D3100D7962F /* ListRightVariablePayments.swift */; }; AA11A42123F15D7000D7962F /* ListRightVariablePaymentsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11A42023F15D7000D7962F /* ListRightVariablePaymentsModel.swift */; }; + AA2D8157241766AC00857570 /* HeadersH2Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA2D8156241766AC00857570 /* HeadersH2Buttons.swift */; }; + AA2D8159241766CC00857570 /* HeadersH2ButtonsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA2D8158241766CC00857570 /* HeadersH2ButtonsModel.swift */; }; AAA74A172410C04600080241 /* HeadersH2NoButtonsBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */; }; AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */; }; BB47A586241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB47A585241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift */; }; @@ -183,8 +185,6 @@ BB6C6AC1242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6C6ABF242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift */; }; BB6C6AC824225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6C6AC62422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift */; }; BB6C6AC924225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6C6AC72422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift */; }; - AA2D8157241766AC00857570 /* HeadersH2Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA2D8156241766AC00857570 /* HeadersH2Buttons.swift */; }; - AA2D8159241766CC00857570 /* HeadersH2ButtonsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA2D8158241766CC00857570 /* HeadersH2ButtonsModel.swift */; }; C003506123AA94CD00B6AC29 /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = C003506023AA94CD00B6AC29 /* Button.swift */; }; C07065C42395677300FBF997 /* Link.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07065C32395677300FBF997 /* Link.swift */; }; C695A67F23C9830600BFB94E /* UnOrderedListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C695A67E23C9830600BFB94E /* UnOrderedListModel.swift */; }; @@ -561,6 +561,8 @@ 94FB966123D797DA003D482B /* MFTextButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFTextButton.m; sourceTree = ""; }; AA11A41E23F15D3100D7962F /* ListRightVariablePayments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariablePayments.swift; sourceTree = ""; }; AA11A42023F15D7000D7962F /* ListRightVariablePaymentsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariablePaymentsModel.swift; sourceTree = ""; }; + AA2D8156241766AC00857570 /* HeadersH2Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2Buttons.swift; sourceTree = ""; }; + AA2D8158241766CC00857570 /* HeadersH2ButtonsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2ButtonsModel.swift; sourceTree = ""; }; AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyText.swift; sourceTree = ""; }; AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyTextModel.swift; sourceTree = ""; }; BB47A585241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextDividerSubsectionModel.swift; sourceTree = ""; }; @@ -569,8 +571,6 @@ BB6C6ABF242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ListOneColumnTextWithWhitespaceDividerTall.swift; path = MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift; sourceTree = SOURCE_ROOT; }; BB6C6AC62422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListOneColumnTextWithWhitespaceDividerShort.swift; sourceTree = ""; }; BB6C6AC72422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListOneColumnTextWithWhitespaceDividerShortModel.swift; sourceTree = ""; }; - AA2D8156241766AC00857570 /* HeadersH2Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2Buttons.swift; sourceTree = ""; }; - AA2D8158241766CC00857570 /* HeadersH2ButtonsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2ButtonsModel.swift; sourceTree = ""; }; C003506023AA94CD00B6AC29 /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; C07065C32395677300FBF997 /* Link.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Link.swift; sourceTree = ""; }; C695A67E23C9830600BFB94E /* UnOrderedListModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnOrderedListModel.swift; sourceTree = ""; }; @@ -912,6 +912,8 @@ children = ( AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */, AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */, + AA2D8156241766AC00857570 /* HeadersH2Buttons.swift */, + AA2D8158241766CC00857570 /* HeadersH2ButtonsModel.swift */, ); path = Headers; sourceTree = ""; @@ -1187,8 +1189,6 @@ 525239C32407FFCC00454969 /* LockUps */, D22B38EC23F4E10700490EF6 /* SectionDividers */, D22B38EA23F4E08B00490EF6 /* List */, - AA2D8156241766AC00857570 /* HeadersH2Buttons.swift */, - AA2D8158241766CC00857570 /* HeadersH2ButtonsModel.swift */, ); path = DesignedComponents; sourceTree = ""; diff --git a/MVMCoreUI/Molecules/DesignedComponents/HeadersH2Buttons.swift b/MVMCoreUI/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift similarity index 80% rename from MVMCoreUI/Molecules/DesignedComponents/HeadersH2Buttons.swift rename to MVMCoreUI/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift index 00521edf..0f359d52 100644 --- a/MVMCoreUI/Molecules/DesignedComponents/HeadersH2Buttons.swift +++ b/MVMCoreUI/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift @@ -8,14 +8,13 @@ import Foundation -@objcMembers open class HeadersH2Buttons: View { +@objcMembers open class HeadersH2Buttons: HeaderView { //-------------------------------------------------- // MARK: - Outlets //-------------------------------------------------- let headlineBody = HeadlineBody(frame: .zero) let buttons = TwoButtonView(frame: .zero) var stack = Stack(frame: .zero) - var spacingBetwenHeadlineBodyAndButton: CGFloat = 24.0 //------------------------------------------------------- // MARK: - View Lifecycle @@ -23,15 +22,10 @@ import Foundation open override func setupView() { super.setupView() stack = Stack.createStack(with: [(view: headlineBody, model: StackItemModel(horizontalAlignment: .leading)), - (view: buttons, model: StackItemModel(spacing: spacingBetwenHeadlineBodyAndButton, horizontalAlignment: .leading))], axis: .vertical) + (view: buttons, model: StackItemModel(spacing: PaddingDefaultVerticalSpacing3, horizontalAlignment: .leading))], axis: .vertical) headlineBody.stylePageHeader() - addSubview(stack) - NSLayoutConstraint.constraintPinSubview(toSuperview: stack) - } - - open override func updateView(_ size: CGFloat) { - super.updateView(size) - stack.updateView(size) + addMolecule(stack) + stack.restack() } //---------------------------------------------------- @@ -42,7 +36,6 @@ import Foundation guard let model = model as? HeadersH2ButtonsModel else { return } headlineBody.set(with: model.headlineBody, delegateObject, additionalData) buttons.set(with: model.buttons, delegateObject, additionalData) - stack.restack() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { diff --git a/MVMCoreUI/Molecules/DesignedComponents/HeadersH2ButtonsModel.swift b/MVMCoreUI/Molecules/DesignedComponents/Headers/HeadersH2ButtonsModel.swift similarity index 80% rename from MVMCoreUI/Molecules/DesignedComponents/HeadersH2ButtonsModel.swift rename to MVMCoreUI/Molecules/DesignedComponents/Headers/HeadersH2ButtonsModel.swift index fb03fefc..5bc285ad 100644 --- a/MVMCoreUI/Molecules/DesignedComponents/HeadersH2ButtonsModel.swift +++ b/MVMCoreUI/Molecules/DesignedComponents/Headers/HeadersH2ButtonsModel.swift @@ -8,13 +8,12 @@ import Foundation -public class HeadersH2ButtonsModel: MoleculeModelProtocol { +public class HeadersH2ButtonsModel: HeaderModel, MoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- public static var identifier: String = "headerH2Btns" - public var backgroundColor: Color? public var headlineBody: HeadlineBodyModel public var buttons: TwoButtonViewModel @@ -24,6 +23,13 @@ public class HeadersH2ButtonsModel: MoleculeModelProtocol { public init(headlineBody: HeadlineBodyModel, buttons: TwoButtonViewModel) { self.headlineBody = headlineBody self.buttons = buttons + super.init() + } + + public override func setDefaults() { + super.setDefaults() + topMarginPadding = PaddingDefaultVerticalSpacing3 + bottomMarginPadding = PaddingDefaultVerticalSpacing3 } //-------------------------------------------------- @@ -31,7 +37,6 @@ public class HeadersH2ButtonsModel: MoleculeModelProtocol { //-------------------------------------------------- private enum CodingKeys: String, CodingKey { case moleculeName - case backgroundColor case headlineBody case buttons } @@ -41,15 +46,15 @@ public class HeadersH2ButtonsModel: MoleculeModelProtocol { //-------------------------------------------------- required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) headlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .headlineBody) buttons = try typeContainer.decode(TwoButtonViewModel.self, forKey: .buttons) + try super.init(from: decoder) } - public func encode(to encoder: Encoder) throws { + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(moleculeName, forKey: .moleculeName) - try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encode(headlineBody, forKey: .headlineBody) try container.encode(buttons, forKey: .buttons) } From 21af3227c929e049560ed3f2464804190324b289 Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Wed, 15 Apr 2020 19:32:34 +0530 Subject: [PATCH 03/67] Restructured folder after merge from develop. --- MVMCoreUI.xcodeproj/project.pbxproj | 16 ++++++++-------- MVMCoreUI/Atomic/MoleculeObjectMapping.swift | 1 + .../Headers/HeadersH2Buttons.swift | 0 .../Headers/HeadersH2ButtonsModel.swift | 0 4 files changed, 9 insertions(+), 8 deletions(-) rename MVMCoreUI/Atomic/Molecules/{HorizontalCombinationViews => }/DesignedComponents/Headers/HeadersH2Buttons.swift (100%) rename MVMCoreUI/Atomic/Molecules/{HorizontalCombinationViews => }/DesignedComponents/Headers/HeadersH2ButtonsModel.swift (100%) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index e681e1e9..1c0a4c00 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -184,14 +184,14 @@ 94F217B723E0BF6100A47C06 /* PrimaryButtonView.m in Sources */ = {isa = PBXBuildFile; fileRef = 94F217B523E0BF6100A47C06 /* PrimaryButtonView.m */; }; 94FB966223D797DA003D482B /* MFTextButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 94FB966023D797DA003D482B /* MFTextButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; 94FB966323D797DA003D482B /* MFTextButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 94FB966123D797DA003D482B /* MFTextButton.m */; }; + AA104B1A24474A66004D2810 /* HeadersH2Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA104B1924474A66004D2810 /* HeadersH2Buttons.swift */; }; + AA104B1C24474A76004D2810 /* HeadersH2ButtonsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA104B1B24474A76004D2810 /* HeadersH2ButtonsModel.swift */; }; AA11A41F23F15D3100D7962F /* ListRightVariablePayments.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11A41E23F15D3100D7962F /* ListRightVariablePayments.swift */; }; AA11A42123F15D7000D7962F /* ListRightVariablePaymentsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11A42023F15D7000D7962F /* ListRightVariablePaymentsModel.swift */; }; AA1EC59724373985003D6F50 /* ListThreeColumnSpeedTestDividerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1EC59624373985003D6F50 /* ListThreeColumnSpeedTestDividerModel.swift */; }; AA1EC59924373994003D6F50 /* ListThreeColumnSpeedTestDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1EC59824373994003D6F50 /* ListThreeColumnSpeedTestDivider.swift */; }; AA56A20F243C5EE900303286 /* ListTwoColumnSubsectionDividerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA56A20E243C5EE900303286 /* ListTwoColumnSubsectionDividerModel.swift */; }; AA56A211243C5EFC00303286 /* ListTwoColumnSubsectionDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA56A210243C5EFC00303286 /* ListTwoColumnSubsectionDivider.swift */; }; - AA2D8157241766AC00857570 /* HeadersH2Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA2D8156241766AC00857570 /* HeadersH2Buttons.swift */; }; - AA2D8159241766CC00857570 /* HeadersH2ButtonsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA2D8158241766CC00857570 /* HeadersH2ButtonsModel.swift */; }; AAA74A172410C04600080241 /* HeadersH2NoButtonsBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */; }; AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */; }; BB2C968F24330EA7006FF80C /* ListRightVariableTextLinkAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB2C968D24330EA7006FF80C /* ListRightVariableTextLinkAllTextAndLinksModel.swift */; }; @@ -612,14 +612,14 @@ 94F217B523E0BF6100A47C06 /* PrimaryButtonView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PrimaryButtonView.m; sourceTree = ""; }; 94FB966023D797DA003D482B /* MFTextButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFTextButton.h; sourceTree = ""; }; 94FB966123D797DA003D482B /* MFTextButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFTextButton.m; sourceTree = ""; }; + AA104B1924474A66004D2810 /* HeadersH2Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2Buttons.swift; sourceTree = ""; }; + AA104B1B24474A76004D2810 /* HeadersH2ButtonsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2ButtonsModel.swift; sourceTree = ""; }; AA11A41E23F15D3100D7962F /* ListRightVariablePayments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariablePayments.swift; sourceTree = ""; }; AA11A42023F15D7000D7962F /* ListRightVariablePaymentsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariablePaymentsModel.swift; sourceTree = ""; }; AA1EC59624373985003D6F50 /* ListThreeColumnSpeedTestDividerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnSpeedTestDividerModel.swift; sourceTree = ""; }; AA1EC59824373994003D6F50 /* ListThreeColumnSpeedTestDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnSpeedTestDivider.swift; sourceTree = ""; }; AA56A20E243C5EE900303286 /* ListTwoColumnSubsectionDividerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnSubsectionDividerModel.swift; sourceTree = ""; }; AA56A210243C5EFC00303286 /* ListTwoColumnSubsectionDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnSubsectionDivider.swift; sourceTree = ""; }; - AA2D8156241766AC00857570 /* HeadersH2Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2Buttons.swift; sourceTree = ""; }; - AA2D8158241766CC00857570 /* HeadersH2ButtonsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2ButtonsModel.swift; sourceTree = ""; }; AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyText.swift; sourceTree = ""; }; AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyTextModel.swift; sourceTree = ""; }; BB2C968D24330EA7006FF80C /* ListRightVariableTextLinkAllTextAndLinksModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListRightVariableTextLinkAllTextAndLinksModel.swift; sourceTree = ""; }; @@ -998,8 +998,8 @@ children = ( AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */, AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */, - AA2D8156241766AC00857570 /* HeadersH2Buttons.swift */, - AA2D8158241766CC00857570 /* HeadersH2ButtonsModel.swift */, + AA104B1924474A66004D2810 /* HeadersH2Buttons.swift */, + AA104B1B24474A76004D2810 /* HeadersH2ButtonsModel.swift */, ); path = Headers; sourceTree = ""; @@ -2240,7 +2240,6 @@ D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */, 011B58F223A2AE2C0085F53C /* DropDownListItemModel.swift in Sources */, 8D448E5524050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift in Sources */, - AA2D8157241766AC00857570 /* HeadersH2Buttons.swift in Sources */, 94C2D9842386F3F80006CF46 /* LabelAttributeModel.swift in Sources */, 944589212385D6E900DE9FD4 /* DashLineModel.swift in Sources */, D2E2A99623D8CF85000B42E6 /* HeadlineBodyLinkToggleModel.swift in Sources */, @@ -2297,7 +2296,6 @@ 0AE14F64238315D2005417F8 /* TextField.swift in Sources */, D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */, D2C78CD224228BBD00B69FDE /* ActionOpenPanelModel.swift in Sources */, - AA2D8159241766CC00857570 /* HeadersH2ButtonsModel.swift in Sources */, C695A68123C9830D00BFB94E /* NumberedListModel.swift in Sources */, 01EB3684236097C0006832FA /* MoleculeModelProtocol.swift in Sources */, D27CD4102339057800C1DC07 /* EyebrowHeadlineBodyLink.swift in Sources */, @@ -2354,10 +2352,12 @@ DBC4391B224421A0001AB423 /* CaretLink.swift in Sources */, D264FA90243BCE6800D98315 /* ThreeLayerCollectionViewController.swift in Sources */, 0198F7A82256A80B0066C936 /* MFRadioButton.m in Sources */, + AA104B1C24474A76004D2810 /* HeadersH2ButtonsModel.swift in Sources */, 0A6BF4722360C56C0028F841 /* BaseDropdownEntryField.swift in Sources */, BB6C6AC824225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift in Sources */, 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */, D21B7F73243BAC6800051ABF /* CollectionItemModelProtocol.swift in Sources */, + AA104B1A24474A66004D2810 /* HeadersH2Buttons.swift in Sources */, C7192E7D23C301750050C2A0 /* HeadLineBodyCaretLinkImage.swift in Sources */, D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */, D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */, diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index ab0d5b43..eaddc237 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -163,6 +163,7 @@ import Foundation // Designed Headers MoleculeObjectMapping.shared()?.register(viewClass: HeadersH2NoButtonsBodyText.self, viewModelClass: HeadersH2NoButtonsBodyTextModel.self) + MoleculeObjectMapping.shared()?.register(viewClass: HeadersH2Buttons.self, viewModelClass: HeadersH2ButtonsModel.self) // TODO: Need View try? ModelRegistry.register(TabsModel.self) diff --git a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/DesignedComponents/Headers/HeadersH2Buttons.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift similarity index 100% rename from MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/DesignedComponents/Headers/HeadersH2Buttons.swift rename to MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift diff --git a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/DesignedComponents/Headers/HeadersH2ButtonsModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2ButtonsModel.swift similarity index 100% rename from MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/DesignedComponents/Headers/HeadersH2ButtonsModel.swift rename to MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2ButtonsModel.swift From b2fee17d8ae228d262fd8831661b52e760b06012 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 17 Apr 2020 16:58:07 -0400 Subject: [PATCH 04/67] changes made to resolve VO issues --- .../Templates/ModalMoleculeListTemplate.swift | 3 +++ .../ThreeLayerTableViewController.swift | 1 + .../Views/Container/ContainerHelper.swift | 20 +++++++++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift index eda35d6b..eb85d80b 100644 --- a/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift @@ -17,5 +17,8 @@ open class ModalMoleculeListTemplate: MoleculeListTemplate { closeButton = MVMCoreUICommonViewsUtility.addCloseButton(to: view, action: { _ in MVMCoreNavigationHandler.shared()?.removeCurrentViewController() }, verticalCentered: false) + + accessibilityElements = [closeButton as Any, tableView as Any] + UIAccessibility.post(notification: .layoutChanged, argument: closeButton) } } diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index 000f2e7f..bc5778b7 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -41,6 +41,7 @@ open class ThreeLayerTableViewController: ProgrammaticTableViewController { createViewForTableHeader() createViewForTableFooter() tableView?.reloadData() + accessibilityElements = [tableView as Any] } override open func viewDidLoad() { diff --git a/MVMCoreUI/Containers/Views/Container/ContainerHelper.swift b/MVMCoreUI/Containers/Views/Container/ContainerHelper.swift index 223589fe..fcb8877e 100644 --- a/MVMCoreUI/Containers/Views/Container/ContainerHelper.swift +++ b/MVMCoreUI/Containers/Views/Container/ContainerHelper.swift @@ -9,7 +9,12 @@ import Foundation + open class ContainerHelper: NSObject { + //-------------------------------------------------- + // MARK: - Constraints + //-------------------------------------------------- + var leftConstraint: NSLayoutConstraint? var topConstraint: NSLayoutConstraint? var bottomConstraint: NSLayoutConstraint? @@ -28,17 +33,26 @@ open class ContainerHelper: NSObject { var bottomLowConstraint: NSLayoutConstraint? var rightLowConstraint: NSLayoutConstraint? + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + open func constrainView(_ view: UIView) { guard let margins = view.superview?.layoutMarginsGuide else { return } + + leftConstraint?.isActive = false leftConstraint = view.leftAnchor.constraint(equalTo: margins.leftAnchor) leftConstraint?.isActive = true + topConstraint?.isActive = false topConstraint = view.topAnchor.constraint(equalTo: margins.topAnchor) topConstraint?.isActive = true + rightConstraint?.isActive = false rightConstraint = margins.rightAnchor.constraint(equalTo: view.rightAnchor) rightConstraint?.isActive = true + bottomConstraint?.isActive = false bottomConstraint = margins.bottomAnchor.constraint(equalTo: view.bottomAnchor) bottomConstraint?.isActive = true @@ -50,23 +64,25 @@ open class ContainerHelper: NSObject { alignCenterTopConstraint = view.topAnchor.constraint(greaterThanOrEqualTo: margins.topAnchor) alignCenterBottomConstraint = margins.bottomAnchor.constraint(greaterThanOrEqualTo: view.bottomAnchor) + leftLowConstraint?.isActive = false leftLowConstraint = view.leftAnchor.constraint(equalTo: margins.leftAnchor) leftLowConstraint?.priority = UILayoutPriority(rawValue: 200) leftLowConstraint?.isActive = true + topLowConstraint?.isActive = false topLowConstraint = view.topAnchor.constraint(equalTo: margins.topAnchor) topLowConstraint?.priority = UILayoutPriority(rawValue: 200) topLowConstraint?.isActive = true + rightLowConstraint?.isActive = false rightLowConstraint = margins.rightAnchor.constraint(equalTo: view.rightAnchor) rightLowConstraint?.priority = UILayoutPriority(rawValue: 200) rightLowConstraint?.isActive = true + bottomLowConstraint?.isActive = false bottomLowConstraint = margins.bottomAnchor.constraint(equalTo: view.bottomAnchor) bottomLowConstraint?.priority = UILayoutPriority(rawValue: 200) bottomLowConstraint?.isActive = true - - setAccessibility(view) } open func setAccessibility(_ view: UIView) { From ac158381beff308121db01ac38d3085054ed489b Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 27 Apr 2020 15:06:09 -0400 Subject: [PATCH 05/67] accessibility as a cell --- ...tVariableRadioButtonAndPaymentMethod.swift | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift index 7bf1ff6a..d32f048f 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift @@ -46,6 +46,11 @@ import UIKit stack.restack() eyebrowHeadlineBodyLink.body.textColor = .mvmOrangeAA eyebrowHeadlineBodyLink.headline.styleBoldBodySmall(true) + + isAccessibilityElement = true + updateAccessibilityLabel() + accessibilityTraits = .button + accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint") } open override func reset() { @@ -64,6 +69,7 @@ import UIKit radioButton.set(with: model.radioButton, delegateObject, additionalData) leftImage.set(with: model.image, delegateObject, additionalData) eyebrowHeadlineBodyLink.set(with: model.eyebrowHeadlineBodyLink, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -73,4 +79,31 @@ import UIKit public override func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { radioButton.tapAction() } + + func updateAccessibilityLabel() { + + var message = "Radio Button, " + + if let radioButtonLabel = radioButton.accessibilityLabel { + message += radioButtonLabel + ", " + } + + if let leftImageLabel = leftImage.accessibilityLabel { + message += leftImageLabel + ", " + } + + if let eyebrowLabel = eyebrowHeadlineBodyLink.eyebrow.text { + message += eyebrowLabel + ", " + } + + if let headlineLabel = eyebrowHeadlineBodyLink.headline.text { + message += headlineLabel + ", " + } + + if let bodyLabel = eyebrowHeadlineBodyLink.eyebrow.text { + message += bodyLabel + } + + accessibilityLabel = message + } } From 372d5c9098971398632a6f102cb5d9ca42aabe8c Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Tue, 28 Apr 2020 14:07:18 +0530 Subject: [PATCH 06/67] Code cleanup --- .../DesignedComponents/Headers/HeadersH2Buttons.swift | 9 ++++----- .../Headers/HeadersH2ButtonsModel.swift | 5 ++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift index 0f359d52..81da0471 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift @@ -12,17 +12,16 @@ import Foundation //-------------------------------------------------- // MARK: - Outlets //-------------------------------------------------- - let headlineBody = HeadlineBody(frame: .zero) - let buttons = TwoButtonView(frame: .zero) - var stack = Stack(frame: .zero) + public let headlineBody = HeadlineBody(frame: .zero) + public let buttons = TwoButtonView(frame: .zero) + public var stack = Stack(frame: .zero) //------------------------------------------------------- // MARK: - View Lifecycle //------------------------------------------------------- open override func setupView() { super.setupView() - stack = Stack.createStack(with: [(view: headlineBody, model: StackItemModel(horizontalAlignment: .leading)), - (view: buttons, model: StackItemModel(spacing: PaddingDefaultVerticalSpacing3, horizontalAlignment: .leading))], axis: .vertical) + stack = Stack.createStack(with: [(view: headlineBody, model: StackItemModel(horizontalAlignment: .leading)), (view: buttons, model: StackItemModel(spacing: PaddingDefaultVerticalSpacing3, horizontalAlignment: .leading))], axis: .vertical) headlineBody.stylePageHeader() addMolecule(stack) stack.restack() diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2ButtonsModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2ButtonsModel.swift index 5bc285ad..afc57f2e 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2ButtonsModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2ButtonsModel.swift @@ -12,7 +12,6 @@ public class HeadersH2ButtonsModel: HeaderModel, MoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - public static var identifier: String = "headerH2Btns" public var headlineBody: HeadlineBodyModel public var buttons: TwoButtonViewModel @@ -28,8 +27,8 @@ public class HeadersH2ButtonsModel: HeaderModel, MoleculeModelProtocol { public override func setDefaults() { super.setDefaults() - topMarginPadding = PaddingDefaultVerticalSpacing3 - bottomMarginPadding = PaddingDefaultVerticalSpacing3 + topPadding = PaddingDefaultVerticalSpacing3 + bottomPadding = PaddingDefaultVerticalSpacing3 } //-------------------------------------------------- From 8e47e4ceb3c522e89960b061f7ea6a47536db189 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 28 Apr 2020 08:33:23 -0400 Subject: [PATCH 07/67] customized accessibility for cell --- MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift | 2 +- .../ListLeftVariableRadioButtonAndPaymentMethod.swift | 8 ++++---- MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m | 10 ++++++---- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift index 2b22fcee..aa73e7b5 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift @@ -127,7 +127,7 @@ import UIKit func updateAccessibilityLabel() { if let state = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "radio_selected_state" : "radio_not_selected_state") { - accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "radio_desc_state") ?? "%@%@", "", state) + accessibilityLabel = state } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift index d32f048f..1c1ddada 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift @@ -77,13 +77,13 @@ import UIKit } public override func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - radioButton.tapAction() + radioButton.tapAction() } func updateAccessibilityLabel() { var message = "Radio Button, " - + if let radioButtonLabel = radioButton.accessibilityLabel { message += radioButtonLabel + ", " } @@ -100,10 +100,10 @@ import UIKit message += headlineLabel + ", " } - if let bodyLabel = eyebrowHeadlineBodyLink.eyebrow.text { + if let bodyLabel = eyebrowHeadlineBodyLink.body.text { message += bodyLabel } - + accessibilityLabel = message } } diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m index 6fc7121f..b2c4785a 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertExpandableView.m @@ -301,11 +301,13 @@ [weakSelf.viewToLayout layoutIfNeeded]; }; + //accessibility - added to make only top alert label and close button accessible. Posted notification when top alert is displayed + weakSelf.accessibilityElements = @[weakSelf.buttonView]; + weakSelf.shortView.isAccessibilityElement = NO; + weakSelf.buttonView.label.accessibilityLabel = [NSString stringWithFormat:@"%@ - %@", [MVMCoreUIUtility hardcodedStringWithKey:@"top_alert_notification"],weakSelf.buttonView.label.accessibilityLabel]; + void(^completion)(void) = ^(void) { - //accessibility - added to make only top alert label and close button accessible. Posted notification when top alert is displayed - weakSelf.accessibilityElements = @[weakSelf.buttonView]; - weakSelf.shortView.isAccessibilityElement = NO; - weakSelf.buttonView.label.accessibilityLabel = [NSString stringWithFormat:@"%@ - %@", [MVMCoreUIUtility hardcodedStringWithKey:@"top_alert_notification"],weakSelf.buttonView.label.accessibilityLabel]; + UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, weakSelf.buttonView.label); [operation markAsFinished]; }; From b92358cca992b7606c85c48f2322e6182fddbb76 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 28 Apr 2020 09:38:28 -0400 Subject: [PATCH 08/67] further accessibility updates. --- ...tVariableRadioButtonAndPaymentMethod.swift | 3 ++- .../ListLeftVariableRadioButtonBodyText.swift | 27 ++++++++++++++++++- .../Items/MoleculeListItemModel.swift | 19 ++++++++++++- .../Items/MoleculeTableViewCell.swift | 3 ++- .../Templates/ModalMoleculeListTemplate.swift | 9 ++++++- .../Templates/MoleculeListTemplate.swift | 6 ++++- .../Strings/en.lproj/Localizable.strings | 1 + 7 files changed, 62 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift index 1c1ddada..5ad9110a 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift @@ -82,8 +82,9 @@ import UIKit func updateAccessibilityLabel() { - var message = "Radio Button, " + var message = MVMCoreUIUtility.hardcodedString(withKey: "radio_button") ?? "" + radioButton.updateAccessibilityLabel() if let radioButtonLabel = radioButton.accessibilityLabel { message += radioButtonLabel + ", " } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift index 9b45eec7..b87c9b6c 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift @@ -14,7 +14,7 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { // MARK: - Outlets //----------------------------------------------------- - let radioButton = RadioButton(frame: .zero) + let radioButton = RadioButton() let headlineBody = HeadlineBody() var stack: Stack @@ -42,6 +42,10 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { addMolecule(stack) stack.restack() + isAccessibilityElement = true + updateAccessibilityLabel() + accessibilityTraits = .button + accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint") } //---------------------------------------------------- @@ -55,6 +59,7 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { radioButton.set(with: model.radioButton, delegateObject, additionalData) headlineBody.set(with: model.headlineBody, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -64,4 +69,24 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { public override func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { radioButton.tapAction() } + + func updateAccessibilityLabel() { + + var message = MVMCoreUIUtility.hardcodedString(withKey: "radio_button") ?? "" + + radioButton.updateAccessibilityLabel() + if let radioButtonLabel = radioButton.accessibilityLabel { + message += radioButtonLabel + ", " + } + + if let headlineLabel = headlineBody.headlineLabel.text { + message += headlineLabel + ", " + } + + if let messageLabel = headlineBody.messageLabel.text { + message += messageLabel + } + + accessibilityLabel = message + } } diff --git a/MVMCoreUI/Atomic/Molecules/Items/MoleculeListItemModel.swift b/MVMCoreUI/Atomic/Molecules/Items/MoleculeListItemModel.swift index 1384ee88..bee9d612 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/MoleculeListItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/MoleculeListItemModel.swift @@ -9,21 +9,39 @@ import Foundation import MVMCore + @objcMembers public class MoleculeListItemModel: ListItemModel, MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public class var identifier: String { return "listItem" } + public var molecule: MoleculeModelProtocol + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case molecule } + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(with moleculeModel: MoleculeModelProtocol) { molecule = moleculeModel super.init() } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) @@ -38,4 +56,3 @@ import MVMCore try container.encodeModel(molecule, forKey: .molecule) } } - diff --git a/MVMCoreUI/Atomic/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Atomic/Molecules/Items/MoleculeTableViewCell.swift index 0c9dec3b..6e1f2965 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/MoleculeTableViewCell.swift @@ -10,8 +10,9 @@ import UIKit @objcMembers open class MoleculeTableViewCell: TableViewCell { - + //-------------------------------------------------- // MARK: - MoleculeViewProtocol + //-------------------------------------------------- public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { diff --git a/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift index eb85d80b..c9ba09b7 100644 --- a/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/ModalMoleculeListTemplate.swift @@ -9,9 +9,16 @@ import UIKit open class ModalMoleculeListTemplate: MoleculeListTemplate { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- public var closeButton: MFCustomButton? - + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + override open func handleNewData() { super.handleNewData() closeButton = MVMCoreUICommonViewsUtility.addCloseButton(to: view, action: { _ in diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift index e40fbc33..521a0d45 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift @@ -12,6 +12,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol //-------------------------------------------------- // MARK: - Stored Properties //-------------------------------------------------- + public var moleculesInfo: [(identifier: String, class: AnyClass, molecule: (ListItemModelProtocol & MoleculeModelProtocol))]? var observer: NSKeyValueObservation? @@ -208,8 +209,11 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol func getMoleculeInfo(with listItem: (ListItemModelProtocol & MoleculeModelProtocol)?) -> (identifier: String, class: AnyClass, molecule: ListItemModelProtocol & MoleculeModelProtocol)? { guard let listItem = listItem, - let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(listItem) else { return nil } + let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(listItem) + else { return nil } + let moleculeName = moleculeClass.nameForReuse(with: listItem, delegateObject() as? MVMCoreUIDelegateObject) ?? listItem.moleculeName + return (moleculeName, moleculeClass, listItem) } diff --git a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings index 48cbe3ce..62c5be46 100644 --- a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings @@ -53,6 +53,7 @@ // MARK: Radio Button +"radio_button" = "Radio Button,"; "radio_action_hint" = "Double tap to select"; "radio_selected_state" = "Selected"; "radio_not_selected_state" = "Not Selected"; From 016eb01908ec7b632fd6581aea1f3036c9919d28 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 28 Apr 2020 11:09:19 -0400 Subject: [PATCH 09/67] accessibility --- .../List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift index b87c9b6c..f1ac9637 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift @@ -68,6 +68,7 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { public override func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { radioButton.tapAction() + updateAccessibilityLabel() } func updateAccessibilityLabel() { From c6eb090bb799cd96763683ff1638184a380bbf90 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 28 Apr 2020 12:10:42 -0400 Subject: [PATCH 10/67] accessibility --- .../Lists/StringAndMoleculeStack/StringAndMoleculeStack.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeStack.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeStack.swift index c887e838..8630e607 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeStack.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeStack.swift @@ -10,7 +10,7 @@ import UIKit // This class is only temporarily necessary. Eventually we will have initWithModel instad of just init for moleculeviews, which will remove this need. open class StringAndMoleculeStack: MoleculeStackView { - override open func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + override open func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { guard let model = model as? StackModelProtocol, let molcules = model.molecules as? [MoleculeStackItemModel] else { return } for stackItemModel in molcules { From 8be9c5aa8741453ed0da6bf4266fc2a0727f1204 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 28 Apr 2020 12:42:17 -0400 Subject: [PATCH 11/67] accessibility --- .../RadioButtonSelectionHelper.swift | 27 ++++++++++--------- ...ableRadioButtonAndPaymentMethodModel.swift | 20 ++++++++++++++ 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonSelectionHelper.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonSelectionHelper.swift index 5196bb9c..4765766b 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonSelectionHelper.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButtonSelectionHelper.swift @@ -19,22 +19,22 @@ import Foundation private var selectedRadioButton: RadioButton? private var selectedRadioButtonModel: RadioButtonModel? public var baseValue: AnyHashable? - -//-------------------------------------------------- -// MARK: - Initializer -//-------------------------------------------------- - + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public func set(_ radioButtonModel: RadioButtonModel, _ radioButton: RadioButton) { self.fieldKey = radioButtonModel.fieldKey self.groupName = radioButtonModel.groupName - + if radioButtonModel.state { if self.baseValue == nil, let selected = radioButtonModel.baseValue as? Bool, selected { self.baseValue = radioButtonModel.fieldValue } selectedRadioButtonModel = radioButtonModel - + // Below code is needed for cell resuse scenario. radioButton.isSelected = true selectedRadioButton = radioButton @@ -50,24 +50,24 @@ import Foundation public static func setupForRadioButtonGroup(_ radioButtonModel: RadioButtonModel, _ radioButton: RadioButton, delegateObject: MVMCoreUIDelegateObject?) { guard let groupName = radioButtonModel.fieldKey, - let formValidator = delegateObject?.formHolderDelegate?.formValidator else { - return - } - + let formValidator = delegateObject?.formHolderDelegate?.formValidator + else { return } + let radioButtonSelectionHelper = formValidator.radioButtonsModelByGroup[groupName] ?? RadioButtonSelectionHelper() radioButtonSelectionHelper.set(radioButtonModel, radioButton) formValidator.radioButtonsModelByGroup[groupName] = radioButtonSelectionHelper FormValidator.setupValidation(for: radioButtonSelectionHelper, delegate: delegateObject?.formHolderDelegate) } - + public func selected(_ radioButton: RadioButton) { + // Checks because the view could be reused if selectedRadioButton?.radioModel === selectedRadioButtonModel { selectedRadioButton?.isSelected = false } else { selectedRadioButtonModel?.state = false } - + selectedRadioButton = radioButton selectedRadioButton?.isSelected = true selectedRadioButtonModel = selectedRadioButton?.radioModel @@ -76,6 +76,7 @@ import Foundation // MARK: - FormValidationFormFieldProtocol extension RadioButtonSelectionHelper { + public func formFieldValue() -> AnyHashable? { return selectedRadioButtonModel?.fieldValue } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethodModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethodModel.swift index 5ea28778..f455882e 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethodModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethodModel.swift @@ -9,11 +9,19 @@ import Foundation public class ListLeftVariableRadioButtonAndPaymentMethodModel: ListItemModel, MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "listLVRBImg" public var radioButton: RadioButtonModel public var image: ImageViewModel public var eyebrowHeadlineBodyLink: EyebrowHeadlineBodyLinkModel + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(radioButton: RadioButtonModel, image: ImageViewModel, eyebrowHeadlineBodyLink:EyebrowHeadlineBodyLinkModel) { self.radioButton = radioButton self.image = image @@ -21,6 +29,10 @@ public class ListLeftVariableRadioButtonAndPaymentMethodModel: ListItemModel, Mo super.init() } + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + public override func setDefaults() { super.setDefaults() if image.width == nil, image.height == nil { @@ -29,6 +41,10 @@ public class ListLeftVariableRadioButtonAndPaymentMethodModel: ListItemModel, Mo } } + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case radioButton @@ -36,6 +52,10 @@ public class ListLeftVariableRadioButtonAndPaymentMethodModel: ListItemModel, Mo case eyebrowHeadlineBodyLink } + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) radioButton = try typeContainer.decode(RadioButtonModel.self, forKey: .radioButton) From 313cab70b351b6b18ecc93400b64dd0af967f5e2 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 5 May 2020 17:52:01 -0400 Subject: [PATCH 12/67] changes for accessibility and formatting --- MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift | 2 +- ...ListLeftVariableRadioButtonAndPaymentMethod.swift | 12 +++++++++--- .../ListLeftVariableRadioButtonBodyText.swift | 11 ++++++++--- .../Atomic/Templates/MoleculeListCellProtocol.swift | 12 +++++------- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift index aa73e7b5..1ac28ded 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioButton.swift @@ -20,7 +20,7 @@ import UIKit } } - public override var isSelected: Bool { + @objc public override var isSelected: Bool { didSet { radioModel?.state = isSelected updateAccessibilityLabel() diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift index 489330b2..b0ac0e6a 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift @@ -14,11 +14,13 @@ import UIKit // MARK: - Outlets //----------------------------------------------------- - let radioButton = RadioButton(frame: .zero) + let radioButton = RadioButton() let leftImage = LoadImageView(pinnedEdges: .all) let eyebrowHeadlineBodyLink = EyebrowHeadlineBodyLink() var stack: Stack + private var observation: NSKeyValueObservation? = nil + //----------------------------------------------------- // MARK: - Initializers //----------------------------------------------------- @@ -46,11 +48,16 @@ import UIKit stack.restack() eyebrowHeadlineBodyLink.body.textColor = .mvmOrangeAA eyebrowHeadlineBodyLink.headline.styleBoldBodySmall(true) - + radioButton.isAccessibilityElement = false isAccessibilityElement = true updateAccessibilityLabel() accessibilityTraits = .button accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint") + updateAccessibilityLabel() + + observation = observe(\.radioButton.isSelected, options: [.new]) { [weak self] _, _ in + self?.updateAccessibilityLabel() + } } open override func reset() { @@ -69,7 +76,6 @@ import UIKit radioButton.set(with: model.radioButton, delegateObject, additionalData) leftImage.set(with: model.image, delegateObject, additionalData) eyebrowHeadlineBodyLink.set(with: model.eyebrowHeadlineBodyLink, delegateObject, additionalData) - updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift index f1ac9637..5e9dd53d 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift @@ -18,6 +18,8 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { let headlineBody = HeadlineBody() var stack: Stack + private var observation: NSKeyValueObservation? = nil + //----------------------------------------------------- // MARK: - Initializers //----------------------------------------------------- @@ -43,9 +45,14 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { addMolecule(stack) stack.restack() isAccessibilityElement = true - updateAccessibilityLabel() + radioButton.isAccessibilityElement = false accessibilityTraits = .button accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint") + updateAccessibilityLabel() + + observation = observe(\.radioButton.isSelected, options: [.new]) { [weak self] _, _ in + self?.updateAccessibilityLabel() + } } //---------------------------------------------------- @@ -59,7 +66,6 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { radioButton.set(with: model.radioButton, delegateObject, additionalData) headlineBody.set(with: model.headlineBody, delegateObject, additionalData) - updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -68,7 +74,6 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { public override func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { radioButton.tapAction() - updateAccessibilityLabel() } func updateAccessibilityLabel() { diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListCellProtocol.swift b/MVMCoreUI/Atomic/Templates/MoleculeListCellProtocol.swift index b9cfc02f..46c9a0fa 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListCellProtocol.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListCellProtocol.swift @@ -21,12 +21,10 @@ public protocol MoleculeListCellProtocol: UITableViewCell { // Default implementation does nothing extension MoleculeListCellProtocol { - public func setLines(with model: LineModel?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, indexPath: IndexPath) { - } - public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - } - - func willDisplay() { - } + public func setLines(with model: LineModel?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, indexPath: IndexPath) { } + + public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { } + + func willDisplay() { } } From 89c62040031c79421b912d1a798a74576f35ef13 Mon Sep 17 00:00:00 2001 From: "Suresh, Kamlesh" Date: Tue, 5 May 2020 20:20:50 -0400 Subject: [PATCH 13/67] show error on end editing --- .../Atoms/TextFields/TextEntryField.swift | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift index 894fadd4..0558fda5 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift @@ -244,14 +244,21 @@ import UIKit self.isValid = isValid if previousValidity && !isValid { - showError = true - observingTextFieldDelegate?.isInvalid?(textfield: self) + shouldShowError(true) } else if (!previousValidity && isValid) { - showError = false - observingTextFieldDelegate?.isValid?(textfield: self) + shouldShowError(false) + } + } + + func shouldShowError(_ showError: Bool) { + self.showError = showError + if showError { + observingTextFieldDelegate?.isValid?(textfield: self) + entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor + } else { + observingTextFieldDelegate?.isInvalid?(textfield: self) } } - /// Executes on UITextField.textDidBeginEditingNotification @objc func startEditing() { isSelected = true @@ -268,10 +275,16 @@ import UIKit /// Executes on UITextField.textDidEndEditingNotification @objc func endInputing() { resignFirstResponder() - if isValid { - showError = false - entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor + + // If user did not enter text int ethe field dont show error yet. + if text?.count ?? 0 == 0{ + return } + + if let isValid = (model as? TextEntryFieldModel)?.isValid { + self.isValid = isValid + } + shouldShowError(!isValid) } @objc public func dismissFieldInput(_ sender: Any?) { From 33c1c3f70e0851babd0c82dc48e3bf33f4b6244d Mon Sep 17 00:00:00 2001 From: "Suresh, Kamlesh" Date: Wed, 6 May 2020 12:16:33 -0400 Subject: [PATCH 14/67] rules error handling --- .../Atoms/TextFields/EntryFieldModel.swift | 5 ++- .../Rules/RuleAllValueChangedModel.swift | 1 + .../Rules/Rules/RuleAnyRequiredModel.swift | 1 + .../Rules/RuleAnyValueChangedModel.swift | 1 + .../Rules/Rules/RuleEqualsModel.swift | 36 ++++++++++--------- .../Rules/Rules/RuleRegexModel.swift | 1 + .../Rules/Rules/RuleRequiredModel.swift | 1 + .../Rules/Rules/RulesProtocol.swift | 8 ++++- 8 files changed, 35 insertions(+), 19 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift b/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift index f7886848..dcccddda 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift @@ -67,7 +67,10 @@ import Foundation } public func setValidity(_ valid: Bool, rule: RulesProtocol) { - self.isValid = valid + if let fieldKey = fieldKey { + self.errorMessage = rule.errorMessage?[fieldKey] + self.isValid = valid + } } //-------------------------------------------------- diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAllValueChangedModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAllValueChangedModel.swift index 1f50bcc7..aa80f5b0 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAllValueChangedModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAllValueChangedModel.swift @@ -15,6 +15,7 @@ public class RuleAllValueChangedModel: RulesProtocol { public static var identifier: String = "allValueChanged" public var type: String = RuleAllValueChangedModel.identifier + public var errorMessage: [String: String]? public var fields: [String] //-------------------------------------------------- diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyRequiredModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyRequiredModel.swift index 6ca905bf..7f153e83 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyRequiredModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyRequiredModel.swift @@ -17,6 +17,7 @@ public class RuleAnyRequiredModel: RulesProtocol { public static var identifier: String = "anyRequired" public var type: String = RuleRequiredModel.identifier public var fields: [String] + public var errorMessage: [String: String]? //-------------------------------------------------- // MARK: - Methods diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyValueChangedModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyValueChangedModel.swift index 450fdb2a..07cf451f 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyValueChangedModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyValueChangedModel.swift @@ -16,6 +16,7 @@ public class RuleAnyValueChangedModel: RulesProtocol { public static var identifier: String = "anyValueChanged" public var type: String = RuleAnyValueChangedModel.identifier + public var errorMessage: [String: String]? public var fields: [String] //-------------------------------------------------- diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift index fb7585f2..9c5c3837 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift @@ -17,6 +17,7 @@ public class RuleEqualsModel: RulesProtocol { public static var identifier: String = "equals" public var type: String = RuleEqualsModel.identifier public var fields: [String] + public var errorMessage: [String: String]? //-------------------------------------------------- // MARK: - Validation @@ -27,23 +28,24 @@ public class RuleEqualsModel: RulesProtocol { } public func validate(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool { - var valid = true - var compareValue: AnyHashable? - - for formKey in fields { - guard let formField = fieldMolecules[formKey] else { continue } + var valid = true + var compareValue: AnyHashable? - if compareValue == nil { - compareValue = formField.formFieldValue() - continue - } - - if compareValue != formField.formFieldValue() { - valid = false - break - } - } - - return valid + for formKey in fields { + guard let formField = fieldMolecules[formKey] else { continue } + + if compareValue == nil { + compareValue = formField.formFieldValue() + continue + } + + if compareValue != formField.formFieldValue() { + valid = false + (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) + break + } + } + + return valid } } diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRegexModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRegexModel.swift index 68eea7e5..5f60a61b 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRegexModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRegexModel.swift @@ -18,6 +18,7 @@ public class RuleRegexModel: RulesProtocol { public var type: String = RuleRegexModel.identifier public var fields: [String] public var regex: String + public var errorMessage: [String: String]? //-------------------------------------------------- // MARK: - Properties diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRequiredModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRequiredModel.swift index b34a24df..c9e7d9f7 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRequiredModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRequiredModel.swift @@ -16,6 +16,7 @@ public class RuleRequiredModel: RulesProtocol { public static var identifier: String = "allRequired" public var type: String = RuleRequiredModel.identifier + public var errorMessage: [String: String]? public var fields: [String] //-------------------------------------------------- diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift index 305b4c35..a2906411 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift @@ -16,7 +16,9 @@ public enum RulesCodingKey: String, CodingKey { public protocol RulesProtocol: ModelProtocol { // The type of rule var type: String { get } - + + var errorMessage: [String: String]? { get } + // The fields that this rule applies to. var fields: [String] { get set } @@ -33,6 +35,10 @@ public extension RulesProtocol { get { return Self.identifier } } +// var errorMessage: String? { +// return nil +// } + static var categoryCodingKey: String { return "type" } From faf70f555231fb4799f7469d6f486faa3e6be81b Mon Sep 17 00:00:00 2001 From: "Suresh, Kamlesh" Date: Wed, 6 May 2020 12:23:22 -0400 Subject: [PATCH 15/67] error --- .../Atomic/Atoms/TextFields/EntryFieldModel.swift | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift b/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift index dcccddda..fc78613b 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift @@ -67,10 +67,12 @@ import Foundation } public func setValidity(_ valid: Bool, rule: RulesProtocol) { - if let fieldKey = fieldKey { - self.errorMessage = rule.errorMessage?[fieldKey] - self.isValid = valid - } + if let fieldKey = fieldKey, + let ruleErrorMessage = rule.errorMessage?[fieldKey] { + self.errorMessage = ruleErrorMessage + } + self.isValid = valid + } //-------------------------------------------------- From 0a79905ef2f1813bf83625c1506f58a96f7af490 Mon Sep 17 00:00:00 2001 From: "Suresh, Kamlesh" Date: Wed, 6 May 2020 12:31:04 -0400 Subject: [PATCH 16/67] remove comment --- MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift index a2906411..7392ea8f 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift @@ -35,10 +35,6 @@ public extension RulesProtocol { get { return Self.identifier } } -// var errorMessage: String? { -// return nil -// } - static var categoryCodingKey: String { return "type" } From 4346abe3785132a0ba67ad4588010ca375e81eed Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Thu, 7 May 2020 16:03:28 +0530 Subject: [PATCH 17/67] Minor change. --- .../Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift index 81da0471..3775408c 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift @@ -21,7 +21,7 @@ import Foundation //------------------------------------------------------- open override func setupView() { super.setupView() - stack = Stack.createStack(with: [(view: headlineBody, model: StackItemModel(horizontalAlignment: .leading)), (view: buttons, model: StackItemModel(spacing: PaddingDefaultVerticalSpacing3, horizontalAlignment: .leading))], axis: .vertical) + stack = Stack.createStack(with: [(view: headlineBody, model: StackItemModel(horizontalAlignment: .fill)), (view: buttons, model: StackItemModel(spacing: PaddingDefaultVerticalSpacing3, horizontalAlignment: .leading))], axis: .vertical) headlineBody.stylePageHeader() addMolecule(stack) stack.restack() From fcca1e3e8310b7d0add4ce2dd8b05d62bf08809b Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 7 May 2020 13:01:04 -0400 Subject: [PATCH 18/67] beginning stages of change --- MVMCoreUI.xcodeproj/project.pbxproj | 16 ++- .../Atoms/TextFields/EntryFieldModel.swift | 6 +- .../Atoms/TextFields/TextViewEntryField.swift | 136 ++++++++++++++++++ .../TextFields/TextViewEntryFieldModel.swift | 95 ++++++++++++ MVMCoreUI/BaseClasses/TextView.swift | 78 +--------- MVMCoreUI/BaseClasses/TextViewModel.swift | 89 +----------- 6 files changed, 256 insertions(+), 164 deletions(-) create mode 100644 MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift create mode 100644 MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index ec7e68b0..89c4ba1d 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -68,6 +68,9 @@ 0A21DB83235DFBC500C160A2 /* MdnEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A21DB82235DFBC500C160A2 /* MdnEntryField.swift */; }; 0A21DB91235E0EDB00C160A2 /* DigitBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A8321AE2355FE9500CB7F00 /* DigitBox.swift */; }; 0A21DB94235E24ED00C160A2 /* DigitEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A21DB93235E24ED00C160A2 /* DigitEntryField.swift */; }; + 0A25209624645AFD000FA9F6 /* TextViewEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A25209524645AFD000FA9F6 /* TextViewEntryField.swift */; }; + 0A25209824645B76000FA9F6 /* TextViewEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A25209724645B76000FA9F6 /* TextViewEntryFieldModel.swift */; }; + 0A2520A924646230000FA9F6 /* TextViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A2520A824646230000FA9F6 /* TextViewModel.swift */; }; 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */; }; 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */; }; @@ -76,7 +79,6 @@ 0A6682AA2435125F00AD3CA1 /* Styler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682A92435125F00AD3CA1 /* Styler.swift */; }; 0A6682AC243531C300AD3CA1 /* Padding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682AB243531C300AD3CA1 /* Padding.swift */; }; 0A6682B5243769C700AD3CA1 /* TextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682B3243769C700AD3CA1 /* TextView.swift */; }; - 0A6682B6243769C700AD3CA1 /* TextViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682B4243769C700AD3CA1 /* TextViewModel.swift */; }; 0A69F611241BDEA700F7231B /* RuleAnyRequiredModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */; }; 0A6BF4722360C56C0028F841 /* BaseDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */; }; 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; }; @@ -475,6 +477,9 @@ 0A21DB7E235DECC500C160A2 /* EntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryField.swift; sourceTree = ""; }; 0A21DB82235DFBC500C160A2 /* MdnEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MdnEntryField.swift; sourceTree = ""; }; 0A21DB93235E24ED00C160A2 /* DigitEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitEntryField.swift; sourceTree = ""; }; + 0A25209524645AFD000FA9F6 /* TextViewEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewEntryField.swift; sourceTree = ""; }; + 0A25209724645B76000FA9F6 /* TextViewEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewEntryFieldModel.swift; sourceTree = ""; }; + 0A2520A824646230000FA9F6 /* TextViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewModel.swift; sourceTree = ""; }; 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.swift"; sourceTree = ""; }; 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = ""; }; 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesProtocol.swift; sourceTree = ""; }; @@ -483,7 +488,6 @@ 0A6682A92435125F00AD3CA1 /* Styler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Styler.swift; sourceTree = ""; }; 0A6682AB243531C300AD3CA1 /* Padding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Padding.swift; sourceTree = ""; }; 0A6682B3243769C700AD3CA1 /* TextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextView.swift; sourceTree = ""; }; - 0A6682B4243769C700AD3CA1 /* TextViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextViewModel.swift; sourceTree = ""; }; 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyRequiredModel.swift; sourceTree = ""; }; 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseDropdownEntryField.swift; sourceTree = ""; }; 0A7918F423F5E7EA00772FF4 /* ImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageView.swift; sourceTree = ""; }; @@ -1638,6 +1642,8 @@ 0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */, 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */, 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */, + 0A25209724645B76000FA9F6 /* TextViewEntryFieldModel.swift */, + 0A25209524645AFD000FA9F6 /* TextViewEntryField.swift */, ); path = TextFields; sourceTree = ""; @@ -1748,7 +1754,6 @@ D2B18B7D236090D500A9AEDC /* BaseClasses */ = { isa = PBXGroup; children = ( - 0A6682B4243769C700AD3CA1 /* TextViewModel.swift */, 0A6682B3243769C700AD3CA1 /* TextView.swift */, C003506023AA94CD00B6AC29 /* Button.swift */, D2B18B7E2360913400A9AEDC /* Control.swift */, @@ -1760,6 +1765,7 @@ D264FAA92440F97600D98315 /* CollectionView.swift */, 0A5D59C323AD488600EFD9E9 /* Protocols */, 0A7918F423F5E7EA00772FF4 /* ImageView.swift */, + 0A2520A824646230000FA9F6 /* TextViewModel.swift */, ); path = BaseClasses; sourceTree = ""; @@ -2022,10 +2028,12 @@ 014AA73123C5059B006F3E93 /* ListPageTemplateModel.swift in Sources */, D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */, D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */, + 0A2520A924646230000FA9F6 /* TextViewModel.swift in Sources */, 94C2D9A723872DA90006CF46 /* LabelAttributeColorModel.swift in Sources */, 943820842432382400B43AF3 /* WebView.swift in Sources */, 0103B84E23D7E33A009C315C /* HeadlineBodyToggleModel.swift in Sources */, D2755D7B23689C7500485468 /* TableViewCell.swift in Sources */, + 0A25209624645AFD000FA9F6 /* TextViewEntryField.swift in Sources */, 014AA72623C501E2006F3E93 /* ContainerModelProtocol.swift in Sources */, AA11A42123F15D7000D7962F /* ListRightVariablePaymentsModel.swift in Sources */, 011D9626240EBB16000E3791 /* RadioButtonLabelModel.swift in Sources */, @@ -2138,7 +2146,6 @@ 012A88B1238C880100FE3DA1 /* CarouselPagingModelProtocol.swift in Sources */, 0A9D091E2433796500D2E6C0 /* NumericCarouselIndicatorModel.swift in Sources */, D29DF2C921E7BFC6003B2FB9 /* MFSizeObject.m in Sources */, - 0A6682B6243769C700AD3CA1 /* TextViewModel.swift in Sources */, 9445890E2385C3F800DE9FD4 /* MultiProgressModel.swift in Sources */, 011D95A5240455DC000E3791 /* FormGroupRule.swift in Sources */, D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */, @@ -2257,6 +2264,7 @@ AA26850C244840AE00CE34CC /* HeadersH2TinyButton.swift in Sources */, 011D95AB2405C553000E3791 /* FormItemProtocol.swift in Sources */, D21EE53C23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift in Sources */, + 0A25209824645B76000FA9F6 /* TextViewEntryFieldModel.swift in Sources */, 525019DD2406430800EED91C /* ListProgressBarDataModel.swift in Sources */, C6FA7D5223C77A4A00A3614A /* UnOrderedList.swift in Sources */, 01509D8F2327EC6F00EF99AA /* MoleculeTableViewCell.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift b/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift index f7886848..cb00bc6f 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift @@ -22,6 +22,7 @@ import Foundation public var title: String? public var feedback: String? public var errorMessage: String? + public var errorTextColor: Color? public var enabled: Bool = true public var showError: Bool? public var locked: Bool? @@ -37,7 +38,7 @@ import Foundation } /// Temporary binding mechanism for the view to update on enable changes. - public var updateUI: (() -> ())? + public var updateUI: ActionBlock? //-------------------------------------------------- // MARK: - Keys @@ -50,6 +51,7 @@ import Foundation case enabled case feedback case errorMessage + case errorTextColor case locked case selected case showError @@ -89,6 +91,7 @@ import Foundation title = try typeContainer.decodeIfPresent(String.self, forKey: .title) feedback = try typeContainer.decodeIfPresent(String.self, forKey: .feedback) 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 locked = try typeContainer.decodeIfPresent(Bool.self, forKey: .locked) selected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected) @@ -111,6 +114,7 @@ import Foundation try container.encodeIfPresent(locked, forKey: .locked) try container.encodeIfPresent(showError, forKey: .showError) try container.encodeIfPresent(selected, forKey: .selected) + try container.encodeIfPresent(errorTextColor, forKey: .errorTextColor) try container.encodeIfPresent(errorMessage, forKey: .errorMessage) try container.encode(enabled, forKey: .enabled) try container.encodeIfPresent(fieldKey, forKey: .fieldKey) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift new file mode 100644 index 00000000..b880ed5e --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -0,0 +1,136 @@ +// +// TextViewEntryField.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 5/7/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + + +class TextViewEntryField: EntryField { + //-------------------------------------------------- + // MARK: - Outlets + //-------------------------------------------------- + + open private(set) var textView: TextView = { + let textView = TextView() + textView.isAccessibilityElement = true + textView.setContentCompressionResistancePriority(.required, for: .vertical) + textView.font = Styler.Font.RegularBodyLarge.getFont() + textView.textColor = .mvmBlack + textView.smartQuotesType = .no + textView.smartDashesType = .no + textView.smartInsertDeleteType = .no + return textView + }() + + //-------------------------------------------------- + // MARK: - Constraint + //-------------------------------------------------- + + public var heightConstraint: NSLayoutConstraint? + + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + + @objc open override func setupFieldContainerContent(_ container: UIView) { + + textView.font = Styler.Font.RegularBodyLarge.getFont() + container.addSubview(textView) + + NSLayoutConstraint.activate([ + textView.topAnchor.constraint(equalTo: container.topAnchor), + textView.leadingAnchor.constraint(equalTo: container.leadingAnchor), + container.trailingAnchor.constraint(equalTo: textView.leadingAnchor), + container.bottomAnchor.constraint(equalTo: textView.bottomAnchor) + ]) + + heightConstraint = textView.heightAnchor.constraint(equalToConstant: 0) + + +// textView.addTarget(self, action: #selector(startEditing), for: .editingDidBegin) +// textView.addTarget(self, action: #selector(dismissFieldInput), for: .editingDidEnd) +// +// let tap = UITapGestureRecognizer(target: self, action: #selector(startEditing)) +// entryFieldContainer.addGestureRecognizer(tap) + + accessibilityElements = [titleLabel, textView, feedbackLabel] + } + + @objc open override func updateView(_ size: CGFloat) { + super.updateView(size) + + textView.font = Styler.Font.RegularBodyLarge.getFont() + layoutIfNeeded() + } + + open override func reset() { + super.reset() + + textView.font = Styler.Font.RegularBodyLarge.getFont() + } + + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.set(with: model, delegateObject, additionalData) + + if let color = model.backgroundColor?.uiColor { + backgroundColor = color + } + + guard let model = model as? TextViewEntryFieldModel else { return } + + heightConstraint?.isActive = false + if let height = model.height { + heightConstraint?.constant = height + heightConstraint?.isActive = true + } + + textView.isEditable = model.editable + textView.textAlignment = model.textAlignment + textView.textColor = model.enabledTextColor.uiColor +// textView.hideBorders = model.hideBorders + text = model.text + textView.uiTextViewDelegate = delegateObject?.uiTextViewDelegate + + if let accessibilityText = model.accessibilityText { + accessibilityLabel = accessibilityText + } + + switch model.type { + case .secure, .password: + textView.isSecureTextEntry = true + case .number: + textView.keyboardType = .numberPad + case .email: + textView.keyboardType = .emailAddress + default: + break + } + + textView.font = model.fontStyle.getFont() + textView.setPlaceholderIfAvailable() + + if isEditable { + FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate) + let observingDelegate = delegateObject?.uiTextViewDelegate ?? self + inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate, + action: #selector(textView.dismissFieldInput)) + + if (model.selected ?? false) && !model.wasInitiallySelected { + model.wasInitiallySelected = true + DispatchQueue.main.async { + self.becomeFirstResponder() + } + } + } + + if !model.enabled { + isEnabled = false + } + } +} diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift new file mode 100644 index 00000000..e518fafc --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift @@ -0,0 +1,95 @@ +// +// TextViewEntryFieldModel.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 5/7/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + +class TextViewEntryFieldModel: TextEntryFieldModel { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public override class var identifier: String { + return "textView" + } + + public var accessibilityText: String? + public var fontStyle: Styler.Font = Styler.Font.RegularBodySmall + public var textAlignment: NSTextAlignment = .left + public var height: CGFloat? + public var placeholderTextColor: Color = Color(uiColor: .mvmCoolGray3) + public var placeholderFontStyle: Styler.Font = Styler.Font.RegularMicro + public var showsPlaceholder: Bool = false + public var hideBorders: Bool = false + public var editable: Bool = true + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case text + case accessibilityText + case fontStyle + case textAlignment + case height + case hideBorders + case placeholderFontStyle + case placeholderTextColor + case editable + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + try super.init(from: decoder) + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + + if let placeholderFontStyle = try typeContainer.decodeIfPresent(Styler.Font.self, forKey: .placeholderFontStyle) { + self.placeholderFontStyle = placeholderFontStyle + } + + if let placeholderTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .placeholderTextColor) { + self.placeholderTextColor = placeholderTextColor + } + + if let textAlignment = try typeContainer.decodeIfPresent(NSTextAlignment.self, forKey: .textAlignment) { + self.textAlignment = textAlignment + } + + if let hideBorders = try typeContainer.decodeIfPresent(Bool.self, forKey: .hideBorders) { + self.hideBorders = hideBorders + } + + if let editable = try typeContainer.decodeIfPresent(Bool.self, forKey: .editable) { + self.editable = editable + } + + if let fontStyle = try typeContainer.decodeIfPresent(Styler.Font.self, forKey: .fontStyle) { + self.fontStyle = fontStyle + } + + accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText) + height = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .height) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText) + try container.encodeIfPresent(height, forKey: .height) + try container.encode(fontStyle, forKey: .fontStyle) + try container.encode(hideBorders, forKey: .hideBorders) + try container.encode(text, forKey: .text) + try container.encode(placeholderFontStyle, forKey: .placeholderFontStyle) + try container.encode(placeholderTextColor, forKey: .placeholderTextColor) + try container.encode(textAlignment, forKey: .textAlignment) + try container.encode(editable, forKey: .editable) + } +} diff --git a/MVMCoreUI/BaseClasses/TextView.swift b/MVMCoreUI/BaseClasses/TextView.swift index 191806bb..0d381777 100644 --- a/MVMCoreUI/BaseClasses/TextView.swift +++ b/MVMCoreUI/BaseClasses/TextView.swift @@ -26,10 +26,10 @@ import UIKit /// Set to true to hide the blinking textField cursor. public var hideBlinkingCaret = false - public var textViewModel: TextViewModel? { - return model as? TextViewModel + public var textViewEntryFieldModel: TextViewEntryFieldModel? { + return model as? TextViewEntryFieldModel } - + /* //-------------------------------------------------- // MARK: - Drawing Properties //-------------------------------------------------- @@ -101,7 +101,7 @@ import UIKit } } } - + */ //-------------------------------------------------- // MARK: - Delegate //-------------------------------------------------- @@ -190,7 +190,7 @@ import UIKit smartDashesType = .no smartInsertDeleteType = .no inputAccessoryView = nil - font = textViewModel?.fontStyle.getFont() +// font = textViewModel?.fontStyle.getFont() isEditable = true isOpaque = false } @@ -202,7 +202,7 @@ import UIKit inputAccessoryView = nil initialConfiguration() } - + /* open override func layoutSubviews() { super.layoutSubviews() @@ -329,7 +329,7 @@ import UIKit bottomStrokeColor = .mvmCoolGray3 textColor = textViewModel?.disabledTextColor.uiColor } - + */ //-------------------------------------------------- // MARK: - Methods //-------------------------------------------------- @@ -424,67 +424,3 @@ import UIKit proprietorTextDelegate?.textViewDidEndEditing?(textView) } } - -// MARK:- MoleculeViewProtocol -extension TextView: MoleculeViewProtocol { - - open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { - self.model = model - self.delegateObject = delegateObject - - if let color = model.backgroundColor?.uiColor { - backgroundColor = color - } - - guard let model = model as? TextViewModel else { return } - - heightConstraint?.isActive = false - if let height = model.height { - heightConstraint = heightAnchor.constraint(equalToConstant: height) - heightConstraint?.isActive = true - } - - isEditable = model.editable - textAlignment = model.textAlignment - textColor = model.enabledTextColor.uiColor - hideBorders = model.hideBorders - text = model.text - uiTextViewDelegate = delegateObject?.uiTextViewDelegate - - if let accessibilityText = model.accessibilityText { - accessibilityLabel = accessibilityText - } - - switch model.type { - case .secure, .password: - isSecureTextEntry = true - case .number: - keyboardType = .numberPad - case .email: - keyboardType = .emailAddress - default: - break - } - - font = model.fontStyle.getFont() - setPlaceholderIfAvailable() - - if isEditable { - FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate) - let observingDelegate = delegateObject?.uiTextViewDelegate ?? self - inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate, - action: #selector(dismissFieldInput)) - - if (model.selected ?? false) && !model.wasInitiallySelected { - model.wasInitiallySelected = true - DispatchQueue.main.async { - self.becomeFirstResponder() - } - } - } - - if !model.enabled { - isEnabled = false - } - } -} diff --git a/MVMCoreUI/BaseClasses/TextViewModel.swift b/MVMCoreUI/BaseClasses/TextViewModel.swift index d9505275..858c4a6f 100644 --- a/MVMCoreUI/BaseClasses/TextViewModel.swift +++ b/MVMCoreUI/BaseClasses/TextViewModel.swift @@ -2,95 +2,8 @@ // TextViewModel.swift // MVMCoreUI // -// Created by Kevin Christiano on 4/2/20. +// Created by Kevin Christiano on 5/7/20. // Copyright © 2020 Verizon Wireless. All rights reserved. // import Foundation - - -open class TextViewModel: TextEntryFieldModel { - //-------------------------------------------------- - // MARK: - Properties - //-------------------------------------------------- - - public override class var identifier: String { - return "textView" - } - - public var accessibilityText: String? - public var fontStyle: Styler.Font = Styler.Font.RegularBodySmall - public var textAlignment: NSTextAlignment = .left - public var height: CGFloat? - public var placeholderTextColor: Color = Color(uiColor: .mvmCoolGray3) - public var placeholderFontStyle: Styler.Font = Styler.Font.RegularMicro - public var showsPlaceholder: Bool = false - public var hideBorders: Bool = false - public var editable: Bool = true - - //-------------------------------------------------- - // MARK: - Keys - //-------------------------------------------------- - - private enum CodingKeys: String, CodingKey { - case text - case accessibilityText - case fontStyle - case textAlignment - case height - case hideBorders - case placeholderFontStyle - case placeholderTextColor - case editable - } - - //-------------------------------------------------- - // MARK: - Codec - //-------------------------------------------------- - - required public init(from decoder: Decoder) throws { - try super.init(from: decoder) - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - - if let placeholderFontStyle = try typeContainer.decodeIfPresent(Styler.Font.self, forKey: .placeholderFontStyle) { - self.placeholderFontStyle = placeholderFontStyle - } - - if let placeholderTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .placeholderTextColor) { - self.placeholderTextColor = placeholderTextColor - } - - if let textAlignment = try typeContainer.decodeIfPresent(NSTextAlignment.self, forKey: .textAlignment) { - self.textAlignment = textAlignment - } - - if let hideBorders = try typeContainer.decodeIfPresent(Bool.self, forKey: .hideBorders) { - self.hideBorders = hideBorders - } - - if let editable = try typeContainer.decodeIfPresent(Bool.self, forKey: .editable) { - self.editable = editable - } - - if let fontStyle = try typeContainer.decodeIfPresent(Styler.Font.self, forKey: .fontStyle) { - self.fontStyle = fontStyle - } - - accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText) - height = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .height) - } - - public override func encode(to encoder: Encoder) throws { - try super.encode(to: encoder) - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText) - try container.encodeIfPresent(height, forKey: .height) - try container.encode(fontStyle, forKey: .fontStyle) - try container.encode(hideBorders, forKey: .hideBorders) - try container.encode(text, forKey: .text) - try container.encode(placeholderFontStyle, forKey: .placeholderFontStyle) - try container.encode(placeholderTextColor, forKey: .placeholderTextColor) - try container.encode(textAlignment, forKey: .textAlignment) - try container.encode(editable, forKey: .editable) - } -} From efe3f95746001e2aad38237914cc47fa74ca29da Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 7 May 2020 14:41:50 -0400 Subject: [PATCH 19/67] further textviewfield development --- .../Atoms/TextFields/TextViewEntryField.swift | 157 ++++++++++++++++-- .../TextFields/TextViewEntryFieldModel.swift | 20 +-- MVMCoreUI/Atomic/MoleculeObjectMapping.swift | 2 +- MVMCoreUI/BaseClasses/TextView.swift | 27 ++- MVMCoreUI/BaseClasses/TextViewModel.swift | 85 +++++++++- 5 files changed, 248 insertions(+), 43 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index b880ed5e..7b1a30bc 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -9,7 +9,7 @@ import UIKit -class TextViewEntryField: EntryField { +class TextViewEntryField: EntryField, UITextViewDelegate { //-------------------------------------------------- // MARK: - Outlets //-------------------------------------------------- @@ -26,12 +26,137 @@ class TextViewEntryField: EntryField { return textView }() + //-------------------------------------------------- + // MARK: - Computed Properties + //-------------------------------------------------- + + /// Validate on each entry in the textField. Default: true + public var validateEachCharacter: Bool = true + + + public var textViewEntryFieldModel: TextViewEntryFieldModel? { + return model as? TextViewEntryFieldModel + } + + public override var isEnabled: Bool { + get { return super.isEnabled } + set (enabled) { + super.isEnabled = enabled + + DispatchQueue.main.async { [weak self] in + guard let self = self else { return } + + self.textView.isEnabled = enabled + self.textView.textColor = enabled ? self.textEntryFieldModel?.enabledTextColor.uiColor : self.textEntryFieldModel?.disabledTextColor.uiColor + } + } + } + + public override var showError: Bool { + get { return super.showError } + set (error) { + + if error { + textView.accessibilityValue = String(format: MVMCoreUIUtility.hardcodedString(withKey: "textView_error_message") ?? "", textView.text ?? "", entryFieldModel?.errorMessage ?? "") + } else { + textView.accessibilityValue = nil + } + + if textView.isSecureTextEntry { +// showErrorView(error) + } + + super.showError = error + } + } + + /// The text of this textView. + open override var text: String? { + get { return textView.text } + set { + textView.text = newValue + textViewEntryFieldModel?.text = newValue + } + } + + /// Placeholder access for the textView. + public var placeholder: String? { + get { +// return textView.placeholder + return textViewEntryFieldModel?.placeholder + } + set { +// textView.placeholder = newValue + textViewEntryFieldModel?.placeholder = newValue + } + } + + + /// Executes on UITextField.textDidBeginEditingNotification + @objc func startEditing() { + isSelected = true + textView.becomeFirstResponder() + } + + /// Executes on UITextField.textDidChangeNotification (each character entry) + @objc func valueChanged() { + guard validateEachCharacter else { return } + isSelected = true + validateTextField() + } + + /// Validates the text of the entry field. + @objc public func validateTextField() { + text = textField.text + _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) + } + + /// Executes on UITextField.textDidEndEditingNotification + @objc func endInputing() { + resignFirstResponder() + if isValid { + showError = false + entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor + } + } + + @objc public func dismissFieldInput(_ sender: Any?) { + resignFirstResponder() + } + //-------------------------------------------------- // MARK: - Constraint //-------------------------------------------------- public var heightConstraint: NSLayoutConstraint? - + + //-------------------------------------------------- + // MARK: - Delegate Properties + //-------------------------------------------------- + + /// The delegate and block for validation. Validates if the text that the user has entered. + public weak var observingTextFieldDelegate: ObservingTextFieldDelegate? { + didSet { + if observingTextFieldDelegate != nil && !observingForChange { + observingForChange = true + NotificationCenter.default.addObserver(self, selector: #selector(valueChanged), name: UITextView.textDidChangeNotification, object: textView) + NotificationCenter.default.addObserver(self, selector: #selector(endInputing), name: UITextView.textDidEndEditingNotification, object: textView) + NotificationCenter.default.addObserver(self, selector: #selector(startEditing), name: UITextView.textDidBeginEditingNotification, object: textView) + + } else if observingTextFieldDelegate == nil && observingForChange { + observingForChange = false + NotificationCenter.default.removeObserver(self, name: UITextView.textDidChangeNotification, object: textView) + NotificationCenter.default.removeObserver(self, name: UITextView.textDidEndEditingNotification, object: textView) + NotificationCenter.default.removeObserver(self, name: UITextView.textDidBeginEditingNotification, object: textView) + } + } + } + + /// If you're using a ViewController, you must set this to it + public weak var uiTextViewDelegate: UITextViewDelegate? { + get { return textView.delegate } + set { textView.delegate = newValue } + } //-------------------------------------------------- // MARK: - Lifecycle @@ -50,13 +175,13 @@ class TextViewEntryField: EntryField { ]) heightConstraint = textView.heightAnchor.constraint(equalToConstant: 0) + heightConstraint?.isActive = true - -// textView.addTarget(self, action: #selector(startEditing), for: .editingDidBegin) -// textView.addTarget(self, action: #selector(dismissFieldInput), for: .editingDidEnd) -// -// let tap = UITapGestureRecognizer(target: self, action: #selector(startEditing)) -// entryFieldContainer.addGestureRecognizer(tap) + // textView.addTarget(self, action: #selector(startEditing), for: .editingDidBegin) + // textView.addTarget(self, action: #selector(dismissFieldInput), for: .editingDidEnd) + // + // let tap = UITapGestureRecognizer(target: self, action: #selector(startEditing)) + // entryFieldContainer.addGestureRecognizer(tap) accessibilityElements = [titleLabel, textView, feedbackLabel] } @@ -72,6 +197,7 @@ class TextViewEntryField: EntryField { super.reset() textView.font = Styler.Font.RegularBodyLarge.getFont() + heightConstraint?.constant = 0 } @@ -84,18 +210,13 @@ class TextViewEntryField: EntryField { guard let model = model as? TextViewEntryFieldModel else { return } - heightConstraint?.isActive = false - if let height = model.height { - heightConstraint?.constant = height - heightConstraint?.isActive = true - } + heightConstraint?.constant = model.height ?? 0 - textView.isEditable = model.editable +// textView.isEditable = model.editable textView.textAlignment = model.textAlignment textView.textColor = model.enabledTextColor.uiColor -// textView.hideBorders = model.hideBorders text = model.text - textView.uiTextViewDelegate = delegateObject?.uiTextViewDelegate + uiTextViewDelegate = delegateObject?.uiTextViewDelegate if let accessibilityText = model.accessibilityText { accessibilityLabel = accessibilityText @@ -115,10 +236,10 @@ class TextViewEntryField: EntryField { textView.font = model.fontStyle.getFont() textView.setPlaceholderIfAvailable() - if isEditable { + if textView.isEditable { FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate) let observingDelegate = delegateObject?.uiTextViewDelegate ?? self - inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate, + textView.inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate, action: #selector(textView.dismissFieldInput)) if (model.selected ?? false) && !model.wasInitiallySelected { diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift index e518fafc..bd0188f6 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift @@ -8,6 +8,7 @@ import UIKit + class TextViewEntryFieldModel: TextEntryFieldModel { //-------------------------------------------------- // MARK: - Properties @@ -19,14 +20,11 @@ class TextViewEntryFieldModel: TextEntryFieldModel { public var accessibilityText: String? public var fontStyle: Styler.Font = Styler.Font.RegularBodySmall - public var textAlignment: NSTextAlignment = .left public var height: CGFloat? + public var textAlignment: NSTextAlignment = .left public var placeholderTextColor: Color = Color(uiColor: .mvmCoolGray3) public var placeholderFontStyle: Styler.Font = Styler.Font.RegularMicro - public var showsPlaceholder: Bool = false - public var hideBorders: Bool = false - public var editable: Bool = true - + //-------------------------------------------------- // MARK: - Keys //-------------------------------------------------- @@ -37,7 +35,6 @@ class TextViewEntryFieldModel: TextEntryFieldModel { case fontStyle case textAlignment case height - case hideBorders case placeholderFontStyle case placeholderTextColor case editable @@ -63,14 +60,6 @@ class TextViewEntryFieldModel: TextEntryFieldModel { self.textAlignment = textAlignment } - if let hideBorders = try typeContainer.decodeIfPresent(Bool.self, forKey: .hideBorders) { - self.hideBorders = hideBorders - } - - if let editable = try typeContainer.decodeIfPresent(Bool.self, forKey: .editable) { - self.editable = editable - } - if let fontStyle = try typeContainer.decodeIfPresent(Styler.Font.self, forKey: .fontStyle) { self.fontStyle = fontStyle } @@ -85,11 +74,10 @@ class TextViewEntryFieldModel: TextEntryFieldModel { try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText) try container.encodeIfPresent(height, forKey: .height) try container.encode(fontStyle, forKey: .fontStyle) - try container.encode(hideBorders, forKey: .hideBorders) try container.encode(text, forKey: .text) try container.encode(placeholderFontStyle, forKey: .placeholderFontStyle) try container.encode(placeholderTextColor, forKey: .placeholderTextColor) try container.encode(textAlignment, forKey: .textAlignment) - try container.encode(editable, forKey: .editable) + } } diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index a9e86d50..af85da8e 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -52,7 +52,7 @@ import Foundation try? ModelRegistry.register(LabelAttributeActionModel.self) // TextView - MoleculeObjectMapping.shared()?.register(viewClass: TextView.self, viewModelClass: TextViewModel.self) + MoleculeObjectMapping.shared()?.register(viewClass: TextViewEntryField.self, viewModelClass: TextViewEntryFieldModel.self) // Buttons MoleculeObjectMapping.shared()?.register(viewClass: PillButton.self, viewModelClass: ButtonModel.self) diff --git a/MVMCoreUI/BaseClasses/TextView.swift b/MVMCoreUI/BaseClasses/TextView.swift index 0d381777..33f51bac 100644 --- a/MVMCoreUI/BaseClasses/TextView.swift +++ b/MVMCoreUI/BaseClasses/TextView.swift @@ -9,7 +9,7 @@ import UIKit -@objc open class TextView: UITextView, UITextViewDelegate, MVMCoreViewProtocol { +@objc open class TextView: UITextView, UITextViewDelegate, MVMCoreViewProtocol, MoleculeViewProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -26,9 +26,21 @@ import UIKit /// Set to true to hide the blinking textField cursor. public var hideBlinkingCaret = false - public var textViewEntryFieldModel: TextViewEntryFieldModel? { - return model as? TextViewEntryFieldModel + public var textViewModel: TextViewModel? { + return model as? TextViewModel } + + open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + + if let color = model.backgroundColor?.uiColor { + backgroundColor = color + } + } + + public var isEnabled: Bool = true { + didSet { } + } + /* //-------------------------------------------------- // MARK: - Drawing Properties @@ -202,6 +214,7 @@ import UIKit inputAccessoryView = nil initialConfiguration() } + /* open override func layoutSubviews() { super.layoutSubviews() @@ -368,8 +381,8 @@ import UIKit isShowingPlaceholder = false text = "" - font = textViewModel?.fontStyle.getFont() - textColor = textViewModel?.enabledTextColor.uiColor + font = Styler.Font.RegularBodySmall.getFont()//textViewModel?.fontStyle.getFont() + textColor = .black//textViewModel?.enabledTextColor.uiColor } public func setPlaceholderContentTraits() { @@ -397,7 +410,7 @@ import UIKit @objc public func textViewDidBeginEditing(_ textView: UITextView) { setTextAppearance() - isSelected = true +// isSelected = true proprietorTextDelegate?.textViewDidBeginEditing?(textView) } @@ -420,7 +433,7 @@ import UIKit @objc public func textViewDidEndEditing(_ textView: UITextView) { setPlaceholderIfAvailable() - isSelected = false +// isSelected = false proprietorTextDelegate?.textViewDidEndEditing?(textView) } } diff --git a/MVMCoreUI/BaseClasses/TextViewModel.swift b/MVMCoreUI/BaseClasses/TextViewModel.swift index 858c4a6f..6d68de1c 100644 --- a/MVMCoreUI/BaseClasses/TextViewModel.swift +++ b/MVMCoreUI/BaseClasses/TextViewModel.swift @@ -6,4 +6,87 @@ // Copyright © 2020 Verizon Wireless. All rights reserved. // -import Foundation +import UIKit + + +open class TextViewModel: MoleculeModelProtocol {//, FormFieldProtocol, FormRuleWatcherFieldProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public class var identifier: String { + return "" + } + + public var baseValue: AnyHashable? + public var backgroundColor: Color? +// public var fieldKey: String? + public var fontStyle: Styler.Font = Styler.Font.RegularBodySmall + public var text: String? + public var placeholder: String? + public var textAlignment: NSTextAlignment = .left +// public var groupName: String + public var editable: Bool = true + public var showsPlaceholder: Bool = false + public var placeholderTextColor: Color = Color(uiColor: .mvmCoolGray3) + public var placeholderFontStyle: Styler.Font = Styler.Font.RegularMicro + + public var isValid: Bool? { + didSet { updateUI?() } + } + + /// Temporary binding mechanism for the view to update on enable changes. + public var updateUI: ActionBlock? + + //-------------------------------------------------- + // MARK: - Validation Methods + //-------------------------------------------------- + + public func formFieldValue() -> AnyHashable? { + return text + } + + public func setValidity(_ valid: Bool, rule: RulesProtocol) { + self.isValid = valid + } + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case moleculeName + case backgroundColor + case editable +// case groupName + case textAlignment + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + + if let editable = try typeContainer.decodeIfPresent(Bool.self, forKey: .editable) { + self.editable = editable + } + +// if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) { +// self.groupName = groupName +// } + + if let textAlignment = try typeContainer.decodeIfPresent(NSTextAlignment.self, forKey: .textAlignment) { + self.textAlignment = textAlignment + } + + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) +// try container.encode(groupName, forKey: .groupName) + try container.encode(editable, forKey: .editable) + try container.encode(textAlignment, forKey: .textAlignment) + } +} From c61f6698065078038196c270b702e0c6fc398544 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 7 May 2020 17:11:43 -0400 Subject: [PATCH 20/67] text registered for init appearance. more acessiility to caret --- .../ListLeftVariableRadioButtonAndPaymentMethod.swift | 1 + .../List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift | 1 + MVMCoreUI/BaseClasses/TableViewCell.swift | 2 ++ 3 files changed, 4 insertions(+) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift index b0ac0e6a..688f457c 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift @@ -76,6 +76,7 @@ import UIKit radioButton.set(with: model.radioButton, delegateObject, additionalData) leftImage.set(with: model.image, delegateObject, additionalData) eyebrowHeadlineBodyLink.set(with: model.eyebrowHeadlineBodyLink, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift index 5e9dd53d..d89604f9 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyText.swift @@ -66,6 +66,7 @@ open class ListLeftVariableRadioButtonBodyText: TableViewCell { radioButton.set(with: model.radioButton, delegateObject, additionalData) headlineBody.set(with: model.headlineBody, delegateObject, additionalData) + updateAccessibilityLabel() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { diff --git a/MVMCoreUI/BaseClasses/TableViewCell.swift b/MVMCoreUI/BaseClasses/TableViewCell.swift index b549b6d0..f07b1ee2 100644 --- a/MVMCoreUI/BaseClasses/TableViewCell.swift +++ b/MVMCoreUI/BaseClasses/TableViewCell.swift @@ -205,6 +205,8 @@ import UIKit let caret = CaretView(lineWidth: 1) caret.translatesAutoresizingMaskIntoConstraints = true caret.isAccessibilityElement = true + caret.accessibilityTraits = .button + caret.accessibilityLabel = "Caret," caret.accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "AccTabHint") caret.size = .small(.vertical) if let size = caret.size?.dimensions() { From 1ea6f9a3b71e1f72d2fa85825d9ed1f157a0d84a Mon Sep 17 00:00:00 2001 From: "Suresh, Kamlesh" Date: Thu, 7 May 2020 20:34:38 -0400 Subject: [PATCH 21/67] fix --- .../Rules/Rules/RuleEqualsModel.swift | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift index 9c5c3837..fa73ed51 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift @@ -31,20 +31,22 @@ public class RuleEqualsModel: RulesProtocol { var valid = true var compareValue: AnyHashable? - for formKey in fields { - guard let formField = fieldMolecules[formKey] else { continue } + for formKey in fields { + guard let formField = fieldMolecules[formKey] else { continue } - if compareValue == nil { - compareValue = formField.formFieldValue() - continue - } + if compareValue == nil { + compareValue = formField.formFieldValue() + continue + } - if compareValue != formField.formFieldValue() { - valid = false - (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) - break - } - } + if compareValue != formField.formFieldValue() { + valid = false + (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) + break + } else { + (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) + } + } return valid } From 7f6bcfc712a18154f9825c559b47a455f2dfc5d4 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 8 May 2020 11:15:50 -0400 Subject: [PATCH 22/67] generall stable --- MVMCoreUI.xcodeproj/project.pbxproj | 4 - .../Atomic/Atoms/TextFields/EntryField.swift | 14 +- .../TextFields/TextEntryFieldModel.swift | 8 + .../Atoms/TextFields/TextViewEntryField.swift | 207 ++++++++------- .../TextFields/TextViewEntryFieldModel.swift | 10 +- MVMCoreUI/Atomic/Atoms/Views/Line.swift | 9 +- MVMCoreUI/BaseClasses/TextView.swift | 238 ++---------------- MVMCoreUI/BaseClasses/TextViewModel.swift | 92 ------- 8 files changed, 150 insertions(+), 432 deletions(-) delete mode 100644 MVMCoreUI/BaseClasses/TextViewModel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 89c4ba1d..6e6030d2 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -70,7 +70,6 @@ 0A21DB94235E24ED00C160A2 /* DigitEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A21DB93235E24ED00C160A2 /* DigitEntryField.swift */; }; 0A25209624645AFD000FA9F6 /* TextViewEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A25209524645AFD000FA9F6 /* TextViewEntryField.swift */; }; 0A25209824645B76000FA9F6 /* TextViewEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A25209724645B76000FA9F6 /* TextViewEntryFieldModel.swift */; }; - 0A2520A924646230000FA9F6 /* TextViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A2520A824646230000FA9F6 /* TextViewModel.swift */; }; 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */; }; 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */; }; @@ -479,7 +478,6 @@ 0A21DB93235E24ED00C160A2 /* DigitEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitEntryField.swift; sourceTree = ""; }; 0A25209524645AFD000FA9F6 /* TextViewEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewEntryField.swift; sourceTree = ""; }; 0A25209724645B76000FA9F6 /* TextViewEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewEntryFieldModel.swift; sourceTree = ""; }; - 0A2520A824646230000FA9F6 /* TextViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewModel.swift; sourceTree = ""; }; 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.swift"; sourceTree = ""; }; 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = ""; }; 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesProtocol.swift; sourceTree = ""; }; @@ -1765,7 +1763,6 @@ D264FAA92440F97600D98315 /* CollectionView.swift */, 0A5D59C323AD488600EFD9E9 /* Protocols */, 0A7918F423F5E7EA00772FF4 /* ImageView.swift */, - 0A2520A824646230000FA9F6 /* TextViewModel.swift */, ); path = BaseClasses; sourceTree = ""; @@ -2028,7 +2025,6 @@ 014AA73123C5059B006F3E93 /* ListPageTemplateModel.swift in Sources */, D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */, D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */, - 0A2520A924646230000FA9F6 /* TextViewModel.swift in Sources */, 94C2D9A723872DA90006CF46 /* LabelAttributeColorModel.swift in Sources */, 943820842432382400B43AF3 /* WebView.swift in Sources */, 0103B84E23D7E33A009C315C /* HeadlineBodyToggleModel.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift index 1fe0b1af..006988f7 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift @@ -69,6 +69,11 @@ import UIKit get { return entryFieldContainer.showError } set (error) { self.feedback = error ? entryFieldModel?.errorMessage : entryFieldModel?.feedback + if error { + feedbackLabel.textColor = entryFieldModel?.errorTextColor?.uiColor ?? .mvmBlack + } else { + feedbackLabel.textColor = .mvmBlack + } self.entryFieldContainer.showError = error self.entryFieldModel?.showError = error } @@ -215,11 +220,10 @@ import UIKit entryFieldContainer.refreshUI() } - /** - Method to override. - Intended to add the interactive content (i.e. textField) to the entryFieldContainer. - */ - @objc open func setupFieldContainerContent(_ container: UIView) { } + /// Intended to add the interactive content (i.e. textField) to the entryFieldContainer. + @objc open func setupFieldContainerContent(_ container: UIView) { + // To Be Overriden + } @objc open override func updateView(_ size: CGFloat) { super.updateView(size) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryFieldModel.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryFieldModel.swift index d47b9802..db5f3724 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryFieldModel.swift @@ -31,6 +31,7 @@ public var placeholder: String? public var enabledTextColor: Color = Color(uiColor: .mvmBlack) public var disabledTextColor: Color = Color(uiColor: .mvmCoolGray3) + public var textAlignment: NSTextAlignment = .left public var type: EntryType? //-------------------------------------------------- @@ -39,6 +40,7 @@ private enum CodingKeys: String, CodingKey { case placeholder + case textAlignment case enabledTextColor case disabledTextColor case type @@ -51,6 +53,7 @@ required public init(from decoder: Decoder) throws { try super.init(from: decoder) let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + placeholder = try typeContainer.decodeIfPresent(String.self, forKey: .placeholder) type = try typeContainer.decodeIfPresent(EntryType.self, forKey: .type) @@ -61,12 +64,17 @@ if let disabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledTextColor) { self.disabledTextColor = disabledTextColor } + + if let textAlignment = try typeContainer.decodeIfPresent(NSTextAlignment.self, forKey: .textAlignment) { + self.textAlignment = textAlignment + } } public override func encode(to encoder: Encoder) throws { try super.encode(to: encoder) var container = encoder.container(keyedBy: CodingKeys.self) try container.encodeIfPresent(placeholder, forKey: .placeholder) + try container.encodeIfPresent(textAlignment, forKey: .textAlignment) try container.encode(enabledTextColor, forKey: .enabledTextColor) try container.encode(disabledTextColor, forKey: .disabledTextColor) try container.encodeIfPresent(type, forKey: .type) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index 7b1a30bc..9b35c39f 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -9,7 +9,7 @@ import UIKit -class TextViewEntryField: EntryField, UITextViewDelegate { +class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDelegate { //-------------------------------------------------- // MARK: - Outlets //-------------------------------------------------- @@ -27,101 +27,63 @@ class TextViewEntryField: EntryField, UITextViewDelegate { }() //-------------------------------------------------- - // MARK: - Computed Properties - //-------------------------------------------------- - - /// Validate on each entry in the textField. Default: true - public var validateEachCharacter: Bool = true + // MARK: - Properties + //-------------------------------------------------- + /// Validate on each entry in the textField. Default: true + public var validateEachCharacter: Bool = true + + private var observingForChange: Bool = false + + //-------------------------------------------------- + // MARK: - Computed Properties + //-------------------------------------------------- public var textViewEntryFieldModel: TextViewEntryFieldModel? { return model as? TextViewEntryFieldModel } - public override var isEnabled: Bool { - get { return super.isEnabled } - set (enabled) { - super.isEnabled = enabled - - DispatchQueue.main.async { [weak self] in - guard let self = self else { return } - - self.textView.isEnabled = enabled - self.textView.textColor = enabled ? self.textEntryFieldModel?.enabledTextColor.uiColor : self.textEntryFieldModel?.disabledTextColor.uiColor - } - } - } - - public override var showError: Bool { - get { return super.showError } - set (error) { - - if error { - textView.accessibilityValue = String(format: MVMCoreUIUtility.hardcodedString(withKey: "textView_error_message") ?? "", textView.text ?? "", entryFieldModel?.errorMessage ?? "") - } else { - textView.accessibilityValue = nil - } - - if textView.isSecureTextEntry { -// showErrorView(error) - } - - super.showError = error - } - } - - /// The text of this textView. - open override var text: String? { - get { return textView.text } - set { - textView.text = newValue - textViewEntryFieldModel?.text = newValue - } - } - - /// Placeholder access for the textView. - public var placeholder: String? { - get { -// return textView.placeholder - return textViewEntryFieldModel?.placeholder - } - set { -// textView.placeholder = newValue - textViewEntryFieldModel?.placeholder = newValue - } - } - - - /// Executes on UITextField.textDidBeginEditingNotification - @objc func startEditing() { - isSelected = true - textView.becomeFirstResponder() - } - - /// Executes on UITextField.textDidChangeNotification (each character entry) - @objc func valueChanged() { - guard validateEachCharacter else { return } - isSelected = true - validateTextField() - } - - /// Validates the text of the entry field. - @objc public func validateTextField() { - text = textField.text - _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) - } - - /// Executes on UITextField.textDidEndEditingNotification - @objc func endInputing() { - resignFirstResponder() - if isValid { - showError = false - entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor + public override var isEnabled: Bool { + get { return super.isEnabled } + set (enabled) { + super.isEnabled = enabled + + DispatchQueue.main.async { [weak self] in + guard let self = self else { return } + + self.textView.isEnabled = enabled + self.textView.textColor = enabled ? self.textViewEntryFieldModel?.enabledTextColor.uiColor : self.textViewEntryFieldModel?.disabledTextColor.uiColor + } } } - @objc public func dismissFieldInput(_ sender: Any?) { - resignFirstResponder() + public override var showError: Bool { + get { return super.showError } + set (error) { + + if error { + textView.accessibilityValue = String(format: MVMCoreUIUtility.hardcodedString(withKey: "textView_error_message") ?? "", textView.text ?? "", entryFieldModel?.errorMessage ?? "") + } else { + textView.accessibilityValue = nil + } + + super.showError = error + } + } + + /// The text of this textView. + open override var text: String? { + get { return textView.text } + set { + textView.text = newValue + textViewEntryFieldModel?.text = newValue + } + } + + /// Placeholder access for the textView. + public var placeholder: String? { + get { return textViewEntryFieldModel?.placeholder } + set { textViewEntryFieldModel?.placeholder = newValue } } //-------------------------------------------------- @@ -158,6 +120,17 @@ class TextViewEntryField: EntryField, UITextViewDelegate { set { textView.delegate = newValue } } + @objc public func setBothTextDelegates(to delegate: (UITextViewDelegate & ObservingTextFieldDelegate)?) { + observingTextFieldDelegate = delegate + uiTextViewDelegate = delegate + } + + open func setupTextViewToolbar() { + let observingDelegate = observingTextFieldDelegate ?? self + textView.inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate, + action: #selector(observingDelegate.dismissFieldInput)) + } + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -200,6 +173,45 @@ class TextViewEntryField: EntryField, UITextViewDelegate { heightConstraint?.constant = 0 } + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + + /// Executes on UITextField.textDidBeginEditingNotification + @objc func startEditing() { + isSelected = true + textView.becomeFirstResponder() + } + + /// Executes on UITextField.textDidChangeNotification (each character entry) + @objc func valueChanged() { + guard validateEachCharacter else { return } + isSelected = true + validateTextField() + } + + /// Validates the text of the entry field. + @objc public func validateTextField() { + text = textView.text + _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) + } + + /// Executes on UITextField.textDidEndEditingNotification + @objc func endInputing() { + resignFirstResponder() + if isValid { + showError = false + entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor + } + } + + @objc public func dismissFieldInput(_ sender: Any?) { + resignFirstResponder() + } + + //-------------------------------------------------- + // MARK: - MoleculeViewProtocol + //-------------------------------------------------- open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) @@ -211,10 +223,6 @@ class TextViewEntryField: EntryField, UITextViewDelegate { guard let model = model as? TextViewEntryFieldModel else { return } heightConstraint?.constant = model.height ?? 0 - -// textView.isEditable = model.editable - textView.textAlignment = model.textAlignment - textView.textColor = model.enabledTextColor.uiColor text = model.text uiTextViewDelegate = delegateObject?.uiTextViewDelegate @@ -222,25 +230,30 @@ class TextViewEntryField: EntryField, UITextViewDelegate { accessibilityLabel = accessibilityText } + textView.isEditable = model.editable + textView.textAlignment = model.textAlignment + textView.textColor = model.enabled ? model.enabledTextColor.uiColor : model.disabledTextColor.uiColor + textView.font = model.fontStyle.getFont() + textView.setPlaceholderIfAvailable() + switch model.type { case .secure, .password: textView.isSecureTextEntry = true + case .number: textView.keyboardType = .numberPad + case .email: textView.keyboardType = .emailAddress - default: - break + + default: break } - textView.font = model.fontStyle.getFont() - textView.setPlaceholderIfAvailable() - if textView.isEditable { FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate) let observingDelegate = delegateObject?.uiTextViewDelegate ?? self textView.inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate, - action: #selector(textView.dismissFieldInput)) + action: #selector(textView.dismissFieldInput)) if (model.selected ?? false) && !model.wasInitiallySelected { model.wasInitiallySelected = true diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift index bd0188f6..78638ddb 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift @@ -21,9 +21,10 @@ class TextViewEntryFieldModel: TextEntryFieldModel { public var accessibilityText: String? public var fontStyle: Styler.Font = Styler.Font.RegularBodySmall public var height: CGFloat? - public var textAlignment: NSTextAlignment = .left public var placeholderTextColor: Color = Color(uiColor: .mvmCoolGray3) public var placeholderFontStyle: Styler.Font = Styler.Font.RegularMicro + public var editable: Bool = true + public var showsPlaceholder: Bool = false //-------------------------------------------------- // MARK: - Keys @@ -33,7 +34,6 @@ class TextViewEntryFieldModel: TextEntryFieldModel { case text case accessibilityText case fontStyle - case textAlignment case height case placeholderFontStyle case placeholderTextColor @@ -56,10 +56,6 @@ class TextViewEntryFieldModel: TextEntryFieldModel { self.placeholderTextColor = placeholderTextColor } - if let textAlignment = try typeContainer.decodeIfPresent(NSTextAlignment.self, forKey: .textAlignment) { - self.textAlignment = textAlignment - } - if let fontStyle = try typeContainer.decodeIfPresent(Styler.Font.self, forKey: .fontStyle) { self.fontStyle = fontStyle } @@ -77,7 +73,5 @@ class TextViewEntryFieldModel: TextEntryFieldModel { try container.encode(text, forKey: .text) try container.encode(placeholderFontStyle, forKey: .placeholderFontStyle) try container.encode(placeholderTextColor, forKey: .placeholderTextColor) - try container.encode(textAlignment, forKey: .textAlignment) - } } diff --git a/MVMCoreUI/Atomic/Atoms/Views/Line.swift b/MVMCoreUI/Atomic/Atoms/Views/Line.swift index 62550503..42043c8f 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Line.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Line.swift @@ -32,16 +32,16 @@ import UIKit switch style { case .standard: updateLineConstraints(constant: 1) - backgroundColor = lineModel?.backgroundColor?.uiColor ?? .mfSilver() + backgroundColor = lineModel?.backgroundColor?.uiColor ?? .mvmCoolGray3 case .thin: updateLineConstraints(constant: 1) - backgroundColor = lineModel?.backgroundColor?.uiColor ?? .black + backgroundColor = lineModel?.backgroundColor?.uiColor ?? .mvmBlack case .medium: updateLineConstraints(constant: 2) - backgroundColor = lineModel?.backgroundColor?.uiColor ?? .black + backgroundColor = lineModel?.backgroundColor?.uiColor ?? .mvmBlack case .heavy: updateLineConstraints(constant: 4) - backgroundColor = lineModel?.backgroundColor?.uiColor ?? .black + backgroundColor = lineModel?.backgroundColor?.uiColor ?? .mvmBlack case .none: updateLineConstraints(constant: 0) } @@ -97,6 +97,7 @@ import UIKit } extension Line: MVMCoreUIViewConstrainingProtocol { + open func needsToBeConstrained() -> Bool { return true } diff --git a/MVMCoreUI/BaseClasses/TextView.swift b/MVMCoreUI/BaseClasses/TextView.swift index 33f51bac..5d8abbf1 100644 --- a/MVMCoreUI/BaseClasses/TextView.swift +++ b/MVMCoreUI/BaseClasses/TextView.swift @@ -19,101 +19,22 @@ import UIKit private var initialSetupPerformed = false /// If true then text textView is currently displaying the stored placeholder text as there is not content to display. - public var isShowingPlaceholder: Bool = false { - didSet { textViewModel?.showsPlaceholder = isShowingPlaceholder } - } + public var isShowingPlaceholder: Bool = false /// Set to true to hide the blinking textField cursor. public var hideBlinkingCaret = false - public var textViewModel: TextViewModel? { - return model as? TextViewModel - } + public var placeholder = "" - open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { - - if let color = model.backgroundColor?.uiColor { - backgroundColor = color - } - } + public var fontStyle: Styler.Font = Styler.Font.RegularBodySmall + public var placeholderFontStyle: Styler.Font = Styler.Font.RegularMicro public var isEnabled: Bool = true { - didSet { } - } - - /* - //-------------------------------------------------- - // MARK: - Drawing Properties - //-------------------------------------------------- - - private(set) var fieldState: FieldState = .original { - didSet (oldState) { - // Will not update if new state is the same as old. - if fieldState != oldState { - DispatchQueue.main.async { [weak self] in - guard let self = self else { return } - - self.fieldState.setStateUI(for: self) - } - } + didSet { + isUserInteractionEnabled = isEnabled } } - /// Determines if the top, left, and right borders should be drawn. - private var hideBorders = false - - public var borderStrokeColor: UIColor = .mvmCoolGray3 - public var bottomStrokeColor: UIColor = .mvmBlack - private var borderPath: UIBezierPath = UIBezierPath() - private var bottomPath: UIBezierPath = UIBezierPath() - - //-------------------------------------------------- - // MARK: - Property Observers - //-------------------------------------------------- - - private var _isEnabled: Bool = true - private var _showError: Bool = false - private var _isSelected: Bool = false - - public var isEnabled: Bool { - get { return _isEnabled } - set (enabled) { - - _isEnabled = enabled - _isSelected = false - _showError = false - - fieldState = enabled ? .original : .disabled - } - } - - public var showError: Bool { - get { return _showError } - set (error) { - - _showError = error - _isEnabled = true - _isSelected = false - - fieldState = error ? .error : .original - } - } - - public var isSelected: Bool { - get { return _isSelected } - set (selected) { - - _isSelected = selected - _isEnabled = true - - if _showError { - fieldState = selected ? .selectedError : .error - } else { - fieldState = selected ? .selected : .original - } - } - } - */ //-------------------------------------------------- // MARK: - Delegate //-------------------------------------------------- @@ -202,7 +123,9 @@ import UIKit smartDashesType = .no smartInsertDeleteType = .no inputAccessoryView = nil -// font = textViewModel?.fontStyle.getFont() + isAccessibilityElement = true + accessibilityTraits = .staticText + font = Styler.Font.RegularBodyLarge.getFont() isEditable = true isOpaque = false } @@ -210,139 +133,13 @@ import UIKit open func reset() { text = "" + textAlignment = .left + font = Styler.Font.RegularBodyLarge.getFont() inputAccessoryView?.removeFromSuperview() inputAccessoryView = nil initialConfiguration() } - /* - open override func layoutSubviews() { - super.layoutSubviews() - - setNeedsDisplay() - } - - //-------------------------------------------------- - // MARK: - Draw - //-------------------------------------------------- - - /// This handles the top, left, and right border lines. - open override func draw(_ rect: CGRect) { - super.draw(rect) - - borderPath.removeAllPoints() - bottomPath.removeAllPoints() - - if !hideBorders { - // Brings the other half of the line inside the view to prevent line cropping. - let origin = bounds.origin - let size = frame.size - let insetLean: CGFloat = 0.5 - borderPath.lineWidth = 1 - - // Drawing begins and ends from the bottom left. - borderPath.move(to: CGPoint(x: origin.x + insetLean, y: origin.y + size.height)) - borderPath.addLine(to: CGPoint(x: origin.x + insetLean, y: origin.y + insetLean)) - borderPath.addLine(to: CGPoint(x: origin.x + size.width - insetLean, y: origin.y + insetLean)) - borderPath.addLine(to: CGPoint(x: origin.x + size.width - insetLean, y: origin.y + size.height)) - - borderStrokeColor.setStroke() - borderPath.stroke() - - let lineWidth: CGFloat = showError || isSelected ? 4 : 1 - bottomPath.lineWidth = lineWidth - bottomPath.move(to: CGPoint(x: origin.x + size.width, y: origin.y + size.height - (lineWidth / 2))) - bottomPath.addLine(to: CGPoint(x: origin.x, y: origin.y + size.height - (lineWidth / 2))) - - bottomStrokeColor.setStroke() - bottomPath.stroke() - } - } - - //-------------------------------------------------- - // MARK: - Draw States - //-------------------------------------------------- - - public enum FieldState { - case original - case error - case selectedError - case selected - case disabled - - public func setStateUI(for inputField: TextView) { - - switch self { - case .original: - inputField.originalUI() - - case .error: - inputField.errorUI() - - case .selectedError: - inputField.selectedErrorUI() - - case .selected: - inputField.selectedUI() - - case .disabled: - inputField.disabledUI() - } - - inputField.setNeedsDisplay() - } - } - - open func originalUI() { - - isEditable = textViewModel?.editable ?? true - isUserInteractionEnabled = true - hideBorders = textViewModel?.hideBorders ?? false - borderStrokeColor = .mvmCoolGray3 - bottomStrokeColor = .mvmBlack - textColor = isShowingPlaceholder ? textViewModel?.placeholderTextColor.uiColor : textViewModel?.enabledTextColor.uiColor - } - - open func errorUI() { - - isEditable = textViewModel?.editable ?? true - isUserInteractionEnabled = true - hideBorders = textViewModel?.hideBorders ?? false - borderStrokeColor = .mvmOrange - bottomStrokeColor = .mvmOrange - textColor = textViewModel?.enabledTextColor.uiColor - } - - open func selectedErrorUI() { - - isEditable = textViewModel?.editable ?? true - isUserInteractionEnabled = true - hideBorders = textViewModel?.hideBorders ?? false - borderStrokeColor = .mvmBlack - bottomStrokeColor = .mvmOrange - textColor = textViewModel?.enabledTextColor.uiColor - } - - open func selectedUI() { - - isEditable = textViewModel?.editable ?? true - isUserInteractionEnabled = true - hideBorders = textViewModel?.hideBorders ?? false - borderStrokeColor = .mvmBlack - bottomStrokeColor = .mvmBlack - textColor = textViewModel?.enabledTextColor.uiColor - } - - open func disabledUI() { - - isEditable = textViewModel?.editable ?? false - isUserInteractionEnabled = false - hideBorders = textViewModel?.hideBorders ?? false - borderStrokeColor = .mvmCoolGray3 - bottomStrokeColor = .mvmCoolGray3 - textColor = textViewModel?.disabledTextColor.uiColor - } - */ //-------------------------------------------------- // MARK: - Methods //-------------------------------------------------- @@ -372,7 +169,7 @@ import UIKit public func setPlaceholderIfAvailable() { - if let placeholder = textViewModel?.placeholder, !placeholder.isEmpty && text.isEmpty { + if !placeholder.isEmpty && text.isEmpty { setPlaceholderContentTraits() } } @@ -381,16 +178,16 @@ import UIKit isShowingPlaceholder = false text = "" - font = Styler.Font.RegularBodySmall.getFont()//textViewModel?.fontStyle.getFont() - textColor = .black//textViewModel?.enabledTextColor.uiColor + font = fontStyle.getFont() + textColor = .mvmBlack } public func setPlaceholderContentTraits() { isShowingPlaceholder = true textColor = textViewModel?.placeholderTextColor.uiColor - font = textViewModel?.placeholderFontStyle.getFont() - text = textViewModel?.placeholder + font = placeholderFontStyle.getFont() + text = placeholder } @objc func dismissFieldInput(_ sender: TextView) { @@ -410,7 +207,6 @@ import UIKit @objc public func textViewDidBeginEditing(_ textView: UITextView) { setTextAppearance() -// isSelected = true proprietorTextDelegate?.textViewDidBeginEditing?(textView) } @@ -421,7 +217,6 @@ import UIKit @objc public func textViewDidChange(_ textView: UITextView) { - textViewModel?.text = textView.text proprietorTextDelegate?.textViewDidChange?(textView) } @@ -433,7 +228,6 @@ import UIKit @objc public func textViewDidEndEditing(_ textView: UITextView) { setPlaceholderIfAvailable() -// isSelected = false proprietorTextDelegate?.textViewDidEndEditing?(textView) } } diff --git a/MVMCoreUI/BaseClasses/TextViewModel.swift b/MVMCoreUI/BaseClasses/TextViewModel.swift deleted file mode 100644 index 6d68de1c..00000000 --- a/MVMCoreUI/BaseClasses/TextViewModel.swift +++ /dev/null @@ -1,92 +0,0 @@ -// -// TextViewModel.swift -// MVMCoreUI -// -// Created by Kevin Christiano on 5/7/20. -// Copyright © 2020 Verizon Wireless. All rights reserved. -// - -import UIKit - - -open class TextViewModel: MoleculeModelProtocol {//, FormFieldProtocol, FormRuleWatcherFieldProtocol { - //-------------------------------------------------- - // MARK: - Properties - //-------------------------------------------------- - - public class var identifier: String { - return "" - } - - public var baseValue: AnyHashable? - public var backgroundColor: Color? -// public var fieldKey: String? - public var fontStyle: Styler.Font = Styler.Font.RegularBodySmall - public var text: String? - public var placeholder: String? - public var textAlignment: NSTextAlignment = .left -// public var groupName: String - public var editable: Bool = true - public var showsPlaceholder: Bool = false - public var placeholderTextColor: Color = Color(uiColor: .mvmCoolGray3) - public var placeholderFontStyle: Styler.Font = Styler.Font.RegularMicro - - public var isValid: Bool? { - didSet { updateUI?() } - } - - /// Temporary binding mechanism for the view to update on enable changes. - public var updateUI: ActionBlock? - - //-------------------------------------------------- - // MARK: - Validation Methods - //-------------------------------------------------- - - public func formFieldValue() -> AnyHashable? { - return text - } - - public func setValidity(_ valid: Bool, rule: RulesProtocol) { - self.isValid = valid - } - - //-------------------------------------------------- - // MARK: - Keys - //-------------------------------------------------- - - private enum CodingKeys: String, CodingKey { - case moleculeName - case backgroundColor - case editable -// case groupName - case textAlignment - } - - //-------------------------------------------------- - // MARK: - Codec - //-------------------------------------------------- - - required public init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - - if let editable = try typeContainer.decodeIfPresent(Bool.self, forKey: .editable) { - self.editable = editable - } - -// if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) { -// self.groupName = groupName -// } - - if let textAlignment = try typeContainer.decodeIfPresent(NSTextAlignment.self, forKey: .textAlignment) { - self.textAlignment = textAlignment - } - - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) -// try container.encode(groupName, forKey: .groupName) - try container.encode(editable, forKey: .editable) - try container.encode(textAlignment, forKey: .textAlignment) - } -} From 7085122b1b93c10651744d996d76e81a79af032d Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 8 May 2020 11:50:36 -0400 Subject: [PATCH 23/67] basic functioning delegation --- .../Atoms/TextFields/TextViewEntryField.swift | 21 +++++++------------ MVMCoreUI/BaseClasses/TextView.swift | 13 +++++++++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index 9b35c39f..56a62629 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -137,24 +137,21 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele @objc open override func setupFieldContainerContent(_ container: UIView) { - textView.font = Styler.Font.RegularBodyLarge.getFont() + textView.delegate = self container.addSubview(textView) NSLayoutConstraint.activate([ - textView.topAnchor.constraint(equalTo: container.topAnchor), - textView.leadingAnchor.constraint(equalTo: container.leadingAnchor), - container.trailingAnchor.constraint(equalTo: textView.leadingAnchor), - container.bottomAnchor.constraint(equalTo: textView.bottomAnchor) + textView.topAnchor.constraint(equalTo: container.topAnchor, constant: Padding.Three), + textView.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: Padding.Three), + container.trailingAnchor.constraint(equalTo: textView.trailingAnchor, constant: Padding.Three), + container.bottomAnchor.constraint(equalTo: textView.bottomAnchor, constant: Padding.Three) ]) heightConstraint = textView.heightAnchor.constraint(equalToConstant: 0) heightConstraint?.isActive = true - // textView.addTarget(self, action: #selector(startEditing), for: .editingDidBegin) - // textView.addTarget(self, action: #selector(dismissFieldInput), for: .editingDidEnd) - // - // let tap = UITapGestureRecognizer(target: self, action: #selector(startEditing)) - // entryFieldContainer.addGestureRecognizer(tap) + let tap = UITapGestureRecognizer(target: self, action: #selector(startEditing)) + entryFieldContainer.addGestureRecognizer(tap) accessibilityElements = [titleLabel, textView, feedbackLabel] } @@ -216,10 +213,6 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) - if let color = model.backgroundColor?.uiColor { - backgroundColor = color - } - guard let model = model as? TextViewEntryFieldModel else { return } heightConstraint?.constant = model.height ?? 0 diff --git a/MVMCoreUI/BaseClasses/TextView.swift b/MVMCoreUI/BaseClasses/TextView.swift index 5d8abbf1..3ce027b5 100644 --- a/MVMCoreUI/BaseClasses/TextView.swift +++ b/MVMCoreUI/BaseClasses/TextView.swift @@ -25,9 +25,9 @@ import UIKit public var hideBlinkingCaret = false public var placeholder = "" - public var fontStyle: Styler.Font = Styler.Font.RegularBodySmall public var placeholderFontStyle: Styler.Font = Styler.Font.RegularMicro + public var placeholderTextColor: UIColor = .mvmCoolGray3 public var isEnabled: Bool = true { didSet { @@ -116,7 +116,7 @@ import UIKit showsVerticalScrollIndicator = false showsHorizontalScrollIndicator = false isSecureTextEntry = false - textContainerInset = UIEdgeInsets(top: Padding.Three, left: Padding.Three, bottom: Padding.Three, right: Padding.Three) +// textContainerInset = UIEdgeInsets(top: Padding.Three, left: Padding.Three, bottom: Padding.Three, right: Padding.Three) backgroundColor = .mvmWhite clipsToBounds = true smartQuotesType = .no @@ -134,7 +134,14 @@ import UIKit text = "" textAlignment = .left + placeholder = "" + fontStyle = Styler.Font.RegularBodyLarge + placeholderFontStyle = Styler.Font.RegularMicro + placeholderTextColor = .mvmCoolGray3 font = Styler.Font.RegularBodyLarge.getFont() + keyboardType = .default + isEditable = true + isEnabled = true inputAccessoryView?.removeFromSuperview() inputAccessoryView = nil initialConfiguration() @@ -185,7 +192,7 @@ import UIKit public func setPlaceholderContentTraits() { isShowingPlaceholder = true - textColor = textViewModel?.placeholderTextColor.uiColor + textColor = placeholderTextColor font = placeholderFontStyle.getFont() text = placeholder } From 66c638a1b42145deb6b0e92040d5503d16d608ef Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 8 May 2020 12:20:06 -0400 Subject: [PATCH 24/67] general working order --- .../Atoms/TextFields/TextViewEntryField.swift | 50 +++++++++++++++-- MVMCoreUI/BaseClasses/TextView.swift | 53 +------------------ 2 files changed, 47 insertions(+), 56 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index 56a62629..e2caeba9 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -96,6 +96,9 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele // MARK: - Delegate Properties //-------------------------------------------------- + /// Holds a reference to the delegating class so this class can internally influence the TextField behavior as well. + private weak var proprietorTextDelegate: UITextViewDelegate? + /// The delegate and block for validation. Validates if the text that the user has entered. public weak var observingTextFieldDelegate: ObservingTextFieldDelegate? { didSet { @@ -117,7 +120,10 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele /// If you're using a ViewController, you must set this to it public weak var uiTextViewDelegate: UITextViewDelegate? { get { return textView.delegate } - set { textView.delegate = newValue } + set { + textView.delegate = self + proprietorTextDelegate = newValue + } } @objc public func setBothTextDelegates(to delegate: (UITextViewDelegate & ObservingTextFieldDelegate)?) { @@ -128,7 +134,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele open func setupTextViewToolbar() { let observingDelegate = observingTextFieldDelegate ?? self textView.inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate, - action: #selector(observingDelegate.dismissFieldInput)) + action: #selector(observingDelegate.dismissFieldInput)) } //-------------------------------------------------- @@ -137,7 +143,6 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele @objc open override func setupFieldContainerContent(_ container: UIView) { - textView.delegate = self container.addSubview(textView) NSLayoutConstraint.activate([ @@ -176,7 +181,6 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele /// Executes on UITextField.textDidBeginEditingNotification @objc func startEditing() { - isSelected = true textView.becomeFirstResponder() } @@ -206,6 +210,44 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele resignFirstResponder() } + //-------------------------------------------------- + // MARK: - UITextViewDelegate + //-------------------------------------------------- + + @objc public func textViewShouldBeginEditing(_ textView: UITextView) -> Bool { + + return proprietorTextDelegate?.textViewShouldBeginEditing?(textView) ?? true + } + + @objc public func textViewDidBeginEditing(_ textView: UITextView) { + + self.textView.setTextAppearance() + isSelected = true + proprietorTextDelegate?.textViewDidBeginEditing?(textView) + } + + @objc public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { + + return proprietorTextDelegate?.textView?(textView, shouldChangeTextIn: range, replacementText: text) ?? true + } + + @objc public func textViewDidChange(_ textView: UITextView) { + + proprietorTextDelegate?.textViewDidChange?(textView) + } + + @objc public func textViewShouldEndEditing(_ textView: UITextView) -> Bool { + + return proprietorTextDelegate?.textViewShouldEndEditing?(textView) ?? true + } + + @objc public func textViewDidEndEditing(_ textView: UITextView) { + + self.textView.setPlaceholderIfAvailable() + isSelected = false + proprietorTextDelegate?.textViewDidEndEditing?(textView) + } + //-------------------------------------------------- // MARK: - MoleculeViewProtocol //-------------------------------------------------- diff --git a/MVMCoreUI/BaseClasses/TextView.swift b/MVMCoreUI/BaseClasses/TextView.swift index 3ce027b5..208e69bc 100644 --- a/MVMCoreUI/BaseClasses/TextView.swift +++ b/MVMCoreUI/BaseClasses/TextView.swift @@ -30,9 +30,7 @@ import UIKit public var placeholderTextColor: UIColor = .mvmCoolGray3 public var isEnabled: Bool = true { - didSet { - isUserInteractionEnabled = isEnabled - } + didSet { isUserInteractionEnabled = isEnabled } } //-------------------------------------------------- @@ -42,18 +40,6 @@ import UIKit /// Holds a reference to the delegating class so this class can internally influence the TextField behavior as well. public weak var didDeleteDelegate: TextInputDidDeleteProtocol? - /// Holds a reference to the delegating class so this class can internally influence the TextField behavior as well. - private weak var proprietorTextDelegate: UITextViewDelegate? - - /// If you're using a ViewController, you must set this to it. - public weak var uiTextViewDelegate: UITextViewDelegate? { - get { return delegate } - set { - delegate = self - proprietorTextDelegate = newValue - } - } - var delegateObject: MVMCoreUIDelegateObject? //-------------------------------------------------- @@ -116,7 +102,6 @@ import UIKit showsVerticalScrollIndicator = false showsHorizontalScrollIndicator = false isSecureTextEntry = false -// textContainerInset = UIEdgeInsets(top: Padding.Three, left: Padding.Three, bottom: Padding.Three, right: Padding.Three) backgroundColor = .mvmWhite clipsToBounds = true smartQuotesType = .no @@ -201,40 +186,4 @@ import UIKit resignFirstResponder() } - - //-------------------------------------------------- - // MARK: - UITextViewDelegate - //-------------------------------------------------- - - @objc public func textViewShouldBeginEditing(_ textView: UITextView) -> Bool { - - return proprietorTextDelegate?.textViewShouldBeginEditing?(textView) ?? true - } - - @objc public func textViewDidBeginEditing(_ textView: UITextView) { - - setTextAppearance() - proprietorTextDelegate?.textViewDidBeginEditing?(textView) - } - - @objc public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { - - return proprietorTextDelegate?.textView?(textView, shouldChangeTextIn: range, replacementText: text) ?? true - } - - @objc public func textViewDidChange(_ textView: UITextView) { - - proprietorTextDelegate?.textViewDidChange?(textView) - } - - @objc public func textViewShouldEndEditing(_ textView: UITextView) -> Bool { - - return proprietorTextDelegate?.textViewShouldEndEditing?(textView) ?? true - } - - @objc public func textViewDidEndEditing(_ textView: UITextView) { - - setPlaceholderIfAvailable() - proprietorTextDelegate?.textViewDidEndEditing?(textView) - } } From f1466763b704b7a2cde7ba7d60310d84073f8da2 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 8 May 2020 13:42:47 -0400 Subject: [PATCH 25/67] borders gone, observe validation --- .../Atomic/Atoms/TextFields/EntryField.swift | 2 + .../Atoms/TextFields/EntryFieldModel.swift | 4 + .../Atoms/TextFields/TextViewEntryField.swift | 83 ++++++++++--------- 3 files changed, 52 insertions(+), 37 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift index 006988f7..9bcb7135 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift @@ -246,6 +246,7 @@ import UIKit titleLabel.textColor = .mvmBlack feedbackLabel.font = Styler.Font.RegularMicro.getFont() feedbackLabel.textColor = .mvmBlack + entryFieldContainer.disableAllBorders = false feedbackLabel.text = nil entryFieldContainer.reset() } @@ -261,6 +262,7 @@ import UIKit title = model.title feedback = model.feedback isEnabled = model.enabled + entryFieldContainer.disableAllBorders = model.hideBorders if let isLocked = model.locked { self.isLocked = isLocked diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift b/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift index cb00bc6f..768efbd7 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/EntryFieldModel.swift @@ -25,6 +25,7 @@ import Foundation public var errorTextColor: Color? public var enabled: Bool = true public var showError: Bool? + public var hideBorders = false public var locked: Bool? public var selected: Bool? public var text: String? @@ -55,6 +56,7 @@ import Foundation case locked case selected case showError + case hideBorders case text case fieldKey case groupName @@ -96,6 +98,7 @@ import Foundation locked = try typeContainer.decodeIfPresent(Bool.self, forKey: .locked) selected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected) text = try typeContainer.decodeIfPresent(String.self, forKey: .text) + hideBorders = try typeContainer.decodeIfPresent(Bool.self, forKey: .hideBorders) ?? false baseValue = text fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey) @@ -117,6 +120,7 @@ import Foundation try container.encodeIfPresent(errorTextColor, forKey: .errorTextColor) try container.encodeIfPresent(errorMessage, forKey: .errorMessage) try container.encode(enabled, forKey: .enabled) + try container.encode(hideBorders, forKey: .hideBorders) try container.encodeIfPresent(fieldKey, forKey: .fieldKey) try container.encodeIfPresent(groupName, forKey: .groupName) } diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index e2caeba9..084df30c 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -104,15 +104,15 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele didSet { if observingTextFieldDelegate != nil && !observingForChange { observingForChange = true - NotificationCenter.default.addObserver(self, selector: #selector(valueChanged), name: UITextView.textDidChangeNotification, object: textView) - NotificationCenter.default.addObserver(self, selector: #selector(endInputing), name: UITextView.textDidEndEditingNotification, object: textView) - NotificationCenter.default.addObserver(self, selector: #selector(startEditing), name: UITextView.textDidBeginEditingNotification, object: textView) +// NotificationCenter.default.addObserver(self, selector: #selector(valueChanged), name: UITextView.textDidChangeNotification, object: textView) +// NotificationCenter.default.addObserver(self, selector: #selector(endInputing), name: UITextView.textDidEndEditingNotification, object: textView) +// NotificationCenter.default.addObserver(self, selector: #selector(startEditing), name: UITextView.textDidBeginEditingNotification, object: textView) } else if observingTextFieldDelegate == nil && observingForChange { observingForChange = false - NotificationCenter.default.removeObserver(self, name: UITextView.textDidChangeNotification, object: textView) - NotificationCenter.default.removeObserver(self, name: UITextView.textDidEndEditingNotification, object: textView) - NotificationCenter.default.removeObserver(self, name: UITextView.textDidBeginEditingNotification, object: textView) +// NotificationCenter.default.removeObserver(self, name: UITextView.textDidChangeNotification, object: textView) +// NotificationCenter.default.removeObserver(self, name: UITextView.textDidEndEditingNotification, object: textView) +// NotificationCenter.default.removeObserver(self, name: UITextView.textDidBeginEditingNotification, object: textView) } } } @@ -153,10 +153,9 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele ]) heightConstraint = textView.heightAnchor.constraint(equalToConstant: 0) - heightConstraint?.isActive = true - let tap = UITapGestureRecognizer(target: self, action: #selector(startEditing)) - entryFieldContainer.addGestureRecognizer(tap) +// let tap = UITapGestureRecognizer(target: self, action: #selector(startEditing)) +// entryFieldContainer.addGestureRecognizer(tap) accessibilityElements = [titleLabel, textView, feedbackLabel] } @@ -173,42 +172,43 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele textView.font = Styler.Font.RegularBodyLarge.getFont() heightConstraint?.constant = 0 + heightConstraint?.isActive = false } //-------------------------------------------------- // MARK: - Methods //-------------------------------------------------- - - /// Executes on UITextField.textDidBeginEditingNotification - @objc func startEditing() { - textView.becomeFirstResponder() - } - - /// Executes on UITextField.textDidChangeNotification (each character entry) - @objc func valueChanged() { - guard validateEachCharacter else { return } - isSelected = true - validateTextField() - } - - /// Validates the text of the entry field. +// +// /// Executes on UITextField.textDidBeginEditingNotification +// @objc func startEditing() { +// textView.becomeFirstResponder() +// } +// +// /// Executes on UITextField.textDidChangeNotification (each character entry) +// @objc func valueChanged() { +// guard validateEachCharacter else { return } +// isSelected = true +// validateTextField() +// } +// +// /// Validates the text of the entry field. @objc public func validateTextField() { text = textView.text _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) } - - /// Executes on UITextField.textDidEndEditingNotification - @objc func endInputing() { - resignFirstResponder() - if isValid { - showError = false - entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor - } - } - - @objc public func dismissFieldInput(_ sender: Any?) { - resignFirstResponder() - } +// +// /// Executes on UITextField.textDidEndEditingNotification +// @objc func endInputing() { +// resignFirstResponder() +// if isValid { +// showError = false +// entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor +// } +// } +// +// @objc public func dismissFieldInput(_ sender: Any?) { +// resignFirstResponder() +// } //-------------------------------------------------- // MARK: - UITextViewDelegate @@ -233,6 +233,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele @objc public func textViewDidChange(_ textView: UITextView) { + validateTextField() proprietorTextDelegate?.textViewDidChange?(textView) } @@ -245,6 +246,10 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele self.textView.setPlaceholderIfAvailable() isSelected = false + if isValid { + showError = false + entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor + } proprietorTextDelegate?.textViewDidEndEditing?(textView) } @@ -257,7 +262,11 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele guard let model = model as? TextViewEntryFieldModel else { return } - heightConstraint?.constant = model.height ?? 0 + if let height = model.height { + heightConstraint?.constant = height + heightConstraint?.isActive = true + } + text = model.text uiTextViewDelegate = delegateObject?.uiTextViewDelegate From 4f3f52195e092e03fc6af0d22788857428cd9cfb Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 8 May 2020 14:08:47 -0400 Subject: [PATCH 26/67] value change --- .../Atoms/TextFields/TextViewEntryField.swift | 77 +++++++++---------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index 084df30c..41e77a99 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -100,19 +100,19 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele private weak var proprietorTextDelegate: UITextViewDelegate? /// The delegate and block for validation. Validates if the text that the user has entered. - public weak var observingTextFieldDelegate: ObservingTextFieldDelegate? { + public weak var observingTextViewdDelegate: ObservingTextFieldDelegate? { didSet { - if observingTextFieldDelegate != nil && !observingForChange { + if observingTextViewdDelegate != nil && !observingForChange { observingForChange = true -// NotificationCenter.default.addObserver(self, selector: #selector(valueChanged), name: UITextView.textDidChangeNotification, object: textView) -// NotificationCenter.default.addObserver(self, selector: #selector(endInputing), name: UITextView.textDidEndEditingNotification, object: textView) -// NotificationCenter.default.addObserver(self, selector: #selector(startEditing), name: UITextView.textDidBeginEditingNotification, object: textView) + NotificationCenter.default.addObserver(self, selector: #selector(valueChanged), name: UITextView.textDidChangeNotification, object: textView) + NotificationCenter.default.addObserver(self, selector: #selector(endInputing), name: UITextView.textDidEndEditingNotification, object: textView) + NotificationCenter.default.addObserver(self, selector: #selector(startEditing), name: UITextView.textDidBeginEditingNotification, object: textView) - } else if observingTextFieldDelegate == nil && observingForChange { + } else if observingTextViewdDelegate == nil && observingForChange { observingForChange = false -// NotificationCenter.default.removeObserver(self, name: UITextView.textDidChangeNotification, object: textView) -// NotificationCenter.default.removeObserver(self, name: UITextView.textDidEndEditingNotification, object: textView) -// NotificationCenter.default.removeObserver(self, name: UITextView.textDidBeginEditingNotification, object: textView) + NotificationCenter.default.removeObserver(self, name: UITextView.textDidChangeNotification, object: textView) + NotificationCenter.default.removeObserver(self, name: UITextView.textDidEndEditingNotification, object: textView) + NotificationCenter.default.removeObserver(self, name: UITextView.textDidBeginEditingNotification, object: textView) } } } @@ -127,12 +127,12 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele } @objc public func setBothTextDelegates(to delegate: (UITextViewDelegate & ObservingTextFieldDelegate)?) { - observingTextFieldDelegate = delegate + observingTextViewdDelegate = delegate uiTextViewDelegate = delegate } open func setupTextViewToolbar() { - let observingDelegate = observingTextFieldDelegate ?? self + let observingDelegate = observingTextViewdDelegate ?? self textView.inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate, action: #selector(observingDelegate.dismissFieldInput)) } @@ -154,9 +154,6 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele heightConstraint = textView.heightAnchor.constraint(equalToConstant: 0) -// let tap = UITapGestureRecognizer(target: self, action: #selector(startEditing)) -// entryFieldContainer.addGestureRecognizer(tap) - accessibilityElements = [titleLabel, textView, feedbackLabel] } @@ -178,38 +175,36 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele //-------------------------------------------------- // MARK: - Methods //-------------------------------------------------- -// -// /// Executes on UITextField.textDidBeginEditingNotification -// @objc func startEditing() { -// textView.becomeFirstResponder() -// } -// -// /// Executes on UITextField.textDidChangeNotification (each character entry) -// @objc func valueChanged() { -// guard validateEachCharacter else { return } -// isSelected = true -// validateTextField() -// } -// -// /// Validates the text of the entry field. + + /// Validates the text of the entry field. @objc public func validateTextField() { text = textView.text _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) } -// -// /// Executes on UITextField.textDidEndEditingNotification -// @objc func endInputing() { -// resignFirstResponder() -// if isValid { -// showError = false -// entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor -// } -// } -// -// @objc public func dismissFieldInput(_ sender: Any?) { -// resignFirstResponder() -// } + /// Executes on UITextField.textDidBeginEditingNotification + @objc func startEditing() { + isSelected = true + textView.becomeFirstResponder() + } + + /// Executes on UITextField.textDidChangeNotification (each character entry) + @objc func valueChanged() { + guard validateEachCharacter else { return } + isSelected = true + validateTextField() + } + + /// Executes on UITextField.textDidEndEditingNotification + @objc func endInputing() { + resignFirstResponder() + if isValid { + showError = false + entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor + } + } + + //-------------------------------------------------- // MARK: - UITextViewDelegate //-------------------------------------------------- From e90be283dc99e36102abc1f84a8520705c8c0f95 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 8 May 2020 15:06:25 -0400 Subject: [PATCH 27/67] curent working order --- .../Atoms/TextFields/TextViewEntryField.swift | 31 ++++++++++++++++++- .../Views/EntryFieldContainer.swift | 6 ++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index 41e77a99..f2188c24 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -179,7 +179,22 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele /// Validates the text of the entry field. @objc public func validateTextField() { text = textView.text - _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) + if let isValid = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) { + self.isValid = isValid + } + } + + @objc public func updateValidation(_ isValid: Bool) { + let previousValidity = self.isValid + self.isValid = isValid + + if previousValidity && !isValid { +// showError = true +// observingTextViewDelegate?.isInvalid?(textfield: self) + } else if (!previousValidity && isValid) { +// showError = false +// observingTextViewDelegate?.isValid?(textfield: self) + } } /// Executes on UITextField.textDidBeginEditingNotification @@ -241,9 +256,13 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele self.textView.setPlaceholderIfAvailable() isSelected = false + if isValid { showError = false entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor + } else { + showError = true + entryFieldContainer.disableAllBorders = false } proprietorTextDelegate?.textViewDidEndEditing?(textView) } @@ -262,6 +281,16 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele heightConstraint?.isActive = true } + model.updateUI = { [weak self] in + MVMCoreDispatchUtility.performBlock(onMainThread: { + guard let self = self else { return } + + if self.isSelected { + self.updateValidation(model.isValid ?? true) + } + }) + } + text = model.text uiTextViewDelegate = delegateObject?.uiTextViewDelegate diff --git a/MVMCoreUI/Containers/Views/EntryFieldContainer.swift b/MVMCoreUI/Containers/Views/EntryFieldContainer.swift index 9ccd1d25..ff54ef7c 100644 --- a/MVMCoreUI/Containers/Views/EntryFieldContainer.swift +++ b/MVMCoreUI/Containers/Views/EntryFieldContainer.swift @@ -19,7 +19,7 @@ import UIKit let layer = CAShapeLayer() layer.backgroundColor = UIColor.mvmBlack.cgColor layer.drawsAsynchronously = true - layer.anchorPoint = CGPoint(x: 0.5, y: 1.0); + layer.anchorPoint = CGPoint(x: 0.5, y: 1.0) return layer }() @@ -140,7 +140,7 @@ import UIKit borderPath.removeAllPoints() - if !disableAllBorders && !hideBorders { + if (disableAllBorders && showError) || (!disableAllBorders && !hideBorders) { // Brings the other half of the line inside the view to prevent cropping. let origin = bounds.origin let size = frame.size @@ -260,7 +260,7 @@ import UIKit open func refreshUI(bottomBarSize: CGFloat? = nil, updateMoleculeLayout: Bool = false) { - if !disableAllBorders { + if !disableAllBorders || (disableAllBorders && showError) { let size: CGFloat = bottomBarSize ?? (showError ? 4 : 1) var heightChanged = false From f923c4de528872dca63c195c0047809711831a0b Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 8 May 2020 15:33:04 -0400 Subject: [PATCH 28/67] latest functioning state --- .../Atoms/TextFields/TextViewEntryField.swift | 34 +++++-------------- .../Views/EntryFieldContainer.swift | 6 ++-- 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index f2188c24..91ca1c2e 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -52,7 +52,11 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele guard let self = self else { return } self.textView.isEnabled = enabled - self.textView.textColor = enabled ? self.textViewEntryFieldModel?.enabledTextColor.uiColor : self.textViewEntryFieldModel?.disabledTextColor.uiColor + if self.textView.isShowingPlaceholder { + self.textView.textColor = self.textView.placeholderTextColor + } else { + self.textView.textColor = enabled ? self.textViewEntryFieldModel?.enabledTextColor.uiColor : self.textViewEntryFieldModel?.disabledTextColor.uiColor + } } } } @@ -184,19 +188,6 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele } } - @objc public func updateValidation(_ isValid: Bool) { - let previousValidity = self.isValid - self.isValid = isValid - - if previousValidity && !isValid { -// showError = true -// observingTextViewDelegate?.isInvalid?(textfield: self) - } else if (!previousValidity && isValid) { -// showError = false -// observingTextViewDelegate?.isValid?(textfield: self) - } - } - /// Executes on UITextField.textDidBeginEditingNotification @objc func startEditing() { isSelected = true @@ -262,8 +253,8 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor } else { showError = true - entryFieldContainer.disableAllBorders = false } + proprietorTextDelegate?.textViewDidEndEditing?(textView) } @@ -281,16 +272,6 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele heightConstraint?.isActive = true } - model.updateUI = { [weak self] in - MVMCoreDispatchUtility.performBlock(onMainThread: { - guard let self = self else { return } - - if self.isSelected { - self.updateValidation(model.isValid ?? true) - } - }) - } - text = model.text uiTextViewDelegate = delegateObject?.uiTextViewDelegate @@ -302,6 +283,9 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele textView.textAlignment = model.textAlignment textView.textColor = model.enabled ? model.enabledTextColor.uiColor : model.disabledTextColor.uiColor textView.font = model.fontStyle.getFont() + textView.placeholder = model.placeholder ?? "" + textView.placeholderFontStyle = model.placeholderFontStyle + textView.placeholderTextColor = model.placeholderTextColor.uiColor textView.setPlaceholderIfAvailable() switch model.type { diff --git a/MVMCoreUI/Containers/Views/EntryFieldContainer.swift b/MVMCoreUI/Containers/Views/EntryFieldContainer.swift index ff54ef7c..9ccd1d25 100644 --- a/MVMCoreUI/Containers/Views/EntryFieldContainer.swift +++ b/MVMCoreUI/Containers/Views/EntryFieldContainer.swift @@ -19,7 +19,7 @@ import UIKit let layer = CAShapeLayer() layer.backgroundColor = UIColor.mvmBlack.cgColor layer.drawsAsynchronously = true - layer.anchorPoint = CGPoint(x: 0.5, y: 1.0) + layer.anchorPoint = CGPoint(x: 0.5, y: 1.0); return layer }() @@ -140,7 +140,7 @@ import UIKit borderPath.removeAllPoints() - if (disableAllBorders && showError) || (!disableAllBorders && !hideBorders) { + if !disableAllBorders && !hideBorders { // Brings the other half of the line inside the view to prevent cropping. let origin = bounds.origin let size = frame.size @@ -260,7 +260,7 @@ import UIKit open func refreshUI(bottomBarSize: CGFloat? = nil, updateMoleculeLayout: Bool = false) { - if !disableAllBorders || (disableAllBorders && showError) { + if !disableAllBorders { let size: CGFloat = bottomBarSize ?? (showError ? 4 : 1) var heightChanged = false From 58c06df8e4204423fb131c400345d4b12595c5d6 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 8 May 2020 17:41:08 -0400 Subject: [PATCH 29/67] removing what isn't needed --- MVMCoreUI/BaseClasses/TextView.swift | 30 ++++++++-------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/MVMCoreUI/BaseClasses/TextView.swift b/MVMCoreUI/BaseClasses/TextView.swift index 208e69bc..eb5bdb7d 100644 --- a/MVMCoreUI/BaseClasses/TextView.swift +++ b/MVMCoreUI/BaseClasses/TextView.swift @@ -40,14 +40,6 @@ import UIKit /// Holds a reference to the delegating class so this class can internally influence the TextField behavior as well. public weak var didDeleteDelegate: TextInputDidDeleteProtocol? - var delegateObject: MVMCoreUIDelegateObject? - - //-------------------------------------------------- - // MARK: - Constraint - //-------------------------------------------------- - - public var heightConstraint: NSLayoutConstraint? - //-------------------------------------------------- // MARK: - Initialization //-------------------------------------------------- @@ -84,20 +76,20 @@ import UIKit } } - open func updateView(_ size: CGFloat) { - - setNeedsDisplay() - } + open func updateView(_ size: CGFloat) { } /// Will be called only once. open func setupView() { translatesAutoresizingMaskIntoConstraints = false - initialConfiguration() + defaultConfiguration() } - public func initialConfiguration() { + public func defaultConfiguration() { + text = "" + placeholder = "" + textAlignment = .left insetsLayoutMarginsFromSafeArea = false showsVerticalScrollIndicator = false showsHorizontalScrollIndicator = false @@ -111,25 +103,19 @@ import UIKit isAccessibilityElement = true accessibilityTraits = .staticText font = Styler.Font.RegularBodyLarge.getFont() + keyboardType = .default isEditable = true isOpaque = false } open func reset() { - text = "" - textAlignment = .left - placeholder = "" fontStyle = Styler.Font.RegularBodyLarge placeholderFontStyle = Styler.Font.RegularMicro placeholderTextColor = .mvmCoolGray3 - font = Styler.Font.RegularBodyLarge.getFont() - keyboardType = .default - isEditable = true isEnabled = true inputAccessoryView?.removeFromSuperview() - inputAccessoryView = nil - initialConfiguration() + defaultConfiguration() } //-------------------------------------------------- From 72f1d48eebe4196e51e15cbf0c185d55101a1135 Mon Sep 17 00:00:00 2001 From: Kyle Matthew Hedden Date: Mon, 11 May 2020 11:52:18 -0400 Subject: [PATCH 30/67] page behavior protocol --- MVMCoreUI.xcodeproj/project.pbxproj | 18 ++++- MVMCoreUI/Atomic/MoleculeObjectMapping.swift | 3 + .../TemplateModelProtocol.swift | 2 +- .../Atomic/Templates/TemplateModel.swift | 6 +- .../MVMControllerModelProtocol.swift | 2 +- .../BaseControllers/ViewController.swift | 17 +++++ MVMCoreUI/Behaviors/PageBehavior.swift | 44 ++++++++++++ .../ScreenBrightnessModifierBehavior.swift | 70 +++++++++++++++++++ 8 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 MVMCoreUI/Behaviors/PageBehavior.swift create mode 100644 MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 3915b055..6bae9611 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -108,6 +108,8 @@ 0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB423FF18D2004C5109 /* Arrow.swift */; }; 0AE98BB723FF18E9004C5109 /* ArrowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB623FF18E9004C5109 /* ArrowModel.swift */; }; 279B1569242BBC2F00921D6C /* ActionModelAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279B1568242BBC2F00921D6C /* ActionModelAdapter.swift */; }; + 27F973532466074500CAB5C5 /* PageBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F973522466074500CAB5C5 /* PageBehavior.swift */; }; + 27F9736A246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F97369246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift */; }; 31BE15CB23D8924D00452370 /* CheckboxLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */; }; 31BE15CC23D8924D00452370 /* CheckboxModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31BE15CA23D8924C00452370 /* CheckboxModel.swift */; }; 522679C123FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522679BF23FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift */; }; @@ -519,6 +521,8 @@ 0AE98BB423FF18D2004C5109 /* Arrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arrow.swift; sourceTree = ""; }; 0AE98BB623FF18E9004C5109 /* ArrowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowModel.swift; sourceTree = ""; }; 279B1568242BBC2F00921D6C /* ActionModelAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionModelAdapter.swift; sourceTree = ""; }; + 27F973522466074500CAB5C5 /* PageBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageBehavior.swift; sourceTree = ""; }; + 27F97369246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenBrightnessModifierBehavior.swift; sourceTree = ""; }; 31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxLabelModel.swift; sourceTree = ""; }; 31BE15CA23D8924C00452370 /* CheckboxModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxModel.swift; sourceTree = ""; }; 522679BF23FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableCheckboxAllTextAndLinks.swift; sourceTree = ""; }; @@ -948,6 +952,15 @@ path = Adapters; sourceTree = ""; }; + 27F973512466071600CAB5C5 /* Behaviors */ = { + isa = PBXGroup; + children = ( + 27F973522466074500CAB5C5 /* PageBehavior.swift */, + 27F97369246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift */, + ); + path = Behaviors; + sourceTree = ""; + }; 5206F150241144A900658DC5 /* Headers */ = { isa = PBXGroup; children = ( @@ -1383,6 +1396,7 @@ D29DF0CE21E404D4003B2FB9 /* MVMCoreUI */ = { isa = PBXGroup; children = ( + 27F973512466071600CAB5C5 /* Behaviors */, D2C78CD324252F4E00B69FDE /* Atomic */, 012A88EF23985E0100FE3DA1 /* CustomPrimitives */, D2B18B7D236090D500A9AEDC /* BaseClasses */, @@ -2103,7 +2117,7 @@ 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */, 011B58F023A2AA980085F53C /* ListItemModelProtocol.swift in Sources */, D22479962316AF6E003FCCF9 /* HeadlineBodyLink.swift in Sources */, - 8DE5BECD2456F7A200772E76 /* ListTwoColumnDropdownSelectorsModel.swift in Sources */, + 8DE5BECD2456F7A200772E76 /* ListTwoColumnDropdownSelectorsModel.swift in Sources */, 0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */, BB55B51D244482C1002001AD /* ListRightVariablePriceChangeBodyText.swift in Sources */, 017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */, @@ -2128,6 +2142,7 @@ AA69AAF62445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift in Sources */, D264FAA3243E632F00D98315 /* ProgrammaticCollectionViewController.swift in Sources */, D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */, + 27F9736A246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift in Sources */, D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */, 526A265E240D200500B0D828 /* ListTwoColumnCompareChanges.swift in Sources */, 8D24041523E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift in Sources */, @@ -2220,6 +2235,7 @@ D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */, D2E2A9A323E096B1000B42E6 /* DisableableModelProtocol.swift in Sources */, D29DF11821E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m in Sources */, + 27F973532466074500CAB5C5 /* PageBehavior.swift in Sources */, 94C2D9A323872C110006CF46 /* LabelAttributeStrikeThroughModel.swift in Sources */, D28A838523CCCA8900DFE4FC /* ScrollerModel.swift in Sources */, D29DF26C21E6AA0B003B2FB9 /* FLAnimatedImage.m in Sources */, diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index a9e86d50..a77b50f4 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -198,6 +198,9 @@ import Foundation try? ModelRegistry.register(ActionTopAlertModel.self) try? ModelRegistry.register(ActionCollapseNotificationModel.self) try? ModelRegistry.register(ActionOpenPanelModel.self) + + // Behaviors + try? ModelRegistry.register(ScreenBrightnessModifierBehavior.self) } /// Convenience function to get required modules for a give model diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift index 3ed37d6b..f34c4ebd 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift @@ -9,7 +9,7 @@ import Foundation -public protocol TemplateModelProtocol: PageModelProtocol, ModelProtocol { +public protocol TemplateModelProtocol: PageModelProtocol, ModelProtocol, PageBehaviorsTemplateProtocol { var template: String { get } } diff --git a/MVMCoreUI/Atomic/Templates/TemplateModel.swift b/MVMCoreUI/Atomic/Templates/TemplateModel.swift index 86da1981..864c2bf8 100644 --- a/MVMCoreUI/Atomic/Templates/TemplateModel.swift +++ b/MVMCoreUI/Atomic/Templates/TemplateModel.swift @@ -9,6 +9,7 @@ import Foundation @objcMembers public class TemplateModel: MVMControllerModelProtocol { + public class var identifier: String { return "" } @@ -21,7 +22,8 @@ import Foundation public var screenHeading: String? public var navigationItem: (NavigationItemModelProtocol & MoleculeModelProtocol)? public var formRules: [FormGroupRule]? - + public var behaviors: [PageBehaviorProtocol]? + public init(pageType: String) { self.pageType = pageType } @@ -32,6 +34,7 @@ import Foundation case screenHeading case backgroundColor case formRules + case behaviors case navigationItem } @@ -41,6 +44,7 @@ import Foundation screenHeading = try typeContainer.decodeIfPresent(String.self, forKey: .screenHeading) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) formRules = try typeContainer.decodeIfPresent([FormGroupRule].self, forKey: .formRules) + behaviors = try typeContainer.decodeModelsIfPresent(codingKey: .behaviors) navigationItem = try typeContainer.decodeModelIfPresent(codingKey: .navigationItem) } diff --git a/MVMCoreUI/BaseControllers/MVMControllerModelProtocol.swift b/MVMCoreUI/BaseControllers/MVMControllerModelProtocol.swift index 579a612e..4ec8ed2c 100644 --- a/MVMCoreUI/BaseControllers/MVMControllerModelProtocol.swift +++ b/MVMCoreUI/BaseControllers/MVMControllerModelProtocol.swift @@ -8,6 +8,6 @@ import Foundation -public protocol MVMControllerModelProtocol: TemplateModelProtocol, FormHolderModelProtocol { +public protocol MVMControllerModelProtocol: TemplateModelProtocol, FormHolderModelProtocol, PageBehaviorsTemplateProtocol { } diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index 75cb897c..28aacc6e 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -306,6 +306,18 @@ import UIKit MVMCoreUISession.sharedGlobal()?.currentPageType = pageType MVMCoreUILoggingHandler.shared()?.defaultLogPageState(forController: self) } + + executeBehaviors { (behavior: PageVisibilityBehavior) in + behavior.onPageShown() + } + } + + open override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + executeBehaviors { (behavior: PageVisibilityBehavior) in + behavior.onPageHidden() + } } deinit { @@ -420,4 +432,9 @@ import UIKit selectedField = nil } } + + // MARK: - Behavior Execution + func executeBehaviors(_ behaviorBlock:(_ behavior:T)->Void) { + pageModel?.behaviors?.compactMap({ $0 as? T }).forEach({ behaviorBlock($0) }) + } } diff --git a/MVMCoreUI/Behaviors/PageBehavior.swift b/MVMCoreUI/Behaviors/PageBehavior.swift new file mode 100644 index 00000000..d8fd99a3 --- /dev/null +++ b/MVMCoreUI/Behaviors/PageBehavior.swift @@ -0,0 +1,44 @@ +// +// PageBehaviors.swift +// MVMCoreUI +// +// Created by Kyle on 5/8/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol PageBehaviorProtocol: ModelProtocol { + + // The type of rule + var behaviorName: String { get } + +} + +public extension PageBehaviorProtocol { + + var behaviorName: String { + get { return Self.identifier } + } + + static var categoryCodingKey: String { + return "behaviorName" + } + + static var categoryName: String { + return "\(PageBehaviorProtocol.self)" + } +} + +public protocol PageVisibilityBehavior: PageBehaviorProtocol { + + func onPageShown() + func onPageHidden() + +} + +public protocol PageBehaviorsTemplateProtocol { + + var behaviors: [PageBehaviorProtocol]? { get } + +} diff --git a/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift b/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift new file mode 100644 index 00000000..422222b6 --- /dev/null +++ b/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift @@ -0,0 +1,70 @@ +// +// ScreenBrightnessModifierBehavior.swift +// MVMCoreUI +// +// Created by Kyle on 5/9/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +class ScreenBrightnessModifierBehavior: PageVisibilityBehavior { + + static var identifier = "screenBrightnessModifier" + + @Clamping(range: 0...1) var screenBrightness: CGFloat + + var originalScreenBrightness: CGFloat? + + //MARK:- PageVisibilityBehavior + + func onPageShown() { + changeScreenBrightness() + } + + func onPageHidden() { + restoreScreenBrightness() + } + + //MARK:- Behavior + + func changeScreenBrightness() { + if originalScreenBrightness == nil { + originalScreenBrightness = UIScreen.main.brightness + UIScreen.main.brightness = screenBrightness + NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), name: UIApplication.willResignActiveNotification, object: nil) + } + } + + func restoreScreenBrightness() { + if let originalScreenBrightness = originalScreenBrightness { + UIScreen.main.brightness = originalScreenBrightness + self.originalScreenBrightness = nil + NotificationCenter.default.removeObserver(self, name: UIApplication.willResignActiveNotification, object: nil) + } + } + + @objc func didEnterBackground() { + restoreScreenBrightness() + NotificationCenter.default.addObserver(self, selector: #selector(didEnterForeground), name: UIApplication.didBecomeActiveNotification, object: nil) + } + + @objc func didEnterForeground() { + NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil) + changeScreenBrightness() + } + + //MARK:- Codable + + enum CodingKeys: String, CodingKey { + case screenBrightness + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + screenBrightness = try typeContainer.decode(CGFloat.self, forKey: .screenBrightness) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(screenBrightness, forKey: .screenBrightness) + } +} From a19003f240194a90358ee11ed6952ff4fd86c269 Mon Sep 17 00:00:00 2001 From: Kyle Matthew Hedden Date: Mon, 11 May 2020 12:04:06 -0400 Subject: [PATCH 31/67] privatize coding keys --- MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift b/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift index 422222b6..b6712354 100644 --- a/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift +++ b/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift @@ -54,7 +54,7 @@ class ScreenBrightnessModifierBehavior: PageVisibilityBehavior { //MARK:- Codable - enum CodingKeys: String, CodingKey { + private enum CodingKeys: String, CodingKey { case screenBrightness } From e6c0145efa9cd122f2119f013e63792dcc022b96 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 11 May 2020 13:44:11 -0400 Subject: [PATCH 32/67] reorientation --- .../Atomic/Atoms/TextFields/EntryField.swift | 6 +---- .../Atoms/TextFields/TextViewEntryField.swift | 4 +--- .../TextFields/TextViewEntryFieldModel.swift | 7 ++++-- MVMCoreUI/BaseClasses/TextView.swift | 23 ++++++++++++++----- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift index 9bcb7135..e54cb80f 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift @@ -69,11 +69,7 @@ import UIKit get { return entryFieldContainer.showError } set (error) { self.feedback = error ? entryFieldModel?.errorMessage : entryFieldModel?.feedback - if error { - feedbackLabel.textColor = entryFieldModel?.errorTextColor?.uiColor ?? .mvmBlack - } else { - feedbackLabel.textColor = .mvmBlack - } + self.feedbackLabel.textColor = error ? entryFieldModel?.errorTextColor?.uiColor ?? .mvmBlack : .mvmBlack self.entryFieldContainer.showError = error self.entryFieldModel?.showError = error } diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index 91ca1c2e..a086b18b 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -222,7 +222,6 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele @objc public func textViewDidBeginEditing(_ textView: UITextView) { - self.textView.setTextAppearance() isSelected = true proprietorTextDelegate?.textViewDidBeginEditing?(textView) } @@ -244,8 +243,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele } @objc public func textViewDidEndEditing(_ textView: UITextView) { - - self.textView.setPlaceholderIfAvailable() + isSelected = false if isValid { diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift index 78638ddb..3d1e1407 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift @@ -31,7 +31,6 @@ class TextViewEntryFieldModel: TextEntryFieldModel { //-------------------------------------------------- private enum CodingKeys: String, CodingKey { - case text case accessibilityText case fontStyle case height @@ -60,6 +59,10 @@ class TextViewEntryFieldModel: TextEntryFieldModel { self.fontStyle = fontStyle } + if let editable = try typeContainer.decodeIfPresent(Bool.self, forKey: .editable) { + self.editable = editable + } + accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText) height = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .height) } @@ -70,7 +73,7 @@ class TextViewEntryFieldModel: TextEntryFieldModel { try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText) try container.encodeIfPresent(height, forKey: .height) try container.encode(fontStyle, forKey: .fontStyle) - try container.encode(text, forKey: .text) + try container.encode(editable, forKey: .editable) try container.encode(placeholderFontStyle, forKey: .placeholderFontStyle) try container.encode(placeholderTextColor, forKey: .placeholderTextColor) } diff --git a/MVMCoreUI/BaseClasses/TextView.swift b/MVMCoreUI/BaseClasses/TextView.swift index eb5bdb7d..9ae48800 100644 --- a/MVMCoreUI/BaseClasses/TextView.swift +++ b/MVMCoreUI/BaseClasses/TextView.swift @@ -119,7 +119,7 @@ import UIKit } //-------------------------------------------------- - // MARK: - Methods + // MARK: - TextInputDidDeleteProtocol //-------------------------------------------------- /// Alters the blinking caret line as per design standards. @@ -138,11 +138,22 @@ import UIKit didDeleteDelegate?.textInputDidDelete() } - public func setTextAppearance() { + //-------------------------------------------------- + // MARK: - Text / Placeholder + //-------------------------------------------------- + + open override func becomeFirstResponder() -> Bool { if isShowingPlaceholder { setTextContentTraits() } + return super.becomeFirstResponder() + } + + open override func resignFirstResponder() -> Bool { + + setPlaceholderIfAvailable() + return super.resignFirstResponder() } public func setPlaceholderIfAvailable() { @@ -152,7 +163,7 @@ import UIKit } } - public func setTextContentTraits() { + open func setTextContentTraits() { isShowingPlaceholder = false text = "" @@ -160,7 +171,7 @@ import UIKit textColor = .mvmBlack } - public func setPlaceholderContentTraits() { + open func setPlaceholderContentTraits() { isShowingPlaceholder = true textColor = placeholderTextColor @@ -168,8 +179,8 @@ import UIKit text = placeholder } - @objc func dismissFieldInput(_ sender: TextView) { + @objc open func dismissFieldInput(_ sender: TextView) { - resignFirstResponder() + _ = resignFirstResponder() } } From 111e4354662850770f40397428049615381e59c3 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 11 May 2020 16:14:42 -0400 Subject: [PATCH 33/67] delegate object for model decoding functions --- MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift | 2 +- MVMCoreUI/BaseControllers/ViewController.swift | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift b/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift index 56b1a86c..04280042 100644 --- a/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift @@ -8,7 +8,6 @@ import Foundation - public protocol TemplateProtocol: AnyObject { associatedtype TemplateModel: TemplateModelProtocol var templateModel: TemplateModel? { get set } @@ -19,6 +18,7 @@ public extension TemplateProtocol where Self: ViewController { guard let pageJSON = json else { return } let data = try JSONSerialization.data(withJSONObject: pageJSON) let decoder = JSONDecoder() + try decoder.add(delegateObject: delegateObjectIVar) let templateModel = try decoder.decode(TemplateModel.self, from: data) self.templateModel = templateModel self.pageModel = templateModel as? MVMControllerModelProtocol diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index 315a0476..0872b0e6 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -17,7 +17,10 @@ import UIKit public var manager: (UIViewController & MVMCoreViewManagerProtocol)? /// A temporary iVar backer for delegateObject() until we change the protocol - public var delegateObjectIVar: MVMCoreUIDelegateObject? + public let delegateObjectIVar: MVMCoreUIDelegateObject = { + return MVMCoreUIDelegateObject.create(withDelegateForAll: self) + }() + public func delegateObject() -> DelegateObject? { return delegateObjectIVar } @@ -264,9 +267,6 @@ import UIKit // Presents from the bottom. modalPresentationStyle = MVMCoreGetterUtility.isOnIPad() ? .formSheet : .overCurrentContext - // Create the default delegate object. - delegateObjectIVar = MVMCoreUIDelegateObject.create(withDelegateForAll: self) - // Do some initial loading. if !initialLoadFinished { initialLoadFinished = true From 605bcddf08c4793bd4744ea5baa9c586d08fde34 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 11 May 2020 16:52:39 -0400 Subject: [PATCH 34/67] renamed font declarations to align with modern changes --- .../Atomic/Atoms/Buttons/CaretLink.swift | 2 +- .../Atomic/Atoms/Selectors/RadioSwatch.swift | 2 +- .../NumericIndicatorView.swift | 2 +- .../Atomic/Atoms/Views/CheckboxLabel.swift | 2 +- .../Headers/HeadersH2NoButtonsBodyText.swift | 1 + .../ListFourColumnDataUsageListItem.swift | 16 +++++----- .../ListLeftVariableIconWithRightCaret.swift | 9 +++--- ...neColumnFullWidthTextAllTextAndLinks.swift | 16 +++++----- .../List/RightVariable/ListRVWheel.swift | 8 ++--- .../ListRightVariablePayments.swift | 4 +-- ...htVariablePriceChangeAllTextAndLinks.swift | 2 +- ...ListRightVariablePriceChangeBodyText.swift | 2 +- .../ListRightVariableTotalData.swift | 8 ++--- .../ListTwoColumnCompareChanges.swift | 32 +++++++++---------- .../ListTwoColumnPriceDescription.swift | 16 +++++----- .../TwoColumn/ListTwoColumnPriceDetails.swift | 8 ++--- ...ColumnFullWidthTextDividerSubsection.swift | 8 ++--- ...ColumnTextWithWhitespaceDividerShort.swift | 8 ++--- ...eColumnTextWithWhitespaceDividerTall.swift | 8 ++--- .../ImageHeadlineBody.swift | 4 +-- .../ActionDetailWithImage.swift | 4 +-- .../LeftRightViews/CornerLabels.swift | 16 +++++----- .../BGImageHeadlineBodyButtonModel.swift | 1 - .../EyebrowHeadlineBodyLink.swift | 12 +++---- .../HeadlineBody.swift | 20 ++++++------ .../HeadlineBodyButton.swift | 4 +-- .../StringAndMoleculeView.swift | 2 +- .../Protocols/MoleculeViewProtocol.swift | 2 -- 28 files changed, 108 insertions(+), 111 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift b/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift index b437a56f..d23a2606 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift @@ -71,7 +71,7 @@ open class CaretLink: Button, MVMCoreUIViewConstrainingProtocol { } public override func updateView(_ size: CGFloat) { - titleLabel?.font = MFStyler.fontB1() + titleLabel?.font = MFStyler.fontBoldBodySmall() } //------------------------------------------------------ diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift index 35294457..d7413e07 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift @@ -6,9 +6,9 @@ // Copyright © 2020 Verizon Wireless. All rights reserved. // -import Foundation import UIKit + open class RadioSwatch: Control { //-------------------------------------------------- // MARK: - Properties diff --git a/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/NumericIndicatorView.swift b/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/NumericIndicatorView.swift index 3585be05..04ea2fcd 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/NumericIndicatorView.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/CarouselIndicator/NumericIndicatorView.swift @@ -16,7 +16,7 @@ open class NumericIndicatorView: CarouselIndicator { /// Text to display the current count of total pages for viewing. open var pageCount: Label = { - let label = Label.commonLabelB2(true) + let label = Label.createLabelRegularBodySmall(true) label.isAccessibilityElement = false label.setContentCompressionResistancePriority(.required, for: .vertical) label.textAlignment = .center diff --git a/MVMCoreUI/Atomic/Atoms/Views/CheckboxLabel.swift b/MVMCoreUI/Atomic/Atoms/Views/CheckboxLabel.swift index 5d4f68be..9d203ea9 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/CheckboxLabel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/CheckboxLabel.swift @@ -13,7 +13,7 @@ //-------------------------------------------------- public let checkbox = Checkbox() - public let label = Label.commonLabelB2(true) + public let label = Label.createLabelRegularBodySmall(true) //-------------------------------------------------- // MARK: - Properties diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyText.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyText.swift index 69bdbbba..8826a239 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyText.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyText.swift @@ -12,6 +12,7 @@ import Foundation //-------------------------------------------------- // MARK: - Outlets //-------------------------------------------------- + let headlineBody = HeadlineBody(frame: .zero) //------------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/FourColumn/ListFourColumnDataUsageListItem.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/FourColumn/ListFourColumnDataUsageListItem.swift index 2377a1f2..a42b6797 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/FourColumn/ListFourColumnDataUsageListItem.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/FourColumn/ListFourColumnDataUsageListItem.swift @@ -14,10 +14,10 @@ import Foundation // MARK: - Outlets //----------------------------------------------------- var stack: Stack - let label1 = Label.commonLabelB2(true) - let label2 = Label.commonLabelB2(true) - let label3 = Label.commonLabelB2(true) - let label4 = Label.commonLabelB2(true) + let label1 = Label.createLabelRegularBodySmall(true) + let label2 = Label.createLabelRegularBodySmall(true) + let label3 = Label.createLabelRegularBodySmall(true) + let label4 = Label.createLabelRegularBodySmall(true) let arrow = Arrow(frame: .zero) let arrowAndLabel2Stack: Stack @@ -69,9 +69,9 @@ import Foundation open override func reset() { super.reset() - label1.styleB2(true) - label2.styleB2(true) - label3.styleB2(true) - label4.styleB2(true) + label1.styleRegularBodySmall(true) + label2.styleRegularBodySmall(true) + label3.styleRegularBodySmall(true) + label4.styleRegularBodySmall(true) } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaret.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaret.swift index 7031e239..db7decbd 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaret.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaret.swift @@ -6,7 +6,6 @@ // Copyright © 2020 Verizon Wireless. All rights reserved. // -import Foundation import UIKit @objcMembers open class ListLeftVariableIconWithRightCaret: TableViewCell { @@ -15,8 +14,8 @@ import UIKit // MARK: - Outlets //------------------------------------------------------- let leftImage = LoadImageView(pinnedEdges: .all) - let leftLabel = Label.commonLabelB2(true) - let rightLabel = Label.commonLabelB2(true) + let leftLabel = Label.createLabelRegularBodySmall(true) + let rightLabel = Label.createLabelRegularBodySmall(true) var stack: Stack //----------------------------------------------------- @@ -64,7 +63,7 @@ import UIKit open override func reset() { super.reset() - leftLabel.styleB2(true) - rightLabel.styleB2(true) + leftLabel.styleRegularBodySmall(true) + rightLabel.styleRegularBodySmall(true) } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextAllTextAndLinks.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextAllTextAndLinks.swift index 599d0cdf..2291c080 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextAllTextAndLinks.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextAllTextAndLinks.swift @@ -15,10 +15,10 @@ import Foundation //----------------------------------------------------- var stack: Stack - let eyebrow = Label.commonLabelB3(true) - let headline = Label.commonLabelH3(true) - let subHeadline = Label.commonLabelB1(true) - let body = Label.commonLabelB2(true) + let eyebrow = Label.createLabelRegularMicro(true) + let headline = Label.createLabelBoldTitleMedium(true) + let subHeadline = Label.createLabelBoldBodySmall(true) + let body = Label.createLabelRegularBodySmall(true) let link = Link() //----------------------------------------------------- @@ -62,9 +62,9 @@ import Foundation open override func reset() { super.reset() - eyebrow.styleB3(true) - headline.styleH3(true) - subHeadline.styleB1(true) - body.styleB2(true) + eyebrow.styleRegularMicro(true) + headline.styleBoldTitleMedium(true) + subHeadline.styleBoldBodySmall(true) + body.styleRegularBodySmall(true) } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRVWheel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRVWheel.swift index f7c65dbe..40579a09 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRVWheel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRVWheel.swift @@ -9,8 +9,8 @@ import Foundation @objcMembers open class ListRVWheel: TableViewCell { let wheel = Wheel(frame: .zero) - let leftLabel = Label.commonLabelB1(true) - let rightLabel = Label.commonLabelB2(true) + let leftLabel = Label.createLabelBoldBodySmall(true) + let rightLabel = Label.createLabelRegularBodySmall(true) var stack: Stack //----------------------------------------------------- @@ -54,8 +54,8 @@ import Foundation //------------------------------------------------- open override func reset() { super.reset() - leftLabel.styleB1(true) - rightLabel.styleB2(true) + leftLabel.styleBoldBodySmall(true) + rightLabel.styleRegularBodySmall(true) } public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePayments.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePayments.swift index 505f9c48..ce73c082 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePayments.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePayments.swift @@ -13,7 +13,7 @@ import Foundation //----------------------------------------------------- // MARK: - Outlets //------------------------------------------------------- - let leftLabel = Label.commonLabelB1(true) + let leftLabel = Label.createLabelBoldBodySmall(true) let rightImage = LoadImageView(pinnedEdges: .all) var stack: Stack @@ -57,6 +57,6 @@ import Foundation open override func reset() { super.reset() - leftLabel.styleB1(true) + leftLabel.styleBoldBodySmall(true) } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePriceChangeAllTextAndLinks.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePriceChangeAllTextAndLinks.swift index 7a74de6e..ab135eb6 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePriceChangeAllTextAndLinks.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePriceChangeAllTextAndLinks.swift @@ -15,7 +15,7 @@ import Foundation //----------------------------------------------------- public let eyebrowHeadlineBodyLink = EyebrowHeadlineBodyLink(frame: .zero) public let arrow = Arrow(frame: .zero) - public let rightLabel = Label.commonLabelB2(true) + public let rightLabel = Label.createLabelRegularBodySmall(true) private let stack: Stack private let arrowStackItem: StackItem private let rightLabelStackItem: StackItem diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePriceChangeBodyText.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePriceChangeBodyText.swift index 2b87294a..63e90d34 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePriceChangeBodyText.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariablePriceChangeBodyText.swift @@ -15,7 +15,7 @@ import Foundation private let stack: Stack public let headlineBody = HeadlineBody(frame: .zero) public let arrow = Arrow(frame: .zero) - public let rightLabel = Label.commonLabelB2(true) + public let rightLabel = Label.createLabelRegularBodySmall(true) let arrowAndRightLabelStack: Stack diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableTotalData.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableTotalData.swift index abef078a..bb6ebd9e 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableTotalData.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableTotalData.swift @@ -14,8 +14,8 @@ import Foundation // MARK: - Outlets //----------------------------------------------------- public var stack: Stack - public let leftLabel = Label.commonLabelB1(true) - public let rightLabel = Label.commonLabelB2(true) + public let leftLabel = Label.createLabelBoldBodySmall(true) + public let rightLabel = Label.createLabelRegularBodySmall(true) public let bar = Line() //----------------------------------------------------- @@ -61,8 +61,8 @@ import Foundation open override func reset() { super.reset() - leftLabel.styleB1(true) - rightLabel.styleB2(true) + leftLabel.styleBoldBodySmall(true) + rightLabel.styleRegularBodySmall(true) bar.setStyle(.heavy) } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnCompareChanges.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnCompareChanges.swift index c007b8c7..e9a78f1b 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnCompareChanges.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnCompareChanges.swift @@ -13,15 +13,15 @@ import Foundation //------------------------------------------------------- // MARK: - Outlets //------------------------------------------------------- - let leftHeadline1 = Label.commonLabelB1(true) - let leftHeadline2 = Label.commonLabelB1(true) - let leftHeadline3 = Label.commonLabelB1(true) - let leftBody = Label.commonLabelB2(true) + let leftHeadline1 = Label.createLabelBoldBodySmall(true) + let leftHeadline2 = Label.createLabelBoldBodySmall(true) + let leftHeadline3 = Label.createLabelBoldBodySmall(true) + let leftBody = Label.createLabelRegularBodySmall(true) let leftLink = Link() - let rightHeadline1 = Label.commonLabelB1(true) - let rightHeadline2 = Label.commonLabelB1(true) - let rightHeadline3 = Label.commonLabelB1(true) - let rightBody = Label.commonLabelB2(true) + let rightHeadline1 = Label.createLabelBoldBodySmall(true) + let rightHeadline2 = Label.createLabelBoldBodySmall(true) + let rightHeadline3 = Label.createLabelBoldBodySmall(true) + let rightBody = Label.createLabelRegularBodySmall(true) let rightLink = Link() let containingStack: Stack @@ -97,14 +97,14 @@ import Foundation open override func reset() { super.reset() - leftHeadline1.styleB1(true) - leftHeadline2.styleB1(true) - leftHeadline3.styleB1(true) - leftBody.styleB2(true) - rightHeadline1.styleB1(true) - rightHeadline2.styleB1(true) - rightHeadline3.styleB1(true) - rightBody.styleB2(true) + leftHeadline1.styleBoldBodySmall(true) + leftHeadline2.styleBoldBodySmall(true) + leftHeadline3.styleBoldBodySmall(true) + leftBody.styleRegularBodySmall(true) + rightHeadline1.styleBoldBodySmall(true) + rightHeadline2.styleBoldBodySmall(true) + rightHeadline3.styleBoldBodySmall(true) + rightBody.styleRegularBodySmall(true) } public override class func estimatedHeight(with molecule: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDescription.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDescription.swift index 9f4f60b2..ecae14e8 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDescription.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDescription.swift @@ -13,10 +13,10 @@ import Foundation //----------------------------------------------------- // MARK: - Outlets //------------------------------------------------------- - public let leftHeadline = Label.commonLabelB1(true) - public let leftBody = Label.commonLabelB2(true) - public let rightLabel = Label.commonLabelB2(true) - public let rightSubLabel = Label.commonLabelB2(true) + public let leftHeadline = Label.createLabelBoldBodySmall(true) + public let leftBody = Label.createLabelRegularBodySmall(true) + public let rightLabel = Label.createLabelRegularBodySmall(true) + public let rightSubLabel = Label.createLabelRegularBodySmall(true) public let view = MVMCoreUICommonViewsUtility.commonView() public let leftVerticalStack: UIStackView @@ -86,9 +86,9 @@ import Foundation super.reset() leftVerticalStack.reset() rightVerticalStack.reset() - leftHeadline.styleB1(true) - leftBody.styleB2(true) - rightLabel.styleB2(true) - rightSubLabel.styleB2(true) + leftHeadline.styleBoldBodySmall(true) + leftBody.styleRegularBodySmall(true) + rightLabel.styleRegularBodySmall(true) + rightSubLabel.styleRegularBodySmall(true) } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDetails.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDetails.swift index 43836cf0..3fbac0f3 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDetails.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDetails.swift @@ -10,8 +10,8 @@ import UIKit @objcMembers open class ListTwoColumnPriceDetails: TableViewCell { - let leftLabel = Label.commonLabelB2(true) - let rightLabel = Label.commonLabelB2(true) + let leftLabel = Label.createLabelRegularBodySmall(true) + let rightLabel = Label.createLabelRegularBodySmall(true) let view = MVMCoreUICommonViewsUtility.commonView() // MARK: - MFViewProtocol @@ -44,8 +44,8 @@ import UIKit super.reset() leftLabel.reset() rightLabel.reset() - leftLabel.styleB2(true) - rightLabel.styleB2(true) + leftLabel.styleRegularBodySmall(true) + rightLabel.styleRegularBodySmall(true) } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnFullWidthTextDividerSubsection.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnFullWidthTextDividerSubsection.swift index c1583583..18529ebe 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnFullWidthTextDividerSubsection.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnFullWidthTextDividerSubsection.swift @@ -13,8 +13,8 @@ import Foundation // MARK: - Outlets //----------------------------------------------------- public var stack: Stack - public let headline = Label.commonLabelB1(true) - public let body = Label.commonLabelB2(true) + public let headline = Label.createLabelBoldBodySmall(true) + public let body = Label.createLabelRegularBodySmall(true) // MARK: - Initializers public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { @@ -50,7 +50,7 @@ import Foundation open override func reset() { super.reset() - headline.styleB1(true) - body.styleB2(true) + headline.styleBoldBodySmall(true) + body.styleRegularBodySmall(true) } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerShort.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerShort.swift index ec65967d..3198a72d 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerShort.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerShort.swift @@ -13,8 +13,8 @@ import Foundation // MARK: - Outlets //----------------------------------------------------- public var stack: Stack - public let headline = Label.commonLabelH3(true) - public let body = Label.commonLabelB2(true) + public let headline = Label.createLabelBoldTitleMedium(true) + public let body = Label.createLabelRegularBodySmall(true) // MARK: - Initializers public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { @@ -50,7 +50,7 @@ import Foundation open override func reset() { super.reset() - headline.styleH3(true) - body.styleB2(true) + headline.styleBoldTitleMedium(true) + body.styleRegularBodySmall(true) } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift index 1f2bcd6f..d725ff61 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift @@ -13,8 +13,8 @@ import Foundation // MARK: - Outlets //----------------------------------------------------- public var stack: Stack - public let headline = Label.commonLabelH3(true) - public let body = Label.commonLabelB2(true) + public let headline = Label.createLabelBoldTitleMedium(true) + public let body = Label.createLabelRegularBodySmall(true) // MARK: - Initializers public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { @@ -50,7 +50,7 @@ import Foundation open override func reset() { super.reset() - headline.styleH3(true) - body.styleB2(true) + headline.styleBoldTitleMedium(true) + body.styleRegularBodySmall(true) } } diff --git a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/ImageHeadlineBody.swift b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/ImageHeadlineBody.swift index 35f3ac29..ff770da3 100644 --- a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/ImageHeadlineBody.swift +++ b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/ImageHeadlineBody.swift @@ -18,7 +18,7 @@ import UIKit open override func setupView() { super.setupView() - headlineBody.headlineLabel.styleB1(true) + headlineBody.headlineLabel.styleBoldBodySmall(true) headlineBody.spaceBetweenLabelsConstant = 0 imageView.addSizeConstraintsForAspectRatio = true @@ -43,7 +43,7 @@ import UIKit open override func reset() { super.reset() headlineBody.reset() - headlineBody.headlineLabel.styleB1(true) + headlineBody.headlineLabel.styleBoldBodySmall(true) headlineBody.spaceBetweenLabelsConstant = 0 imageView.reset() } diff --git a/MVMCoreUI/Atomic/Molecules/LeftRightViews/ActionDetailWithImage.swift b/MVMCoreUI/Atomic/Molecules/LeftRightViews/ActionDetailWithImage.swift index 5dd6c722..ab0924b2 100644 --- a/MVMCoreUI/Atomic/Molecules/LeftRightViews/ActionDetailWithImage.swift +++ b/MVMCoreUI/Atomic/Molecules/LeftRightViews/ActionDetailWithImage.swift @@ -92,8 +92,8 @@ import UIKit private func setDefaultState() { - headlineBodyButton.headlineBody.headlineLabel.font = MFStyler.fontH3() - headlineBodyButton.headlineBody.messageLabel.font = MFStyler.fontB3() + headlineBodyButton.headlineBody.headlineLabel.font = MFStyler.fontBoldTitleMedium() + headlineBodyButton.headlineBody.messageLabel.font = MFStyler.fontRegularMicro() imageLoader.imageView.contentMode = .scaleAspectFit imageLoader.addSizeConstraintsForAspectRatio = true buttonHeaderPadding = PaddingTwo diff --git a/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabels.swift b/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabels.swift index 7eb3282b..5751fbc2 100644 --- a/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabels.swift +++ b/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabels.swift @@ -10,10 +10,10 @@ import UIKit @objcMembers public class CornerLabels: View { var middleView: UIView? - let topLeftLabel = Label.commonLabelB1(true) - let topRightLabel = Label.commonLabelB1(true) - let bottomLeftLabel = Label.commonLabelB3(true) - let bottomRightLabel = Label.commonLabelB3(true) + let topLeftLabel = Label.createLabelBoldBodySmall(true) + let topRightLabel = Label.createLabelBoldBodySmall(true) + let bottomLeftLabel = Label.createLabelRegularMicro(true) + let bottomRightLabel = Label.createLabelRegularMicro(true) let topLabelsView = MVMCoreUICommonViewsUtility.commonView() let bottomLabelsView = MVMCoreUICommonViewsUtility.commonView() @@ -151,10 +151,10 @@ import UIKit } func styleDefault() { - topLeftLabel.styleB1(true) - topRightLabel.styleB1(true) - bottomLeftLabel.styleB3(true) - bottomRightLabel.styleB3(true) + topLeftLabel.styleBoldBodySmall(true) + topRightLabel.styleBoldBodySmall(true) + bottomLeftLabel.styleRegularMicro(true) + bottomRightLabel.styleRegularMicro(true) } public class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/BGImageHeadlineBodyButtonModel.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/BGImageHeadlineBodyButtonModel.swift index f6fd4fcf..040b368c 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/BGImageHeadlineBodyButtonModel.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/BGImageHeadlineBodyButtonModel.swift @@ -6,7 +6,6 @@ // Copyright © 2020 Verizon Wireless. All rights reserved. // -import Foundation import UIKit public class BGImageHeadlineBodyButtonModel: ContainerModel, MoleculeModelProtocol { diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift index dd04140b..9ad26015 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift @@ -14,9 +14,9 @@ import UIKit //-------------------------------------------------- public let stack = Stack(frame: .zero) - public let eyebrow = Label.commonLabelB3(true) - public let headline = Label.commonLabelB1(true) - public let body = Label.commonLabelB2(true) + public let eyebrow = Label.createLabelRegularMicro(true) + public let headline = Label.createLabelBoldBodySmall(true) + public let body = Label.createLabelRegularBodySmall(true) public let link = Link() var castModel: EyebrowHeadlineBodyLinkModel? { @@ -48,9 +48,9 @@ import UIKit open override func reset() { super.reset() stack.reset() - eyebrow.styleB3(true) - headline.styleB1(true) - body.styleB2(true) + eyebrow.styleRegularMicro(true) + headline.styleBoldBodySmall(true) + body.styleRegularBodySmall(true) } //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBody.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBody.swift index b36525f9..4e9b97dd 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBody.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBody.swift @@ -10,8 +10,8 @@ import UIKit open class HeadlineBody: View { - let headlineLabel = Label.commonLabelH2(true) - let messageLabel = Label.commonLabelB2(true) + let headlineLabel = Label.createLabelBoldTitleLarge(true) + let messageLabel = Label.createLabelRegularBodySmall(true) var spaceBetweenLabelsConstant = PaddingOne var spaceBetweenLabels: NSLayoutConstraint? var leftConstraintTitle: NSLayoutConstraint? @@ -39,26 +39,26 @@ open class HeadlineBody: View { } func styleLandingPageHeader() { - headlineLabel.styleH1(true) - messageLabel.styleB2(true) + headlineLabel.styleTitle2XLarge(true) + messageLabel.styleRegularBodySmall(true) spaceBetweenLabelsConstant = PaddingTwo } func stylePageHeader() { - headlineLabel.styleH2(true) - messageLabel.styleB2(true) + headlineLabel.styleBoldTitleLarge(true) + messageLabel.styleRegularBodySmall(true) spaceBetweenLabelsConstant = PaddingOne } func styleListItem() { - headlineLabel.styleB1(true) - messageLabel.styleB2(true) + headlineLabel.styleBoldBodySmall(true) + messageLabel.styleRegularBodySmall(true) spaceBetweenLabelsConstant = 0 } func styleListItemDivider() { - headlineLabel.styleH3(true) - messageLabel.styleB2(true) + headlineLabel.styleBoldTitleMedium(true) + messageLabel.styleRegularBodySmall(true) spaceBetweenLabelsConstant = 0 } diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyButton.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyButton.swift index 35522146..c1c3a709 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyButton.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyButton.swift @@ -82,8 +82,8 @@ import UIKit private func defaultState() { - headlineBody.headlineLabel.font = MFStyler.fontH3() - headlineBody.messageLabel.font = MFStyler.fontB3() + headlineBody.headlineLabel.font = MFStyler.fontBoldTitleMedium() + headlineBody.messageLabel.font = MFStyler.fontRegularMicro() button.styleSecondary() button.isHidden = false buttonHeadlinePadding = PaddingTwo diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeView.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeView.swift index a7c9e20d..30a82134 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeView.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeView.swift @@ -9,7 +9,7 @@ import Foundation open class StringAndMoleculeView: View { - var label = Label.commonLabelB2(true) + var label = Label.createLabelRegularBodySmall(true) var molecule: MoleculeViewProtocol var leftWidthConstraint: NSLayoutConstraint? diff --git a/MVMCoreUI/Atomic/Protocols/MoleculeViewProtocol.swift b/MVMCoreUI/Atomic/Protocols/MoleculeViewProtocol.swift index 91f461dd..a8600c79 100644 --- a/MVMCoreUI/Atomic/Protocols/MoleculeViewProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/MoleculeViewProtocol.swift @@ -6,8 +6,6 @@ // Copyright © 2019 Verizon Wireless. All rights reserved. // -import Foundation - import UIKit import MVMCore.MVMCoreViewProtocol From 4fd654c3725a5a49edb486f6bf52daf7246353e9 Mon Sep 17 00:00:00 2001 From: "Suresh, Kamlesh" Date: Mon, 11 May 2020 20:05:51 -0400 Subject: [PATCH 35/67] code review --- MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift index 0558fda5..9d7c8927 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift @@ -254,7 +254,7 @@ import UIKit self.showError = showError if showError { observingTextFieldDelegate?.isValid?(textfield: self) - entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor + entryFieldContainer.originalUI() } else { observingTextFieldDelegate?.isInvalid?(textfield: self) } @@ -276,8 +276,8 @@ import UIKit @objc func endInputing() { resignFirstResponder() - // If user did not enter text int ethe field dont show error yet. - if text?.count ?? 0 == 0{ + // Don't show error till user starts typing. + guard text?.count ?? 0 != 0 else { return } From a2a1f9563109ffa544ab741db311f1ac8d4ee9db Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Tue, 12 May 2020 18:25:43 +0530 Subject: [PATCH 36/67] Code changes as per review comments. --- MVMCoreUI.xcodeproj/project.pbxproj | 2 +- .../DesignedComponents/Headers/HeadersH2Buttons.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 6d308156..1b66b097 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -959,8 +959,8 @@ AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */, AA26850D244840C300CE34CC /* HeadersH2TinyButtonModel.swift */, AA26850B244840AE00CE34CC /* HeadersH2TinyButton.swift */, - AA104B1924474A66004D2810 /* HeadersH2Buttons.swift */, AA104B1B24474A76004D2810 /* HeadersH2ButtonsModel.swift */, + AA104B1924474A66004D2810 /* HeadersH2Buttons.swift */, ); path = Headers; sourceTree = ""; diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift index 3775408c..b647d32f 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift @@ -21,7 +21,8 @@ import Foundation //------------------------------------------------------- open override func setupView() { super.setupView() - stack = Stack.createStack(with: [(view: headlineBody, model: StackItemModel(horizontalAlignment: .fill)), (view: buttons, model: StackItemModel(spacing: PaddingDefaultVerticalSpacing3, horizontalAlignment: .leading))], axis: .vertical) + stack.model = StackModel(molecules: [], axis: .vertical, spacing: 0) + stack.set(with: [(view: headlineBody, model: StackItemModel(horizontalAlignment: .fill)), (view: buttons, model: StackItemModel(spacing: PaddingDefaultVerticalSpacing3, horizontalAlignment: .fill))]) headlineBody.stylePageHeader() addMolecule(stack) stack.restack() @@ -44,6 +45,5 @@ import Foundation open override func reset() { super.reset() headlineBody.stylePageHeader() - buttons.reset() } } From 3cbd9b53a8646c38720573fd0a893652a9c60b99 Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Tue, 12 May 2020 18:56:10 +0530 Subject: [PATCH 37/67] 18972(iOS - List - ProgressBar - Thin) story initial commit. --- MVMCoreUI.xcodeproj/project.pbxproj | 8 ++ MVMCoreUI/Atomic/MoleculeObjectMapping.swift | 1 + .../List/ListProgressBarThin.swift | 89 +++++++++++++++++++ .../List/ListProgressBarThinModel.swift | 69 ++++++++++++++ 4 files changed, 167 insertions(+) create mode 100644 MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift create mode 100644 MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index ec7e68b0..35697500 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -196,6 +196,8 @@ AA85236C244435A20059CC1E /* RadioSwatchCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */; }; AAA74A172410C04600080241 /* HeadersH2NoButtonsBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */; }; AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */; }; + AAB7EDEF246ADA1600E54929 /* ListProgressBarThinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB7EDEE246ADA1600E54929 /* ListProgressBarThinModel.swift */; }; + AAB7EDF1246ADA2A00E54929 /* ListProgressBarThin.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB7EDF0246ADA2A00E54929 /* ListProgressBarThin.swift */; }; AAB9C10824346F4B00151545 /* RadioSwatches.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB9C10724346F4B00151545 /* RadioSwatches.swift */; }; AAB9C10A243496DD00151545 /* RadioSwatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB9C109243496DD00151545 /* RadioSwatch.swift */; }; AAC6F167243332E400F295C1 /* RadioSwatchesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC6F166243332E400F295C1 /* RadioSwatchesModel.swift */; }; @@ -607,6 +609,8 @@ AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchCollectionViewCell.swift; sourceTree = ""; }; AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyText.swift; sourceTree = ""; }; AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyTextModel.swift; sourceTree = ""; }; + AAB7EDEE246ADA1600E54929 /* ListProgressBarThinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListProgressBarThinModel.swift; sourceTree = ""; }; + AAB7EDF0246ADA2A00E54929 /* ListProgressBarThin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListProgressBarThin.swift; sourceTree = ""; }; AAB9C10724346F4B00151545 /* RadioSwatches.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatches.swift; sourceTree = ""; }; AAB9C109243496DD00151545 /* RadioSwatch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatch.swift; sourceTree = ""; }; AAC6F166243332E400F295C1 /* RadioSwatchesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchesModel.swift; sourceTree = ""; }; @@ -1240,6 +1244,8 @@ D20492F12434CB5F00A5EED6 /* FourColumn */, AA4FC2A323F4F69600E251DB /* RightVariable */, D22B38EB23F4E0AE00490EF6 /* LeftVariable */, + AAB7EDEE246ADA1600E54929 /* ListProgressBarThinModel.swift */, + AAB7EDF0246ADA2A00E54929 /* ListProgressBarThin.swift */, ); path = List; sourceTree = ""; @@ -2180,6 +2186,7 @@ C695A68123C9830D00BFB94E /* NumberedListModel.swift in Sources */, 01EB3684236097C0006832FA /* MoleculeModelProtocol.swift in Sources */, D27CD4102339057800C1DC07 /* EyebrowHeadlineBodyLink.swift in Sources */, + AAB7EDF1246ADA2A00E54929 /* ListProgressBarThin.swift in Sources */, 8D070BB2241B56AD0099AC56 /* ListRightVariableTotalData.swift in Sources */, D264FAA5243F66A500D98315 /* CollectionTemplateItemProtocol.swift in Sources */, D29DF11D21E684A9003B2FB9 /* MVMCoreUISplitViewController.m in Sources */, @@ -2264,6 +2271,7 @@ EA5124FD243601600051A3A4 /* BGImageHeadlineBodyButton.swift in Sources */, 0105618D224BBE7700E1557D /* FormValidator.swift in Sources */, 01509D912327ECE600EF99AA /* CornerLabels.swift in Sources */, + AAB7EDEF246ADA1600E54929 /* ListProgressBarThinModel.swift in Sources */, D21B7F75243BAC8900051ABF /* CarouselItem.swift in Sources */, C695A69823C990C200BFB94E /* DoughnutChartView.swift in Sources */, 8D3BA9BD2433787000D341BA /* ListThreeColumnInternationalDataDividerModel.swift in Sources */, diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index a9e86d50..cb108207 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -162,6 +162,7 @@ import Foundation MoleculeObjectMapping.shared()?.register(viewClass: ListThreeColumnInternationalData.self, viewModelClass: ListThreeColumnInternationalDataModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListThreeColumnDataUsage.self, viewModelClass: ListThreeColumnDataUsageModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListFourColumnDataUsageListItem.self, viewModelClass: ListFourColumnDataUsageListItemModel.self) + MoleculeObjectMapping.shared()?.register(viewClass: ListProgressBarThin.self, viewModelClass: ListProgressBarThinModel.self) // Designed Section Dividers MoleculeObjectMapping.shared()?.register(viewClass: ListFourColumnDataUsageDivider.self, viewModelClass: ListFourColumnDataUsageDividerModel.self) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift new file mode 100644 index 00000000..69e26ea2 --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift @@ -0,0 +1,89 @@ +// +// ListProgressBarThin.swift +// MVMCoreUI +// +// Created by Lekshmi S on 12/05/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation +@objcMembers open class ListProgressBarThin: TableViewCell { + //-------------------------------------------------- + // MARK: - Outlets + //-------------------------------------------------- + let progressBar = ProgressBar() + let leftHeadline = Label.commonLabelB1(true) + let leftBody = Label.commonLabelB2(true) + let leftBody2 = Label.commonLabelB2(true) + let bar = Line() + let rightLabel = Label.commonLabelB2(true) + public var horizontalStack: Stack + public var verticalStack: Stack + public var stack: Stack + + //------------------------------------------------------ + // MARK: - Initializers + //------------------------------------------------------ + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + verticalStack = Stack.createStack(with: [(view: leftHeadline, model: StackItemModel(horizontalAlignment: .leading)), + (view: leftBody, model: StackItemModel(horizontalAlignment: .leading)), + (view: leftBody2, model: StackItemModel(horizontalAlignment: .leading))], + axis: .vertical, spacing: 0) + horizontalStack = Stack.createStack(with: [(view: verticalStack, model: StackItemModel(horizontalAlignment: .leading, verticalAlignment: .leading)), + (view: bar, model: StackItemModel(horizontalAlignment: .fill)), (view: rightLabel, model: StackItemModel(spacing: 5, horizontalAlignment: .fill))], + axis: .horizontal) + stack = Stack.createStack(with: [(view: horizontalStack, model: StackItemModel(horizontalAlignment: .fill)), (view: progressBar, model: StackItemModel(spacing: 20, horizontalAlignment: .fill))], axis: .vertical) + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open override func alignAccessoryToHero() -> CGPoint? { + let heroCenter = super.alignAccessoryToHero() + return heroCenter + } + + //------------------------------------------------------- + // MARK: - View Lifecycle + //------------------------------------------------------- + open override func setupView() { + super.setupView() + bar.widthAnchor.constraint(equalToConstant: 20).isActive = true + rightLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal) + rightLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .horizontal) + rightLabel.numberOfLines = 1 + addMolecule(stack) + stack.restack() + horizontalStack.restack() + verticalStack.restack() + } + + //------------------------------------------------------ + // MARK: - Molecule + //------------------------------------------------------ + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListProgressBarThinModel else { return } + verticalStack.updateContainedMolecules(with: [model.leftHeadline, + model.leftBody, + model.leftBody2],delegateObject, additionalData) + progressBar.set(with: model.progressBar, delegateObject, additionalData) + bar.set(with: model.bar, delegateObject, additionalData) + rightLabel.set(with: model.rightLabel, delegateObject, additionalData) + } + + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return 120 + } + + open override func reset() { + super.reset() + leftHeadline.styleB1(true) + leftBody.styleB2(true) + leftBody2.styleB2(true) + rightLabel.styleB2(true) + bar.setStyle(.medium) + } +} diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift new file mode 100644 index 00000000..2e0b7cdb --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift @@ -0,0 +1,69 @@ +// +// ListProgressBarThinModel.swift +// MVMCoreUI +// +// Created by Lekshmi S on 12/05/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation +public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol { + public static var identifier = "listPrgBarThin" + public var progressBar: ProgressBarModel + public var leftHeadline: LabelModel? + public var leftBody: LabelModel? + public var leftBody2: LabelModel? + public var bar: LineModel + public var rightLabel: LabelModel + + public init(progressBar: ProgressBarModel, leftHeadline: LabelModel, leftBody: LabelModel, leftBody2: LabelModel, bar: LineModel, rightLabel: LabelModel) { + self.progressBar = progressBar + self.leftHeadline = leftHeadline + self.leftBody = leftBody + self.leftBody2 = leftBody2 + self.bar = bar + self.rightLabel = rightLabel + super.init() + } + + override public func setDefaults() { + super.setDefaults() + bar.type = .medium + if bar.backgroundColor == nil { + bar.backgroundColor = Color(uiColor: .gray) + } + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case progressBar + case leftHeadline + case leftBody + case leftBody2 + case line + case rightLabel + } + + public required init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + progressBar = try typeContainer.decode(ProgressBarModel.self, forKey:.progressBar) + leftHeadline = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .leftHeadline) + leftBody = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .leftBody) + leftBody2 = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .leftBody2) + bar = try typeContainer.decode(LineModel.self, forKey: .line) + rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(progressBar, forKey: .progressBar) + try container.encodeIfPresent(leftHeadline, forKey: .leftHeadline) + try container.encodeIfPresent(leftBody, forKey: .leftBody) + try container.encodeIfPresent(leftBody2, forKey: .leftBody2) + try container.encode(bar, forKey: .line) + try container.encode(rightLabel, forKey: .rightLabel) + } +} From 7729529a9ca545634900f9637519b58079749ccd Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 12 May 2020 13:03:17 -0400 Subject: [PATCH 38/67] efficiency changes --- .../Headers/HeadersH2Buttons.swift | 16 +++++++++++++--- .../Headers/HeadersH2TinyButton.swift | 15 +++++++++++++-- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift index b647d32f..57e62d24 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2Buttons.swift @@ -14,15 +14,25 @@ import Foundation //-------------------------------------------------- public let headlineBody = HeadlineBody(frame: .zero) public let buttons = TwoButtonView(frame: .zero) - public var stack = Stack(frame: .zero) + public let stack: Stack + + //------------------------------------------------------- + // MARK: - Initializers + //------------------------------------------------------- + public override init(frame: CGRect) { + stack = Stack.createStack(with: [headlineBody, buttons], spacing: PaddingDefaultVerticalSpacing3) + super.init(frame: frame) + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } //------------------------------------------------------- // MARK: - View Lifecycle //------------------------------------------------------- open override func setupView() { super.setupView() - stack.model = StackModel(molecules: [], axis: .vertical, spacing: 0) - stack.set(with: [(view: headlineBody, model: StackItemModel(horizontalAlignment: .fill)), (view: buttons, model: StackItemModel(spacing: PaddingDefaultVerticalSpacing3, horizontalAlignment: .fill))]) headlineBody.stylePageHeader() addMolecule(stack) stack.restack() diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2TinyButton.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2TinyButton.swift index 0991eec6..788a6a89 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2TinyButton.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/Headers/HeadersH2TinyButton.swift @@ -14,7 +14,19 @@ import Foundation //-------------------------------------------------- public let headlineBody = HeadlineBody(frame: .zero) public let button = PillButton(frame: .zero) - public var stack = Stack(frame: .zero) + public let stack: Stack + + //------------------------------------------------------- + // MARK: - Initializers + //------------------------------------------------------- + public override init(frame: CGRect) { + stack = Stack.createStack(with: [(view: headlineBody, model: StackItemModel(horizontalAlignment: .fill)), (view: button, model: StackItemModel(spacing: spacingBetwenHeadlineBodyAndButton, horizontalAlignment: .leading))], axis: .vertical) + super.init(frame: frame) + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } //------------------------------------------------------ // MARK: - Constants @@ -26,7 +38,6 @@ import Foundation //------------------------------------------------------- open override func setupView() { super.setupView() - stack = Stack.createStack(with: [(view: headlineBody, model: StackItemModel(horizontalAlignment: .fill)), (view: button, model: StackItemModel(spacing: spacingBetwenHeadlineBodyAndButton, horizontalAlignment: .leading))], axis: .vertical) headlineBody.stylePageHeader() addMolecule(stack) stack.restack() From 64a99da609f2de5e674a8831796c1ff0a7f808f3 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 12 May 2020 15:30:32 -0400 Subject: [PATCH 39/67] latest changes --- .../Atoms/TextFields/TextViewEntryField.swift | 51 ++++++++----------- MVMCoreUI/BaseClasses/TextView.swift | 4 +- .../BaseControllers/ViewController.swift | 2 +- 3 files changed, 25 insertions(+), 32 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index a086b18b..a027017c 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -30,7 +30,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele // MARK: - Properties //-------------------------------------------------- - /// Validate on each entry in the textField. Default: true + /// Validate on each entry in the textView. Default: true public var validateEachCharacter: Bool = true private var observingForChange: Bool = false @@ -55,7 +55,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele if self.textView.isShowingPlaceholder { self.textView.textColor = self.textView.placeholderTextColor } else { - self.textView.textColor = enabled ? self.textViewEntryFieldModel?.enabledTextColor.uiColor : self.textViewEntryFieldModel?.disabledTextColor.uiColor + self.textView.textColor = (enabled ? self.textViewEntryFieldModel?.enabledTextColor : self.textViewEntryFieldModel?.disabledTextColor)?.uiColor } } } @@ -87,7 +87,10 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele /// Placeholder access for the textView. public var placeholder: String? { get { return textViewEntryFieldModel?.placeholder } - set { textViewEntryFieldModel?.placeholder = newValue } + set { + textViewEntryFieldModel?.placeholder = newValue + textView.placeholder = newValue ?? "" + } } //-------------------------------------------------- @@ -100,19 +103,19 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele // MARK: - Delegate Properties //-------------------------------------------------- - /// Holds a reference to the delegating class so this class can internally influence the TextField behavior as well. + /// Holds a reference to the delegating class so this class can internally influence the TextView behavior as well. private weak var proprietorTextDelegate: UITextViewDelegate? /// The delegate and block for validation. Validates if the text that the user has entered. - public weak var observingTextViewdDelegate: ObservingTextFieldDelegate? { + public weak var observingTextViewDelegate: ObservingTextFieldDelegate? { didSet { - if observingTextViewdDelegate != nil && !observingForChange { + if observingTextViewDelegate != nil && !observingForChange { observingForChange = true NotificationCenter.default.addObserver(self, selector: #selector(valueChanged), name: UITextView.textDidChangeNotification, object: textView) NotificationCenter.default.addObserver(self, selector: #selector(endInputing), name: UITextView.textDidEndEditingNotification, object: textView) NotificationCenter.default.addObserver(self, selector: #selector(startEditing), name: UITextView.textDidBeginEditingNotification, object: textView) - } else if observingTextViewdDelegate == nil && observingForChange { + } else if observingTextViewDelegate == nil && observingForChange { observingForChange = false NotificationCenter.default.removeObserver(self, name: UITextView.textDidChangeNotification, object: textView) NotificationCenter.default.removeObserver(self, name: UITextView.textDidEndEditingNotification, object: textView) @@ -131,12 +134,12 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele } @objc public func setBothTextDelegates(to delegate: (UITextViewDelegate & ObservingTextFieldDelegate)?) { - observingTextViewdDelegate = delegate + observingTextViewDelegate = delegate uiTextViewDelegate = delegate } open func setupTextViewToolbar() { - let observingDelegate = observingTextViewdDelegate ?? self + let observingDelegate = observingTextViewDelegate ?? self textView.inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate, action: #selector(observingDelegate.dismissFieldInput)) } @@ -161,17 +164,10 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele accessibilityElements = [titleLabel, textView, feedbackLabel] } - @objc open override func updateView(_ size: CGFloat) { - super.updateView(size) - - textView.font = Styler.Font.RegularBodyLarge.getFont() - layoutIfNeeded() - } - open override func reset() { super.reset() - textView.font = Styler.Font.RegularBodyLarge.getFont() + textView.reset() heightConstraint?.constant = 0 heightConstraint?.isActive = false } @@ -181,27 +177,26 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele //-------------------------------------------------- /// Validates the text of the entry field. - @objc public func validateTextField() { + @objc public func validateTextView() { text = textView.text if let isValid = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) { self.isValid = isValid } } - /// Executes on UITextField.textDidBeginEditingNotification + /// Executes on UITextView.textDidBeginEditingNotification @objc func startEditing() { isSelected = true - textView.becomeFirstResponder() + _ = textView.becomeFirstResponder() } - /// Executes on UITextField.textDidChangeNotification (each character entry) + /// Executes on UITextView.textDidChangeNotification (each character entry) @objc func valueChanged() { guard validateEachCharacter else { return } - isSelected = true - validateTextField() + validateTextView() } - /// Executes on UITextField.textDidEndEditingNotification + /// Executes on UITextView.textDidEndEditingNotification @objc func endInputing() { resignFirstResponder() if isValid { @@ -210,7 +205,6 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele } } - //-------------------------------------------------- // MARK: - UITextViewDelegate //-------------------------------------------------- @@ -233,7 +227,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele @objc public func textViewDidChange(_ textView: UITextView) { - validateTextField() + validateTextView() proprietorTextDelegate?.textViewDidChange?(textView) } @@ -305,10 +299,9 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele textView.inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate, action: #selector(textView.dismissFieldInput)) - if (model.selected ?? false) && !model.wasInitiallySelected { - model.wasInitiallySelected = true + if isSelected { DispatchQueue.main.async { - self.becomeFirstResponder() + _ = self.textView.becomeFirstResponder() } } } diff --git a/MVMCoreUI/BaseClasses/TextView.swift b/MVMCoreUI/BaseClasses/TextView.swift index 9ae48800..a5825dd8 100644 --- a/MVMCoreUI/BaseClasses/TextView.swift +++ b/MVMCoreUI/BaseClasses/TextView.swift @@ -25,7 +25,7 @@ import UIKit public var hideBlinkingCaret = false public var placeholder = "" - public var fontStyle: Styler.Font = Styler.Font.RegularBodySmall + public var fontStyle: Styler.Font = Styler.Font.RegularBodyLarge public var placeholderFontStyle: Styler.Font = Styler.Font.RegularMicro public var placeholderTextColor: UIColor = .mvmCoolGray3 @@ -181,6 +181,6 @@ import UIKit @objc open func dismissFieldInput(_ sender: TextView) { - _ = resignFirstResponder() + resignFirstResponder() } } diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index 0872b0e6..a10e0767 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -17,7 +17,7 @@ import UIKit public var manager: (UIViewController & MVMCoreViewManagerProtocol)? /// A temporary iVar backer for delegateObject() until we change the protocol - public let delegateObjectIVar: MVMCoreUIDelegateObject = { + public lazy var delegateObjectIVar: MVMCoreUIDelegateObject = { return MVMCoreUIDelegateObject.create(withDelegateForAll: self) }() From c3e6b49b815309cf639df51c66d2e639fdb895d0 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 12 May 2020 15:59:06 -0400 Subject: [PATCH 40/67] changes --- .../Atoms/TextFields/TextViewEntryField.swift | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index a027017c..ba1d377a 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -199,10 +199,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele /// Executes on UITextView.textDidEndEditingNotification @objc func endInputing() { resignFirstResponder() - if isValid { - showError = false - entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor - } + showError = !isValid } //-------------------------------------------------- @@ -266,6 +263,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele text = model.text uiTextViewDelegate = delegateObject?.uiTextViewDelegate + observingTextViewDelegate = delegateObject?.observingTextFieldDelegate if let accessibilityText = model.accessibilityText { accessibilityLabel = accessibilityText @@ -295,9 +293,10 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele if textView.isEditable { FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate) - let observingDelegate = delegateObject?.uiTextViewDelegate ?? self - textView.inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate, - action: #selector(textView.dismissFieldInput)) + setupTextViewToolbar() +// let observingDelegate = delegateObject?.uiTextViewDelegate ?? self +// textView.inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate, +// action: #selector(textView.dismissFieldInput)) if isSelected { DispatchQueue.main.async { From b4f8e4281759dedb60e62f2bc62c44128baf491d Mon Sep 17 00:00:00 2001 From: Kyle Matthew Hedden Date: Tue, 12 May 2020 16:06:22 -0400 Subject: [PATCH 41/67] code review items --- .../ScreenBrightnessModifierBehavior.swift | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift b/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift index b6712354..03464841 100644 --- a/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift +++ b/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift @@ -6,9 +6,9 @@ // Copyright © 2020 Verizon Wireless. All rights reserved. // -class ScreenBrightnessModifierBehavior: PageVisibilityBehavior { +public class ScreenBrightnessModifierBehavior: PageVisibilityBehavior { - static var identifier = "screenBrightnessModifier" + public static var identifier = "screenBrightnessModifier" @Clamping(range: 0...1) var screenBrightness: CGFloat @@ -16,38 +16,36 @@ class ScreenBrightnessModifierBehavior: PageVisibilityBehavior { //MARK:- PageVisibilityBehavior - func onPageShown() { + public func onPageShown() { changeScreenBrightness() } - func onPageHidden() { + public func onPageHidden() { restoreScreenBrightness() } //MARK:- Behavior func changeScreenBrightness() { - if originalScreenBrightness == nil { - originalScreenBrightness = UIScreen.main.brightness - UIScreen.main.brightness = screenBrightness - NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackground), name: UIApplication.willResignActiveNotification, object: nil) - } + if originalScreenBrightness != nil { return } + originalScreenBrightness = UIScreen.main.brightness + UIScreen.main.brightness = screenBrightness + NotificationCenter.default.addObserver(self, selector: #selector(willResignActive), name: UIApplication.willResignActiveNotification, object: nil) } func restoreScreenBrightness() { - if let originalScreenBrightness = originalScreenBrightness { - UIScreen.main.brightness = originalScreenBrightness - self.originalScreenBrightness = nil - NotificationCenter.default.removeObserver(self, name: UIApplication.willResignActiveNotification, object: nil) - } + guard let originalScreenBrightness = originalScreenBrightness else { return } + UIScreen.main.brightness = originalScreenBrightness + self.originalScreenBrightness = nil + NotificationCenter.default.removeObserver(self, name: UIApplication.willResignActiveNotification, object: nil) } - @objc func didEnterBackground() { + @objc func willResignActive() { restoreScreenBrightness() - NotificationCenter.default.addObserver(self, selector: #selector(didEnterForeground), name: UIApplication.didBecomeActiveNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil) } - @objc func didEnterForeground() { + @objc func didBecomeActive() { NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil) changeScreenBrightness() } From 233a0ae71b1b3883a6aff494a345bd5ba00b8a52 Mon Sep 17 00:00:00 2001 From: Kyle Matthew Hedden Date: Tue, 12 May 2020 16:07:03 -0400 Subject: [PATCH 42/67] code review --- .../Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift index f34c4ebd..3ed37d6b 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift @@ -9,7 +9,7 @@ import Foundation -public protocol TemplateModelProtocol: PageModelProtocol, ModelProtocol, PageBehaviorsTemplateProtocol { +public protocol TemplateModelProtocol: PageModelProtocol, ModelProtocol { var template: String { get } } From 6f1b3000174653114cbc599b86b1b7da6d76f41f Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 12 May 2020 16:12:39 -0400 Subject: [PATCH 43/67] moving code --- MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index ba1d377a..9ef346ba 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -294,9 +294,6 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele if textView.isEditable { FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate) setupTextViewToolbar() -// let observingDelegate = delegateObject?.uiTextViewDelegate ?? self -// textView.inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate, -// action: #selector(textView.dismissFieldInput)) if isSelected { DispatchQueue.main.async { From 14db4dfeaa789bab8c7b9f31cc87c383f61f1274 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 12 May 2020 16:45:07 -0400 Subject: [PATCH 44/67] more changes --- MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index 9ef346ba..c39c12c6 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -175,7 +175,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele //-------------------------------------------------- // MARK: - Methods //-------------------------------------------------- - + /// Validates the text of the entry field. @objc public func validateTextView() { text = textView.text @@ -234,7 +234,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele } @objc public func textViewDidEndEditing(_ textView: UITextView) { - + isSelected = false if isValid { From eb6035b378f39b284fdf0657440975d7df5970ee Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 12 May 2020 16:47:02 -0400 Subject: [PATCH 45/67] delegate fix --- MVMCoreUI/BaseControllers/ViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index 0872b0e6..a10e0767 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -17,7 +17,7 @@ import UIKit public var manager: (UIViewController & MVMCoreViewManagerProtocol)? /// A temporary iVar backer for delegateObject() until we change the protocol - public let delegateObjectIVar: MVMCoreUIDelegateObject = { + public lazy var delegateObjectIVar: MVMCoreUIDelegateObject = { return MVMCoreUIDelegateObject.create(withDelegateForAll: self) }() From a47bb11bb6a7344fd1ac9291f8f079aee1b955ed Mon Sep 17 00:00:00 2001 From: "Xinlei(Ryan) Pan" Date: Tue, 12 May 2020 16:59:19 -0400 Subject: [PATCH 46/67] remove NHaasGroteskDSStd font --- MVMCoreUI.xcodeproj/project.pbxproj | 8 -------- .../Fonts/NHaasGroteskDSStd-55Rg.otf | Bin 75048 -> 0 bytes .../Fonts/NHaasGroteskDSStd-75Bd.otf | Bin 64188 -> 0 bytes MVMCoreUI/Utility/MFFonts.h | 3 --- MVMCoreUI/Utility/MFFonts.m | 7 ------- 5 files changed, 18 deletions(-) delete mode 100644 MVMCoreUI/SupportingFiles/Fonts/NHaasGroteskDSStd-55Rg.otf delete mode 100644 MVMCoreUI/SupportingFiles/Fonts/NHaasGroteskDSStd-75Bd.otf diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 1b66b097..ef7059f0 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -146,8 +146,6 @@ 8DE5BECF2456F7B100772E76 /* ListTwoColumnDropdownSelectors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DE5BECE2456F7B100772E76 /* ListTwoColumnDropdownSelectors.swift */; }; 8DEFA95C243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DEFA95B243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift */; }; 8DEFA95E243DAC2F000D27E5 /* ListThreeColumnDataUsageDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DEFA95D243DAC2F000D27E5 /* ListThreeColumnDataUsageDivider.swift */; }; - 942C372E241149170066E45E /* NHaasGroteskDSStd-75Bd.otf in Resources */ = {isa = PBXBuildFile; fileRef = 942C372C241149170066E45E /* NHaasGroteskDSStd-75Bd.otf */; }; - 942C372F241149170066E45E /* NHaasGroteskDSStd-55Rg.otf in Resources */ = {isa = PBXBuildFile; fileRef = 942C372D241149170066E45E /* NHaasGroteskDSStd-55Rg.otf */; }; 942C378C2412F4FA0066E45E /* ModalMoleculeListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 942C378B2412F4FA0066E45E /* ModalMoleculeListTemplate.swift */; }; 942C378E2412F5B60066E45E /* ModalMoleculeStackTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 942C378D2412F5B60066E45E /* ModalMoleculeStackTemplate.swift */; }; 9432A79F23DB47BA00719041 /* EntryFieldContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9432A79E23DB47BA00719041 /* EntryFieldContainer.swift */; }; @@ -560,8 +558,6 @@ 8DEFA95B243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnDataUsageDividerModel.swift; sourceTree = ""; }; 8DEFA95D243DAC2F000D27E5 /* ListThreeColumnDataUsageDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnDataUsageDivider.swift; sourceTree = ""; }; 9402C34F23A2CEA3004B974C /* LeftRightLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeftRightLabelModel.swift; sourceTree = ""; }; - 942C372C241149170066E45E /* NHaasGroteskDSStd-75Bd.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NHaasGroteskDSStd-75Bd.otf"; sourceTree = ""; }; - 942C372D241149170066E45E /* NHaasGroteskDSStd-55Rg.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NHaasGroteskDSStd-55Rg.otf"; sourceTree = ""; }; 942C378B2412F4FA0066E45E /* ModalMoleculeListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalMoleculeListTemplate.swift; sourceTree = ""; }; 942C378D2412F5B60066E45E /* ModalMoleculeStackTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalMoleculeStackTemplate.swift; sourceTree = ""; }; 9432A79E23DB47BA00719041 /* EntryFieldContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntryFieldContainer.swift; sourceTree = ""; }; @@ -1714,8 +1710,6 @@ 94CA227924058533002D6750 /* VerizonNHGeDS-Regular.otf */, 94CA227824058533002D6750 /* VerizonNHGeTX-Bold.otf */, 94CA227B24058533002D6750 /* VerizonNHGeTX-Regular.otf */, - 942C372D241149170066E45E /* NHaasGroteskDSStd-55Rg.otf */, - 942C372C241149170066E45E /* NHaasGroteskDSStd-75Bd.otf */, D29DF31721ECECC0003B2FB9 /* OCRAExtended.ttf */, ); path = Fonts; @@ -1902,8 +1896,6 @@ D29DF32C21EE8736003B2FB9 /* Localizable.strings in Resources */, 94CA227D24058534002D6750 /* VerizonNHGeDS-Regular.otf in Resources */, D29DF32E21EE8C3D003B2FB9 /* Media.xcassets in Resources */, - 942C372E241149170066E45E /* NHaasGroteskDSStd-75Bd.otf in Resources */, - 942C372F241149170066E45E /* NHaasGroteskDSStd-55Rg.otf in Resources */, 94CA227E24058534002D6750 /* VerizonNHGeDS-Bold.otf in Resources */, D287651A245B338E00CB882D /* VerizonNHGeTX-Regular.otf in Resources */, D29DF31B21ECECC0003B2FB9 /* OCRAExtended.ttf in Resources */, diff --git a/MVMCoreUI/SupportingFiles/Fonts/NHaasGroteskDSStd-55Rg.otf b/MVMCoreUI/SupportingFiles/Fonts/NHaasGroteskDSStd-55Rg.otf deleted file mode 100644 index f56ed7aaf89f16bad53d72034e0002639d48364e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75048 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

_D2qW`Ep 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

3x1o+N6#i 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 Date: Tue, 12 May 2020 17:45:17 -0400 Subject: [PATCH 47/67] code review --- MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift b/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift index 03464841..b6ea9f6d 100644 --- a/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift +++ b/MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift @@ -27,7 +27,7 @@ public class ScreenBrightnessModifierBehavior: PageVisibilityBehavior { //MARK:- Behavior func changeScreenBrightness() { - if originalScreenBrightness != nil { return } + guard originalScreenBrightness == nil else { return } originalScreenBrightness = UIScreen.main.brightness UIScreen.main.brightness = screenBrightness NotificationCenter.default.addObserver(self, selector: #selector(willResignActive), name: UIApplication.willResignActiveNotification, object: nil) From 3fce526c90c556d72a6c8e391894e1ac899d7d8b Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Wed, 13 May 2020 15:52:50 +0530 Subject: [PATCH 48/67] Code changes for aligning rightlabel with leftheadline. --- .../List/ListProgressBarThin.swift | 30 +++++++++++++++---- .../List/ListProgressBarThinModel.swift | 3 ++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift index 69e26ea2..73561ec1 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift @@ -17,6 +17,8 @@ import Foundation let leftBody2 = Label.commonLabelB2(true) let bar = Line() let rightLabel = Label.commonLabelB2(true) + private let barStackItem: StackItem + private let rightLabelStackItem: StackItem public var horizontalStack: Stack public var verticalStack: Stack public var stack: Stack @@ -25,14 +27,25 @@ import Foundation // MARK: - Initializers //------------------------------------------------------ public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - verticalStack = Stack.createStack(with: [(view: leftHeadline, model: StackItemModel(horizontalAlignment: .leading)), - (view: leftBody, model: StackItemModel(horizontalAlignment: .leading)), - (view: leftBody2, model: StackItemModel(horizontalAlignment: .leading))], + //vertical stack with leftHeadline, leftBody, leftBody2 + let verticalStackModel = StackModel(molecules: [StackItemModel(horizontalAlignment: .leading, verticalAlignment: .leading), StackItemModel(horizontalAlignment: .leading), StackItemModel(horizontalAlignment: .leading)], axis: .vertical, spacing: 0) - horizontalStack = Stack.createStack(with: [(view: verticalStack, model: StackItemModel(horizontalAlignment: .leading, verticalAlignment: .leading)), - (view: bar, model: StackItemModel(horizontalAlignment: .fill)), (view: rightLabel, model: StackItemModel(spacing: 5, horizontalAlignment: .fill))], + let verticalStackItems = [StackItem(andContain: leftHeadline), StackItem(andContain: leftBody), StackItem(andContain: leftBody2)] + verticalStack = Stack(with: verticalStackModel, stackItems: verticalStackItems) + + //horizontal stack with leftHeadline, leftBody, leftBody2, bar, rightLabel + let horizontalStackModel = StackModel(molecules: [StackItemModel(horizontalAlignment: .leading), StackItemModel(horizontalAlignment: .fill), StackItemModel(spacing: 5, horizontalAlignment: .fill)], axis: .horizontal) - stack = Stack.createStack(with: [(view: horizontalStack, model: StackItemModel(horizontalAlignment: .fill)), (view: progressBar, model: StackItemModel(spacing: 20, horizontalAlignment: .fill))], axis: .vertical) + barStackItem = StackItem(andContain: bar) + rightLabelStackItem = StackItem(andContain: rightLabel) + let horizontalStackItems = [StackItem(andContain: verticalStack), barStackItem, rightLabelStackItem] + horizontalStack = Stack(with: horizontalStackModel, stackItems: horizontalStackItems) + + //stack with all components + let stackModel = StackModel(molecules: [StackItemModel(horizontalAlignment: .fill), + StackItemModel(spacing: 20, horizontalAlignment: .fill)], axis: .vertical) + let stackItems = [StackItem(andContain: horizontalStack), StackItem(andContain: progressBar)] + stack = Stack(with: stackModel, stackItems: stackItems) super.init(style: style, reuseIdentifier: reuseIdentifier) } @@ -42,6 +55,11 @@ import Foundation open override func alignAccessoryToHero() -> CGPoint? { let heroCenter = super.alignAccessoryToHero() + if let heroCenter = heroCenter { + let convertedPoint = horizontalStack.convert(heroCenter, from: self) + barStackItem.containerHelper.alignCenterVerticalConstraint?.constant = convertedPoint.y - horizontalStack.bounds.midY + rightLabelStackItem.containerHelper.alignCenterVerticalConstraint?.constant = convertedPoint.y - horizontalStack.bounds.midY + } return heroCenter } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift index 2e0b7cdb..7bed74b1 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift @@ -32,6 +32,9 @@ public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol { if bar.backgroundColor == nil { bar.backgroundColor = Color(uiColor: .gray) } + if let leftHeadline = leftHeadline { + leftHeadline.hero = 0 + } } private enum CodingKeys: String, CodingKey { From a2451a523daff0efb1f0f0caf78245b7d3a80ae9 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 13 May 2020 09:25:32 -0400 Subject: [PATCH 49/67] mild changes --- MVMCoreUI/BaseClasses/TextView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/BaseClasses/TextView.swift b/MVMCoreUI/BaseClasses/TextView.swift index a5825dd8..3202650d 100644 --- a/MVMCoreUI/BaseClasses/TextView.swift +++ b/MVMCoreUI/BaseClasses/TextView.swift @@ -102,7 +102,7 @@ import UIKit inputAccessoryView = nil isAccessibilityElement = true accessibilityTraits = .staticText - font = Styler.Font.RegularBodyLarge.getFont() + font = fontStyle.getFont() keyboardType = .default isEditable = true isOpaque = false @@ -181,6 +181,6 @@ import UIKit @objc open func dismissFieldInput(_ sender: TextView) { - resignFirstResponder() + _ = resignFirstResponder() } } From e217970a0417c992676c342256c913094bfe0408 Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Wed, 13 May 2020 19:41:17 +0530 Subject: [PATCH 50/67] Updated code as per confluence changes. --- .../List/ListProgressBarThin.swift | 21 ++++++------------- .../List/ListProgressBarThinModel.swift | 7 +------ 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift index 73561ec1..901e5b2d 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift @@ -14,7 +14,6 @@ import Foundation let progressBar = ProgressBar() let leftHeadline = Label.commonLabelB1(true) let leftBody = Label.commonLabelB2(true) - let leftBody2 = Label.commonLabelB2(true) let bar = Line() let rightLabel = Label.commonLabelB2(true) private let barStackItem: StackItem @@ -27,25 +26,19 @@ import Foundation // MARK: - Initializers //------------------------------------------------------ public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - //vertical stack with leftHeadline, leftBody, leftBody2 - let verticalStackModel = StackModel(molecules: [StackItemModel(horizontalAlignment: .leading, verticalAlignment: .leading), StackItemModel(horizontalAlignment: .leading), StackItemModel(horizontalAlignment: .leading)], - axis: .vertical, spacing: 0) - let verticalStackItems = [StackItem(andContain: leftHeadline), StackItem(andContain: leftBody), StackItem(andContain: leftBody2)] - verticalStack = Stack(with: verticalStackModel, stackItems: verticalStackItems) + //vertical stack with leftHeadline, leftBody + verticalStack = Stack.createStack(with: [leftHeadline, leftBody], axis: .vertical, spacing: 2) - //horizontal stack with leftHeadline, leftBody, leftBody2, bar, rightLabel + //horizontal stack with leftHeadline, leftBody, bar, rightLabel let horizontalStackModel = StackModel(molecules: [StackItemModel(horizontalAlignment: .leading), StackItemModel(horizontalAlignment: .fill), StackItemModel(spacing: 5, horizontalAlignment: .fill)], axis: .horizontal) barStackItem = StackItem(andContain: bar) rightLabelStackItem = StackItem(andContain: rightLabel) let horizontalStackItems = [StackItem(andContain: verticalStack), barStackItem, rightLabelStackItem] horizontalStack = Stack(with: horizontalStackModel, stackItems: horizontalStackItems) - + //stack with all components - let stackModel = StackModel(molecules: [StackItemModel(horizontalAlignment: .fill), - StackItemModel(spacing: 20, horizontalAlignment: .fill)], axis: .vertical) - let stackItems = [StackItem(andContain: horizontalStack), StackItem(andContain: progressBar)] - stack = Stack(with: stackModel, stackItems: stackItems) + stack = Stack.createStack(with: [horizontalStack, progressBar], axis: .vertical, spacing: PaddingDefaultVerticalSpacing3) super.init(style: style, reuseIdentifier: reuseIdentifier) } @@ -85,8 +78,7 @@ import Foundation super.set(with: model, delegateObject, additionalData) guard let model = model as? ListProgressBarThinModel else { return } verticalStack.updateContainedMolecules(with: [model.leftHeadline, - model.leftBody, - model.leftBody2],delegateObject, additionalData) + model.leftBody], delegateObject, additionalData) progressBar.set(with: model.progressBar, delegateObject, additionalData) bar.set(with: model.bar, delegateObject, additionalData) rightLabel.set(with: model.rightLabel, delegateObject, additionalData) @@ -100,7 +92,6 @@ import Foundation super.reset() leftHeadline.styleB1(true) leftBody.styleB2(true) - leftBody2.styleB2(true) rightLabel.styleB2(true) bar.setStyle(.medium) } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift index 7bed74b1..5c9c507b 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift @@ -12,15 +12,13 @@ public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol { public var progressBar: ProgressBarModel public var leftHeadline: LabelModel? public var leftBody: LabelModel? - public var leftBody2: LabelModel? public var bar: LineModel public var rightLabel: LabelModel - public init(progressBar: ProgressBarModel, leftHeadline: LabelModel, leftBody: LabelModel, leftBody2: LabelModel, bar: LineModel, rightLabel: LabelModel) { + public init(progressBar: ProgressBarModel, leftHeadline: LabelModel, leftBody: LabelModel, bar: LineModel, rightLabel: LabelModel) { self.progressBar = progressBar self.leftHeadline = leftHeadline self.leftBody = leftBody - self.leftBody2 = leftBody2 self.bar = bar self.rightLabel = rightLabel super.init() @@ -42,7 +40,6 @@ public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol { case progressBar case leftHeadline case leftBody - case leftBody2 case line case rightLabel } @@ -52,7 +49,6 @@ public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol { progressBar = try typeContainer.decode(ProgressBarModel.self, forKey:.progressBar) leftHeadline = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .leftHeadline) leftBody = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .leftBody) - leftBody2 = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .leftBody2) bar = try typeContainer.decode(LineModel.self, forKey: .line) rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel) try super.init(from: decoder) @@ -65,7 +61,6 @@ public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol { try container.encode(progressBar, forKey: .progressBar) try container.encodeIfPresent(leftHeadline, forKey: .leftHeadline) try container.encodeIfPresent(leftBody, forKey: .leftBody) - try container.encodeIfPresent(leftBody2, forKey: .leftBody2) try container.encode(bar, forKey: .line) try container.encode(rightLabel, forKey: .rightLabel) } From 19a6ef8a2ae0916c775e01485d40da9aae13569a Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 13 May 2020 10:23:44 -0400 Subject: [PATCH 51/67] removing selegate --- .../Atoms/TextFields/TextViewEntryField.swift | 67 +++---------------- MVMCoreUI/BaseClasses/TextView.swift | 4 +- 2 files changed, 11 insertions(+), 60 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index c39c12c6..b11181fa 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -16,13 +16,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele open private(set) var textView: TextView = { let textView = TextView() - textView.isAccessibilityElement = true textView.setContentCompressionResistancePriority(.required, for: .vertical) - textView.font = Styler.Font.RegularBodyLarge.getFont() - textView.textColor = .mvmBlack - textView.smartQuotesType = .no - textView.smartDashesType = .no - textView.smartInsertDeleteType = .no return textView }() @@ -103,9 +97,6 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele // MARK: - Delegate Properties //-------------------------------------------------- - /// Holds a reference to the delegating class so this class can internally influence the TextView behavior as well. - private weak var proprietorTextDelegate: UITextViewDelegate? - /// The delegate and block for validation. Validates if the text that the user has entered. public weak var observingTextViewDelegate: ObservingTextFieldDelegate? { didSet { @@ -127,10 +118,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele /// If you're using a ViewController, you must set this to it public weak var uiTextViewDelegate: UITextViewDelegate? { get { return textView.delegate } - set { - textView.delegate = self - proprietorTextDelegate = newValue - } + set { textView.delegate = newValue } } @objc public func setBothTextDelegates(to delegate: (UITextViewDelegate & ObservingTextFieldDelegate)?) { @@ -160,10 +148,14 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele ]) heightConstraint = textView.heightAnchor.constraint(equalToConstant: 0) - accessibilityElements = [titleLabel, textView, feedbackLabel] } + open override func updateView(_ size: CGFloat) { + super.updateView(size) + textView.updateView(size) + } + open override func reset() { super.reset() @@ -199,52 +191,8 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele /// Executes on UITextView.textDidEndEditingNotification @objc func endInputing() { resignFirstResponder() - showError = !isValid - } - - //-------------------------------------------------- - // MARK: - UITextViewDelegate - //-------------------------------------------------- - - @objc public func textViewShouldBeginEditing(_ textView: UITextView) -> Bool { - - return proprietorTextDelegate?.textViewShouldBeginEditing?(textView) ?? true - } - - @objc public func textViewDidBeginEditing(_ textView: UITextView) { - - isSelected = true - proprietorTextDelegate?.textViewDidBeginEditing?(textView) - } - - @objc public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { - - return proprietorTextDelegate?.textView?(textView, shouldChangeTextIn: range, replacementText: text) ?? true - } - - @objc public func textViewDidChange(_ textView: UITextView) { - - validateTextView() - proprietorTextDelegate?.textViewDidChange?(textView) - } - - @objc public func textViewShouldEndEditing(_ textView: UITextView) -> Bool { - - return proprietorTextDelegate?.textViewShouldEndEditing?(textView) ?? true - } - - @objc public func textViewDidEndEditing(_ textView: UITextView) { - isSelected = false - - if isValid { - showError = false - entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor - } else { - showError = true - } - - proprietorTextDelegate?.textViewDidEndEditing?(textView) + showError = !isValid } //-------------------------------------------------- @@ -291,6 +239,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele default: break } + /// No point in configuring if the TextView is Read-only. if textView.isEditable { FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate) setupTextViewToolbar() diff --git a/MVMCoreUI/BaseClasses/TextView.swift b/MVMCoreUI/BaseClasses/TextView.swift index 3202650d..31288d87 100644 --- a/MVMCoreUI/BaseClasses/TextView.swift +++ b/MVMCoreUI/BaseClasses/TextView.swift @@ -76,7 +76,9 @@ import UIKit } } - open func updateView(_ size: CGFloat) { } + open func updateView(_ size: CGFloat) { + font = fontStyle.getFont() + } /// Will be called only once. open func setupView() { From e23db4d3f5d61d807f7ccfdc7851e20696a1690a Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 13 May 2020 10:32:09 -0400 Subject: [PATCH 52/67] removed unneeded protocol --- MVMCoreUI/BaseClasses/TextView.swift | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/MVMCoreUI/BaseClasses/TextView.swift b/MVMCoreUI/BaseClasses/TextView.swift index 31288d87..4d2c4907 100644 --- a/MVMCoreUI/BaseClasses/TextView.swift +++ b/MVMCoreUI/BaseClasses/TextView.swift @@ -9,7 +9,7 @@ import UIKit -@objc open class TextView: UITextView, UITextViewDelegate, MVMCoreViewProtocol, MoleculeViewProtocol { +@objc open class TextView: UITextView, MVMCoreViewProtocol, MoleculeViewProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -58,11 +58,6 @@ import UIKit initialSetup() } - convenience init(delegate: UITextViewDelegate) { - self.init(frame: .zero, textContainer: nil) - self.delegate = delegate - } - //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- From 268ee222bb10b3f9ffcf14d24b9b5bdf0f28ccdd Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 13 May 2020 10:45:34 -0400 Subject: [PATCH 53/67] removing opaque --- MVMCoreUI/BaseClasses/TextView.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/MVMCoreUI/BaseClasses/TextView.swift b/MVMCoreUI/BaseClasses/TextView.swift index 4d2c4907..f11efde9 100644 --- a/MVMCoreUI/BaseClasses/TextView.swift +++ b/MVMCoreUI/BaseClasses/TextView.swift @@ -102,7 +102,6 @@ import UIKit font = fontStyle.getFont() keyboardType = .default isEditable = true - isOpaque = false } open func reset() { From e5ac0127d1ddd21027fa29635b818146ebafe818 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 13 May 2020 12:07:33 -0400 Subject: [PATCH 54/67] fixed resue issue --- .../Atoms/TextFields/TextViewEntryField.swift | 47 ++++++++++++++----- .../TextFields/TextViewEntryFieldModel.swift | 2 +- MVMCoreUI/BaseClasses/TextView.swift | 5 +- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index b11181fa..f16c4e12 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -82,8 +82,9 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele public var placeholder: String? { get { return textViewEntryFieldModel?.placeholder } set { - textViewEntryFieldModel?.placeholder = newValue textView.placeholder = newValue ?? "" + textViewEntryFieldModel?.placeholder = newValue + textView.setPlaceholderIfAvailable() } } @@ -92,6 +93,19 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele //-------------------------------------------------- public var heightConstraint: NSLayoutConstraint? + private var topConstraint: NSLayoutConstraint? + private var leadingConstraint: NSLayoutConstraint? + private var trailingConstraint: NSLayoutConstraint? + private var bottomConstraint: NSLayoutConstraint? + + private func adjustMarginConstraints(constant: CGFloat) { + + topConstraint?.constant = constant + leadingConstraint?.constant = constant + trailingConstraint?.constant = constant + bottomConstraint?.constant = constant + layoutIfNeeded() + } //-------------------------------------------------- // MARK: - Delegate Properties @@ -139,14 +153,17 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele @objc open override func setupFieldContainerContent(_ container: UIView) { container.addSubview(textView) - - NSLayoutConstraint.activate([ - textView.topAnchor.constraint(equalTo: container.topAnchor, constant: Padding.Three), - textView.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: Padding.Three), - container.trailingAnchor.constraint(equalTo: textView.trailingAnchor, constant: Padding.Three), - container.bottomAnchor.constraint(equalTo: textView.bottomAnchor, constant: Padding.Three) - ]) - + + topConstraint = textView.topAnchor.constraint(equalTo: container.topAnchor, constant: Padding.Three) + leadingConstraint = textView.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: Padding.Three) + trailingConstraint = container.trailingAnchor.constraint(equalTo: textView.trailingAnchor, constant: Padding.Three) + bottomConstraint = container.bottomAnchor.constraint(equalTo: textView.bottomAnchor, constant: Padding.Three) + + topConstraint?.isActive = true + leadingConstraint?.isActive = true + trailingConstraint?.isActive = true + bottomConstraint?.isActive = true + heightConstraint = textView.heightAnchor.constraint(equalToConstant: 0) accessibilityElements = [titleLabel, textView, feedbackLabel] } @@ -160,6 +177,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele super.reset() textView.reset() + adjustMarginConstraints(constant: Padding.Three) heightConstraint?.constant = 0 heightConstraint?.isActive = false } @@ -224,7 +242,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele textView.placeholder = model.placeholder ?? "" textView.placeholderFontStyle = model.placeholderFontStyle textView.placeholderTextColor = model.placeholderTextColor.uiColor - textView.setPlaceholderIfAvailable() + switch model.type { case .secure, .password: @@ -251,8 +269,13 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele } } - if !model.enabled { - isEnabled = false + if model.hideBorders { + adjustMarginConstraints(constant: 0) } + + textView.setPlaceholderIfAvailable() +// if !model.enabled { +// isEnabled = false +// } } } diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift index 3d1e1407..ce1173ae 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryFieldModel.swift @@ -19,7 +19,7 @@ class TextViewEntryFieldModel: TextEntryFieldModel { } public var accessibilityText: String? - public var fontStyle: Styler.Font = Styler.Font.RegularBodySmall + public var fontStyle: Styler.Font = Styler.Font.RegularBodyLarge public var height: CGFloat? public var placeholderTextColor: Color = Color(uiColor: .mvmCoolGray3) public var placeholderFontStyle: Styler.Font = Styler.Font.RegularMicro diff --git a/MVMCoreUI/BaseClasses/TextView.swift b/MVMCoreUI/BaseClasses/TextView.swift index f11efde9..2c609e02 100644 --- a/MVMCoreUI/BaseClasses/TextView.swift +++ b/MVMCoreUI/BaseClasses/TextView.swift @@ -72,7 +72,7 @@ import UIKit } open func updateView(_ size: CGFloat) { - font = fontStyle.getFont() + font = (isShowingPlaceholder ? placeholderFontStyle : fontStyle).getFont() } /// Will be called only once. @@ -109,7 +109,10 @@ import UIKit fontStyle = Styler.Font.RegularBodyLarge placeholderFontStyle = Styler.Font.RegularMicro placeholderTextColor = .mvmCoolGray3 + textColor = .mvmBlack isEnabled = true + text = "" + isShowingPlaceholder = false inputAccessoryView?.removeFromSuperview() defaultConfiguration() } From 5ef0d54b97991ec06a7c748a2c1ce7f1152807d0 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 13 May 2020 12:55:14 -0400 Subject: [PATCH 55/67] removed comment and layout statement --- .../Atomic/Atoms/TextFields/TextViewEntryField.swift | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift index f16c4e12..546b5c30 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextViewEntryField.swift @@ -104,7 +104,6 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele leadingConstraint?.constant = constant trailingConstraint?.constant = constant bottomConstraint?.constant = constant - layoutIfNeeded() } //-------------------------------------------------- @@ -242,7 +241,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele textView.placeholder = model.placeholder ?? "" textView.placeholderFontStyle = model.placeholderFontStyle textView.placeholderTextColor = model.placeholderTextColor.uiColor - + textView.setPlaceholderIfAvailable() switch model.type { case .secure, .password: @@ -273,9 +272,8 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele adjustMarginConstraints(constant: 0) } - textView.setPlaceholderIfAvailable() -// if !model.enabled { -// isEnabled = false -// } + if !model.enabled { + isEnabled = false + } } } From 1e3c52c15fbe4fbabf6baf56347c0392bfc96a48 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 13 May 2020 16:03:08 -0400 Subject: [PATCH 56/67] to match legacy for now and fix defect) --- MVMCoreUI/Containers/NavigationController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Containers/NavigationController.swift b/MVMCoreUI/Containers/NavigationController.swift index f278236c..05e5c406 100644 --- a/MVMCoreUI/Containers/NavigationController.swift +++ b/MVMCoreUI/Containers/NavigationController.swift @@ -58,7 +58,7 @@ import UIKit if navigationController == MVMCoreUISession.sharedGlobal()?.navigationController, navigationController.topViewController == viewController { // Update line. - MVMCoreUISession.sharedGlobal()?.navigationController?.separatorView?.setStyle(navigationItemModel.line?.type ?? .standard) + MVMCoreUISession.sharedGlobal()?.navigationController?.separatorView?.isHidden = navigationItemModel.line?.type ?? .standard == .none } if navigationController == MVMCoreUISplitViewController.main()?.navigationController, From 77a99e99c9cff8f4eab6b3700c7e1d048bd1d7bb Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Thu, 14 May 2020 15:43:19 +0530 Subject: [PATCH 57/67] Code changes: made headline as required key and body as optional. --- .../List/ListProgressBarThinModel.swift | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift index 5c9c507b..44d11479 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift @@ -10,12 +10,12 @@ import Foundation public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol { public static var identifier = "listPrgBarThin" public var progressBar: ProgressBarModel - public var leftHeadline: LabelModel? + public var leftHeadline: LabelModel public var leftBody: LabelModel? public var bar: LineModel public var rightLabel: LabelModel - public init(progressBar: ProgressBarModel, leftHeadline: LabelModel, leftBody: LabelModel, bar: LineModel, rightLabel: LabelModel) { + public init(progressBar: ProgressBarModel, leftHeadline: LabelModel, leftBody: LabelModel? = nil, bar: LineModel, rightLabel: LabelModel) { self.progressBar = progressBar self.leftHeadline = leftHeadline self.leftBody = leftBody @@ -30,9 +30,7 @@ public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol { if bar.backgroundColor == nil { bar.backgroundColor = Color(uiColor: .gray) } - if let leftHeadline = leftHeadline { - leftHeadline.hero = 0 - } + leftHeadline.hero = 0 } private enum CodingKeys: String, CodingKey { @@ -47,7 +45,7 @@ public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol { public required init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) progressBar = try typeContainer.decode(ProgressBarModel.self, forKey:.progressBar) - leftHeadline = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .leftHeadline) + leftHeadline = try typeContainer.decode(LabelModel.self, forKey: .leftHeadline) leftBody = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .leftBody) bar = try typeContainer.decode(LineModel.self, forKey: .line) rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel) @@ -59,7 +57,7 @@ public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(moleculeName, forKey: .moleculeName) try container.encode(progressBar, forKey: .progressBar) - try container.encodeIfPresent(leftHeadline, forKey: .leftHeadline) + try container.encode(leftHeadline, forKey: .leftHeadline) try container.encodeIfPresent(leftBody, forKey: .leftBody) try container.encode(bar, forKey: .line) try container.encode(rightLabel, forKey: .rightLabel) From b49579d05965983403a2baf96e4436dc70f791ae Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 14 May 2020 10:52:17 -0400 Subject: [PATCH 58/67] line fix, small clean --- .../List/ListProgressBarThin.swift | 31 ++++++++++--------- .../List/ListProgressBarThinModel.swift | 18 +++++------ 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift index 901e5b2d..072be6bb 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThin.swift @@ -11,15 +11,15 @@ import Foundation //-------------------------------------------------- // MARK: - Outlets //-------------------------------------------------- - let progressBar = ProgressBar() - let leftHeadline = Label.commonLabelB1(true) - let leftBody = Label.commonLabelB2(true) - let bar = Line() - let rightLabel = Label.commonLabelB2(true) + public let progressBar = ProgressBar() + public let leftHeadline = Label.commonLabelB1(true) + public let leftBody = Label.commonLabelB2(true) + public let rightBar = Line() + public let rightLabel = Label.commonLabelB2(true) private let barStackItem: StackItem private let rightLabelStackItem: StackItem + public var labelStack: Stack public var horizontalStack: Stack - public var verticalStack: Stack public var stack: Stack //------------------------------------------------------ @@ -27,14 +27,14 @@ import Foundation //------------------------------------------------------ public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { //vertical stack with leftHeadline, leftBody - verticalStack = Stack.createStack(with: [leftHeadline, leftBody], axis: .vertical, spacing: 2) + labelStack = Stack.createStack(with: [leftHeadline, leftBody], axis: .vertical, spacing: 2) //horizontal stack with leftHeadline, leftBody, bar, rightLabel + barStackItem = StackItem(andContain: rightBar) + rightLabelStackItem = StackItem(andContain: rightLabel) + let horizontalStackItems = [StackItem(andContain: labelStack), barStackItem, rightLabelStackItem] let horizontalStackModel = StackModel(molecules: [StackItemModel(horizontalAlignment: .leading), StackItemModel(horizontalAlignment: .fill), StackItemModel(spacing: 5, horizontalAlignment: .fill)], axis: .horizontal) - barStackItem = StackItem(andContain: bar) - rightLabelStackItem = StackItem(andContain: rightLabel) - let horizontalStackItems = [StackItem(andContain: verticalStack), barStackItem, rightLabelStackItem] horizontalStack = Stack(with: horizontalStackModel, stackItems: horizontalStackItems) //stack with all components @@ -47,6 +47,7 @@ import Foundation } open override func alignAccessoryToHero() -> CGPoint? { + // Ensures that the right items are centered with the arrow. let heroCenter = super.alignAccessoryToHero() if let heroCenter = heroCenter { let convertedPoint = horizontalStack.convert(heroCenter, from: self) @@ -61,14 +62,14 @@ import Foundation //------------------------------------------------------- open override func setupView() { super.setupView() - bar.widthAnchor.constraint(equalToConstant: 20).isActive = true + rightBar.widthAnchor.constraint(equalToConstant: 20).isActive = true rightLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal) rightLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .horizontal) rightLabel.numberOfLines = 1 addMolecule(stack) stack.restack() horizontalStack.restack() - verticalStack.restack() + labelStack.restack() } //------------------------------------------------------ @@ -77,10 +78,10 @@ import Foundation open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { super.set(with: model, delegateObject, additionalData) guard let model = model as? ListProgressBarThinModel else { return } - verticalStack.updateContainedMolecules(with: [model.leftHeadline, + labelStack.updateContainedMolecules(with: [model.leftHeadline, model.leftBody], delegateObject, additionalData) progressBar.set(with: model.progressBar, delegateObject, additionalData) - bar.set(with: model.bar, delegateObject, additionalData) + rightBar.set(with: model.rightBar, delegateObject, additionalData) rightLabel.set(with: model.rightLabel, delegateObject, additionalData) } @@ -93,6 +94,6 @@ import Foundation leftHeadline.styleB1(true) leftBody.styleB2(true) rightLabel.styleB2(true) - bar.setStyle(.medium) + rightBar.setStyle(.medium) } } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift index 44d11479..acd8e013 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/ListProgressBarThinModel.swift @@ -12,23 +12,23 @@ public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol { public var progressBar: ProgressBarModel public var leftHeadline: LabelModel public var leftBody: LabelModel? - public var bar: LineModel + public var rightBar: LineModel public var rightLabel: LabelModel - public init(progressBar: ProgressBarModel, leftHeadline: LabelModel, leftBody: LabelModel? = nil, bar: LineModel, rightLabel: LabelModel) { + public init(progressBar: ProgressBarModel, leftHeadline: LabelModel, leftBody: LabelModel? = nil, rightBar: LineModel, rightLabel: LabelModel) { self.progressBar = progressBar self.leftHeadline = leftHeadline self.leftBody = leftBody - self.bar = bar + self.rightBar = rightBar self.rightLabel = rightLabel super.init() } override public func setDefaults() { super.setDefaults() - bar.type = .medium - if bar.backgroundColor == nil { - bar.backgroundColor = Color(uiColor: .gray) + rightBar.type = .medium + if rightBar.backgroundColor == nil { + rightBar.backgroundColor = Color(uiColor: .gray) } leftHeadline.hero = 0 } @@ -38,7 +38,7 @@ public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol { case progressBar case leftHeadline case leftBody - case line + case rightBar case rightLabel } @@ -47,7 +47,7 @@ public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol { progressBar = try typeContainer.decode(ProgressBarModel.self, forKey:.progressBar) leftHeadline = try typeContainer.decode(LabelModel.self, forKey: .leftHeadline) leftBody = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .leftBody) - bar = try typeContainer.decode(LineModel.self, forKey: .line) + rightBar = try typeContainer.decode(LineModel.self, forKey: .rightBar) rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel) try super.init(from: decoder) } @@ -59,7 +59,7 @@ public class ListProgressBarThinModel: ListItemModel, MoleculeModelProtocol { try container.encode(progressBar, forKey: .progressBar) try container.encode(leftHeadline, forKey: .leftHeadline) try container.encodeIfPresent(leftBody, forKey: .leftBody) - try container.encode(bar, forKey: .line) + try container.encode(rightBar, forKey: .rightBar) try container.encode(rightLabel, forKey: .rightLabel) } } From 8ea3404294830d89ed691d809986638aa3d62a67 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 14 May 2020 11:24:07 -0400 Subject: [PATCH 59/67] load image update control for delegate --- .../Atomic/Atoms/Views/LoadImageView.swift | 18 +++++++++--------- .../Device/ListDeviceComplexButtonMedium.swift | 1 + .../Device/ListDeviceComplexButtonSmall.swift | 1 + .../Device/ListDeviceComplexLinkMedium.swift | 1 + .../Device/ListDeviceComplexLinkSmall.swift | 1 + 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift index a8d0ba9a..e3c9123e 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift @@ -12,6 +12,7 @@ import UIKit public let loadingSpinner = MFLoadingSpinner(frame: .zero) public let imageView = MFTransparentGIFView(frame: .zero) public var addSizeConstraintsForAspectRatio = false + public var shouldNotifyDelegateOnUpdate = true var centerX: NSLayoutConstraint? var centerY: NSLayoutConstraint? var widthConstraint: NSLayoutConstraint? @@ -264,16 +265,15 @@ import UIKit } let finishedLoadingBlock: MVMCoreGetImageBlock = {[weak self] (image, data, isFallbackImage) in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in - guard let loadingImageName = self?.currentImageName, loadingImageName == imageName else { - return - } - self?.isFallbackImage = isFallbackImage - self?.loadingSpinner.pause() - let layoutWillChange = self?.layoutWillChange(width: self?.currentImageWidth, height: self?.currentImageHeight, size: image?.size) ?? false - self?.addConstraints(width: width, height: height, size: image?.size) - self?.loadingSpinnerHeightConstraint?.constant = 0 + guard let self = self, + let loadingImageName = self.currentImageName, loadingImageName == imageName else { return } + self.isFallbackImage = isFallbackImage + self.loadingSpinner.pause() + let layoutWillChange = self.shouldNotifyDelegateOnUpdate ? self.layoutWillChange(width: self.currentImageWidth, height: self.currentImageHeight, size: image?.size) : false + self.addConstraints(width: width, height: height, size: image?.size) + self.loadingSpinnerHeightConstraint?.constant = 0 if layoutWillChange { - self?.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self!) + self.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self) } completionBlock(image,data,isFallbackImage) })} diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMedium.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMedium.swift index c39bce65..e6e226cb 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMedium.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonMedium.swift @@ -43,6 +43,7 @@ import Foundation // MARK: - MFViewProtocol open override func setupView() { super.setupView() + rightImageView.shouldNotifyDelegateOnUpdate = false addMolecule(stack) stack.restack() verticalStack.restack() diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmall.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmall.swift index 77a189c2..e8436620 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmall.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexButtonSmall.swift @@ -43,6 +43,7 @@ import Foundation // MARK: - MFViewProtocol open override func setupView() { super.setupView() + rightImageView.shouldNotifyDelegateOnUpdate = false addMolecule(stack) stack.restack() verticalStack.restack() diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkMedium.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkMedium.swift index f53da09c..573335c0 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkMedium.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkMedium.swift @@ -46,6 +46,7 @@ import Foundation //----------------------------------------------------- open override func setupView() { super.setupView() + rightImage.shouldNotifyDelegateOnUpdate = false addMolecule(stack) stack.restack() verticalStack.restack() diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkSmall.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkSmall.swift index 5ba8ac97..49173067 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkSmall.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/Device/ListDeviceComplexLinkSmall.swift @@ -46,6 +46,7 @@ import Foundation //----------------------------------------------------- open override func setupView() { super.setupView() + rightImage.shouldNotifyDelegateOnUpdate = false addMolecule(stack) stack.restack() verticalStack.restack() From 57342800fe6d60399f98173e60476998532d3b43 Mon Sep 17 00:00:00 2001 From: "Khan, Arshad" Date: Fri, 15 May 2020 23:30:49 +0530 Subject: [PATCH 60/67] image width and height fix 1. making addSizeConstraintsForAspectRatio default true 2. removing 900 priority constraints --- MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift index e3c9123e..baa63ee8 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadImageView.swift @@ -11,7 +11,7 @@ import UIKit @objcMembers open class LoadImageView: View { public let loadingSpinner = MFLoadingSpinner(frame: .zero) public let imageView = MFTransparentGIFView(frame: .zero) - public var addSizeConstraintsForAspectRatio = false + public var addSizeConstraintsForAspectRatio = true public var shouldNotifyDelegateOnUpdate = true var centerX: NSLayoutConstraint? var centerY: NSLayoutConstraint? @@ -173,7 +173,6 @@ import UIKit } else { heightConstraint?.isActive = false heightConstraint = imageView.heightAnchor.constraint(equalToConstant: height) - heightConstraint?.priority = UILayoutPriority(rawValue: 900) } heightConstraint?.isActive = true } @@ -183,7 +182,6 @@ import UIKit widthConstraint.constant = width } else { widthConstraint = imageView.widthAnchor.constraint(equalToConstant: width) - widthConstraint?.priority = UILayoutPriority(rawValue: 900) } widthConstraint?.isActive = true } From 7e3c9fdcdbbbdcd43cc85809d36185d8bbb6b0f1 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 15 May 2020 15:20:03 -0400 Subject: [PATCH 61/67] new rule equalsignorecase --- MVMCoreUI.xcodeproj/project.pbxproj | 4 ++ MVMCoreUI/Atomic/MoleculeObjectMapping.swift | 1 + .../Rules/RuleEqualsIgnoreCaseModel.swift | 55 +++++++++++++++++++ .../Rules/Rules/RuleRequiredModel.swift | 1 + 4 files changed, 61 insertions(+) create mode 100644 MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index d7afb970..20472d78 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -92,6 +92,7 @@ 0A7EF86323D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86223D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift */; }; 0A7EF86523D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */; }; 0A7EF86723D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */; }; + 0A849EFE246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A849EFD246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift */; }; 0A9D091D2433796500D2E6C0 /* BarsCarouselIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D09172433796500D2E6C0 /* BarsCarouselIndicatorModel.swift */; }; 0A9D091E2433796500D2E6C0 /* NumericCarouselIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D09182433796500D2E6C0 /* NumericCarouselIndicatorModel.swift */; }; 0A9D091F2433796500D2E6C0 /* NumericIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D09192433796500D2E6C0 /* NumericIndicatorView.swift */; }; @@ -505,6 +506,7 @@ 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryFieldModel.swift; sourceTree = ""; }; 0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryFieldModel.swift; sourceTree = ""; }; 0A8321AE2355FE9500CB7F00 /* DigitBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitBox.swift; sourceTree = ""; }; + 0A849EFD246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleEqualsIgnoreCaseModel.swift; sourceTree = ""; }; 0A9D09172433796500D2E6C0 /* BarsCarouselIndicatorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarsCarouselIndicatorModel.swift; sourceTree = ""; }; 0A9D09182433796500D2E6C0 /* NumericCarouselIndicatorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumericCarouselIndicatorModel.swift; sourceTree = ""; }; 0A9D09192433796500D2E6C0 /* NumericIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumericIndicatorView.swift; sourceTree = ""; }; @@ -873,6 +875,7 @@ 011D95A0240453D0000E3791 /* RuleEqualsModel.swift */, 011D95A2240453F8000E3791 /* RuleRegexModel.swift */, 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */, + 0A849EFD246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift */, ); name = Rules; path = Rules/Rules; @@ -2038,6 +2041,7 @@ AA11A42123F15D7000D7962F /* ListRightVariablePaymentsModel.swift in Sources */, 011D9626240EBB16000E3791 /* RadioButtonLabelModel.swift in Sources */, 8DDD6C1D244D90B8006A2232 /* ListThreeColumnDataUsage.swift in Sources */, + 0A849EFE246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift in Sources */, D28764FB245A33A500CB882D /* TwoLinkViewModel.swift in Sources */, AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */, D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */, diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index 76c17c6a..0a0768f8 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -194,6 +194,7 @@ import Foundation try? ModelRegistry.register(RuleAnyValueChangedModel.self) try? ModelRegistry.register(RuleAllValueChangedModel.self) try? ModelRegistry.register(RuleEqualsModel.self) + try? ModelRegistry.register(RuleEqualsIgnoreCaseModel.self) try? ModelRegistry.register(RuleRegexModel.self) // Actions diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift new file mode 100644 index 00000000..c988cfce --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift @@ -0,0 +1,55 @@ +// +// RuleEqualsIgnoreCaseModel.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 5/15/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + + +public class RuleEqualsIgnoreCaseModel: RulesProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public static var identifier: String = "equalsIgnoreCase" + public var type: String = RuleEqualsModel.identifier + public var fields: [String] + public var errorMessage: [String: String]? + + //-------------------------------------------------- + // MARK: - Validation + //-------------------------------------------------- + + public func isValid(_ formField: FormFieldProtocol) -> Bool { + return false + } + + public func validate(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool { + var valid = true + var compareValue: AnyHashable? + + for formKey in fields { + guard let formField = fieldMolecules[formKey] else { continue } + + if compareValue == nil { + compareValue = formField.formFieldValue() + continue + } + + let a = compareValue.caseInsensitiveCompare(formField.formFieldValue()) + + if compareValue != formField.formFieldValue() { + valid = false + (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) + break + } else { + (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) + } + } + + return valid + } +} diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRequiredModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRequiredModel.swift index c9e7d9f7..77cdf254 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRequiredModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRequiredModel.swift @@ -24,6 +24,7 @@ public class RuleRequiredModel: RulesProtocol { //-------------------------------------------------- public func isValid(_ formField: FormFieldProtocol) -> Bool { + guard let value = formField.formFieldValue() else { return false } var valid = true From 461fd5e2cab9a58cb7c7fe31e9b3c513a573b169 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 15 May 2020 15:37:40 -0400 Subject: [PATCH 62/67] new rule logic. --- .../Rules/Rules/RuleEqualsIgnoreCaseModel.swift | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift index c988cfce..15bcb3f0 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift @@ -28,23 +28,21 @@ public class RuleEqualsIgnoreCaseModel: RulesProtocol { } public func validate(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool { - var valid = true - var compareValue: AnyHashable? + var valid = false + var compareValue: String? for formKey in fields { guard let formField = fieldMolecules[formKey] else { continue } if compareValue == nil { - compareValue = formField.formFieldValue() + compareValue = formField.formFieldValue() as? String continue } - - let a = compareValue.caseInsensitiveCompare(formField.formFieldValue()) - if compareValue != formField.formFieldValue() { + if let compareValue = compareValue, let fieldValue = formField.formFieldValue() as? String, + compareValue.caseInsensitiveCompare(fieldValue) == .orderedSame { valid = false (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) - break } else { (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) } From 6d3805c9581c238739e0990794c3628eadddaa3f Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 15 May 2020 15:39:35 -0400 Subject: [PATCH 63/67] valid true --- .../FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift index 15bcb3f0..224d2334 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift @@ -41,7 +41,7 @@ public class RuleEqualsIgnoreCaseModel: RulesProtocol { if let compareValue = compareValue, let fieldValue = formField.formFieldValue() as? String, compareValue.caseInsensitiveCompare(fieldValue) == .orderedSame { - valid = false + valid = true (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) } else { (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) From c144b07a836e591daa78eb934bb34aa588819278 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 15 May 2020 16:14:16 -0400 Subject: [PATCH 64/67] revisions for review --- .../Rules/Rules/RuleEqualsIgnoreCaseModel.swift | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift index 224d2334..090812b3 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift @@ -29,23 +29,22 @@ public class RuleEqualsIgnoreCaseModel: RulesProtocol { public func validate(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool { var valid = false - var compareValue: String? + var compareText: String? for formKey in fields { guard let formField = fieldMolecules[formKey] else { continue } - if compareValue == nil { - compareValue = formField.formFieldValue() as? String + guard let compareString = compareText else { + compareText = formField.formFieldValue() as? String continue } - if let compareValue = compareValue, let fieldValue = formField.formFieldValue() as? String, - compareValue.caseInsensitiveCompare(fieldValue) == .orderedSame { + if let fieldValue = formField.formFieldValue() as? String, + compareString.caseInsensitiveCompare(fieldValue) == .orderedSame { valid = true - (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) - } else { - (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) } + + (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) } return valid From 926659c12919291c1ff4883b846a54d4194f8496 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 15 May 2020 16:15:43 -0400 Subject: [PATCH 65/67] dramatic change --- .../Rules/Rules/RuleEqualsIgnoreCaseModel.swift | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift index 090812b3..9f361dfd 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift @@ -34,13 +34,14 @@ public class RuleEqualsIgnoreCaseModel: RulesProtocol { for formKey in fields { guard let formField = fieldMolecules[formKey] else { continue } - guard let compareString = compareText else { - compareText = formField.formFieldValue() as? String - continue + guard let compareString = compareText, + let fieldValue = formField.formFieldValue() as? String + else { + compareText = formField.formFieldValue() as? String + continue } - if let fieldValue = formField.formFieldValue() as? String, - compareString.caseInsensitiveCompare(fieldValue) == .orderedSame { + if compareString.caseInsensitiveCompare(fieldValue) == .orderedSame { valid = true } From ac5bf372eb1e349e133666f3bbd61e293c86c926 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 15 May 2020 16:16:14 -0400 Subject: [PATCH 66/67] undo --- .../Rules/Rules/RuleEqualsIgnoreCaseModel.swift | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift index 9f361dfd..090812b3 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift @@ -34,14 +34,13 @@ public class RuleEqualsIgnoreCaseModel: RulesProtocol { for formKey in fields { guard let formField = fieldMolecules[formKey] else { continue } - guard let compareString = compareText, - let fieldValue = formField.formFieldValue() as? String - else { - compareText = formField.formFieldValue() as? String - continue + guard let compareString = compareText else { + compareText = formField.formFieldValue() as? String + continue } - if compareString.caseInsensitiveCompare(fieldValue) == .orderedSame { + if let fieldValue = formField.formFieldValue() as? String, + compareString.caseInsensitiveCompare(fieldValue) == .orderedSame { valid = true } From 90d5093318cd0d812a269f34cc6d36213ae6fc09 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 15 May 2020 16:25:37 -0400 Subject: [PATCH 67/67] name change --- .../FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift index 090812b3..0bdd7ca3 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift @@ -15,7 +15,7 @@ public class RuleEqualsIgnoreCaseModel: RulesProtocol { //-------------------------------------------------- public static var identifier: String = "equalsIgnoreCase" - public var type: String = RuleEqualsModel.identifier + public var type: String = RuleEqualsIgnoreCaseModel.identifier public var fields: [String] public var errorMessage: [String: String]?