From 89c62040031c79421b912d1a798a74576f35ef13 Mon Sep 17 00:00:00 2001 From: "Suresh, Kamlesh" Date: Tue, 5 May 2020 20:20:50 -0400 Subject: [PATCH 01/28] 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 02/28] 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 03/28] 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 04/28] 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 fcca1e3e8310b7d0add4ce2dd8b05d62bf08809b Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 7 May 2020 13:01:04 -0400 Subject: [PATCH 05/28] 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 06/28] 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 1ea6f9a3b71e1f72d2fa85825d9ed1f157a0d84a Mon Sep 17 00:00:00 2001 From: "Suresh, Kamlesh" Date: Thu, 7 May 2020 20:34:38 -0400 Subject: [PATCH 07/28] 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 08/28] 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 09/28] 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 10/28] 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 11/28] 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 12/28] 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 13/28] 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 14/28] 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 15/28] 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 e6c0145efa9cd122f2119f013e63792dcc022b96 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 11 May 2020 13:44:11 -0400 Subject: [PATCH 16/28] 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 4fd654c3725a5a49edb486f6bf52daf7246353e9 Mon Sep 17 00:00:00 2001 From: "Suresh, Kamlesh" Date: Mon, 11 May 2020 20:05:51 -0400 Subject: [PATCH 17/28] 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 64a99da609f2de5e674a8831796c1ff0a7f808f3 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 12 May 2020 15:30:32 -0400 Subject: [PATCH 18/28] 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 19/28] 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 6f1b3000174653114cbc599b86b1b7da6d76f41f Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 12 May 2020 16:12:39 -0400 Subject: [PATCH 20/28] 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 21/28] 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 a2451a523daff0efb1f0f0caf78245b7d3a80ae9 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 13 May 2020 09:25:32 -0400 Subject: [PATCH 22/28] 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 19a6ef8a2ae0916c775e01485d40da9aae13569a Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 13 May 2020 10:23:44 -0400 Subject: [PATCH 23/28] 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 24/28] 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 25/28] 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 26/28] 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 27/28] 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 28/28] 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,