From 1b391272c51e83ac31c132e0e4f21be78a63b57c Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 12 Jul 2024 14:45:20 -0500 Subject: [PATCH 1/6] updated model Signed-off-by: Matt Bruce --- MVMCoreUI/Atomic/Atoms/FormFields/FormFieldModel.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/FormFieldModel.swift b/MVMCoreUI/Atomic/Atoms/FormFields/FormFieldModel.swift index ca6f1e52..c96a8266 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/FormFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/FormFieldModel.swift @@ -25,6 +25,7 @@ import VDS public var readOnly: Bool = false public var showError: Bool? public var errorMessage: String? + public var initialErrorMessage: String? public var fieldKey: String? public var groupName: String = FormValidator.defaultGroupName @@ -89,9 +90,11 @@ import VDS if let ruleErrorMessage = errorMessage, fieldKey != nil { self.errorMessage = ruleErrorMessage + } else { + self.errorMessage = initialErrorMessage } - self.isValid = valid + isValid = valid updateUI?() } @@ -103,6 +106,7 @@ import VDS id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier) errorMessage = try typeContainer.decodeIfPresent(String.self, forKey: .errorMessage) + initialErrorMessage = errorMessage enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true required = try typeContainer.decodeIfPresent(Bool.self, forKey: .required) ?? true readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false From 716550bf23a6e1c7f0b1799c084272c2c5daabe7 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 12 Jul 2024 14:48:36 -0500 Subject: [PATCH 2/6] added new rule Signed-off-by: Matt Bruce --- MVMCoreUI.xcodeproj/project.pbxproj | 4 ++ .../Rules/Rules/RuleVDSModel.swift | 59 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 MVMCoreUI/FormUIHelpers/Rules/Rules/RuleVDSModel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 39bd239c..25045a2f 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -578,6 +578,7 @@ EA17584A2BC97EF100A5C0D9 /* BadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1758492BC97EF100A5C0D9 /* BadgeIndicatorModel.swift */; }; EA17584C2BC9894800A5C0D9 /* ButtonIconModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA17584B2BC9894800A5C0D9 /* ButtonIconModel.swift */; }; EA17584E2BC9895A00A5C0D9 /* ButtonIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA17584D2BC9895A00A5C0D9 /* ButtonIcon.swift */; }; + EA1B02DE2C41BFD200F0758B /* RuleVDSModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1B02DD2C41BFD200F0758B /* RuleVDSModel.swift */; }; EA41F4AC2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA41F4AB2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift */; }; EA5124FD243601600051A3A4 /* BGImageHeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FC243601600051A3A4 /* BGImageHeadlineBodyButton.swift */; }; EA5124FF2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */; }; @@ -1199,6 +1200,7 @@ EA1758492BC97EF100A5C0D9 /* BadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeIndicatorModel.swift; sourceTree = ""; }; EA17584B2BC9894800A5C0D9 /* ButtonIconModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconModel.swift; sourceTree = ""; }; EA17584D2BC9895A00A5C0D9 /* ButtonIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIcon.swift; sourceTree = ""; }; + EA1B02DD2C41BFD200F0758B /* RuleVDSModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleVDSModel.swift; sourceTree = ""; }; EA41F4AB2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicRuleFormFieldEffectModel.swift; sourceTree = ""; }; EA5124FC243601600051A3A4 /* BGImageHeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButton.swift; sourceTree = ""; }; EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButtonModel.swift; sourceTree = ""; }; @@ -1296,6 +1298,7 @@ 011D95A0240453D0000E3791 /* RuleEqualsModel.swift */, 0A849EFD246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift */, FD9912FF28E21E4900542CC3 /* RuleNotEqualsModel.swift */, + EA1B02DD2C41BFD200F0758B /* RuleVDSModel.swift */, ); name = Rules; path = Rules/Rules; @@ -2836,6 +2839,7 @@ D253BB8A24574CC5002DE544 /* StackModel.swift in Sources */, EAB14BC127D935F00012AB2C /* RuleCompareModelProtocol.swift in Sources */, 011D95A924057AC7000E3791 /* FormGroupWatcherFieldProtocol.swift in Sources */, + EA1B02DE2C41BFD200F0758B /* RuleVDSModel.swift in Sources */, EA985C892981AB7100F2FF2E /* VDS-TextStyle.swift in Sources */, BB2BF0EA2452A9BB001D0FC2 /* ListDeviceComplexButtonSmall.swift in Sources */, D20C700B250BFDE40095B21C /* NotificationContainerView.swift in Sources */, diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleVDSModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleVDSModel.swift new file mode 100644 index 00000000..da818e64 --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleVDSModel.swift @@ -0,0 +1,59 @@ +// +// RuleVDSModel.swift +// MVMCoreUI +// +// Created by Matt Bruce on 7/12/24. +// Copyright © 2024 Verizon Wireless. All rights reserved. +// + +import Foundation +import VDS + +open class VDSRuleBase: RuleAnyModelProtocol { + open var ruleId: String? + open var errorMessage: [String : String]? + open var fields = [String]() + public init(){} + + open func isValid(_ formField: any FormFieldProtocol) -> Bool { + fatalError() + } + public static var identifier: String = "AnyVDSRule" +} + +public class RuleVDSModel: VDSRuleBase { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public var rule: AnyRule + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + + public init(field: String, rule: AnyRule) { + self.rule = rule + super.init() + self.fields = [field] + self.ruleId = "\(rule.self)-\(Int.random(in: 1...1000))" + } + + required init(from decoder: any Decoder) throws { + fatalError("init(from:) has not been implemented") + } + + //-------------------------------------------------- + // MARK: - Validation + //-------------------------------------------------- + + public override func isValid(_ formField: FormFieldProtocol) -> Bool { + let value = formField.formFieldValue() as? ValueType + let valid = rule.isValid(value: value) + if let field = fields.first, valid { + errorMessage = [field: rule.errorMessage] + } else { + errorMessage = nil + } + return valid + } +} From c92532334717274d36c0991ab0193d58e9ac8298 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 12 Jul 2024 14:48:48 -0500 Subject: [PATCH 3/6] implemented new protocol Signed-off-by: Matt Bruce --- MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift b/MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift index 7bd05047..8b578fb3 100644 --- a/MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift +++ b/MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift @@ -6,7 +6,7 @@ // Copyright © 2020 Verizon Wireless. All rights reserved. // // Form fields are items can be interacted with. They have value, and may need to be validated. - +import VDS public protocol FormFieldProtocol: FormItemProtocol { @@ -36,6 +36,21 @@ public extension FormFieldProtocol { } } +public protocol FormFieldInternalValidatableProtocol: FormFieldProtocol { + associatedtype ValueType + var rules: [AnyRule]? { get set } + var internalRules: [RuleAnyModelProtocol]? { get } +} + +extension FormFieldInternalValidatableProtocol { + public var internalRules: [RuleAnyModelProtocol]? { + guard let fieldKey else { return nil } + return rules?.compactMap{ rule in + return RuleVDSModel(field: fieldKey, rule: rule) + } + } +} + public class FormFieldValidity{ public var fieldKey: String public var valid: Bool = true From 05e296713109b8b6f3ca59744ac6d34967674c6a Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 12 Jul 2024 14:48:56 -0500 Subject: [PATCH 4/6] add to validator Signed-off-by: Matt Bruce --- MVMCoreUI/FormUIHelpers/FormValidator.swift | 24 ++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/FormUIHelpers/FormValidator.swift b/MVMCoreUI/FormUIHelpers/FormValidator.swift index 3aa50030..b01c7ad4 100644 --- a/MVMCoreUI/FormUIHelpers/FormValidator.swift +++ b/MVMCoreUI/FormUIHelpers/FormValidator.swift @@ -44,6 +44,29 @@ import MVMCore if let fieldKey = field.fieldKey { fields[fieldKey] = field } + // add internal validators if needed + if let field = field as? any FormFieldInternalValidatableProtocol { + addInternalRules(field) + } + } + + /// Adds additional Rules that are from another source + private func addInternalRules(_ field: any FormFieldInternalValidatableProtocol) { + if let internalRules = field.internalRules, !internalRules.isEmpty { + + //find the group + if let formGroup = formRules?.first(where: {$0.groupName == field.groupName}) { + formGroup.rules.append(contentsOf: internalRules) + } else { + //create the new group + let formGroup = FormGroupRule(field.groupName, internalRules, []) + if var formRules { + formRules.append(formGroup) + } else { + formRules = [formGroup] + } + } + } } /// Adds the form action to the validator. @@ -72,7 +95,6 @@ import MVMCore if let validator = delegate?.formValidator { validator.delegate = delegate validator.insert(item) - // TODO: Temporary hacks, rewrite architecture to support this. _ = validator.validate() } From d2eae79f47a1872faf42868d6f2d52759d36daf2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 12 Jul 2024 14:57:56 -0500 Subject: [PATCH 5/6] bug in rule Signed-off-by: Matt Bruce --- MVMCoreUI/FormUIHelpers/Rules/Rules/RuleVDSModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleVDSModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleVDSModel.swift index da818e64..e4cfb2aa 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleVDSModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleVDSModel.swift @@ -49,7 +49,7 @@ public class RuleVDSModel: VDSRuleBase { public override func isValid(_ formField: FormFieldProtocol) -> Bool { let value = formField.formFieldValue() as? ValueType let valid = rule.isValid(value: value) - if let field = fields.first, valid { + if let field = fields.first, !valid { errorMessage = [field: rule.errorMessage] } else { errorMessage = nil From c8496194f0ae98ca2cf4d8199351bfb468a93a2e Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 12 Jul 2024 15:03:46 -0500 Subject: [PATCH 6/6] updated FormField Signed-off-by: Matt Bruce --- MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift b/MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift index 8b578fb3..8490cd69 100644 --- a/MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift +++ b/MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift @@ -37,7 +37,7 @@ public extension FormFieldProtocol { } public protocol FormFieldInternalValidatableProtocol: FormFieldProtocol { - associatedtype ValueType + associatedtype ValueType = AnyHashable var rules: [AnyRule]? { get set } var internalRules: [RuleAnyModelProtocol]? { get } }