Merge branch 'feature/form_page' into 'develop'

changes

See merge request BPHV_MIPS/mvm_core_ui!289
This commit is contained in:
Pan, Xinlei (Ryan) 2020-03-13 20:51:33 -04:00
commit 1cc0830d73
60 changed files with 923 additions and 741 deletions

View File

@ -10,12 +10,25 @@
01004F3022721C3800991ECC /* RadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01004F2F22721C3800991ECC /* RadioButton.swift */; };
0103B84E23D7E33A009C315C /* HeadlineBodyToggleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0103B84D23D7E33A009C315C /* HeadlineBodyToggleModel.swift */; };
0105618D224BBE7700E1557D /* FormValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618A224BBE7700E1557D /* FormValidator.swift */; };
0105618E224BBE7700E1557D /* FormValidator+TextFields.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */; };
0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */; };
0116A4E5228B19640094F3ED /* RadioButtonSelectionHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0116A4E4228B19640094F3ED /* RadioButtonSelectionHelper.swift */; };
011B58F023A2AA980085F53C /* ListItemModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011B58EF23A2AA980085F53C /* ListItemModelProtocol.swift */; };
011B58F223A2AE2C0085F53C /* DropDownListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011B58F123A2AE2C0085F53C /* DropDownListItemModel.swift */; };
011D958524042432000E3791 /* RulesProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D958424042432000E3791 /* RulesProtocol.swift */; };
011D958724042492000E3791 /* FormFieldProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D958624042492000E3791 /* FormFieldProtocol.swift */; };
011D95892404249B000E3791 /* FormProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D95882404249B000E3791 /* FormProtocol.swift */; };
011D959B240451E3000E3791 /* RuleRequiredModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D959A240451E3000E3791 /* RuleRequiredModel.swift */; };
011D959D2404536F000E3791 /* RuleAnyValueChangedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D959C2404536F000E3791 /* RuleAnyValueChangedModel.swift */; };
011D959F240453A1000E3791 /* RuleAllValueChangedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D959E240453A1000E3791 /* RuleAllValueChangedModel.swift */; };
011D95A1240453D0000E3791 /* RuleEqualsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D95A0240453D0000E3791 /* RuleEqualsModel.swift */; };
011D95A3240453F8000E3791 /* RuleRegexModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D95A2240453F8000E3791 /* RuleRegexModel.swift */; };
011D95A5240455DC000E3791 /* FormGroupRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D95A4240455DC000E3791 /* FormGroupRule.swift */; };
011D95A924057AC7000E3791 /* FormActionFieldProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D95A824057AC7000E3791 /* FormActionFieldProtocol.swift */; };
011D95AB2405C553000E3791 /* FormItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D95AA2405C553000E3791 /* FormItemProtocol.swift */; };
011D95AD2406BB57000E3791 /* FormHolderProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D95AC2406BB57000E3791 /* FormHolderProtocol.swift */; };
011D95AF2407266E000E3791 /* RadioButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D95AE2407266E000E3791 /* RadioButtonModel.swift */; };
011D9602240DA20A000E3791 /* ValidProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D9601240DA20A000E3791 /* ValidProtocol.swift */; };
011D9626240EBB16000E3791 /* RadioButtonLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D9625240EBB16000E3791 /* RadioButtonLabelModel.swift */; };
011D9628240EFA1E000E3791 /* MFViewController+Form.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D9627240EFA1E000E3791 /* MFViewController+Form.swift */; };
012A889C23889E8400FE3DA1 /* TemplateModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A889B23889E8400FE3DA1 /* TemplateModelProtocol.swift */; };
012A88AD238C418100FE3DA1 /* TemplateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */; };
012A88B1238C880100FE3DA1 /* CarouselPagingModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88B0238C880100FE3DA1 /* CarouselPagingModelProtocol.swift */; };
@ -26,7 +39,6 @@
012A88DB238ED45900FE3DA1 /* CarouselModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88AE238C626E00FE3DA1 /* CarouselModel.swift */; };
012A88EC238F084D00FE3DA1 /* FooterModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88EB238F084D00FE3DA1 /* FooterModel.swift */; };
012A88F123985E0100FE3DA1 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88F023985E0100FE3DA1 /* Color.swift */; };
012CA99A2384A687003F810F /* MFTextField+ModelExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA9992384A687003F810F /* MFTextField+ModelExtension.swift */; };
012CA99E2385A2D3003F810F /* MFView+ModelExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA99D2385A2D3003F810F /* MFView+ModelExtension.swift */; };
013F801923FB4A8E00AD8013 /* UIContentMode+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 013F801823FB4A8E00AD8013 /* UIContentMode+Extension.swift */; };
014AA72423C501E2006F3E93 /* MoleculeContainerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014AA72123C501E2006F3E93 /* MoleculeContainerModel.swift */; };
@ -43,13 +55,11 @@
017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */; };
017BEB3C2361EA1D0024EF95 /* MFViewController+Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017BEB3B2361EA1D0024EF95 /* MFViewController+Model.swift */; };
017BEB4023620A230024EF95 /* TextFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017BEB3F23620A230024EF95 /* TextFieldModel.swift */; };
017BEB4223620AD20024EF95 /* FormModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017BEB4123620AD20024EF95 /* FormModelProtocol.swift */; };
017BEB442362192F0024EF95 /* MVMCoreUIMoleculeMappingObject+ModelExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017BEB432362192F0024EF95 /* MVMCoreUIMoleculeMappingObject+ModelExtension.swift */; };
017BEB48236230DB0024EF95 /* MoleculeViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017BEB47236230DB0024EF95 /* MoleculeViewProtocol.swift */; };
017BEB4A236235BA0024EF95 /* ModelMoleculeViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017BEB49236235BA0024EF95 /* ModelMoleculeViewProtocol.swift */; };
017BEB7B236763000024EF95 /* LineModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017BEB7A236763000024EF95 /* LineModel.swift */; };
017BEB7F23676E870024EF95 /* MoleculeObjectMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017BEB7E23676E870024EF95 /* MoleculeObjectMapping.swift */; };
0198F79F225679880066C936 /* FormValidationProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0198F79E225679870066C936 /* FormValidationProtocol.swift */; };
0198F7A62256A80B0066C936 /* MFRadioButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 0198F7A02256A80A0066C936 /* MFRadioButton.h */; settings = {ATTRIBUTES = (Public, ); }; };
0198F7A82256A80B0066C936 /* MFRadioButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 0198F7A22256A80A0066C936 /* MFRadioButton.m */; };
01C851D323CF9E740021F976 /* LabelToggleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01C851D223CF9E740021F976 /* LabelToggleModel.swift */; };
@ -81,6 +91,7 @@
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 */; };
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 */; };
0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; };
@ -373,12 +384,25 @@
01004F2F22721C3800991ECC /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = "<group>"; };
0103B84D23D7E33A009C315C /* HeadlineBodyToggleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyToggleModel.swift; sourceTree = "<group>"; };
0105618A224BBE7700E1557D /* FormValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormValidator.swift; sourceTree = "<group>"; };
0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+TextFields.swift"; sourceTree = "<group>"; };
0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+FormParams.swift"; sourceTree = "<group>"; };
0116A4E4228B19640094F3ED /* RadioButtonSelectionHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonSelectionHelper.swift; sourceTree = "<group>"; };
011B58EF23A2AA980085F53C /* ListItemModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemModelProtocol.swift; sourceTree = "<group>"; };
011B58F123A2AE2C0085F53C /* DropDownListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropDownListItemModel.swift; sourceTree = "<group>"; };
011D958424042432000E3791 /* RulesProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RulesProtocol.swift; sourceTree = "<group>"; };
011D958624042492000E3791 /* FormFieldProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormFieldProtocol.swift; sourceTree = "<group>"; };
011D95882404249B000E3791 /* FormProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormProtocol.swift; sourceTree = "<group>"; };
011D959A240451E3000E3791 /* RuleRequiredModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleRequiredModel.swift; sourceTree = "<group>"; };
011D959C2404536F000E3791 /* RuleAnyValueChangedModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyValueChangedModel.swift; sourceTree = "<group>"; };
011D959E240453A1000E3791 /* RuleAllValueChangedModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAllValueChangedModel.swift; sourceTree = "<group>"; };
011D95A0240453D0000E3791 /* RuleEqualsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleEqualsModel.swift; sourceTree = "<group>"; };
011D95A2240453F8000E3791 /* RuleRegexModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleRegexModel.swift; sourceTree = "<group>"; };
011D95A4240455DC000E3791 /* FormGroupRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormGroupRule.swift; sourceTree = "<group>"; };
011D95A824057AC7000E3791 /* FormActionFieldProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormActionFieldProtocol.swift; sourceTree = "<group>"; };
011D95AA2405C553000E3791 /* FormItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormItemProtocol.swift; sourceTree = "<group>"; };
011D95AC2406BB57000E3791 /* FormHolderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormHolderProtocol.swift; sourceTree = "<group>"; };
011D95AE2407266E000E3791 /* RadioButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonModel.swift; sourceTree = "<group>"; };
011D9601240DA20A000E3791 /* ValidProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidProtocol.swift; sourceTree = "<group>"; };
011D9625240EBB16000E3791 /* RadioButtonLabelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioButtonLabelModel.swift; sourceTree = "<group>"; };
011D9627240EFA1E000E3791 /* MFViewController+Form.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFViewController+Form.swift"; sourceTree = "<group>"; };
012A889B23889E8400FE3DA1 /* TemplateModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateModelProtocol.swift; sourceTree = "<group>"; };
012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateProtocol.swift; sourceTree = "<group>"; };
012A88AE238C626E00FE3DA1 /* CarouselModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselModel.swift; sourceTree = "<group>"; };
@ -389,7 +413,6 @@
012A88C7238DB02000FE3DA1 /* ModelMoleculeDelegateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelMoleculeDelegateProtocol.swift; sourceTree = "<group>"; };
012A88EB238F084D00FE3DA1 /* FooterModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FooterModel.swift; sourceTree = "<group>"; };
012A88F023985E0100FE3DA1 /* Color.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = "<group>"; };
012CA9992384A687003F810F /* MFTextField+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFTextField+ModelExtension.swift"; sourceTree = "<group>"; };
012CA99D2385A2D3003F810F /* MFView+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFView+ModelExtension.swift"; sourceTree = "<group>"; };
013F801823FB4A8E00AD8013 /* UIContentMode+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIContentMode+Extension.swift"; sourceTree = "<group>"; };
014AA72123C501E2006F3E93 /* MoleculeContainerModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeContainerModel.swift; sourceTree = "<group>"; };
@ -406,13 +429,11 @@
017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioButtonLabel.swift; sourceTree = "<group>"; };
017BEB3B2361EA1D0024EF95 /* MFViewController+Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFViewController+Model.swift"; sourceTree = "<group>"; };
017BEB3F23620A230024EF95 /* TextFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldModel.swift; sourceTree = "<group>"; };
017BEB4123620AD20024EF95 /* FormModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormModelProtocol.swift; sourceTree = "<group>"; };
017BEB432362192F0024EF95 /* MVMCoreUIMoleculeMappingObject+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUIMoleculeMappingObject+ModelExtension.swift"; sourceTree = "<group>"; };
017BEB47236230DB0024EF95 /* MoleculeViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeViewProtocol.swift; sourceTree = "<group>"; };
017BEB49236235BA0024EF95 /* ModelMoleculeViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelMoleculeViewProtocol.swift; sourceTree = "<group>"; };
017BEB7A236763000024EF95 /* LineModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineModel.swift; sourceTree = "<group>"; };
017BEB7E23676E870024EF95 /* MoleculeObjectMapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeObjectMapping.swift; sourceTree = "<group>"; };
0198F79E225679870066C936 /* FormValidationProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormValidationProtocol.swift; sourceTree = "<group>"; };
0198F7A02256A80A0066C936 /* MFRadioButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFRadioButton.h; sourceTree = "<group>"; };
0198F7A22256A80A0066C936 /* MFRadioButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFRadioButton.m; sourceTree = "<group>"; };
01C851D223CF9E740021F976 /* LabelToggleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelToggleModel.swift; sourceTree = "<group>"; };
@ -432,6 +453,7 @@
0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.swift"; sourceTree = "<group>"; };
0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = "<group>"; };
0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesProtocol.swift; sourceTree = "<group>"; };
0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyRequiredModel.swift; sourceTree = "<group>"; };
0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseDropdownEntryField.swift; sourceTree = "<group>"; };
0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = "<group>"; };
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = "<group>"; };
@ -752,7 +774,6 @@
isa = PBXGroup;
children = (
014AA72323C501E2006F3E93 /* ContainerModelProtocol.swift */,
017BEB4123620AD20024EF95 /* FormModelProtocol.swift */,
012A88C3238D86E600FE3DA1 /* CarouselItemModelProtocol.swift */,
012A88B0238C880100FE3DA1 /* CarouselPagingModelProtocol.swift */,
01EB3683236097C0006832FA /* MoleculeModelProtocol.swift */,
@ -764,6 +785,22 @@
path = ModelProtocols;
sourceTree = "<group>";
};
011D958A24042794000E3791 /* Rules */ = {
isa = PBXGroup;
children = (
011D958424042432000E3791 /* RulesProtocol.swift */,
011D959A240451E3000E3791 /* RuleRequiredModel.swift */,
011D959C2404536F000E3791 /* RuleAnyValueChangedModel.swift */,
011D959E240453A1000E3791 /* RuleAllValueChangedModel.swift */,
011D95A0240453D0000E3791 /* RuleEqualsModel.swift */,
011D95A2240453F8000E3791 /* RuleRegexModel.swift */,
011D95A4240455DC000E3791 /* FormGroupRule.swift */,
0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */,
);
name = Rules;
path = Rules/Rules;
sourceTree = "<group>";
};
012A88EF23985E0100FE3DA1 /* CustomPrimitives */ = {
isa = PBXGroup;
children = (
@ -783,10 +820,14 @@
01C74D87224298E2009C25A3 /* FormUIHelpers */ = {
isa = PBXGroup;
children = (
0198F79E225679870066C936 /* FormValidationProtocol.swift */,
011D95882404249B000E3791 /* FormProtocol.swift */,
011D95AC2406BB57000E3791 /* FormHolderProtocol.swift */,
011D95AA2405C553000E3791 /* FormItemProtocol.swift */,
011D958624042492000E3791 /* FormFieldProtocol.swift */,
011D95A824057AC7000E3791 /* FormActionFieldProtocol.swift */,
011D9601240DA20A000E3791 /* ValidProtocol.swift */,
0105618A224BBE7700E1557D /* FormValidator.swift */,
0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */,
0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */,
011D958A24042794000E3791 /* Rules */,
);
path = FormUIHelpers;
sourceTree = "<group>";
@ -1225,6 +1266,7 @@
D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */,
D28A838423CCCA8900DFE4FC /* ScrollerModel.swift */,
D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */,
011D9625240EBB16000E3791 /* RadioButtonLabelModel.swift */,
017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */,
017BEB47236230DB0024EF95 /* MoleculeViewProtocol.swift */,
017BEB49236235BA0024EF95 /* ModelMoleculeViewProtocol.swift */,
@ -1239,6 +1281,7 @@
D29DF16021E69996003B2FB9 /* MFViewController.h */,
D29DF15F21E69996003B2FB9 /* MFViewController.m */,
017BEB3B2361EA1D0024EF95 /* MFViewController+Model.swift */,
011D9627240EFA1E000E3791 /* MFViewController+Form.swift */,
D29DF28F21E7ADB8003B2FB9 /* MFScrollingViewController.h */,
D29DF29021E7ADB8003B2FB9 /* MFScrollingViewController.m */,
D29DF29121E7ADB8003B2FB9 /* ProgrammaticScrollViewController.h */,
@ -1411,7 +1454,6 @@
0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */,
0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */,
017BEB3F23620A230024EF95 /* TextFieldModel.swift */,
012CA9992384A687003F810F /* MFTextField+ModelExtension.swift */,
);
path = TextFields;
sourceTree = "<group>";
@ -1735,6 +1777,7 @@
D28A838123CCB0D800DFE4FC /* AccordionListItemModel.swift in Sources */,
DBC4391822442197001AB423 /* CaretView.swift in Sources */,
C07065C42395677300FBF997 /* Link.swift in Sources */,
0A69F611241BDEA700F7231B /* RuleAnyRequiredModel.swift in Sources */,
D29770F221F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m in Sources */,
D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */,
D28A838923CCCFCB00DFE4FC /* LinkModel.swift in Sources */,
@ -1757,6 +1800,7 @@
D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */,
D29DF11721E6805F003B2FB9 /* UIColor+MFConvenience.m in Sources */,
D2B18B7F2360913400A9AEDC /* Control.swift in Sources */,
011D95A924057AC7000E3791 /* FormActionFieldProtocol.swift in Sources */,
0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */,
D29DF12F21E6851E003B2FB9 /* MVMCoreUITopAlertMainView.m in Sources */,
942C378C2412F4FA0066E45E /* ModalMoleculeListTemplate.swift in Sources */,
@ -1771,9 +1815,11 @@
9445891F2385D2E900DE9FD4 /* CaretViewModel.swift in Sources */,
01C851D323CF9E740021F976 /* LabelToggleModel.swift in Sources */,
D29DF2C521E7BF57003B2FB9 /* MFTabBarSwipeAnimator.m in Sources */,
011D95A3240453F8000E3791 /* RuleRegexModel.swift in Sources */,
D2E2A98323D8B32D000B42E6 /* EyebrowHeadlineBodyLinkModel.swift in Sources */,
012A88AD238C418100FE3DA1 /* TemplateProtocol.swift in Sources */,
D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */,
011D9602240DA20A000E3791 /* ValidProtocol.swift in Sources */,
D260106323D0C05000764D80 /* StackItemModel.swift in Sources */,
D2E2A99823D8D63C000B42E6 /* ActionDetailWithImageModel.swift in Sources */,
D2E2A99D23DA3217000B42E6 /* UIStackViewAlignment+Extension.swift in Sources */,
@ -1814,6 +1860,7 @@
AA11A42123F15D7000D7962F /* ListRightVariablePaymentsModel.swift in Sources */,
01EB369223609801006832FA /* MoleculeStackModel.swift in Sources */,
012CA99E2385A2D3003F810F /* MFView+ModelExtension.swift in Sources */,
011D9626240EBB16000E3791 /* RadioButtonLabelModel.swift in Sources */,
D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */,
944589232385DA9600DE9FD4 /* ImageViewModel.swift in Sources */,
D213347723843825008E41B3 /* Line.swift in Sources */,
@ -1830,6 +1877,7 @@
DBEFFA04225A829700230692 /* Label.swift in Sources */,
D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */,
0A7EF85F23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift in Sources */,
011D959B240451E3000E3791 /* RuleRequiredModel.swift in Sources */,
01509D952327ED1900EF99AA /* HeadlineBodyLinkToggle.swift in Sources */,
31BE15CB23D8924D00452370 /* CheckboxLabelModel.swift in Sources */,
D260105523CEA7DC00764D80 /* MVMCoreUISwitch+Model.swift in Sources */,
@ -1860,7 +1908,6 @@
D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */,
01EB368F23609801006832FA /* LabelModel.swift in Sources */,
942C378E2412F5B60066E45E /* ModalMoleculeStackTemplate.swift in Sources */,
0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */,
01F2A03223A4498200D954D8 /* CaretLinkModel.swift in Sources */,
0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */,
011B58F023A2AA980085F53C /* ListItemModelProtocol.swift in Sources */,
@ -1875,6 +1922,7 @@
017BEB7B236763000024EF95 /* LineModel.swift in Sources */,
D256E9932412880000360572 /* Header.swift in Sources */,
94C2D9A523872C350006CF46 /* LabelAttributeFontModel.swift in Sources */,
011D958724042492000E3791 /* FormFieldProtocol.swift in Sources */,
011D95AF2407266E000E3791 /* RadioButtonModel.swift in Sources */,
017BEB7F23676E870024EF95 /* MoleculeObjectMapping.swift in Sources */,
D274CA332236A78900B01B62 /* FooterView.swift in Sources */,
@ -1887,6 +1935,7 @@
944589212385D6E900DE9FD4 /* DashLineModel.swift in Sources */,
D2E2A99623D8CF85000B42E6 /* HeadlineBodyLinkToggleModel.swift in Sources */,
C6FA7D5323C77A4A00A3614A /* StringAndMoleculeStack.swift in Sources */,
011D958524042432000E3791 /* RulesProtocol.swift in Sources */,
94AF4A3F23E9D13900676048 /* MFCaretButton.m in Sources */,
D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */,
D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */,
@ -1896,6 +1945,7 @@
012A88B1238C880100FE3DA1 /* CarouselPagingModelProtocol.swift in Sources */,
D29DF2C921E7BFC6003B2FB9 /* MFSizeObject.m in Sources */,
9445890E2385C3F800DE9FD4 /* MultiProgressModel.swift in Sources */,
011D95A5240455DC000E3791 /* FormGroupRule.swift in Sources */,
D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */,
D2A6390122CBB1820052ED1F /* Carousel.swift in Sources */,
D29DF2C721E7BF57003B2FB9 /* MFTabBarInteractor.m in Sources */,
@ -1917,7 +1967,6 @@
D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */,
C695A67F23C9830600BFB94E /* UnOrderedListModel.swift in Sources */,
0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */,
017BEB4223620AD20024EF95 /* FormModelProtocol.swift in Sources */,
D2D90B442404789000DD6EC9 /* MoleculeContainerProtocol.swift in Sources */,
012A88DB238ED45900FE3DA1 /* CarouselModel.swift in Sources */,
D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */,
@ -1925,11 +1974,9 @@
D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */,
017BEB4A236235BA0024EF95 /* ModelMoleculeViewProtocol.swift in Sources */,
C695A68123C9830D00BFB94E /* NumberedListModel.swift in Sources */,
012CA99A2384A687003F810F /* MFTextField+ModelExtension.swift in Sources */,
01EB3684236097C0006832FA /* MoleculeModelProtocol.swift in Sources */,
D27CD4102339057800C1DC07 /* EyebrowHeadlineBodyLink.swift in Sources */,
D29DF11D21E684A9003B2FB9 /* MVMCoreUISplitViewController.m in Sources */,
0198F79F225679880066C936 /* FormValidationProtocol.swift in Sources */,
D243859923A16B1800332775 /* Container.swift in Sources */,
D2C521A923EDE79E00CA2634 /* ViewController.swift in Sources */,
D260105B23D0BB7100764D80 /* StackModelProtocol.swift in Sources */,
@ -1947,13 +1994,16 @@
94C2D9A123872BCC0006CF46 /* LabelAttributeUnderlineModel.swift in Sources */,
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */,
D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */,
011D9628240EFA1E000E3791 /* MFViewController+Form.swift in Sources */,
0A21DB94235E24ED00C160A2 /* DigitEntryField.swift in Sources */,
52B201D224081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift in Sources */,
D26C5A6B23F4A40D007AEECE /* ListItemModel.swift in Sources */,
0A21DB8D235E06EF00C160A2 /* MFDigitTextField.m in Sources */,
94AF4A4323E9D19E00676048 /* MFCaretView.m in Sources */,
943784F6236B77BB006A1E82 /* GraphViewAnimationHandler.swift in Sources */,
011D95A1240453D0000E3791 /* RuleEqualsModel.swift in Sources */,
D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */,
011D95892404249B000E3791 /* FormProtocol.swift in Sources */,
948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */,
013F801923FB4A8E00AD8013 /* UIContentMode+Extension.swift in Sources */,
D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */,
@ -1975,13 +2025,13 @@
C7192E7D23C301750050C2A0 /* HeadLineBodyCaretLinkImage.swift in Sources */,
D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */,
D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */,
0105618E224BBE7700E1557D /* FormValidator+TextFields.swift in Sources */,
0A7EF86323D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift in Sources */,
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */,
D2B18B922361E65A00A9AEDC /* CoreUIObject.swift in Sources */,
D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */,
014AA72E23C5059B006F3E93 /* StackCenteredPageTemplateModel.swift in Sources */,
D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */,
011D959D2404536F000E3791 /* RuleAnyValueChangedModel.swift in Sources */,
D260105923D0A92900764D80 /* ContainerProtocol.swift in Sources */,
C695A69423C9909000BFB94E /* DoughnutChartModel.swift in Sources */,
D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */,
@ -1990,6 +2040,7 @@
D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */,
D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */,
94C661D923CCF4B400D9FE5B /* LeftRightLabelModel.swift in Sources */,
011D95AB2405C553000E3791 /* FormItemProtocol.swift in Sources */,
D21EE53C23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift in Sources */,
525019DD2406430800EED91C /* ListProgressBarDataModel.swift in Sources */,
C6FA7D5223C77A4A00A3614A /* UnOrderedList.swift in Sources */,
@ -1999,6 +2050,8 @@
D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */,
C695A69823C990C200BFB94E /* DoughnutChartView.swift in Sources */,
D29DF2CB21E7BFCC003B2FB9 /* MFSizeThreshold.m in Sources */,
011D959F240453A1000E3791 /* RuleAllValueChangedModel.swift in Sources */,
011D95AD2406BB57000E3791 /* FormHolderProtocol.swift in Sources */,
01509D932327ECFB00EF99AA /* ProgressBar.swift in Sources */,
D260106523D0CEA700764D80 /* StackModel.swift in Sources */,
D29770F521F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m in Sources */,

View File

@ -18,7 +18,8 @@ public enum ButtonSize: String, Codable {
case tiny
}
public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol {
public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormActionFieldProtocol {
public static var identifier: String = "button"
public var backgroundColor: Color?
public var title: String
@ -32,9 +33,15 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol {
public var disabledFillColor: Color?
public var disabledTextColor: Color?
public var disabledBorderColor: Color?
public var required: Bool?
public var requiredGroups: [String]?
public var groupName: String? = FormValidator.defaultGroupName
public func updateEnable(_ enabled: Bool) {
self.enabled = enabled
updateUI?()
}
public var updateUI: (() -> Void)?
init(with title: String, action: ActionModelProtocol) {
self.title = title
self.action = action
@ -66,8 +73,7 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol {
case disabledFillColor
case disabledTextColor
case disabledBorderColor
case required
case requiredGroups
case groupName
}
required public init(from decoder: Decoder) throws {
@ -76,8 +82,9 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol {
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
title = try typeContainer.decode(String.self, forKey: .title)
action = try typeContainer.decodeModel(codingKey: .action)
required = try typeContainer.decodeIfPresent(Bool.self, forKey: .required)
requiredGroups = try typeContainer.decodeIfPresent([String].self, forKey: .requiredGroups)
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
self.groupName = groupName
}
if let style = try typeContainer.decodeIfPresent(ButtonStyle.self, forKey: .style) {
self.style = style
}
@ -110,7 +117,6 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol {
try container.encodeIfPresent(disabledFillColor, forKey: .disabledFillColor)
try container.encodeIfPresent(disabledTextColor, forKey: .disabledTextColor)
try container.encodeIfPresent(disabledBorderColor, forKey: .disabledBorderColor)
try container.encodeIfPresent(required, forKey: .required)
try container.encodeIfPresent(requiredGroups, forKey: .requiredGroups)
try container.encodeIfPresent(groupName, forKey: .groupName)
}
}

View File

@ -8,7 +8,7 @@
import UIKit
open class PillButton: Button, MVMCoreUIViewConstrainingProtocol, FormValidationEnableDisableProtocol {
open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
// Used to size the button.
var size = MVMCoreUIUtility.getWidth()
@ -125,11 +125,12 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol, FormValidation
guard let model = model as? ButtonModel else { return }
setTitle(model.title, for: .normal)
if let required = model.required,
required {
FormValidator.setupValidation(molecule: self, delegate: delegateObject?.formValidationProtocol)
model.updateUI = { [weak self] in
self?.enableField(model.enabled)
}
FormValidator.setupValidation(molecule: model, delegate: delegateObject?.formHolderDelegate)
}
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
@ -163,17 +164,8 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol, FormValidation
open func horizontalAlignment() -> UIStackView.Alignment {
return .center
}
// MARK: - FormValidationEnableDisableProtocol
public func isValidationRequired() -> Bool {
return buttonModel?.required ?? false
}
public func requiredGroups() -> [String]? {
return buttonModel?.requiredGroups
}
public func enableField(_ enable: Bool) {
isEnabled = isValidationRequired() ? enable : true
isEnabled = enable
}
}

View File

@ -16,14 +16,6 @@ extension PrimaryButton: ModelMoleculeViewProtocol {
setTitle(model.title, for: .normal)
backgroundColor = model.backgroundColor?.uiColor
self.validationRequired = model.required ?? false
self.requiredGroupsList = model.requiredGroups
if self.validationRequired,
let selfForm = self as? FormValidationEnableDisableProtocol {
FormValidator.setupValidation(molecule: selfForm, delegate: delegateObject?.formValidationProtocol)
}
if let style = model.style {
switch style {
case .primary:

View File

@ -48,8 +48,6 @@ import UIKit
//--------------------------------------------------
public var isValid: Bool = false
public var fieldKey: String?
public var errorMessage: String?
public var standardMessage: String? {
didSet {
@ -259,10 +257,6 @@ import UIKit
} else if let isSelected = model.isSelected{
self.isSelected = isSelected
}
if let fieldKey = model.fieldKey {
self.fieldKey = fieldKey
}
}
}
@ -300,11 +294,6 @@ extension EntryField {
if let isSelected = dictionary["isSelected"] as? Bool {
self.isSelected = isSelected
}
// Key used to send text value to server
if let fieldKey = dictionary[KeyFieldKey] as? String {
self.fieldKey = fieldKey
}
}
@objc open class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
@ -312,22 +301,6 @@ extension EntryField {
}
}
// MARK: - Form Validation
extension EntryField: FormValidationProtocol {
@objc public func isValidField() -> Bool {
return isValid
}
@objc public func formFieldName() -> String? {
return fieldKey
}
@objc public func formFieldValue() -> Any? {
return text
}
}
// MARK: - Accessibility
extension EntryField {

View File

@ -9,7 +9,8 @@
import Foundation
@objcMembers public class EntryFieldModel: MoleculeModelProtocol {
@objcMembers public class EntryFieldModel: MoleculeModelProtocol, FormFieldProtocol, ValidProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -26,8 +27,19 @@ import Foundation
public var isLocked: Bool?
public var isSelected: Bool?
public var fieldKey: String?
public var isValid: Bool?
public var isRequired: Bool?
public var groupName: String? = FormValidator.defaultGroupName
public var text: String?
public var baseValue: AnyHashable?
public var isValid: Bool? {
didSet {
updateUI?()
}
}
public var updateUI: (() -> Void)?
public func setValidity(_ isValid: Bool) {
self.isValid = isValid
}
//--------------------------------------------------
// MARK: - Keys
@ -45,6 +57,12 @@ import Foundation
case fieldKey
case isValid
case isRequired = "required"
case text
case groupName
}
public func formFieldValue() -> AnyHashable? {
return text
}
//--------------------------------------------------
@ -62,6 +80,11 @@ import Foundation
isSelected = try typeContainer.decodeIfPresent(Bool.self, forKey: .isSelected)
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
isValid = try typeContainer.decodeIfPresent(Bool.self, forKey: .isValid)
text = try typeContainer.decodeIfPresent(String.self, forKey: .text)
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
self.groupName = groupName
}
}
public func encode(to encoder: Encoder) throws {
@ -76,5 +99,7 @@ import Foundation
try container.encode(isSelected, forKey: .isSelected)
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
try container.encodeIfPresent(isValid, forKey: .isValid)
try container.encodeIfPresent(text, forKey: .text)
try container.encodeIfPresent(groupName, forKey: .groupName)
}
}

View File

@ -1,79 +0,0 @@
//
// MFTextField+ModelExtension.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 11/19/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
enum TextType: String {
case dropDown = "dropDown"
case password = "password"
case number = "number"
case email = "email"
}
extension MFTextField: ModelMoleculeViewProtocol {
//
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
//TODO: Need to create setWithModel in ViewConstraining View
#warning("This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView.")
//TODO: This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView.
setUpDefaultWithModel(model, delegateObject, additionalData)
guard let textFieldModel = model as? TextFieldModel,
let delegateObject = delegateObject else {
return
}
if let delegate = delegateObject.formValidationProtocol {
let formValidator = FormValidator.getFormValidatorFor(delegate: delegate)
mfTextFieldDelegate = formValidator
uiTextFieldDelegate = delegateObject.uiTextFieldDelegate
if let textField = textField {
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: uiTextFieldDelegate)
}
}
formText = textFieldModel.label as NSString?
text = textFieldModel.value as NSString?
if let disabled = textFieldModel.disabled {
enable(disabled)
}
errMessage = textFieldModel.errorMsg
fieldKey = textFieldModel.fieldKey
groupName = textFieldModel.groupName
switch textFieldModel.type {
case TextType.dropDown.rawValue:
dropDownCarrotLabel?.isHidden = true
hasDropDown = true
break
case TextType.password.rawValue:
textField?.isSecureTextEntry = true
break
case TextType.number.rawValue:
textField?.keyboardType = .numberPad
break
case TextType.email.rawValue:
textField?.keyboardType = .emailAddress
break
default:
print("default")
}
if let regex = textFieldModel.regex {
validationBlock = {(enteredValue: String?) -> Bool in
if let enteredValue = enteredValue {
return MVMCoreUIUtility.validate(enteredValue, withRegularExpression: regex)
}
return true
}
} else {
setDefaultValidationBlock()
}
}
}

View File

@ -97,24 +97,24 @@ import MVMCore
return MVMCoreUIUtility.validateInternationalMDNString(MDN)
}
@objc public override func validateTextField() -> Bool {
@objc public func validateMDNTextField() -> Bool {
guard !shouldValidateMDN, let MDN = mdn, !MDN.isEmpty else {
isValid = true
return true
}
let isValid = hasValidMDN()
if isValid {
showError = false
} else {
errorMessage = errorMessage ?? MVMCoreUIUtility.hardcodedString(withKey: "textfield_phone_format_error_message")
showError = true
UIAccessibility.post(notification: .layoutChanged, argument: textField)
}
return isValid
}
@ -186,7 +186,7 @@ import MVMCore
proprietorTextDelegate?.textFieldDidEndEditing?(textField)
if validateTextField() && isNationalMDN {
if validateMDNTextField() && isNationalMDN {
textField.text = MVMCoreUIUtility.formatMdn(textField.text)
}
}

View File

@ -44,12 +44,12 @@ import UIKit
private var observingForChange: Bool = false
/// Validate on each entry in the textField. Default: false
public var validateEachCharacter: 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
//--------------------------------------------------
// MARK: - Computed Properties
//--------------------------------------------------
@ -197,9 +197,8 @@ import UIKit
@objc deinit {
setBothTextDelegates(to: nil)
}
@objc public func setBothTextDelegates(to delegate: (UITextFieldDelegate & ObservingTextFieldDelegate)?) {
observingTextFieldDelegate = delegate
uiTextFieldDelegate = delegate
}
@ -218,62 +217,55 @@ import UIKit
@discardableResult
@objc override open func resignFirstResponder() -> Bool {
if validateWhenDoneEditing {
validateTextField()
}
textField.resignFirstResponder()
isSelected = false
return true
}
/// Validates the text of the entry field.
@discardableResult
@objc public func validateTextField() -> Bool {
isValid = validationBlock?(text) ?? true
if isValid {
showError = false
observingTextFieldDelegate?.isValid?(textfield: self)
} else {
@objc public func validateTextField() {
text = textField.text
FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
}
@objc public func updateValidation(_ isValid: Bool) {
let previousValidity = self.isValid
self.isValid = isValid
if previousValidity && !isValid {
showError = true
observingTextFieldDelegate?.isInvalid?(textfield: self)
} else if (!previousValidity && isValid) {
showError = false
observingTextFieldDelegate?.isValid?(textfield: self)
}
return isValid
}
/// Executes on UITextField.textDidBeginEditingNotification
@objc func startEditing() {
isSelected = true
textField.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.black.cgColor
}
resignFirstResponder()
}
@objc func dismissFieldInput(_ sender: Any?) {
resignFirstResponder()
}
@ -281,9 +273,14 @@ import UIKit
super.set(with: model, delegateObject, additionalData)
guard let model = model as? TextEntryFieldModel else { return }
FormValidator.setupValidation(molecule: self, delegate: delegateObject?.formValidationProtocol)
model.updateUI = { [weak self] in
if self?.isSelected ?? false {
self?.updateValidation(model.isValid ?? true)
}
}
self.delegateObject = delegateObject
FormValidator.setupValidation(molecule: model, delegate: delegateObject?.formHolderDelegate)
textColor.enabled = model.enabledTextColor?.uiColor
textColor.disabled = model.disabledTextColor?.uiColor
text = model.text
@ -312,11 +309,8 @@ import UIKit
defaultValidationBlock()
}
if let formValidationProtocol = delegateObject?.formValidationProtocol {
observingTextFieldDelegate = FormValidator.getFormValidatorFor(delegate: formValidationProtocol)
}
uiTextFieldDelegate = delegateObject?.uiTextFieldDelegate
observingTextFieldDelegate = delegateObject?.observingTextFieldDelegate
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: uiTextFieldDelegate)
}
}
@ -330,9 +324,7 @@ extension TextEntryField {
guard let delegateObject = delegateObject,
let dictionary = json
else { return }
FormValidator.setupValidation(molecule: self, delegate: delegateObject.formValidationProtocol)
if let enabledTextColorHex = dictionary["enabledTextColor"] as? String {
textColor.enabled = UIColor.mfGet(forHex: enabledTextColorHex)
}
@ -374,11 +366,9 @@ extension TextEntryField {
defaultValidationBlock()
}
if let formValidationProtocol = delegateObject.formValidationProtocol {
observingTextFieldDelegate = FormValidator.getFormValidatorFor(delegate: formValidationProtocol)
}
uiTextFieldDelegate = delegateObject.uiTextFieldDelegate
observingTextFieldDelegate = delegateObject.observingTextFieldDelegate
MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: uiTextFieldDelegate)
}
}

View File

@ -16,7 +16,6 @@
return "textField"
}
public var text: String?
public var placeholder: String?
public var enabledTextColor: Color?
public var disabledTextColor: Color?

View File

@ -8,7 +8,7 @@
import UIKit
@objcMembers public class TextFieldModel: MoleculeModelProtocol, FormModelProtocol {
@objcMembers public class TextFieldModel: MoleculeModelProtocol {
public static var identifier: String = "textField"
public var backgroundColor: Color?

View File

@ -126,9 +126,10 @@ import MVMCore
didSet {
if !updateSelectionOnly {
layoutIfNeeded()
(model as? CheckboxModel)?.isChecked = isSelected
shapeLayer?.removeAllAnimations()
updateCheckboxUI(isSelected: isSelected, isAnimated: isAnimated)
FormValidator.enableByValidationWith(delegate: delegateObject?.formValidationProtocol)
FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
updateAccessibilityLabel()
}
}
@ -399,14 +400,9 @@ import MVMCore
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? CheckboxModel else { return }
self.delegateObject = delegateObject
FormValidator.setupValidation(molecule: self, delegate: delegateObject?.formValidationProtocol)
groupName = model.groupName
fieldValue = model.fieldValue
FormValidator.setupValidation(molecule: model, delegate: delegateObject?.formHolderDelegate)
if let fieldKey = model.fieldKey {
self.fieldKey = fieldKey
@ -440,23 +436,3 @@ import MVMCore
}
}
}
// MARK:- FormValidationProtocol
extension Checkbox: FormValidationFormFieldProtocol {
public func formFieldGroupName() -> String? {
return groupName
}
public func isValidField() -> Bool {
return (fieldKey != nil) ? isSelected : true
}
public func formFieldName() -> String? {
return fieldKey
}
public func formFieldValue() -> Any? {
return fieldValue ?? (isSelected ? fieldValue : nil)
}
}

View File

@ -8,18 +8,13 @@
import Foundation
@objcMembers public class CheckboxModel: MoleculeModelProtocol {
@objcMembers public class CheckboxModel: MoleculeModelProtocol, FormFieldProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "checkbox"
public var backgroundColor: Color?
public var groupName: String?
public var fieldKey: String?
public var fieldValue: JSONValue?
public var isChecked: Bool = false
public var isEnabled: Bool = true
public var isAnimated: Bool = true
@ -34,13 +29,18 @@ import Foundation
public var disabledCheckColor: Color = Color(uiColor: .mvmCoolGray3)
public var action: ActionModelProtocol?
public var fieldKey: String?
public var fieldValue: JSONValue?
public var groupName: String? = FormValidator.defaultGroupName
public var baseValue: AnyHashable?
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case moleculeName
case groupName
case fieldKey
case fieldValue
case isChecked = "checked"
@ -56,17 +56,21 @@ import Foundation
case disabledCheckColor
case disabledBorderColor
case action
case groupName
}
init(isChecked: Bool = false) {}
public func formFieldValue() -> AnyHashable? {
return isChecked
}
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName)
fieldValue = try typeContainer.decodeIfPresent(JSONValue.self, forKey: .fieldValue)
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
borderWidth = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .borderWidth) ?? 1
@ -82,6 +86,9 @@ import Foundation
isRound = try typeContainer.decodeIfPresent(Bool.self, forKey: .isRound) ?? false
isEnabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .isEnabled) ?? true
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
self.groupName = groupName
}
}
public func encode(to encoder: Encoder) throws {
@ -103,5 +110,6 @@ import Foundation
try container.encodeIfPresent(isRound, forKey: .isRound)
try container.encodeIfPresent(isEnabled, forKey: .isEnabled)
try container.encodeModelIfPresent(action, forKey: .action)
try container.encodeIfPresent(groupName, forKey: .groupName)
}
}

View File

@ -18,7 +18,7 @@ extension MFView {
}
extension ModelMoleculeViewProtocol where Self: MFView {
func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
setUpDefaultWithModel(model, delegateObject, additionalData)
}
}

View File

@ -13,10 +13,7 @@ extension MVMCoreUISwitch: ModelMoleculeViewProtocol {
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
guard let model = model as? ToggleModel else { return }
if let castSelf = self as? FormValidationProtocol {
FormValidator.setupValidation(molecule: castSelf, delegate: delegateObject?.formValidationProtocol)
}
FormValidator.setupValidation(molecule: model, delegate: delegateObject?.formHolderDelegate)
setState(model.state, animated: false)
guard let action = model.action else { return }

View File

@ -8,34 +8,33 @@
import UIKit
@objcMembers public class RadioButton: Control, FormValidationFormFieldProtocol {
@objcMembers public class RadioButton: Control {
var diameter: CGFloat = 30 {
didSet {
widthConstraint?.constant = diameter
}
}
var enabledColor = UIColor.black
var disabledColor = UIColor.mfSilver()
var disabledColor = UIColor.mfSilver()
var delegateObject: MVMCoreUIDelegateObject?
var fieldKey: String?
var formValue: Bool?
var isRequired: Bool = false
var widthConstraint: NSLayoutConstraint?
var heightConstraint: NSLayoutConstraint?
var radioModel: RadioButtonModel? {
return model as? RadioButtonModel
}
lazy var radioGroupName: String? = {
[unowned self] in
return json?.optionalStringForKey("radioGroupName") ?? json?.optionalStringForKey("fieldKey")
[unowned self] in return radioModel?.fieldKey
}()
lazy var radioButtonModel: RadioButtonSelectionHelper? = {
lazy var radioButtonSelectionHelper: RadioButtonSelectionHelper? = {
[unowned self] in
if let radioGroupName = radioGroupName,
let radioButtonModel = delegateObject?.formValidationProtocol?.formValidatorModel?()?.radioButtonsModelByGroup[radioGroupName] {
let radioButtonModel = delegateObject?.formHolderDelegate?.formValidator?.radioButtonsModelByGroup[radioGroupName] {
return radioButtonModel
} else {
return nil
@ -58,12 +57,12 @@ import UIKit
/// The action performed when tapped.
func tapAction() {
if let radioButtonModel = radioButtonModel {
if let radioButtonModel = radioButtonSelectionHelper {
radioButtonModel.selected(self)
} else {
isSelected = !isSelected
}
FormValidator.enableByValidationWith(delegate: delegateObject?.formValidationProtocol)
FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
setNeedsDisplay()
}
@ -72,15 +71,15 @@ import UIKit
}
public func formFieldName() -> String? {
return json?.optionalStringForKey("fieldKey")
return radioModel?.fieldKey
}
public func formFieldGroupName() -> String? {
return json?.optionalStringForKey("groupName")
return radioModel?.fieldKey
}
public func formFieldValue() -> Any? {
return isSelected
public func formFieldValue() -> AnyHashable? {
return radioModel?.fieldValue
}
// MARK: - MVMViewProtocol
@ -104,40 +103,14 @@ import UIKit
guard let model = model as? RadioButtonModel else {
return
}
setWithJSON(model.toJSON(), delegateObject: delegateObject, additionalData: additionalData)
}
}
// MARK: - MVMCoreUIViewConstrainingProtocol
extension RadioButton: MVMCoreUIViewConstrainingProtocol {
public func needsToBeConstrained() -> Bool {
return true
}
}
// MARK: - MVMCoreUIMoleculeViewProtocol
extension RadioButton {
@objc open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
// Configure class properties with JSON values
guard let jsonDictionary = json else {
return
}
fieldKey = jsonDictionary.optionalStringForKey("fieldKey")
isRequired = jsonDictionary.boolForKey("required")
self.delegateObject = delegateObject
let radioButtonModel = RadioButtonSelectionHelper.setupForRadioButtonGroup(radioButton: self,
formValidator: delegateObject?.formValidationProtocol?.formValidatorModel?())
FormValidator.setupValidation(molecule: radioButtonModel, delegate: delegateObject?.formValidationProtocol)
let radioButtonModel = RadioButtonSelectionHelper.setupForRadioButtonGroup(model,
formValidator: delegateObject?.formHolderDelegate?.formValidator)
FormValidator.setupValidation(molecule: radioButtonModel, delegate: delegateObject?.formHolderDelegate)
}
public override func reset() {
super.reset()
backgroundColor = .white
super.reset()
backgroundColor = .white
}
}

View File

@ -7,14 +7,19 @@
//
import Foundation
import MVMCore
public class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
public class RadioButtonModel: MoleculeModelProtocol {
public static var identifier: String = "radioButton"
public var backgroundColor: Color?
public var state: Bool = false
public var enabled: Bool = true
public var baseValue: AnyHashable?
public var groupName: String?
public var fieldKey: String?
public var fieldValue: String?
private enum CodingKeys: String, CodingKey {
case moleculeName
@ -22,12 +27,18 @@ public class RadioButtonModel: MoleculeModelProtocol {
case state
case enabled
case fieldKey
case fieldValue
case groupName
}
public init(_ state: Bool) {
self.state = state
}
public func formFieldValue() -> AnyHashable? {
return state
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
if let state = try typeContainer.decodeIfPresent(Bool.self, forKey: .state) {
@ -38,6 +49,8 @@ public class RadioButtonModel: MoleculeModelProtocol {
}
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName)
fieldValue = try typeContainer.decodeIfPresent(String.self, forKey: .fieldValue)
}
public func encode(to encoder: Encoder) throws {
@ -47,5 +60,7 @@ public class RadioButtonModel: MoleculeModelProtocol {
try container.encode(state, forKey: .state)
try container.encode(enabled, forKey: .enabled)
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
try container.encodeIfPresent(groupName, forKey: .groupName)
try container.encodeIfPresent(fieldValue, forKey: .fieldValue)
}
}

View File

@ -19,7 +19,7 @@ public typealias ActionBlockConfirmation = () -> (Bool)
Container: The background of the toggle control.
Knob: The circular indicator that slides on the container.
*/
@objcMembers open class Toggle: Control, MVMCoreUIViewConstrainingProtocol, FormValidationFormFieldProtocol {
@objcMembers open class Toggle: Control, MVMCoreUIViewConstrainingProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -100,8 +100,9 @@ public typealias ActionBlockConfirmation = () -> (Bool)
knobView.backgroundColor = isOn ? knobTintColor?.on : knobTintColor?.off
self.constrainKnob()
}
FormValidator.enableByValidationWith(delegate: delegateObject?.formValidationProtocol)
(model as? ToggleModel)?.state = isOn
FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
accessibilityValue = isOn ? MVMCoreUIUtility.hardcodedString(withKey: "AccOn") : MVMCoreUIUtility.hardcodedString(withKey: "AccOff")
setNeedsLayout()
layoutIfNeeded()
@ -339,82 +340,61 @@ public typealias ActionBlockConfirmation = () -> (Bool)
return
}
self.model = model
self.delegateObject = delegateObject
let toggleModelJSON = toggleModel.toJSON()
FormValidator.setupValidation(molecule: toggleModel, delegate: delegateObject?.formHolderDelegate)
setWithJSON(toggleModelJSON, delegateObject: delegateObject, additionalData: additionalData)
}
//TODO: change to setWith Model
public override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
guard let dictionary = json else { return }
if let color = dictionary["onTintColor"] as? String {
containerTintColor?.on = UIColor.mfGet(forHex: color)
}
if let color = dictionary["offTintColor"] as? String {
containerTintColor?.off = UIColor.mfGet(forHex: color)
}
if let color = dictionary["onKnobTintColor"] as? String {
knobTintColor?.on = UIColor.mfGet(forHex: color)
}
if let color = dictionary["offKnobTintColor"] as? String {
knobTintColor?.off = UIColor.mfGet(forHex: color)
}
if let state = dictionary["state"] as? Bool {
changeStateNoAnimation(state)
}
if let actionMap = dictionary.optionalDictionaryForKey("action") {
didToggleAction = { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) }
}
if let isAnimated = dictionary["isAnimated"] as? Bool {
self.isAnimated = isAnimated
}
if let isEnabled = dictionary["isEnabled"] as? Bool{
self.isEnabled = isEnabled
}
}
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
return Self.getContainerHeight()
}
}
// MARK: - Accessibility
extension Toggle {
public func formFieldGroupName() -> String? {
return json?["groupName"] as? String
}
}
// MARK: - FormValidationProtocol
extension Toggle {
public func isValidField() -> Bool {
return isOn && json?["required"] as? Bool ?? false
}
public func formFieldName() -> String? {
return json?[KeyFieldKey] as? String ?? ""
}
public func formFieldValue() -> Any? {
return NSNumber(value: isOn)
}
}
// MARK: - MVMCoreUIMoleculeViewProtocol
extension Toggle {
public override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
self.delegateObject = delegateObject
FormValidator.setupValidation(molecule: self, delegate: delegateObject?.formValidationProtocol)
guard let dictionary = json else { return }
if let color = dictionary["onTintColor"] as? String {
containerTintColor?.on = UIColor.mfGet(forHex: color)
}
if let color = dictionary["offTintColor"] as? String {
containerTintColor?.off = UIColor.mfGet(forHex: color)
}
if let color = dictionary["onKnobTintColor"] as? String {
knobTintColor?.on = UIColor.mfGet(forHex: color)
}
if let color = dictionary["offKnobTintColor"] as? String {
knobTintColor?.off = UIColor.mfGet(forHex: color)
}
if let state = dictionary["state"] as? Bool {
changeStateNoAnimation(state)
}
if let actionMap = dictionary.optionalDictionaryForKey("action") {
didToggleAction = { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) }
}
if let isAnimated = dictionary["isAnimated"] as? Bool {
self.isAnimated = isAnimated
}
if let isEnabled = dictionary["isEnabled"] as? Bool{
self.isEnabled = isEnabled
}
}
public class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return Self.getContainerHeight()

View File

@ -8,23 +8,29 @@
import UIKit
public class ToggleModel: MoleculeModelProtocol {
public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol {
public static var identifier: String = "toggle"
public var backgroundColor: Color?
public var state: Bool = true
public var action: ActionModelProtocol?
public var alternateAction: ActionModelProtocol?
public var required: Bool?
public var fieldKey: String?
public var groupName: String? = FormValidator.defaultGroupName
public var baseValue: AnyHashable?
private enum CodingKeys: String, CodingKey {
case moleculeName
case state
case action
case backgroundColor
case required
case fieldKey
case alternateAction
case groupName
}
public func formFieldValue() -> AnyHashable? {
return state
}
public init(_ state: Bool) {
@ -39,8 +45,10 @@ public class ToggleModel: MoleculeModelProtocol {
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
alternateAction = try typeContainer.decodeModelIfPresent(codingKey: .alternateAction)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
required = try typeContainer.decodeIfPresent(Bool.self, forKey: .required)
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
self.groupName = groupName
}
}
public func encode(to encoder: Encoder) throws {
@ -50,7 +58,7 @@ public class ToggleModel: MoleculeModelProtocol {
try container.encodeModelIfPresent(alternateAction, forKey: .alternateAction)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(state, forKey: .state)
try container.encodeIfPresent(required, forKey: .required)
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
try container.encodeIfPresent(groupName, forKey: .groupName)
}
}

View File

@ -0,0 +1,22 @@
//
// MFViewController+Form.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 3/3/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
extension MFViewController: ObservingTextFieldDelegate {
}
public extension MFViewController {
@objc func startValidation() {
(self as? FormHolderProtocol)?.formValidator?.validate()
}
@objc func addFormParams(requestParameters: MVMCoreRequestParameters) {
(self as? FormHolderProtocol)?.formValidator?.addFormParams(requestParameters: requestParameters)
}
}

View File

@ -38,7 +38,7 @@
#import <MVMCoreUI/MVMCoreUI-Swift.h>
@import MVMAnimationFramework;
@interface MFViewController() <FormValidationProtocol>
@interface MFViewController()
// A flag for if this view controller is observing for cache updates or not.
@property (nonatomic) BOOL observingForResponseJSONUpdates;
@ -52,19 +52,10 @@
// title view for navigation bar, used for custom navigation titles
@property (weak, nonatomic) UILabel *titleLabel;
@property (strong, nonatomic) FormValidator *formValidator;
@end
@implementation MFViewController
- (FormValidator *)formValidatorModel {
if (self.formValidator == nil) {
self.formValidator = [FormValidator new];
}
return self.formValidator;
}
- (void)dismiss {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
if (self.presentingViewController) {
@ -477,7 +468,7 @@
// Since we have new data, build stuff for the screen and update the ui once the screen is done laying out.
[self newDataBuildAndUpdate];
self.needToupdateUIOnScreenSizeChanges = YES;
if (UIAccessibilityIsVoiceOverRunning()) {
@ -487,12 +478,13 @@
if (!self.disableAnimations) {
[self setupIntroAnimations];
}
}
- (void)newDataBuildAndUpdate {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
[self newDataBuildScreen];
[self.formValidator enableByValidation];
[self startValidation];
self.needToUpdateUI = YES;
[self.view setNeedsLayout];
}];
@ -690,9 +682,8 @@
[[MVMCoreUISession sharedGlobal].splitViewController.rightPanel willOpenWithActionInformation:actionInformation];
}
[self.formValidator addFormParamsWithRequestParameters:requestParameters];
[self addFormParamsWithRequestParameters:requestParameters];
requestParameters.parentPageType = [self.loadObject.pageJSON stringForKey:@"parentPageType"];
[[MVMCoreLoadHandler sharedGlobal] loadRequest:requestParameters dataForPage:additionalData delegateObject:[self delegateObject]];
}

View File

@ -0,0 +1,14 @@
//
// FormActionFieldProtocol.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 1/31/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public protocol FormActionFieldProtocol: EnableableModelProtocol, FormItemProtocol {
func updateEnable(_ enabled: Bool)
var updateUI: (() -> Void)? { get set }
}

View File

@ -0,0 +1,22 @@
//
// FormFieldProtocol.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 1/31/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public protocol FormFieldProtocol: FormItemProtocol {
var fieldKey: String? { get set }
var baseValue: AnyHashable? { get set }
func formFieldValue() -> AnyHashable?
}
extension FormFieldProtocol {
var baseValue: AnyHashable? {
return nil
}
}

View File

@ -0,0 +1,17 @@
//
// FormHolderProtocol.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 2/26/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
//Protocol for Validation
public protocol FormHolderProtocol: NSObjectProtocol {
var formValidator: FormValidator? { get set }
/// Should call formValidator's validate method
func validate()
}

View File

@ -0,0 +1,19 @@
//
// FormItemProtocol.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 2/25/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public protocol FormItemProtocol {
static var defaultGroupName: String? { get }
var groupName: String? { get set }
}
extension FormItemProtocol{
public static var defaultGroupName: String? {
return "default"
}
}

View File

@ -0,0 +1,15 @@
//
// Validatable.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 2/5/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
//Protocol for Validation
public protocol FormProtocol: class {
var formRules: [FormGroupRule]? { get set }
var formValidator: FormValidator? { get set }
}

View File

@ -1,41 +0,0 @@
//
// FormValidationProtocol.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 3/26/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import Foundation
@objc public protocol FormValidationProtocol: NSObjectProtocol {
// Getter method to get the FormValidator from the delegate (Mostly from the parent View Controller)
@objc optional func formValidatorModel() -> FormValidator?
}
@objc public protocol FormValidationFormFieldProtocol: FormValidationProtocol {
// Used to check the validity of the field. For example, to enable/disable the primary button.
@objc func isValidField() -> Bool
// The Field name key value pair for sending to server
@objc func formFieldName() -> String?
// Returns the group name for validation. The class should always return a value.
@objc func formFieldGroupName() -> String?
// The Field value key value pair for sending to server
@objc func formFieldValue() -> Any?
}
@objc public protocol FormValidationEnableDisableProtocol: FormValidationProtocol {
// Returns true if the button needs to be enabled/disabled based on the validation
@objc func isValidationRequired() -> Bool
// Based on the isValidField(), the fields which needs to be enabled can call this method
@objc optional func enableField(_ enable: Bool)
// Returns the list of field keys required to enable/disable
@objc optional func requiredGroups() -> [String]?
}

View File

@ -1,28 +0,0 @@
//
// MVMCoreUIFormValidator+FormParams.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 3/21/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import Foundation
@objc public extension FormValidator {
@objc func addFormParams(requestParameters: MVMCoreRequestParameters) {
requestParameters.add(self.getFormParams())
}
@objc func getFormParams() -> [String: Any] {
var extraParam: [String: Any] = [:]
MVMCoreDispatchUtility.performSyncBlock(onMainThread: {
for molecule in self.fieldMolecules {
if let formFieldName = molecule.formFieldName(),
let formFieldValue = molecule.formFieldValue() {
extraParam[formFieldName] = formFieldValue
}
}
})
return extraParam
}
}

View File

@ -1,70 +0,0 @@
//
// MVMCoreUIFormValidator+TextFields.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 3/21/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import Foundation
@objc extension FormValidator: MFTextFieldDelegate {
public func dismissFieldInput(_ sender: Any?) {
if let delegate = delegate as? MFTextFieldDelegate {
delegate.dismissFieldInput?(sender)
}
}
public func entryIsValid(_ textfield: MFTextField?) {
MVMCoreDispatchUtility.performBlock(onMainThread: {
self.enableByValidation()
if let delegate = self.delegate as? MFTextFieldDelegate {
delegate.entryIsValid?(textfield)
}
})
}
public func entryIsInvalid(_ textfield: MFTextField?) {
MVMCoreDispatchUtility.performBlock(onMainThread: {
self.enableByValidation()
if let delegate = self.delegate as? MFTextFieldDelegate {
delegate.entryIsInvalid?(textfield)
}
})
}
}
// Temporary: Looking to either combine or separate entirely with MFTextFieldDelegate.
extension FormValidator: ObservingTextFieldDelegate {
public func dismissField(_ sender: Any?) {
if let delegate = delegate as? MFTextFieldDelegate {
delegate.dismissFieldInput?(sender)
}
}
@nonobjc public func isValid(_ textfield: MFTextField?) {
MVMCoreDispatchUtility.performBlock(onMainThread: {
self.enableByValidation()
if let delegate = self.delegate as? MFTextFieldDelegate {
delegate.entryIsValid?(textfield)
}
})
}
public func isInvalid(_ textfield: MFTextField?) {
MVMCoreDispatchUtility.performBlock(onMainThread: {
self.enableByValidation()
if let delegate = self.delegate as? MFTextFieldDelegate {
delegate.entryIsInvalid?(textfield)
}
})
}
}

View File

@ -11,75 +11,107 @@ import MVMCore
@objcMembers public class FormValidator: NSObject {
static var defaultGroupName: String = "default"
var extraValidationBlock: (() -> Bool)?
var dummyGroupName = "dummyGroupName"
weak var delegate: FormValidationProtocol?
var fieldMolecules: [FormValidationFormFieldProtocol] = []
var enableDisableMolecules: [FormValidationEnableDisableProtocol] = []
var formRules: [FormGroupRule]?
var delegate: FormHolderProtocol?
var fieldMolecules: [String: FormFieldProtocol] = [:]
var formActionMolecules: [FormActionFieldProtocol] = []
var radioButtonsModelByGroup: [String: RadioButtonSelectionHelper] = [:]
public func insertMolecule(_ molecule: FormValidationProtocol) {
if let molecule = molecule as? FormValidationFormFieldProtocol {
fieldMolecules.append(molecule)
}
if let moleculeT = molecule as? FormValidationEnableDisableProtocol,
moleculeT.isValidationRequired() {
enableDisableMolecules.append(moleculeT)
}
public init(_ formRules: [FormGroupRule]?) {
self.formRules = formRules
}
public static func enableByValidationWith(delegate: FormValidationProtocol?) {
if let delegate = delegate {
let formValidator = FormValidator.getFormValidatorFor(delegate: delegate)
formValidator?.enableByValidation()
public func insertMolecule(_ molecule: FormItemProtocol) {
if var molecule = molecule as? FormFieldProtocol,
let fieldKey = molecule.fieldKey {
if molecule.baseValue == nil {
molecule.baseValue = molecule.formFieldValue()
}
fieldMolecules[fieldKey] = molecule
}
if let molecule = molecule as? FormActionFieldProtocol {
formActionMolecules.append(molecule)
}
}
public static func getFormValidatorFor(delegate: FormValidationProtocol) -> FormValidator? {
return delegate.formValidatorModel?()
}
public static func setupValidation(molecule: FormValidationProtocol, delegate: FormValidationProtocol?) {
if let validator = delegate?.formValidatorModel?() {
public static func setupValidation(molecule: FormItemProtocol, delegate: FormHolderProtocol?) {
if let validator = delegate?.formValidator {
validator.delegate = delegate
validator.insertMolecule(molecule)
}
}
public func enableByValidation() {
for molecule in enableDisableMolecules {
var requiredGroups = molecule.requiredGroups?() ?? [dummyGroupName]
if requiredGroups.count == 0 {
requiredGroups = [dummyGroupName]
}
enableWithGroups(requiredGroups, molecule)
}
public static func getFormValidatorFor(delegate: FormHolderProtocol?) -> FormValidator? {
return delegate?.formValidator
}
public func enableWithGroups(_ requiredGroupList: [String], _ enableDisableMolecule: FormValidationEnableDisableProtocol) {
let requiredGroupSet = Set(requiredGroupList)
var valid = true
for molecule in fieldMolecules {
let groupName = molecule.formFieldGroupName() ?? dummyGroupName
if requiredGroupSet.contains(groupName) {
valid = valid && molecule.isValidField()
if valid == false {
break
}
public static func validate(delegate: FormHolderProtocol?) {
delegate?.formValidator?.validate()
}
public func validate() {
guard let formRules = formRules else {
return
}
formActionMolecules.forEach { (actionModel) in
if let groupName = actionModel.groupName,
let formRule = formRules.first(where: { $0.groupName == groupName }) {
validate(groupName, actionModel, formRule.rules)
}
}
enableDisableMolecule.enableField?(valid)
}
public func enableIgnoreGroupName(_ enableDisableMolecules: FormValidationEnableDisableProtocol) {
public func validate(_ groupName: String, _ actionModel: FormActionFieldProtocol, _ rules: [RulesProtocol]) {
var valid = true
for molecule in fieldMolecules {
valid = valid && molecule.isValidField()
if (!valid) {
for rule in rules {
valid = valid && rule.isValid(fieldMolecules)
if !valid {
break
}
}
let enableField = valid && (extraValidationBlock?() ?? true)
enableDisableMolecules.enableField?(enableField)
actionModel.updateEnable(valid)
}
public func formField(for fieldKey: String) -> FormFieldProtocol? {
return fieldMolecules[fieldKey]
}
}
// mark Form params
@objc public extension FormValidator {
@objc func addFormParams(requestParameters: MVMCoreRequestParameters) {
let formButton = getFormButton(forPageType: requestParameters.pageType)
let groupName = formButton?.groupName ?? FormValidator.defaultGroupName
let formParams = self.getFormParams(forGroup: groupName)
requestParameters.add(formParams)
}
@objc func getFormParams( forGroup groupName: String) -> [String: Any] {
var extraParam: [String: Any] = [:]
MVMCoreDispatchUtility.performSyncBlock(onMainThread: {
for (fieldKey, molecule) in self.fieldMolecules {
if let formFieldValue = molecule.formFieldValue(),
groupName == molecule.groupName {
extraParam[fieldKey] = formFieldValue
}
}
})
return extraParam
}
}
// Temporary
public extension FormValidator {
func getFormButton(forPageType pageType: String?) -> ButtonModel? {
for actionItem in formActionMolecules {
if let buttonModel = actionItem as? ButtonModel,
pageType == (buttonModel.action as? ActionOpenPageModel)?.pageType {
return buttonModel
}
}
return nil
}
}

View File

@ -0,0 +1,38 @@
//
// FormRule.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 2/24/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
open class FormGroupRule: Codable {
var groupName: String
var rules: [RulesProtocol]
init(_ groupName: String, _ rules: [RulesProtocol]) {
self.groupName = groupName
self.rules = rules
}
private enum CodingKeys: String, CodingKey {
case groupName
case rules
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
self.groupName = try typeContainer.decode(String.self, forKey: .groupName)
self.rules = try typeContainer.decodeModels(codingKey: .rules)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(groupName, forKey: .groupName)
try container.encodeModels(rules, forKey: .rules)
}
}

View File

@ -0,0 +1,20 @@
//
// RuleValueChangeModel.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 2/24/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public class RuleAllValueChangedModel: RulesProtocol {
public static var identifier: String = "allValueChanged"
public var type: String = RuleAllValueChangedModel.identifier
public var fields: [String]
public func isValid(_ formField: FormFieldProtocol) -> Bool {
return formField.baseValue != formField.formFieldValue()
}
}

View File

@ -0,0 +1,49 @@
//
// RuleAnyRequiredModel.swift
// MVMCoreUI
//
// Created by Kevin Christiano on 3/13/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import UIKit
public class RuleAnyRequiredModel: RulesProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "anyRequired"
public var type: String = RuleRequiredModel.identifier
public var fields: [String]
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
public func isValid(_ formField: FormFieldProtocol) -> Bool {
guard let value = formField.formFieldValue() else { return false }
if let valueString = value as? String {
return valueString.count > 0
} else if let valueBool = value as? Bool {
return valueBool
}
return false
}
public func isValid(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool {
for formKey in fields {
guard let formField = fieldMolecules[formKey] else { continue }
if isValid(formField) {
return true
}
}
return false
}
}

View File

@ -0,0 +1,32 @@
//
// RuleAnyModel.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 2/24/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public class RuleAnyValueChangedModel: RulesProtocol {
public static var identifier: String = "anyValueChanged"
public var type: String = RuleAnyValueChangedModel.identifier
public var fields: [String]
public func isValid(_ formField: FormFieldProtocol) -> Bool {
return formField.baseValue != formField.formFieldValue()
}
public func isValid(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool {
for formKey in fields {
guard let formField = fieldMolecules[formKey] else {
continue
}
if isValid(formField) {
return true
}
}
return false
}
}

View File

@ -0,0 +1,40 @@
//
// RuleEqualsModel.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 2/24/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public class RuleEqualsModel: RulesProtocol {
public static var identifier: String = "equals"
public var type: String = RuleEqualsModel.identifier
public var fields: [String]
public func isValid(_ formField: FormFieldProtocol) -> Bool {
return false
}
public func isValid(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool {
var valid = true
var compareValue: AnyHashable?
for formKey in fields {
guard let formField = fieldMolecules[formKey] else {
continue
}
if compareValue == nil {
compareValue = formField.formFieldValue()
continue
}
if compareValue != formField.formFieldValue(){
valid = false
break
}
}
return valid
}
}

View File

@ -0,0 +1,23 @@
//
// RuleRegexModel.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 2/24/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public class RuleRegexModel: RulesProtocol {
public static var identifier: String = "regex"
public var type: String = RuleRegexModel.identifier
public var fields: [String]
public var regex: String
public func isValid(_ formField: FormFieldProtocol) -> Bool {
if let stringToValidate = formField.formFieldValue() as? String {
return MVMCoreUIUtility.validate(stringToValidate, withRegularExpression: regex)
}
return false
}
}

View File

@ -0,0 +1,30 @@
//
// FormFieldRuleRequiredModel.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 2/24/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public class RuleRequiredModel: RulesProtocol {
public static var identifier: String = "required"
public var type: String = RuleRequiredModel.identifier
public var fields: [String]
public func isValid(_ formField: FormFieldProtocol) -> Bool {
guard let value = formField.formFieldValue() else {
return false
}
var valid = true
if let valueString = value as? String {
valid = valueString.count > 0
} else if let valueBool = value as? Bool {
valid = valueBool
}
return valid
}
}

View File

@ -0,0 +1,56 @@
//
// FormBaseRulesProtocol.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 1/31/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public enum RulesCodingKey: String, CodingKey {
case ruleType
}
public protocol RulesProtocol: ModelProtocol {
var type: String { get set }
var fields: [String] { get set }
func isValid(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool
func isValid(_ formField: FormFieldProtocol) -> Bool
func setValid(_ formField: FormFieldProtocol, _ isValid: Bool)
}
public extension RulesProtocol {
var ruleType: String? {
get { return Self.identifier }
}
static var categoryCodingKey: String {
return "type"
}
static var categoryName: String {
return "\(RulesProtocol.self)"
}
func isValid(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool {
var valid = true
for formKey in fields {
guard let formField = fieldMolecules[formKey] else { continue }
let fieldValidity = isValid(formField)
setValid(formField, fieldValidity)
valid = valid && fieldValidity
}
return valid
}
func setValid(_ formField: FormFieldProtocol, _ isValid: Bool) {
guard let formFieldValid = formField as? ValidProtocol else { return }
formFieldValid.setValidity(isValid)
}
}

View File

@ -0,0 +1,15 @@
//
// ValidProtocol.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 3/2/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public protocol ValidProtocol {
var isValid: Bool? { get set }
func setValidity(_ isValid: Bool)
var updateUI: (() -> Void)? { get set }
}

View File

@ -18,7 +18,7 @@
@import MVMCore.NSDictionary_MFConvenience;
@import MVMCore.MVMCoreJSONConstants;
@interface MFTextField() <FormValidationFormFieldProtocol>
@interface MFTextField()
@property (strong, nonatomic) UIColor *customPlaceHolderColor;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *separatorHeightConstraint;
@ -560,11 +560,7 @@
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
[super setWithJSON:json delegateObject:delegateObject additionalData:additionalData];
if ([delegateObject isKindOfClass:[MVMCoreUIDelegateObject class]]) {
[FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol];
FormValidator *formValidator = [FormValidator getFormValidatorForDelegate:delegateObject.formValidationProtocol];
[self setWithMap:json];
self.mfTextFieldDelegate = formValidator;
[self setWithMap:json];
self.uiTextFieldDelegate = delegateObject.uiTextFieldDelegate;
[MVMCoreUICommonViewsUtility addDismissToolbar:self.textField delegate:self.uiTextFieldDelegate];
}
@ -574,24 +570,4 @@
+ (CGFloat)estimatedHeightForRow:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject {
return 76;
}
#pragma mark - FormValidationProtocol
- (BOOL)isValidField {
return self.isValid;
}
- (nullable NSString *)formFieldName {
return self.fieldKey;
}
- (nullable id)formFieldValue {
return self.text;
}
- (NSString * _Nullable)formFieldGroupName {
return self.groupName;
}
@end

View File

@ -21,7 +21,7 @@
static const CGFloat FaultTolerance = 20.f;
static const CGFloat CheckBoxHeightWidth = 18.0;
@interface MVMCoreUICheckBox () <FormValidationFormFieldProtocol, MVMCoreUIMoleculeViewProtocol>
@interface MVMCoreUICheckBox () <MVMCoreUIMoleculeViewProtocol>
@property (nonatomic, readwrite) BOOL isSelected;
@property (weak, nonatomic) UIView *checkedSquare;
@ -59,9 +59,7 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
}
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
[FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol];
self.delegateObject = delegateObject;
self.fieldKey = [json stringForKey:KeyFieldKey];
self.isRequired = [json boolForKey:KeyRequired];
@ -109,23 +107,6 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
return checkBox;
}
#pragma mark - FormValidationProtocol
- (BOOL)isValidField {
if (self.isRequired) {
return self.isSelected;
}
return true;
}
- (nullable NSString *)formFieldName {
return self.fieldKey;
}
- (nullable id)formFieldValue {
return @(self.isSelected);
}
#pragma mark - inits
- (instancetype)init {
@ -350,7 +331,7 @@ static const CGFloat CheckBoxHeightWidth = 18.0;
[self.checkMark updateCheckSelected:NO animated:animated];
}
[FormValidator enableByValidationWithDelegate:self.delegateObject.formValidationProtocol];
// [FormValidator enableByValidationWithDelegate:self.delegateObject.formValidationProtocol];
}
- (void)setColor:(nullable UIColor *)color forState:(UIControlState)state {

View File

@ -22,7 +22,7 @@ const CGFloat SwitchKnobWidth = 20;
const CGFloat SwitchKnobHeight = 20;
const CGFloat SwitchShakeIntensity = 2;
@interface MVMCoreUISwitch () <FormValidationFormFieldProtocol, MVMCoreUIViewConstrainingProtocol>
@interface MVMCoreUISwitch () <MVMCoreUIViewConstrainingProtocol>
@property (weak, nonatomic) UIView *baseView;
@property (weak, nonatomic) UIView *knobView;
@ -147,8 +147,6 @@ const CGFloat SwitchShakeIntensity = 2;
self.json = json;
self.delegate = delegateObject;
[FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol];
NSString *color = [json string:@"onTintColor"];
if (color) {
self.onTintColor = [UIColor mfGetColorForHex:color];
@ -339,12 +337,11 @@ const CGFloat SwitchShakeIntensity = 2;
[self setState:state withoutBlockAnimated:animated];
if (self.valueChangedBlock) {
self.valueChangedBlock();
}
if (self.delegate && [self.delegate respondsToSelector:@selector(formValidationProtocol)] && [[self.delegate performSelector:@selector(formValidationProtocol)] respondsToSelector:@selector(formValidatorModel)]) {
FormValidator *formValidator = [[self.delegate performSelector:@selector(formValidationProtocol)] performSelector:@selector(formValidatorModel)];
[formValidator enableByValidation];
}
}
// if (self.delegate && [self.delegate respondsToSelector:@selector(formValidationProtocol)] && [[self.delegate performSelector:@selector(formValidationProtocol)] respondsToSelector:@selector(formValidatorModel)]) {
// FormValidator *formValidator = [[self.delegate performSelector:@selector(formValidationProtocol)] performSelector:@selector(formValidatorModel)];
// [formValidator enableByValidation];
// }
}
- (void)setState:(BOOL)state withoutBlockAnimated:(BOOL)animated {
@ -427,22 +424,4 @@ const CGFloat SwitchShakeIntensity = 2;
return [MVMCoreUIUtility hardcodedStringWithKey:@"AccToggleHint"];
}
#pragma mark FormValidationProtocol
- (NSString * _Nullable)formFieldGroupName {
return [self.json string:@"groupName"];
}
- (BOOL)isValidField {
return self.isOn && [self.json boolForKey:@"required"];
}
- (NSString *)formFieldName {
return [self.json string:KeyFieldKey];
}
- (id)formFieldValue {
return @(self.isOn);
}
@end

View File

@ -18,7 +18,7 @@
@import MVMCore.MVMCoreGetterUtility;
@import MVMCore.NSDictionary_MFConvenience;
@interface PrimaryButton() <FormValidationEnableDisableProtocol>
@interface PrimaryButton()
@property (nonatomic) BOOL smallButton;
@property (assign, nonatomic) BOOL tinyButton;
@ -671,7 +671,6 @@
self.validationRequired = [json boolForKey:@"required"];
self.requiredGroupsList = [json array:@"requiredGroups"];
[FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol];
self.primaryButtonType = PrimaryButtonTypeCustom;
NSString *style = [json string:@"style"];
@ -781,22 +780,4 @@
}
}
#pragma mark - FormValidationEnableDisableProtocol
- (BOOL)isValidationRequired {
return self.validationRequired;
}
- (NSArray<NSString *> *)requiredGroups {
return self.requiredGroupsList;
}
- (void)enableField:(BOOL)enable {
if (!self.validationRequired) {
self.enabled = YES;
} else {
self.enabled = enable;
}
}
@end

View File

@ -1,16 +0,0 @@
//
// FormModelProtocol.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 10/24/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import Foundation
public protocol FormModelProtocol: ModelProtocol {
var required: Bool? { get }
var fieldKey: String? { get }
var groupName: String? { get }
}

View File

@ -9,7 +9,7 @@
import Foundation
public protocol TemplateModelProtocol: PageModelProtocol, ModelProtocol {
public protocol TemplateModelProtocol: PageModelProtocol, ModelProtocol, FormProtocol {
var template: String { get }
}

View File

@ -30,7 +30,8 @@ import UIKit
let self = self,
let index = self.dropDown.pickerData.firstIndex(of: newValue),
let dropListItemJSON = (self.listItemModel as? DropDownListItemModel).toJSON(),
let json2d = dropListItemJSON.optionalArrayForKey("molecules") as? [[[AnyHashable: Any]]]
let json2d = dropListItemJSON.optionalArrayForKey("molecules") as? [[[AnyHashable: Any]]],
!json2d.isEmpty && !(json2d.first?.isEmpty ?? false)
else { return }
if self.previousIndex != NSNotFound {

View File

@ -51,7 +51,7 @@ import Foundation
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
molecules = try typeContainer.decodeModels2D(codingKey: .molecules)
molecules = try typeContainer.decodeModels2DIfPresent(codingKey: .molecules) ?? [[]]
dropDown = try typeContainer.decode(ItemDropdownEntryFieldModel.self, forKey: .dropDown)
try super.init(from: decoder)
}

View File

@ -8,7 +8,7 @@
import UIKit
@objcMembers public class RadioButtonLabel: ViewConstrainingView {
@objcMembers public class RadioButtonLabel: View {
public let radioButton = RadioButton()
var delegateObject: MVMCoreUIDelegateObject?
@ -65,26 +65,12 @@ import UIKit
let rightView = ViewConstrainingView(constrainingView: label)
return rightView
}
}
// MARK: - MVMCoreUIMoleculeViewProtocol
extension RadioButtonLabel {
@objc open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
self.delegateObject = delegateObject
radioButton.setWithJSON(json?.optionalDictionaryForKey("radioButton"), delegateObject: delegateObject, additionalData: additionalData)
label.setWithJSON(json?.optionalDictionaryForKey(KeyLabel),
delegateObject: delegateObject,
additionalData: additionalData)
}
public override func reset() {
super.reset()
radioButton.reset()
label.reset()
}
public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 45
}
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
guard let radioButtonLabelModel = model as? RadioButtonLabelModel else { return }
radioButton.set(with: radioButtonLabelModel.radioButton, delegateObject, additionalData)
label.set(with: radioButtonLabelModel.label, delegateObject, additionalData)
}
}

View File

@ -0,0 +1,17 @@
//
// RadioButtonLabelModel.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 3/3/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
@objcMembers public class RadioButtonLabelModel: MoleculeModelProtocol {
public static var identifier: String = "radioButtonLabel"
public var backgroundColor: Color?
public var radioButton: RadioButtonModel
public var label: LabelModel
}

View File

@ -9,21 +9,29 @@
import Foundation
import UIKit
@objcMembers public class RadioButtonSelectionHelper: NSObject {
@objcMembers public class RadioButtonSelectionHelper: FormFieldProtocol {
public var fieldKey: String?
public var groupName: String? = FormValidator.defaultGroupName
private var selectedRadioButton: RadioButton?
private var fieldGroupName: String?
public var baseValue: AnyHashable?
init(_ fieldKey: String?) {
self.fieldKey = fieldKey
}
public static func setupForRadioButtonGroup(radioButton: RadioButton, formValidator: FormValidator?) -> RadioButtonSelectionHelper {
guard let groupName = radioButton.radioGroupName,
public static func setupForRadioButtonGroup(_ radioButtonModel: RadioButtonModel, formValidator: FormValidator?) -> RadioButtonSelectionHelper {
guard let groupName = radioButtonModel.fieldKey,
let formValidator = formValidator else {
return RadioButtonSelectionHelper()
return RadioButtonSelectionHelper(radioButtonModel.fieldKey)
}
let radioButtonModel = formValidator.radioButtonsModelByGroup[groupName] ?? RadioButtonSelectionHelper()
radioButtonModel.fieldGroupName = radioButton.formFieldGroupName()
formValidator.radioButtonsModelByGroup[groupName] = radioButtonModel
return radioButtonModel
let radioButtonSelectionHelper = formValidator.radioButtonsModelByGroup[groupName] ?? RadioButtonSelectionHelper(radioButtonModel.fieldKey)
radioButtonSelectionHelper.fieldGroupName = radioButtonModel.fieldKey
formValidator.radioButtonsModelByGroup[groupName] = radioButtonSelectionHelper
return radioButtonSelectionHelper
}
public func selected(_ radioButton: RadioButton) {
@ -34,21 +42,12 @@ import UIKit
}
// MARK: - FormValidationFormFieldProtocol
extension RadioButtonSelectionHelper: FormValidationFormFieldProtocol {
extension RadioButtonSelectionHelper {
public func formFieldGroupName() -> String? {
return selectedRadioButton?.formFieldGroupName() ?? self.fieldGroupName
}
// Used to check the validity of the field, to enable/disable the primary button.
@objc public func isValidField() -> Bool {
return selectedRadioButton != nil ? true : false
}
// Name of the field to send to server
@objc public func formFieldName() -> String? {
return selectedRadioButton?.fieldKey
}
// The field value key value pair for sending to server
@objc public func formFieldValue() -> Any? {
return selectedRadioButton != nil ? true : false
public func formFieldValue() -> AnyHashable? {
return selectedRadioButton?.formFieldValue()
}
}

View File

@ -9,16 +9,18 @@
import UIKit
open class MVMCoreUIDelegateObject: DelegateObject {
public weak var formValidationProtocol: FormValidationProtocol?
public weak var formHolderDelegate: FormHolderProtocol?
public weak var buttonDelegate: ButtonDelegateProtocol?
public weak var uiTextFieldDelegate: UITextFieldDelegate?
public weak var observingTextFieldDelegate: ObservingTextFieldDelegate?
public var moleculeDelegate: MoleculeDelegateProtocol?
open override func setAll(withDelegate delegate: Any) {
super.setAll(withDelegate: delegate)
formValidationProtocol = delegate as? FormValidationProtocol
formHolderDelegate = delegate as? FormHolderProtocol
buttonDelegate = delegate as? ButtonDelegateProtocol
uiTextFieldDelegate = delegate as? UITextFieldDelegate
observingTextFieldDelegate = delegate as? ObservingTextFieldDelegate
moleculeDelegate = delegate as? MoleculeDelegateProtocol
}

View File

@ -51,8 +51,9 @@ import Foundation
MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Toggle.self, viewModelClass: ToggleModel.self)
MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Checkbox.self, viewModelClass: CheckboxModel.self)
MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: CheckboxLabel.self, viewModelClass: CheckboxLabelModel.self)
MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: RadioButton.self, viewModelClass: RadioButtonModel.self)
MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Arrow.self, viewModelClass: ArrowModel.self)
MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: RadioButton.self, viewModelClass: RadioButtonModel.self)
MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: RadioButtonLabel.self, viewModelClass: RadioButtonLabelModel.self)
// Horizontal Combination Molecules
MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: StringAndMoleculeView.self, viewModelClass: StringAndMoleculeModel.self)
@ -116,10 +117,17 @@ import Foundation
MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping.setObject(DateDropdownEntryField.self, forKey: "dateDropdownEntryField" as NSString)
MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping.setObject(Checkbox.self, forKey: "checkbox" as NSString)
MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping.setObject(CheckboxLabel.self, forKey: "checkboxLabel" as NSString)
MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping.setObject(RadioButtonLabel.self, forKey: "radioButtonLabel" as NSString)
MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping.setObject(MVMCoreUIPageControl.self, forKey: "barsPager" as NSString)
// TODO: Need View
try? ModelRegistry.register(TabsModel.self)
// Helper models
try? ModelRegistry.register(RuleRequiredModel.self)
try? ModelRegistry.register(RuleAnyRequiredModel.self)
try? ModelRegistry.register(RuleAnyValueChangedModel.self)
try? ModelRegistry.register(RuleAllValueChangedModel.self)
try? ModelRegistry.register(RuleEqualsModel.self)
try? ModelRegistry.register(RuleRegexModel.self)
}
}

View File

@ -9,6 +9,10 @@
import Foundation
@objcMembers public class ListPageTemplateModel: TemplateModelProtocol {
public var formRules: [FormGroupRule]?
public var formValidator: FormValidator?
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -47,6 +51,7 @@ import Foundation
case footer
case line
case isAtomicTabs
case formRules
}
//--------------------------------------------------
@ -62,6 +67,7 @@ import Foundation
header = try typeContainer.decodeModelIfPresent(codingKey: .header)
footer = try typeContainer.decodeModelIfPresent(codingKey: .footer)
line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line)
formRules = try typeContainer.decodeIfPresent([FormGroupRule].self, forKey: .formRules)
}
public func encode(to encoder: Encoder) throws {
@ -73,6 +79,7 @@ import Foundation
try container.encodeModelIfPresent(header, forKey: .header)
try container.encodeModelIfPresent(footer, forKey: .footer)
try container.encode(line, forKey: .line)
try container.encodeIfPresent(formRules, forKey: .formRules)
}
}

View File

@ -12,7 +12,12 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
//--------------------------------------------------
// MARK: - Stored Properties
//--------------------------------------------------
public var formValidator: FormValidator?
public func validate() {
// Can override
}
public var moleculesInfo: [(identifier: String, class: AnyClass, molecule: (ListItemModelProtocol & MoleculeModelProtocol))]?
var observer: NSKeyValueObservation?

View File

@ -9,6 +9,11 @@
import UIKit
open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol {
public func validate() {
}
public var formValidator: FormValidator?
var observer: NSKeyValueObservation?
public var templateModel: StackPageTemplateModel?

View File

@ -10,8 +10,35 @@ import Foundation
@objcMembers public class StackCenteredPageTemplateModel: TemplateModelProtocol {
public var formRules: [FormGroupRule]?
public var formValidator: FormValidator?
public static var identifier: String = "stackCenterTemplate"
public var pageType: String
public var screenHeading: String?
public var isAtomicTabs: Bool?
public init(pageType: String) {
self.pageType = pageType
}
private enum CodingKeys: String, CodingKey {
case pageType
case screenHeading
case isAtomicTabs
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
pageType = try typeContainer.decode(String.self, forKey: .pageType)
screenHeading = try typeContainer.decodeIfPresent(String.self, forKey: .screenHeading)
isAtomicTabs = try typeContainer.decodeIfPresent(Bool.self, forKey: .isAtomicTabs)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(pageType, forKey: .pageType)
try container.encodeIfPresent(screenHeading, forKey: .screenHeading)
try container.encodeIfPresent(isAtomicTabs, forKey: .isAtomicTabs)
}
}

View File

@ -10,6 +10,9 @@ import Foundation
@objcMembers public class StackPageTemplateModel: TemplateModelProtocol {
public var formRules: [FormGroupRule]?
public var formValidator: FormValidator?
public static var identifier: String = "stack"
public var pageType: String
@ -32,6 +35,7 @@ import Foundation
case footer
case stack
case isAtomicTabs
case formRules
}
required public init(from decoder: Decoder) throws {
@ -42,6 +46,7 @@ import Foundation
isAtomicTabs = try typeContainer.decodeIfPresent(Bool.self, forKey: .isAtomicTabs)
header = try typeContainer.decodeModelIfPresent(codingKey: .header)
footer = try typeContainer.decodeModelIfPresent(codingKey: .footer)
formRules = try typeContainer.decodeIfPresent([FormGroupRule].self, forKey: .formRules)
}
public func encode(to encoder: Encoder) throws {
@ -52,5 +57,6 @@ import Foundation
try container.encodeIfPresent(isAtomicTabs, forKey: .isAtomicTabs)
try container.encodeModelIfPresent(header, forKey: .header)
try container.encodeModelIfPresent(footer, forKey: .footer)
try container.encodeIfPresent(formRules, forKey: .formRules)
}
}

View File

@ -8,18 +8,23 @@
import Foundation
public protocol TemplateProtocol: class {
public protocol TemplateProtocol: FormHolderProtocol {
associatedtype TemplateModel: TemplateModelProtocol
var templateModel: TemplateModel? { get set }
}
public extension TemplateProtocol where Self: MFViewController {
func parseTemplateJSON() throws {
guard let pageJSON = self.loadObject?.pageJSON else { return }
let data = try JSONSerialization.data(withJSONObject: pageJSON)
let decoder = JSONDecoder()
let templateModel = try decoder.decode(TemplateModel.self, from: data)
if self.formValidator == nil {
let rules = templateModel.formRules
self.formValidator = FormValidator(rules)
}
self.templateModel = templateModel
}
}

View File

@ -9,6 +9,10 @@
import Foundation
@objcMembers public class ThreeLayerPageTemplateModel: TemplateModelProtocol {
public var formRules: [FormGroupRule]?
public var formValidator: FormValidator?
public static var identifier: String = "threeLayer"
public var pageType: String

View File

@ -9,6 +9,11 @@
import UIKit
@objcMembers open class ThreeLayerTemplate: ThreeLayerViewController, TemplateProtocol {
public func validate() {
}
public var formValidator: FormValidator?
public var templateModel: ThreeLayerPageTemplateModel?