diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index f3d4ca1b..7757c2d3 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -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 /* FormHolderModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D95882404249B000E3791 /* FormHolderModelProtocol.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 */; }; @@ -86,6 +96,7 @@ 0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */; }; 0A4253AF23F5C2C100554656 /* BarsIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A4253AE23F5C2C000554656 /* BarsIndicatorView.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 */; }; 0A7918F523F5E7EA00772FF4 /* ImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7918F423F5E7EA00772FF4 /* ImageView.swift */; }; 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; }; @@ -118,8 +129,14 @@ 525019DE2406430800EED91C /* ListProgressBarData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525019DC2406430800EED91C /* ListProgressBarData.swift */; }; 525019E52406852100EED91C /* ListFourColumnDataUsageDividerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525019E42406852100EED91C /* ListFourColumnDataUsageDividerModel.swift */; }; 525019E72406853600EED91C /* ListFourColumnDataUsageDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525019E62406853600EED91C /* ListFourColumnDataUsageDivider.swift */; }; + 525239C02407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525239BF2407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift */; }; + 525239C22407BD1000454969 /* ListTwoColumnPriceDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525239C12407BD1000454969 /* ListTwoColumnPriceDetails.swift */; }; + 526A265C240D1FF700B0D828 /* ListTwoColumnCompareChangesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 526A265B240D1FF700B0D828 /* ListTwoColumnCompareChangesModel.swift */; }; + 526A265E240D200500B0D828 /* ListTwoColumnCompareChanges.swift in Sources */ = {isa = PBXBuildFile; fileRef = 526A265D240D200500B0D828 /* ListTwoColumnCompareChanges.swift */; }; 52B201D224081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B201D024081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift */; }; 52B201D324081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B201D124081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift */; }; + 8D070BB0241B56530099AC56 /* ListRightVariableTotalDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D070BAF241B56530099AC56 /* ListRightVariableTotalDataModel.swift */; }; + 8D070BB2241B56AD0099AC56 /* ListRightVariableTotalData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */; }; 8D084AD02410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */; }; 8D084AD22410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D084AD12410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift */; }; 8D24041123E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D24041023E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift */; }; @@ -145,6 +162,8 @@ 94AF4A3F23E9D13900676048 /* MFCaretButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 94AF4A3D23E9D13900676048 /* MFCaretButton.m */; }; 94AF4A4223E9D19E00676048 /* MFCaretView.h in Headers */ = {isa = PBXBuildFile; fileRef = 94AF4A4023E9D19E00676048 /* MFCaretView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 94AF4A4323E9D19E00676048 /* MFCaretView.m in Sources */ = {isa = PBXBuildFile; fileRef = 94AF4A4123E9D19E00676048 /* MFCaretView.m */; }; + 94C0150A24215643005811A9 /* ActionTopAlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C0150924215643005811A9 /* ActionTopAlertModel.swift */; }; + 94C0150C2421564A005811A9 /* ActionCollapseNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C0150B2421564A005811A9 /* ActionCollapseNotificationModel.swift */; }; 94C2D9842386F3F80006CF46 /* LabelAttributeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9832386F3F80006CF46 /* LabelAttributeModel.swift */; }; 94C2D9A123872BCC0006CF46 /* LabelAttributeUnderlineModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9A023872BCC0006CF46 /* LabelAttributeUnderlineModel.swift */; }; 94C2D9A323872C110006CF46 /* LabelAttributeStrikeThroughModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9A223872C110006CF46 /* LabelAttributeStrikeThroughModel.swift */; }; @@ -164,6 +183,14 @@ 94FB966323D797DA003D482B /* MFTextButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 94FB966123D797DA003D482B /* MFTextButton.m */; }; AA11A41F23F15D3100D7962F /* ListRightVariablePayments.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11A41E23F15D3100D7962F /* ListRightVariablePayments.swift */; }; AA11A42123F15D7000D7962F /* ListRightVariablePaymentsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11A42023F15D7000D7962F /* ListRightVariablePaymentsModel.swift */; }; + AAA74A172410C04600080241 /* HeadersH2NoButtonsBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */; }; + AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */; }; + BB47A586241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB47A585241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift */; }; + BB47A588241615FA002BB23C /* ListOneColumnFullWidthTextDividerSubsection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB47A587241615FA002BB23C /* ListOneColumnFullWidthTextDividerSubsection.swift */; }; + BB6C6AC0242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6C6ABE242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift */; }; + BB6C6AC1242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6C6ABF242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift */; }; + BB6C6AC824225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6C6AC62422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift */; }; + BB6C6AC924225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6C6AC72422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift */; }; C003506123AA94CD00B6AC29 /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = C003506023AA94CD00B6AC29 /* Button.swift */; }; C07065C42395677300FBF997 /* Link.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07065C32395677300FBF997 /* Link.swift */; }; C695A67F23C9830600BFB94E /* UnOrderedListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C695A67E23C9830600BFB94E /* UnOrderedListModel.swift */; }; @@ -178,6 +205,7 @@ C7F8012123E8303200396FBD /* ListRVWheel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F8012023E8303200396FBD /* ListRVWheel.swift */; }; C7F8012323E846C300396FBD /* ListRVWheelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F8012223E846C300396FBD /* ListRVWheelModel.swift */; }; D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; }; + D20FB165241A5D75004AFC3A /* NavigationItemModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20FB164241A5D75004AFC3A /* NavigationItemModelProtocol.swift */; }; D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; }; D21EE53C23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */; }; D224798A2314445E003FCCF9 /* LabelToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479892314445E003FCCF9 /* LabelToggle.swift */; }; @@ -193,6 +221,11 @@ D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */; }; D22D1F562204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D22D1F542204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D22D1F572204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D22D1F552204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m */; }; + D22D8393241C27B100D3DF69 /* TemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22D8392241C27B100D3DF69 /* TemplateModel.swift */; }; + D22D8395241FB41200D3DF69 /* UIStackView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22D8394241FB41200D3DF69 /* UIStackView+Extension.swift */; }; + D236E5B4241FEB1000C38625 /* ListTwoColumnPriceDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = D236E5B2241FEB1000C38625 /* ListTwoColumnPriceDescription.swift */; }; + D236E5B5241FEB1000C38625 /* ListTwoColumnPriceDescriptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D236E5B3241FEB1000C38625 /* ListTwoColumnPriceDescriptionModel.swift */; }; + D236E5B7242007C500C38625 /* MVMControllerModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D236E5B6242007C500C38625 /* MVMControllerModelProtocol.swift */; }; D243859923A16B1800332775 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = D243859823A16B1800332775 /* Container.swift */; }; D256E9932412880000360572 /* Header.swift in Sources */ = {isa = PBXBuildFile; fileRef = D256E9922412880000360572 /* Header.swift */; }; D260105323CEA61600764D80 /* ToggleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D260105223CEA61600764D80 /* ToggleModel.swift */; }; @@ -241,6 +274,7 @@ D29770FC21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770FA21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m */; }; D29770FD21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29770FB21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */; }; + D29C94D5242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29C94D4242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift */; }; D29DF0D121E404D4003B2FB9 /* MVMCoreUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */; }; D29DF11521E6805F003B2FB9 /* UIColor+MFConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF11121E6805F003B2FB9 /* UIColor+MFConvenience.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -285,11 +319,11 @@ D29DF28421E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF28221E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF28B21E7AC2B003B2FB9 /* ViewConstrainingView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF28721E7AC2B003B2FB9 /* ViewConstrainingView.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF28821E7AC2B003B2FB9 /* ViewConstrainingView.m */; }; - D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF28D21E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m */; }; + D29DF29521E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF28D21E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.m */; }; D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF28E21E7ADB8003B2FB9 /* StackableViewController.m */; }; D29DF29721E7ADB8003B2FB9 /* MFScrollingViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF28F21E7ADB8003B2FB9 /* MFScrollingViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF29821E7ADB8003B2FB9 /* MFScrollingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF29021E7ADB8003B2FB9 /* MFScrollingViewController.m */; }; - D29DF29921E7ADB8003B2FB9 /* ProgrammaticScrollViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF29121E7ADB8003B2FB9 /* ProgrammaticScrollViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D29DF29921E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF29121E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF29A21E7ADB8003B2FB9 /* MFProgrammaticTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF29221E7ADB8003B2FB9 /* MFProgrammaticTableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF29B21E7ADB9003B2FB9 /* StackableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF29321E7ADB8003B2FB9 /* StackableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF29421E7ADB8003B2FB9 /* MFProgrammaticTableViewController.m */; }; @@ -342,6 +376,9 @@ D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A638FC22CA98280052ED1F /* HeadlineBody.swift */; }; D2A6390122CBB1820052ED1F /* Carousel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A6390022CBB1820052ED1F /* Carousel.swift */; }; D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */; }; + D2A92882241AAB67004E01C6 /* ScrollingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A92881241AAB67004E01C6 /* ScrollingViewController.swift */; }; + D2A92884241ACB25004E01C6 /* ProgrammaticScrollViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A92883241ACB25004E01C6 /* ProgrammaticScrollViewController.swift */; }; + D2A92886241ACD99004E01C6 /* ProgrammaticTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A92885241ACD99004E01C6 /* ProgrammaticTableViewController.swift */; }; D2B18B7F2360913400A9AEDC /* Control.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B7E2360913400A9AEDC /* Control.swift */; }; D2B18B812360945C00A9AEDC /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B802360945C00A9AEDC /* View.swift */; }; D2B18B922361E65A00A9AEDC /* CoreUIObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B912361E65A00A9AEDC /* CoreUIObject.swift */; }; @@ -350,6 +387,7 @@ D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */; }; D2C521A923EDE79E00CA2634 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C521A823EDE79E00CA2634 /* ViewController.swift */; }; + D2C78CD224228BBD00B69FDE /* ActionOpenPanelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C78CD124228BBD00B69FDE /* ActionOpenPanelModel.swift */; }; D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */; }; D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */; }; D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D90B41240463E100DD6EC9 /* MoleculeHeaderModel.swift */; }; @@ -381,12 +419,25 @@ 01004F2F22721C3800991ECC /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = ""; }; 0103B84D23D7E33A009C315C /* HeadlineBodyToggleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyToggleModel.swift; sourceTree = ""; }; 0105618A224BBE7700E1557D /* FormValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormValidator.swift; sourceTree = ""; }; - 0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+TextFields.swift"; sourceTree = ""; }; - 0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+FormParams.swift"; sourceTree = ""; }; 0116A4E4228B19640094F3ED /* RadioButtonSelectionHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonSelectionHelper.swift; sourceTree = ""; }; 011B58EF23A2AA980085F53C /* ListItemModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemModelProtocol.swift; sourceTree = ""; }; 011B58F123A2AE2C0085F53C /* DropDownListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropDownListItemModel.swift; sourceTree = ""; }; + 011D958424042432000E3791 /* RulesProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RulesProtocol.swift; sourceTree = ""; }; + 011D958624042492000E3791 /* FormFieldProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormFieldProtocol.swift; sourceTree = ""; }; + 011D95882404249B000E3791 /* FormHolderModelProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormHolderModelProtocol.swift; sourceTree = ""; }; + 011D959A240451E3000E3791 /* RuleRequiredModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleRequiredModel.swift; sourceTree = ""; }; + 011D959C2404536F000E3791 /* RuleAnyValueChangedModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyValueChangedModel.swift; sourceTree = ""; }; + 011D959E240453A1000E3791 /* RuleAllValueChangedModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAllValueChangedModel.swift; sourceTree = ""; }; + 011D95A0240453D0000E3791 /* RuleEqualsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleEqualsModel.swift; sourceTree = ""; }; + 011D95A2240453F8000E3791 /* RuleRegexModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleRegexModel.swift; sourceTree = ""; }; + 011D95A4240455DC000E3791 /* FormGroupRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormGroupRule.swift; sourceTree = ""; }; + 011D95A824057AC7000E3791 /* FormActionFieldProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormActionFieldProtocol.swift; sourceTree = ""; }; + 011D95AA2405C553000E3791 /* FormItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormItemProtocol.swift; sourceTree = ""; }; + 011D95AC2406BB57000E3791 /* FormHolderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormHolderProtocol.swift; sourceTree = ""; }; 011D95AE2407266E000E3791 /* RadioButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonModel.swift; sourceTree = ""; }; + 011D9601240DA20A000E3791 /* ValidProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidProtocol.swift; sourceTree = ""; }; + 011D9625240EBB16000E3791 /* RadioButtonLabelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioButtonLabelModel.swift; sourceTree = ""; }; + 011D9627240EFA1E000E3791 /* MFViewController+Form.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFViewController+Form.swift"; sourceTree = ""; }; 012A889B23889E8400FE3DA1 /* TemplateModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateModelProtocol.swift; sourceTree = ""; }; 012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateProtocol.swift; sourceTree = ""; }; 012A88AE238C626E00FE3DA1 /* CarouselModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselModel.swift; sourceTree = ""; }; @@ -397,7 +448,6 @@ 012A88C7238DB02000FE3DA1 /* ModelMoleculeDelegateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelMoleculeDelegateProtocol.swift; sourceTree = ""; }; 012A88EB238F084D00FE3DA1 /* FooterModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FooterModel.swift; sourceTree = ""; }; 012A88F023985E0100FE3DA1 /* Color.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; - 012CA9992384A687003F810F /* MFTextField+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFTextField+ModelExtension.swift"; sourceTree = ""; }; 012CA99D2385A2D3003F810F /* MFView+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFView+ModelExtension.swift"; sourceTree = ""; }; 013F801823FB4A8E00AD8013 /* UIContentMode+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIContentMode+Extension.swift"; sourceTree = ""; }; 014AA72123C501E2006F3E93 /* MoleculeContainerModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeContainerModel.swift; sourceTree = ""; }; @@ -414,13 +464,11 @@ 017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioButtonLabel.swift; sourceTree = ""; }; 017BEB3B2361EA1D0024EF95 /* MFViewController+Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFViewController+Model.swift"; sourceTree = ""; }; 017BEB3F23620A230024EF95 /* TextFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldModel.swift; sourceTree = ""; }; - 017BEB4123620AD20024EF95 /* FormModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormModelProtocol.swift; sourceTree = ""; }; 017BEB432362192F0024EF95 /* MVMCoreUIMoleculeMappingObject+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUIMoleculeMappingObject+ModelExtension.swift"; sourceTree = ""; }; 017BEB47236230DB0024EF95 /* MoleculeViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeViewProtocol.swift; sourceTree = ""; }; 017BEB49236235BA0024EF95 /* ModelMoleculeViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelMoleculeViewProtocol.swift; sourceTree = ""; }; 017BEB7A236763000024EF95 /* LineModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineModel.swift; sourceTree = ""; }; 017BEB7E23676E870024EF95 /* MoleculeObjectMapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeObjectMapping.swift; sourceTree = ""; }; - 0198F79E225679870066C936 /* FormValidationProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormValidationProtocol.swift; sourceTree = ""; }; 0198F7A02256A80A0066C936 /* MFRadioButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFRadioButton.h; sourceTree = ""; }; 0198F7A22256A80A0066C936 /* MFRadioButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFRadioButton.m; sourceTree = ""; }; 01C851D223CF9E740021F976 /* LabelToggleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelToggleModel.swift; sourceTree = ""; }; @@ -445,6 +493,7 @@ 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = ""; }; 0A4253AE23F5C2C000554656 /* BarsIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarsIndicatorView.swift; sourceTree = ""; }; 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesProtocol.swift; sourceTree = ""; }; + 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyRequiredModel.swift; sourceTree = ""; }; 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseDropdownEntryField.swift; sourceTree = ""; }; 0A7918F423F5E7EA00772FF4 /* ImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageView.swift; sourceTree = ""; }; 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = ""; }; @@ -480,8 +529,14 @@ 525019DC2406430800EED91C /* ListProgressBarData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListProgressBarData.swift; sourceTree = ""; }; 525019E42406852100EED91C /* ListFourColumnDataUsageDividerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListFourColumnDataUsageDividerModel.swift; sourceTree = ""; }; 525019E62406853600EED91C /* ListFourColumnDataUsageDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListFourColumnDataUsageDivider.swift; sourceTree = ""; }; + 525239BF2407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnPriceDetailsModel.swift; sourceTree = ""; }; + 525239C12407BD1000454969 /* ListTwoColumnPriceDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnPriceDetails.swift; sourceTree = ""; }; + 526A265B240D1FF700B0D828 /* ListTwoColumnCompareChangesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnCompareChangesModel.swift; sourceTree = ""; }; + 526A265D240D200500B0D828 /* ListTwoColumnCompareChanges.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnCompareChanges.swift; sourceTree = ""; }; 52B201D024081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonAndPaymentMethod.swift; sourceTree = ""; }; 52B201D124081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonAndPaymentMethodModel.swift; sourceTree = ""; }; + 8D070BAF241B56530099AC56 /* ListRightVariableTotalDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableTotalDataModel.swift; sourceTree = ""; }; + 8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableTotalData.swift; sourceTree = ""; }; 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextBodyTextModel.swift; sourceTree = ""; }; 8D084AD12410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextBodyText.swift; sourceTree = ""; }; 8D24041023E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconWithRightCaret.swift; sourceTree = ""; }; @@ -508,6 +563,8 @@ 94AF4A3D23E9D13900676048 /* MFCaretButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MFCaretButton.m; sourceTree = ""; }; 94AF4A4023E9D19E00676048 /* MFCaretView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MFCaretView.h; sourceTree = ""; }; 94AF4A4123E9D19E00676048 /* MFCaretView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MFCaretView.m; sourceTree = ""; }; + 94C0150924215643005811A9 /* ActionTopAlertModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionTopAlertModel.swift; sourceTree = ""; }; + 94C0150B2421564A005811A9 /* ActionCollapseNotificationModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionCollapseNotificationModel.swift; sourceTree = ""; }; 94C2D9832386F3F80006CF46 /* LabelAttributeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeModel.swift; sourceTree = ""; }; 94C2D9A023872BCC0006CF46 /* LabelAttributeUnderlineModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeUnderlineModel.swift; sourceTree = ""; }; 94C2D9A223872C110006CF46 /* LabelAttributeStrikeThroughModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeStrikeThroughModel.swift; sourceTree = ""; }; @@ -525,6 +582,14 @@ 94FB966123D797DA003D482B /* MFTextButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFTextButton.m; sourceTree = ""; }; AA11A41E23F15D3100D7962F /* ListRightVariablePayments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariablePayments.swift; sourceTree = ""; }; AA11A42023F15D7000D7962F /* ListRightVariablePaymentsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariablePaymentsModel.swift; sourceTree = ""; }; + AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyText.swift; sourceTree = ""; }; + AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyTextModel.swift; sourceTree = ""; }; + BB47A585241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextDividerSubsectionModel.swift; sourceTree = ""; }; + BB47A587241615FA002BB23C /* ListOneColumnFullWidthTextDividerSubsection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextDividerSubsection.swift; sourceTree = ""; }; + BB6C6ABE242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ListOneColumnTextWithWhitespaceDividerTallModel.swift; path = MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnTextWithWhitespaceDividerTallModel.swift; sourceTree = SOURCE_ROOT; }; + BB6C6ABF242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ListOneColumnTextWithWhitespaceDividerTall.swift; path = MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift; sourceTree = SOURCE_ROOT; }; + BB6C6AC62422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListOneColumnTextWithWhitespaceDividerShort.swift; sourceTree = ""; }; + BB6C6AC72422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListOneColumnTextWithWhitespaceDividerShortModel.swift; sourceTree = ""; }; C003506023AA94CD00B6AC29 /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; C07065C32395677300FBF997 /* Link.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Link.swift; sourceTree = ""; }; C695A67E23C9830600BFB94E /* UnOrderedListModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnOrderedListModel.swift; sourceTree = ""; }; @@ -539,6 +604,7 @@ C7F8012023E8303200396FBD /* ListRVWheel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListRVWheel.swift; sourceTree = ""; }; C7F8012223E846C300396FBD /* ListRVWheelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRVWheelModel.swift; sourceTree = ""; }; D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = ""; }; + D20FB164241A5D75004AFC3A /* NavigationItemModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItemModelProtocol.swift; sourceTree = ""; }; D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSLayoutConstraintAxis+Extension.swift"; sourceTree = ""; }; D22479892314445E003FCCF9 /* LabelToggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelToggle.swift; sourceTree = ""; }; @@ -554,6 +620,11 @@ D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUISwitch.m; sourceTree = ""; }; D22D1F542204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIStackableViewController.h; sourceTree = ""; }; D22D1F552204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIStackableViewController.m; sourceTree = ""; }; + D22D8392241C27B100D3DF69 /* TemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateModel.swift; sourceTree = ""; }; + D22D8394241FB41200D3DF69 /* UIStackView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIStackView+Extension.swift"; sourceTree = ""; }; + D236E5B2241FEB1000C38625 /* ListTwoColumnPriceDescription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListTwoColumnPriceDescription.swift; sourceTree = ""; }; + D236E5B3241FEB1000C38625 /* ListTwoColumnPriceDescriptionModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListTwoColumnPriceDescriptionModel.swift; sourceTree = ""; }; + D236E5B6242007C500C38625 /* MVMControllerModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMControllerModelProtocol.swift; sourceTree = ""; }; D243859823A16B1800332775 /* Container.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Container.swift; sourceTree = ""; }; D256E9922412880000360572 /* Header.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Header.swift; sourceTree = ""; }; D260105223CEA61600764D80 /* ToggleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleModel.swift; sourceTree = ""; }; @@ -601,6 +672,7 @@ D29770FA21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUITextFieldView.m; sourceTree = ""; }; D29770FB21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUITextFieldView.h; sourceTree = ""; }; D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModuleMolecule.swift; sourceTree = ""; }; + D29C94D4242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUICommonViewsUtility+Extension.swift"; sourceTree = ""; }; D29DF0CC21E404D4003B2FB9 /* MVMCoreUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MVMCoreUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUI.h; sourceTree = ""; }; D29DF0D021E404D4003B2FB9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -666,11 +738,11 @@ D29DF28221E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUICommonViewsUtility.h; sourceTree = ""; }; D29DF28721E7AC2B003B2FB9 /* ViewConstrainingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewConstrainingView.h; sourceTree = ""; }; D29DF28821E7AC2B003B2FB9 /* ViewConstrainingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewConstrainingView.m; sourceTree = ""; }; - D29DF28D21E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProgrammaticScrollViewController.m; sourceTree = ""; }; + D29DF28D21E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFProgrammaticScrollViewController.m; sourceTree = ""; }; D29DF28E21E7ADB8003B2FB9 /* StackableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StackableViewController.m; sourceTree = ""; }; D29DF28F21E7ADB8003B2FB9 /* MFScrollingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFScrollingViewController.h; sourceTree = ""; }; D29DF29021E7ADB8003B2FB9 /* MFScrollingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFScrollingViewController.m; sourceTree = ""; }; - D29DF29121E7ADB8003B2FB9 /* ProgrammaticScrollViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProgrammaticScrollViewController.h; sourceTree = ""; }; + D29DF29121E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFProgrammaticScrollViewController.h; sourceTree = ""; }; D29DF29221E7ADB8003B2FB9 /* MFProgrammaticTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFProgrammaticTableViewController.h; sourceTree = ""; }; D29DF29321E7ADB8003B2FB9 /* StackableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackableViewController.h; sourceTree = ""; }; D29DF29421E7ADB8003B2FB9 /* MFProgrammaticTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFProgrammaticTableViewController.m; sourceTree = ""; }; @@ -717,6 +789,9 @@ D2A638FC22CA98280052ED1F /* HeadlineBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBody.swift; sourceTree = ""; }; D2A6390022CBB1820052ED1F /* Carousel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Carousel.swift; sourceTree = ""; }; D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeCollectionViewCell.swift; sourceTree = ""; }; + D2A92881241AAB67004E01C6 /* ScrollingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollingViewController.swift; sourceTree = ""; }; + D2A92883241ACB25004E01C6 /* ProgrammaticScrollViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgrammaticScrollViewController.swift; sourceTree = ""; }; + D2A92885241ACD99004E01C6 /* ProgrammaticTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgrammaticTableViewController.swift; sourceTree = ""; }; D2B18B7E2360913400A9AEDC /* Control.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Control.swift; sourceTree = ""; }; D2B18B802360945C00A9AEDC /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; D2B18B912361E65A00A9AEDC /* CoreUIObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreUIObject.swift; sourceTree = ""; }; @@ -725,6 +800,7 @@ D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewControllerMappingObject.h; sourceTree = ""; }; D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = ""; }; D2C521A823EDE79E00CA2634 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + D2C78CD124228BBD00B69FDE /* ActionOpenPanelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionOpenPanelModel.swift; sourceTree = ""; }; D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scroller.swift; sourceTree = ""; }; D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTemplate.swift; sourceTree = ""; }; D2D90B41240463E100DD6EC9 /* MoleculeHeaderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeHeaderModel.swift; sourceTree = ""; }; @@ -768,7 +844,6 @@ isa = PBXGroup; children = ( 014AA72323C501E2006F3E93 /* ContainerModelProtocol.swift */, - 017BEB4123620AD20024EF95 /* FormModelProtocol.swift */, 012A88C3238D86E600FE3DA1 /* CarouselItemModelProtocol.swift */, 012A88B0238C880100FE3DA1 /* CarouselPagingModelProtocol.swift */, 01EB3683236097C0006832FA /* MoleculeModelProtocol.swift */, @@ -780,6 +855,22 @@ path = ModelProtocols; sourceTree = ""; }; + 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 = ""; + }; 012A88EF23985E0100FE3DA1 /* CustomPrimitives */ = { isa = PBXGroup; children = ( @@ -799,10 +890,14 @@ 01C74D87224298E2009C25A3 /* FormUIHelpers */ = { isa = PBXGroup; children = ( - 0198F79E225679870066C936 /* FormValidationProtocol.swift */, + 011D95882404249B000E3791 /* FormHolderModelProtocol.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 = ""; @@ -851,6 +946,15 @@ path = Link; sourceTree = ""; }; + 5206F150241144A900658DC5 /* Headers */ = { + isa = PBXGroup; + children = ( + AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */, + AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */, + ); + path = Headers; + sourceTree = ""; + }; 52267A0523FFE0A900906CBA /* OneColumn */ = { isa = PBXGroup; children = ( @@ -880,6 +984,36 @@ path = LockUps; sourceTree = ""; }; + 525665CB24211FD5007BF25F /* OneColumn */ = { + isa = PBXGroup; + children = ( + BB6C6AC72422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift */, + BB6C6AC62422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift */, + BB6C6ABE242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift */, + BB6C6ABF242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift */, + BB47A585241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift */, + BB47A587241615FA002BB23C /* ListOneColumnFullWidthTextDividerSubsection.swift */, + ); + path = OneColumn; + sourceTree = ""; + }; + 526A265A240D1FCE00B0D828 /* TwoColumn */ = { + isa = PBXGroup; + children = ( + ); + path = TwoColumn; + sourceTree = ""; + }; + 94C01508242155FE005811A9 /* Actions */ = { + isa = PBXGroup; + children = ( + 94C0150924215643005811A9 /* ActionTopAlertModel.swift */, + 94C0150B2421564A005811A9 /* ActionCollapseNotificationModel.swift */, + D2C78CD124228BBD00B69FDE /* ActionOpenPanelModel.swift */, + ); + path = Actions; + sourceTree = ""; + }; 94C2D9822386F3E30006CF46 /* Label */ = { isa = PBXGroup; children = ( @@ -901,6 +1035,8 @@ children = ( AA11A42023F15D7000D7962F /* ListRightVariablePaymentsModel.swift */, AA11A41E23F15D3100D7962F /* ListRightVariablePayments.swift */, + 8D070BAF241B56530099AC56 /* ListRightVariableTotalDataModel.swift */, + 8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */, C7F8012223E846C300396FBD /* ListRVWheelModel.swift */, C7F8012023E8303200396FBD /* ListRVWheel.swift */, ); @@ -910,8 +1046,20 @@ D213347423842FE3008E41B3 /* Controllers */ = { isa = PBXGroup; children = ( + D29DF16021E69996003B2FB9 /* MFViewController.h */, + D29DF15F21E69996003B2FB9 /* MFViewController.m */, + 017BEB3B2361EA1D0024EF95 /* MFViewController+Model.swift */, + 011D9627240EFA1E000E3791 /* MFViewController+Form.swift */, + D29DF28F21E7ADB8003B2FB9 /* MFScrollingViewController.h */, + D29DF29021E7ADB8003B2FB9 /* MFScrollingViewController.m */, + D29DF29121E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.h */, + D29DF28D21E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.m */, D29DF29321E7ADB8003B2FB9 /* StackableViewController.h */, D29DF28E21E7ADB8003B2FB9 /* StackableViewController.m */, + D29DF29221E7ADB8003B2FB9 /* MFProgrammaticTableViewController.h */, + D29DF29421E7ADB8003B2FB9 /* MFProgrammaticTableViewController.m */, + D22D1F542204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h */, + D22D1F552204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m */, D29770F021F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.h */, D29770F121F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m */, D29770EF21F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.h */, @@ -1079,6 +1227,7 @@ D22B38E923F4E07800490EF6 /* DesignedComponents */ = { isa = PBXGroup; children = ( + 5206F150241144A900658DC5 /* Headers */, 525239C32407FFCC00454969 /* LockUps */, D22B38EC23F4E10700490EF6 /* SectionDividers */, D22B38EA23F4E08B00490EF6 /* List */, @@ -1089,6 +1238,7 @@ D22B38EA23F4E08B00490EF6 /* List */ = { isa = PBXGroup; children = ( + D22D8396241FDE4700D3DF69 /* TwoColumn */, 52267A0523FFE0A900906CBA /* OneColumn */, AA4FC2A323F4F69600E251DB /* RightVariable */, D22B38EB23F4E0AE00490EF6 /* LeftVariable */, @@ -1112,6 +1262,8 @@ D22B38EC23F4E10700490EF6 /* SectionDividers */ = { isa = PBXGroup; children = ( + 525665CB24211FD5007BF25F /* OneColumn */, + 526A265A240D1FCE00B0D828 /* TwoColumn */, 525019E3240684E500EED91C /* FourColumn */, D22B38ED23F4E11100490EF6 /* ThreeColumn */, ); @@ -1136,6 +1288,19 @@ path = Legacy; sourceTree = ""; }; + D22D8396241FDE4700D3DF69 /* TwoColumn */ = { + isa = PBXGroup; + children = ( + D236E5B3241FEB1000C38625 /* ListTwoColumnPriceDescriptionModel.swift */, + D236E5B2241FEB1000C38625 /* ListTwoColumnPriceDescription.swift */, + 526A265B240D1FF700B0D828 /* ListTwoColumnCompareChangesModel.swift */, + 526A265D240D200500B0D828 /* ListTwoColumnCompareChanges.swift */, + 525239BF2407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift */, + 525239C12407BD1000454969 /* ListTwoColumnPriceDetails.swift */, + ); + path = TwoColumn; + sourceTree = ""; + }; D260105723CF9CC500764D80 /* Doughnut */ = { isa = PBXGroup; children = ( @@ -1179,6 +1344,7 @@ D22D1F582204D2590077CEC0 /* Legacy */, D29DF10F21E67A7D003B2FB9 /* BaseControllers */, D29DF11E21E6851E003B2FB9 /* TopAlert */, + 94C01508242155FE005811A9 /* Actions */, D29DF10D21E67A70003B2FB9 /* Atoms */, D29DF10E21E67A77003B2FB9 /* Molecules */, D22479902316A9CB003FCCF9 /* Organisms */, @@ -1193,6 +1359,7 @@ isa = PBXGroup; children = ( 012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */, + D22D8392241C27B100D3DF69 /* TemplateModel.swift */, 014AA72823C5059B006F3E93 /* StackPageTemplateModel.swift */, D2A5146022121FBF00345BFB /* MoleculeStackTemplate.swift */, 942C378D2412F5B60066E45E /* ModalMoleculeStackTemplate.swift */, @@ -1246,10 +1413,12 @@ D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */, D28A838423CCCA8900DFE4FC /* ScrollerModel.swift */, D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */, + 011D9625240EBB16000E3791 /* RadioButtonLabelModel.swift */, 017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */, 017BEB47236230DB0024EF95 /* MoleculeViewProtocol.swift */, 017BEB49236235BA0024EF95 /* ModelMoleculeViewProtocol.swift */, D260105723CF9CC500764D80 /* Doughnut */, + D20FB164241A5D75004AFC3A /* NavigationItemModelProtocol.swift */, ); path = Molecules; sourceTree = ""; @@ -1257,22 +1426,15 @@ D29DF10F21E67A7D003B2FB9 /* BaseControllers */ = { isa = PBXGroup; children = ( - D29DF16021E69996003B2FB9 /* MFViewController.h */, - D29DF15F21E69996003B2FB9 /* MFViewController.m */, - 017BEB3B2361EA1D0024EF95 /* MFViewController+Model.swift */, - D29DF28F21E7ADB8003B2FB9 /* MFScrollingViewController.h */, - D29DF29021E7ADB8003B2FB9 /* MFScrollingViewController.m */, - D29DF29121E7ADB8003B2FB9 /* ProgrammaticScrollViewController.h */, - D29DF28D21E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m */, - D29DF29221E7ADB8003B2FB9 /* MFProgrammaticTableViewController.h */, - D29DF29421E7ADB8003B2FB9 /* MFProgrammaticTableViewController.m */, - D22D1F542204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h */, - D22D1F552204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m */, + D236E5B6242007C500C38625 /* MVMControllerModelProtocol.swift */, D29DF2CC21E7C104003B2FB9 /* MFLoadingViewController.h */, D29DF2CD21E7C104003B2FB9 /* MFLoadingViewController.m */, D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */, D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */, D2C521A823EDE79E00CA2634 /* ViewController.swift */, + D2A92881241AAB67004E01C6 /* ScrollingViewController.swift */, + D2A92883241ACB25004E01C6 /* ProgrammaticScrollViewController.swift */, + D2A92885241ACD99004E01C6 /* ProgrammaticTableViewController.swift */, ); path = BaseControllers; sourceTree = ""; @@ -1287,6 +1449,7 @@ D29DF11421E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m */, D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */, 0AA33B33239813C50067DD0F /* UIColor+Extension.swift */, + D22D8394241FB41200D3DF69 /* UIStackView+Extension.swift */, ); path = Categories; sourceTree = ""; @@ -1334,6 +1497,7 @@ D29DF13B21E6870B003B2FB9 /* Sizing */, D29DF28221E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.h */, D29DF28121E7AB23003B2FB9 /* MVMCoreUICommonViewsUtility.m */, + D29C94D4242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift */, D29DF14D21E693AD003B2FB9 /* MFFonts.h */, D29DF14C21E693AD003B2FB9 /* MFFonts.m */, 9458C3152406C8FD00930963 /* UIFont+FontWrapping.h */, @@ -1433,7 +1597,6 @@ 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */, 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */, 017BEB3F23620A230024EF95 /* TextFieldModel.swift */, - 012CA9992384A687003F810F /* MFTextField+ModelExtension.swift */, ); path = TextFields; sourceTree = ""; @@ -1602,7 +1765,7 @@ D29DF2A921E7B2F9003B2FB9 /* MVMCoreUIConstants.h in Headers */, 0198F7A62256A80B0066C936 /* MFRadioButton.h in Headers */, D22D1F1A220341F60077CEC0 /* MVMCoreUICheckBox.h in Headers */, - D29DF29921E7ADB8003B2FB9 /* ProgrammaticScrollViewController.h in Headers */, + D29DF29921E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.h in Headers */, D29DF11C21E684A9003B2FB9 /* MVMCoreUISplitViewController.h in Headers */, D29DF29B21E7ADB9003B2FB9 /* StackableViewController.h in Headers */, D29770F421F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.h in Headers */, @@ -1752,6 +1915,7 @@ files = ( 5248BFED23F12E350059236A /* ListThreeColumnPlanDataDividerModel.swift in Sources */, 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */, + 8D070BB0241B56530099AC56 /* ListRightVariableTotalDataModel.swift in Sources */, 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */, 31BE15CC23D8924D00452370 /* CheckboxModel.swift in Sources */, 94C661DA23CCF4FB00D9FE5B /* UIColor+Extension.swift in Sources */, @@ -1759,6 +1923,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 */, @@ -1778,12 +1943,16 @@ 01004F3022721C3800991ECC /* RadioButton.swift in Sources */, D268C70E238C22D7007F2C1C /* DropDownFilterTableViewCell.swift in Sources */, 017BEB3C2361EA1D0024EF95 /* MFViewController+Model.swift in Sources */, + D236E5B7242007C500C38625 /* MVMControllerModelProtocol.swift in Sources */, D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */, D29DF11721E6805F003B2FB9 /* UIColor+MFConvenience.m in Sources */, D2B18B7F2360913400A9AEDC /* Control.swift in Sources */, + 011D95A924057AC7000E3791 /* FormActionFieldProtocol.swift in Sources */, + D236E5B4241FEB1000C38625 /* ListTwoColumnPriceDescription.swift in Sources */, 0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */, D29DF12F21E6851E003B2FB9 /* MVMCoreUITopAlertMainView.m in Sources */, 942C378C2412F4FA0066E45E /* ModalMoleculeListTemplate.swift in Sources */, + BB47A588241615FA002BB23C /* ListOneColumnFullWidthTextDividerSubsection.swift in Sources */, 012A88C8238DB02000FE3DA1 /* ModelMoleculeDelegateProtocol.swift in Sources */, 0A7EF86123D8AC2500B2AAD1 /* DigitEntryFieldModel.swift in Sources */, DBC4392122491730001AB423 /* LabelWithInternalButton.swift in Sources */, @@ -1795,13 +1964,17 @@ 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 */, + BB6C6AC1242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.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 */, 01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */, + D2A92884241ACB25004E01C6 /* ProgrammaticScrollViewController.swift in Sources */, 0A21DB7F235DECC500C160A2 /* EntryField.swift in Sources */, D2E2A99F23E07F8A000B42E6 /* PillButton.swift in Sources */, 0A4253AF23F5C2C100554656 /* BarsIndicatorView.swift in Sources */, @@ -1824,9 +1997,12 @@ 012A88C4238D86E600FE3DA1 /* CarouselItemModelProtocol.swift in Sources */, D2E2A9A123E095AB000B42E6 /* ButtonModelProtocol.swift in Sources */, 94C2D9AB23872EB50006CF46 /* LabelAttributeActionModel.swift in Sources */, + D22D8395241FB41200D3DF69 /* UIStackView+Extension.swift in Sources */, 52B201D324081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift in Sources */, + 525239C02407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift in Sources */, D2E2A99A23D8D6B4000B42E6 /* HeadlineBodyButtonModel.swift in Sources */, 8D084AD22410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift in Sources */, + 94C0150C2421564A005811A9 /* ActionCollapseNotificationModel.swift in Sources */, 014AA73123C5059B006F3E93 /* ListPageTemplateModel.swift in Sources */, 017BEB4023620A230024EF95 /* TextFieldModel.swift in Sources */, D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */, @@ -1840,6 +2016,8 @@ AA11A42123F15D7000D7962F /* ListRightVariablePaymentsModel.swift in Sources */, 01EB369223609801006832FA /* MoleculeStackModel.swift in Sources */, 012CA99E2385A2D3003F810F /* MFView+ModelExtension.swift in Sources */, + 011D9626240EBB16000E3791 /* RadioButtonLabelModel.swift in Sources */, + AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */, D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */, 944589232385DA9600DE9FD4 /* ImageViewModel.swift in Sources */, D213347723843825008E41B3 /* Line.swift in Sources */, @@ -1856,6 +2034,9 @@ DBEFFA04225A829700230692 /* Label.swift in Sources */, D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */, 0A7EF85F23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift in Sources */, + 011D959B240451E3000E3791 /* RuleRequiredModel.swift in Sources */, + 526A265C240D1FF700B0D828 /* ListTwoColumnCompareChangesModel.swift in Sources */, + D2A92886241ACD99004E01C6 /* ProgrammaticTableViewController.swift in Sources */, 01509D952327ED1900EF99AA /* HeadlineBodyLinkToggle.swift in Sources */, 31BE15CB23D8924D00452370 /* CheckboxLabelModel.swift in Sources */, D260105523CEA7DC00764D80 /* MVMCoreUISwitch+Model.swift in Sources */, @@ -1867,12 +2048,14 @@ 0A1B4A96233BB18F005B3FB4 /* CheckboxLabel.swift in Sources */, 0A21DB8B235E06EF00C160A2 /* MFDigitTextBox.m in Sources */, D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */, + BB47A586241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift in Sources */, D2B18B812360945C00A9AEDC /* View.swift in Sources */, C6FA7D5423C77A4A00A3614A /* NumberedList.swift in Sources */, D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */, 525019E52406852100EED91C /* ListFourColumnDataUsageDividerModel.swift in Sources */, 0A7EF86723D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift in Sources */, 94FB966323D797DA003D482B /* MFTextButton.m in Sources */, + D29C94D5242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift in Sources */, D260105323CEA61600764D80 /* ToggleModel.swift in Sources */, 014AA72523C501E2006F3E93 /* ContainerModel.swift in Sources */, 0A7EF86523D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift in Sources */, @@ -1886,7 +2069,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 */, @@ -1902,6 +2084,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 */, @@ -1915,24 +2098,29 @@ 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 */, + 526A265E240D200500B0D828 /* ListTwoColumnCompareChanges.swift in Sources */, 8D24041523E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift in Sources */, D28A838F23CCDEDE00DFE4FC /* TwoButtonViewModel.swift in Sources */, D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */, 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 */, 0A14F6B423E8C29700EDF7F7 /* NumericIndicatorView.swift in Sources */, D29DF2C721E7BF57003B2FB9 /* MFTabBarInteractor.m in Sources */, C7F8012123E8303200396FBD /* ListRVWheel.swift in Sources */, - D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */, + D29DF29521E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.m in Sources */, D2FB151B23A2B65B00C20E10 /* MoleculeContainer.swift in Sources */, + BB6C6AC0242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift in Sources */, D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */, D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */, + AAA74A172410C04600080241 /* HeadersH2NoButtonsBodyText.swift in Sources */, 522679C223FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinksModel.swift in Sources */, 8D084AD02410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift in Sources */, 0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */, @@ -1940,26 +2128,27 @@ D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */, 525019E72406853600EED91C /* ListFourColumnDataUsageDivider.swift in Sources */, 0AE98BB323FF0934004C5109 /* ExternalLinkModel.swift in Sources */, + D20FB165241A5D75004AFC3A /* NavigationItemModelProtocol.swift in Sources */, DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */, 0A21DB89235E06EF00C160A2 /* MFMdnTextField.m in Sources */, D224798A2314445E003FCCF9 /* LabelToggle.swift in Sources */, + D2A92882241AAB67004E01C6 /* ScrollingViewController.swift in Sources */, 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 */, + 94C0150A24215643005811A9 /* ActionTopAlertModel.swift in Sources */, 012A88DB238ED45900FE3DA1 /* CarouselModel.swift in Sources */, D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */, 0AE14F64238315D2005417F8 /* TextField.swift in Sources */, D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */, + D2C78CD224228BBD00B69FDE /* ActionOpenPanelModel.swift 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 */, + 8D070BB2241B56AD0099AC56 /* ListRightVariableTotalData.swift in Sources */, D29DF11D21E684A9003B2FB9 /* MVMCoreUISplitViewController.m in Sources */, - 0A7918F523F5E7EA00772FF4 /* ImageView.swift in Sources */, - 0198F79F225679880066C936 /* FormValidationProtocol.swift in Sources */, D243859923A16B1800332775 /* Container.swift in Sources */, D2C521A923EDE79E00CA2634 /* ViewController.swift in Sources */, D260105B23D0BB7100764D80 /* StackModelProtocol.swift in Sources */, @@ -1977,15 +2166,19 @@ 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 /* FormHolderModelProtocol.swift in Sources */, 948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */, 013F801923FB4A8E00AD8013 /* UIContentMode+Extension.swift in Sources */, + 525239C22407BD1000454969 /* ListTwoColumnPriceDetails.swift in Sources */, D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */, D2E2A9A323E096B1000B42E6 /* DisableableModelProtocol.swift in Sources */, D29DF11821E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m in Sources */, @@ -1994,6 +2187,7 @@ D29DF26C21E6AA0B003B2FB9 /* FLAnimatedImage.m in Sources */, D28A839123CD4FD400DFE4FC /* CornerLabelsModel.swift in Sources */, 012A88F123985E0100FE3DA1 /* Color.swift in Sources */, + D22D8393241C27B100D3DF69 /* TemplateModel.swift in Sources */, 012A889C23889E8400FE3DA1 /* TemplateModelProtocol.swift in Sources */, D29770FC21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m in Sources */, 52267A0723FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift in Sources */, @@ -2002,18 +2196,21 @@ DBC4391B224421A0001AB423 /* CaretLink.swift in Sources */, 0198F7A82256A80B0066C936 /* MFRadioButton.m in Sources */, 0A6BF4722360C56C0028F841 /* BaseDropdownEntryField.swift in Sources */, + BB6C6AC824225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift in Sources */, 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */, 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 */, + D236E5B5241FEB1000C38625 /* ListTwoColumnPriceDescriptionModel.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 */, + BB6C6AC924225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift in Sources */, C695A69423C9909000BFB94E /* DoughnutChartModel.swift in Sources */, D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */, D29E28DD23D7404C00ACEA85 /* ContainerHelper.swift in Sources */, @@ -2021,6 +2218,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 */, @@ -2031,6 +2229,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 */, diff --git a/MVMCoreUI.xcodeproj/project.pbxproj.orig b/MVMCoreUI.xcodeproj/project.pbxproj.orig index 030eda91..69ba4c43 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj.orig +++ b/MVMCoreUI.xcodeproj/project.pbxproj.orig @@ -10,11 +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 /* RadioButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0116A4E4228B19640094F3ED /* RadioButtonModel.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 /* FormHolderModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011D95882404249B000E3791 /* FormHolderModelProtocol.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 */; }; @@ -25,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 */; }; @@ -42,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 */; }; @@ -85,6 +96,7 @@ 0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */; }; 0A4253AF23F5C2C100554656 /* BarsIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A4253AE23F5C2C000554656 /* BarsIndicatorView.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 */; }; 0A7918F523F5E7EA00772FF4 /* ImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7918F423F5E7EA00772FF4 /* ImageView.swift */; }; 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; }; @@ -96,9 +108,9 @@ 0A7EF86323D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86223D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift */; }; 0A7EF86523D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */; }; 0A7EF86723D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */; }; - 0A9F3DE823EDE9F200318918 /* Arrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9F3DE723EDE9F200318918 /* Arrow.swift */; }; - 0A9F3DEA23EDEA1A00318918 /* ArrowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9F3DE923EDEA1A00318918 /* ArrowModel.swift */; }; 0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B392398524F0067DD0F /* Toggle.swift */; }; + 0AAF8E2A240EA57D008DD263 /* BarsCarouselIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AAF8E29240EA57D008DD263 /* BarsCarouselIndicatorModel.swift */; }; + 0AAF8E2C240EA594008DD263 /* NumericCarouselIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AAF8E2B240EA594008DD263 /* NumericCarouselIndicatorModel.swift */; }; 0ABD136D237CAD1E0081388D /* DateDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */; }; 0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */; }; 0AE14F64238315D2005417F8 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE14F63238315D2005417F8 /* TextField.swift */; }; @@ -113,9 +125,27 @@ 52267A0723FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52267A0623FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift */; }; 5248BFEC23F12E350059236A /* ListThreeColumnPlanDataDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5248BFEA23F12E350059236A /* ListThreeColumnPlanDataDivider.swift */; }; 5248BFED23F12E350059236A /* ListThreeColumnPlanDataDividerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5248BFEB23F12E350059236A /* ListThreeColumnPlanDataDividerModel.swift */; }; + 525019DD2406430800EED91C /* ListProgressBarDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525019DB2406430700EED91C /* ListProgressBarDataModel.swift */; }; + 525019DE2406430800EED91C /* ListProgressBarData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525019DC2406430800EED91C /* ListProgressBarData.swift */; }; + 525019E52406852100EED91C /* ListFourColumnDataUsageDividerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525019E42406852100EED91C /* ListFourColumnDataUsageDividerModel.swift */; }; + 525019E72406853600EED91C /* ListFourColumnDataUsageDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525019E62406853600EED91C /* ListFourColumnDataUsageDivider.swift */; }; + 525239C02407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525239BF2407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift */; }; + 525239C22407BD1000454969 /* ListTwoColumnPriceDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525239C12407BD1000454969 /* ListTwoColumnPriceDetails.swift */; }; + 526A265C240D1FF700B0D828 /* ListTwoColumnCompareChangesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 526A265B240D1FF700B0D828 /* ListTwoColumnCompareChangesModel.swift */; }; + 526A265E240D200500B0D828 /* ListTwoColumnCompareChanges.swift in Sources */ = {isa = PBXBuildFile; fileRef = 526A265D240D200500B0D828 /* ListTwoColumnCompareChanges.swift */; }; + 52B201D224081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B201D024081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift */; }; + 52B201D324081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B201D124081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift */; }; + 8D070BB0241B56530099AC56 /* ListRightVariableTotalDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D070BAF241B56530099AC56 /* ListRightVariableTotalDataModel.swift */; }; + 8D070BB2241B56AD0099AC56 /* ListRightVariableTotalData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */; }; + 8D084AD02410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */; }; + 8D084AD22410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D084AD12410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift */; }; 8D24041123E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D24041023E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift */; }; 8D24041523E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D24041423E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift */; }; 8D448E5524050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D448E5424050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift */; }; + 942C372E241149170066E45E /* NHaasGroteskDSStd-75Bd.otf in Resources */ = {isa = PBXBuildFile; fileRef = 942C372C241149170066E45E /* NHaasGroteskDSStd-75Bd.otf */; }; + 942C372F241149170066E45E /* NHaasGroteskDSStd-55Rg.otf in Resources */ = {isa = PBXBuildFile; fileRef = 942C372D241149170066E45E /* NHaasGroteskDSStd-55Rg.otf */; }; + 942C378C2412F4FA0066E45E /* ModalMoleculeListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 942C378B2412F4FA0066E45E /* ModalMoleculeListTemplate.swift */; }; + 942C378E2412F5B60066E45E /* ModalMoleculeStackTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 942C378D2412F5B60066E45E /* ModalMoleculeStackTemplate.swift */; }; 9432A79F23DB47BA00719041 /* EntryFieldContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9432A79E23DB47BA00719041 /* EntryFieldContainer.swift */; }; 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F3236B77BB006A1E82 /* GraphView.swift */; }; 943784F6236B77BB006A1E82 /* GraphViewAnimationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */; }; @@ -127,12 +157,13 @@ 9455B19C234F8A0400A574DB /* MVMAnimationFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9455B19B234F8A0400A574DB /* MVMAnimationFramework.framework */; }; 9458C3172406C8FD00930963 /* UIFont+FontWrapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 9458C3152406C8FD00930963 /* UIFont+FontWrapping.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9458C3182406C8FD00930963 /* UIFont+FontWrapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 9458C3162406C8FD00930963 /* UIFont+FontWrapping.m */; }; - 946EE1BA237B66D80036751F /* MoleculeModelHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 946EE1B9237B66D80036751F /* MoleculeModelHelper.swift */; }; 948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948DB67D2326DCD90011F916 /* MultiProgress.swift */; }; 94AF4A3E23E9D13900676048 /* MFCaretButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 94AF4A3C23E9D13900676048 /* MFCaretButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; 94AF4A3F23E9D13900676048 /* MFCaretButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 94AF4A3D23E9D13900676048 /* MFCaretButton.m */; }; 94AF4A4223E9D19E00676048 /* MFCaretView.h in Headers */ = {isa = PBXBuildFile; fileRef = 94AF4A4023E9D19E00676048 /* MFCaretView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 94AF4A4323E9D19E00676048 /* MFCaretView.m in Sources */ = {isa = PBXBuildFile; fileRef = 94AF4A4123E9D19E00676048 /* MFCaretView.m */; }; + 94C0150A24215643005811A9 /* ActionTopAlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C0150924215643005811A9 /* ActionTopAlertModel.swift */; }; + 94C0150C2421564A005811A9 /* ActionCollapseNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C0150B2421564A005811A9 /* ActionCollapseNotificationModel.swift */; }; 94C2D9842386F3F80006CF46 /* LabelAttributeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9832386F3F80006CF46 /* LabelAttributeModel.swift */; }; 94C2D9A123872BCC0006CF46 /* LabelAttributeUnderlineModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9A023872BCC0006CF46 /* LabelAttributeUnderlineModel.swift */; }; 94C2D9A323872C110006CF46 /* LabelAttributeStrikeThroughModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9A223872C110006CF46 /* LabelAttributeStrikeThroughModel.swift */; }; @@ -152,6 +183,14 @@ 94FB966323D797DA003D482B /* MFTextButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 94FB966123D797DA003D482B /* MFTextButton.m */; }; AA11A41F23F15D3100D7962F /* ListRightVariablePayments.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11A41E23F15D3100D7962F /* ListRightVariablePayments.swift */; }; AA11A42123F15D7000D7962F /* ListRightVariablePaymentsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA11A42023F15D7000D7962F /* ListRightVariablePaymentsModel.swift */; }; + AAA74A172410C04600080241 /* HeadersH2NoButtonsBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */; }; + AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */; }; + BB47A586241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB47A585241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift */; }; + BB47A588241615FA002BB23C /* ListOneColumnFullWidthTextDividerSubsection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB47A587241615FA002BB23C /* ListOneColumnFullWidthTextDividerSubsection.swift */; }; + BB6C6AC0242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6C6ABE242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift */; }; + BB6C6AC1242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6C6ABF242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift */; }; + BB6C6AC824225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6C6AC62422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift */; }; + BB6C6AC924225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6C6AC72422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift */; }; C003506123AA94CD00B6AC29 /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = C003506023AA94CD00B6AC29 /* Button.swift */; }; C07065C42395677300FBF997 /* Link.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07065C32395677300FBF997 /* Link.swift */; }; C695A67F23C9830600BFB94E /* UnOrderedListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C695A67E23C9830600BFB94E /* UnOrderedListModel.swift */; }; @@ -166,6 +205,7 @@ C7F8012123E8303200396FBD /* ListRVWheel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F8012023E8303200396FBD /* ListRVWheel.swift */; }; C7F8012323E846C300396FBD /* ListRVWheelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F8012223E846C300396FBD /* ListRVWheelModel.swift */; }; D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; }; + D20FB165241A5D75004AFC3A /* NavigationItemModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20FB164241A5D75004AFC3A /* NavigationItemModelProtocol.swift */; }; D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; }; D21EE53C23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */; }; D224798A2314445E003FCCF9 /* LabelToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479892314445E003FCCF9 /* LabelToggle.swift */; }; @@ -181,7 +221,13 @@ D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */; }; D22D1F562204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D22D1F542204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D22D1F572204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D22D1F552204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m */; }; + D22D8393241C27B100D3DF69 /* TemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22D8392241C27B100D3DF69 /* TemplateModel.swift */; }; + D22D8395241FB41200D3DF69 /* UIStackView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22D8394241FB41200D3DF69 /* UIStackView+Extension.swift */; }; + D236E5B4241FEB1000C38625 /* ListTwoColumnPriceDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = D236E5B2241FEB1000C38625 /* ListTwoColumnPriceDescription.swift */; }; + D236E5B5241FEB1000C38625 /* ListTwoColumnPriceDescriptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D236E5B3241FEB1000C38625 /* ListTwoColumnPriceDescriptionModel.swift */; }; + D236E5B7242007C500C38625 /* MVMControllerModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D236E5B6242007C500C38625 /* MVMControllerModelProtocol.swift */; }; D243859923A16B1800332775 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = D243859823A16B1800332775 /* Container.swift */; }; + D256E9932412880000360572 /* Header.swift in Sources */ = {isa = PBXBuildFile; fileRef = D256E9922412880000360572 /* Header.swift */; }; D260105323CEA61600764D80 /* ToggleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D260105223CEA61600764D80 /* ToggleModel.swift */; }; D260105523CEA7DC00764D80 /* MVMCoreUISwitch+Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = D260105423CEA7DC00764D80 /* MVMCoreUISwitch+Model.swift */; }; D260105923D0A92900764D80 /* ContainerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D260105823D0A92900764D80 /* ContainerProtocol.swift */; }; @@ -228,6 +274,7 @@ D29770FC21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770FA21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m */; }; D29770FD21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29770FB21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */; }; + D29C94D5242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29C94D4242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift */; }; D29DF0D121E404D4003B2FB9 /* MVMCoreUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */; }; D29DF11521E6805F003B2FB9 /* UIColor+MFConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF11121E6805F003B2FB9 /* UIColor+MFConvenience.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -272,11 +319,11 @@ D29DF28421E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF28221E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF28B21E7AC2B003B2FB9 /* ViewConstrainingView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF28721E7AC2B003B2FB9 /* ViewConstrainingView.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF28821E7AC2B003B2FB9 /* ViewConstrainingView.m */; }; - D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF28D21E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m */; }; + D29DF29521E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF28D21E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.m */; }; D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF28E21E7ADB8003B2FB9 /* StackableViewController.m */; }; D29DF29721E7ADB8003B2FB9 /* MFScrollingViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF28F21E7ADB8003B2FB9 /* MFScrollingViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF29821E7ADB8003B2FB9 /* MFScrollingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF29021E7ADB8003B2FB9 /* MFScrollingViewController.m */; }; - D29DF29921E7ADB8003B2FB9 /* ProgrammaticScrollViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF29121E7ADB8003B2FB9 /* ProgrammaticScrollViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D29DF29921E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF29121E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF29A21E7ADB8003B2FB9 /* MFProgrammaticTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF29221E7ADB8003B2FB9 /* MFProgrammaticTableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF29B21E7ADB9003B2FB9 /* StackableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF29321E7ADB8003B2FB9 /* StackableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29DF29421E7ADB8003B2FB9 /* MFProgrammaticTableViewController.m */; }; @@ -329,6 +376,9 @@ D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A638FC22CA98280052ED1F /* HeadlineBody.swift */; }; D2A6390122CBB1820052ED1F /* Carousel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A6390022CBB1820052ED1F /* Carousel.swift */; }; D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */; }; + D2A92882241AAB67004E01C6 /* ScrollingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A92881241AAB67004E01C6 /* ScrollingViewController.swift */; }; + D2A92884241ACB25004E01C6 /* ProgrammaticScrollViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A92883241ACB25004E01C6 /* ProgrammaticScrollViewController.swift */; }; + D2A92886241ACD99004E01C6 /* ProgrammaticTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A92885241ACD99004E01C6 /* ProgrammaticTableViewController.swift */; }; D2B18B7F2360913400A9AEDC /* Control.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B7E2360913400A9AEDC /* Control.swift */; }; D2B18B812360945C00A9AEDC /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B802360945C00A9AEDC /* View.swift */; }; D2B18B922361E65A00A9AEDC /* CoreUIObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B912361E65A00A9AEDC /* CoreUIObject.swift */; }; @@ -337,6 +387,7 @@ D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */; }; D2C521A923EDE79E00CA2634 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C521A823EDE79E00CA2634 /* ViewController.swift */; }; + D2C78CD224228BBD00B69FDE /* ActionOpenPanelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C78CD124228BBD00B69FDE /* ActionOpenPanelModel.swift */; }; D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */; }; D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */; }; D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D90B41240463E100DD6EC9 /* MoleculeHeaderModel.swift */; }; @@ -368,11 +419,25 @@ 01004F2F22721C3800991ECC /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = ""; }; 0103B84D23D7E33A009C315C /* HeadlineBodyToggleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyToggleModel.swift; sourceTree = ""; }; 0105618A224BBE7700E1557D /* FormValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormValidator.swift; sourceTree = ""; }; - 0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+TextFields.swift"; sourceTree = ""; }; - 0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+FormParams.swift"; sourceTree = ""; }; - 0116A4E4228B19640094F3ED /* RadioButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonModel.swift; sourceTree = ""; }; + 0116A4E4228B19640094F3ED /* RadioButtonSelectionHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonSelectionHelper.swift; sourceTree = ""; }; 011B58EF23A2AA980085F53C /* ListItemModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemModelProtocol.swift; sourceTree = ""; }; 011B58F123A2AE2C0085F53C /* DropDownListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropDownListItemModel.swift; sourceTree = ""; }; + 011D958424042432000E3791 /* RulesProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RulesProtocol.swift; sourceTree = ""; }; + 011D958624042492000E3791 /* FormFieldProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormFieldProtocol.swift; sourceTree = ""; }; + 011D95882404249B000E3791 /* FormHolderModelProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormHolderModelProtocol.swift; sourceTree = ""; }; + 011D959A240451E3000E3791 /* RuleRequiredModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleRequiredModel.swift; sourceTree = ""; }; + 011D959C2404536F000E3791 /* RuleAnyValueChangedModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyValueChangedModel.swift; sourceTree = ""; }; + 011D959E240453A1000E3791 /* RuleAllValueChangedModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAllValueChangedModel.swift; sourceTree = ""; }; + 011D95A0240453D0000E3791 /* RuleEqualsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleEqualsModel.swift; sourceTree = ""; }; + 011D95A2240453F8000E3791 /* RuleRegexModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleRegexModel.swift; sourceTree = ""; }; + 011D95A4240455DC000E3791 /* FormGroupRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormGroupRule.swift; sourceTree = ""; }; + 011D95A824057AC7000E3791 /* FormActionFieldProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormActionFieldProtocol.swift; sourceTree = ""; }; + 011D95AA2405C553000E3791 /* FormItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormItemProtocol.swift; sourceTree = ""; }; + 011D95AC2406BB57000E3791 /* FormHolderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormHolderProtocol.swift; sourceTree = ""; }; + 011D95AE2407266E000E3791 /* RadioButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonModel.swift; sourceTree = ""; }; + 011D9601240DA20A000E3791 /* ValidProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidProtocol.swift; sourceTree = ""; }; + 011D9625240EBB16000E3791 /* RadioButtonLabelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioButtonLabelModel.swift; sourceTree = ""; }; + 011D9627240EFA1E000E3791 /* MFViewController+Form.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFViewController+Form.swift"; sourceTree = ""; }; 012A889B23889E8400FE3DA1 /* TemplateModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateModelProtocol.swift; sourceTree = ""; }; 012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateProtocol.swift; sourceTree = ""; }; 012A88AE238C626E00FE3DA1 /* CarouselModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselModel.swift; sourceTree = ""; }; @@ -383,7 +448,6 @@ 012A88C7238DB02000FE3DA1 /* ModelMoleculeDelegateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelMoleculeDelegateProtocol.swift; sourceTree = ""; }; 012A88EB238F084D00FE3DA1 /* FooterModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FooterModel.swift; sourceTree = ""; }; 012A88F023985E0100FE3DA1 /* Color.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; - 012CA9992384A687003F810F /* MFTextField+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFTextField+ModelExtension.swift"; sourceTree = ""; }; 012CA99D2385A2D3003F810F /* MFView+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFView+ModelExtension.swift"; sourceTree = ""; }; 013F801823FB4A8E00AD8013 /* UIContentMode+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIContentMode+Extension.swift"; sourceTree = ""; }; 014AA72123C501E2006F3E93 /* MoleculeContainerModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeContainerModel.swift; sourceTree = ""; }; @@ -400,13 +464,11 @@ 017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioButtonLabel.swift; sourceTree = ""; }; 017BEB3B2361EA1D0024EF95 /* MFViewController+Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFViewController+Model.swift"; sourceTree = ""; }; 017BEB3F23620A230024EF95 /* TextFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldModel.swift; sourceTree = ""; }; - 017BEB4123620AD20024EF95 /* FormModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormModelProtocol.swift; sourceTree = ""; }; 017BEB432362192F0024EF95 /* MVMCoreUIMoleculeMappingObject+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUIMoleculeMappingObject+ModelExtension.swift"; sourceTree = ""; }; 017BEB47236230DB0024EF95 /* MoleculeViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeViewProtocol.swift; sourceTree = ""; }; 017BEB49236235BA0024EF95 /* ModelMoleculeViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelMoleculeViewProtocol.swift; sourceTree = ""; }; 017BEB7A236763000024EF95 /* LineModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineModel.swift; sourceTree = ""; }; 017BEB7E23676E870024EF95 /* MoleculeObjectMapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeObjectMapping.swift; sourceTree = ""; }; - 0198F79E225679870066C936 /* FormValidationProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormValidationProtocol.swift; sourceTree = ""; }; 0198F7A02256A80A0066C936 /* MFRadioButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFRadioButton.h; sourceTree = ""; }; 0198F7A22256A80A0066C936 /* MFRadioButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFRadioButton.m; sourceTree = ""; }; 01C851D223CF9E740021F976 /* LabelToggleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelToggleModel.swift; sourceTree = ""; }; @@ -431,6 +493,7 @@ 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = ""; }; 0A4253AE23F5C2C000554656 /* BarsIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarsIndicatorView.swift; sourceTree = ""; }; 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesProtocol.swift; sourceTree = ""; }; + 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyRequiredModel.swift; sourceTree = ""; }; 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseDropdownEntryField.swift; sourceTree = ""; }; 0A7918F423F5E7EA00772FF4 /* ImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageView.swift; sourceTree = ""; }; 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = ""; }; @@ -444,10 +507,10 @@ 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryFieldModel.swift; sourceTree = ""; }; 0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryFieldModel.swift; sourceTree = ""; }; 0A8321AE2355FE9500CB7F00 /* DigitBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitBox.swift; sourceTree = ""; }; - 0A9F3DE723EDE9F200318918 /* Arrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arrow.swift; sourceTree = ""; }; - 0A9F3DE923EDEA1A00318918 /* ArrowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowModel.swift; sourceTree = ""; }; 0AA33B33239813C50067DD0F /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = ""; }; 0AA33B392398524F0067DD0F /* Toggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toggle.swift; sourceTree = ""; }; + 0AAF8E29240EA57D008DD263 /* BarsCarouselIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarsCarouselIndicatorModel.swift; sourceTree = ""; }; + 0AAF8E2B240EA594008DD263 /* NumericCarouselIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumericCarouselIndicatorModel.swift; sourceTree = ""; }; 0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryField.swift; sourceTree = ""; }; 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryField.swift; sourceTree = ""; }; 0AE14F63238315D2005417F8 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = ""; }; @@ -462,10 +525,28 @@ 52267A0623FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextAllTextAndLinks.swift; sourceTree = ""; }; 5248BFEA23F12E350059236A /* ListThreeColumnPlanDataDivider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListThreeColumnPlanDataDivider.swift; sourceTree = ""; }; 5248BFEB23F12E350059236A /* ListThreeColumnPlanDataDividerModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListThreeColumnPlanDataDividerModel.swift; sourceTree = ""; }; + 525019DB2406430700EED91C /* ListProgressBarDataModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListProgressBarDataModel.swift; sourceTree = ""; }; + 525019DC2406430800EED91C /* ListProgressBarData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListProgressBarData.swift; sourceTree = ""; }; + 525019E42406852100EED91C /* ListFourColumnDataUsageDividerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListFourColumnDataUsageDividerModel.swift; sourceTree = ""; }; + 525019E62406853600EED91C /* ListFourColumnDataUsageDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListFourColumnDataUsageDivider.swift; sourceTree = ""; }; + 525239BF2407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnPriceDetailsModel.swift; sourceTree = ""; }; + 525239C12407BD1000454969 /* ListTwoColumnPriceDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnPriceDetails.swift; sourceTree = ""; }; + 526A265B240D1FF700B0D828 /* ListTwoColumnCompareChangesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnCompareChangesModel.swift; sourceTree = ""; }; + 526A265D240D200500B0D828 /* ListTwoColumnCompareChanges.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnCompareChanges.swift; sourceTree = ""; }; + 52B201D024081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonAndPaymentMethod.swift; sourceTree = ""; }; + 52B201D124081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonAndPaymentMethodModel.swift; sourceTree = ""; }; + 8D070BAF241B56530099AC56 /* ListRightVariableTotalDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableTotalDataModel.swift; sourceTree = ""; }; + 8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableTotalData.swift; sourceTree = ""; }; + 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextBodyTextModel.swift; sourceTree = ""; }; + 8D084AD12410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextBodyText.swift; sourceTree = ""; }; 8D24041023E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconWithRightCaret.swift; sourceTree = ""; }; 8D24041423E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconWithRightCaretModel.swift; sourceTree = ""; }; 8D448E5424050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextAllTextAndLinksModel.swift; sourceTree = ""; }; 9402C34F23A2CEA3004B974C /* LeftRightLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeftRightLabelModel.swift; sourceTree = ""; }; + 942C372C241149170066E45E /* NHaasGroteskDSStd-75Bd.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NHaasGroteskDSStd-75Bd.otf"; sourceTree = ""; }; + 942C372D241149170066E45E /* NHaasGroteskDSStd-55Rg.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NHaasGroteskDSStd-55Rg.otf"; sourceTree = ""; }; + 942C378B2412F4FA0066E45E /* ModalMoleculeListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalMoleculeListTemplate.swift; sourceTree = ""; }; + 942C378D2412F5B60066E45E /* ModalMoleculeStackTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalMoleculeStackTemplate.swift; sourceTree = ""; }; 9432A79E23DB47BA00719041 /* EntryFieldContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntryFieldContainer.swift; sourceTree = ""; }; 943784F3236B77BB006A1E82 /* GraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphView.swift; sourceTree = ""; }; 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphViewAnimationHandler.swift; sourceTree = ""; }; @@ -477,12 +558,13 @@ 9455B19B234F8A0400A574DB /* MVMAnimationFramework.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MVMAnimationFramework.framework; path = ../SharedFrameworks/MVMAnimationFramework.framework; sourceTree = ""; }; 9458C3152406C8FD00930963 /* UIFont+FontWrapping.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIFont+FontWrapping.h"; sourceTree = ""; }; 9458C3162406C8FD00930963 /* UIFont+FontWrapping.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIFont+FontWrapping.m"; sourceTree = ""; }; - 946EE1B9237B66D80036751F /* MoleculeModelHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeModelHelper.swift; sourceTree = ""; }; 948DB67D2326DCD90011F916 /* MultiProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiProgress.swift; sourceTree = ""; }; 94AF4A3C23E9D13900676048 /* MFCaretButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MFCaretButton.h; sourceTree = ""; }; 94AF4A3D23E9D13900676048 /* MFCaretButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MFCaretButton.m; sourceTree = ""; }; 94AF4A4023E9D19E00676048 /* MFCaretView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MFCaretView.h; sourceTree = ""; }; 94AF4A4123E9D19E00676048 /* MFCaretView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MFCaretView.m; sourceTree = ""; }; + 94C0150924215643005811A9 /* ActionTopAlertModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionTopAlertModel.swift; sourceTree = ""; }; + 94C0150B2421564A005811A9 /* ActionCollapseNotificationModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionCollapseNotificationModel.swift; sourceTree = ""; }; 94C2D9832386F3F80006CF46 /* LabelAttributeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeModel.swift; sourceTree = ""; }; 94C2D9A023872BCC0006CF46 /* LabelAttributeUnderlineModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeUnderlineModel.swift; sourceTree = ""; }; 94C2D9A223872C110006CF46 /* LabelAttributeStrikeThroughModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeStrikeThroughModel.swift; sourceTree = ""; }; @@ -500,6 +582,14 @@ 94FB966123D797DA003D482B /* MFTextButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFTextButton.m; sourceTree = ""; }; AA11A41E23F15D3100D7962F /* ListRightVariablePayments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariablePayments.swift; sourceTree = ""; }; AA11A42023F15D7000D7962F /* ListRightVariablePaymentsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariablePaymentsModel.swift; sourceTree = ""; }; + AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyText.swift; sourceTree = ""; }; + AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyTextModel.swift; sourceTree = ""; }; + BB47A585241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextDividerSubsectionModel.swift; sourceTree = ""; }; + BB47A587241615FA002BB23C /* ListOneColumnFullWidthTextDividerSubsection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextDividerSubsection.swift; sourceTree = ""; }; + BB6C6ABE242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ListOneColumnTextWithWhitespaceDividerTallModel.swift; path = MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnTextWithWhitespaceDividerTallModel.swift; sourceTree = SOURCE_ROOT; }; + BB6C6ABF242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ListOneColumnTextWithWhitespaceDividerTall.swift; path = MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift; sourceTree = SOURCE_ROOT; }; + BB6C6AC62422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListOneColumnTextWithWhitespaceDividerShort.swift; sourceTree = ""; }; + BB6C6AC72422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListOneColumnTextWithWhitespaceDividerShortModel.swift; sourceTree = ""; }; C003506023AA94CD00B6AC29 /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; C07065C32395677300FBF997 /* Link.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Link.swift; sourceTree = ""; }; C695A67E23C9830600BFB94E /* UnOrderedListModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnOrderedListModel.swift; sourceTree = ""; }; @@ -514,6 +604,7 @@ C7F8012023E8303200396FBD /* ListRVWheel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListRVWheel.swift; sourceTree = ""; }; C7F8012223E846C300396FBD /* ListRVWheelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRVWheelModel.swift; sourceTree = ""; }; D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = ""; }; + D20FB164241A5D75004AFC3A /* NavigationItemModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItemModelProtocol.swift; sourceTree = ""; }; D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSLayoutConstraintAxis+Extension.swift"; sourceTree = ""; }; D22479892314445E003FCCF9 /* LabelToggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelToggle.swift; sourceTree = ""; }; @@ -529,7 +620,13 @@ D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUISwitch.m; sourceTree = ""; }; D22D1F542204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIStackableViewController.h; sourceTree = ""; }; D22D1F552204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIStackableViewController.m; sourceTree = ""; }; + D22D8392241C27B100D3DF69 /* TemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateModel.swift; sourceTree = ""; }; + D22D8394241FB41200D3DF69 /* UIStackView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIStackView+Extension.swift"; sourceTree = ""; }; + D236E5B2241FEB1000C38625 /* ListTwoColumnPriceDescription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListTwoColumnPriceDescription.swift; sourceTree = ""; }; + D236E5B3241FEB1000C38625 /* ListTwoColumnPriceDescriptionModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListTwoColumnPriceDescriptionModel.swift; sourceTree = ""; }; + D236E5B6242007C500C38625 /* MVMControllerModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMControllerModelProtocol.swift; sourceTree = ""; }; D243859823A16B1800332775 /* Container.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Container.swift; sourceTree = ""; }; + D256E9922412880000360572 /* Header.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Header.swift; sourceTree = ""; }; D260105223CEA61600764D80 /* ToggleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleModel.swift; sourceTree = ""; }; D260105423CEA7DC00764D80 /* MVMCoreUISwitch+Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUISwitch+Model.swift"; sourceTree = ""; }; D260105823D0A92900764D80 /* ContainerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerProtocol.swift; sourceTree = ""; }; @@ -575,6 +672,7 @@ D29770FA21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUITextFieldView.m; sourceTree = ""; }; D29770FB21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUITextFieldView.h; sourceTree = ""; }; D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModuleMolecule.swift; sourceTree = ""; }; + D29C94D4242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUICommonViewsUtility+Extension.swift"; sourceTree = ""; }; D29DF0CC21E404D4003B2FB9 /* MVMCoreUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MVMCoreUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUI.h; sourceTree = ""; }; D29DF0D021E404D4003B2FB9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -640,11 +738,11 @@ D29DF28221E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUICommonViewsUtility.h; sourceTree = ""; }; D29DF28721E7AC2B003B2FB9 /* ViewConstrainingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewConstrainingView.h; sourceTree = ""; }; D29DF28821E7AC2B003B2FB9 /* ViewConstrainingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewConstrainingView.m; sourceTree = ""; }; - D29DF28D21E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProgrammaticScrollViewController.m; sourceTree = ""; }; + D29DF28D21E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFProgrammaticScrollViewController.m; sourceTree = ""; }; D29DF28E21E7ADB8003B2FB9 /* StackableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StackableViewController.m; sourceTree = ""; }; D29DF28F21E7ADB8003B2FB9 /* MFScrollingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFScrollingViewController.h; sourceTree = ""; }; D29DF29021E7ADB8003B2FB9 /* MFScrollingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFScrollingViewController.m; sourceTree = ""; }; - D29DF29121E7ADB8003B2FB9 /* ProgrammaticScrollViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProgrammaticScrollViewController.h; sourceTree = ""; }; + D29DF29121E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFProgrammaticScrollViewController.h; sourceTree = ""; }; D29DF29221E7ADB8003B2FB9 /* MFProgrammaticTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFProgrammaticTableViewController.h; sourceTree = ""; }; D29DF29321E7ADB8003B2FB9 /* StackableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackableViewController.h; sourceTree = ""; }; D29DF29421E7ADB8003B2FB9 /* MFProgrammaticTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFProgrammaticTableViewController.m; sourceTree = ""; }; @@ -691,6 +789,9 @@ D2A638FC22CA98280052ED1F /* HeadlineBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBody.swift; sourceTree = ""; }; D2A6390022CBB1820052ED1F /* Carousel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Carousel.swift; sourceTree = ""; }; D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeCollectionViewCell.swift; sourceTree = ""; }; + D2A92881241AAB67004E01C6 /* ScrollingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollingViewController.swift; sourceTree = ""; }; + D2A92883241ACB25004E01C6 /* ProgrammaticScrollViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgrammaticScrollViewController.swift; sourceTree = ""; }; + D2A92885241ACD99004E01C6 /* ProgrammaticTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgrammaticTableViewController.swift; sourceTree = ""; }; D2B18B7E2360913400A9AEDC /* Control.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Control.swift; sourceTree = ""; }; D2B18B802360945C00A9AEDC /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; D2B18B912361E65A00A9AEDC /* CoreUIObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreUIObject.swift; sourceTree = ""; }; @@ -699,6 +800,7 @@ D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewControllerMappingObject.h; sourceTree = ""; }; D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = ""; }; D2C521A823EDE79E00CA2634 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + D2C78CD124228BBD00B69FDE /* ActionOpenPanelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionOpenPanelModel.swift; sourceTree = ""; }; D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scroller.swift; sourceTree = ""; }; D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTemplate.swift; sourceTree = ""; }; D2D90B41240463E100DD6EC9 /* MoleculeHeaderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeHeaderModel.swift; sourceTree = ""; }; @@ -742,7 +844,6 @@ isa = PBXGroup; children = ( 014AA72323C501E2006F3E93 /* ContainerModelProtocol.swift */, - 017BEB4123620AD20024EF95 /* FormModelProtocol.swift */, 012A88C3238D86E600FE3DA1 /* CarouselItemModelProtocol.swift */, 012A88B0238C880100FE3DA1 /* CarouselPagingModelProtocol.swift */, 01EB3683236097C0006832FA /* MoleculeModelProtocol.swift */, @@ -754,6 +855,22 @@ path = ModelProtocols; sourceTree = ""; }; + 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 = ""; + }; 012A88EF23985E0100FE3DA1 /* CustomPrimitives */ = { isa = PBXGroup; children = ( @@ -766,7 +883,6 @@ isa = PBXGroup; children = ( 011B58EE23A2AA850085F53C /* ModelProtocols */, - 946EE1B5237B663A0036751F /* Extensions */, ); path = Models; sourceTree = ""; @@ -774,10 +890,14 @@ 01C74D87224298E2009C25A3 /* FormUIHelpers */ = { isa = PBXGroup; children = ( - 0198F79E225679870066C936 /* FormValidationProtocol.swift */, + 011D95882404249B000E3791 /* FormHolderModelProtocol.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 = ""; @@ -785,20 +905,14 @@ 0A14F6B023E8C27A00EDF7F7 /* CarouselIndicator */ = { isa = PBXGroup; children = ( - 0A14F6B723ECA7F900EDF7F7 /* IndicatorViews */, - 0A14F69223E349EF00EDF7F7 /* CarouselIndicator.swift */, 0A14F6A823E8750300EDF7F7 /* CarouselIndicatorModel.swift */, - ); - path = CarouselIndicator; - sourceTree = ""; - }; - 0A14F6B723ECA7F900EDF7F7 /* IndicatorViews */ = { - isa = PBXGroup; - children = ( + 0A14F69223E349EF00EDF7F7 /* CarouselIndicator.swift */, + 0AAF8E29240EA57D008DD263 /* BarsCarouselIndicatorModel.swift */, 0A4253AE23F5C2C000554656 /* BarsIndicatorView.swift */, + 0AAF8E2B240EA594008DD263 /* NumericCarouselIndicatorModel.swift */, 0A14F6B323E8C29700EDF7F7 /* NumericIndicatorView.swift */, ); - path = IndicatorViews; + path = CarouselIndicator; sourceTree = ""; }; 0A5D59C323AD488600EFD9E9 /* Protocols */ = { @@ -832,21 +946,72 @@ path = Link; sourceTree = ""; }; + 5206F150241144A900658DC5 /* Headers */ = { + isa = PBXGroup; + children = ( + AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */, + AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */, + ); + path = Headers; + sourceTree = ""; + }; 52267A0523FFE0A900906CBA /* OneColumn */ = { isa = PBXGroup; children = ( 8D448E5424050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift */, 52267A0623FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift */, + 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */, + 8D084AD12410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift */, ); path = OneColumn; sourceTree = ""; }; - 946EE1B5237B663A0036751F /* Extensions */ = { + 525019E3240684E500EED91C /* FourColumn */ = { isa = PBXGroup; children = ( - 946EE1B9237B66D80036751F /* MoleculeModelHelper.swift */, + 525019E42406852100EED91C /* ListFourColumnDataUsageDividerModel.swift */, + 525019E62406853600EED91C /* ListFourColumnDataUsageDivider.swift */, ); - path = Extensions; + path = FourColumn; + sourceTree = ""; + }; + 525239C32407FFCC00454969 /* LockUps */ = { + isa = PBXGroup; + children = ( + 525019DB2406430700EED91C /* ListProgressBarDataModel.swift */, + 525019DC2406430800EED91C /* ListProgressBarData.swift */, + ); + path = LockUps; + sourceTree = ""; + }; + 525665CB24211FD5007BF25F /* OneColumn */ = { + isa = PBXGroup; + children = ( + BB6C6AC72422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift */, + BB6C6AC62422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift */, + BB6C6ABE242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift */, + BB6C6ABF242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift */, + BB47A585241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift */, + BB47A587241615FA002BB23C /* ListOneColumnFullWidthTextDividerSubsection.swift */, + ); + path = OneColumn; + sourceTree = ""; + }; + 526A265A240D1FCE00B0D828 /* TwoColumn */ = { + isa = PBXGroup; + children = ( + ); + path = TwoColumn; + sourceTree = ""; + }; + 94C01508242155FE005811A9 /* Actions */ = { + isa = PBXGroup; + children = ( + 94C0150924215643005811A9 /* ActionTopAlertModel.swift */, + 94C0150B2421564A005811A9 /* ActionCollapseNotificationModel.swift */, + D2C78CD124228BBD00B69FDE /* ActionOpenPanelModel.swift */, + ); + path = Actions; sourceTree = ""; }; 94C2D9822386F3E30006CF46 /* Label */ = { @@ -865,18 +1030,13 @@ path = Label; sourceTree = ""; }; - 94FB5B83238D892800EB2193 /* Recovered References */ = { - isa = PBXGroup; - children = ( - ); - name = "Recovered References"; - sourceTree = ""; - }; AA4FC2A323F4F69600E251DB /* RightVariable */ = { isa = PBXGroup; children = ( AA11A42023F15D7000D7962F /* ListRightVariablePaymentsModel.swift */, AA11A41E23F15D3100D7962F /* ListRightVariablePayments.swift */, + 8D070BAF241B56530099AC56 /* ListRightVariableTotalDataModel.swift */, + 8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */, C7F8012223E846C300396FBD /* ListRVWheelModel.swift */, C7F8012023E8303200396FBD /* ListRVWheel.swift */, ); @@ -886,8 +1046,20 @@ D213347423842FE3008E41B3 /* Controllers */ = { isa = PBXGroup; children = ( + D29DF16021E69996003B2FB9 /* MFViewController.h */, + D29DF15F21E69996003B2FB9 /* MFViewController.m */, + 017BEB3B2361EA1D0024EF95 /* MFViewController+Model.swift */, + 011D9627240EFA1E000E3791 /* MFViewController+Form.swift */, + D29DF28F21E7ADB8003B2FB9 /* MFScrollingViewController.h */, + D29DF29021E7ADB8003B2FB9 /* MFScrollingViewController.m */, + D29DF29121E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.h */, + D29DF28D21E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.m */, D29DF29321E7ADB8003B2FB9 /* StackableViewController.h */, D29DF28E21E7ADB8003B2FB9 /* StackableViewController.m */, + D29DF29221E7ADB8003B2FB9 /* MFProgrammaticTableViewController.h */, + D29DF29421E7ADB8003B2FB9 /* MFProgrammaticTableViewController.m */, + D22D1F542204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h */, + D22D1F552204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m */, D29770F021F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.h */, D29770F121F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m */, D29770EF21F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.h */, @@ -1055,6 +1227,8 @@ D22B38E923F4E07800490EF6 /* DesignedComponents */ = { isa = PBXGroup; children = ( + 5206F150241144A900658DC5 /* Headers */, + 525239C32407FFCC00454969 /* LockUps */, D22B38EC23F4E10700490EF6 /* SectionDividers */, D22B38EA23F4E08B00490EF6 /* List */, ); @@ -1064,6 +1238,7 @@ D22B38EA23F4E08B00490EF6 /* List */ = { isa = PBXGroup; children = ( + D22D8396241FDE4700D3DF69 /* TwoColumn */, 52267A0523FFE0A900906CBA /* OneColumn */, AA4FC2A323F4F69600E251DB /* RightVariable */, D22B38EB23F4E0AE00490EF6 /* LeftVariable */, @@ -1074,6 +1249,8 @@ D22B38EB23F4E0AE00490EF6 /* LeftVariable */ = { isa = PBXGroup; children = ( + 52B201D124081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift */, + 52B201D024081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift */, 522679C023FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinksModel.swift */, 522679BF23FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift */, 8D24041423E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift */, @@ -1085,6 +1262,9 @@ D22B38EC23F4E10700490EF6 /* SectionDividers */ = { isa = PBXGroup; children = ( + 525665CB24211FD5007BF25F /* OneColumn */, + 526A265A240D1FCE00B0D828 /* TwoColumn */, + 525019E3240684E500EED91C /* FourColumn */, D22B38ED23F4E11100490EF6 /* ThreeColumn */, ); path = SectionDividers; @@ -1108,6 +1288,19 @@ path = Legacy; sourceTree = ""; }; + D22D8396241FDE4700D3DF69 /* TwoColumn */ = { + isa = PBXGroup; + children = ( + D236E5B3241FEB1000C38625 /* ListTwoColumnPriceDescriptionModel.swift */, + D236E5B2241FEB1000C38625 /* ListTwoColumnPriceDescription.swift */, + 526A265B240D1FF700B0D828 /* ListTwoColumnCompareChangesModel.swift */, + 526A265D240D200500B0D828 /* ListTwoColumnCompareChanges.swift */, + 525239BF2407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift */, + 525239C12407BD1000454969 /* ListTwoColumnPriceDetails.swift */, + ); + path = TwoColumn; + sourceTree = ""; + }; D260105723CF9CC500764D80 /* Doughnut */ = { isa = PBXGroup; children = ( @@ -1124,7 +1317,6 @@ D29DF0CE21E404D4003B2FB9 /* MVMCoreUI */, D29DF0CD21E404D4003B2FB9 /* Products */, D29DF0E421E4F3C7003B2FB9 /* Frameworks */, - 94FB5B83238D892800EB2193 /* Recovered References */, ); sourceTree = ""; }; @@ -1152,6 +1344,7 @@ D22D1F582204D2590077CEC0 /* Legacy */, D29DF10F21E67A7D003B2FB9 /* BaseControllers */, D29DF11E21E6851E003B2FB9 /* TopAlert */, + 94C01508242155FE005811A9 /* Actions */, D29DF10D21E67A70003B2FB9 /* Atoms */, D29DF10E21E67A77003B2FB9 /* Molecules */, D22479902316A9CB003FCCF9 /* Organisms */, @@ -1166,13 +1359,16 @@ isa = PBXGroup; children = ( 012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */, + D22D8392241C27B100D3DF69 /* TemplateModel.swift */, 014AA72823C5059B006F3E93 /* StackPageTemplateModel.swift */, D2A5146022121FBF00345BFB /* MoleculeStackTemplate.swift */, + 942C378D2412F5B60066E45E /* ModalMoleculeStackTemplate.swift */, 014AA72923C5059B006F3E93 /* StackCenteredPageTemplateModel.swift */, D2A514622213643100345BFB /* MoleculeStackCenteredTemplate.swift */, D28A837A23C928DA00DFE4FC /* MoleculeListCellProtocol.swift */, 014AA72C23C5059B006F3E93 /* ListPageTemplateModel.swift */, D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */, + 942C378B2412F4FA0066E45E /* ModalMoleculeListTemplate.swift */, 014AA72A23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift */, D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */, ); @@ -1207,19 +1403,22 @@ D224798E2316A995003FCCF9 /* HorizontalCombinationViews */, D224798D2316A988003FCCF9 /* VerticalCombinationViews */, 01EB368C23609801006832FA /* HeaderModel.swift */, + D256E9922412880000360572 /* Header.swift */, D2D90B41240463E100DD6EC9 /* MoleculeHeaderModel.swift */, D2A514662213885800345BFB /* MoleculeHeaderView.swift */, 012A88EB238F084D00FE3DA1 /* FooterModel.swift */, D274CA322236A78900B01B62 /* FooterView.swift */, - 0116A4E4228B19640094F3ED /* RadioButtonModel.swift */, + 0116A4E4228B19640094F3ED /* RadioButtonSelectionHelper.swift */, 012A88C5238DA34000FE3DA1 /* ModuleMoleculeModel.swift */, D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */, D28A838423CCCA8900DFE4FC /* ScrollerModel.swift */, D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */, + 011D9625240EBB16000E3791 /* RadioButtonLabelModel.swift */, 017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */, 017BEB47236230DB0024EF95 /* MoleculeViewProtocol.swift */, 017BEB49236235BA0024EF95 /* ModelMoleculeViewProtocol.swift */, D260105723CF9CC500764D80 /* Doughnut */, + D20FB164241A5D75004AFC3A /* NavigationItemModelProtocol.swift */, ); path = Molecules; sourceTree = ""; @@ -1227,22 +1426,15 @@ D29DF10F21E67A7D003B2FB9 /* BaseControllers */ = { isa = PBXGroup; children = ( - D29DF16021E69996003B2FB9 /* MFViewController.h */, - D29DF15F21E69996003B2FB9 /* MFViewController.m */, - 017BEB3B2361EA1D0024EF95 /* MFViewController+Model.swift */, - D29DF28F21E7ADB8003B2FB9 /* MFScrollingViewController.h */, - D29DF29021E7ADB8003B2FB9 /* MFScrollingViewController.m */, - D29DF29121E7ADB8003B2FB9 /* ProgrammaticScrollViewController.h */, - D29DF28D21E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m */, - D29DF29221E7ADB8003B2FB9 /* MFProgrammaticTableViewController.h */, - D29DF29421E7ADB8003B2FB9 /* MFProgrammaticTableViewController.m */, - D22D1F542204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h */, - D22D1F552204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m */, + D236E5B6242007C500C38625 /* MVMControllerModelProtocol.swift */, D29DF2CC21E7C104003B2FB9 /* MFLoadingViewController.h */, D29DF2CD21E7C104003B2FB9 /* MFLoadingViewController.m */, D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */, D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */, D2C521A823EDE79E00CA2634 /* ViewController.swift */, + D2A92881241AAB67004E01C6 /* ScrollingViewController.swift */, + D2A92883241ACB25004E01C6 /* ProgrammaticScrollViewController.swift */, + D2A92885241ACD99004E01C6 /* ProgrammaticTableViewController.swift */, ); path = BaseControllers; sourceTree = ""; @@ -1257,6 +1449,7 @@ D29DF11421E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m */, D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */, 0AA33B33239813C50067DD0F /* UIColor+Extension.swift */, + D22D8394241FB41200D3DF69 /* UIStackView+Extension.swift */, ); path = Categories; sourceTree = ""; @@ -1304,6 +1497,7 @@ D29DF13B21E6870B003B2FB9 /* Sizing */, D29DF28221E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.h */, D29DF28121E7AB23003B2FB9 /* MVMCoreUICommonViewsUtility.m */, + D29C94D4242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift */, D29DF14D21E693AD003B2FB9 /* MFFonts.h */, D29DF14C21E693AD003B2FB9 /* MFFonts.m */, 9458C3152406C8FD00930963 /* UIFont+FontWrapping.h */, @@ -1369,6 +1563,7 @@ 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */, 31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */, 0A7BAFA2232BE63400FB8E22 /* CheckboxLabel.swift */, + 011D95AE2407266E000E3791 /* RadioButtonModel.swift */, 01004F2F22721C3800991ECC /* RadioButton.swift */, D28A838223CCBD3F00DFE4FC /* CircleProgressModel.swift */, 943784F3236B77BB006A1E82 /* GraphView.swift */, @@ -1377,13 +1572,8 @@ 0AA33B392398524F0067DD0F /* Toggle.swift */, D260105423CEA7DC00764D80 /* MVMCoreUISwitch+Model.swift */, 012CA99D2385A2D3003F810F /* MFView+ModelExtension.swift */, -<<<<<<< HEAD - 0A9F3DE723EDE9F200318918 /* Arrow.swift */, - 0A9F3DE923EDEA1A00318918 /* ArrowModel.swift */, -======= 0AE98BB623FF18E9004C5109 /* ArrowModel.swift */, 0AE98BB423FF18D2004C5109 /* Arrow.swift */, ->>>>>>> develop ); path = Views; sourceTree = ""; @@ -1407,7 +1597,6 @@ 0A7EF86423D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift */, 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */, 017BEB3F23620A230024EF95 /* TextFieldModel.swift */, - 012CA9992384A687003F810F /* MFTextField+ModelExtension.swift */, ); path = TextFields; sourceTree = ""; @@ -1497,6 +1686,8 @@ 94CA227924058533002D6750 /* VerizonNHGeDS-Regular.otf */, 94CA227824058533002D6750 /* VerizonNHGeTX-Bold.otf */, 94CA227B24058533002D6750 /* VerizonNHGeTX-Regular.otf */, + 942C372D241149170066E45E /* NHaasGroteskDSStd-55Rg.otf */, + 942C372C241149170066E45E /* NHaasGroteskDSStd-75Bd.otf */, D29DF31721ECECC0003B2FB9 /* OCRAExtended.ttf */, ); path = Fonts; @@ -1574,7 +1765,7 @@ D29DF2A921E7B2F9003B2FB9 /* MVMCoreUIConstants.h in Headers */, 0198F7A62256A80B0066C936 /* MFRadioButton.h in Headers */, D22D1F1A220341F60077CEC0 /* MVMCoreUICheckBox.h in Headers */, - D29DF29921E7ADB8003B2FB9 /* ProgrammaticScrollViewController.h in Headers */, + D29DF29921E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.h in Headers */, D29DF11C21E684A9003B2FB9 /* MVMCoreUISplitViewController.h in Headers */, D29DF29B21E7ADB9003B2FB9 /* StackableViewController.h in Headers */, D29770F421F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.h in Headers */, @@ -1708,6 +1899,8 @@ 0A21DB86235E06EF00C160A2 /* MFTextField.xib in Resources */, 94CA227D24058534002D6750 /* VerizonNHGeDS-Regular.otf in Resources */, D29DF32E21EE8C3D003B2FB9 /* Media.xcassets in Resources */, + 942C372E241149170066E45E /* NHaasGroteskDSStd-75Bd.otf in Resources */, + 942C372F241149170066E45E /* NHaasGroteskDSStd-55Rg.otf in Resources */, 94CA227E24058534002D6750 /* VerizonNHGeDS-Bold.otf in Resources */, D29DF31B21ECECC0003B2FB9 /* OCRAExtended.ttf in Resources */, ); @@ -1722,6 +1915,7 @@ files = ( 5248BFED23F12E350059236A /* ListThreeColumnPlanDataDividerModel.swift in Sources */, 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */, + 8D070BB0241B56530099AC56 /* ListRightVariableTotalDataModel.swift in Sources */, 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */, 31BE15CC23D8924D00452370 /* CheckboxModel.swift in Sources */, 94C661DA23CCF4FB00D9FE5B /* UIColor+Extension.swift in Sources */, @@ -1729,6 +1923,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 */, @@ -1738,7 +1933,7 @@ D2FB151D23A40F1500C20E10 /* MoleculeStackItem.swift in Sources */, AA11A41F23F15D3100D7962F /* ListRightVariablePayments.swift in Sources */, D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */, - 0116A4E5228B19640094F3ED /* RadioButtonModel.swift in Sources */, + 0116A4E5228B19640094F3ED /* RadioButtonSelectionHelper.swift in Sources */, 017BEB48236230DB0024EF95 /* MoleculeViewProtocol.swift in Sources */, D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */, D27CD40E2322EEAF00C1DC07 /* TabsTableViewCell.swift in Sources */, @@ -1748,11 +1943,16 @@ 01004F3022721C3800991ECC /* RadioButton.swift in Sources */, D268C70E238C22D7007F2C1C /* DropDownFilterTableViewCell.swift in Sources */, 017BEB3C2361EA1D0024EF95 /* MFViewController+Model.swift in Sources */, + D236E5B7242007C500C38625 /* MVMControllerModelProtocol.swift in Sources */, D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */, D29DF11721E6805F003B2FB9 /* UIColor+MFConvenience.m in Sources */, D2B18B7F2360913400A9AEDC /* Control.swift in Sources */, + 011D95A924057AC7000E3791 /* FormActionFieldProtocol.swift in Sources */, + D236E5B4241FEB1000C38625 /* ListTwoColumnPriceDescription.swift in Sources */, 0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */, D29DF12F21E6851E003B2FB9 /* MVMCoreUITopAlertMainView.m in Sources */, + 942C378C2412F4FA0066E45E /* ModalMoleculeListTemplate.swift in Sources */, + BB47A588241615FA002BB23C /* ListOneColumnFullWidthTextDividerSubsection.swift in Sources */, 012A88C8238DB02000FE3DA1 /* ModelMoleculeDelegateProtocol.swift in Sources */, 0A7EF86123D8AC2500B2AAD1 /* DigitEntryFieldModel.swift in Sources */, DBC4392122491730001AB423 /* LabelWithInternalButton.swift in Sources */, @@ -1764,13 +1964,17 @@ 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 */, + BB6C6AC1242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.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 */, 01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */, + D2A92884241ACB25004E01C6 /* ProgrammaticScrollViewController.swift in Sources */, 0A21DB7F235DECC500C160A2 /* EntryField.swift in Sources */, D2E2A99F23E07F8A000B42E6 /* PillButton.swift in Sources */, 0A4253AF23F5C2C100554656 /* BarsIndicatorView.swift in Sources */, @@ -1793,7 +1997,12 @@ 012A88C4238D86E600FE3DA1 /* CarouselItemModelProtocol.swift in Sources */, D2E2A9A123E095AB000B42E6 /* ButtonModelProtocol.swift in Sources */, 94C2D9AB23872EB50006CF46 /* LabelAttributeActionModel.swift in Sources */, + D22D8395241FB41200D3DF69 /* UIStackView+Extension.swift in Sources */, + 52B201D324081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift in Sources */, + 525239C02407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift in Sources */, D2E2A99A23D8D6B4000B42E6 /* HeadlineBodyButtonModel.swift in Sources */, + 8D084AD22410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift in Sources */, + 94C0150C2421564A005811A9 /* ActionCollapseNotificationModel.swift in Sources */, 014AA73123C5059B006F3E93 /* ListPageTemplateModel.swift in Sources */, 017BEB4023620A230024EF95 /* TextFieldModel.swift in Sources */, D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */, @@ -1802,15 +2011,19 @@ 0103B84E23D7E33A009C315C /* HeadlineBodyToggleModel.swift in Sources */, D2755D7B23689C7500485468 /* TableViewCell.swift in Sources */, 0A21DB85235E06EF00C160A2 /* MFTextField.m in Sources */, + 0AAF8E2C240EA594008DD263 /* NumericCarouselIndicatorModel.swift in Sources */, 014AA72623C501E2006F3E93 /* ContainerModelProtocol.swift in Sources */, AA11A42123F15D7000D7962F /* ListRightVariablePaymentsModel.swift in Sources */, 01EB369223609801006832FA /* MoleculeStackModel.swift in Sources */, 012CA99E2385A2D3003F810F /* MFView+ModelExtension.swift in Sources */, + 011D9626240EBB16000E3791 /* RadioButtonLabelModel.swift in Sources */, + AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */, D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */, 944589232385DA9600DE9FD4 /* ImageViewModel.swift in Sources */, D213347723843825008E41B3 /* Line.swift in Sources */, D28A837723C79FC600DFE4FC /* MFCustomButton+ActionModel.swift in Sources */, D2E2A99C23D8D975000B42E6 /* ImageHeadlineBodyModel.swift in Sources */, + 525019DE2406430800EED91C /* ListProgressBarData.swift in Sources */, D28A837F23CCA96400DFE4FC /* TabsModel.swift in Sources */, 012A88EC238F084D00FE3DA1 /* FooterModel.swift in Sources */, D2A514672213885800345BFB /* MoleculeHeaderView.swift in Sources */, @@ -1821,6 +2034,9 @@ DBEFFA04225A829700230692 /* Label.swift in Sources */, D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */, 0A7EF85F23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift in Sources */, + 011D959B240451E3000E3791 /* RuleRequiredModel.swift in Sources */, + 526A265C240D1FF700B0D828 /* ListTwoColumnCompareChangesModel.swift in Sources */, + D2A92886241ACD99004E01C6 /* ProgrammaticTableViewController.swift in Sources */, 01509D952327ED1900EF99AA /* HeadlineBodyLinkToggle.swift in Sources */, 31BE15CB23D8924D00452370 /* CheckboxLabelModel.swift in Sources */, D260105523CEA7DC00764D80 /* MVMCoreUISwitch+Model.swift in Sources */, @@ -1832,11 +2048,14 @@ 0A1B4A96233BB18F005B3FB4 /* CheckboxLabel.swift in Sources */, 0A21DB8B235E06EF00C160A2 /* MFDigitTextBox.m in Sources */, D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */, + BB47A586241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift in Sources */, D2B18B812360945C00A9AEDC /* View.swift in Sources */, C6FA7D5423C77A4A00A3614A /* NumberedList.swift in Sources */, D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */, + 525019E52406852100EED91C /* ListFourColumnDataUsageDividerModel.swift in Sources */, 0A7EF86723D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift in Sources */, 94FB966323D797DA003D482B /* MFTextButton.m in Sources */, + D29C94D5242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift in Sources */, D260105323CEA61600764D80 /* ToggleModel.swift in Sources */, 014AA72523C501E2006F3E93 /* ContainerModel.swift in Sources */, 0A7EF86523D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift in Sources */, @@ -1845,12 +2064,11 @@ D2B18B94236214AD00A9AEDC /* NavigationController.swift in Sources */, D29E28DA23D21AFA00ACEA85 /* StringAndMoleculeModel.swift in Sources */, D282AACB2243C61700C46919 /* ButtonView.swift in Sources */, - 0A9F3DE823EDE9F200318918 /* Arrow.swift in Sources */, D260105D23D0BCD400764D80 /* Stack.swift in Sources */, 0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */, D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */, 01EB368F23609801006832FA /* LabelModel.swift in Sources */, - 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */, + 942C378E2412F5B60066E45E /* ModalMoleculeStackTemplate.swift in Sources */, 01F2A03223A4498200D954D8 /* CaretLinkModel.swift in Sources */, 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */, 011B58F023A2AA980085F53C /* ListItemModelProtocol.swift in Sources */, @@ -1864,7 +2082,10 @@ D29DF18321E69E54003B2FB9 /* SeparatorView.m in Sources */, D29DF17A21E69E1F003B2FB9 /* MFCustomButton.m in Sources */, 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 */, D29DF2BF21E7BEA4003B2FB9 /* MVMCoreUITabBarPageControlViewController.m in Sources */, @@ -1877,49 +2098,62 @@ 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 */, + 526A265E240D200500B0D828 /* ListTwoColumnCompareChanges.swift in Sources */, 8D24041523E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift in Sources */, D28A838F23CCDEDE00DFE4FC /* TwoButtonViewModel.swift in Sources */, D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */, 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 */, 0A14F6B423E8C29700EDF7F7 /* NumericIndicatorView.swift in Sources */, D29DF2C721E7BF57003B2FB9 /* MFTabBarInteractor.m in Sources */, C7F8012123E8303200396FBD /* ListRVWheel.swift in Sources */, - D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */, + D29DF29521E7ADB8003B2FB9 /* MFProgrammaticScrollViewController.m in Sources */, D2FB151B23A2B65B00C20E10 /* MoleculeContainer.swift in Sources */, + BB6C6AC0242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift in Sources */, D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */, D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */, + AAA74A172410C04600080241 /* HeadersH2NoButtonsBodyText.swift in Sources */, 522679C223FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinksModel.swift in Sources */, + 8D084AD02410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift in Sources */, 0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */, 8D24041123E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift in Sources */, D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */, + 525019E72406853600EED91C /* ListFourColumnDataUsageDivider.swift in Sources */, 0AE98BB323FF0934004C5109 /* ExternalLinkModel.swift in Sources */, + D20FB165241A5D75004AFC3A /* NavigationItemModelProtocol.swift in Sources */, DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */, 0A21DB89235E06EF00C160A2 /* MFMdnTextField.m in Sources */, D224798A2314445E003FCCF9 /* LabelToggle.swift in Sources */, + D2A92882241AAB67004E01C6 /* ScrollingViewController.swift in Sources */, 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 */, + 94C0150A24215643005811A9 /* ActionTopAlertModel.swift in Sources */, 012A88DB238ED45900FE3DA1 /* CarouselModel.swift in Sources */, D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */, 0AE14F64238315D2005417F8 /* TextField.swift in Sources */, D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */, + D2C78CD224228BBD00B69FDE /* ActionOpenPanelModel.swift 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 */, + 8D070BB2241B56AD0099AC56 /* ListRightVariableTotalData.swift in Sources */, D29DF11D21E684A9003B2FB9 /* MVMCoreUISplitViewController.m in Sources */, +<<<<<<< HEAD 0A7918F523F5E7EA00772FF4 /* ImageView.swift in Sources */, 0198F79F225679880066C936 /* FormValidationProtocol.swift in Sources */, +======= +>>>>>>> develop D243859923A16B1800332775 /* Container.swift in Sources */, D2C521A923EDE79E00CA2634 /* ViewController.swift in Sources */, D260105B23D0BB7100764D80 /* StackModelProtocol.swift in Sources */, @@ -1937,15 +2171,19 @@ 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 /* FormHolderModelProtocol.swift in Sources */, 948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */, - 0A9F3DEA23EDEA1A00318918 /* ArrowModel.swift in Sources */, 013F801923FB4A8E00AD8013 /* UIContentMode+Extension.swift in Sources */, + 525239C22407BD1000454969 /* ListTwoColumnPriceDetails.swift in Sources */, D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */, D2E2A9A323E096B1000B42E6 /* DisableableModelProtocol.swift in Sources */, D29DF11821E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m in Sources */, @@ -1954,6 +2192,7 @@ D29DF26C21E6AA0B003B2FB9 /* FLAnimatedImage.m in Sources */, D28A839123CD4FD400DFE4FC /* CornerLabelsModel.swift in Sources */, 012A88F123985E0100FE3DA1 /* Color.swift in Sources */, + D22D8393241C27B100D3DF69 /* TemplateModel.swift in Sources */, 012A889C23889E8400FE3DA1 /* TemplateModelProtocol.swift in Sources */, D29770FC21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m in Sources */, 52267A0723FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift in Sources */, @@ -1962,18 +2201,21 @@ DBC4391B224421A0001AB423 /* CaretLink.swift in Sources */, 0198F7A82256A80B0066C936 /* MFRadioButton.m in Sources */, 0A6BF4722360C56C0028F841 /* BaseDropdownEntryField.swift in Sources */, + BB6C6AC824225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift in Sources */, 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */, 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 */, + D236E5B5241FEB1000C38625 /* ListTwoColumnPriceDescriptionModel.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 */, + BB6C6AC924225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift in Sources */, C695A69423C9909000BFB94E /* DoughnutChartModel.swift in Sources */, D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */, D29E28DD23D7404C00ACEA85 /* ContainerHelper.swift in Sources */, @@ -1981,15 +2223,19 @@ 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 */, 01509D8F2327EC6F00EF99AA /* MoleculeTableViewCell.swift in Sources */, 0105618D224BBE7700E1557D /* FormValidator.swift in Sources */, + 0AAF8E2A240EA57D008DD263 /* BarsCarouselIndicatorModel.swift in Sources */, 01509D912327ECE600EF99AA /* CornerLabels.swift in Sources */, D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */, C695A69823C990C200BFB94E /* DoughnutChartView.swift in Sources */, D29DF2CB21E7BFCC003B2FB9 /* MFSizeThreshold.m in Sources */, - 946EE1BA237B66D80036751F /* MoleculeModelHelper.swift 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 */, diff --git a/MVMCoreUI/Actions/ActionCollapseNotificationModel.swift b/MVMCoreUI/Actions/ActionCollapseNotificationModel.swift new file mode 100644 index 00000000..9a6e6793 --- /dev/null +++ b/MVMCoreUI/Actions/ActionCollapseNotificationModel.swift @@ -0,0 +1,17 @@ +// +// ActionCollapseNotificationModel.swift +// MVMCore +// +// Created by Ryan on 3/17/20. +// Copyright © 2020 myverizon. All rights reserved. +// + +import UIKit + +@objcMembers public class ActionCollapseNotificationModel: ActionModelProtocol { + public static var identifier: String = "collapseNotification" + public var actionType: String + public var extraParameters: JSONValueDictionary? + public var analyticsData: JSONValueDictionary? + public var title: String? +} diff --git a/MVMCoreUI/Actions/ActionOpenPanelModel.swift b/MVMCoreUI/Actions/ActionOpenPanelModel.swift new file mode 100644 index 00000000..55fd272a --- /dev/null +++ b/MVMCoreUI/Actions/ActionOpenPanelModel.swift @@ -0,0 +1,31 @@ +// +// ActionOpenPanelModel.swift +// MVMCore +// +// Created by Khan, Arshad on 12/02/20. +// Copyright © 2020 myverizon. All rights reserved. +// + +import Foundation + +public class ActionOpenPanelModel: ActionModelProtocol { + + public enum Panel: String, Codable { + case left + case right + case support // Legacy, means left + case menu // Legacy, means right. + } + + public static var identifier: String = "openPanel" + public var actionType: String = ActionOpenPanelModel.identifier + public var panel: Panel + public var extraParameters: JSONValueDictionary? + public var analyticsData: JSONValueDictionary? + // Temporary fix till server changes + public var title: String? + + public init(panel: Panel) { + self.panel = panel + } +} diff --git a/MVMCoreUI/Actions/ActionTopAlertModel.swift b/MVMCoreUI/Actions/ActionTopAlertModel.swift new file mode 100644 index 00000000..628633c2 --- /dev/null +++ b/MVMCoreUI/Actions/ActionTopAlertModel.swift @@ -0,0 +1,23 @@ +// +// ActionTopAlertModel.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 12/16/19. +// Copyright © 2019 myverizon. All rights reserved. +// + +import Foundation + +@objcMembers public class ActionTopAlertModel: ActionModelProtocol { + public static var identifier: String = "topAlert" + public var actionType: String = ActionTopAlertModel.identifier + public var pageType: String + public var extraParameters: JSONValueDictionary? + public var analyticsData: JSONValueDictionary? + // Temporary fix till server changes + public var title: String? + + public init(pageType: String) { + self.pageType = pageType + } +} diff --git a/MVMCoreUI/Atoms/Buttons/ButtonModel.swift b/MVMCoreUI/Atoms/Buttons/ButtonModel.swift index db24d474..ac9d1dc1 100644 --- a/MVMCoreUI/Atoms/Buttons/ButtonModel.swift +++ b/MVMCoreUI/Atoms/Buttons/ButtonModel.swift @@ -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) } } diff --git a/MVMCoreUI/Atoms/Buttons/PillButton.swift b/MVMCoreUI/Atoms/Buttons/PillButton.swift index d7fa8db5..c760c0b7 100644 --- a/MVMCoreUI/Atoms/Buttons/PillButton.swift +++ b/MVMCoreUI/Atoms/Buttons/PillButton.swift @@ -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 } } diff --git a/MVMCoreUI/Atoms/Buttons/PrimaryButton+MoleculeProtocolExtension.swift b/MVMCoreUI/Atoms/Buttons/PrimaryButton+MoleculeProtocolExtension.swift index 0e2368b8..6cf0df21 100644 --- a/MVMCoreUI/Atoms/Buttons/PrimaryButton+MoleculeProtocolExtension.swift +++ b/MVMCoreUI/Atoms/Buttons/PrimaryButton+MoleculeProtocolExtension.swift @@ -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: diff --git a/MVMCoreUI/Atoms/TextFields/DigitEntryField.swift b/MVMCoreUI/Atoms/TextFields/DigitEntryField.swift index 53181bff..004651d4 100644 --- a/MVMCoreUI/Atoms/TextFields/DigitEntryField.swift +++ b/MVMCoreUI/Atoms/TextFields/DigitEntryField.swift @@ -207,7 +207,7 @@ import UIKit let digitBox = DigitBox() digitBox.isAccessibilityElement = true - MVMCoreUICommonViewsUtility.addDismissToolbar(digitBox.digitField, delegate: self) + digitBox.digitField.inputAccessoryView = MVMCoreUICommonViewsUtility.getToolbarWithDoneButton(delegate: self) digitBox.digitField.delegate = self digitBox.digitBoxDelegate = self return digitBox @@ -329,16 +329,14 @@ import UIKit } public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { - - + guard let model = model as? DigitEntryFieldModel else { return } numberOfDigits = model.digits - setAsSecureTextEntry(model.secureEntry) for digitBox in digitBoxes { - MVMCoreUICommonViewsUtility.addDismissToolbar(digitBox.digitField, delegate: delegateObject as? UITextFieldDelegate) + digitBox.digitField.inputAccessoryView = MVMCoreUICommonViewsUtility.getToolbarWithDoneButton(delegate: delegateObject?.observingTextFieldDelegate ?? self) } super.set(with: model, delegateObject, additionalData) diff --git a/MVMCoreUI/Atoms/TextFields/EntryField.swift b/MVMCoreUI/Atoms/TextFields/EntryField.swift index bbea1c62..48214210 100644 --- a/MVMCoreUI/Atoms/TextFields/EntryField.swift +++ b/MVMCoreUI/Atoms/TextFields/EntryField.swift @@ -48,8 +48,6 @@ import UIKit //-------------------------------------------------- public var isValid: Bool = false - public var fieldKey: String? - public var errorMessage: String? public var standardMessage: String? { didSet { @@ -118,8 +116,7 @@ import UIKit set (newFeedback) { feedbackLabel.text = newFeedback feedbackLabel.accessibilityElementsHidden = feedbackLabel.text?.isEmpty ?? true - entryFieldContainer.refreshUI() - delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self) + entryFieldContainer.refreshUI(updateMoleculeLayout: true) } } @@ -259,10 +256,6 @@ import UIKit } else if let isSelected = model.isSelected{ self.isSelected = isSelected } - - if let fieldKey = model.fieldKey { - self.fieldKey = fieldKey - } } } @@ -300,11 +293,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 +300,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 { diff --git a/MVMCoreUI/Atoms/TextFields/EntryFieldModel.swift b/MVMCoreUI/Atoms/TextFields/EntryFieldModel.swift index e4a794bc..54b441f7 100644 --- a/MVMCoreUI/Atoms/TextFields/EntryFieldModel.swift +++ b/MVMCoreUI/Atoms/TextFields/EntryFieldModel.swift @@ -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) } } diff --git a/MVMCoreUI/Atoms/TextFields/MFTextField+ModelExtension.swift b/MVMCoreUI/Atoms/TextFields/MFTextField+ModelExtension.swift deleted file mode 100644 index e57cec9c..00000000 --- a/MVMCoreUI/Atoms/TextFields/MFTextField+ModelExtension.swift +++ /dev/null @@ -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() - } - } -} - diff --git a/MVMCoreUI/Atoms/TextFields/MdnEntryField.swift b/MVMCoreUI/Atoms/TextFields/MdnEntryField.swift index a0a893a6..92a1e073 100644 --- a/MVMCoreUI/Atoms/TextFields/MdnEntryField.swift +++ b/MVMCoreUI/Atoms/TextFields/MdnEntryField.swift @@ -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) } } diff --git a/MVMCoreUI/Atoms/TextFields/TextEntryField.swift b/MVMCoreUI/Atoms/TextFields/TextEntryField.swift index 61f6c82c..c97412a8 100644 --- a/MVMCoreUI/Atoms/TextFields/TextEntryField.swift +++ b/MVMCoreUI/Atoms/TextFields/TextEntryField.swift @@ -19,7 +19,7 @@ import UIKit } -@objcMembers open class TextEntryField: EntryField, UITextFieldDelegate { +@objcMembers open class TextEntryField: EntryField, UITextFieldDelegate, ObservingTextFieldDelegate { //-------------------------------------------------- // MARK: - Outlets //-------------------------------------------------- @@ -44,12 +44,16 @@ 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 + public var textEntryFieldModel: TextEntryFieldModel? { + return model as? TextEntryFieldModel + } + //-------------------------------------------------- // MARK: - Computed Properties //-------------------------------------------------- @@ -87,7 +91,7 @@ import UIKit get { return textField.text } set { textField.text = newValue - (model as? TextEntryFieldModel)?.text = newValue + textEntryFieldModel?.text = newValue } } @@ -167,7 +171,8 @@ import UIKit textField.heightAnchor.constraint(equalToConstant: 24), textField.topAnchor.constraint(equalTo: container.topAnchor, constant: 12), textField.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 16), - container.bottomAnchor.constraint(equalTo: textField.bottomAnchor, constant: 12)]) + container.bottomAnchor.constraint(equalTo: textField.bottomAnchor, constant: 12) + ]) textFieldTrailingConstraint = container.trailingAnchor.constraint(equalTo: textField.trailingAnchor, constant: 16) textFieldTrailingConstraint?.isActive = true @@ -197,9 +202,8 @@ import UIKit @objc deinit { setBothTextDelegates(to: nil) } - + @objc public func setBothTextDelegates(to delegate: (UITextFieldDelegate & ObservingTextFieldDelegate)?) { - observingTextFieldDelegate = delegate uiTextFieldDelegate = delegate } @@ -218,62 +222,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 +278,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,12 +314,9 @@ import UIKit defaultValidationBlock() } - if let formValidationProtocol = delegateObject?.formValidationProtocol { - observingTextFieldDelegate = FormValidator.getFormValidatorFor(delegate: formValidationProtocol) - } - uiTextFieldDelegate = delegateObject?.uiTextFieldDelegate - MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: uiTextFieldDelegate) + observingTextFieldDelegate = delegateObject?.observingTextFieldDelegate + textField.inputAccessoryView = MVMCoreUICommonViewsUtility.getToolbarWithDoneButton(delegate: observingTextFieldDelegate ?? self) } } @@ -330,9 +329,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 +371,8 @@ extension TextEntryField { defaultValidationBlock() } - if let formValidationProtocol = delegateObject.formValidationProtocol { - observingTextFieldDelegate = FormValidator.getFormValidatorFor(delegate: formValidationProtocol) - } - uiTextFieldDelegate = delegateObject.uiTextFieldDelegate + observingTextFieldDelegate = delegateObject.observingTextFieldDelegate MVMCoreUICommonViewsUtility.addDismissToolbar(textField, delegate: uiTextFieldDelegate) } } diff --git a/MVMCoreUI/Atoms/TextFields/TextEntryFieldModel.swift b/MVMCoreUI/Atoms/TextFields/TextEntryFieldModel.swift index 27b0e933..8b8e582e 100644 --- a/MVMCoreUI/Atoms/TextFields/TextEntryFieldModel.swift +++ b/MVMCoreUI/Atoms/TextFields/TextEntryFieldModel.swift @@ -16,7 +16,6 @@ return "textField" } - public var text: String? public var placeholder: String? public var enabledTextColor: Color? public var disabledTextColor: Color? diff --git a/MVMCoreUI/Atoms/TextFields/TextFieldModel.swift b/MVMCoreUI/Atoms/TextFields/TextFieldModel.swift index e26995d6..4d6f1fd0 100644 --- a/MVMCoreUI/Atoms/TextFields/TextFieldModel.swift +++ b/MVMCoreUI/Atoms/TextFields/TextFieldModel.swift @@ -8,11 +8,11 @@ import UIKit -@objcMembers public class TextFieldModel: MoleculeModelProtocol, FormModelProtocol { +@objcMembers public class TextFieldModel: MoleculeModelProtocol { public static var identifier: String = "textField" public var backgroundColor: Color? - public var moleculeName: String? = TextFieldModel.identifier + public var moleculeName: String = TextFieldModel.identifier public var editable: Bool? public var disabled: Bool? public var errorMsg: String? diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index e12fae69..f288c4cd 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -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) - } -} diff --git a/MVMCoreUI/Atoms/Views/CheckboxModel.swift b/MVMCoreUI/Atoms/Views/CheckboxModel.swift index 4d9addd3..13b730a6 100644 --- a/MVMCoreUI/Atoms/Views/CheckboxModel.swift +++ b/MVMCoreUI/Atoms/Views/CheckboxModel.swift @@ -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) } } diff --git a/MVMCoreUI/Atoms/Views/ImageViewModel.swift b/MVMCoreUI/Atoms/Views/ImageViewModel.swift index 0f585119..d5ba0a14 100644 --- a/MVMCoreUI/Atoms/Views/ImageViewModel.swift +++ b/MVMCoreUI/Atoms/Views/ImageViewModel.swift @@ -11,7 +11,7 @@ import Foundation @objcMembers public class ImageViewModel: MoleculeModelProtocol { public static var identifier: String = "image" public var backgroundColor: Color? - public var moleculeName: String? = ImageViewModel.identifier + public var moleculeName: String = ImageViewModel.identifier public var image: String public var accessibilityText: String? public var fallbackImage: String? diff --git a/MVMCoreUI/Atoms/Views/Label/LabelAttributeModel.swift b/MVMCoreUI/Atoms/Views/Label/LabelAttributeModel.swift index ddc468b7..77f7fde6 100644 --- a/MVMCoreUI/Atoms/Views/Label/LabelAttributeModel.swift +++ b/MVMCoreUI/Atoms/Views/Label/LabelAttributeModel.swift @@ -32,7 +32,7 @@ import Foundation var location: Int var length: Int - init(_ location: Int, _ length: Int) { + public init(_ location: Int, _ length: Int) { self.location = location self.length = length } diff --git a/MVMCoreUI/Atoms/Views/Label/LabelAttributeStrikeThroughModel.swift b/MVMCoreUI/Atoms/Views/Label/LabelAttributeStrikeThroughModel.swift index f69e966d..59552e18 100644 --- a/MVMCoreUI/Atoms/Views/Label/LabelAttributeStrikeThroughModel.swift +++ b/MVMCoreUI/Atoms/Views/Label/LabelAttributeStrikeThroughModel.swift @@ -19,4 +19,8 @@ import UIKit public override func encode(to encoder: Encoder) throws { try super.encode(to: encoder) } + + public override init(_ location: Int, _ length: Int) { + super.init(location, length) + } } diff --git a/MVMCoreUI/Atoms/Views/LeftRightLabelModel.swift b/MVMCoreUI/Atoms/Views/LeftRightLabelModel.swift index 44564c93..07c534f8 100644 --- a/MVMCoreUI/Atoms/Views/LeftRightLabelModel.swift +++ b/MVMCoreUI/Atoms/Views/LeftRightLabelModel.swift @@ -14,7 +14,7 @@ import UIKit //-------------------------------------------------- public static var identifier: String = "leftRightLabelView" - public var moleculeName: String? = LeftRightLabelModel.identifier + public var moleculeName: String = LeftRightLabelModel.identifier public var backgroundColor: Color? public var leftText: LabelModel public var rightText: LabelModel? diff --git a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift index e61a5af3..d8415d2d 100644 --- a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift +++ b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift @@ -181,7 +181,7 @@ import UIKit let widthWillChange = !MVMCoreGetterUtility.cgfequal(widthConstraint?.constant ?? 0, width ?? 0) let heightWillChange = !MVMCoreGetterUtility.cgfequal(heightConstraint?.constant ?? 0, height ?? 0) let sizeWillChange = (width == nil || height == nil) && !(size?.equalTo(imageView.image?.size ?? CGSize.zero) ?? false) - let heightChangeFromSpinner = ((height ?? size?.height) ?? 0) < loadingSpinnerHeightConstraint?.constant ?? CGFloat.leastNormalMagnitude + let heightChangeFromSpinner = (heightConstraint?.isActive ?? false) ? false : ((height ?? size?.height) ?? 0) < loadingSpinnerHeightConstraint?.constant ?? CGFloat.leastNormalMagnitude return widthWillChange || heightWillChange || sizeWillChange || heightChangeFromSpinner } diff --git a/MVMCoreUI/Atoms/Views/MFView+ModelExtension.swift b/MVMCoreUI/Atoms/Views/MFView+ModelExtension.swift index af14bc44..840a5d18 100644 --- a/MVMCoreUI/Atoms/Views/MFView+ModelExtension.swift +++ b/MVMCoreUI/Atoms/Views/MFView+ModelExtension.swift @@ -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) } } diff --git a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch+Model.swift b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch+Model.swift index aeccf2ff..1b7ad307 100644 --- a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch+Model.swift +++ b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch+Model.swift @@ -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 } diff --git a/MVMCoreUI/Atoms/Views/RadioButton.swift b/MVMCoreUI/Atoms/Views/RadioButton.swift index 47eeb0ca..4158cb3f 100644 --- a/MVMCoreUI/Atoms/Views/RadioButton.swift +++ b/MVMCoreUI/Atoms/Views/RadioButton.swift @@ -8,62 +8,80 @@ import UIKit -@objcMembers public class RadioButton: Control, FormValidationFormFieldProtocol { +@objcMembers open class RadioButton: Control { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- - var diameter: CGFloat = 30 { + public var diameter: CGFloat = 30 { didSet { widthConstraint?.constant = diameter } } - var enabledColor = UIColor.black - var disabledColor = UIColor.mfSilver() - - var delegateObject: MVMCoreUIDelegateObject? - var fieldKey: String? - var formValue: Bool? - var isRequired: Bool = false + public var enabledColor: UIColor = .black + public var disabledColor: UIColor = .mfSilver() + public var delegateObject: MVMCoreUIDelegateObject? - var widthConstraint: NSLayoutConstraint? - var heightConstraint: NSLayoutConstraint? + public var radioModel: RadioButtonModel? { + return model as? RadioButtonModel + } - lazy var radioGroupName: String? = { - [unowned self] in - return json?.optionalStringForKey("radioGroupName") ?? json?.optionalStringForKey("fieldKey") + lazy public var radioGroupName: String? = { + [unowned self] in return radioModel?.fieldKey }() - lazy var radioButtonModel: RadioButtonSelectionHelper? = { - [unowned self] in + lazy public var radioButtonSelectionHelper: RadioButtonSelectionHelper? = { if let radioGroupName = radioGroupName, - let radioButtonModel = delegateObject?.formValidationProtocol?.formValidatorModel?()?.radioButtonsModelByGroup[radioGroupName] { + let radioButtonModel = delegateObject?.formHolderDelegate?.formValidator?.radioButtonsModelByGroup[radioGroupName] { return radioButtonModel } else { return nil } }() + //-------------------------------------------------- + // MARK: - Constraints + //-------------------------------------------------- + + public var widthConstraint: NSLayoutConstraint? + public var heightConstraint: NSLayoutConstraint? + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open override func draw(_ rect: CGRect) { guard let context = UIGraphicsGetCurrentContext() else { return } + let color = isEnabled ? enabledColor.cgColor : disabledColor.cgColor layer.cornerRadius = bounds.width * 0.5 layer.borderColor = color layer.borderWidth = bounds.width * 0.0333 + if isSelected { // Space around inner circle is 1/5 the size - context.addEllipse(in: CGRect(x: bounds.width*0.2, y: bounds.height*0.2, width: bounds.width*0.6, height: bounds.height*0.6)) + context.addEllipse(in: CGRect(x: bounds.width * 0.2, + y: bounds.height * 0.2, + width: bounds.width * 0.6, + height: bounds.height * 0.6)) context.setFillColor(color) context.fillPath() } } + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + /// 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,20 +90,24 @@ 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 + //-------------------------------------------------- + // MARK: - MVMViewProtocol + //-------------------------------------------------- + open override func setupView() { super.setupView() + backgroundColor = .white clipsToBounds = true widthConstraint = widthAnchor.constraint(equalToConstant: 30) @@ -99,45 +121,18 @@ import UIKit accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint") } - public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) - 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 - } + guard let model = model as? RadioButtonModel 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) + isSelected = model.state + RadioButtonSelectionHelper.setupForRadioButtonGroup(model, self, delegateObject: delegateObject) } public override func reset() { - super.reset() - backgroundColor = .white + super.reset() + backgroundColor = .white } } diff --git a/MVMCoreUI/Atoms/Views/RadioButtonModel.swift b/MVMCoreUI/Atoms/Views/RadioButtonModel.swift index d26e1671..581e03f8 100644 --- a/MVMCoreUI/Atoms/Views/RadioButtonModel.swift +++ b/MVMCoreUI/Atoms/Views/RadioButtonModel.swift @@ -7,14 +7,27 @@ // import Foundation +import MVMCore -public class RadioButtonModel: MoleculeModelProtocol { +open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + 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? + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- private enum CodingKeys: String, CodingKey { case moleculeName @@ -22,22 +35,45 @@ public class RadioButtonModel: MoleculeModelProtocol { case state case enabled case fieldKey + case fieldValue + case groupName } + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(_ state: Bool) { self.state = state } + //-------------------------------------------------- + // MARK: - Method + //-------------------------------------------------- + + public func formFieldValue() -> AnyHashable? { + return state + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + 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) { self.state = state } + if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { self.enabled = enabled } + 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 +83,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) } } diff --git a/MVMCoreUI/Atoms/Views/Toggle.swift b/MVMCoreUI/Atoms/Views/Toggle.swift index ee888b3f..7e45c567 100644 --- a/MVMCoreUI/Atoms/Views/Toggle.swift +++ b/MVMCoreUI/Atoms/Views/Toggle.swift @@ -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() diff --git a/MVMCoreUI/Atoms/Views/ToggleModel.swift b/MVMCoreUI/Atoms/Views/ToggleModel.swift index 948a8e96..5e67be8a 100644 --- a/MVMCoreUI/Atoms/Views/ToggleModel.swift +++ b/MVMCoreUI/Atoms/Views/ToggleModel.swift @@ -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) } } diff --git a/MVMCoreUI/BaseControllers/MVMControllerModelProtocol.swift b/MVMCoreUI/BaseControllers/MVMControllerModelProtocol.swift new file mode 100644 index 00000000..579a612e --- /dev/null +++ b/MVMCoreUI/BaseControllers/MVMControllerModelProtocol.swift @@ -0,0 +1,13 @@ +// +// MVMControllerModelProtocol.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/16/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol MVMControllerModelProtocol: TemplateModelProtocol, FormHolderModelProtocol { + +} diff --git a/MVMCoreUI/BaseControllers/ProgrammaticScrollViewController.swift b/MVMCoreUI/BaseControllers/ProgrammaticScrollViewController.swift new file mode 100644 index 00000000..b6ed6353 --- /dev/null +++ b/MVMCoreUI/BaseControllers/ProgrammaticScrollViewController.swift @@ -0,0 +1,56 @@ +// +// ProgrammaticScrollViewController.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/12/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +open class ProgrammaticScrollViewController: ScrollingViewController { + public var topConstraint: NSLayoutConstraint? + public var bottomConstraint: NSLayoutConstraint? + + public override init(with scrollView: UIScrollView) { + super.init(with: scrollView) + } + + public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + } + + required public init?(coder: NSCoder) { + super.init(coder: coder) + } + + open override func loadView() { + + let view = UIView() + view.backgroundColor = .white + + let scrollView = UIScrollView() + scrollView.backgroundColor = .clear + scrollView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(scrollView) + + // Sets the constraints for the scroll view + let constraints = NSLayoutConstraint.constraintPinSubview(toSuperview: scrollView) + topConstraint = constraints?[ConstraintTop] as? NSLayoutConstraint + bottomConstraint = constraints?[ConstraintBot] as? NSLayoutConstraint + + let contentView = MVMCoreUICommonViewsUtility.commonView() + scrollView.addSubview(contentView) + + // Sets the constraints for the content view + NSLayoutConstraint.constraintPinSubview(toSuperview: contentView) + + // Super will set later. + contentWidthConstraint = contentView.widthAnchor.constraint(equalToConstant: 320.0) + contentWidthConstraint?.isActive = true + + self.contentView = contentView + self.scrollView = scrollView + self.view = view + } +} diff --git a/MVMCoreUI/BaseControllers/ProgrammaticTableViewController.swift b/MVMCoreUI/BaseControllers/ProgrammaticTableViewController.swift new file mode 100644 index 00000000..4e262398 --- /dev/null +++ b/MVMCoreUI/BaseControllers/ProgrammaticTableViewController.swift @@ -0,0 +1,81 @@ +// +// ProgrammaticTableViewController.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/12/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +open class ProgrammaticTableViewController: ProgrammaticScrollViewController, UITableViewDelegate, UITableViewDataSource { + @IBOutlet public var tableView: UITableView! + + public init(with tableView: UITableView) { + self.tableView = tableView + super.init(with: tableView) + } + + required public init?(coder: NSCoder) { + super.init(coder: coder) + } + + public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + } + + open override func loadView() { + let view = UIView() + view.backgroundColor = .white + + let tableView = createTableView() + tableView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(tableView) + + // Sets the constraints for the scroll view + let constraints = NSLayoutConstraint.constraintPinSubview(toSuperview: tableView) + topConstraint = constraints?[ConstraintTop] as? NSLayoutConstraint + bottomConstraint = constraints?[ConstraintBot] as? NSLayoutConstraint + + self.tableView = tableView + scrollView = tableView + self.view = view + } + + /// This class should create the table view that will be used here. Subclass this for different table styles. + open func createTableView() -> UITableView { + let tableView = UITableView(frame: .zero, style: .grouped) + tableView.backgroundColor = .clear + tableView.separatorStyle = UITableViewCell.SeparatorStyle.none + tableView.delegate = self + tableView.dataSource = self + tableView.insetsContentViewsToSafeArea = false + return tableView + } + + // Registers classes and nibs. Can subclass for different nibs. Can call super and then add new ones after as well. + open func registerWithTable() {} + + /// Sets the table to have no section headers or footers. + open func setNoSectionHeadersFooters() { + tableView.sectionHeaderHeight = CGFloat.leastNormalMagnitude + tableView.sectionFooterHeight = CGFloat.leastNormalMagnitude + } + + /// For subclassing, returns the number of sections for table. This function calls numberOfSectionsForTableview aftre ensuring the table is setup properly. + open func getNumberOfSections() -> Int { + return 1 + } + + open func numberOfSections(in tableView: UITableView) -> Int { + return tableView.bounds.width > 1 ? getNumberOfSections() : 0 + } + + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return 0 + } + + open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + return UITableViewCell() + } +} diff --git a/MVMCoreUI/BaseControllers/ScrollingViewController.swift b/MVMCoreUI/BaseControllers/ScrollingViewController.swift new file mode 100644 index 00000000..2e4eceef --- /dev/null +++ b/MVMCoreUI/BaseControllers/ScrollingViewController.swift @@ -0,0 +1,109 @@ +// +// ScrollingViewController.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/12/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +open class ScrollingViewController: ViewController { + public var dismissKeyboardTapGesture: UITapGestureRecognizer? + @IBOutlet public var scrollView: UIScrollView! + public var contentView: UIView? + public var contentWidthConstraint: NSLayoutConstraint? + + private var keyboardNotificationsAdded = false + private var keyboardIsShowing = false + private var preKeyboardContentInset: UIEdgeInsets? + + public init(with scrollView: UIScrollView) { + self.scrollView = scrollView + super.init(nibName: nil, bundle: nil) + } + + required public init?(coder: NSCoder) { + super.init(coder: coder) + } + + public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + } + + // MARK: - View Life Cycle + open override func viewDidLoad() { + super.viewDidLoad() + + // Adds the tap gesture to dismiss the keyboard. + dismissKeyboardTapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissFieldInput(sender:))) + view.addGestureRecognizer(dismissKeyboardTapGesture!) + dismissKeyboardTapGesture?.isEnabled = false + scrollView.alwaysBounceVertical = false + scrollView.delegate = self + } + + open override func updateViewConstraints() { + super.updateViewConstraints() + // Sets the width of the content to the width of the screen. + contentWidthConstraint?.constant = view.bounds.width - scrollView.contentInset.left - scrollView.contentInset.right + } + + open override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + view.setNeedsUpdateConstraints() + view.layoutSubviews() + } + + open override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + registerForKeyboardNotifications() + } + + // MARK: - Keyboard Handling + open func registerForKeyboardNotifications() { + if !keyboardNotificationsAdded { + keyboardNotificationsAdded = true + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil) + } + } + + open func unregisterForKeyboardNotifications() { + if keyboardNotificationsAdded { + NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil) + NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil) + keyboardNotificationsAdded = false + } + } + + @objc open func keyboardWillShow(notification: Notification) { + // Stores the current scroll insets if the keyboard was hidden. + if !keyboardIsShowing { + preKeyboardContentInset = scrollView.contentInset + } + keyboardIsShowing = true + + // Enables the tap gesture. + dismissKeyboardTapGesture?.isEnabled = true + + MVMCoreUIUtility.setScrollViewInsetForKeyboardShow(notification, scrollView: scrollView, viewController: self) { [weak self] () -> CGRect in + return self?.rectToScrollToWhenKeyboardPopsUp() ?? .zero + } + } + + @objc open func keyboardWillBeHidden(notification: Notification) { + keyboardIsShowing = false + + // Disables the tap gesture. + dismissKeyboardTapGesture?.isEnabled = false + + MVMCoreUIUtility.setScrollViewInsetForKeyboardHide(notification, scrollView: scrollView, viewController: self, contentInset: preKeyboardContentInset ?? scrollView.contentInset) + } + + open func rectToScrollToWhenKeyboardPopsUp() -> CGRect? { + guard let field = selectedField, + let parent = selectedField?.superview else { return nil } + return scrollView.convert(field.frame, from: parent) + } +} diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index ae3d2fac..c0f267fc 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -9,7 +9,7 @@ import UIKit import MVMAnimationFramework -open class ThreeLayerTableViewController: MFProgrammaticTableViewController { +open class ThreeLayerTableViewController: ProgrammaticTableViewController { // The three main views private var topView: UIView? private var bottomView: UIView? @@ -17,7 +17,7 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { private var footerView: UIView? private var safeAreaView: UIView? var useMargins: Bool = true - var bottomViewOutsideOfScrollArea: Bool = false + public var bottomViewOutsideOfScrollArea: Bool = false private var topViewBottomConstraint: NSLayoutConstraint? private var bottomViewTopConstraint: NSLayoutConstraint? @@ -36,8 +36,8 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { self.tableView?.reloadData() } - open override func newDataBuildScreen() { - super.newDataBuildScreen() + open override func handleNewData() { + super.handleNewData() createViewForTableHeader() createViewForTableFooter() tableView?.reloadData() @@ -45,8 +45,8 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { override open func viewDidLoad() { super.viewDidLoad() - setToHaveNoSectionHeadersFooters() // Do any additional setup after loading the view. + setNoSectionHeadersFooters() } //MARK: - Spacing @@ -227,26 +227,7 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { return view } - //MARK: - Scrollview - open override func scrollViewDidScroll(_ scrollView: UIScrollView) { - // To stop handscroll animation if animating after scroll - stopHandScrollAnimation(true) - } - deinit { tableView?.delegate = nil } - - //MARK: - Animation - open override func setupIntroAnimations() { - if let topView = topView, topView.subviews.count > 0 { - introAnimationManager?.addAnimation(animation: MVMAnimations.fadeUpAnimation(view: topView)) - } - if let tableView = tableView { - introAnimationManager?.addAnimation(animation: MVMAnimations.animateTableViewFadeInCells(tableView: tableView)) - } - if let bottomView = bottomView, bottomView.subviews.count > 0 { - introAnimationManager?.addAnimation(animation: MVMAnimations.fadeUpAnimation(view: bottomView)) - } - } } diff --git a/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift index ea6923c5..bf557814 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift @@ -61,21 +61,25 @@ open class ThreeLayerViewController: ProgrammaticScrollViewController { } } - open override func newDataBuildScreen() { - super.newDataBuildScreen() - + open override func handleNewData() { // Removes the views topView?.removeFromSuperview() middleView?.removeFromSuperview() bottomView?.removeFromSuperview() safeAreaView?.removeFromSuperview() - MVMCoreUIStackableViewController.remove(contentView?.subviews) + if let subViews = contentView?.subviews { + for view in subViews { + view.removeFromSuperview() + } + } // Reset constraints bottomConstraint?.isActive = true heightConstraint?.isActive = false setupLayers() + + super.handleNewData() } //MARK:-Functions to subclass @@ -241,18 +245,3 @@ extension ThreeLayerViewController { } } } - -//MARK:-Animation -extension ThreeLayerViewController { - open override func setupIntroAnimations() { - if let topView = topView, topView.subviews.count > 0 { - introAnimationManager?.addAnimation(animation: MVMAnimations.fadeUpAnimation(view: topView)) - } - if let middleView = middleView, middleView.subviews.count > 0 { - introAnimationManager?.addAnimation(animation: MVMAnimations.fadeUpAnimation(view: middleView)) - } - if let bottomView = bottomView, bottomView.subviews.count > 0 { - introAnimationManager?.addAnimation(animation: MVMAnimations.fadeUpAnimation(view: bottomView)) - } - } -} diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index 1bb06324..2603e9e7 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -8,19 +8,119 @@ import UIKit -@objcMembers open class ViewController: UIViewController, MVMCoreViewControllerProtocol { - public var pageType: String? - public var loadObject: MVMCoreLoadObject? - public var pageModel: PageModelProtocol? +@objc open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMCoreViewManagerViewControllerProtocol, MoleculeDelegateProtocol, FormHolderProtocol, MVMCoreActionDelegateProtocol, UITextFieldDelegate, UITextViewDelegate, ObservingTextFieldDelegate { + @objc public var pageType: String? + @objc public var loadObject: MVMCoreLoadObject? + public var pageModel: MVMControllerModelProtocol? + + /// Set if this page is containted in a manager. + public var manager: (UIViewController & MVMCoreViewManagerProtocol)? + + // TODO: Change this logic once we convert the MVMCoreViewControllerProtocol to swift + public var selfDelegateObject: MVMCoreUIDelegateObject? + public func delegateObject() -> DelegateObject? { + if selfDelegateObject == nil { + selfDelegateObject = MVMCoreUIDelegateObject.create(withDelegateForAll: self) + } + return selfDelegateObject + } + + public var formValidator: FormValidator? + + public var needsUpdateUI = true + private var observingForResponses = false + private var initialLoadFinished = false + private var previousScreenSize = CGSize.zero + + public var selectedField: UIView? - // MARK: Response handling - public func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer) -> Bool { + /// Checks if the screen width has changed + open func screenSizeChanged() -> Bool { + return !MVMCoreGetterUtility.cgfequalwiththreshold(previousScreenSize.width, view.bounds.size.width, 0.1) + } + + // MARK: - Response handling + open func observeForResponseJSONUpdates() { + guard !observingForResponses, + (pagesToListenFor()?.count ?? 0 > 0 || modulesToListenFor()?.count ?? 0 > 0) else { return } + observingForResponses = true + NotificationCenter.default.addObserver(self, selector: #selector(responseJSONUpdated(notification:)), name: NSNotification.Name(rawValue: NotificationResponseLoaded), object: nil) + } + + open func stopObservingForResponseJSONUpdates() { + guard observingForResponses else { return } + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NotificationResponseLoaded), object: nil) + observingForResponses = false + } + + open func pagesToListenFor() -> [String]? { + guard let pageType = loadObject?.pageType else { return nil } + return [pageType] + } + + open func modulesToListenFor() -> [String]? { + return loadObject?.requestParameters?.modules as? [String] + } + + @objc open func responseJSONUpdated(notification: Notification) { + // Checks for a page we are listening for. + var newData = false + if let pagesLoaded = notification.userInfo?.optionalDictionaryForKey(KeyPageMap), + let pageType = pagesToListenFor()?.first(where: { (pageTypeListened) -> Bool in + guard let page = pagesLoaded.optionalDictionaryForKey(pageTypeListened), + let pageType = page.optionalStringForKey(KeyPageType), + pageType == pageTypeListened else { return false } + return true + }) { + newData = true + loadObject?.pageJSON = pagesLoaded.optionalDictionaryForKey(pageType) + } + + // Checks for modules we are listening for. + if let modulesLoaded = notification.userInfo?.optionalDictionaryForKey(KeyModuleMap), + let modulesListened = modulesToListenFor() { + for moduleName in modulesListened { + if let module = modulesLoaded.optionalDictionaryForKey(moduleName) { + newData = true + var currentModules = loadObject?.modulesJSON ?? [:] + currentModules.updateValue(module, forKey: moduleName) + loadObject?.modulesJSON = currentModules + } + } + } + + guard newData else { return } + do { + try parsePageJSON() + MVMCoreDispatchUtility.performBlock(onMainThread: { + self.handleNewDataAndUpdateUI() + // If the screen is showing, can update the navigation controller. + if let navigationController = self.manager?.navigationController, + self.manager!.getCurrentViewController() == self { + self.set(navigationController: navigationController) + } else if let navigationController = self.navigationController, + self == MVMCoreUIUtility.getCurrentVisibleController() { + self.set(navigationController: navigationController) + } + }) + } catch { + if let coreError = MVMCoreErrorObject.createErrorObject(for: error, location: "updateJSON for pageType: \(String(describing: pageType))") { + MVMCoreLoggingHandler.shared()?.addError(toLog: coreError) + } + } + } + + open func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer) -> Bool { pageType = loadObject.pageType self.loadObject = loadObject + // Verifies all modules needed are loaded. TODO: change to ViewController + guard MFViewController.verifyRequiredModulesLoaded(for: loadObject, error: error) else { return false } + // Parse the model for the page. do { try parsePageJSON() + return true } catch let parsingError { // Log all parsing errors and fail load. if let errorObject = MVMCoreErrorObject.createErrorObject(for: parsingError, location: MVMCoreLoadHandler.sharedGlobal()?.errorLocation(forRequest: loadObject)) { @@ -29,15 +129,12 @@ import UIKit } return false } - - // Verifies all modules needed are loaded. - return MFViewController.verifyRequiredModulesLoaded(for: loadObject, error: error) } - @objc func parsePageJSON() throws { + open func parsePageJSON() throws { } - public class func verifyRequiredModulesLoaded(for loadObject: MVMCoreLoadObject?, error: inout MVMCoreErrorObject?) -> Bool { + open class func verifyRequiredModulesLoaded(for loadObject: MVMCoreLoadObject?, error: inout MVMCoreErrorObject?) -> Bool { guard let pageType = loadObject?.pageType, var modulesRequired = MVMCoreUIViewControllerMappingObject.shared()?.modulesRequired(forPageType: pageType) else { return true } guard let loadedModules = loadObject?.modulesJSON else { return false } @@ -58,25 +155,269 @@ import UIKit return true } - open func setNavigationItem() { - navigationItem.title = pageModel?.screenHeading - navigationItem.accessibilityLabel = pageModel?.screenHeading + /// Calls processNewData and then sets the ui to update with updateView + open func handleNewDataAndUpdateUI() { + handleNewData() + self.needsUpdateUI = true + self.view.setNeedsLayout() } - open func newDataBuildScreen() { - // TODO atomize the navigation item - setNavigationItem() + /// Processes any new data. Called after the page is loaded the first time and on response updates for this page, + open func handleNewData() { + // TODO: remove legacy. Temporary, convert legacy to navigation model. + var navigationModel = pageModel?.navigationItem ?? NavigationItemModel() + navigationModel.title = pageModel?.screenHeading + navigationModel.showLeftPanelButton = isMasterInitiallyAccessible() + navigationModel.showRightPanelButton = isSupportInitiallyAccessible() + if /*(self as? MVMCoreUITabBarPageControlViewController) != nil ||*/ manager != nil || loadObject?.requestParameters?.tabWasPressed ?? false == true { + navigationModel.line = LineModel(type: .none) + } + pageModel?.navigationItem = navigationModel + if self.formValidator == nil { + let rules = pageModel?.formRules + self.formValidator = FormValidator(rules) + } + } + + // MARK: - Navigation Item (Move to model base) + open func set(navigationController: UINavigationController?) { + guard let navigationItemModel = pageModel?.navigationItem, + let navigationController = navigationController else { + MVMCoreUISession.sharedGlobal()?.splitViewController?.parent?.setNeedsStatusBarAppearanceUpdate() + return + } + if navigationController == MVMCoreUISplitViewController.main()?.navigationController, + navigationController.topViewController == self { + MVMCoreUISession.sharedGlobal()?.splitViewController?.setupPanels() + showBottomProgressBar() + } + NavigationController.set(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: self) + } + + // Eventually will be moved to server + open func isMasterInitiallyAccessible() -> Bool { + if loadObject?.pageJSON?.boolForKey(KeyHideMainMenu) ?? false { + return false + } + return MVMCoreUISession.sharedGlobal()?.launchAppLoadedSuccessfully ?? false + } + + // Eventually will be moved to server + open func isSupportInitiallyAccessible() -> Bool { + if loadObject?.pageJSON?.boolForKey(KeyHideMainMenu) ?? false { + return false + } + return (MVMCoreUISession.sharedGlobal()?.launchAppLoadedSuccessfully ?? false) || showRightPanelForScreenBeforeLaunchApp() + } + + open func showRightPanelForScreenBeforeLaunchApp() -> Bool { + return loadObject?.pageJSON?.lenientBoolForKey("showRightPanel") ?? false } + // Eventually will be moved to separate button in navigation item model + open func isOverridingRightButton() -> Bool { + guard let rightPanelLink = loadObject?.pageJSON?.optionalDictionaryForKey("rightPanelButtonLink") else { + return false + } + MVMCoreActionHandler.shared()?.handleAction(with: rightPanelLink, additionalData: nil, delegateObject: delegateObject()) + return true + } + + // Eventually will be moved to separate button in navigation item model + open func isOverridingLeftButton() -> Bool { + guard let leftPanelLink = loadObject?.pageJSON?.optionalDictionaryForKey("leftPanelButtonLink") else { + return false + } + MVMCoreActionHandler.shared()?.handleAction(with: leftPanelLink, additionalData: nil, delegateObject: delegateObject()) + return true + } + + // Eventually will be moved to Model + open func showBottomProgressBar() { + if MVMCoreUISplitViewController.main()?.getCurrentVisibleController() == self, + let progressString = loadObject?.pageJSON?.optionalStringForKey(KeyProgressPercent), + let progress = Float(progressString) { + MVMCoreUISplitViewController.main()?.setBottomProgressBarProgress(progress / Float(100)) + } + } + + // MARK: - View lifecycle open func initialLoad() { + observeForResponseJSONUpdates() } open func updateViews() { + formValidator?.validate() } override open func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "View Controller Loaded : \(self)") + + // We use our own margins. + viewRespectsSystemMinimumLayoutMargins = false + + // Presents from the bottom. + modalPresentationStyle = MVMCoreGetterUtility.isOnIPad() ? UIModalPresentationStyle.formSheet : UIModalPresentationStyle.overCurrentContext + + // Do some initial loading. + if !initialLoadFinished { + initialLoadFinished = true + initialLoad() + } + + // Handle data on load + handleNewData() + + view.setNeedsLayout() + } + + open override func viewDidLayoutSubviews() { + // Add to fix a constraint bug where the width is zero and things get messed up. + guard isViewLoaded, view.bounds.width > 1 else { + super.viewDidLayoutSubviews() + return + } + + if needsUpdateUI || screenSizeChanged() { + updateViews() + needsUpdateUI = false + } + + previousScreenSize = view.bounds.size; + + super.viewDidLayoutSubviews() + } + + open override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + // Update the navigation bar ui when view is appearing unless in a manager. The manager is expected to handle. + if manager == nil { + set(navigationController: navigationController) + } + } + + open override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + if manager == nil { + MVMCoreUISession.sharedGlobal()?.currentPageType = pageType + MVMCoreUILoggingHandler.shared()?.defaultLogPageState(forController: self) + } + } + + deinit { + stopObservingForResponseJSONUpdates() + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "View Controller Deallocated : \(self)") + } + + open override var supportedInterfaceOrientations: UIInterfaceOrientationMask { + return MVMCoreGetterUtility.isOnIPad() ? UIInterfaceOrientationMask.all : UIInterfaceOrientationMask.portrait + } + + open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + + // Updates the detail view width + coordinator.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) in + }) { (UIViewControllerTransitionCoordinatorContext) in + self.view.setNeedsLayout() + } + } + + // MARK: - MVMCoreViewManagerViewControllerProtocol + open func viewControllerReady(inManager manager: UIViewController & MVMCoreViewManagerProtocol) { + if initialLoadFinished { + set(navigationController: manager.navigationController) + } + // Janky way to track current page. + MVMCoreUISession.sharedGlobal()?.currentPageType = pageType + MVMCoreUILoggingHandler.shared()?.defaultLogPageState(forController: self) + } + + // MARK: - MVMCoreActionDelegateProtocol + open func handleOpenPage(for requestParameters: MVMCoreRequestParameters, actionInformation: [AnyHashable : Any]?, additionalData: [AnyHashable : Any]?) { + formValidator?.addFormParams(requestParameters: requestParameters) + requestParameters.parentPageType = loadObject?.pageJSON?.optionalStringForKey("parentPageType") + MVMCoreActionHandler.defaultHandleOpenPage(for: requestParameters, additionalData: additionalData, delegateObject: selfDelegateObject) + } + + open func logAction(withActionInformation actionInformation: [AnyHashable : Any]?, additionalData: [AnyHashable : Any]?) { + MVMCoreUILoggingHandler.shared()?.defaultLogAction(forController: self, actionInformation: actionInformation, additionalData: additionalData) + } + + // MARK: - MoleculeDelegateProtocol + open func getModuleWithName(_ name: String?) -> [AnyHashable : Any]? { + guard let name = name else { return nil } + return loadObject?.modulesJSON?.optionalDictionaryForKey(name) + } + + open func getModuleWithName(_ moleculeName: String) -> MoleculeModelProtocol? { + guard let moduleJSON = loadObject?.modulesJSON?.optionalDictionaryForKey(moleculeName), + let moleculeName = moduleJSON.optionalStringForKey("moleculeName"), + let modelType = ModelRegistry.getType(for: moleculeName, with: MoleculeModelProtocol.self) + else { return nil } + do { + return try modelType.decode(jsonDict: moduleJSON) as? MoleculeModelProtocol + } catch { + MVMCoreUILoggingHandler.logDebugMessage(withDelegate: "error: \(error)") + } + + return nil + } + + // Needed otherwise when subclassed, the extension gets called. + open func moleculeLayoutUpdated(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) {} + open func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? { return nil } + open func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) {} + open func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) {} + + // MARK: - UITextFieldDelegate (Check if this is still needed) + // To Remove TextFields Bug: Keyboard is not dismissing after reaching textfield max length limit + open func textFieldShouldReturn(_ textField: UITextField) -> Bool { + textField.resignFirstResponder() + return true + } + + open func textFieldDidBeginEditing(_ textField: UITextField) { + selectedField = textField + + // TODO: Make this into a protocol + if UIAccessibility.isVoiceOverRunning { + if let toolBar = textField.inputAccessoryView as? UIToolbar, let _ = toolBar.items?.last, let pickerView = textField.inputView as? UIPickerView { + view.accessibilityElements = [pickerView, toolBar] + } + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + UIAccessibility.post(notification: UIAccessibility.Notification.layoutChanged, argument: textField.inputView) + } + } + } + + open func textFieldDidEndEditing(_ textField: UITextField, reason: UITextField.DidEndEditingReason) { + if textField === selectedField { + if UIAccessibility.isVoiceOverRunning { + view.accessibilityElements = nil + UIAccessibility.post(notification: UIAccessibility.Notification.layoutChanged, argument: textField) + } + selectedField = nil + } + } + + @objc open func dismissFieldInput(sender: Any?) { + selectedField?.resignFirstResponder() + } + + // MARK: - UITextViewDelegate (Check if this is still needed) + open func textViewDidBeginEditing(_ textView: UITextView) { + selectedField = textView + } + + open func textViewDidEndEditing(_ textView: UITextView) { + if textView === selectedField { + selectedField = nil + } } } diff --git a/MVMCoreUI/Categories/UIColor+Extension.swift b/MVMCoreUI/Categories/UIColor+Extension.swift index 94bf780d..81fe6743 100644 --- a/MVMCoreUI/Categories/UIColor+Extension.swift +++ b/MVMCoreUI/Categories/UIColor+Extension.swift @@ -42,7 +42,7 @@ extension UIColor { "orangeShade2": (.mvmOrangeShade2, "#984700"), "orangeAA": (.mvmOrangeAA, "#CC4D0F"), "blue": (.mvmBlue, "#0077B4"), - "blue33": (.mvmBlue33, "#57B1DF"), + "blue33": (.mvmBlue33, "#B1D8EF"), "blue66": (.mvmBlue66, "#57B1DF"), "blueShade1": (.mvmBlueShade1, "#136598"), "blueShade2": (.mvmBlueShade2, "#0B4467"), @@ -162,7 +162,7 @@ extension UIColor { /// HEX: #0077B4 public static let mvmBlue = UIColor.color8Bits(red: 0, green: 119, blue: 180) - /// HEX: #57B1DF + /// HEX: #B1D8EF public static let mvmBlue33 = UIColor.color8Bits(red: 87, green: 177, blue: 223) /// HEX: #57B1DF @@ -289,7 +289,7 @@ extension UIColor { return .white } - public class func setBackgroundColor(forNavigationBar color: UIColor, navigationBar: UINavigationBar, transparent: Bool) { + public class func setBackgroundColor(_ color: UIColor, for navigationBar: UINavigationBar, isTransparent: Bool) { DispatchQueue.main.async { @@ -305,7 +305,7 @@ extension UIColor { let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() - if transparent { + if isTransparent { navigationBar.setBackgroundImage(UIImage(), for: .default) navigationBar.isTranslucent = false } else { diff --git a/MVMCoreUI/Categories/UIStackView+Extension.swift b/MVMCoreUI/Categories/UIStackView+Extension.swift new file mode 100644 index 00000000..e968fd7c --- /dev/null +++ b/MVMCoreUI/Categories/UIStackView+Extension.swift @@ -0,0 +1,23 @@ +// +// UIStackView+Extension.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/16/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +extension UIStackView: MVMCoreUIMoleculeViewProtocol { + public func updateView(_ size: CGFloat) { + for view in arrangedSubviews { + (view as? MVMCoreViewProtocol)?.updateView(size) + } + } + + public func reset() { + for view in arrangedSubviews { + (view as? MVMCoreUIMoleculeViewProtocol)?.reset?() + } + } +} diff --git a/MVMCoreUI/Containers/NavigationController.swift b/MVMCoreUI/Containers/NavigationController.swift index 6e18e427..74aadca7 100644 --- a/MVMCoreUI/Containers/NavigationController.swift +++ b/MVMCoreUI/Containers/NavigationController.swift @@ -39,4 +39,34 @@ import UIKit MVMCoreUISession.sharedGlobal()?.setup(asStandardLoadViewDelegate: navigationController) return navigationController } + + public static func set(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol, viewController: (UIViewController & MVMCoreViewControllerProtocol)) { + viewController.navigationItem.title = navigationItemModel.title + viewController.navigationItem.accessibilityLabel = navigationItemModel.title + viewController.navigationItem.hidesBackButton = !navigationItemModel.systemBackButton + + navigationController.setNavigationBarHidden(navigationItemModel.hidden, animated: true) + UIColor.setBackgroundColor(navigationItemModel.backgroundColor?.uiColor ?? .white, for: navigationController.navigationBar, isTransparent: navigationItemModel.transparent) + + let tint = navigationItemModel.tintColor.uiColor + navigationController.navigationBar.tintColor = tint + + // Have the navigation title match the tint color + navigationController.navigationBar.titleTextAttributes?.updateValue(tint, forKey: .foregroundColor) + + // Update icons if main navigation controller. + if navigationController == MVMCoreUISession.sharedGlobal()?.navigationController, + navigationController.topViewController == viewController { + // Update line. + MVMCoreUISession.sharedGlobal()?.navigationController?.separatorView?.set(with: navigationItemModel.line ?? LineModel(type: .standard), viewController.delegateObject?() as? MVMCoreUIDelegateObject, nil) + } + + if navigationController == MVMCoreUISplitViewController.main()?.navigationController, + navigationController.topViewController == viewController { + // Update Panels + MVMCoreUISplitViewController.main()?.setLeftPanelIsAccessible(navigationItemModel.showLeftPanelButton ?? false, for: viewController) + MVMCoreUISplitViewController.main()?.setRightPanelIsAccessible(navigationItemModel.showRightPanelButton ?? false, for: viewController) + MVMCoreUISession.sharedGlobal()?.splitViewController?.setNavigationIconColor(tint) + } + } } diff --git a/MVMCoreUI/Containers/TabBarController/MVMCoreUITabBarPageControlViewController.m b/MVMCoreUI/Containers/TabBarController/MVMCoreUITabBarPageControlViewController.m index cb48eb54..d700e57f 100644 --- a/MVMCoreUI/Containers/TabBarController/MVMCoreUITabBarPageControlViewController.m +++ b/MVMCoreUI/Containers/TabBarController/MVMCoreUITabBarPageControlViewController.m @@ -227,7 +227,7 @@ self.selectedIndex = i; [tabbar selectIndex:self.selectedIndex animated:NO]; - if ([self.viewController respondsToSelector:@selector(shouldCacheInManager)] && [((UIViewController *)self.viewController) shouldCacheInManager]) { + if (![self.viewController respondsToSelector:@selector(shouldCacheInManager)] || [((UIViewController *)self.viewController) shouldCacheInManager]) { [viewControllers addObject:self.viewController]; } else { [viewControllers addObject:[NSNull null]]; diff --git a/MVMCoreUI/Containers/Views/EntryFieldContainer.swift b/MVMCoreUI/Containers/Views/EntryFieldContainer.swift index 773721f7..494eaf5c 100644 --- a/MVMCoreUI/Containers/Views/EntryFieldContainer.swift +++ b/MVMCoreUI/Containers/Views/EntryFieldContainer.swift @@ -260,13 +260,21 @@ import UIKit refreshUI(bottomBarSize: 1) } - open func refreshUI(bottomBarSize: CGFloat? = nil) { + open func refreshUI(bottomBarSize: CGFloat? = nil, updateMoleculeLayout: Bool = false) { if !disableAllBorders { let size: CGFloat = bottomBarSize ?? (showError ? 4 : 1) + var heightChanged = false + + if let bottomHeight = bottomBar?.bounds.height { + heightChanged = size != bottomHeight + } bottomBar?.frame = CGRect(x: 0, y: bounds.height - size, width: bounds.width, height: size) - delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self) + if updateMoleculeLayout || heightChanged { + delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self) + } + setNeedsDisplay() layoutIfNeeded() } diff --git a/MVMCoreUI/FormUIHelpers/FormActionFieldProtocol.swift b/MVMCoreUI/FormUIHelpers/FormActionFieldProtocol.swift new file mode 100644 index 00000000..31208e95 --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/FormActionFieldProtocol.swift @@ -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 } +} diff --git a/MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift b/MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift new file mode 100644 index 00000000..c59ccd08 --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/FormFieldProtocol.swift @@ -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 + } +} diff --git a/MVMCoreUI/FormUIHelpers/FormHolderModelProtocol.swift b/MVMCoreUI/FormUIHelpers/FormHolderModelProtocol.swift new file mode 100644 index 00000000..a9428a2b --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/FormHolderModelProtocol.swift @@ -0,0 +1,14 @@ +// +// FormHolderModelProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 2/5/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// +// A protocol for the model of the delegate object that holds the form validator. The rules are stored in the model. + +import Foundation + +public protocol FormHolderModelProtocol { + var formRules: [FormGroupRule]? { get set } +} diff --git a/MVMCoreUI/FormUIHelpers/FormHolderProtocol.swift b/MVMCoreUI/FormUIHelpers/FormHolderProtocol.swift new file mode 100644 index 00000000..26bceac4 --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/FormHolderProtocol.swift @@ -0,0 +1,14 @@ +// +// FormHolderProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 2/26/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// +// A delegate object that holds the form validator. + +import Foundation + +public protocol FormHolderProtocol: NSObjectProtocol { + var formValidator: FormValidator? { get set } +} diff --git a/MVMCoreUI/FormUIHelpers/FormItemProtocol.swift b/MVMCoreUI/FormUIHelpers/FormItemProtocol.swift new file mode 100644 index 00000000..9b671238 --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/FormItemProtocol.swift @@ -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" + } +} diff --git a/MVMCoreUI/FormUIHelpers/FormValidationProtocol.swift b/MVMCoreUI/FormUIHelpers/FormValidationProtocol.swift deleted file mode 100644 index 49cfacc9..00000000 --- a/MVMCoreUI/FormUIHelpers/FormValidationProtocol.swift +++ /dev/null @@ -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]? -} diff --git a/MVMCoreUI/FormUIHelpers/FormValidator+FormParams.swift b/MVMCoreUI/FormUIHelpers/FormValidator+FormParams.swift deleted file mode 100644 index 4c4945a4..00000000 --- a/MVMCoreUI/FormUIHelpers/FormValidator+FormParams.swift +++ /dev/null @@ -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 - } -} diff --git a/MVMCoreUI/FormUIHelpers/FormValidator+TextFields.swift b/MVMCoreUI/FormUIHelpers/FormValidator+TextFields.swift deleted file mode 100644 index 21599abf..00000000 --- a/MVMCoreUI/FormUIHelpers/FormValidator+TextFields.swift +++ /dev/null @@ -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) - } - }) - } -} diff --git a/MVMCoreUI/FormUIHelpers/FormValidator.swift b/MVMCoreUI/FormUIHelpers/FormValidator.swift index cff26347..0a14e027 100644 --- a/MVMCoreUI/FormUIHelpers/FormValidator.swift +++ b/MVMCoreUI/FormUIHelpers/FormValidator.swift @@ -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]? + weak 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 + } +} + diff --git a/MVMCoreUI/FormUIHelpers/Rules/FormHolderModelProtocol.swift b/MVMCoreUI/FormUIHelpers/Rules/FormHolderModelProtocol.swift new file mode 100644 index 00000000..a9428a2b --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/Rules/FormHolderModelProtocol.swift @@ -0,0 +1,14 @@ +// +// FormHolderModelProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 2/5/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// +// A protocol for the model of the delegate object that holds the form validator. The rules are stored in the model. + +import Foundation + +public protocol FormHolderModelProtocol { + var formRules: [FormGroupRule]? { get set } +} diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/FormGroupRule.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/FormGroupRule.swift new file mode 100644 index 00000000..34dfb7b8 --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/FormGroupRule.swift @@ -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) + } +} + diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAllValueChangedModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAllValueChangedModel.swift new file mode 100644 index 00000000..7535c6dd --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAllValueChangedModel.swift @@ -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() + } +} diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyRequiredModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyRequiredModel.swift new file mode 100644 index 00000000..d41c0b0c --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyRequiredModel.swift @@ -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 + } +} diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyValueChangedModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyValueChangedModel.swift new file mode 100644 index 00000000..042243db --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyValueChangedModel.swift @@ -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 + } +} diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift new file mode 100644 index 00000000..e6b338a4 --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift @@ -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 + } +} diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRegexModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRegexModel.swift new file mode 100644 index 00000000..db1c4859 --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRegexModel.swift @@ -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 + } +} diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRequiredModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRequiredModel.swift new file mode 100644 index 00000000..3900249a --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleRequiredModel.swift @@ -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 + } +} diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift new file mode 100644 index 00000000..25119e03 --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift @@ -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) + } +} diff --git a/MVMCoreUI/FormUIHelpers/ValidProtocol.swift b/MVMCoreUI/FormUIHelpers/ValidProtocol.swift new file mode 100644 index 00000000..20afd256 --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/ValidProtocol.swift @@ -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 } +} diff --git a/MVMCoreUI/BaseControllers/ProgrammaticScrollViewController.h b/MVMCoreUI/Legacy/Controllers/MFProgrammaticScrollViewController.h similarity index 61% rename from MVMCoreUI/BaseControllers/ProgrammaticScrollViewController.h rename to MVMCoreUI/Legacy/Controllers/MFProgrammaticScrollViewController.h index 9e486066..f152b932 100644 --- a/MVMCoreUI/BaseControllers/ProgrammaticScrollViewController.h +++ b/MVMCoreUI/Legacy/Controllers/MFProgrammaticScrollViewController.h @@ -1,5 +1,5 @@ // -// ProgrammaticScrollViewController.h +// MFProgrammaticScrollViewController.h // myverizon // // Created by Scott Pfeil on 1/26/16. @@ -8,7 +8,7 @@ #import -@interface ProgrammaticScrollViewController : MFScrollingViewController +@interface MFProgrammaticScrollViewController : MFScrollingViewController @end diff --git a/MVMCoreUI/BaseControllers/ProgrammaticScrollViewController.m b/MVMCoreUI/Legacy/Controllers/MFProgrammaticScrollViewController.m similarity index 92% rename from MVMCoreUI/BaseControllers/ProgrammaticScrollViewController.m rename to MVMCoreUI/Legacy/Controllers/MFProgrammaticScrollViewController.m index 2bfeb35d..5152ec79 100644 --- a/MVMCoreUI/BaseControllers/ProgrammaticScrollViewController.m +++ b/MVMCoreUI/Legacy/Controllers/MFProgrammaticScrollViewController.m @@ -1,21 +1,21 @@ // -// ProgrammaticScrollViewController.m +// MFProgrammaticScrollViewController.m // myverizon // // Created by Scott Pfeil on 1/26/16. // Copyright © 2016 Verizon Wireless. All rights reserved. // -#import "ProgrammaticScrollViewController.h" +#import "MFProgrammaticScrollViewController.h" @import MVMCore.NSDictionary_MFConvenience; #import "NSLayoutConstraint+MFConvenience.h" #import "MVMCoreUICommonViewsUtility.h" -@interface ProgrammaticScrollViewController () +@interface MFProgrammaticScrollViewController () @end -@implementation ProgrammaticScrollViewController +@implementation MFProgrammaticScrollViewController - (void)loadView { diff --git a/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.h b/MVMCoreUI/Legacy/Controllers/MFProgrammaticTableViewController.h similarity index 100% rename from MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.h rename to MVMCoreUI/Legacy/Controllers/MFProgrammaticTableViewController.h diff --git a/MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.m b/MVMCoreUI/Legacy/Controllers/MFProgrammaticTableViewController.m similarity index 100% rename from MVMCoreUI/BaseControllers/MFProgrammaticTableViewController.m rename to MVMCoreUI/Legacy/Controllers/MFProgrammaticTableViewController.m diff --git a/MVMCoreUI/BaseControllers/MFScrollingViewController.h b/MVMCoreUI/Legacy/Controllers/MFScrollingViewController.h similarity index 100% rename from MVMCoreUI/BaseControllers/MFScrollingViewController.h rename to MVMCoreUI/Legacy/Controllers/MFScrollingViewController.h diff --git a/MVMCoreUI/BaseControllers/MFScrollingViewController.m b/MVMCoreUI/Legacy/Controllers/MFScrollingViewController.m similarity index 100% rename from MVMCoreUI/BaseControllers/MFScrollingViewController.m rename to MVMCoreUI/Legacy/Controllers/MFScrollingViewController.m diff --git a/MVMCoreUI/Legacy/Controllers/MFViewController+Form.swift b/MVMCoreUI/Legacy/Controllers/MFViewController+Form.swift new file mode 100644 index 00000000..2c3b14bf --- /dev/null +++ b/MVMCoreUI/Legacy/Controllers/MFViewController+Form.swift @@ -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) + } +} diff --git a/MVMCoreUI/BaseControllers/MFViewController+Model.swift b/MVMCoreUI/Legacy/Controllers/MFViewController+Model.swift similarity index 100% rename from MVMCoreUI/BaseControllers/MFViewController+Model.swift rename to MVMCoreUI/Legacy/Controllers/MFViewController+Model.swift diff --git a/MVMCoreUI/BaseControllers/MFViewController.h b/MVMCoreUI/Legacy/Controllers/MFViewController.h similarity index 100% rename from MVMCoreUI/BaseControllers/MFViewController.h rename to MVMCoreUI/Legacy/Controllers/MFViewController.h diff --git a/MVMCoreUI/BaseControllers/MFViewController.m b/MVMCoreUI/Legacy/Controllers/MFViewController.m similarity index 98% rename from MVMCoreUI/BaseControllers/MFViewController.m rename to MVMCoreUI/Legacy/Controllers/MFViewController.m index f663193f..52cf01cf 100644 --- a/MVMCoreUI/BaseControllers/MFViewController.m +++ b/MVMCoreUI/Legacy/Controllers/MFViewController.m @@ -38,7 +38,7 @@ #import @import MVMAnimationFramework; -@interface MFViewController() +@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,15 @@ if (!self.disableAnimations) { [self setupIntroAnimations]; } + } - (void)newDataBuildAndUpdate { [MVMCoreDispatchUtility performBlockOnMainThread:^{ [self newDataBuildScreen]; - [self.formValidator enableByValidation]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self startValidation]; + }); self.needToUpdateUI = YES; [self.view setNeedsLayout]; }]; @@ -690,9 +684,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]]; } diff --git a/MVMCoreUI/BaseControllers/MVMCoreUIStackableViewController.h b/MVMCoreUI/Legacy/Controllers/MVMCoreUIStackableViewController.h similarity index 95% rename from MVMCoreUI/BaseControllers/MVMCoreUIStackableViewController.h rename to MVMCoreUI/Legacy/Controllers/MVMCoreUIStackableViewController.h index 0c702925..12d02f43 100644 --- a/MVMCoreUI/BaseControllers/MVMCoreUIStackableViewController.h +++ b/MVMCoreUI/Legacy/Controllers/MVMCoreUIStackableViewController.h @@ -6,9 +6,9 @@ // Copyright © 2019 Verizon Wireless. All rights reserved. // -#import +#import -@interface MVMCoreUIStackableViewController : ProgrammaticScrollViewController +@interface MVMCoreUIStackableViewController : MFProgrammaticScrollViewController // An array of ui elements that will be spaced out on the screen top to bottom from index 0 to formUIArray.count. @property (nullable, strong, nonatomic) NSArray *formUIArray; diff --git a/MVMCoreUI/BaseControllers/MVMCoreUIStackableViewController.m b/MVMCoreUI/Legacy/Controllers/MVMCoreUIStackableViewController.m similarity index 100% rename from MVMCoreUI/BaseControllers/MVMCoreUIStackableViewController.m rename to MVMCoreUI/Legacy/Controllers/MVMCoreUIStackableViewController.m diff --git a/MVMCoreUI/Legacy/Views/MFTextField.m b/MVMCoreUI/Legacy/Views/MFTextField.m index fec796bf..081f9fe8 100644 --- a/MVMCoreUI/Legacy/Views/MFTextField.m +++ b/MVMCoreUI/Legacy/Views/MFTextField.m @@ -18,7 +18,7 @@ @import MVMCore.NSDictionary_MFConvenience; @import MVMCore.MVMCoreJSONConstants; -@interface MFTextField() +@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 diff --git a/MVMCoreUI/Legacy/Views/MVMCoreUICheckBox.m b/MVMCoreUI/Legacy/Views/MVMCoreUICheckBox.m index 40fa987f..4c6bf8a5 100644 --- a/MVMCoreUI/Legacy/Views/MVMCoreUICheckBox.m +++ b/MVMCoreUI/Legacy/Views/MVMCoreUICheckBox.m @@ -21,7 +21,7 @@ static const CGFloat FaultTolerance = 20.f; static const CGFloat CheckBoxHeightWidth = 18.0; -@interface MVMCoreUICheckBox () +@interface MVMCoreUICheckBox () @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 { diff --git a/MVMCoreUI/Legacy/Views/MVMCoreUIPageControl.m b/MVMCoreUI/Legacy/Views/MVMCoreUIPageControl.m index 9a8f880f..f2b9976e 100644 --- a/MVMCoreUI/Legacy/Views/MVMCoreUIPageControl.m +++ b/MVMCoreUI/Legacy/Views/MVMCoreUIPageControl.m @@ -311,7 +311,7 @@ static CGFloat const IndicatorRectangleHeight = 4; self.currentPage = page; } -#pragma mark - MoleculeViewProtocol +#pragma mark - MVMCoreUIMoleculeViewProtocol - (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { NSString *colorString = [json string:KeyBackgroundColor]; diff --git a/MVMCoreUI/Legacy/Views/MVMCoreUISwitch.m b/MVMCoreUI/Legacy/Views/MVMCoreUISwitch.m index 1c40bc5a..8cbb434d 100644 --- a/MVMCoreUI/Legacy/Views/MVMCoreUISwitch.m +++ b/MVMCoreUI/Legacy/Views/MVMCoreUISwitch.m @@ -22,7 +22,7 @@ const CGFloat SwitchKnobWidth = 20; const CGFloat SwitchKnobHeight = 20; const CGFloat SwitchShakeIntensity = 2; -@interface MVMCoreUISwitch () +@interface MVMCoreUISwitch () @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 diff --git a/MVMCoreUI/Legacy/Views/PrimaryButton.m b/MVMCoreUI/Legacy/Views/PrimaryButton.m index 439d5479..0e16ce8e 100644 --- a/MVMCoreUI/Legacy/Views/PrimaryButton.m +++ b/MVMCoreUI/Legacy/Views/PrimaryButton.m @@ -18,7 +18,7 @@ @import MVMCore.MVMCoreGetterUtility; @import MVMCore.NSDictionary_MFConvenience; -@interface PrimaryButton() +@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 *)requiredGroups { - return self.requiredGroupsList; -} - -- (void)enableField:(BOOL)enable { - if (!self.validationRequired) { - self.enabled = YES; - } else { - self.enabled = enable; - } -} - @end diff --git a/MVMCoreUI/MVMCoreUI.h b/MVMCoreUI/MVMCoreUI.h index 5e8c92cc..22707550 100644 --- a/MVMCoreUI/MVMCoreUI.h +++ b/MVMCoreUI/MVMCoreUI.h @@ -48,7 +48,7 @@ FOUNDATION_EXPORT const unsigned char MVMCoreUIVersionString[]; #pragma mark - BaseControllers #import #import -#import +#import #import #import #import diff --git a/MVMCoreUI/Models/ModelProtocols/FormModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/FormModelProtocol.swift deleted file mode 100644 index 28840f06..00000000 --- a/MVMCoreUI/Models/ModelProtocols/FormModelProtocol.swift +++ /dev/null @@ -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 } -} diff --git a/MVMCoreUI/Models/ModelProtocols/MoleculeModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/MoleculeModelProtocol.swift index 2928cf2a..913c3bd0 100644 --- a/MVMCoreUI/Models/ModelProtocols/MoleculeModelProtocol.swift +++ b/MVMCoreUI/Models/ModelProtocols/MoleculeModelProtocol.swift @@ -2,13 +2,13 @@ import Foundation public protocol MoleculeModelProtocol: ModelProtocol { - var moleculeName: String? { get } + var moleculeName: String { get } var backgroundColor: Color? { get set } } public extension MoleculeModelProtocol { - var moleculeName: String? { + var moleculeName: String { get { return Self.identifier } } diff --git a/MVMCoreUI/Models/ModelProtocols/PageModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/PageModelProtocol.swift index 34b58818..5c53ea4e 100644 --- a/MVMCoreUI/Models/ModelProtocols/PageModelProtocol.swift +++ b/MVMCoreUI/Models/ModelProtocols/PageModelProtocol.swift @@ -13,4 +13,5 @@ public protocol PageModelProtocol { var pageType: String { get set } var screenHeading: String? { get set } var isAtomicTabs: Bool? { get set } + var navigationItem: (NavigationItemModelProtocol & MoleculeModelProtocol)? { get set } } diff --git a/MVMCoreUI/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyText.swift b/MVMCoreUI/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyText.swift new file mode 100644 index 00000000..69bdbbba --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyText.swift @@ -0,0 +1,43 @@ +// +// HeadersH2NoButtonsBodyText.swift +// MVMCoreUI +// +// Created by Lekshmi S on 05/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers open class HeadersH2NoButtonsBodyText: HeaderView { + //-------------------------------------------------- + // MARK: - Outlets + //-------------------------------------------------- + let headlineBody = HeadlineBody(frame: .zero) + + //------------------------------------------------------- + // MARK: - View Lifecycle + //------------------------------------------------------- + open override func setupView() { + super.setupView() + headlineBody.stylePageHeader() + addMolecule(headlineBody) + } + + //---------------------------------------------------- + // MARK: - Molecule + //------------------------------------------------------ + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + super.set(with: model, delegateObject, additionalData) + guard let model = model as? HeadersH2NoButtonsBodyTextModel else { return } + headlineBody.set(with: model.headlineBody, delegateObject, additionalData) + } + + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return 121 + } + + open override func reset() { + super.reset() + headlineBody.stylePageHeader() + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyTextModel.swift b/MVMCoreUI/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyTextModel.swift new file mode 100644 index 00000000..eb5502eb --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/Headers/HeadersH2NoButtonsBodyTextModel.swift @@ -0,0 +1,55 @@ +// +// HeadersH2NoButtonsBodyTextModel.swift +// MVMCoreUI +// +// Created by Lekshmi S on 05/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class HeadersH2NoButtonsBodyTextModel: HeaderModel, MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "headerH2" + public var headlineBody: HeadlineBodyModel + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(headlineBody: HeadlineBodyModel) { + self.headlineBody = headlineBody + super.init() + } + + public override func setDefaults() { + super.setDefaults() + topMarginPadding = PaddingDefaultVerticalSpacing3 + bottomMarginPadding = PaddingDefaultVerticalSpacing3 + } + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { + case moleculeName + case headlineBody + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + headlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .headlineBody) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(headlineBody, forKey: .headlineBody) + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift b/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift index b4bb2fc3..12ae94fe 100644 --- a/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift +++ b/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift @@ -64,4 +64,8 @@ import UIKit open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { return 90 } + + public override func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + radioButton.tapAction() + } } diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift b/MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift new file mode 100644 index 00000000..1f2bcd6f --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift @@ -0,0 +1,56 @@ +// +// ListOneColumnTextWithWhitespaceDividerTall.swift +// MVMCoreUI +// +// Created by Dhamodaram Nandi on 09/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation +@objcMembers open class ListOneColumnTextWithWhitespaceDividerTall: TableViewCell { + + //----------------------------------------------------- + // MARK: - Outlets + //----------------------------------------------------- + public var stack: Stack + public let headline = Label.commonLabelH3(true) + public let body = Label.commonLabelB2(true) + + // MARK: - Initializers + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + stack = Stack.createStack(with: [(view: headline, model: StackItemModel(horizontalAlignment: .leading)), + (view: body, model: StackItemModel(spacing: 0, horizontalAlignment: .leading))], + axis: .vertical) + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + //----------------------------------------------------- + // MARK: - View Lifecycle + //----------------------------------------------------- + override open func setupView() { + super.setupView() + addMolecule(stack) + stack.restack() + } + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListOneColumnTextWithWhitespaceDividerTallModel else { return } + headline.set(with: model.headline, delegateObject, additionalData) + body.set(with: model.body, delegateObject, additionalData) + } + + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return 90 + } + + open override func reset() { + super.reset() + headline.styleH3(true) + body.styleB2(true) + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnTextWithWhitespaceDividerTallModel.swift b/MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnTextWithWhitespaceDividerTallModel.swift new file mode 100644 index 00000000..7c95b7e8 --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnTextWithWhitespaceDividerTallModel.swift @@ -0,0 +1,48 @@ +// +// ListOneColumnTextWithWhitespaceDividerTallModel.swift +// MVMCoreUI +// +// Created by Dhamodaram Nandi on 09/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class ListOneColumnTextWithWhitespaceDividerTallModel: ListItemModel, MoleculeModelProtocol { + public static var identifier: String = "list1CTxtDiv2" + public var headline: LabelModel + public var body: LabelModel + + public init(headline: LabelModel, body: LabelModel) { + self.headline = headline + self.body = body + super.init() + } + + /// Defaults to set + override public func setDefaults() { + super.setDefaults() + style = "tallDivider" + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case headline + case body + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + headline = try typeContainer.decode(LabelModel.self, forKey: .headline) + body = try typeContainer.decode(LabelModel.self, forKey: .body) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(headline, forKey: .headline) + try container.encode(body, forKey: .body) + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/RightVariable/ListRightVariableTotalData.swift b/MVMCoreUI/Molecules/DesignedComponents/List/RightVariable/ListRightVariableTotalData.swift new file mode 100644 index 00000000..abef078a --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/List/RightVariable/ListRightVariableTotalData.swift @@ -0,0 +1,68 @@ +// +// ListRightVariableTotalData.swift +// MVMCoreUI +// +// Created by Kruthika KP on 02/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers open class ListRightVariableTotalData: TableViewCell { + + //----------------------------------------------------- + // MARK: - Outlets + //----------------------------------------------------- + public var stack: Stack + public let leftLabel = Label.commonLabelB1(true) + public let rightLabel = Label.commonLabelB2(true) + public let bar = Line() + + //----------------------------------------------------- + // MARK: - Initializers + //----------------------------------------------------- + + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + stack = Stack.createStack(with: [(view: leftLabel, model: StackItemModel(horizontalAlignment: .leading)), + (view: bar, model: StackItemModel(horizontalAlignment: .fill)), + (view: rightLabel, model: StackItemModel(spacing: 4, horizontalAlignment: .fill))], + axis: .horizontal) + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + //----------------------------------------------------- + // MARK: - View Lifecycle + //------------------------------------------------------- + + override open func setupView() { + super.setupView() + bar.setStyle(.heavy) + bar.widthAnchor.constraint(equalToConstant: 20).isActive = true + rightLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal) + addMolecule(stack) + stack.restack() + } + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?){ + super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListRightVariableTotalDataModel else { return } + leftLabel.set(with: model.leftLabel, delegateObject, additionalData) + rightLabel.set(with: model.rightLabel, delegateObject, additionalData) + bar.set(with: model.bar, delegateObject, additionalData) + } + + open override class func estimatedHeight(with molecule: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat?{ + return 70 + } + + open override func reset() { + super.reset() + leftLabel.styleB1(true) + rightLabel.styleB2(true) + bar.setStyle(.heavy) + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/RightVariable/ListRightVariableTotalDataModel.swift b/MVMCoreUI/Molecules/DesignedComponents/List/RightVariable/ListRightVariableTotalDataModel.swift new file mode 100644 index 00000000..f0790391 --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/List/RightVariable/ListRightVariableTotalDataModel.swift @@ -0,0 +1,57 @@ +// +// ListRightVariableTotalDataModel.swift +// MVMCoreUI +// +// Created by Kruthika KP on 02/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class ListRightVariableTotalDataModel: ListItemModel, MoleculeModelProtocol { + + public static var identifier: String = "listRVLine" + public var leftLabel: LabelModel + public var rightLabel: LabelModel + public var bar: LineModel + + override public func setDefaults() { + super.setDefaults() + rightLabel.hero = 0 + bar.type = .heavy + if bar.backgroundColor == nil { + bar.backgroundColor = Color(uiColor: .mvmBlue) + } + } + + public init (leftLabel: LabelModel, rightlabel:LabelModel, bar: LineModel){ + self.leftLabel = leftLabel + self.rightLabel = rightlabel + self.bar = bar + super.init() + } + + private enum CodingKeys: String, CodingKey{ + case moleculeName + case leftLabel + case rightLabel + case bar + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + leftLabel = try typeContainer.decode(LabelModel.self, forKey: .leftLabel) + rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel) + bar = try typeContainer.decode(LineModel.self, forKey: .bar) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(leftLabel, forKey: .leftLabel) + try container.encode(rightLabel, forKey: .rightLabel) + try container.encode(bar, forKey: .bar) + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnCompareChanges.swift b/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnCompareChanges.swift new file mode 100644 index 00000000..c007b8c7 --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnCompareChanges.swift @@ -0,0 +1,113 @@ +// +// ListTwoColumnCompareChanges.swift +// MVMCoreUI +// +// Created by Lekshmi S on 24/02/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers open class ListTwoColumnCompareChanges: TableViewCell { + + //------------------------------------------------------- + // MARK: - Outlets + //------------------------------------------------------- + let leftHeadline1 = Label.commonLabelB1(true) + let leftHeadline2 = Label.commonLabelB1(true) + let leftHeadline3 = Label.commonLabelB1(true) + let leftBody = Label.commonLabelB2(true) + let leftLink = Link() + let rightHeadline1 = Label.commonLabelB1(true) + let rightHeadline2 = Label.commonLabelB1(true) + let rightHeadline3 = Label.commonLabelB1(true) + let rightBody = Label.commonLabelB2(true) + let rightLink = Link() + let containingStack: Stack + + //------------------------------------------------------ + // MARK: - Initializers + //------------------------------------------------------ + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + let stackHeadline1 = Stack.createStack(with: [(view: leftHeadline1, model: StackItemModel(percent: 50, verticalAlignment: .leading)), + (view: rightHeadline1, model: StackItemModel(percent: 50, verticalAlignment: .leading))], + axis: .horizontal) + let stackHeadline2 = Stack.createStack(with: [(view: leftHeadline2, model: StackItemModel(percent: 50, verticalAlignment: .leading)), + (view: rightHeadline2, model: StackItemModel(percent: 50, verticalAlignment: .leading))], + axis: .horizontal) + let stackHeadline3 = Stack.createStack(with: [(view: leftHeadline3, model: StackItemModel(percent: 50, verticalAlignment: .leading)), + (view: rightHeadline3, model: StackItemModel(percent: 50, verticalAlignment: .leading))], + axis: .horizontal) + let stackBody = Stack.createStack(with: [(view: leftBody, model: StackItemModel(percent: 50, verticalAlignment: .leading)), + (view: rightBody, model: StackItemModel(percent: 50, verticalAlignment: .leading))], + axis: .horizontal) + let stackLink = Stack.createStack(with: [(view: leftLink, model: StackItemModel(percent: 50, verticalAlignment: .leading)), + (view: rightLink, model: StackItemModel(percent: 50, verticalAlignment: .leading))], + axis: .horizontal) + containingStack = Stack.createStack(with: [stackHeadline1, + stackHeadline2, + stackHeadline3, + stackBody, + stackLink], + spacing: 0) + containingStack.stackModel?.molecules[1].spacing = 5 + containingStack.stackModel?.molecules[2].spacing = 5 + containingStack.stackModel?.molecules[4].spacing = 5 + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + //------------------------------------------------------ + // MARK: - Properties + //------------------------------------------------------ + let stackSpacing: CGFloat = 5.0 + + //------------------------------------------------------- + // MARK: - View Lifecycle + //------------------------------------------------------- + open override func setupView() { + super.setupView() + addMolecule(containingStack) + for molecule in containingStack.stackItems { + ((molecule as? StackItem)?.view as? Stack)?.restack() + } + containingStack.restack() + } + + //------------------------------------------------------ + // MARK: - Molecule + //------------------------------------------------------ + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListTwoColumnCompareChangesModel else { return } + leftHeadline1.set(with: model.leftHeadline1, delegateObject, additionalData) + leftHeadline2.set(with: model.leftHeadline2, delegateObject, additionalData) + leftHeadline3.set(with: model.leftHeadline3, delegateObject, additionalData) + leftBody.set(with: model.leftBody, delegateObject, additionalData) + leftLink.set(with: model.leftLink, delegateObject, additionalData) + rightHeadline1.set(with: model.rightHeadline1, delegateObject, additionalData) + rightHeadline2.set(with: model.rightHeadline2, delegateObject, additionalData) + rightHeadline3.set(with: model.rightHeadline3, delegateObject, additionalData) + rightBody.set(with: model.rightBody, delegateObject, additionalData) + rightLink.set(with: model.rightLink, delegateObject, additionalData) + } + + open override func reset() { + super.reset() + leftHeadline1.styleB1(true) + leftHeadline2.styleB1(true) + leftHeadline3.styleB1(true) + leftBody.styleB2(true) + rightHeadline1.styleB1(true) + rightHeadline2.styleB1(true) + rightHeadline3.styleB1(true) + rightBody.styleB2(true) + } + + public override class func estimatedHeight(with molecule: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return 121 + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnCompareChangesModel.swift b/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnCompareChangesModel.swift new file mode 100644 index 00000000..5e4e876c --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnCompareChangesModel.swift @@ -0,0 +1,83 @@ +// +// ListTwoColumnCompareChangesModel.swift +// MVMCoreUI +// +// Created by Lekshmi S on 24/02/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class ListTwoColumnCompareChangesModel: ListItemModel, MoleculeModelProtocol { + + public static var identifier: String = "list2CCmpr1" + public var leftHeadline1: LabelModel + public var leftHeadline2: LabelModel + public var leftHeadline3: LabelModel + public var leftBody: LabelModel + public var leftLink: LinkModel + public var rightHeadline1: LabelModel + public var rightHeadline2: LabelModel + public var rightHeadline3: LabelModel + public var rightBody: LabelModel + public var rightLink: LinkModel + + public init(leftHeadline1: LabelModel, leftHeadline2: LabelModel, leftHeadline3: LabelModel, leftBody: LabelModel, leftLink: LinkModel, rightHeadline1: LabelModel, rightHeadline2: LabelModel, rightHeadline3: LabelModel, rightBody: LabelModel, rightLink: LinkModel) { + self.leftHeadline1 = leftHeadline1 + self.leftHeadline2 = leftHeadline2 + self.leftHeadline3 = leftHeadline3 + self.leftBody = leftBody + self.leftLink = leftLink + self.rightHeadline1 = rightHeadline1 + self.rightHeadline2 = rightHeadline2 + self.rightHeadline3 = rightHeadline3 + self.rightBody = rightBody + self.rightLink = rightLink + super.init() + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case leftHeadline1 + case leftHeadline2 + case leftHeadline3 + case leftBody + case leftLink + case rightHeadline1 + case rightHeadline2 + case rightHeadline3 + case rightBody + case rightLink + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + leftHeadline1 = try typeContainer.decode(LabelModel.self, forKey: .leftHeadline1) + leftHeadline2 = try typeContainer.decode(LabelModel.self, forKey: .leftHeadline2) + leftHeadline3 = try typeContainer.decode(LabelModel.self, forKey: .leftHeadline3) + leftBody = try typeContainer.decode(LabelModel.self, forKey: .leftBody) + leftLink = try typeContainer.decode(LinkModel.self, forKey: .leftLink) + rightHeadline1 = try typeContainer.decode(LabelModel.self, forKey: .rightHeadline1) + rightHeadline2 = try typeContainer.decode(LabelModel.self, forKey: .rightHeadline2) + rightHeadline3 = try typeContainer.decode(LabelModel.self, forKey: .rightHeadline3) + rightBody = try typeContainer.decode(LabelModel.self, forKey: .rightBody) + rightLink = try typeContainer.decode(LinkModel.self, forKey: .rightLink) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(leftHeadline1, forKey: .leftHeadline1) + try container.encode(leftHeadline2, forKey: .leftHeadline2) + try container.encode(leftHeadline3, forKey: .leftHeadline3) + try container.encode(leftBody, forKey: .leftBody) + try container.encode(leftLink, forKey: .leftLink) + try container.encode(rightHeadline1, forKey: .rightHeadline1) + try container.encode(rightHeadline2, forKey: .rightHeadline2) + try container.encode(rightHeadline3, forKey: .rightHeadline3) + try container.encode(rightBody, forKey: .rightBody) + try container.encode(rightLink, forKey: .rightLink) + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDescription.swift b/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDescription.swift new file mode 100644 index 00000000..9f4f60b2 --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDescription.swift @@ -0,0 +1,94 @@ +// +// ListTwoColumnPriceDescription.swift +// MVMCoreUI +// +// Created by Kruthika KP on 24/02/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers open class ListTwoColumnPriceDescription: TableViewCell { + + //----------------------------------------------------- + // MARK: - Outlets + //------------------------------------------------------- + public let leftHeadline = Label.commonLabelB1(true) + public let leftBody = Label.commonLabelB2(true) + public let rightLabel = Label.commonLabelB2(true) + public let rightSubLabel = Label.commonLabelB2(true) + + public let view = MVMCoreUICommonViewsUtility.commonView() + public let leftVerticalStack: UIStackView + public let rightVerticalStack: UIStackView + + //------------------------------------------------------ + // MARK: - Initializers + //------------------------------------------------------ + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + leftVerticalStack = UIStackView(arrangedSubviews: [leftHeadline, leftBody]) + leftVerticalStack.axis = .vertical + leftVerticalStack.alignment = .leading + rightVerticalStack = UIStackView(arrangedSubviews: [rightLabel, rightSubLabel]) + rightVerticalStack.axis = .vertical + rightVerticalStack.alignment = .trailing + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + //----------------------------------------------------- + // MARK: - View Lifecycle + //------------------------------------------------------- + open override func updateView(_ size: CGFloat) { + super.updateView(size) + leftVerticalStack.updateView(size) + rightVerticalStack.updateView(size) + } + + override open func setupView() { + super.setupView() + contentView.addSubview(view) + containerHelper.constrainView(view) + + leftVerticalStack.translatesAutoresizingMaskIntoConstraints = false + rightVerticalStack.translatesAutoresizingMaskIntoConstraints = false + rightLabel.setContentHuggingPriority(.defaultHigh, for: .vertical) + rightSubLabel.setContentHuggingPriority(.defaultHigh, for: .vertical) + view.addSubview(leftVerticalStack) + view.addSubview(rightVerticalStack) + NSLayoutConstraint.pinViews(leftView: leftVerticalStack, rightView: rightVerticalStack, alignTop: true) + + leftHeadline.numberOfLines = 1 + rightLabel.numberOfLines = 1 + rightSubLabel.numberOfLines = 1 + } + //---------------------------------------------------- + // MARK: - Molecule + //------------------------------------------------------ + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListTwoColumnPriceDescriptionModel else { return } + leftHeadline.set(with: model.leftHeadline, delegateObject, additionalData) + leftBody.set(with: model.leftBody, delegateObject, additionalData) + rightLabel.set(with: model.rightLabel, delegateObject, additionalData) + rightSubLabel.set(with: model.rightSubLabel, delegateObject, additionalData) + } + + open override class func estimatedHeight(with molecule: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return 80 + } + + override open func reset() { + super.reset() + leftVerticalStack.reset() + rightVerticalStack.reset() + leftHeadline.styleB1(true) + leftBody.styleB2(true) + rightLabel.styleB2(true) + rightSubLabel.styleB2(true) + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDescriptionModel.swift b/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDescriptionModel.swift new file mode 100644 index 00000000..996b1b47 --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDescriptionModel.swift @@ -0,0 +1,66 @@ +// +// ListTwoColumnPriceDescriptionModel.swift +// MVMCoreUI +// +// Created by Kruthika KP on 26/02/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class ListTwoColumnPriceDescriptionModel: ListItemModel, MoleculeModelProtocol { + public static var identifier: String = "list2CTxtPrc1" + public var leftHeadline: LabelModel + public var leftBody: LabelModel + public var rightLabel: LabelModel + public var rightSubLabel: LabelModel + + override public func setDefaults() { + super.setDefaults() + rightLabel.hero = 0 + if rightSubLabel.textColor == nil { + rightSubLabel.textColor = Color(uiColor: .mvmCoolGray6) + } + if rightSubLabel.attributes == nil { + rightSubLabel.attributes = [LabelAttributeStrikeThroughModel(0, rightSubLabel.text.count)] + } + } + + public init(leftHeadline: LabelModel,leftBody: LabelModel, rightLabel: LabelModel, rightSubLabel: LabelModel) { + self.leftHeadline = leftHeadline + self.leftBody = leftBody + self.rightLabel = rightLabel + self.rightSubLabel = rightSubLabel + super.init() + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case leftHeadline + case leftBody + case rightLabel + case rightSubLabel + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + leftHeadline = try typeContainer.decode(LabelModel.self, forKey: .leftHeadline) + leftBody = try typeContainer.decode(LabelModel.self, forKey: .leftBody) + rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel) + rightSubLabel = try typeContainer.decode(LabelModel.self, forKey: .rightSubLabel) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(leftHeadline, forKey: .leftHeadline) + try container.encode(leftBody, forKey: .leftBody) + try container.encode(rightLabel, forKey: .rightLabel) + try container.encode(rightSubLabel, forKey: .rightSubLabel) + } +} + + + diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDetails.swift b/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDetails.swift new file mode 100644 index 00000000..610821b3 --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDetails.swift @@ -0,0 +1,54 @@ +// +// ListTwoColumnPriceDetails.swift +// MVMCoreUI +// +// Created by Lekshmi S on 19/02/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers open class ListTwoColumnPriceDetails: TableViewCell { + + let leftLabel = Label.commonLabelB2(true) + let rightLabel = Label.commonLabelB2(true) + let view = MVMCoreUICommonViewsUtility.commonView() + + // MARK: - MFViewProtocol + open override func setupView() { + super.setupView() + view.addSubview(leftLabel) + view.addSubview(rightLabel) + NSLayoutConstraint.pinViews(leftView: leftLabel, rightView: rightLabel, alignTop: true) + contentView.addSubview(view) + containerHelper.constrainView(view) + rightLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal) + rightLabel.setContentHuggingPriority(.defaultHigh, for: .vertical) + } + + open override func updateView(_ size: CGFloat) { + super.updateView(size) + leftLabel.updateView(size) + rightLabel.updateView(size) + } + + // MARK: - MVMCoreUIMoleculeViewProtocol + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListTwoColumnPriceDetailsModel else { return } + leftLabel.set(with: model.leftLabel, delegateObject, additionalData) + rightLabel.set(with: model.rightLabel, delegateObject, additionalData) + } + + open override func reset() { + super.reset() + leftLabel.reset() + rightLabel.reset() + leftLabel.styleB2(true) + rightLabel.styleB2(true) + } + + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return 15 + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDetailsModel.swift b/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDetailsModel.swift new file mode 100644 index 00000000..2de46552 --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/List/TwoColumn/ListTwoColumnPriceDetailsModel.swift @@ -0,0 +1,54 @@ +// +// ListTwoColumnPriceDetailsModel.swift +// MVMCoreUI +// +// Created by Lekshmi S on 19/02/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class ListTwoColumnPriceDetailsModel: ListItemModel, MoleculeModelProtocol { + public static var identifier: String = "list2CTxtPrc2" + public var leftLabel: LabelModel + public var rightLabel: LabelModel + + public init(leftLabel: LabelModel, rightLabel:LabelModel) { + self.leftLabel = leftLabel + self.rightLabel = rightLabel + super.init() + } + + /// Defaults to set + override public func setDefaults() { + super.setDefaults() + style = "none" + if leftLabel.textColor == nil { + leftLabel.textColor = Color(uiColor: .mvmCoolGray6) + } + if rightLabel.textColor == nil { + rightLabel.textColor = Color(uiColor: .mvmCoolGray6) + } + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case leftLabel + case rightLabel + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + leftLabel = try typeContainer.decode(LabelModel.self, forKey: .leftLabel) + rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(leftLabel, forKey: .leftLabel) + try container.encode(rightLabel, forKey: .rightLabel) + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnFullWidthTextDividerSubsection.swift b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnFullWidthTextDividerSubsection.swift new file mode 100644 index 00000000..c1583583 --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnFullWidthTextDividerSubsection.swift @@ -0,0 +1,56 @@ +// +// ListOneColumnFullWidthTextDividerSubsection.swift +// MVMCoreUI +// +// Created by Dhamodaram Nandi on 09/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation +@objcMembers open class ListOneColumnFullWidthTextDividerSubsection: TableViewCell { + + //----------------------------------------------------- + // MARK: - Outlets + //----------------------------------------------------- + public var stack: Stack + public let headline = Label.commonLabelB1(true) + public let body = Label.commonLabelB2(true) + + // MARK: - Initializers + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + stack = Stack.createStack(with: [(view: headline, model: StackItemModel(horizontalAlignment: .leading)), + (view: body, model: StackItemModel(spacing: 0, horizontalAlignment: .leading))], + axis: .vertical) + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + //----------------------------------------------------- + // MARK: - View Lifecycle + //----------------------------------------------------- + override open func setupView() { + super.setupView() + addMolecule(stack) + stack.restack() + } + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListOneColumnFullWidthTextDividerSubsectionModel else { return } + headline.set(with: model.headline, delegateObject, additionalData) + body.set(with: model.body, delegateObject, additionalData) + } + + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return 90 + } + + open override func reset() { + super.reset() + headline.styleB1(true) + body.styleB2(true) + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnFullWidthTextDividerSubsectionModel.swift b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnFullWidthTextDividerSubsectionModel.swift new file mode 100644 index 00000000..04fb2e87 --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnFullWidthTextDividerSubsectionModel.swift @@ -0,0 +1,48 @@ +// +// ListOneColumnFullWidthTextDividerSubsectionModel.swift +// MVMCoreUI +// +// Created by Dhamodaram Nandi on 09/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class ListOneColumnFullWidthTextDividerSubsectionModel: ListItemModel, MoleculeModelProtocol { + public static var identifier: String = "list1CTxtDiv3" + public var headline: LabelModel + public var body: LabelModel + + public init(headline: LabelModel, body: LabelModel) { + self.headline = headline + self.body = body + super.init() + } + + /// Defaults to set + override public func setDefaults() { + super.setDefaults() + style = "tallDivider" + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case headline + case body + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + headline = try typeContainer.decode(LabelModel.self, forKey: .headline) + body = try typeContainer.decode(LabelModel.self, forKey: .body) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(headline, forKey: .headline) + try container.encode(body, forKey: .body) + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerShort.swift b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerShort.swift new file mode 100644 index 00000000..ec65967d --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerShort.swift @@ -0,0 +1,56 @@ +// +// ListOneColumnTextWithWhitespaceDividerShort.swift +// MVMCoreUI +// +// Created by Dhamodaram Nandi on 04/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation +@objcMembers open class ListOneColumnTextWithWhitespaceDividerShort: TableViewCell { + + //----------------------------------------------------- + // MARK: - Outlets + //----------------------------------------------------- + public var stack: Stack + public let headline = Label.commonLabelH3(true) + public let body = Label.commonLabelB2(true) + + // MARK: - Initializers + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + stack = Stack.createStack(with: [(view: headline, model: StackItemModel(horizontalAlignment: .leading)), + (view: body, model: StackItemModel(spacing: 0, horizontalAlignment: .leading))], + axis: .vertical) + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + //----------------------------------------------------- + // MARK: - View Lifecycle + //----------------------------------------------------- + override open func setupView() { + super.setupView() + addMolecule(stack) + stack.restack() + } + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListOneColumnTextWithWhitespaceDividerShortModel else { return } + headline.set(with: model.headline, delegateObject, additionalData) + body.set(with: model.body, delegateObject, additionalData) + } + + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return 90 + } + + open override func reset() { + super.reset() + headline.styleH3(true) + body.styleB2(true) + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerShortModel.swift b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerShortModel.swift new file mode 100644 index 00000000..340ccddc --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerShortModel.swift @@ -0,0 +1,48 @@ +// +// ListOneColumnTextWithWhitespaceDividerShortModel.swift +// MVMCoreUI +// +// Created by Dhamodaram Nandi on 04/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class ListOneColumnTextWithWhitespaceDividerShortModel: ListItemModel, MoleculeModelProtocol { + public static var identifier: String = "list1CTxtDiv1" + public var headline: LabelModel + public var body: LabelModel + + public init(headline: LabelModel, body: LabelModel) { + self.headline = headline + self.body = body + super.init() + } + + /// Defaults to set + override public func setDefaults() { + super.setDefaults() + style = "shortDivider" + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case headline + case body + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + headline = try typeContainer.decode(LabelModel.self, forKey: .headline) + body = try typeContainer.decode(LabelModel.self, forKey: .body) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(headline, forKey: .headline) + try container.encode(body, forKey: .body) + } +} diff --git a/MVMCoreUI/Molecules/Doughnut/DoughnutChartModel.swift b/MVMCoreUI/Molecules/Doughnut/DoughnutChartModel.swift index 1e5c7dce..ff9b1bf6 100644 --- a/MVMCoreUI/Molecules/Doughnut/DoughnutChartModel.swift +++ b/MVMCoreUI/Molecules/Doughnut/DoughnutChartModel.swift @@ -11,7 +11,7 @@ import Foundation @objcMembers public class DoughnutChartModel: MoleculeModelProtocol { public var backgroundColor: Color? public static var identifier: String = "doughnutChart" - public var moleculeName: String? = DoughnutChartModel.identifier + public var moleculeName: String = DoughnutChartModel.identifier public var title: LabelModel? public var subtitle: LabelModel? public var sections: [DoughnutChartItemModel] @@ -25,7 +25,7 @@ import Foundation @objcMembers public class DoughnutChartItemModel: MoleculeModelProtocol { public var backgroundColor: Color? public static var identifier: String = "doughnutChartItem" - public var moleculeName: String? = DoughnutChartItemModel.identifier + public var moleculeName: String = DoughnutChartItemModel.identifier public var label: LabelModel @Percent public var percent: CGFloat public var color: Color diff --git a/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBodyModel.swift b/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBodyModel.swift index f34e7b94..4ac675c5 100644 --- a/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBodyModel.swift +++ b/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBodyModel.swift @@ -10,7 +10,7 @@ import Foundation public struct ImageHeadlineBodyModel: MoleculeModelProtocol { public static var identifier: String = "imageHeadlineBody" - public var moleculeName: String? = ImageHeadlineBodyModel.identifier + public var moleculeName: String = ImageHeadlineBodyModel.identifier public var backgroundColor: Color? public var image: ImageViewModel public var headlineBody: HeadlineBodyModel diff --git a/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift index 714c7dd9..a7970861 100644 --- a/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift @@ -32,18 +32,14 @@ import UIKit override public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { accordionButton.isSelected = !accordionButton.isSelected accordionButton.setTitle(accordionButton.isSelected ? "-" : "+", for: .normal) - guard let model = accordionListItemModel else { - return - } - - guard let json = model.toJSON(), - let molecules = json.optionalArrayForKey("molecules") as? [[AnyHashable: Any]] - else { return } + guard let model = accordionListItemModel else { return } if accordionButton.isSelected { - delegateObject?.moleculeDelegate?.addMolecules(molecules, sender: self, animation: .automatic) + if let indexPath = delegateObject?.moleculeDelegate?.getIndexPath(for: model) { + delegateObject?.moleculeDelegate?.addMolecules(model.molecules, indexPath: indexPath, animation: .automatic) + } } else { - delegateObject?.moleculeDelegate?.removeMolecules(molecules, sender: self, animation: .automatic) + delegateObject?.moleculeDelegate?.removeMolecules(model.molecules, animation: .automatic) } if (accordionListItemModel?.hideLineWhenExpanded ?? false) && (self.bottomSeparatorView?.shouldBeVisible() ?? false) { diff --git a/MVMCoreUI/Molecules/Items/DropDownFilterTableViewCell.swift b/MVMCoreUI/Molecules/Items/DropDownFilterTableViewCell.swift index f9b9d976..aa581ba1 100644 --- a/MVMCoreUI/Molecules/Items/DropDownFilterTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/DropDownFilterTableViewCell.swift @@ -29,15 +29,16 @@ import UIKit guard newValue != oldValue, 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 model = self.listItemModel as? DropDownListItemModel else { return } if self.previousIndex != NSNotFound { - self.delegateObject?.moleculeDelegate?.removeMolecules(json2d[self.previousIndex], sender: self, animation: .fade) + self.delegateObject?.moleculeDelegate?.removeMolecules(model.molecules[self.previousIndex], animation: .fade) } - self.delegateObject?.moleculeDelegate?.addMolecules(json2d[index], sender: self, animation: .fade) + if let indexPath = self.delegateObject?.moleculeDelegate?.getIndexPath(for: model) { + self.delegateObject?.moleculeDelegate?.addMolecules(model.molecules[index], indexPath: indexPath, animation: .fade) + } self.previousIndex = index } } diff --git a/MVMCoreUI/Molecules/Items/DropDownListItemModel.swift b/MVMCoreUI/Molecules/Items/DropDownListItemModel.swift index 99d493b8..0cd2f5ef 100644 --- a/MVMCoreUI/Molecules/Items/DropDownListItemModel.swift +++ b/MVMCoreUI/Molecules/Items/DropDownListItemModel.swift @@ -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) } diff --git a/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift index 9c63ba64..cf1779be 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift @@ -116,11 +116,10 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi public class func nameForReuse(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { guard let molecule = (model as? CarouselItemModel)?.molecule, - let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(molecule) as? ModelMoleculeViewProtocol.Type, - let name = moleculeClass.nameForReuse(with: molecule, delegateObject) ?? molecule.moleculeName else { + let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(molecule) as? ModelMoleculeViewProtocol.Type else { return nil } - return name + return moleculeClass.nameForReuse(with: molecule, delegateObject) ?? molecule.moleculeName } public func updateView(_ size: CGFloat) { diff --git a/MVMCoreUI/Molecules/Items/StackItemModel.swift b/MVMCoreUI/Molecules/Items/StackItemModel.swift index 795b2983..12254fb5 100644 --- a/MVMCoreUI/Molecules/Items/StackItemModel.swift +++ b/MVMCoreUI/Molecules/Items/StackItemModel.swift @@ -10,7 +10,7 @@ import Foundation @objcMembers public class StackItemModel: ContainerModel, StackItemModelProtocol, MoleculeModelProtocol { public static var identifier: String = "simpleStackItem" - public var moleculeName: String? = StackItemModel.identifier + public var moleculeName: String = StackItemModel.identifier public var backgroundColor: Color? public var spacing: CGFloat? public var percent: Int? diff --git a/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift b/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift index da700a28..cb6ee755 100644 --- a/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift @@ -54,23 +54,19 @@ import UIKit extension TabsTableViewCell: TopTabbarDelegate { public func shouldSelectItem(at index: Int, topTabbar: TopTabbar) -> Bool { - if let model = tabsListItemModel, - let json = model.toJSON(), - let json2d = json.optionalArrayForKey("molecules") as? [[[AnyHashable: Any]]] { - let molecules = json2d[topTabbar.selectedIndex] - delegateObject?.moleculeDelegate?.removeMolecules(molecules, sender: self, animation: index < tabs.selectedIndex ? .right : .left) + if let model = tabsListItemModel { + let molecules = model.molecules[topTabbar.selectedIndex] + delegateObject?.moleculeDelegate?.removeMolecules(molecules, animation: index < tabs.selectedIndex ? .right : .left) } previousTabIndex = tabs.selectedIndex return true } public func topTabbar(_ topTabbar: TopTabbar, didSelectItemAt index: Int) { - if let model = tabsListItemModel, - let json = model.toJSON(), - let json2d = json.optionalArrayForKey("molecules") as? [[[AnyHashable: Any]]] { - let molecules = json2d[index] - delegateObject?.moleculeDelegate?.addMolecules(molecules, sender: self, animation: index < previousTabIndex ? .left : .right) - } + guard let model = tabsListItemModel, + let indexPath = delegateObject?.moleculeDelegate?.getIndexPath(for: model) else { return } + let molecules = model.molecules[index] + delegateObject?.moleculeDelegate?.addMolecules(molecules, indexPath: indexPath, animation: index < previousTabIndex ? .left : .right) } } diff --git a/MVMCoreUI/Molecules/LeftRightViews/ActionDetailWithImageModel.swift b/MVMCoreUI/Molecules/LeftRightViews/ActionDetailWithImageModel.swift index 9dbf53c0..d617f053 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/ActionDetailWithImageModel.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/ActionDetailWithImageModel.swift @@ -10,7 +10,7 @@ import Foundation public struct ActionDetailWithImageModel: MoleculeModelProtocol { public static var identifier: String = "actionDetailWithImage" - public var moleculeName: String? = ActionDetailWithImageModel.identifier + public var moleculeName: String = ActionDetailWithImageModel.identifier public var backgroundColor: Color? public var headlineBodyButton: HeadlineBodyButtonModel public var image: ImageViewModel diff --git a/MVMCoreUI/Molecules/LeftRightViews/CornerLabels.swift b/MVMCoreUI/Molecules/LeftRightViews/CornerLabels.swift index f7ae36de..bbdda6af 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/CornerLabels.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/CornerLabels.swift @@ -152,7 +152,7 @@ import UIKit styleDefault() spaceAboveMolecule = 6.0 spaceBelowMolecule = 6.0 - (middleView as? MoleculeViewProtocol)?.reset?() + (middleView as? MVMCoreUIMoleculeViewProtocol)?.reset?() } func styleDefault() { diff --git a/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyLinkToggleModel.swift b/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyLinkToggleModel.swift index aad8ec06..917bf5dc 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyLinkToggleModel.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyLinkToggleModel.swift @@ -9,7 +9,7 @@ import Foundation public struct HeadlineBodyLinkToggleModel: MoleculeModelProtocol { public static var identifier: String = "headlineBodyLinkToggle" - public var moleculeName: String? = HeadlineBodyLinkToggleModel.identifier + public var moleculeName: String = HeadlineBodyLinkToggleModel.identifier public var backgroundColor: Color? public var headlineBodyLink: HeadlineBodyLinkModel public var toggle: ToggleModel diff --git a/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyToggleModel.swift b/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyToggleModel.swift index bb3391a6..800c976b 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyToggleModel.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/HeadlineBodyToggleModel.swift @@ -11,7 +11,7 @@ import Foundation open class HeadlineBodyToggleModel: MoleculeModelProtocol { public static var identifier: String = "headlineBodyToggle" - public var moleculeName: String? = HeadlineBodyToggleModel.identifier + public var moleculeName: String = HeadlineBodyToggleModel.identifier open var backgroundColor: Color? open var headlineBody: HeadlineBodyModel open var toggle: ToggleModel diff --git a/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/LabelToggleModel.swift b/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/LabelToggleModel.swift index 526ac6b9..16f292ed 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/LabelToggleModel.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/ToggleMolecules/LabelToggleModel.swift @@ -10,7 +10,7 @@ import Foundation public class LabelToggleModel: MoleculeModelProtocol { public static var identifier: String = "labelToggle" - public var moleculeName: String? = LabelToggleModel.identifier + public var moleculeName: String = LabelToggleModel.identifier public var backgroundColor: Color? public var label: LabelModel public var toggle: ToggleModel diff --git a/MVMCoreUI/Molecules/NavigationItemModelProtocol.swift b/MVMCoreUI/Molecules/NavigationItemModelProtocol.swift new file mode 100644 index 00000000..d7df7cc9 --- /dev/null +++ b/MVMCoreUI/Molecules/NavigationItemModelProtocol.swift @@ -0,0 +1,125 @@ +// +// NavigationItemModelProtocol.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/12/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol NavigationItemModelProtocol { + var title: String? { get set } + var titleView: MoleculeModelProtocol? { get set } + var hidden: Bool { get set } + var backgroundColor: Color? { get set } + var transparent: Bool { get set } + var tintColor: Color { get set } + var line: LineModel? { get set } + var systemBackButton: Bool { get set } + var showLeftPanelButton: Bool? { get set } + var showRightPanelButton: Bool? { get set } + var additionalLeftItems: [NavigationItemButtonModel]? { get set } + var additionalRightItems: [NavigationItemButtonModel]? { get set } +} + +public class NavigationItemButtonModel: Codable { + var imageName: String + var action: ActionModelProtocol + + public init(with imageName: String, action: ActionModelProtocol) { + self.imageName = imageName + self.action = action + } + + private enum CodingKeys: String, CodingKey { + case imageName + case action + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + imageName = try typeContainer.decode(String.self, forKey: .imageName) + action = try typeContainer.decodeModel(codingKey: .action) + } + + open func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(imageName, forKey: .imageName) + try container.encodeModel(action, forKey: .action) + } +} + +public class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtocol { + public class var identifier: String { + return "navigationItem" + } + + public var title: String? + public var titleView: MoleculeModelProtocol? + public var hidden: Bool + public var backgroundColor: Color? + public var transparent: Bool + public var tintColor: Color + public var line: LineModel? + public var systemBackButton = false + public var showLeftPanelButton: Bool? + public var showRightPanelButton: Bool? + public var additionalLeftItems: [NavigationItemButtonModel]? + public var additionalRightItems: [NavigationItemButtonModel]? + + init() { + hidden = false + transparent = false + backgroundColor = Color(uiColor: .white) + tintColor = Color(uiColor: .black) + line = LineModel(type: .standard) + } + + private enum CodingKeys: String, CodingKey { + case title + case titleView + case hidden + case backgroundColor + case transparent + case tintColor + case line + case systemBackButton + case showLeftPanelButton + case showRightPanelButton + case additionalLeftItems + case additionalRightItems + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + title = try typeContainer.decodeIfPresent(String.self, forKey: .title) + titleView = try typeContainer.decodeModelIfPresent(codingKey: .titleView) + hidden = try typeContainer.decodeIfPresent(Bool.self, forKey: .hidden) ?? false + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) ?? Color(uiColor: .white) + transparent = try typeContainer.decodeIfPresent(Bool.self, forKey: .transparent) ?? false + tintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .tintColor) ?? Color(uiColor: .black) + line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) + systemBackButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .systemBackButton) ?? false + showLeftPanelButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .showLeftPanelButton) + showRightPanelButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .showRightPanelButton) + additionalLeftItems = try typeContainer.decodeIfPresent([NavigationItemButtonModel].self, forKey: .additionalLeftItems) + additionalRightItems = try typeContainer.decodeIfPresent([NavigationItemButtonModel].self, forKey: .additionalRightItems) + } + + open func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(title, forKey: .title) + try container.encodeModelIfPresent(titleView, forKey: .titleView) + try container.encode(hidden, forKey: .hidden) + try container.encode(backgroundColor, forKey: .backgroundColor) + try container.encode(transparent, forKey: .transparent) + try container.encode(tintColor, forKey: .tintColor) + try container.encodeIfPresent(line, forKey: .line) + try container.encode(systemBackButton, forKey: .systemBackButton) + try container.encode(showLeftPanelButton, forKey: .showLeftPanelButton) + try container.encode(showRightPanelButton, forKey: .showRightPanelButton) + try container.encodeIfPresent(additionalLeftItems, forKey: .additionalLeftItems) + try container.encodeIfPresent(additionalRightItems, forKey: .additionalRightItems) + } +} diff --git a/MVMCoreUI/Molecules/RadioButtonLabel.swift b/MVMCoreUI/Molecules/RadioButtonLabel.swift index e889b4f2..0db4e191 100644 --- a/MVMCoreUI/Molecules/RadioButtonLabel.swift +++ b/MVMCoreUI/Molecules/RadioButtonLabel.swift @@ -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) + } + } diff --git a/MVMCoreUI/Molecules/RadioButtonLabelModel.swift b/MVMCoreUI/Molecules/RadioButtonLabelModel.swift new file mode 100644 index 00000000..28a0f558 --- /dev/null +++ b/MVMCoreUI/Molecules/RadioButtonLabelModel.swift @@ -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 +} diff --git a/MVMCoreUI/Molecules/RadioButtonSelectionHelper.swift b/MVMCoreUI/Molecules/RadioButtonSelectionHelper.swift index f20ac3b2..601588db 100644 --- a/MVMCoreUI/Molecules/RadioButtonSelectionHelper.swift +++ b/MVMCoreUI/Molecules/RadioButtonSelectionHelper.swift @@ -9,21 +9,33 @@ import Foundation import UIKit -@objcMembers public class RadioButtonSelectionHelper: NSObject { - - private var selectedRadioButton: RadioButton? +@objcMembers public class RadioButtonSelectionHelper: FormFieldProtocol { + + + public var fieldKey: String? + public var groupName: String? = FormValidator.defaultGroupName + 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, - let formValidator = formValidator else { - return RadioButtonSelectionHelper() + public static func setupForRadioButtonGroup(_ radioButtonModel: RadioButtonModel, _ radioButton: RadioButton, delegateObject: MVMCoreUIDelegateObject?) { + guard let groupName = radioButtonModel.fieldKey, + let formValidator = delegateObject?.formHolderDelegate?.formValidator else { + return } - 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 + + if radioButtonModel.state { + radioButtonSelectionHelper.selectedRadioButton = radioButton + } + FormValidator.setupValidation(molecule: radioButtonSelectionHelper, delegate: delegateObject?.formHolderDelegate) } public func selected(_ radioButton: RadioButton) { @@ -34,21 +46,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() } } diff --git a/MVMCoreUI/Molecules/ScrollerModel.swift b/MVMCoreUI/Molecules/ScrollerModel.swift index 91dc2e1c..74256e99 100644 --- a/MVMCoreUI/Molecules/ScrollerModel.swift +++ b/MVMCoreUI/Molecules/ScrollerModel.swift @@ -10,6 +10,6 @@ import UIKit public class ScrollerModel: MoleculeContainerModel, MoleculeModelProtocol { public static var identifier: String = "scroller" - public var moleculeName: String? = ScrollerModel.identifier + public var moleculeName: String = ScrollerModel.identifier public var backgroundColor: Color? } diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLinkModel.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLinkModel.swift index e277f5de..0f158c2c 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLinkModel.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLinkModel.swift @@ -14,7 +14,7 @@ public class EyebrowHeadlineBodyLinkModel: MoleculeModelProtocol { //-------------------------------------------------- public static var identifier: String = "eyebrowHeadlineBodyLink" - public var moleculeName: String? = EyebrowHeadlineBodyLinkModel.identifier + public var moleculeName: String = EyebrowHeadlineBodyLinkModel.identifier public var backgroundColor: Color? public var eyebrow: LabelModel? public var headline: LabelModel? diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift index ba2aa009..a120807d 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift @@ -46,7 +46,7 @@ open class HeadlineBody: View { func stylePageHeader() { headlineLabel.styleH2(true) messageLabel.styleB2(true) - spaceBetweenLabelsConstant = PaddingTwo + spaceBetweenLabelsConstant = PaddingOne } func styleListItem() { diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyButtonModel.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyButtonModel.swift index ec97fda0..439e3aec 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyButtonModel.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyButtonModel.swift @@ -10,7 +10,7 @@ import Foundation public struct HeadlineBodyButtonModel: MoleculeModelProtocol { public static var identifier: String = "headlineBodyButton" - public var moleculeName: String? = HeadlineBodyButtonModel.identifier + public var moleculeName: String = HeadlineBodyButtonModel.identifier public var backgroundColor: Color? public var headlineBody: HeadlineBodyModel diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyLinkModel.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyLinkModel.swift index 27f0d670..4ef4018b 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyLinkModel.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyLinkModel.swift @@ -10,7 +10,7 @@ import Foundation public struct HeadlineBodyLinkModel: MoleculeModelProtocol { public static var identifier: String = "headlineBodyLink" - public var moleculeName: String? = HeadlineBodyLinkModel.identifier + public var moleculeName: String = HeadlineBodyLinkModel.identifier public var headlineBody: HeadlineBodyModel public var link: LinkModel public var backgroundColor: Color? diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift index 0ec98c65..e715b61e 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift @@ -10,7 +10,7 @@ import Foundation @objcMembers open class HeadlineBodyModel: MoleculeModelProtocol { public static var identifier: String = "headlineBody" - public var moleculeName: String? = HeadlineBodyModel.identifier + public var moleculeName: String = HeadlineBodyModel.identifier public var headline: LabelModel? public var body: LabelModel? public var style: String? diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeStack.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeStack.swift index 48f39fa0..56cc0447 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeStack.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeStack.swift @@ -14,8 +14,7 @@ open class StringAndMoleculeStack: MoleculeStackView { guard let model = stackModel else { return } for stackItemModel in model.molecules { guard let stringAndMoleculeModel = stackItemModel.molecule as? StringAndMoleculeModel, - let moleculeName = stringAndMoleculeModel.molecule.moleculeName, - let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forName: moleculeName) as? (UIView & ModelMoleculeViewProtocol) else { + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forName: stringAndMoleculeModel.molecule.moleculeName) as? (UIView & ModelMoleculeViewProtocol) else { // Throw error return } diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeView.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeView.swift index 95392b8d..09ed8a7b 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeView.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/Lists/StringAndMoleculeStack/StringAndMoleculeView.swift @@ -73,7 +73,7 @@ open class StringAndMoleculeView: View { override open func reset() { super.reset() label.reset() - (molecule as? MoleculeViewProtocol)?.reset?() + (molecule as? MVMCoreUIMoleculeViewProtocol)?.reset?() } public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { diff --git a/MVMCoreUI/Organisms/Carousel.swift b/MVMCoreUI/Organisms/Carousel.swift index 05266a57..341e41f8 100644 --- a/MVMCoreUI/Organisms/Carousel.swift +++ b/MVMCoreUI/Organisms/Carousel.swift @@ -21,22 +21,24 @@ open class Carousel: View { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) + + public let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) /// The current index of the collection view. Includes dummy cells when looping. - var currentIndex = 0 + public var currentIndex = 0 /// The index of the page, does not include dummy cells. - var pageIndex: Int { - get { return loop ? currentIndex - 2 : currentIndex } - set (newIndex) { + public var pageIndex: Int { + get { + return loop ? currentIndex - 2 : currentIndex + } + set(newIndex) { currentIndex = loop ? newIndex + 2 : newIndex } } /// The number of pages that there are. Used for the page control and for calculations. Should not include the looping dummy cells. Be sure to set this if subclassing and not using the molecules. - var numberOfPages = 0 + open var numberOfPages = 0 /// The json for the molecules. var molecules: [MoleculeModelProtocol]? @@ -45,21 +47,21 @@ open class Carousel: View { var itemAlignment: UICollectionView.ScrollPosition = .left /// From 0-1. The item width as a percent of the carousel width. - var itemWidthPercent: Float = 1 + public var itemWidthPercent: Float = 1 /// The height of the carousel. Default is 300. - var collectionViewHeight: NSLayoutConstraint? + public var collectionViewHeight: NSLayoutConstraint? /// The view that we use for paging - var pagingView: (UIView & CarouselPageControlProtocol)? + public var pagingView: (UIView & CarouselPageControlProtocol)? /// If the carousel should loop after scrolling past the first and final cells. var loop = false private var dragging = false - /// For adding pager - private var bottomPin: NSLayoutConstraint? + // For adding pager + public var bottomPin: NSLayoutConstraint? //-------------------------------------------------- // MARK: - MVMCoreViewProtocol @@ -195,11 +197,10 @@ open class Carousel: View { /// Returns the (identifier, class) of the molecule for the given map. func getMoleculeInfo(with molecule: MoleculeModelProtocol, delegateObject: MVMCoreUIDelegateObject?) -> (identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)? { - guard let className = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(molecule) , - let moleculeName = (className as? ModelMoleculeViewProtocol.Type)?.nameForReuse(with: molecule, delegateObject) ?? molecule.moleculeName - else { return nil } - - return (moleculeName, className, molecule) + guard let className = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(molecule) else { + return nil + } + return ((className as? ModelMoleculeViewProtocol.Type)?.nameForReuse(with: molecule, delegateObject) ?? molecule.moleculeName, className, molecule) } /// Sets the alignment from the string. @@ -275,9 +276,10 @@ open class Carousel: View { } } - func setAccessiblity(_ cell: UICollectionViewCell?, index: Int) { - guard let cell = cell else { return } - + public func setAccessiblity(_ cell: UICollectionViewCell?, index: Int) { + guard let cell = cell else { + return + } if index == currentIndex { cell.accessibilityElementsHidden = false var array = cell.accessibilityElements @@ -298,24 +300,22 @@ open class Carousel: View { } extension Carousel: UICollectionViewDelegateFlowLayout { - - public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent) return CGSize(width: itemWidth, height: collectionView.bounds.height) } - public func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { + open func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { (cell as? MoleculeCollectionViewCell)?.setPeaking(false, animated: false) } } extension Carousel: UICollectionViewDataSource { - - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return molecules?.count ?? 0 } - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let molecule = molecules?[indexPath.row], let moleculeInfo = getMoleculeInfo(with: molecule, delegateObject: nil) else { return UICollectionViewCell() } @@ -388,7 +388,7 @@ extension Carousel: UIScrollViewDelegate { handleUserOnBufferCell() } - public func scrollViewDidScroll(_ scrollView: UIScrollView) { + open func scrollViewDidScroll(_ scrollView: UIScrollView) { // Check if the user is dragging the card even further past the next card. checkForDraggingOutOfBounds(scrollView) diff --git a/MVMCoreUI/Organisms/Stack.swift b/MVMCoreUI/Organisms/Stack.swift index 696964f1..8e6df863 100644 --- a/MVMCoreUI/Organisms/Stack.swift +++ b/MVMCoreUI/Organisms/Stack.swift @@ -135,7 +135,7 @@ open class Stack: Container where T: (StackModelProtocol & MoleculeModelProto super.reset() backgroundColor = .clear for item in stackItems { - (item as? MoleculeViewProtocol)?.reset?() + (item as? MVMCoreUIMoleculeViewProtocol)?.reset?() } } @@ -162,13 +162,11 @@ open class Stack: Container where T: (StackModelProtocol & MoleculeModelProto } var name = "stack<" for case let item in model.molecules { - if let moleculeName = item.moleculeName { - if let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping[moleculeName] as? ModelMoleculeViewProtocol.Type, - let nameForReuse = moleculeClass.nameForReuse(with: item, delegateObject) { - name.append(nameForReuse + ",") - } else { - name.append(moleculeName + ",") - } + if let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping[item.moleculeName] as? ModelMoleculeViewProtocol.Type, + let nameForReuse = moleculeClass.nameForReuse(with: item, delegateObject) { + name.append(nameForReuse + ",") + } else { + name.append(item.moleculeName + ",") } } name.append(">") diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift b/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift index f64162db..c9d5d34c 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift @@ -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 var moleculeDelegate: MoleculeDelegateProtocol? + public weak var observingTextFieldDelegate: ObservingTextFieldDelegate? + public weak 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 } diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUILoggingHandler.h b/MVMCoreUI/OtherHandlers/MVMCoreUILoggingHandler.h index 003d67f8..9fec90f5 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUILoggingHandler.h +++ b/MVMCoreUI/OtherHandlers/MVMCoreUILoggingHandler.h @@ -14,11 +14,11 @@ NS_ASSUME_NONNULL_BEGIN @interface MVMCoreUILoggingHandler : MVMCoreLoggingHandler // Page State Logging -- (void)defaultLogPageStateForController:(nonnull MFViewController *)controller; +- (void)defaultLogPageStateForController:(nonnull id )controller; // Action Logging -- (void)defaultLogActionForController:(nonnull MFViewController *)controller actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData; -- (nullable NSDictionary *)defaultGetActionTrackDataDictionaryForController:(nonnull MFViewController *)controller actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData; +- (void)defaultLogActionForController:(nonnull id )controller actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData; +- (nullable NSDictionary *)defaultGetActionTrackDataDictionaryForController:(nonnull id )controller actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData; @end diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUILoggingHandler.m b/MVMCoreUI/OtherHandlers/MVMCoreUILoggingHandler.m index 6395fbcc..0c694cce 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUILoggingHandler.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUILoggingHandler.m @@ -10,13 +10,13 @@ @implementation MVMCoreUILoggingHandler -- (void)defaultLogPageStateForController:(nonnull MFViewController *)controller { +- (void)defaultLogPageStateForController:(nonnull id )controller { } -- (void)defaultLogActionForController:(nonnull MFViewController *)controller actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData { +- (void)defaultLogActionForController:(nonnull id )controller actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData { } -- (nullable NSDictionary *)defaultGetActionTrackDataDictionaryForController:(nonnull MFViewController *)controller actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData { +- (nullable NSDictionary *)defaultGetActionTrackDataDictionaryForController:(nonnull id )controller actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData { return nil; } diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift index 6c791ccf..52d48b6c 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift @@ -16,11 +16,7 @@ public extension MVMCoreUIMoleculeMappingObject { } func getMoleculeClass(_ model: MoleculeModelProtocol) -> AnyClass? { - if let moleculeName = model.moleculeName { - return moleculeMapping.object(forKey: moleculeName) as? AnyClass - } - - return nil + return moleculeMapping.object(forKey: model.moleculeName) as? AnyClass } func createMolecule(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> (UIView & MVMCoreUIMoleculeViewProtocol)? { @@ -28,8 +24,7 @@ public extension MVMCoreUIMoleculeMappingObject { } func createMolecule(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ constrainIfNeeded: Bool) -> (UIView & MVMCoreUIMoleculeViewProtocol)? { - guard let moleculeName = model.moleculeName, - let molecule = createMolecule(forName: moleculeName) else { + guard let molecule = createMolecule(forName: model.moleculeName) else { return nil } diff --git a/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift b/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift index eb175c3a..07df3296 100644 --- a/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift +++ b/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift @@ -8,7 +8,7 @@ import Foundation -public protocol MoleculeDelegateProtocol { +public protocol MoleculeDelegateProtocol: AnyObject { /// returns a module for the corresponding module name. func getModuleWithName(_ name: String?) -> [AnyHashable : Any]? @@ -18,39 +18,16 @@ public protocol MoleculeDelegateProtocol { func moleculeLayoutUpdated(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) //optional /// Asks the delegate to add or remove molecules. - //optional - func addMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) - func addMolecules(_ molecules: [[AnyHashable : Any]], indexPath: IndexPath, animation: UITableView.RowAnimation) - - func removeMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) - - //optional - func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) - func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) + func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? + func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) + func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) } extension MoleculeDelegateProtocol { - public func moleculeLayoutUpdated(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) { - // Do Nothing - } - public func addMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { - // Do nothing - } + public func moleculeLayoutUpdated(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) {} - public func addMolecules(_ molecules: [[AnyHashable : Any]], indexPath: IndexPath, animation: UITableView.RowAnimation) { - // Do nothing - } - - public func removeMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { - // Do nothing - } - - public func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { - // Do nothing - } - - public func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { - // Do nothing - } + public func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? { return nil } + public func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) {} + public func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) {} } diff --git a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift index 8f12752e..881fa20f 100644 --- a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift +++ b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift @@ -53,8 +53,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) @@ -81,7 +82,6 @@ import Foundation MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: AccordionMoleculeTableViewCell.self, viewModelClass: AccordionListItemModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: TabsTableViewCell.self, viewModelClass: TabsListItemModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListProgressBarData.self, viewModelClass: ListProgressBarDataModel.self) - // Other Items MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: MoleculeStackItem.self, viewModelClass: MoleculeStackItemModel.self) @@ -105,25 +105,43 @@ import Foundation // Designed List Items MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListLeftVariableIconWithRightCaret.self, viewModelClass: ListLeftVariableIconWithRightCaretModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListLeftVariableCheckboxAllTextAndLinks.self, viewModelClass: ListLeftVariableCheckboxAllTextAndLinksModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListRightVariablePayments.self, viewModelClass: ListRightVariablePaymentsModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListLeftVariableRadioButtonAndPaymentMethod.self, viewModelClass: ListLeftVariableRadioButtonAndPaymentMethodModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListRVWheel.self, viewModelClass: ListRVWheelModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListRightVariablePayments.self, viewModelClass: ListRightVariablePaymentsModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListRightVariableTotalData.self, viewModelClass: ListRightVariableTotalDataModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListOneColumnFullWidthTextAllTextAndLinks.self, viewModelClass: ListOneColumnFullWidthTextAllTextAndLinksModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListOneColumnFullWidthTextBodyText.self, viewModelClass: ListOneColumnFullWidthTextBodyTextModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListTwoColumnCompareChanges.self, viewModelClass: ListTwoColumnCompareChangesModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListTwoColumnPriceDetails.self, viewModelClass: ListTwoColumnPriceDetailsModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListTwoColumnPriceDescription.self, viewModelClass: ListTwoColumnPriceDescriptionModel.self) // Designed Section Dividers MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListFourColumnDataUsageDivider.self, viewModelClass: ListFourColumnDataUsageDividerModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListThreeColumnPlanDataDivider.self, viewModelClass: ListThreeColumnPlanDataDividerModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListOneColumnTextWithWhitespaceDividerShort.self, viewModelClass: ListOneColumnTextWithWhitespaceDividerShortModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListOneColumnTextWithWhitespaceDividerTall.self, viewModelClass: ListOneColumnTextWithWhitespaceDividerTallModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListOneColumnFullWidthTextDividerSubsection.self, viewModelClass: ListOneColumnFullWidthTextDividerSubsectionModel.self) + + // Designed Headers + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: HeadersH2NoButtonsBodyText.self, viewModelClass: HeadersH2NoButtonsBodyTextModel.self) // TODO: Need model - MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping.setObject(DigitEntryField.self, forKey: "digitTextField" as NSString) - 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) + + // Actions + try? ModelRegistry.register(ActionTopAlertModel.self) + try? ModelRegistry.register(ActionCollapseNotificationModel.self) + try? ModelRegistry.register(ActionOpenPanelModel.self) } } diff --git a/MVMCoreUI/Templates/ListPageTemplateModel.swift b/MVMCoreUI/Templates/ListPageTemplateModel.swift index 6bd3f332..0188a434 100644 --- a/MVMCoreUI/Templates/ListPageTemplateModel.swift +++ b/MVMCoreUI/Templates/ListPageTemplateModel.swift @@ -8,7 +8,11 @@ import Foundation -@objcMembers public class ListPageTemplateModel: TemplateModelProtocol { +@objcMembers public class ListPageTemplateModel: MVMControllerModelProtocol { + + public var formRules: [FormGroupRule]? + public var formValidator: FormValidator? + //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -18,6 +22,7 @@ import Foundation public var pageType: String public var screenHeading: String? public var isAtomicTabs: Bool? + public var navigationItem: (NavigationItemModelProtocol & MoleculeModelProtocol)? public var header: MoleculeModelProtocol? public var molecules: [ListItemModelProtocol & MoleculeModelProtocol]? @@ -39,7 +44,7 @@ import Foundation //-------------------------------------------------- private enum CodingKeys: String, CodingKey { - case moleculeName + case template case pageType case screenHeading case molecules @@ -47,6 +52,7 @@ import Foundation case footer case line case isAtomicTabs + case formRules } //-------------------------------------------------- @@ -62,17 +68,20 @@ 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 { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(pageType, forKey: .pageType) + try container.encode(template, forKey: .template) try container.encodeIfPresent(screenHeading, forKey: .screenHeading) try container.encodeModelsIfPresent(molecules, forKey: .molecules) try container.encodeIfPresent(isAtomicTabs, forKey: .isAtomicTabs) try container.encodeModelIfPresent(header, forKey: .header) try container.encodeModelIfPresent(footer, forKey: .footer) try container.encode(line, forKey: .line) + try container.encodeIfPresent(formRules, forKey: .formRules) } } diff --git a/MVMCoreUI/Templates/ModalMoleculeListTemplate.swift b/MVMCoreUI/Templates/ModalMoleculeListTemplate.swift index 6dae1700..7c62faab 100644 --- a/MVMCoreUI/Templates/ModalMoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/ModalMoleculeListTemplate.swift @@ -10,11 +10,12 @@ import UIKit open class ModalMoleculeListTemplate: MoleculeListTemplate { - override open func newDataBuildScreen() { - super.newDataBuildScreen() - MVMCoreUICommonViewsUtility.addCloseButton(to: view, action: {[weak self] _ in - self?.dismiss() + public var closeButton: MFCustomButton? + + override open func handleNewData() { + super.handleNewData() + closeButton = MVMCoreUICommonViewsUtility.addCloseButton(to: view, action: { [weak self] _ in + MVMCoreNavigationHandler.shared()?.removeCurrentViewController() }, verticalCentered: false) } - } diff --git a/MVMCoreUI/Templates/ModalMoleculeStackTemplate.swift b/MVMCoreUI/Templates/ModalMoleculeStackTemplate.swift index 9f1ea9b9..b50400a7 100644 --- a/MVMCoreUI/Templates/ModalMoleculeStackTemplate.swift +++ b/MVMCoreUI/Templates/ModalMoleculeStackTemplate.swift @@ -10,10 +10,12 @@ import UIKit open class ModalMoleculeStackTemplate: MoleculeStackTemplate { - override open func newDataBuildScreen() { - super.newDataBuildScreen() + override open func handleNewData() { + super.handleNewData() MVMCoreUICommonViewsUtility.addCloseButton(to: view, action: {[weak self] _ in - self?.dismiss() + if let _ = self { + MVMCoreNavigationHandler.shared()?.removeCurrentViewController() + } }, verticalCentered: false) } diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index 1dfb0938..d68a1170 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -12,7 +12,6 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol //-------------------------------------------------- // MARK: - Stored Properties //-------------------------------------------------- - public var moleculesInfo: [(identifier: String, class: AnyClass, molecule: (ListItemModelProtocol & MoleculeModelProtocol))]? var observer: NSKeyValueObservation? @@ -22,13 +21,9 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol //-------------------------------------------------- // MARK: - Computed Properties //-------------------------------------------------- - - open override func parsePageJSON(_ error: NSErrorPointer) { - do { - try parseTemplateJSON() - } catch let parseError { - error?.pointee = parseError as NSError - } + open override func parsePageJSON() throws { + try parseTemplate(json: loadObject?.pageJSON) + try super.parsePageJSON() } open override var loadObject: MVMCoreLoadObject? { @@ -85,8 +80,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol return true } - open override func newDataBuildScreen() { - super.newDataBuildScreen() + open override func handleNewData() { + super.handleNewData() setup() registerWithTable() } @@ -104,7 +99,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } } - open override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { + open func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { guard let moleculeInfo = moleculesInfo?[indexPath.row], let estimatedHeight = (moleculeInfo.class as? ModelMoleculeViewProtocol.Type)?.estimatedHeight(with: moleculeInfo.molecule, delegateObject() as? MVMCoreUIDelegateObject) else { return 0 } @@ -122,47 +117,34 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol let cell = tableView.dequeueReusableCell(withIdentifier: moleculeInfo.identifier) else { return UITableViewCell() } - let delegate = delegateObject() as? MVMCoreUIDelegateObject let moleculeCell = cell as? MVMCoreUIMoleculeViewProtocol moleculeCell?.reset?() if let protocolCell = cell as? MoleculeListCellProtocol { - protocolCell.setLines(with: templateModel?.line, delegateObject: delegate, additionalData: nil, indexPath: indexPath) + protocolCell.setLines(with: templateModel?.line, delegateObject: selfDelegateObject, additionalData: nil, indexPath: indexPath) } - (moleculeCell as? ModelMoleculeViewProtocol)?.set(with: moleculeInfo.molecule, delegate, nil) + (moleculeCell as? ModelMoleculeViewProtocol)?.set(with: moleculeInfo.molecule, selfDelegateObject, nil) moleculeCell?.updateView(tableView.bounds.width) - + // Neded to fix an apple defect where the cell is not the correct size on certain devices for certain cells + cell.layoutIfNeeded() return cell } - open override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + open func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { if let protocolCell = cell as? MoleculeListCellProtocol { protocolCell.willDisplay() } } - open override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if let cell = tableView.cellForRow(at: indexPath) as? MoleculeListCellProtocol { cell.didSelectCell(at: indexPath, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, additionalData: nil) } } - //-------------------------------------------------- - // MARK: - Cache Handling - //-------------------------------------------------- - - open override func pageTypesToListenFor() -> [Any]? { - guard let pageType = self.pageType else { return super.pageTypesToListenFor() } - return [pageType] - } - - open override func modulesToListenFor() -> [Any]? { - return loadObject?.requestParameters?.modules - } - //-------------------------------------------------- // MARK: - MoleculeDelegateProtocol //-------------------------------------------------- @@ -178,76 +160,18 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } } - open override func addMolecules(_ molecules: [[AnyHashable : Any]], indexPath: IndexPath, animation: UITableView.RowAnimation) { - var tmpMolecules = [ListItemModelProtocol & MoleculeModelProtocol]() - - molecules.forEach { molecule in - if let data = try? JSONSerialization.data(withJSONObject: molecule), let listItemModel = try? JSONDecoder().decode(MoleculeListItemModel.self, from: data) { - tmpMolecules.append(listItemModel) - } - } - - DispatchQueue.main.async { - var indexPaths: [IndexPath] = [] - - for molecule in tmpMolecules { - if let info = self.getMoleculeInfo(with: molecule) { - self.tableView?.register(info.class, forCellReuseIdentifier: info.identifier) - let index = indexPath.row + 1 + indexPaths.count - self.moleculesInfo?.insert(info, at: index) - indexPaths.append(IndexPath(row: index, section: 0)) - } - } - - self.tableView?.insertRows(at: indexPaths, with: animation) - self.updateViewConstraints() - self.view.layoutIfNeeded() - } + open override func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? { + guard let index = moleculesInfo?.firstIndex(where: { (moleculeInfo) -> Bool in + //TODO: check for molecule protocola eqaulity + let json = moleculeInfo.molecule.toJSON() + return json == molecule.toJSON() + }) else { return nil } + return IndexPath(row: index, section: 0) } - open override func addMolecules(_ molecules: [[AnyHashable: Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { - - DispatchQueue.main.async { [weak self] in - guard let indexPath = self?.tableView?.indexPath(for: sender) else { return } - DispatchQueue.global().async { - self?.addMolecules(molecules, indexPath: indexPath, animation: animation) - } - } - } - - open override func removeMolecules(_ molecules: [[AnyHashable: Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { - - var tmpMolecules = [ListItemModelProtocol & MoleculeModelProtocol]() - - molecules.forEach { molecule in - if let data = try? JSONSerialization.data(withJSONObject: molecule), - let listItemModel = try? JSONDecoder().decode(MoleculeListItemModel.self, from: data) { - tmpMolecules.append(listItemModel) - } - } - - var indexPaths: [IndexPath] = [] - - //TODO: cehck for molecule protocola eqality - - for molecule in tmpMolecules { - if let removeIndex = moleculesInfo?.firstIndex(where: { molecule.toJSON() == $0.molecule.toJSON() }) { - - moleculesInfo?.remove(at: removeIndex) - indexPaths.append(IndexPath(row: removeIndex + indexPaths.count, section: 0)) - } - } - - tableView?.deleteRows(at: indexPaths, with: animation) - updateViewConstraints() - view.layoutIfNeeded() - } - - open func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { - + open override func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) { // This dispatch is needed to fix a race condition that can occur if this function is called during the table setup. DispatchQueue.main.async { - guard let indexPath = self.tableView?.indexPath(for: sender) else { return } var indexPaths: [IndexPath] = [] for molecule in molecules { @@ -259,16 +183,16 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } } + guard indexPaths.count > 0 else { return } self.tableView?.insertRows(at: indexPaths, with: animation) self.updateViewConstraints() self.view.layoutIfNeeded() } } - open func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { - + open override func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) { var indexPaths: [IndexPath] = [] - //TODO: cehck for molecule protocola eqality + //TODO: check for molecule protocola equality for molecule in molecules { if let removeIndex = moleculesInfo?.firstIndex(where: { molecule.toJSON() == $0.molecule.toJSON() }) { @@ -277,6 +201,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } } + guard indexPaths.count > 0 else { return } tableView?.deleteRows(at: indexPaths, with: animation) updateViewConstraints() view.layoutIfNeeded() @@ -290,10 +215,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol func getMoleculeInfo(with listItem: (ListItemModelProtocol & MoleculeModelProtocol)?) -> (identifier: String, class: AnyClass, molecule: ListItemModelProtocol & MoleculeModelProtocol)? { guard let listItem = listItem, - let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(listItem), - let moleculeName = (moleculeClass as? ModelMoleculeViewProtocol.Type)?.nameForReuse(with: listItem, delegateObject() as? MVMCoreUIDelegateObject) ?? listItem.moleculeName - else { return nil } - + let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(listItem) else { return nil } + let moleculeName = (moleculeClass as? ModelMoleculeViewProtocol.Type)?.nameForReuse(with: listItem, delegateObject() as? MVMCoreUIDelegateObject) ?? listItem.moleculeName return (moleculeName, moleculeClass, listItem) } diff --git a/MVMCoreUI/Templates/MoleculeStackTemplate.swift b/MVMCoreUI/Templates/MoleculeStackTemplate.swift index e05a067a..c8d807cc 100644 --- a/MVMCoreUI/Templates/MoleculeStackTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeStackTemplate.swift @@ -9,15 +9,12 @@ import UIKit open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol { - var observer: NSKeyValueObservation? public var templateModel: StackPageTemplateModel? - open override func parsePageJSON(_ error: NSErrorPointer) { - do { - try parseTemplateJSON() - } catch let parseError { - error?.pointee = parseError as NSError - } + + open override func parsePageJSON() throws { + try parseTemplate(json: loadObject?.pageJSON) + try super.parsePageJSON() } open override var loadObject: MVMCoreLoadObject? { @@ -68,17 +65,7 @@ open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol { } // MARK: - cache handling - open override func pageTypesToListenFor() -> [Any]? { - guard let pageType = self.pageType else { - return super.pageTypesToListenFor() - } - return [pageType] - } - - open override func modulesToListenFor() -> [Any]? { - return loadObject?.requestParameters?.modules - } - + /// Adds modules from requiredModules() to the MVMCoreViewControllerMapping.requiredModules map. open func updateRequiredModules() { if let requiredModules = requiredModules(), let pageType = pageType { diff --git a/MVMCoreUI/Templates/StackCenteredPageTemplateModel.swift b/MVMCoreUI/Templates/StackCenteredPageTemplateModel.swift index 86c09b6d..22934239 100644 --- a/MVMCoreUI/Templates/StackCenteredPageTemplateModel.swift +++ b/MVMCoreUI/Templates/StackCenteredPageTemplateModel.swift @@ -8,10 +8,43 @@ import Foundation -@objcMembers public class StackCenteredPageTemplateModel: TemplateModelProtocol { +@objcMembers public class StackCenteredPageTemplateModel: MVMControllerModelProtocol { + + 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 var navigationItem: (NavigationItemModelProtocol & MoleculeModelProtocol)? + + public init(pageType: String) { + self.pageType = pageType + } + + private enum CodingKeys: String, CodingKey { + case pageType + case template + case screenHeading + case isAtomicTabs + case formRules + } + + 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) + formRules = try typeContainer.decodeIfPresent([FormGroupRule].self, forKey: .formRules) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(pageType, forKey: .pageType) + try container.encode(template, forKey: .template) + try container.encodeIfPresent(screenHeading, forKey: .screenHeading) + try container.encodeIfPresent(isAtomicTabs, forKey: .isAtomicTabs) + try container.encodeIfPresent(formRules, forKey: .formRules) + } } diff --git a/MVMCoreUI/Templates/StackPageTemplateModel.swift b/MVMCoreUI/Templates/StackPageTemplateModel.swift index 0eddf030..09045995 100644 --- a/MVMCoreUI/Templates/StackPageTemplateModel.swift +++ b/MVMCoreUI/Templates/StackPageTemplateModel.swift @@ -9,47 +9,43 @@ import Foundation -@objcMembers public class StackPageTemplateModel: TemplateModelProtocol { - public static var identifier: String = "stack" - - public var pageType: String - public var screenHeading: String? - public var isAtomicTabs: Bool? +@objcMembers public class StackPageTemplateModel: TemplateModel { + public override class var identifier: String { + return "stack" + } public var header: MoleculeModelProtocol? public var moleculeStack: MoleculeStackModel public var footer: MoleculeModelProtocol? public init(pageType: String, moleculeStack: MoleculeStackModel) { - self.pageType = pageType self.moleculeStack = moleculeStack + super.init(pageType: pageType) } private enum CodingKeys: String, CodingKey { case pageType + case template case screenHeading case header case footer case stack - 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) moleculeStack = try typeContainer.decode(MoleculeStackModel.self, forKey: .stack) - screenHeading = try typeContainer.decodeIfPresent(String.self, forKey: .screenHeading) - isAtomicTabs = try typeContainer.decodeIfPresent(Bool.self, forKey: .isAtomicTabs) header = try typeContainer.decodeModelIfPresent(codingKey: .header) footer = try typeContainer.decodeModelIfPresent(codingKey: .footer) + try super.init(from: decoder) } - public func encode(to encoder: Encoder) throws { + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(pageType, forKey: .pageType) + try container.encode(template, forKey: .template) try container.encode(moleculeStack, forKey: .stack) - try container.encodeIfPresent(screenHeading, forKey: .screenHeading) - try container.encodeIfPresent(isAtomicTabs, forKey: .isAtomicTabs) try container.encodeModelIfPresent(header, forKey: .header) try container.encodeModelIfPresent(footer, forKey: .footer) } diff --git a/MVMCoreUI/Templates/TemplateModel.swift b/MVMCoreUI/Templates/TemplateModel.swift new file mode 100644 index 00000000..786068d0 --- /dev/null +++ b/MVMCoreUI/Templates/TemplateModel.swift @@ -0,0 +1,50 @@ +// +// TemplateModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/13/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers public class TemplateModel: MVMControllerModelProtocol { + public class var identifier: String { + return "" + } + public var pageType: String + public var screenHeading: String? + public var isAtomicTabs: Bool? + public var navigationItem: (NavigationItemModelProtocol & MoleculeModelProtocol)? + public var formRules: [FormGroupRule]? + + public init(pageType: String) { + self.pageType = pageType + } + + private enum CodingKeys: String, CodingKey { + case pageType + case screenHeading + case isAtomicTabs + case formRules + case navigationItem + } + + 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) + formRules = try typeContainer.decodeIfPresent([FormGroupRule].self, forKey: .formRules) + navigationItem = try typeContainer.decodeModelIfPresent(codingKey: .navigationItem) + } + + 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) + try container.encodeIfPresent(formRules, forKey: .formRules) + try container.encodeModelIfPresent(navigationItem, forKey: .navigationItem) + } +} diff --git a/MVMCoreUI/Templates/TemplateProtocol.swift b/MVMCoreUI/Templates/TemplateProtocol.swift index 63c66263..4d494fe4 100644 --- a/MVMCoreUI/Templates/TemplateProtocol.swift +++ b/MVMCoreUI/Templates/TemplateProtocol.swift @@ -8,18 +8,19 @@ import Foundation + public protocol TemplateProtocol: class { 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 } +public extension TemplateProtocol where Self: ViewController { + func parseTemplate(json: [AnyHashable: Any]?) throws { + guard let pageJSON = json else { return } let data = try JSONSerialization.data(withJSONObject: pageJSON) let decoder = JSONDecoder() let templateModel = try decoder.decode(TemplateModel.self, from: data) self.templateModel = templateModel + self.pageModel = templateModel as? MVMControllerModelProtocol } } diff --git a/MVMCoreUI/Templates/ThreeLayerPageTemplateModel.swift b/MVMCoreUI/Templates/ThreeLayerPageTemplateModel.swift index 321b07a7..9ee830e2 100644 --- a/MVMCoreUI/Templates/ThreeLayerPageTemplateModel.swift +++ b/MVMCoreUI/Templates/ThreeLayerPageTemplateModel.swift @@ -8,12 +8,17 @@ import Foundation -@objcMembers public class ThreeLayerPageTemplateModel: TemplateModelProtocol { +@objcMembers public class ThreeLayerPageTemplateModel: MVMControllerModelProtocol { + + public var formRules: [FormGroupRule]? + public var formValidator: FormValidator? + public static var identifier: String = "threeLayer" public var pageType: String public var screenHeading: String? public var isAtomicTabs: Bool? + public var navigationItem: (NavigationItemModelProtocol & MoleculeModelProtocol)? public var header: MoleculeModelProtocol? public var middle: MoleculeModelProtocol? @@ -28,11 +33,13 @@ import Foundation private enum CodingKeys: String, CodingKey { case pageType + case template case screenHeading case header case footer case middle case isAtomicTabs + case formRules } required public init(from decoder: Decoder) throws { @@ -43,15 +50,18 @@ import Foundation header = try typeContainer.decodeModelIfPresent(codingKey: .header) middle = try typeContainer.decodeModelIfPresent(codingKey: .middle) footer = try typeContainer.decodeModelIfPresent(codingKey: .footer) + formRules = try typeContainer.decodeIfPresent([FormGroupRule].self, forKey: .formRules) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(pageType, forKey: .pageType) + try container.encode(template, forKey: .template) try container.encodeIfPresent(screenHeading, forKey: .screenHeading) try container.encodeIfPresent(isAtomicTabs, forKey: .isAtomicTabs) try container.encodeModelIfPresent(header, forKey: .header) try container.encodeModelIfPresent(header, forKey: .middle) try container.encodeModelIfPresent(footer, forKey: .footer) + try container.encodeIfPresent(formRules, forKey: .formRules) } } diff --git a/MVMCoreUI/Templates/ThreeLayerTemplate.swift b/MVMCoreUI/Templates/ThreeLayerTemplate.swift index eb822279..ba35c971 100644 --- a/MVMCoreUI/Templates/ThreeLayerTemplate.swift +++ b/MVMCoreUI/Templates/ThreeLayerTemplate.swift @@ -9,15 +9,11 @@ import UIKit @objcMembers open class ThreeLayerTemplate: ThreeLayerViewController, TemplateProtocol { - public var templateModel: ThreeLayerPageTemplateModel? - open override func parsePageJSON(_ error: NSErrorPointer) { - do { - try parseTemplateJSON() - } catch let parseError { - error?.pointee = parseError as NSError - } + open override func parsePageJSON() throws { + try parseTemplate(json: loadObject?.pageJSON) + try super.parsePageJSON() } override open func viewDidLoad() { @@ -26,8 +22,8 @@ import UIKit // Do any additional setup after loading the view. } - open override func newDataBuildScreen() { - super.newDataBuildScreen() + open override func handleNewData() { + super.handleNewData() heightConstraint?.isActive = true } diff --git a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility+Extension.swift b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility+Extension.swift new file mode 100644 index 00000000..3ee452b0 --- /dev/null +++ b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility+Extension.swift @@ -0,0 +1,23 @@ +// +// MVMCoreUICommonViewsUtility+Extension.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/23/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public extension MVMCoreUICommonViewsUtility { + + static func getToolbarWithDoneButton(delegate: ObservingTextFieldDelegate) -> UIToolbar { + + let toolbar = self.makeEmptyToolbar() + let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) + let button = UIBarButtonItem(barButtonSystemItem: .done, target: delegate, action: #selector(ObservingTextFieldDelegate.dismissFieldInput(sender:))) + button.tintColor = .black + toolbar.setItems([space, button], animated: false) + + return toolbar + } +} diff --git a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m index 4a21b1a5..5c796417 100644 --- a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m @@ -260,15 +260,15 @@ static const CGFloat VertialShadowOffset = 6; UIBezierPath *shadowPath = [UIBezierPath bezierPath]; //get the variables for frame - CGFloat x = 0; - CGFloat y = 0; + CGFloat x = rect.origin.x; + CGFloat y = rect.origin.y; CGFloat width = CGRectGetWidth(rect); CGFloat height = CGRectGetHeight(rect); [shadowPath moveToPoint:CGPointMake(x + HorizontalShadowInset, y)]; - [shadowPath addLineToPoint:CGPointMake(width - HorizontalShadowInset, y)]; - [shadowPath addLineToPoint:CGPointMake(width - HorizontalShadowInset, height-VertialShadowOffset/2)]; - [shadowPath addQuadCurveToPoint:CGPointMake(x + HorizontalShadowInset, height - VertialShadowOffset/2) controlPoint:CGPointMake(width/2.f, height - VertialShadowOffset * 1.5)]; + [shadowPath addLineToPoint:CGPointMake(x + width - HorizontalShadowInset, y)]; + [shadowPath addLineToPoint:CGPointMake(x + width - HorizontalShadowInset, height-VertialShadowOffset/2)]; + [shadowPath addQuadCurveToPoint:CGPointMake(x + HorizontalShadowInset, height - VertialShadowOffset/2) controlPoint:CGPointMake((x + width)/2.f, height - VertialShadowOffset * 1.5)]; [shadowPath addLineToPoint:CGPointMake(x + HorizontalShadowInset, y)]; [shadowPath closePath]; diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.h b/MVMCoreUI/Utility/MVMCoreUIUtility.h index 9300de90..21c92c38 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.h +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.h @@ -31,6 +31,9 @@ NS_ASSUME_NONNULL_BEGIN // Returns the margins for a view. + (UIEdgeInsets)getMarginsForView:(nullable UIView *)view; +/// Gets the current visible view controller. Checks presented view controllers first, and then it checks on the NavigationController in the session object. ++ (UIViewController *)getCurrentVisibleController; + #pragma mark - Setters + (void)setMarginsForView:(nullable UIView *)view leading:(CGFloat)leading top:(CGFloat)top trailing:(CGFloat)trailing bottom:(CGFloat)bottom; diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.m b/MVMCoreUI/Utility/MVMCoreUIUtility.m index b760eb36..4b0278de 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.m @@ -10,6 +10,7 @@ #import "MVMCoreUIConstants.h" #import "MVMCoreUISession.h" #import "MVMCoreUISplitViewController.h" +#import @import MVMCore.MVMCoreNavigationHandler; @import MVMCore.MVMCoreGetterUtility; @@ -60,6 +61,26 @@ return UIEdgeInsetsMake(view.directionalLayoutMargins.top, view.directionalLayoutMargins.leading, view.directionalLayoutMargins.bottom, view.directionalLayoutMargins.trailing); } ++ (UIViewController *)getCurrentVisibleController { + UIViewController *baseViewController = [MVMCoreNavigationHandler sharedNavigationHandler].viewControllerToPresentOn ?: [UIApplication sharedApplication].keyWindow.rootViewController; + UIViewController *viewController = nil; + while (baseViewController.presentedViewController && !baseViewController.presentedViewController.isBeingDismissed) { + viewController = baseViewController.presentedViewController; + baseViewController = viewController; + } + if ([viewController isKindOfClass:[UINavigationController class]]) { + viewController = ((UINavigationController *)viewController).topViewController; + } + // if it is not presented viewcontroller, existing BAU logic will be working + if (!viewController) { + viewController = [MVMCoreUISession sharedGlobal].navigationController.topViewController; + if ([viewController conformsToProtocol:@protocol(MVMCoreViewManagerProtocol)]) { + viewController = [viewController performSelector:@selector(getCurrentViewController)]; + } + } + return viewController; +} + #pragma mark - Setters + (void)setMarginsForView:(nullable UIView *)view leading:(CGFloat)leading top:(CGFloat)top trailing:(CGFloat)trailing bottom:(CGFloat)bottom {