Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into bugfix/carousel
This commit is contained in:
commit
bbe3d7693a
@ -92,6 +92,7 @@
|
||||
0A7EF86323D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86223D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift */; };
|
||||
0A7EF86523D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */; };
|
||||
0A7EF86723D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */; };
|
||||
0A849EFE246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A849EFD246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift */; };
|
||||
0A9D091D2433796500D2E6C0 /* BarsCarouselIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D09172433796500D2E6C0 /* BarsCarouselIndicatorModel.swift */; };
|
||||
0A9D091E2433796500D2E6C0 /* NumericCarouselIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D09182433796500D2E6C0 /* NumericCarouselIndicatorModel.swift */; };
|
||||
0A9D091F2433796500D2E6C0 /* NumericIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9D09192433796500D2E6C0 /* NumericIndicatorView.swift */; };
|
||||
@ -109,6 +110,8 @@
|
||||
0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB423FF18D2004C5109 /* Arrow.swift */; };
|
||||
0AE98BB723FF18E9004C5109 /* ArrowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB623FF18E9004C5109 /* ArrowModel.swift */; };
|
||||
279B1569242BBC2F00921D6C /* ActionModelAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279B1568242BBC2F00921D6C /* ActionModelAdapter.swift */; };
|
||||
27F973532466074500CAB5C5 /* PageBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F973522466074500CAB5C5 /* PageBehavior.swift */; };
|
||||
27F9736A246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F97369246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift */; };
|
||||
31BE15CB23D8924D00452370 /* CheckboxLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */; };
|
||||
31BE15CC23D8924D00452370 /* CheckboxModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31BE15CA23D8924C00452370 /* CheckboxModel.swift */; };
|
||||
522679C123FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522679BF23FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift */; };
|
||||
@ -195,6 +198,8 @@
|
||||
AA69AAF62445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA69AAF52445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift */; };
|
||||
AA69AAF82445BF6800AF3D3B /* ListLeftVariableCheckboxBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA69AAF72445BF6800AF3D3B /* ListLeftVariableCheckboxBodyTextModel.swift */; };
|
||||
AA85236C244435A20059CC1E /* RadioSwatchCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */; };
|
||||
AA9972502475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA99724F2475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift */; };
|
||||
AA997252247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA997251247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift */; };
|
||||
AAA74A172410C04600080241 /* HeadersH2NoButtonsBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */; };
|
||||
AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */; };
|
||||
AAB7EDEF246ADA1600E54929 /* ListProgressBarThinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB7EDEE246ADA1600E54929 /* ListProgressBarThinModel.swift */; };
|
||||
@ -506,6 +511,7 @@
|
||||
0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A8321AE2355FE9500CB7F00 /* DigitBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitBox.swift; sourceTree = "<group>"; };
|
||||
0A849EFD246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleEqualsIgnoreCaseModel.swift; sourceTree = "<group>"; };
|
||||
0A9D09172433796500D2E6C0 /* BarsCarouselIndicatorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarsCarouselIndicatorModel.swift; sourceTree = "<group>"; };
|
||||
0A9D09182433796500D2E6C0 /* NumericCarouselIndicatorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumericCarouselIndicatorModel.swift; sourceTree = "<group>"; };
|
||||
0A9D09192433796500D2E6C0 /* NumericIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumericIndicatorView.swift; sourceTree = "<group>"; };
|
||||
@ -524,6 +530,8 @@
|
||||
0AE98BB423FF18D2004C5109 /* Arrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arrow.swift; sourceTree = "<group>"; };
|
||||
0AE98BB623FF18E9004C5109 /* ArrowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowModel.swift; sourceTree = "<group>"; };
|
||||
279B1568242BBC2F00921D6C /* ActionModelAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionModelAdapter.swift; sourceTree = "<group>"; };
|
||||
27F973522466074500CAB5C5 /* PageBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageBehavior.swift; sourceTree = "<group>"; };
|
||||
27F97369246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenBrightnessModifierBehavior.swift; sourceTree = "<group>"; };
|
||||
31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxLabelModel.swift; sourceTree = "<group>"; };
|
||||
31BE15CA23D8924C00452370 /* CheckboxModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxModel.swift; sourceTree = "<group>"; };
|
||||
522679BF23FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableCheckboxAllTextAndLinks.swift; sourceTree = "<group>"; };
|
||||
@ -610,6 +618,8 @@
|
||||
AA69AAF52445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableCheckboxBodyText.swift; sourceTree = "<group>"; };
|
||||
AA69AAF72445BF6800AF3D3B /* ListLeftVariableCheckboxBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableCheckboxBodyTextModel.swift; sourceTree = "<group>"; };
|
||||
AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchCollectionViewCell.swift; sourceTree = "<group>"; };
|
||||
AA99724F2475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconAllTextLinksModel.swift; sourceTree = "<group>"; };
|
||||
AA997251247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconAllTextLinks.swift; sourceTree = "<group>"; };
|
||||
AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyText.swift; sourceTree = "<group>"; };
|
||||
AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyTextModel.swift; sourceTree = "<group>"; };
|
||||
AAB7EDEE246ADA1600E54929 /* ListProgressBarThinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListProgressBarThinModel.swift; sourceTree = "<group>"; };
|
||||
@ -876,6 +886,7 @@
|
||||
011D95A0240453D0000E3791 /* RuleEqualsModel.swift */,
|
||||
011D95A2240453F8000E3791 /* RuleRegexModel.swift */,
|
||||
0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */,
|
||||
0A849EFD246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift */,
|
||||
);
|
||||
name = Rules;
|
||||
path = Rules/Rules;
|
||||
@ -957,6 +968,15 @@
|
||||
path = Adapters;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
27F973512466071600CAB5C5 /* Behaviors */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
27F973522466074500CAB5C5 /* PageBehavior.swift */,
|
||||
27F97369246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift */,
|
||||
);
|
||||
path = Behaviors;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5206F150241144A900658DC5 /* Headers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -1270,6 +1290,8 @@
|
||||
8D24041023E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift */,
|
||||
0A6682A32434DB8D00AD3CA1 /* ListLeftVariableRadioButtonBodyTextModel.swift */,
|
||||
0A6682A12434DB4F00AD3CA1 /* ListLeftVariableRadioButtonBodyText.swift */,
|
||||
AA99724F2475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift */,
|
||||
AA997251247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift */,
|
||||
);
|
||||
path = LeftVariable;
|
||||
sourceTree = "<group>";
|
||||
@ -1396,6 +1418,7 @@
|
||||
D29DF0CE21E404D4003B2FB9 /* MVMCoreUI */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
27F973512466071600CAB5C5 /* Behaviors */,
|
||||
D2C78CD324252F4E00B69FDE /* Atomic */,
|
||||
012A88EF23985E0100FE3DA1 /* CustomPrimitives */,
|
||||
D2B18B7D236090D500A9AEDC /* BaseClasses */,
|
||||
@ -2041,6 +2064,7 @@
|
||||
AA11A42123F15D7000D7962F /* ListRightVariablePaymentsModel.swift in Sources */,
|
||||
011D9626240EBB16000E3791 /* RadioButtonLabelModel.swift in Sources */,
|
||||
8DDD6C1D244D90B8006A2232 /* ListThreeColumnDataUsage.swift in Sources */,
|
||||
0A849EFE246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift in Sources */,
|
||||
D28764FB245A33A500CB882D /* TwoLinkViewModel.swift in Sources */,
|
||||
AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */,
|
||||
D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */,
|
||||
@ -2136,9 +2160,11 @@
|
||||
D2E2A99623D8CF85000B42E6 /* HeadlineBodyLinkToggleModel.swift in Sources */,
|
||||
C6FA7D5323C77A4A00A3614A /* StringAndMoleculeStack.swift in Sources */,
|
||||
011D958524042432000E3791 /* RulesProtocol.swift in Sources */,
|
||||
AA9972502475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift in Sources */,
|
||||
AA69AAF62445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift in Sources */,
|
||||
D264FAA3243E632F00D98315 /* ProgrammaticCollectionViewController.swift in Sources */,
|
||||
D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */,
|
||||
27F9736A246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift in Sources */,
|
||||
D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */,
|
||||
526A265E240D200500B0D828 /* ListTwoColumnCompareChanges.swift in Sources */,
|
||||
8D24041523E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift in Sources */,
|
||||
@ -2228,10 +2254,12 @@
|
||||
948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */,
|
||||
013F801923FB4A8E00AD8013 /* UIContentMode+Extension.swift in Sources */,
|
||||
525239C22407BD1000454969 /* ListTwoColumnPriceDetails.swift in Sources */,
|
||||
AA997252247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift in Sources */,
|
||||
D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */,
|
||||
D23EA7FB2475F09800D60C34 /* CarouselItemProtocol.swift in Sources */,
|
||||
D2E2A9A323E096B1000B42E6 /* DisableableModelProtocol.swift in Sources */,
|
||||
D29DF11821E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m in Sources */,
|
||||
27F973532466074500CAB5C5 /* PageBehavior.swift in Sources */,
|
||||
94C2D9A323872C110006CF46 /* LabelAttributeStrikeThroughModel.swift in Sources */,
|
||||
D28A838523CCCA8900DFE4FC /* ScrollerModel.swift in Sources */,
|
||||
D29DF26C21E6AA0B003B2FB9 /* FLAnimatedImage.m in Sources */,
|
||||
|
||||
@ -322,7 +322,7 @@ import UIKit
|
||||
@objc override open func resignFirstResponder() -> Bool {
|
||||
|
||||
if validateWhenDoneEditing {
|
||||
validateTextField()
|
||||
validateText()
|
||||
}
|
||||
|
||||
selectedDigitBox?.isSelected = false
|
||||
@ -440,7 +440,7 @@ extension DigitEntryField {
|
||||
selectedDigitBox = nil
|
||||
|
||||
if !switchFieldsAutomatically && validateWhenDoneEditing {
|
||||
validateTextField()
|
||||
validateText()
|
||||
}
|
||||
|
||||
proprietorTextDelegate?.textFieldDidEndEditing?(textField)
|
||||
|
||||
@ -49,6 +49,9 @@ import UIKit
|
||||
|
||||
public var isValid: Bool = false
|
||||
|
||||
/// Validate on each entry in the textField. Default: true
|
||||
public var validateEachCharacter: Bool = true
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Computed Properties
|
||||
//--------------------------------------------------
|
||||
@ -229,6 +232,48 @@ import UIKit
|
||||
entryFieldContainer.updateView(size)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Validation
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Validates the text of the entry field.
|
||||
@objc public func validateText() {
|
||||
if let isValid = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) {
|
||||
self.isValid = isValid
|
||||
}
|
||||
}
|
||||
|
||||
/// Executes on .textDidBeginEditingNotification
|
||||
@objc func startEditing() {
|
||||
isSelected = true
|
||||
}
|
||||
|
||||
/// Executes on .textDidChangeNotification (each character entry)
|
||||
@objc func valueChanged() {
|
||||
guard validateEachCharacter else { return }
|
||||
}
|
||||
|
||||
/// Executes on .textDidEndEditingNotification
|
||||
@objc func endInputing() {
|
||||
isSelected = false
|
||||
resignFirstResponder()
|
||||
}
|
||||
|
||||
@objc public func updateValidation(_ isValid: Bool) {
|
||||
let previousValidity = self.isValid
|
||||
self.isValid = isValid
|
||||
|
||||
if previousValidity && !isValid {
|
||||
shouldShowError(true)
|
||||
} else if (!previousValidity && isValid) {
|
||||
shouldShowError(false)
|
||||
}
|
||||
}
|
||||
|
||||
func shouldShowError(_ showError: Bool) {
|
||||
self.showError = showError
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - MoleculeViewProtocol
|
||||
//--------------------------------------------------
|
||||
@ -255,6 +300,18 @@ import UIKit
|
||||
|
||||
entryFieldContainer.set(with: model, delegateObject, additionalData)
|
||||
|
||||
model.updateUI = { [weak self] in
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
guard let self = self else { return }
|
||||
|
||||
if self.isSelected {
|
||||
self.updateValidation(model.isValid ?? true)
|
||||
} else if model.isValid ?? true && self.showError {
|
||||
self.showError = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
title = model.title
|
||||
feedback = model.feedback
|
||||
isEnabled = model.enabled
|
||||
|
||||
@ -71,12 +71,13 @@ import Foundation
|
||||
}
|
||||
|
||||
public func setValidity(_ valid: Bool, rule: RulesProtocol) {
|
||||
if let fieldKey = fieldKey,
|
||||
let ruleErrorMessage = rule.errorMessage?[fieldKey] {
|
||||
|
||||
if let fieldKey = fieldKey, let ruleErrorMessage = rule.errorMessage?[fieldKey] {
|
||||
self.errorMessage = ruleErrorMessage
|
||||
}
|
||||
|
||||
self.isValid = valid
|
||||
|
||||
updateUI?()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -51,9 +51,6 @@ import UIKit
|
||||
|
||||
private var observingForChange: Bool = false
|
||||
|
||||
/// Validate on each entry in the textField. Default: true
|
||||
public var validateEachCharacter: Bool = true
|
||||
|
||||
/// Validate when user resigns editing. Default: true
|
||||
public var validateWhenDoneEditing: Bool = true
|
||||
|
||||
@ -226,7 +223,7 @@ import UIKit
|
||||
@discardableResult
|
||||
@objc override open func resignFirstResponder() -> Bool {
|
||||
if validateWhenDoneEditing {
|
||||
validateTextField()
|
||||
validateText()
|
||||
}
|
||||
textField.resignFirstResponder()
|
||||
isSelected = false
|
||||
@ -234,56 +231,37 @@ import UIKit
|
||||
}
|
||||
|
||||
/// Validates the text of the entry field.
|
||||
@objc public func validateTextField() {
|
||||
@objc public override func validateText() {
|
||||
text = textField.text
|
||||
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
|
||||
super.validateText()
|
||||
}
|
||||
|
||||
@objc public func updateValidation(_ isValid: Bool) {
|
||||
let previousValidity = self.isValid
|
||||
self.isValid = isValid
|
||||
|
||||
if previousValidity && !isValid {
|
||||
shouldShowError(true)
|
||||
} else if (!previousValidity && isValid) {
|
||||
shouldShowError(false)
|
||||
}
|
||||
}
|
||||
|
||||
func shouldShowError(_ showError: Bool) {
|
||||
self.showError = showError
|
||||
if showError {
|
||||
observingTextFieldDelegate?.isValid?(textfield: self)
|
||||
entryFieldContainer.originalUI()
|
||||
} else {
|
||||
observingTextFieldDelegate?.isInvalid?(textfield: self)
|
||||
}
|
||||
}
|
||||
/// Executes on UITextField.textDidBeginEditingNotification
|
||||
@objc func startEditing() {
|
||||
isSelected = true
|
||||
@objc override func startEditing() {
|
||||
super.startEditing()
|
||||
textField.becomeFirstResponder()
|
||||
}
|
||||
|
||||
/// Executes on UITextField.textDidChangeNotification (each character entry)
|
||||
@objc func valueChanged() {
|
||||
guard validateEachCharacter else { return }
|
||||
isSelected = true
|
||||
validateTextField()
|
||||
@objc override func valueChanged() {
|
||||
super.valueChanged()
|
||||
validateText()
|
||||
}
|
||||
|
||||
/// Executes on UITextField.textDidEndEditingNotification
|
||||
@objc func endInputing() {
|
||||
resignFirstResponder()
|
||||
|
||||
@objc override func endInputing() {
|
||||
super.endInputing()
|
||||
|
||||
// Don't show error till user starts typing.
|
||||
guard text?.count ?? 0 != 0 else {
|
||||
showError = false
|
||||
return
|
||||
}
|
||||
|
||||
if let isValid = (model as? TextEntryFieldModel)?.isValid {
|
||||
if let isValid = textEntryFieldModel?.isValid {
|
||||
self.isValid = isValid
|
||||
}
|
||||
|
||||
shouldShowError(!isValid)
|
||||
}
|
||||
|
||||
@ -311,6 +289,16 @@ import UIKit
|
||||
}
|
||||
}
|
||||
|
||||
override func shouldShowError(_ showError: Bool) {
|
||||
super.shouldShowError(showError)
|
||||
|
||||
if showError {
|
||||
observingTextFieldDelegate?.isValid?(textfield: self)
|
||||
} else {
|
||||
observingTextFieldDelegate?.isInvalid?(textfield: self)
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - MoleculeViewProtocol
|
||||
//--------------------------------------------------
|
||||
@ -320,16 +308,6 @@ import UIKit
|
||||
|
||||
guard let model = model as? TextEntryFieldModel else { return }
|
||||
|
||||
model.updateUI = { [weak self] in
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
guard let self = self else { return }
|
||||
|
||||
if self.isSelected {
|
||||
self.updateValidation(model.isValid ?? true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
self.delegateObject = delegateObject
|
||||
FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate)
|
||||
text = model.text
|
||||
|
||||
@ -24,9 +24,6 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Validate on each entry in the textView. Default: true
|
||||
public var validateEachCharacter: Bool = true
|
||||
|
||||
private var observingForChange: Bool = false
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -71,7 +68,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
|
||||
/// The text of this textView.
|
||||
open override var text: String? {
|
||||
get { return textView.text }
|
||||
get { return textViewEntryFieldModel?.text }
|
||||
set {
|
||||
textView.text = newValue
|
||||
textViewEntryFieldModel?.text = newValue
|
||||
@ -186,29 +183,37 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Validates the text of the entry field.
|
||||
@objc public func validateTextView() {
|
||||
@objc public override func validateText() {
|
||||
text = textView.text
|
||||
if let isValid = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) {
|
||||
self.isValid = isValid
|
||||
}
|
||||
super.validateText()
|
||||
}
|
||||
|
||||
/// Executes on UITextView.textDidBeginEditingNotification
|
||||
@objc func startEditing() {
|
||||
isSelected = true
|
||||
@objc override func startEditing() {
|
||||
super.startEditing()
|
||||
_ = textView.becomeFirstResponder()
|
||||
}
|
||||
|
||||
/// Executes on UITextView.textDidChangeNotification (each character entry)
|
||||
@objc func valueChanged() {
|
||||
guard validateEachCharacter else { return }
|
||||
validateTextView()
|
||||
@objc override func valueChanged() {
|
||||
super.valueChanged()
|
||||
validateText()
|
||||
}
|
||||
|
||||
/// Executes on UITextView.textDidEndEditingNotification
|
||||
@objc func endInputing() {
|
||||
resignFirstResponder()
|
||||
isSelected = false
|
||||
@objc override func endInputing() {
|
||||
super.endInputing()
|
||||
|
||||
// Don't show error till user starts typing.
|
||||
guard text?.count ?? 0 != 0 else {
|
||||
showError = false
|
||||
return
|
||||
}
|
||||
|
||||
if let isValid = textViewEntryFieldModel?.isValid {
|
||||
self.isValid = isValid
|
||||
}
|
||||
|
||||
showError = !isValid
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ import UIKit
|
||||
@objcMembers open class LoadImageView: View {
|
||||
public let loadingSpinner = MFLoadingSpinner(frame: .zero)
|
||||
public let imageView = MFTransparentGIFView(frame: .zero)
|
||||
public var addSizeConstraintsForAspectRatio = false
|
||||
public var addSizeConstraintsForAspectRatio = true
|
||||
public var shouldNotifyDelegateOnUpdate = true
|
||||
var centerX: NSLayoutConstraint?
|
||||
var centerY: NSLayoutConstraint?
|
||||
@ -173,7 +173,6 @@ import UIKit
|
||||
} else {
|
||||
heightConstraint?.isActive = false
|
||||
heightConstraint = imageView.heightAnchor.constraint(equalToConstant: height)
|
||||
heightConstraint?.priority = UILayoutPriority(rawValue: 900)
|
||||
}
|
||||
heightConstraint?.isActive = true
|
||||
}
|
||||
@ -183,7 +182,6 @@ import UIKit
|
||||
widthConstraint.constant = width
|
||||
} else {
|
||||
widthConstraint = imageView.widthAnchor.constraint(equalToConstant: width)
|
||||
widthConstraint?.priority = UILayoutPriority(rawValue: 900)
|
||||
}
|
||||
widthConstraint?.isActive = true
|
||||
}
|
||||
|
||||
@ -146,6 +146,7 @@ import Foundation
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableRadioButtonAndPaymentMethod.self, viewModelClass: ListLeftVariableRadioButtonAndPaymentMethodModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableRadioButtonBodyText.self, viewModelClass: ListLeftVariableRadioButtonBodyTextModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableCheckboxBodyText.self, viewModelClass: ListLeftVariableCheckboxBodyTextModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableIconAllTextLinks.self, viewModelClass: ListLeftVariableIconAllTextLinksModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: ListRVWheel.self, viewModelClass: ListRVWheelModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: ListRightVariablePayments.self, viewModelClass: ListRightVariablePaymentsModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: ListRightVariableTotalData.self, viewModelClass: ListRightVariableTotalDataModel.self)
|
||||
@ -194,12 +195,16 @@ import Foundation
|
||||
try? ModelRegistry.register(RuleAnyValueChangedModel.self)
|
||||
try? ModelRegistry.register(RuleAllValueChangedModel.self)
|
||||
try? ModelRegistry.register(RuleEqualsModel.self)
|
||||
try? ModelRegistry.register(RuleEqualsIgnoreCaseModel.self)
|
||||
try? ModelRegistry.register(RuleRegexModel.self)
|
||||
|
||||
// Actions
|
||||
try? ModelRegistry.register(ActionTopAlertModel.self)
|
||||
try? ModelRegistry.register(ActionCollapseNotificationModel.self)
|
||||
try? ModelRegistry.register(ActionOpenPanelModel.self)
|
||||
|
||||
// Behaviors
|
||||
try? ModelRegistry.register(ScreenBrightnessModifierBehavior.self)
|
||||
}
|
||||
|
||||
/// Convenience function to get required modules for a give model
|
||||
|
||||
@ -0,0 +1,54 @@
|
||||
//
|
||||
// ListLeftVariableIconAllTextLinks.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Lekshmi S on 20/05/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@objcMembers open class ListLeftVariableIconAllTextLinks: TableViewCell {
|
||||
//-----------------------------------------------------
|
||||
// MARK: - Outlets
|
||||
//-----------------------------------------------------
|
||||
public let leftImage = LoadImageView()
|
||||
public let eyebrowHeadlineBodyLink = EyebrowHeadlineBodyLink(frame: .zero)
|
||||
public var stack: Stack<StackModel>
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
stack = Stack<StackModel>.createStack(with: [(view: leftImage, model: StackItemModel(horizontalAlignment: .fill)), (view: eyebrowHeadlineBodyLink, model: StackItemModel(horizontalAlignment: .leading))], axis: .horizontal)
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
}
|
||||
|
||||
public required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Life Cycle
|
||||
//--------------------------------------------------
|
||||
override open func setupView() {
|
||||
super.setupView()
|
||||
leftImage.addSizeConstraintsForAspectRatio = true
|
||||
leftImage.imageView.contentMode = .scaleAspectFit
|
||||
addMolecule(stack)
|
||||
stack.restack()
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - Molecule
|
||||
//------------------------------------------------------
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
guard let model = model as? ListLeftVariableIconAllTextLinksModel else { return }
|
||||
leftImage.set(with: model.image, delegateObject, additionalData)
|
||||
eyebrowHeadlineBodyLink.set(with: model.eyebrowHeadlineBodyLink, delegateObject, additionalData)
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 140
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
//
|
||||
// ListLeftVariableIconAllTextLinksModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Lekshmi S on 20/05/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
public class ListLeftVariableIconAllTextLinksModel: ListItemModel, MoleculeModelProtocol {
|
||||
public static var identifier: String = "listLVImgAll"
|
||||
public var image: ImageViewModel
|
||||
public var eyebrowHeadlineBodyLink: EyebrowHeadlineBodyLinkModel
|
||||
|
||||
override public func setDefaults() {
|
||||
super.setDefaults()
|
||||
if image.width == nil, image.height == nil {
|
||||
image.width = 30
|
||||
image.height = 30
|
||||
}
|
||||
}
|
||||
|
||||
public init(image: ImageViewModel, eyebrowHeadlineBodyLink: EyebrowHeadlineBodyLinkModel) {
|
||||
self.image = image
|
||||
self.eyebrowHeadlineBodyLink = eyebrowHeadlineBodyLink
|
||||
super.init()
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case image
|
||||
case eyebrowHeadlineBodyLink
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
image = try typeContainer.decode(ImageViewModel.self, forKey: .image)
|
||||
eyebrowHeadlineBodyLink = try typeContainer.decode(EyebrowHeadlineBodyLinkModel.self, forKey: .eyebrowHeadlineBodyLink)
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(image, forKey: .image)
|
||||
try container.encode(eyebrowHeadlineBodyLink, forKey: .eyebrowHeadlineBodyLink)
|
||||
}
|
||||
}
|
||||
@ -28,6 +28,7 @@ import Foundation
|
||||
public var screenHeading: String?
|
||||
public var navigationItem: (NavigationItemModelProtocol & MoleculeModelProtocol)?
|
||||
public var formRules: [FormGroupRule]?
|
||||
public var behaviors: [PageBehaviorProtocol]?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
@ -47,6 +48,7 @@ import Foundation
|
||||
case screenHeading
|
||||
case backgroundColor
|
||||
case formRules
|
||||
case behaviors
|
||||
case navigationItem
|
||||
}
|
||||
|
||||
@ -60,6 +62,7 @@ import Foundation
|
||||
screenHeading = try typeContainer.decodeIfPresent(String.self, forKey: .screenHeading)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
formRules = try typeContainer.decodeIfPresent([FormGroupRule].self, forKey: .formRules)
|
||||
behaviors = try typeContainer.decodeModelsIfPresent(codingKey: .behaviors)
|
||||
navigationItem = try typeContainer.decodeModelIfPresent(codingKey: .navigationItem)
|
||||
}
|
||||
|
||||
|
||||
@ -8,6 +8,6 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol MVMControllerModelProtocol: TemplateModelProtocol, FormHolderModelProtocol {
|
||||
public protocol MVMControllerModelProtocol: TemplateModelProtocol, FormHolderModelProtocol, PageBehaviorsTemplateProtocol {
|
||||
|
||||
}
|
||||
|
||||
@ -310,6 +310,18 @@ import UIKit
|
||||
MVMCoreUISession.sharedGlobal()?.currentPageType = pageType
|
||||
MVMCoreUILoggingHandler.shared()?.defaultLogPageState(forController: self)
|
||||
}
|
||||
|
||||
executeBehaviors { (behavior: PageVisibilityBehavior) in
|
||||
behavior.onPageShown()
|
||||
}
|
||||
}
|
||||
|
||||
open override func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidDisappear(animated)
|
||||
|
||||
executeBehaviors { (behavior: PageVisibilityBehavior) in
|
||||
behavior.onPageHidden()
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
@ -424,4 +436,9 @@ import UIKit
|
||||
selectedField = nil
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Behavior Execution
|
||||
func executeBehaviors<T>(_ behaviorBlock:(_ behavior:T)->Void) {
|
||||
pageModel?.behaviors?.compactMap({ $0 as? T }).forEach({ behaviorBlock($0) })
|
||||
}
|
||||
}
|
||||
|
||||
44
MVMCoreUI/Behaviors/PageBehavior.swift
Normal file
44
MVMCoreUI/Behaviors/PageBehavior.swift
Normal file
@ -0,0 +1,44 @@
|
||||
//
|
||||
// PageBehaviors.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kyle on 5/8/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol PageBehaviorProtocol: ModelProtocol {
|
||||
|
||||
// The type of rule
|
||||
var behaviorName: String { get }
|
||||
|
||||
}
|
||||
|
||||
public extension PageBehaviorProtocol {
|
||||
|
||||
var behaviorName: String {
|
||||
get { return Self.identifier }
|
||||
}
|
||||
|
||||
static var categoryCodingKey: String {
|
||||
return "behaviorName"
|
||||
}
|
||||
|
||||
static var categoryName: String {
|
||||
return "\(PageBehaviorProtocol.self)"
|
||||
}
|
||||
}
|
||||
|
||||
public protocol PageVisibilityBehavior: PageBehaviorProtocol {
|
||||
|
||||
func onPageShown()
|
||||
func onPageHidden()
|
||||
|
||||
}
|
||||
|
||||
public protocol PageBehaviorsTemplateProtocol {
|
||||
|
||||
var behaviors: [PageBehaviorProtocol]? { get }
|
||||
|
||||
}
|
||||
68
MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift
Normal file
68
MVMCoreUI/Behaviors/ScreenBrightnessModifierBehavior.swift
Normal file
@ -0,0 +1,68 @@
|
||||
//
|
||||
// ScreenBrightnessModifierBehavior.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kyle on 5/9/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
public class ScreenBrightnessModifierBehavior: PageVisibilityBehavior {
|
||||
|
||||
public static var identifier = "screenBrightnessModifier"
|
||||
|
||||
@Clamping(range: 0...1) var screenBrightness: CGFloat
|
||||
|
||||
var originalScreenBrightness: CGFloat?
|
||||
|
||||
//MARK:- PageVisibilityBehavior
|
||||
|
||||
public func onPageShown() {
|
||||
changeScreenBrightness()
|
||||
}
|
||||
|
||||
public func onPageHidden() {
|
||||
restoreScreenBrightness()
|
||||
}
|
||||
|
||||
//MARK:- Behavior
|
||||
|
||||
func changeScreenBrightness() {
|
||||
guard originalScreenBrightness == nil else { return }
|
||||
originalScreenBrightness = UIScreen.main.brightness
|
||||
UIScreen.main.brightness = screenBrightness
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(willResignActive), name: UIApplication.willResignActiveNotification, object: nil)
|
||||
}
|
||||
|
||||
func restoreScreenBrightness() {
|
||||
guard let originalScreenBrightness = originalScreenBrightness else { return }
|
||||
UIScreen.main.brightness = originalScreenBrightness
|
||||
self.originalScreenBrightness = nil
|
||||
NotificationCenter.default.removeObserver(self, name: UIApplication.willResignActiveNotification, object: nil)
|
||||
}
|
||||
|
||||
@objc func willResignActive() {
|
||||
restoreScreenBrightness()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
|
||||
}
|
||||
|
||||
@objc func didBecomeActive() {
|
||||
NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
|
||||
changeScreenBrightness()
|
||||
}
|
||||
|
||||
//MARK:- Codable
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case screenBrightness
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
screenBrightness = try typeContainer.decode(CGFloat.self, forKey: .screenBrightness)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(screenBrightness, forKey: .screenBrightness)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
//
|
||||
// RuleEqualsIgnoreCaseModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Kevin Christiano on 5/15/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public class RuleEqualsIgnoreCaseModel: RulesProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var identifier: String = "equalsIgnoreCase"
|
||||
public var type: String = RuleEqualsIgnoreCaseModel.identifier
|
||||
public var fields: [String]
|
||||
public var errorMessage: [String: String]?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Validation
|
||||
//--------------------------------------------------
|
||||
|
||||
public func isValid(_ formField: FormFieldProtocol) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
public func validate(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool {
|
||||
var valid = false
|
||||
var compareText: String?
|
||||
|
||||
for formKey in fields {
|
||||
guard let formField = fieldMolecules[formKey] else { continue }
|
||||
|
||||
guard let compareString = compareText else {
|
||||
compareText = formField.formFieldValue() as? String
|
||||
continue
|
||||
}
|
||||
|
||||
if let fieldValue = formField.formFieldValue() as? String,
|
||||
compareString.caseInsensitiveCompare(fieldValue) == .orderedSame {
|
||||
valid = true
|
||||
for formKey in fields {
|
||||
guard let formField = fieldMolecules[formKey] else { continue }
|
||||
(formField as? FormRuleWatcherFieldProtocol)?.setValidity(true, rule: self)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
(formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self)
|
||||
}
|
||||
|
||||
return valid
|
||||
}
|
||||
}
|
||||
@ -24,6 +24,7 @@ public class RuleRequiredModel: RulesProtocol {
|
||||
//--------------------------------------------------
|
||||
|
||||
public func isValid(_ formField: FormFieldProtocol) -> Bool {
|
||||
|
||||
guard let value = formField.formFieldValue() else { return false }
|
||||
|
||||
var valid = true
|
||||
|
||||
Loading…
Reference in New Issue
Block a user