Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into bugfix/scripts
This commit is contained in:
commit
4a695b7430
@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 48;
|
||||
objectVersion = 52;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@ -61,6 +61,10 @@
|
||||
01EB369323609801006832FA /* HeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368C23609801006832FA /* HeaderModel.swift */; };
|
||||
01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368D23609801006832FA /* HeadlineBodyModel.swift */; };
|
||||
01F2A03223A4498200D954D8 /* CaretLinkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2A03123A4498200D954D8 /* CaretLinkModel.swift */; };
|
||||
01F2C20227C81F9700DC3D36 /* SubNavManagerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2C1FE27C81F9700DC3D36 /* SubNavManagerController.swift */; };
|
||||
01F2C20327C81F9700DC3D36 /* SubNavManagerNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2C1FF27C81F9700DC3D36 /* SubNavManagerNavigationController.swift */; };
|
||||
01F2C20427C81F9700DC3D36 /* SubNavInteractor.swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2C20027C81F9700DC3D36 /* SubNavInteractor.swift.swift */; };
|
||||
01F2C20527C81F9700DC3D36 /* SubNavSwipeAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F2C20127C81F9700DC3D36 /* SubNavSwipeAnimator.swift */; };
|
||||
0A0FEC7425D42A5E00AF2548 /* BaseItemPickerEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A0FEC7325D42A5E00AF2548 /* BaseItemPickerEntryField.swift */; };
|
||||
0A0FEC7825D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A0FEC7725D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift */; };
|
||||
0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; };
|
||||
@ -122,6 +126,7 @@
|
||||
0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB423FF18D2004C5109 /* Arrow.swift */; };
|
||||
0AE98BB723FF18E9004C5109 /* ArrowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB623FF18E9004C5109 /* ArrowModel.swift */; };
|
||||
0AF60F0926B3316E00AC3DB4 /* MVMCoreUIUtility+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AF60F0826B3316E00AC3DB4 /* MVMCoreUIUtility+Extension.swift */; };
|
||||
187FEB2A2844D2A600BF29C2 /* VDSFormControlsTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 187FEB292844D2A600BF29C2 /* VDSFormControlsTokens.xcframework */; };
|
||||
1D6D258826899B0C00DEBB08 /* ImageButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6D258626899B0B00DEBB08 /* ImageButtonModel.swift */; };
|
||||
1D6D258926899B0C00DEBB08 /* ImageButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6D258726899B0B00DEBB08 /* ImageButton.swift */; };
|
||||
279B1569242BBC2F00921D6C /* ActionModelAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279B1568242BBC2F00921D6C /* ActionModelAdapter.swift */; };
|
||||
@ -141,6 +146,9 @@
|
||||
32D2609724C19E2100B56344 /* LockupsPlanSMLXLModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32D2609524C19E2100B56344 /* LockupsPlanSMLXLModel.swift */; };
|
||||
32F8804624765C6E00C2ACB3 /* ListLeftVariableNumberedListAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32F8804524765C6E00C2ACB3 /* ListLeftVariableNumberedListAllTextAndLinksModel.swift */; };
|
||||
32F8804824765C8400C2ACB3 /* ListLeftVariableNumberedListAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32F8804724765C8400C2ACB3 /* ListLeftVariableNumberedListAllTextAndLinks.swift */; };
|
||||
444FB7C12821B73200DFE692 /* TitleLockup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 444FB7C02821B73200DFE692 /* TitleLockup.swift */; };
|
||||
444FB7C32821B76B00DFE692 /* TitleLockupModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 444FB7C22821B76B00DFE692 /* TitleLockupModel.swift */; };
|
||||
4457904E27ECE989002B1E1E /* UIImageRenderingMode+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4457904D27ECE989002B1E1E /* UIImageRenderingMode+Extension.swift */; };
|
||||
522679C123FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522679BF23FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift */; };
|
||||
522679C223FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522679C023FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinksModel.swift */; };
|
||||
52267A0723FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52267A0623FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift */; };
|
||||
@ -268,6 +276,8 @@
|
||||
AAE7270E24AC8B9300A3ED0E /* HeadersH2CaretLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE7270D24AC8B9300A3ED0E /* HeadersH2CaretLink.swift */; };
|
||||
AAE96FA225341F6A0037A989 /* ListStoreLocatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE96FA125341F6A0037A989 /* ListStoreLocatorModel.swift */; };
|
||||
AAE96FA525341F7D0037A989 /* ListStoreLocator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE96FA425341F7D0037A989 /* ListStoreLocator.swift */; };
|
||||
AFE4A1D127DFB5EE00C458D0 /* VDSColorTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = AFE4A1D027DFB5EE00C458D0 /* VDSColorTokens.xcframework */; };
|
||||
AFE4A1D627DFBB6F00C458D0 /* UINavigationController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */; };
|
||||
BB105859248DEFF70069D008 /* UICollectionViewLeftAlignedLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB105858248DEFF60069D008 /* UICollectionViewLeftAlignedLayout.swift */; };
|
||||
BB1D17E0244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1D17DF244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift */; };
|
||||
BB1D17E2244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1D17E1244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift */; };
|
||||
@ -341,7 +351,7 @@
|
||||
D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */; };
|
||||
D22479962316AF6E003FCCF9 /* HeadlineBodyLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479952316AF6D003FCCF9 /* HeadlineBodyLink.swift */; };
|
||||
D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */; };
|
||||
D22D8393241C27B100D3DF69 /* TemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22D8392241C27B100D3DF69 /* TemplateModel.swift */; };
|
||||
D22D8393241C27B100D3DF69 /* BaseTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22D8392241C27B100D3DF69 /* BaseTemplateModel.swift */; };
|
||||
D22D8395241FB41200D3DF69 /* UIStackView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22D8394241FB41200D3DF69 /* UIStackView+Extension.swift */; };
|
||||
D23118B325124E18001C8440 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D23118B225124E18001C8440 /* Notification.swift */; };
|
||||
D2351C7A24A4D433007DF0BC /* ListRightVariableToggleAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2351C7924A4D433007DF0BC /* ListRightVariableToggleAllTextAndLinksModel.swift */; };
|
||||
@ -569,8 +579,20 @@
|
||||
DBC4391922442197001AB423 /* DashLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391722442197001AB423 /* DashLine.swift */; };
|
||||
DBC4391B224421A0001AB423 /* CaretLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC4391A224421A0001AB423 /* CaretLink.swift */; };
|
||||
DBEFFA04225A829700230692 /* Label.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB891E822253FA8500022516 /* Label.swift */; };
|
||||
EA05EFA9278DDE2C00828819 /* ClearFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA05EFA8278DDE2C00828819 /* ClearFormFieldEffectModel.swift */; };
|
||||
EA05EFAB278DE53600828819 /* ClearableModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA05EFAA278DE53600828819 /* ClearableModelProtocol.swift */; };
|
||||
EA41F4AC2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA41F4AB2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift */; };
|
||||
EA5124FD243601600051A3A4 /* BGImageHeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FC243601600051A3A4 /* BGImageHeadlineBodyButton.swift */; };
|
||||
EA5124FF2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */; };
|
||||
EA7E67742758310500ABF773 /* EnableFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7E67732758310500ABF773 /* EnableFormFieldEffectModel.swift */; };
|
||||
EA7E67762758365300ABF773 /* UIUpdatableModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7E67752758365300ABF773 /* UIUpdatableModelProtocol.swift */; };
|
||||
EAA0CFAF275E7D8000D65EB0 /* FormFieldEffectProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA0CFAE275E7D8000D65EB0 /* FormFieldEffectProtocol.swift */; };
|
||||
EAA0CFB1275E823A00D65EB0 /* HideFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA0CFB0275E823A00D65EB0 /* HideFormFieldEffectModel.swift */; };
|
||||
EAA0CFB3275E831E00D65EB0 /* DisableFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA0CFB2275E831E00D65EB0 /* DisableFormFieldEffectModel.swift */; };
|
||||
EAB14BC127D935F00012AB2C /* RuleCompareModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB14BC027D935F00012AB2C /* RuleCompareModelProtocol.swift */; };
|
||||
EAB14BC327D9378D0012AB2C /* RuleAnyModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB14BC227D9378D0012AB2C /* RuleAnyModelProtocol.swift */; };
|
||||
EABFC1412763BB8D00E78B40 /* FormLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC1402763BB8D00E78B40 /* FormLabel.swift */; };
|
||||
EABFC152276913E800E78B40 /* FormLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC151276913E800E78B40 /* FormLabelModel.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@ -628,6 +650,10 @@
|
||||
01EB368C23609801006832FA /* HeaderModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderModel.swift; sourceTree = "<group>"; };
|
||||
01EB368D23609801006832FA /* HeadlineBodyModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeadlineBodyModel.swift; sourceTree = "<group>"; };
|
||||
01F2A03123A4498200D954D8 /* CaretLinkModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaretLinkModel.swift; sourceTree = "<group>"; };
|
||||
01F2C1FE27C81F9700DC3D36 /* SubNavManagerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubNavManagerController.swift; sourceTree = "<group>"; };
|
||||
01F2C1FF27C81F9700DC3D36 /* SubNavManagerNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubNavManagerNavigationController.swift; sourceTree = "<group>"; };
|
||||
01F2C20027C81F9700DC3D36 /* SubNavInteractor.swift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubNavInteractor.swift.swift; sourceTree = "<group>"; };
|
||||
01F2C20127C81F9700DC3D36 /* SubNavSwipeAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubNavSwipeAnimator.swift; sourceTree = "<group>"; };
|
||||
0A0FEC7325D42A5E00AF2548 /* BaseItemPickerEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseItemPickerEntryField.swift; sourceTree = "<group>"; };
|
||||
0A0FEC7725D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseItemPickerEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||
0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = "<group>"; };
|
||||
@ -691,6 +717,7 @@
|
||||
0AE98BB423FF18D2004C5109 /* Arrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arrow.swift; sourceTree = "<group>"; };
|
||||
0AE98BB623FF18E9004C5109 /* ArrowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowModel.swift; sourceTree = "<group>"; };
|
||||
0AF60F0826B3316E00AC3DB4 /* MVMCoreUIUtility+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUIUtility+Extension.swift"; sourceTree = "<group>"; };
|
||||
187FEB292844D2A600BF29C2 /* VDSFormControlsTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSFormControlsTokens.xcframework; path = ../SharedFrameworks/VDSFormControlsTokens.xcframework; sourceTree = "<group>"; };
|
||||
1D6D258626899B0B00DEBB08 /* ImageButtonModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageButtonModel.swift; path = MVMCoreUI/Atomic/Atoms/Buttons/ImageButtonModel.swift; sourceTree = SOURCE_ROOT; };
|
||||
1D6D258726899B0B00DEBB08 /* ImageButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageButton.swift; path = MVMCoreUI/Atomic/Atoms/Buttons/ImageButton.swift; sourceTree = SOURCE_ROOT; };
|
||||
279B1568242BBC2F00921D6C /* ActionModelAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionModelAdapter.swift; sourceTree = "<group>"; };
|
||||
@ -710,6 +737,9 @@
|
||||
32D2609524C19E2100B56344 /* LockupsPlanSMLXLModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockupsPlanSMLXLModel.swift; sourceTree = "<group>"; };
|
||||
32F8804524765C6E00C2ACB3 /* ListLeftVariableNumberedListAllTextAndLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableNumberedListAllTextAndLinksModel.swift; sourceTree = "<group>"; };
|
||||
32F8804724765C8400C2ACB3 /* ListLeftVariableNumberedListAllTextAndLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableNumberedListAllTextAndLinks.swift; sourceTree = "<group>"; };
|
||||
444FB7C02821B73200DFE692 /* TitleLockup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockup.swift; sourceTree = "<group>"; };
|
||||
444FB7C22821B76B00DFE692 /* TitleLockupModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockupModel.swift; sourceTree = "<group>"; };
|
||||
4457904D27ECE989002B1E1E /* UIImageRenderingMode+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImageRenderingMode+Extension.swift"; sourceTree = "<group>"; };
|
||||
522679BF23FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableCheckboxAllTextAndLinks.swift; sourceTree = "<group>"; };
|
||||
522679C023FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinksModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableCheckboxAllTextAndLinksModel.swift; sourceTree = "<group>"; };
|
||||
52267A0623FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextAllTextAndLinks.swift; sourceTree = "<group>"; };
|
||||
@ -837,6 +867,8 @@
|
||||
AAE7270D24AC8B9300A3ED0E /* HeadersH2CaretLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2CaretLink.swift; sourceTree = "<group>"; };
|
||||
AAE96FA125341F6A0037A989 /* ListStoreLocatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStoreLocatorModel.swift; sourceTree = "<group>"; };
|
||||
AAE96FA425341F7D0037A989 /* ListStoreLocator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStoreLocator.swift; sourceTree = "<group>"; };
|
||||
AFE4A1D027DFB5EE00C458D0 /* VDSColorTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSColorTokens.xcframework; path = ../SharedFrameworks/VDSColorTokens.xcframework; sourceTree = "<group>"; };
|
||||
AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationController+Extension.swift"; sourceTree = "<group>"; };
|
||||
BB105858248DEFF60069D008 /* UICollectionViewLeftAlignedLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UICollectionViewLeftAlignedLayout.swift; sourceTree = "<group>"; };
|
||||
BB1D17DF244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListDeviceComplexButtonMediumModel.swift; sourceTree = "<group>"; };
|
||||
BB1D17E1244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListDeviceComplexButtonMedium.swift; sourceTree = "<group>"; };
|
||||
@ -910,7 +942,7 @@
|
||||
D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutConstraintExtension.swift; sourceTree = "<group>"; };
|
||||
D22479952316AF6D003FCCF9 /* HeadlineBodyLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyLink.swift; sourceTree = "<group>"; };
|
||||
D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccordionMoleculeTableViewCell.swift; sourceTree = "<group>"; };
|
||||
D22D8392241C27B100D3DF69 /* TemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateModel.swift; sourceTree = "<group>"; };
|
||||
D22D8392241C27B100D3DF69 /* BaseTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTemplateModel.swift; sourceTree = "<group>"; };
|
||||
D22D8394241FB41200D3DF69 /* UIStackView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIStackView+Extension.swift"; sourceTree = "<group>"; };
|
||||
D23118B225124E18001C8440 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = "<group>"; };
|
||||
D2351C7924A4D433007DF0BC /* ListRightVariableToggleAllTextAndLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableToggleAllTextAndLinksModel.swift; sourceTree = "<group>"; };
|
||||
@ -1139,8 +1171,20 @@
|
||||
DBC4391622442196001AB423 /* CaretView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretView.swift; sourceTree = "<group>"; };
|
||||
DBC4391722442197001AB423 /* DashLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashLine.swift; sourceTree = "<group>"; };
|
||||
DBC4391A224421A0001AB423 /* CaretLink.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretLink.swift; sourceTree = "<group>"; };
|
||||
EA05EFA8278DDE2C00828819 /* ClearFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearFormFieldEffectModel.swift; sourceTree = "<group>"; };
|
||||
EA05EFAA278DE53600828819 /* ClearableModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearableModelProtocol.swift; sourceTree = "<group>"; };
|
||||
EA41F4AB2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicRuleFormFieldEffectModel.swift; sourceTree = "<group>"; };
|
||||
EA5124FC243601600051A3A4 /* BGImageHeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButton.swift; sourceTree = "<group>"; };
|
||||
EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButtonModel.swift; sourceTree = "<group>"; };
|
||||
EA7E67732758310500ABF773 /* EnableFormFieldEffectModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnableFormFieldEffectModel.swift; sourceTree = "<group>"; };
|
||||
EA7E67752758365300ABF773 /* UIUpdatableModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIUpdatableModelProtocol.swift; sourceTree = "<group>"; };
|
||||
EAA0CFAE275E7D8000D65EB0 /* FormFieldEffectProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormFieldEffectProtocol.swift; sourceTree = "<group>"; };
|
||||
EAA0CFB0275E823A00D65EB0 /* HideFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HideFormFieldEffectModel.swift; sourceTree = "<group>"; };
|
||||
EAA0CFB2275E831E00D65EB0 /* DisableFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisableFormFieldEffectModel.swift; sourceTree = "<group>"; };
|
||||
EAB14BC027D935F00012AB2C /* RuleCompareModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleCompareModelProtocol.swift; sourceTree = "<group>"; };
|
||||
EAB14BC227D9378D0012AB2C /* RuleAnyModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyModelProtocol.swift; sourceTree = "<group>"; };
|
||||
EABFC1402763BB8D00E78B40 /* FormLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormLabel.swift; sourceTree = "<group>"; };
|
||||
EABFC151276913E800E78B40 /* FormLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormLabelModel.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -1149,7 +1193,9 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */,
|
||||
AFE4A1D127DFB5EE00C458D0 /* VDSColorTokens.xcframework in Frameworks */,
|
||||
9455B19C234F8A0400A574DB /* MVMAnimationFramework.framework in Frameworks */,
|
||||
187FEB2A2844D2A600BF29C2 /* VDSFormControlsTokens.xcframework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1165,6 +1211,7 @@
|
||||
D23EA7FA2475F09800D60C34 /* CarouselItemProtocol.swift */,
|
||||
012A88C3238D86E600FE3DA1 /* CarouselItemModelProtocol.swift */,
|
||||
012A88B0238C880100FE3DA1 /* CarouselPagingModelProtocol.swift */,
|
||||
EA05EFAA278DE53600828819 /* ClearableModelProtocol.swift */,
|
||||
01EB3683236097C0006832FA /* MoleculeModelProtocol.swift */,
|
||||
012A889B23889E8400FE3DA1 /* TemplateModelProtocol.swift */,
|
||||
D28A837823C7D5BC00DFE4FC /* PageModelProtocol.swift */,
|
||||
@ -1183,12 +1230,14 @@
|
||||
children = (
|
||||
011D95A4240455DC000E3791 /* FormGroupRule.swift */,
|
||||
011D958424042432000E3791 /* RulesProtocol.swift */,
|
||||
011D959A240451E3000E3791 /* RuleRequiredModel.swift */,
|
||||
011D959C2404536F000E3791 /* RuleAnyValueChangedModel.swift */,
|
||||
EAB14BC227D9378D0012AB2C /* RuleAnyModelProtocol.swift */,
|
||||
EAB14BC027D935F00012AB2C /* RuleCompareModelProtocol.swift */,
|
||||
011D959E240453A1000E3791 /* RuleAllValueChangedModel.swift */,
|
||||
011D95A0240453D0000E3791 /* RuleEqualsModel.swift */,
|
||||
011D959A240451E3000E3791 /* RuleRequiredModel.swift */,
|
||||
011D95A2240453F8000E3791 /* RuleRegexModel.swift */,
|
||||
011D959C2404536F000E3791 /* RuleAnyValueChangedModel.swift */,
|
||||
0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */,
|
||||
011D95A0240453D0000E3791 /* RuleEqualsModel.swift */,
|
||||
0A849EFD246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift */,
|
||||
);
|
||||
name = Rules;
|
||||
@ -1206,6 +1255,7 @@
|
||||
01C74D87224298E2009C25A3 /* FormUIHelpers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EAA0CFAD275E7D5A00D65EB0 /* FormFieldEffect */,
|
||||
011D95882404249B000E3791 /* FormHolderModelProtocol.swift */,
|
||||
011D95AC2406BB57000E3791 /* FormHolderProtocol.swift */,
|
||||
011D95AA2405C553000E3791 /* FormItemProtocol.swift */,
|
||||
@ -1213,11 +1263,31 @@
|
||||
011D95A824057AC7000E3791 /* FormGroupWatcherFieldProtocol.swift */,
|
||||
011D9601240DA20A000E3791 /* FormRuleWatcherFieldProtocol.swift */,
|
||||
0105618A224BBE7700E1557D /* FormValidator.swift */,
|
||||
EA7E67752758365300ABF773 /* UIUpdatableModelProtocol.swift */,
|
||||
011D958A24042794000E3791 /* Rules */,
|
||||
);
|
||||
path = FormUIHelpers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
01F2C1FC27C81F9700DC3D36 /* Managers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
01F2C1FD27C81F9700DC3D36 /* SubNav */,
|
||||
);
|
||||
path = Managers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
01F2C1FD27C81F9700DC3D36 /* SubNav */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
01F2C1FE27C81F9700DC3D36 /* SubNavManagerController.swift */,
|
||||
01F2C1FF27C81F9700DC3D36 /* SubNavManagerNavigationController.swift */,
|
||||
01F2C20027C81F9700DC3D36 /* SubNavInteractor.swift.swift */,
|
||||
01F2C20127C81F9700DC3D36 /* SubNavSwipeAnimator.swift */,
|
||||
);
|
||||
path = SubNav;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0A0FEC7125D4246000AF2548 /* Dropdown Fields */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -1368,6 +1438,8 @@
|
||||
525019DC2406430800EED91C /* ListProgressBarData.swift */,
|
||||
AA45AA0A24BF0263007A6EA7 /* LockUpsPlanNamesModel.swift */,
|
||||
AA45AA0C24BF0276007A6EA7 /* LockUpsPlanNames.swift */,
|
||||
444FB7C22821B76B00DFE692 /* TitleLockupModel.swift */,
|
||||
444FB7C02821B73200DFE692 /* TitleLockup.swift */,
|
||||
);
|
||||
path = LockUps;
|
||||
sourceTree = "<group>";
|
||||
@ -1428,6 +1500,8 @@
|
||||
94C2D9A823872E5E0006CF46 /* LabelAttributeImageModel.swift */,
|
||||
94C2D9AA23872EB50006CF46 /* LabelAttributeActionModel.swift */,
|
||||
DB891E822253FA8500022516 /* Label.swift */,
|
||||
EABFC151276913E800E78B40 /* FormLabelModel.swift */,
|
||||
EABFC1402763BB8D00E78B40 /* FormLabel.swift */,
|
||||
);
|
||||
path = Label;
|
||||
sourceTree = "<group>";
|
||||
@ -1477,6 +1551,15 @@
|
||||
path = Miscellaneous;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
AFE4A1D427DFBB2700C458D0 /* NavigationController */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D2B18B93236214AD00A9AEDC /* NavigationController.swift */,
|
||||
AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */,
|
||||
);
|
||||
path = NavigationController;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D202AFE2242A5F1400E5BEDF /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -1491,6 +1574,7 @@
|
||||
D2ED27E6254B0CE600A1C293 /* UIAlertActionStyle+Codable.swift */,
|
||||
D2ED27E7254B0CE600A1C293 /* UIAlertControllerStyle+Extension.swift */,
|
||||
D2E0FFF726AF68530085D696 /* UITableViewRowAnimation+Extension.swift */,
|
||||
4457904D27ECE989002B1E1E /* UIImageRenderingMode+Extension.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
@ -1886,6 +1970,7 @@
|
||||
D29DF0CE21E404D4003B2FB9 /* MVMCoreUI */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
01F2C1FC27C81F9700DC3D36 /* Managers */,
|
||||
D2ED27D8254B0C1F00A1C293 /* Alerts */,
|
||||
27F973512466071600CAB5C5 /* Behaviors */,
|
||||
D2C78CD324252F4E00B69FDE /* Atomic */,
|
||||
@ -1910,7 +1995,7 @@
|
||||
D29DF0DF21E418B2003B2FB9 /* Templates */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D22D8392241C27B100D3DF69 /* TemplateModel.swift */,
|
||||
D22D8392241C27B100D3DF69 /* BaseTemplateModel.swift */,
|
||||
D2092356244FA1EF0044AD09 /* ThreeLayerModelBase.swift */,
|
||||
014AA72823C5059B006F3E93 /* StackPageTemplateModel.swift */,
|
||||
D2A5146022121FBF00345BFB /* MoleculeStackTemplate.swift */,
|
||||
@ -1943,6 +2028,8 @@
|
||||
D29DF0E421E4F3C7003B2FB9 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
187FEB292844D2A600BF29C2 /* VDSFormControlsTokens.xcframework */,
|
||||
AFE4A1D027DFB5EE00C458D0 /* VDSColorTokens.xcframework */,
|
||||
D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */,
|
||||
9455B19B234F8A0400A574DB /* MVMAnimationFramework.framework */,
|
||||
);
|
||||
@ -2013,9 +2100,9 @@
|
||||
D29DF11921E68467003B2FB9 /* Containers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AFE4A1D427DFBB2700C458D0 /* NavigationController */,
|
||||
0ABD1369237B18EE0081388D /* Views */,
|
||||
D29DF2B621E7BE66003B2FB9 /* SplitViewController */,
|
||||
D2B18B93236214AD00A9AEDC /* NavigationController.swift */,
|
||||
);
|
||||
path = Containers;
|
||||
sourceTree = "<group>";
|
||||
@ -2400,6 +2487,19 @@
|
||||
path = Alerts;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EAA0CFAD275E7D5A00D65EB0 /* FormFieldEffect */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EAA0CFAE275E7D8000D65EB0 /* FormFieldEffectProtocol.swift */,
|
||||
EAA0CFB2275E831E00D65EB0 /* DisableFormFieldEffectModel.swift */,
|
||||
EA41F4AB2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift */,
|
||||
EA7E67732758310500ABF773 /* EnableFormFieldEffectModel.swift */,
|
||||
EAA0CFB0275E823A00D65EB0 /* HideFormFieldEffectModel.swift */,
|
||||
EA05EFA8278DDE2C00828819 /* ClearFormFieldEffectModel.swift */,
|
||||
);
|
||||
path = FormFieldEffect;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
@ -2538,6 +2638,7 @@
|
||||
324FB6AA249366F3002552C7 /* ListLeftVariableNumberedListBodyTextModel.swift in Sources */,
|
||||
5248BFED23F12E350059236A /* ListThreeColumnPlanDataDividerModel.swift in Sources */,
|
||||
AA0A257824766C8A00862F64 /* ListLeftVariableIconWithRightCaretBodyTextModel.swift in Sources */,
|
||||
EABFC152276913E800E78B40 /* FormLabelModel.swift in Sources */,
|
||||
0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */,
|
||||
0AF60F0926B3316E00AC3DB4 /* MVMCoreUIUtility+Extension.swift in Sources */,
|
||||
8D070BB0241B56530099AC56 /* ListRightVariableTotalDataModel.swift in Sources */,
|
||||
@ -2564,12 +2665,15 @@
|
||||
DBC4391922442197001AB423 /* DashLine.swift in Sources */,
|
||||
D2ED27FC254B0E0300A1C293 /* MVMCoreAlertObject+Swift.swift in Sources */,
|
||||
D264FAAA2440F97600D98315 /* CollectionView.swift in Sources */,
|
||||
AFE4A1D627DFBB6F00C458D0 /* UINavigationController+Extension.swift in Sources */,
|
||||
AAC23FAD24D92A0D009208DF /* ListThreeColumnSpeedTestModel.swift in Sources */,
|
||||
BBC0C4FF24811DCA0087C44F /* TagModel.swift in Sources */,
|
||||
01F2C20527C81F9700DC3D36 /* SubNavSwipeAnimator.swift in Sources */,
|
||||
0AE277EC25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift in Sources */,
|
||||
0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */,
|
||||
3265B30424BCA749000D154B /* HeadersH1NoButtonsBodyText.swift in Sources */,
|
||||
AAA7CD69250641F90045B959 /* HeartModel.swift in Sources */,
|
||||
444FB7C12821B73200DFE692 /* TitleLockup.swift in Sources */,
|
||||
D2FB151D23A40F1500C20E10 /* MoleculeStackItem.swift in Sources */,
|
||||
D28BA7452481652D00B75CB8 /* TabBarProtocol.swift in Sources */,
|
||||
AA11A41F23F15D3100D7962F /* ListRightVariablePayments.swift in Sources */,
|
||||
@ -2601,11 +2705,13 @@
|
||||
D29DF11721E6805F003B2FB9 /* UIColor+MFConvenience.m in Sources */,
|
||||
D2B18B7F2360913400A9AEDC /* Control.swift in Sources */,
|
||||
D253BB8A24574CC5002DE544 /* StackModel.swift in Sources */,
|
||||
EAB14BC127D935F00012AB2C /* RuleCompareModelProtocol.swift in Sources */,
|
||||
011D95A924057AC7000E3791 /* FormGroupWatcherFieldProtocol.swift in Sources */,
|
||||
BB2BF0EA2452A9BB001D0FC2 /* ListDeviceComplexButtonSmall.swift in Sources */,
|
||||
D20C700B250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift in Sources */,
|
||||
D236E5B4241FEB1000C38625 /* ListTwoColumnPriceDescription.swift in Sources */,
|
||||
0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */,
|
||||
EA7E67742758310500ABF773 /* EnableFormFieldEffectModel.swift in Sources */,
|
||||
D29DF12F21E6851E003B2FB9 /* MVMCoreUITopAlertMainView.m in Sources */,
|
||||
942C378C2412F4FA0066E45E /* ModalMoleculeListTemplate.swift in Sources */,
|
||||
BB47A588241615FA002BB23C /* ListOneColumnFullWidthTextDividerSubsection.swift in Sources */,
|
||||
@ -2748,6 +2854,7 @@
|
||||
D2CAC7CD251104FE00C75681 /* NotificationModel.swift in Sources */,
|
||||
D2ED2803254B0E0300A1C293 /* MVMCoreAlertHandler.m in Sources */,
|
||||
0A1B4A96233BB18F005B3FB4 /* CheckboxLabel.swift in Sources */,
|
||||
EAA0CFAF275E7D8000D65EB0 /* FormFieldEffectProtocol.swift in Sources */,
|
||||
D20923592450ECE00044AD09 /* TableView.swift in Sources */,
|
||||
BB47A586241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift in Sources */,
|
||||
AA69AAF82445BF6800AF3D3B /* ListLeftVariableCheckboxBodyTextModel.swift in Sources */,
|
||||
@ -2760,6 +2867,7 @@
|
||||
525019E52406852100EED91C /* ListFourColumnDataUsageDividerModel.swift in Sources */,
|
||||
32D2609624C19E2100B56344 /* LockupsPlanSMLXL.swift in Sources */,
|
||||
0A7EF86723D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift in Sources */,
|
||||
444FB7C32821B76B00DFE692 /* TitleLockupModel.swift in Sources */,
|
||||
D29C94D5242901C9003813BA /* MVMCoreUICommonViewsUtility+Extension.swift in Sources */,
|
||||
D260105323CEA61600764D80 /* ToggleModel.swift in Sources */,
|
||||
014AA72523C501E2006F3E93 /* ContainerModel.swift in Sources */,
|
||||
@ -2802,6 +2910,7 @@
|
||||
BB55B51D244482C1002001AD /* ListRightVariablePriceChangeBodyText.swift in Sources */,
|
||||
017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */,
|
||||
323AC96C24C837FF00F8E4C4 /* ListThreeColumnBillChanges.swift in Sources */,
|
||||
EAB14BC327D9378D0012AB2C /* RuleAnyModelProtocol.swift in Sources */,
|
||||
0A0FEC7825D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift in Sources */,
|
||||
D28A837923C7D5BC00DFE4FC /* PageModelProtocol.swift in Sources */,
|
||||
D2351C7C24A4D4C3007DF0BC /* ListRightVariableToggleAllTextAndLinks.swift in Sources */,
|
||||
@ -2816,6 +2925,7 @@
|
||||
D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */,
|
||||
011B58F223A2AE2C0085F53C /* DropDownListItemModel.swift in Sources */,
|
||||
D2509ED12472ED9B001BFB9D /* NavigationItemModelProtocol.swift in Sources */,
|
||||
EA05EFAB278DE53600828819 /* ClearableModelProtocol.swift in Sources */,
|
||||
8D448E5524050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift in Sources */,
|
||||
BBC0C4FD24811DBC0087C44F /* Tag.swift in Sources */,
|
||||
94C2D9842386F3F80006CF46 /* LabelAttributeModel.swift in Sources */,
|
||||
@ -2824,6 +2934,7 @@
|
||||
C6FA7D5323C77A4A00A3614A /* StringAndMoleculeStack.swift in Sources */,
|
||||
32F8804624765C6E00C2ACB3 /* ListLeftVariableNumberedListAllTextAndLinksModel.swift in Sources */,
|
||||
011D958524042432000E3791 /* RulesProtocol.swift in Sources */,
|
||||
4457904E27ECE989002B1E1E /* UIImageRenderingMode+Extension.swift in Sources */,
|
||||
D23118B325124E18001C8440 /* Notification.swift in Sources */,
|
||||
AA9972502475309F00FC7472 /* ListLeftVariableIconAllTextLinksModel.swift in Sources */,
|
||||
AA69AAF62445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift in Sources */,
|
||||
@ -2930,6 +3041,7 @@
|
||||
D2CAC7D12511058C00C75681 /* MVMCoreUITopAlertMainView+Extension.swift in Sources */,
|
||||
0A21DB83235DFBC500C160A2 /* MdnEntryField.swift in Sources */,
|
||||
0AE98BB723FF18E9004C5109 /* ArrowModel.swift in Sources */,
|
||||
01F2C20427C81F9700DC3D36 /* SubNavInteractor.swift.swift in Sources */,
|
||||
D28A837D23CCA86A00DFE4FC /* TabsListItemModel.swift in Sources */,
|
||||
0A51F3E32475CB73002E08B6 /* LoadingSpinner.swift in Sources */,
|
||||
BB2FB3BB247E7EBC00DF73CD /* TagCollectionViewCell.swift in Sources */,
|
||||
@ -2942,6 +3054,7 @@
|
||||
0A21DB94235E24ED00C160A2 /* DigitEntryField.swift in Sources */,
|
||||
AA56A211243C5EFC00303286 /* ListTwoColumnSubsectionDivider.swift in Sources */,
|
||||
D264FA8C243BCD8E00D98315 /* CollectionTemplateModel.swift in Sources */,
|
||||
01F2C20227C81F9700DC3D36 /* SubNavManagerController.swift in Sources */,
|
||||
AA85236C244435A20059CC1E /* RadioSwatchCollectionViewCell.swift in Sources */,
|
||||
52B201D224081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift in Sources */,
|
||||
D26C5A6B23F4A40D007AEECE /* ListItemModel.swift in Sources */,
|
||||
@ -2953,12 +3066,15 @@
|
||||
1D6D258826899B0C00DEBB08 /* ImageButtonModel.swift in Sources */,
|
||||
AA07EA912510A442009A2AE3 /* StarModel.swift in Sources */,
|
||||
D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */,
|
||||
EA41F4AC2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift in Sources */,
|
||||
011D95892404249B000E3791 /* FormHolderModelProtocol.swift in Sources */,
|
||||
BB54C5202434D92F0038326C /* ListRightVariableButtonAllTextAndLinks.swift in Sources */,
|
||||
948DB67E2326DCD90011F916 /* MultiProgress.swift in Sources */,
|
||||
013F801923FB4A8E00AD8013 /* UIContentMode+Extension.swift in Sources */,
|
||||
AA104AC724472DB0004D2810 /* HeadersH1Button.swift in Sources */,
|
||||
525239C22407BD1000454969 /* ListTwoColumnPriceDetails.swift in Sources */,
|
||||
01F2C20327C81F9700DC3D36 /* SubNavManagerNavigationController.swift in Sources */,
|
||||
EABFC1412763BB8D00E78B40 /* FormLabel.swift in Sources */,
|
||||
AA997252247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift in Sources */,
|
||||
D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */,
|
||||
D23EA7FB2475F09800D60C34 /* CarouselItemProtocol.swift in Sources */,
|
||||
@ -2968,16 +3084,19 @@
|
||||
27F973532466074500CAB5C5 /* PageBehaviorProtocol.swift in Sources */,
|
||||
94C2D9A323872C110006CF46 /* LabelAttributeStrikeThroughModel.swift in Sources */,
|
||||
D28A838523CCCA8900DFE4FC /* ScrollerModel.swift in Sources */,
|
||||
EAA0CFB3275E831E00D65EB0 /* DisableFormFieldEffectModel.swift in Sources */,
|
||||
D29DF26C21E6AA0B003B2FB9 /* FLAnimatedImage.m in Sources */,
|
||||
D23EA7FE247EBBB700D60C34 /* NavigationLabelButtonModel.swift in Sources */,
|
||||
D28A839123CD4FD400DFE4FC /* CornerLabelsModel.swift in Sources */,
|
||||
012A88F123985E0100FE3DA1 /* Color.swift in Sources */,
|
||||
D22D8393241C27B100D3DF69 /* TemplateModel.swift in Sources */,
|
||||
D22D8393241C27B100D3DF69 /* BaseTemplateModel.swift in Sources */,
|
||||
012A889C23889E8400FE3DA1 /* TemplateModelProtocol.swift in Sources */,
|
||||
EAA0CFB1275E823A00D65EB0 /* HideFormFieldEffectModel.swift in Sources */,
|
||||
D23A8FFB26123189007E14CE /* PageBehaviorModelProtocol.swift in Sources */,
|
||||
52267A0723FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift in Sources */,
|
||||
D2ED2812254B0EB800A1C293 /* MVMCoreTopAlertObject.m in Sources */,
|
||||
0AA4D2E125CAEC72008DB32D /* AccessibilityModelProtocol.swift in Sources */,
|
||||
EA05EFA9278DDE2C00828819 /* ClearFormFieldEffectModel.swift in Sources */,
|
||||
C003506123AA94CD00B6AC29 /* Button.swift in Sources */,
|
||||
DBC4391B224421A0001AB423 /* CaretLink.swift in Sources */,
|
||||
D29C559025C095210082E7D6 /* Video.swift in Sources */,
|
||||
@ -3040,6 +3159,7 @@
|
||||
011D95AD2406BB57000E3791 /* FormHolderProtocol.swift in Sources */,
|
||||
D23A9004261234CE007E14CE /* PageBehaviorHandlerProtocol.swift in Sources */,
|
||||
01509D932327ECFB00EF99AA /* ProgressBar.swift in Sources */,
|
||||
EA7E67762758365300ABF773 /* UIUpdatableModelProtocol.swift in Sources */,
|
||||
D2169301251E51E7002A6324 /* SectionListTemplate.swift in Sources */,
|
||||
0A6682AA2435125F00AD3CA1 /* Styler.swift in Sources */,
|
||||
D264FAA7243FE13B00D98315 /* RadioBox.swift in Sources */,
|
||||
@ -3180,7 +3300,8 @@
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
@ -3202,8 +3323,13 @@
|
||||
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../SharedFrameworks";
|
||||
INFOPLIST_FILE = MVMCoreUI/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.vzw.MVMCoreUI;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
@ -3228,8 +3354,13 @@
|
||||
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../SharedFrameworks";
|
||||
INFOPLIST_FILE = MVMCoreUI/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.vzw.MVMCoreUI;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
||||
@ -52,7 +52,9 @@ public extension MVMCoreAlertHandler {
|
||||
extension MVMCoreAlertHandler: MVMCorePresentationDelegateProtocol {
|
||||
// Update displayable for each top alert operation when page type changes, in top queue priority order.
|
||||
public func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) {
|
||||
guard navigationController == MVMCoreUISplitViewController.main()?.navigationController else { return }
|
||||
guard topAlertQueue.operations.count > 0 else { return }
|
||||
let viewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController)
|
||||
guard viewController == MVMCoreUISplitViewController.main()?.getCurrentViewController() else { return }
|
||||
let pageType = (viewController as? MVMCoreViewControllerProtocol)?.pageType
|
||||
topAlertQueue.operations.compactMap {
|
||||
$0 as? MVMCoreTopAlertOperation
|
||||
|
||||
@ -104,6 +104,9 @@
|
||||
/// Hides a persistent alert based on the type string.
|
||||
- (void)hidePersistentTopAlertViewOfType:(nullable NSString *)type;
|
||||
|
||||
/// Hides a alert based on the type string.
|
||||
- (void)hideTopAlertViewOfType:(nullable NSString *)type;
|
||||
|
||||
/// Removes a scheduled top alert given its top alert object.
|
||||
- (void)removeTopAlertForObject:(nonnull MVMCoreTopAlertObject *)topAlertObject;
|
||||
|
||||
|
||||
@ -239,6 +239,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)hideTopAlertViewOfType:(nullable NSString *)type {
|
||||
if (type) {
|
||||
for (MVMCoreTopAlertOperation *operation in self.topAlertQueue.operations) {
|
||||
|
||||
// Cancel all operations of this type.
|
||||
if ([operation.topAlertObject.type isEqualToString:type]) {
|
||||
operation.reAddAfterCancel = NO;
|
||||
[operation cancel];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeTopAlertForObject:(MVMCoreTopAlertObject *)topAlertObject {
|
||||
for (MVMCoreTopAlertOperation *operation in self.topAlertQueue.operations) {
|
||||
// Finds an cancels top alerts associated with the object.
|
||||
|
||||
@ -40,6 +40,10 @@ public extension MVMCoreAlertObject {
|
||||
alertObject?.alertStyle = UIAlertController.Style(rawValue: alertStyle)
|
||||
}
|
||||
|
||||
if let analyticsData = alertJson.optionalDictionaryForKey("analyticsData") {
|
||||
alertObject?.pageJson = ["analyticsData": analyticsData]
|
||||
}
|
||||
|
||||
return alertObject
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,8 +54,8 @@
|
||||
}
|
||||
|
||||
__block MVMCoreAlertObject *alert = [[MVMCoreAlertObject alloc] init];
|
||||
alert.title = [responseInfo stringForKey:KeyErrorHeading];
|
||||
alert.message = [responseInfo stringForKey:KeyUserMessage];
|
||||
alert.title = [responseInfo string:KeyErrorHeading] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle];
|
||||
alert.message = [responseInfo string:KeyUserMessage] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess];
|
||||
|
||||
NSString *messageStyle = [responseInfo stringForKey:KeyMessageStyle];
|
||||
if ([ValueTypeFieldErrors isEqualToString:[responseInfo string:KeyType]]) {
|
||||
@ -151,9 +151,9 @@
|
||||
+ (nullable instancetype)alertObjectWithPage:(nullable NSDictionary *)page isGreedy:(BOOL)isGreedy additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject error:(MVMCoreErrorObject *_Nullable *_Nullable)error {
|
||||
|
||||
MVMCoreAlertObject *alert = [[MVMCoreAlertObject alloc] init];
|
||||
alert.title = [page stringForKey:KeyTitle];
|
||||
alert.title = [page string:KeyTitle] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle];
|
||||
alert.pageJson = page;
|
||||
alert.message = [page stringForKey:KeyMessage];
|
||||
alert.message = [page string:KeyMessage] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess];
|
||||
alert.isGreedy = isGreedy;
|
||||
alert.type = MFAlertTypePopup;
|
||||
alert.alertStyle = UIAlertControllerStyleAlert;
|
||||
@ -217,9 +217,8 @@
|
||||
+ (nullable instancetype)alertObjectForPageType:(nullable NSString *)pageType responseInfo:(nullable NSDictionary *)responseInfo additionalData:(nullable NSDictionary *)additionalData actionDelegate:(nullable NSObject <MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)actionDelegate {
|
||||
|
||||
__block MVMCoreAlertObject *alert = [[MVMCoreAlertObject alloc] init];
|
||||
alert.title = [responseInfo stringForKey:KeyErrorHeading];
|
||||
alert.message = [responseInfo stringForKey:KeyUserMessage];
|
||||
|
||||
alert.title = [responseInfo string:KeyErrorHeading] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle];
|
||||
alert.message = [responseInfo string:KeyUserMessage] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess];
|
||||
NSString *messageStyle = [responseInfo stringForKey:KeyMessageStyle];
|
||||
if ([ValueTypeFieldErrors isEqualToString:[responseInfo string:KeyType]]) {
|
||||
|
||||
@ -279,9 +278,9 @@
|
||||
+ (nullable instancetype)alertObjectWithPage:(nullable NSDictionary *)page isGreedy:(BOOL)isGreedy additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject <MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate error:(MVMCoreErrorObject *_Nullable *_Nullable)error {
|
||||
|
||||
MVMCoreAlertObject *alert = [[MVMCoreAlertObject alloc] init];
|
||||
alert.title = [page stringForKey:KeyTitle];
|
||||
alert.title = [page string:KeyTitle] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle];
|
||||
alert.pageJson = page;
|
||||
alert.message = [page stringForKey:KeyMessage];
|
||||
alert.message = [page string:KeyMessage] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess];
|
||||
alert.isGreedy = isGreedy;
|
||||
alert.type = MFAlertTypePopup;
|
||||
alert.alertStyle = UIAlertControllerStyleAlert;
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
// Created by Suresh, Kamlesh on 7/9/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import MVMCore
|
||||
|
||||
@objcMembers public class ActionAlertModel: ActionModelProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -17,4 +17,12 @@
|
||||
public var alert: AlertModel
|
||||
public var extraParameters: JSONValueDictionary?
|
||||
public var analyticsData: JSONValueDictionary?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(alert: AlertModel) {
|
||||
self.alert = alert
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import MVMCore
|
||||
|
||||
|
||||
public class AlertButtonModel: Codable {
|
||||
@ -69,6 +70,7 @@ public class AlertModel: Codable {
|
||||
public var message: String
|
||||
public var style: UIAlertController.Style = .alert
|
||||
public var alertActions: [AlertButtonModel]
|
||||
public var analyticsData: JSONValueDictionary?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
@ -89,6 +91,7 @@ public class AlertModel: Codable {
|
||||
case message
|
||||
case alertActions
|
||||
case style
|
||||
case analyticsData
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -100,7 +103,8 @@ public class AlertModel: Codable {
|
||||
title = try typeContainer.decode(String.self, forKey: .title)
|
||||
message = try typeContainer.decode(String.self, forKey: .message)
|
||||
alertActions = try typeContainer.decode([AlertButtonModel].self, forKey: .alertActions)
|
||||
|
||||
analyticsData = try typeContainer.decodeIfPresent(JSONValueDictionary.self, forKey: .analyticsData)
|
||||
|
||||
if let style = try typeContainer.decodeIfPresent(String.self, forKey: .style) {
|
||||
self.style = UIAlertController.Style(rawValue: style)
|
||||
}
|
||||
@ -112,5 +116,6 @@ public class AlertModel: Codable {
|
||||
try container.encode(message, forKey: .message)
|
||||
try container.encode(alertActions, forKey: .alertActions)
|
||||
try container.encode(style.rawValueString, forKey: .style)
|
||||
try container.encodeIfPresent(analyticsData, forKey: .analyticsData)
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,21 +7,23 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import VDSColorTokens
|
||||
|
||||
public typealias FacadeElements = (fill: UIColor?, text: UIColor?, border: UIColor?)
|
||||
|
||||
|
||||
open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWatcherFieldProtocol, EnableableModelProtocol {
|
||||
open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWatcherFieldProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
//Making static property as class property so that subclasses can override getter function of the property
|
||||
open class var identifier: String { "button" }
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var accessibilityText: String?
|
||||
public var title: String
|
||||
public var action: ActionModelProtocol
|
||||
public var enabled: Bool = true
|
||||
public var width: CGFloat?
|
||||
public var style: Styler.Button.Style? {
|
||||
didSet {
|
||||
guard let style = style else { return }
|
||||
@ -56,15 +58,23 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
public var disabledTextColor_inverted: Color?
|
||||
public var disabledBorderColor_inverted: Color?
|
||||
|
||||
private var _backgroundColor: Color?
|
||||
public var backgroundColor: Color? {
|
||||
get {
|
||||
if let backgroundColor = _backgroundColor { return backgroundColor }
|
||||
if inverted {
|
||||
return enabled ? enabledFillColor_inverted : disabledFillColor_inverted
|
||||
}
|
||||
return enabled ? enabledFillColor : disabledFillColor
|
||||
}
|
||||
set {
|
||||
_backgroundColor = newValue
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
public func setValidity(_ valid: Bool, group: FormGroupRule) {
|
||||
enabled = valid
|
||||
updateUI?()
|
||||
}
|
||||
|
||||
/// Temporary binding mechanism for the view to update on enable changes.
|
||||
public var updateUI: ActionBlock?
|
||||
|
||||
@ -75,18 +85,21 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
public init(with title: String, action: ActionModelProtocol) {
|
||||
self.title = title
|
||||
self.action = action
|
||||
setFacade(by: .primary)
|
||||
}
|
||||
|
||||
public init(secondaryButtonWith title: String, action: ActionModelProtocol) {
|
||||
self.title = title
|
||||
self.action = action
|
||||
style = .secondary
|
||||
setFacade(by: .secondary)
|
||||
}
|
||||
|
||||
public init(primaryButtonWith title: String, action: ActionModelProtocol) {
|
||||
self.title = title
|
||||
self.action = action
|
||||
style = .primary
|
||||
setFacade(by: .primary)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -119,40 +132,30 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
|
||||
/// Defines the default appearance for the primary style.
|
||||
func setPrimaryFacade() {
|
||||
enabledFillColor = Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
enabledTextColor = Color(uiColor: VDSColor.elementsPrimaryOndark)
|
||||
disabledFillColor = Color(uiColor: VDSColor.interactiveDisabledOnlight)
|
||||
disabledTextColor = Color(uiColor: VDSColor.elementsPrimaryOndark)
|
||||
|
||||
if enabledFillColor == nil && enabledTextColor == nil {
|
||||
enabledFillColor = Color(uiColor: .mvmBlack)
|
||||
enabledTextColor = Color(uiColor: .mvmWhite)
|
||||
}
|
||||
|
||||
if disabledFillColor == nil && disabledTextColor == nil {
|
||||
disabledFillColor = Color(uiColor: .mvmCoolGray6)
|
||||
disabledTextColor = Color(uiColor: .mvmWhite)
|
||||
}
|
||||
|
||||
enabledFillColor_inverted = Color(uiColor: .mvmWhite)
|
||||
enabledTextColor_inverted = Color(uiColor: .mvmBlack)
|
||||
disabledFillColor_inverted = Color(uiColor: .mvmCoolGray6)
|
||||
disabledTextColor_inverted = Color(uiColor: .mvmBlack)
|
||||
enabledFillColor_inverted = Color(uiColor: VDSColor.elementsPrimaryOndark)
|
||||
enabledTextColor_inverted = Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
disabledFillColor_inverted = Color(uiColor: VDSColor.interactiveDisabledOndark)
|
||||
disabledTextColor_inverted = Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
}
|
||||
|
||||
/// Defines the default appearance for the Secondary style.
|
||||
func setSecondaryFacade() {
|
||||
enabledTextColor = Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
enabledFillColor = Color(uiColor: UIColor.clear)
|
||||
enabledBorderColor = Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
disabledTextColor = Color(uiColor: VDSColor.interactiveDisabledOnlight)
|
||||
disabledBorderColor = Color(uiColor: VDSColor.interactiveDisabledOnlight)
|
||||
|
||||
if enabledTextColor == nil && enabledBorderColor == nil {
|
||||
enabledTextColor = Color(uiColor: .mvmBlack)
|
||||
enabledBorderColor = Color(uiColor: .mvmBlack)
|
||||
}
|
||||
|
||||
if disabledTextColor == nil && disabledBorderColor == nil {
|
||||
disabledTextColor = Color(uiColor: .mvmCoolGray6)
|
||||
disabledBorderColor = Color(uiColor: .mvmCoolGray6)
|
||||
}
|
||||
|
||||
enabledTextColor_inverted = Color(uiColor: .mvmWhite)
|
||||
enabledBorderColor_inverted = Color(uiColor: .mvmWhite)
|
||||
disabledTextColor_inverted = Color(uiColor: .mvmCoolGray6)
|
||||
disabledBorderColor_inverted = Color(uiColor: .mvmCoolGray6)
|
||||
enabledTextColor_inverted = Color(uiColor: VDSColor.elementsPrimaryOndark)
|
||||
enabledFillColor_inverted = Color(uiColor: UIColor.clear)
|
||||
enabledBorderColor_inverted = Color(uiColor: VDSColor.elementsPrimaryOndark)
|
||||
disabledTextColor_inverted = Color(uiColor: VDSColor.interactiveDisabledOndark)
|
||||
disabledBorderColor_inverted = Color(uiColor: VDSColor.interactiveDisabledOndark)
|
||||
}
|
||||
|
||||
public func setFacade(by style: Styler.Button.Style) {
|
||||
@ -174,6 +177,7 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case accessibilityText
|
||||
case title
|
||||
case inverted
|
||||
case action
|
||||
@ -187,6 +191,7 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
case disabledFillColor
|
||||
case disabledTextColor
|
||||
case disabledBorderColor
|
||||
case width
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -196,14 +201,21 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
|
||||
title = try typeContainer.decode(String.self, forKey: .title)
|
||||
action = try typeContainer.decodeModel(codingKey: .action)
|
||||
|
||||
if let style = decoder.context?.value(forKey: CodingKeys.style.stringValue) as? Styler.Button.Style{
|
||||
self.style = style
|
||||
setFacade(by: style)
|
||||
}
|
||||
|
||||
if let style = try typeContainer.decodeIfPresent(Styler.Button.Style.self, forKey: .style) {
|
||||
self.style = style
|
||||
setFacade(by: style)
|
||||
} else {
|
||||
setFacade(by: .primary)
|
||||
}
|
||||
|
||||
if let size = try typeContainer.decodeIfPresent(Styler.Button.Size.self, forKey: .size) {
|
||||
@ -245,6 +257,9 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
if let disabledBorderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledBorderColor) {
|
||||
self.disabledBorderColor = disabledBorderColor
|
||||
}
|
||||
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
width = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .width)
|
||||
}
|
||||
|
||||
open func encode(to encoder: Encoder) throws {
|
||||
@ -254,8 +269,9 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(inverted, forKey: .inverted)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
|
||||
try container.encodeIfPresent(enabledFillColor, forKey: .fillColor)
|
||||
try container.encodeIfPresent(enabledTextColor, forKey: .textColor)
|
||||
try container.encodeIfPresent(enabledBorderColor, forKey: .borderColor)
|
||||
@ -265,5 +281,6 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
try container.encodeIfPresent(style, forKey: .style)
|
||||
try container.encodeIfPresent(size, forKey: .size)
|
||||
try container.encodeIfPresent(groupName, forKey: .groupName)
|
||||
try container.encodeIfPresent(width, forKey: .width)
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ public class CaretLinkModel: ButtonModelProtocol, MoleculeModelProtocol, Enablea
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
try container.encode(enabled, forKey: .enabledColor)
|
||||
try container.encode(enabledColor, forKey: .enabledColor)
|
||||
try container.encodeIfPresent(disabledColor, forKey: .disabledColor)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(enabledColor_inverted, forKey: .enabledColor_inverted)
|
||||
|
||||
@ -36,7 +36,7 @@ import Foundation
|
||||
|
||||
}
|
||||
|
||||
private func setState() {
|
||||
public func setState() {
|
||||
guard let castModel = model as? ImageButtonModel else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
open class ImageButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWatcherFieldProtocol, EnableableModelProtocol {
|
||||
open class ImageButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWatcherFieldProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -25,11 +25,6 @@ open class ImageButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGro
|
||||
public var disabledTintColor: Color?
|
||||
|
||||
public var groupName: String = ""
|
||||
|
||||
public func setValidity(_ valid: Bool, group: FormGroupRule) {
|
||||
enabled = valid
|
||||
updateUI?()
|
||||
}
|
||||
|
||||
public var updateUI: ActionBlock?
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
import VDSColorTokens
|
||||
|
||||
@objcMembers open class Link: Button {
|
||||
//--------------------------------------------------
|
||||
@ -28,8 +28,8 @@ import UIKit
|
||||
// x should be according to the text, not the button
|
||||
let x = textRect.origin.x
|
||||
|
||||
// Line is 1 point below the text
|
||||
let y = textRect.origin.y + textRect.size.height + 1
|
||||
// Line is 0 point below the text
|
||||
let y = textRect.origin.y + textRect.size.height
|
||||
|
||||
context.move(to: CGPoint(x: x, y: y))
|
||||
context.addLine(to: CGPoint(x: x + textRect.size.width, y: y))
|
||||
@ -38,7 +38,7 @@ import UIKit
|
||||
|
||||
open override var intrinsicContentSize: CGSize {
|
||||
guard let size = titleLabel?.intrinsicContentSize else { return super.intrinsicContentSize }
|
||||
return CGSize(width: size.width, height: size.height + 2)
|
||||
return CGSize(width: size.width, height: size.height + 1)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -51,10 +51,14 @@ import UIKit
|
||||
guard let model = model as? LinkModel else { return }
|
||||
|
||||
setTitle(model.title, for: .normal)
|
||||
accessibilityLabel = model.title
|
||||
if let accessibilityText = model.accessibilityText {
|
||||
accessibilityLabel = accessibilityText
|
||||
}
|
||||
setTitleColor((model.inverted ? model.enabledColor_inverted : model.enabledColor).uiColor, for: .normal)
|
||||
setTitleColor((model.inverted ? model.disabledColor_inverted : model.disabledColor).uiColor, for: .disabled)
|
||||
setTitleColor((model.inverted ? model.activeColor_inverted : model.activeColor).uiColor, for: .highlighted)
|
||||
isEnabled = model.enabled
|
||||
titleLabel?.font = model.getFont(model.size)
|
||||
set(with: model.action, delegateObject: delegateObject, additionalData: additionalData)
|
||||
}
|
||||
|
||||
@ -66,21 +70,15 @@ extension Link {
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
|
||||
var width = size
|
||||
if MVMCoreGetterUtility.fequal(a: Float.leastNormalMagnitude, b: Float(size)) {
|
||||
width = MVMCoreUIUtility.getWidth()
|
||||
}
|
||||
|
||||
titleLabel?.font = MFStyler.fontB2(forWidth: width)
|
||||
}
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
backgroundColor = .clear
|
||||
contentMode = .redraw
|
||||
setTitleColor(.mvmBlack, for: .normal)
|
||||
setTitleColor(.mvmCoolGray6, for: .disabled)
|
||||
setTitleColor(VDSColor.elementsPrimaryOnlight, for: .normal)
|
||||
setTitleColor(VDSColor.interactiveDisabledOnlight, for: .disabled)
|
||||
setTitleColor(VDSColor.interactiveActiveOnlight, for: .highlighted)
|
||||
titleLabel?.numberOfLines = 1
|
||||
titleLabel?.lineBreakMode = .byTruncatingTail
|
||||
titleLabel?.textAlignment = .left
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
import VDSColorTokens
|
||||
|
||||
open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableModelProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -19,13 +19,18 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var title: String
|
||||
public var accessibilityText: String?
|
||||
public var action: ActionModelProtocol
|
||||
public var enabled = true
|
||||
public var enabledColor = Color(uiColor: .mvmBlack)
|
||||
public var enabledColor_inverted = Color(uiColor: .mvmWhite)
|
||||
public var disabledColor = Color(uiColor: .mvmCoolGray6)
|
||||
public var disabledColor_inverted = Color(uiColor: .mvmCoolGray10)
|
||||
public var enabledColor = Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
public var enabledColor_inverted = Color(uiColor: VDSColor.elementsPrimaryOndark)
|
||||
public var disabledColor = Color(uiColor: VDSColor.interactiveDisabledOnlight)
|
||||
public var disabledColor_inverted = Color(uiColor: VDSColor.interactiveDisabledOndark)
|
||||
public var activeColor = Color(uiColor: VDSColor.interactiveActiveOnlight)
|
||||
public var activeColor_inverted = Color(uiColor: VDSColor.interactiveActiveOndark)
|
||||
|
||||
public var inverted = false
|
||||
public var size:linkFontSize = linkFontSize.small
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
@ -44,6 +49,7 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
case accessibilityText
|
||||
case title
|
||||
case action
|
||||
case enabled
|
||||
@ -51,9 +57,30 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
|
||||
case enabledColor_inverted
|
||||
case disabledColor
|
||||
case disabledColor_inverted
|
||||
case activeColor
|
||||
case activeColor_inverted
|
||||
case inverted
|
||||
case size
|
||||
}
|
||||
|
||||
public enum linkFontSize: String, Codable {
|
||||
case small
|
||||
case large
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Method
|
||||
//--------------------------------------------------
|
||||
|
||||
func getFont(_ type: linkFontSize) -> UIFont {
|
||||
switch type {
|
||||
case .small:
|
||||
return MFStyler.fontRegularBodySmall()
|
||||
case .large:
|
||||
return MFStyler.fontRegularBodyLarge()
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
@ -64,6 +91,7 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
title = try typeContainer.decode(String.self, forKey: .title)
|
||||
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
|
||||
action = try typeContainer.decodeModel(codingKey: .action)
|
||||
|
||||
if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
|
||||
@ -89,6 +117,17 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
|
||||
if let disabledColor_inverted = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledColor_inverted) {
|
||||
self.disabledColor_inverted = disabledColor_inverted
|
||||
}
|
||||
|
||||
if let activeColor = try typeContainer.decodeIfPresent(Color.self, forKey: .activeColor) {
|
||||
self.activeColor = activeColor
|
||||
}
|
||||
|
||||
if let activeColor_inverted = try typeContainer.decodeIfPresent(Color.self, forKey: .activeColor_inverted) {
|
||||
self.activeColor_inverted = activeColor_inverted
|
||||
}
|
||||
if let size = try typeContainer.decodeIfPresent(linkFontSize.self, forKey: .size) {
|
||||
self.size = size
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -104,5 +143,8 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
|
||||
try container.encode(enabledColor_inverted, forKey: .enabledColor_inverted)
|
||||
try container.encode(disabledColor, forKey: .disabledColor)
|
||||
try container.encode(disabledColor_inverted, forKey: .disabledColor_inverted)
|
||||
try container.encode(activeColor, forKey: .activeColor)
|
||||
try container.encode(activeColor_inverted, forKey: .activeColor_inverted)
|
||||
try container.encodeIfPresent(size, forKey: .size)
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
import VDSColorTokens
|
||||
|
||||
open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -23,21 +23,29 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
|
||||
/// Need to re-style on set.
|
||||
open override var isEnabled: Bool {
|
||||
didSet { style() }
|
||||
didSet { style(with: buttonModel) }
|
||||
}
|
||||
|
||||
open var buttonSize: Styler.Button.Size = .standard {
|
||||
didSet { buttonModel?.size = buttonSize }
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
|
||||
public var widthConstraint: NSLayoutConstraint?
|
||||
public var minimumWidthConstraint: NSLayoutConstraint?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc public convenience init(asPrimaryButton isPrimary: Bool, makeTiny istiny: Bool) {
|
||||
self.init()
|
||||
buttonSize = istiny ? .tiny : .standard
|
||||
isPrimary ? stylePrimary() : styleSecondary()
|
||||
let model = ButtonModel(with: "", action: ActionNoopModel())
|
||||
model.style = isPrimary ? .primary : .secondary
|
||||
model.size = istiny ? .tiny : .standard
|
||||
self.init(model: model, nil, nil)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -68,39 +76,26 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
|
||||
/// The primary styling for a button. Should be used for main buttons
|
||||
public func stylePrimary() {
|
||||
|
||||
enabledTitleColor = buttonModel?.enabledColors.text ?? .mvmWhite
|
||||
disabledTitleColor = buttonModel?.disabledColors.text ?? .mvmWhite
|
||||
layer.borderWidth = 0
|
||||
backgroundColor = isEnabled ? buttonModel?.enabledColors.fill ?? .mvmBlack : buttonModel?.disabledColors.fill ?? .mvmCoolGray6
|
||||
let buttonModel = ButtonModel(primaryButtonWith: "", action: ActionNoopModel())
|
||||
style(with: buttonModel)
|
||||
}
|
||||
|
||||
/// The secondary styling for a button. Should be used for secondary buttons
|
||||
public func styleSecondary() {
|
||||
|
||||
enabledTitleColor = buttonModel?.enabledColors.text ?? .mvmBlack
|
||||
disabledTitleColor = buttonModel?.disabledColors.text ?? .mvmCoolGray6
|
||||
backgroundColor = .clear
|
||||
layer.borderWidth = 1
|
||||
borderColor = isEnabled ? buttonModel?.enabledColors.border ?? .mvmBlack : buttonModel?.disabledColors.border ?? .mvmCoolGray6
|
||||
let buttonModel = ButtonModel(secondaryButtonWith: "", action: ActionNoopModel())
|
||||
style(with: buttonModel)
|
||||
}
|
||||
|
||||
/// Styles the button based on the model style
|
||||
private func style() {
|
||||
private func style(with model: ButtonModel?) {
|
||||
|
||||
switch buttonModel?.style {
|
||||
case .secondary:
|
||||
styleSecondary()
|
||||
|
||||
default:
|
||||
stylePrimary()
|
||||
}
|
||||
layer.borderWidth = model?.style == .secondary ? 1 : 0
|
||||
|
||||
if let titleColor = buttonModel?.enabledColors.text {
|
||||
if let titleColor = model?.enabledColors.text {
|
||||
enabledTitleColor = titleColor
|
||||
}
|
||||
|
||||
if let disabledTitleColor = buttonModel?.disabledColors.text {
|
||||
if let disabledTitleColor = model?.disabledColors.text {
|
||||
self.disabledTitleColor = disabledTitleColor
|
||||
}
|
||||
|
||||
@ -110,72 +105,46 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
#endif
|
||||
|
||||
if isEnabled {
|
||||
if let fillColor = buttonModel?.enabledColors.fill {
|
||||
if let fillColor = model?.enabledColors.fill {
|
||||
backgroundColor = fillColor
|
||||
}
|
||||
|
||||
if let borderColor = buttonModel?.enabledColors.border {
|
||||
layer.borderWidth = 1
|
||||
if let borderColor = model?.enabledColors.border {
|
||||
self.borderColor = borderColor
|
||||
}
|
||||
} else {
|
||||
if let fillColor = buttonModel?.disabledColors.fill {
|
||||
if let fillColor = model?.disabledColors.fill {
|
||||
backgroundColor = fillColor
|
||||
}
|
||||
|
||||
if let borderColor = buttonModel?.disabledColors.border {
|
||||
layer.borderWidth = 1
|
||||
if let borderColor = model?.disabledColors.border {
|
||||
self.borderColor = borderColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func getInnerPadding() -> CGFloat {
|
||||
getHeight() / 2.0
|
||||
buttonSize.getHeight() / 2.0
|
||||
}
|
||||
|
||||
private func getHeight() -> CGFloat {
|
||||
PillButton.getHeight(for: buttonSize, size: size)
|
||||
}
|
||||
|
||||
public static func getHeight(for buttonSize: Styler.Button.Size?, size: CGFloat) -> CGFloat {
|
||||
|
||||
private func getContentEdgeInsets() -> UIEdgeInsets {
|
||||
var verticalPadding = 0.0
|
||||
var horizontalPadding = 0.0
|
||||
switch buttonSize {
|
||||
case .standard:
|
||||
verticalPadding = Padding.Three
|
||||
horizontalPadding = Padding.Five
|
||||
break
|
||||
case .small:
|
||||
verticalPadding = Padding.Two
|
||||
horizontalPadding = Padding.Four
|
||||
break
|
||||
case .tiny:
|
||||
let tinyHeight = Styler.Button.Size.tiny.getHeight()
|
||||
return MFSizeObject(standardSize: tinyHeight,
|
||||
standardiPadPortraitSize: 34,
|
||||
iPadProLandscapeSize: 38)?.getValueBased(onSize: size) ?? tinyHeight
|
||||
|
||||
default:
|
||||
let standardHeight = Styler.Button.Size.standard.getHeight()
|
||||
return MFSizeObject(standardSize: standardHeight,
|
||||
standardiPadPortraitSize: 46,
|
||||
iPadProLandscapeSize: 50)?.getValueBased(onSize: size) ?? standardHeight
|
||||
}
|
||||
}
|
||||
|
||||
private func getMinimumWidth() -> CGFloat {
|
||||
|
||||
switch buttonSize {
|
||||
case .tiny:
|
||||
return MFSizeObject(standardSize: 49,
|
||||
standardiPadPortraitSize: 90,
|
||||
iPadProLandscapeSize: 135)?.getValueBased(onSize: size) ?? 49
|
||||
|
||||
default: return 151
|
||||
}
|
||||
}
|
||||
|
||||
open override var intrinsicContentSize: CGSize {
|
||||
if buttonSize == .tiny {
|
||||
let size = super.intrinsicContentSize
|
||||
let width = size.width + (2 * getInnerPadding())
|
||||
return CGSize(width: max(width, getMinimumWidth()), height: getHeight())
|
||||
} else {
|
||||
let width = Padding.Component.gutterForApplicationWidth + (2.0 * Padding.Component.columnFor(size: MVMCoreUISplitViewController.getApplicationViewWidth()))
|
||||
return CGSize(width: min(292, width), height: getHeight())
|
||||
verticalPadding = Padding.One
|
||||
horizontalPadding = Padding.Two
|
||||
break
|
||||
}
|
||||
return UIEdgeInsets(top: verticalPadding, left: horizontalPadding, bottom: verticalPadding, right: horizontalPadding)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -187,7 +156,11 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
|
||||
guard let model = model as? ButtonModel else { return }
|
||||
|
||||
setTitle(model.title, for: .normal)
|
||||
if let accessibilityText = model.accessibilityText {
|
||||
accessibilityLabel = accessibilityText
|
||||
}
|
||||
|
||||
if let size = model.size {
|
||||
buttonSize = size
|
||||
@ -203,24 +176,44 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
PillButton.getHeight(for: (model as? ButtonModel)?.size, size: MVMCoreUIUtility.getWidth())
|
||||
return (model as? ButtonModel)?.size?.getHeight()
|
||||
}
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
self.size = size
|
||||
|
||||
invalidateIntrinsicContentSize()
|
||||
|
||||
switch buttonSize {
|
||||
case .tiny:
|
||||
titleLabel?.font = MFFonts.mfFont75Bd(11 * (intrinsicContentSize.height / Styler.Button.Size.tiny.getHeight()))
|
||||
|
||||
default:
|
||||
titleLabel?.font = MFFonts.mfFont75Bd(13 * (intrinsicContentSize.height / Styler.Button.Size.standard.getHeight()))
|
||||
titleLabel?.font = Styler.Font.BoldMicro.getFont(false)
|
||||
case .small:
|
||||
titleLabel?.font = Styler.Font.BoldBodySmall.getFont(false)
|
||||
case .standard:
|
||||
titleLabel?.font = Styler.Font.BoldBodyLarge.getFont(false)
|
||||
}
|
||||
|
||||
layer.cornerRadius = getInnerPadding()
|
||||
contentEdgeInsets = getContentEdgeInsets()
|
||||
|
||||
if let contraint = buttonModel?.width {
|
||||
|
||||
if widthConstraint == nil {
|
||||
widthConstraint = widthAnchor.constraint(equalToConstant: contraint)
|
||||
} else if widthConstraint?.constant != contraint {
|
||||
widthConstraint?.constant = contraint
|
||||
}
|
||||
widthConstraint?.isActive = true
|
||||
minimumWidthConstraint?.isActive = false
|
||||
} else {
|
||||
|
||||
if minimumWidthConstraint == nil {
|
||||
minimumWidthConstraint = widthAnchor.constraint(greaterThanOrEqualToConstant: buttonSize.minimumWidth())
|
||||
} else {
|
||||
minimumWidthConstraint?.constant = buttonSize.minimumWidth()
|
||||
}
|
||||
minimumWidthConstraint?.isActive = true
|
||||
widthConstraint?.isActive = false
|
||||
}
|
||||
}
|
||||
|
||||
open override func setupView() {
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MVMCore
|
||||
|
||||
@objcMembers public class TagModel: MoleculeModelProtocol {
|
||||
public static var identifier: String = "tag"
|
||||
@ -27,6 +28,14 @@ import Foundation
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(label: LabelModel) {
|
||||
self.label = label
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
label = try typeContainer.decode(LabelModel.self, forKey: .label)
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MVMCore
|
||||
|
||||
@objcMembers public class TagsModel: MoleculeModelProtocol {
|
||||
public static var identifier: String = "tags"
|
||||
@ -19,6 +20,14 @@ import Foundation
|
||||
case tags
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(with tags: [TagModel]) {
|
||||
self.tags = tags
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
tags = try typeContainer.decode([TagModel].self, forKey: .tags)
|
||||
|
||||
@ -38,29 +38,6 @@ import UIKit
|
||||
// Default dimensions of the DigitBox
|
||||
static let size: CGSize = CGSize(width: 39, height: 44)
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Computed Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public override var showError: Bool {
|
||||
get { super.showError }
|
||||
set (error) {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
self.borderStrokeColor = error ? .mvmOrange : .mvmCoolGray3
|
||||
|
||||
let barHeight: CGFloat = self.showError ? 4 : 1
|
||||
self.bottomBar?.frame = CGRect(x: 0, y: self.bounds.height - barHeight, width: self.bounds.width, height: barHeight)
|
||||
self.bottomBar?.backgroundColor = self.showError ? UIColor.mvmOrange.cgColor : UIColor.mvmBlack.cgColor
|
||||
|
||||
self.setNeedsDisplay()
|
||||
self.layoutIfNeeded()
|
||||
}
|
||||
super.showError = error
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Delegate
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -105,7 +105,7 @@ import UIKit
|
||||
super.isLocked = locked
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override var placeholder: String? {
|
||||
get {
|
||||
var string = ""
|
||||
@ -249,6 +249,10 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
public override func showErrorView(_ show: Bool) {
|
||||
//do nothing since you should show the error view
|
||||
//within a digitEntryField
|
||||
}
|
||||
|
||||
@objc public func setAsSecureTextEntry(_ secureEntry: Bool) {
|
||||
|
||||
@ -311,7 +315,6 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc override func startEditing() {
|
||||
|
||||
selectedDigitBox?.isSelected = true
|
||||
selectedDigitBox?.digitField.becomeFirstResponder()
|
||||
}
|
||||
@ -328,7 +331,6 @@ import UIKit
|
||||
}
|
||||
|
||||
@objc public override func dismissFieldInput(_ sender: Any?) {
|
||||
|
||||
digitBoxes.forEach {
|
||||
if $0.isSelected {
|
||||
$0.digitField.resignFirstResponder()
|
||||
@ -398,7 +400,6 @@ extension DigitEntryField {
|
||||
digitEntryModel?.text = text
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@ -411,9 +412,9 @@ extension DigitEntryField {
|
||||
}
|
||||
|
||||
@objc public func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||
|
||||
digitBoxes.forEach {
|
||||
if $0.digitField === textField {
|
||||
startEditing()
|
||||
selectedDigitBox = $0
|
||||
$0.isSelected = true
|
||||
return
|
||||
@ -429,15 +430,15 @@ extension DigitEntryField {
|
||||
}
|
||||
|
||||
@objc public func textFieldDidEndEditing(_ textField: UITextField) {
|
||||
|
||||
// There should only be one digitBox to deselect.
|
||||
selectedDigitBox?.isSelected = false
|
||||
selectedDigitBox = nil
|
||||
|
||||
if !switchFieldsAutomatically && validateWhenDoneEditing {
|
||||
validateText()
|
||||
endInputing()
|
||||
}
|
||||
|
||||
|
||||
proprietorTextDelegate?.textFieldDidEndEditing?(textField)
|
||||
}
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ import UIKit
|
||||
super.isEnabled = enabled
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
//--------------------------------------------------
|
||||
|
||||
public override func formFieldValue() -> AnyHashable? {
|
||||
guard enabled else { return nil }
|
||||
guard !options.isEmpty,
|
||||
let index = selectedIndex
|
||||
else { return nil }
|
||||
@ -57,6 +58,6 @@
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(options, forKey: .options)
|
||||
try container.encodeIfPresent(options, forKey: .selectedIndex)
|
||||
try container.encodeIfPresent(selectedIndex, forKey: .selectedIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ import Foundation
|
||||
//--------------------------------------------------
|
||||
|
||||
public override func formFieldValue() -> AnyHashable? {
|
||||
|
||||
guard enabled else { return nil }
|
||||
guard !components.isEmpty && !selectedIndexes.isEmpty else { return nil }
|
||||
|
||||
return selectedRowText
|
||||
|
||||
@ -17,11 +17,8 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
// MARK: - Outlets
|
||||
//--------------------------------------------------
|
||||
|
||||
public private(set) var titleLabel: Label = {
|
||||
let label = Label()
|
||||
label.font = Styler.Font.RegularMicro.getFont()
|
||||
label.textColor = .mvmBlack
|
||||
public private(set) var titleLabel: FormLabel = {
|
||||
let label = FormLabel()
|
||||
label.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
return label
|
||||
}()
|
||||
@ -29,14 +26,33 @@ import UIKit
|
||||
public private(set) var entryFieldContainer = EntryFieldContainer()
|
||||
|
||||
/// Provides contextual information on the TextField.
|
||||
public private(set) var feedbackLabel: Label = {
|
||||
public private(set) var feedbackLabel: FormLabel = {
|
||||
let label = FormLabel()
|
||||
label.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
return label
|
||||
}()
|
||||
|
||||
public private(set) var errorLabel: Label = {
|
||||
let label = Label()
|
||||
label.font = Styler.Font.RegularMicro.getFont()
|
||||
label.setFontStyle(.RegularMicro)
|
||||
label.textColor = .mvmBlack
|
||||
label.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
return label
|
||||
}()
|
||||
|
||||
|
||||
public lazy var stack: UIStackView = {
|
||||
errorLabel.isHidden = true
|
||||
let stack = UIStackView(arrangedSubviews: [titleLabel, entryFieldContainer, errorLabel, feedbackLabel])
|
||||
stack.axis = .vertical
|
||||
stack.alignment = .fill
|
||||
stack.distribution = .fill
|
||||
stack.setCustomSpacing(Padding.One, after: titleLabel)
|
||||
stack.setCustomSpacing(Padding.Two, after: entryFieldContainer)
|
||||
stack.setCustomSpacing(Padding.One, after: errorLabel)
|
||||
stack.translatesAutoresizingMaskIntoConstraints = false
|
||||
return stack
|
||||
}()
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Delegate
|
||||
//--------------------------------------------------
|
||||
@ -46,7 +62,6 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
// MARK: - Stored Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public var isValid: Bool = false
|
||||
|
||||
/// Validate on each entry in the textField. Default: true
|
||||
@ -60,19 +75,32 @@ import UIKit
|
||||
public var isEnabled: Bool {
|
||||
get { entryFieldContainer.isEnabled }
|
||||
set (enabled) {
|
||||
titleLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3
|
||||
feedbackLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3
|
||||
entryFieldContainer.isEnabled = enabled
|
||||
entryFieldModel?.enabled = enabled
|
||||
if(entryFieldContainer.isEnabled != enabled){
|
||||
titleLabel.isEnabled = enabled
|
||||
feedbackLabel.isEnabled = enabled
|
||||
entryFieldContainer.isEnabled = enabled
|
||||
entryFieldModel?.enabled = enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Toggles enabled (original) or disabled UI.
|
||||
public var isRequired: Bool = true {
|
||||
didSet{
|
||||
titleLabel.isRequired = isRequired
|
||||
}
|
||||
}
|
||||
|
||||
/// Toggles error or original UI.
|
||||
public var showError: Bool {
|
||||
get { entryFieldContainer.showError }
|
||||
set (error) {
|
||||
feedback = error ? errorMessage : entryFieldModel?.feedback
|
||||
feedbackLabel.textColor = error ? entryFieldModel?.errorTextColor?.uiColor ?? .mvmBlack : .mvmBlack
|
||||
if error {
|
||||
errorLabel.text = self.errorMessage ?? ""
|
||||
errorLabel.isHidden = false
|
||||
} else {
|
||||
errorLabel.isHidden = true
|
||||
}
|
||||
entryFieldContainer.showError = error
|
||||
entryFieldModel?.showError = error
|
||||
}
|
||||
@ -104,11 +132,11 @@ import UIKit
|
||||
public var title: String? {
|
||||
get { titleLabel.text }
|
||||
set {
|
||||
titleLabel.text = newValue
|
||||
titleLabel.set(text: newValue ?? "")
|
||||
setAccessibilityString(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Override this to conveniently get/set the textfield(s).
|
||||
public var text: String? {
|
||||
get { nil }
|
||||
@ -119,7 +147,7 @@ import UIKit
|
||||
public var feedback: String? {
|
||||
get { feedbackLabel.text }
|
||||
set {
|
||||
feedbackLabel.text = newValue
|
||||
feedbackLabel.set(text: newValue ?? "")
|
||||
feedbackLabel.accessibilityElementsHidden = feedbackLabel.text?.isEmpty ?? true
|
||||
}
|
||||
}
|
||||
@ -128,22 +156,6 @@ import UIKit
|
||||
model as? EntryFieldModel
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
|
||||
public var entryFieldContainerLeading: NSLayoutConstraint?
|
||||
public var entryFieldContainerTrailing: NSLayoutConstraint?
|
||||
|
||||
public var feedbackLabelTrailing: NSLayoutConstraint?
|
||||
public var feedbackLabelLeading: NSLayoutConstraint?
|
||||
|
||||
public var titleLabelLeading: NSLayoutConstraint?
|
||||
public var titleLabelTrailing: NSLayoutConstraint?
|
||||
|
||||
public var titleContainerDistance: NSLayoutConstraint?
|
||||
public var feedbackContainerDistance: NSLayoutConstraint?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
@ -183,37 +195,18 @@ import UIKit
|
||||
|
||||
isAccessibilityElement = false
|
||||
setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
accessibilityElements = [titleLabel, feedbackLabel]
|
||||
accessibilityElements = [titleLabel, errorLabel, feedbackLabel]
|
||||
backgroundColor = .mvmWhite
|
||||
|
||||
addSubview(titleLabel)
|
||||
|
||||
titleLabel.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true
|
||||
titleLabelLeading = titleLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
|
||||
titleLabelLeading?.isActive = true
|
||||
titleLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor)
|
||||
titleLabelLeading?.isActive = true
|
||||
|
||||
addSubview(entryFieldContainer)
|
||||
|
||||
addSubview(stack)
|
||||
|
||||
entryFieldContainer.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
setupFieldContainerContent(entryFieldContainer)
|
||||
|
||||
titleContainerDistance = entryFieldContainer.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: Padding.One)
|
||||
titleContainerDistance?.isActive = true
|
||||
entryFieldContainerLeading = entryFieldContainer.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
|
||||
entryFieldContainerLeading?.isActive = true
|
||||
entryFieldContainerTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: entryFieldContainer.trailingAnchor)
|
||||
entryFieldContainerTrailing?.isActive = true
|
||||
|
||||
addSubview(feedbackLabel)
|
||||
|
||||
feedbackContainerDistance = feedbackLabel.topAnchor.constraint(equalTo: entryFieldContainer.bottomAnchor, constant: Padding.Two)
|
||||
feedbackContainerDistance?.isActive = true
|
||||
feedbackLabelLeading = feedbackLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
|
||||
feedbackLabelLeading?.isActive = true
|
||||
feedbackLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: feedbackLabel.trailingAnchor)
|
||||
feedbackLabelTrailing?.isActive = true
|
||||
layoutMarginsGuide.bottomAnchor.constraint(equalTo: feedbackLabel.bottomAnchor).isActive = true
|
||||
|
||||
stack.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true
|
||||
stack.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true
|
||||
layoutMarginsGuide.trailingAnchor.constraint(equalTo: stack.trailingAnchor).isActive = true
|
||||
layoutMarginsGuide.bottomAnchor.constraint(equalTo: stack.bottomAnchor).isActive = true
|
||||
}
|
||||
|
||||
@objc open override func layoutSubviews() {
|
||||
@ -229,10 +222,7 @@ import UIKit
|
||||
|
||||
@objc open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
|
||||
titleLabel.updateView(size)
|
||||
feedbackLabel.updateView(size)
|
||||
entryFieldContainer.updateView(size)
|
||||
stack.updateView(size)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -290,19 +280,30 @@ import UIKit
|
||||
titleLabel.textColor = .mvmBlack
|
||||
feedbackLabel.font = Styler.Font.RegularMicro.getFont()
|
||||
feedbackLabel.textColor = .mvmBlack
|
||||
errorLabel.font = Styler.Font.RegularMicro.getFont()
|
||||
errorLabel.textColor = .mvmBlack
|
||||
errorLabel.text = nil
|
||||
entryFieldContainer.disableAllBorders = false
|
||||
feedbackLabel.text = nil
|
||||
entryFieldContainer.reset()
|
||||
entryFieldModel?.updateUI = nil
|
||||
}
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
self.delegateObject = delegateObject
|
||||
|
||||
guard let model = model as? EntryFieldModel else { return }
|
||||
guard let model = entryFieldModel else { return }
|
||||
|
||||
entryFieldContainer.set(with: model, delegateObject, additionalData)
|
||||
|
||||
//setup the properties for setting models
|
||||
//later with enabled/showError
|
||||
titleLabel.setup(model: model.titleStateLabel, delegateObject, additionalData)
|
||||
feedbackLabel.setup(model: model.feedbackStateLabel, delegateObject, additionalData)
|
||||
|
||||
isEnabled = model.enabled && !model.readOnly
|
||||
isRequired = model.required
|
||||
model.updateUI = { [weak self] in
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
guard let self = self else { return }
|
||||
@ -313,6 +314,8 @@ import UIKit
|
||||
} else if model.isValid ?? true && self.showError {
|
||||
self.showError = false
|
||||
}
|
||||
self.isEnabled = model.enabled
|
||||
self.text = model.text
|
||||
})
|
||||
}
|
||||
|
||||
@ -328,13 +331,10 @@ import UIKit
|
||||
self.updateValidation(validState)
|
||||
})
|
||||
}
|
||||
|
||||
title = model.title
|
||||
feedback = model.feedback
|
||||
isEnabled = model.enabled
|
||||
|
||||
entryFieldContainer.disableAllBorders = model.hideBorders
|
||||
accessibilityIdentifier = model.accessibilityIdentifier ?? model.fieldKey
|
||||
|
||||
|
||||
if let isLocked = model.locked {
|
||||
self.isLocked = isLocked
|
||||
|
||||
@ -364,3 +364,11 @@ extension EntryField {
|
||||
// To Be Overriden
|
||||
}
|
||||
}
|
||||
|
||||
extension LabelModel {
|
||||
public convenience init(text: String = "", fontStyle: Styler.Font, textColor: Color) {
|
||||
self.init(text: text)
|
||||
self.fontStyle = fontStyle
|
||||
self.textColor = textColor
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,8 @@
|
||||
import Foundation
|
||||
|
||||
|
||||
@objcMembers open class EntryFieldModel: MoleculeModelProtocol, FormFieldProtocol, FormRuleWatcherFieldProtocol, EnableableModelProtocol {
|
||||
@objcMembers open class EntryFieldModel: MoleculeModelProtocol, FormFieldProtocol, FormRuleWatcherFieldProtocol, UIUpdatableModelProtocol, ClearableModelProtocol {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -18,8 +19,6 @@ import Foundation
|
||||
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var title: String?
|
||||
public var feedback: String?
|
||||
public var shouldClearText: Bool = false
|
||||
public var dynamicErrorMessage: String? {
|
||||
didSet {
|
||||
@ -30,6 +29,8 @@ import Foundation
|
||||
public var errorMessage: String?
|
||||
public var errorTextColor: Color?
|
||||
public var enabled: Bool = true
|
||||
public var required: Bool = true
|
||||
public var readOnly: Bool = false
|
||||
public var showError: Bool?
|
||||
public var hideBorders = false
|
||||
public var locked: Bool?
|
||||
@ -39,7 +40,13 @@ import Foundation
|
||||
public var groupName: String = FormValidator.defaultGroupName
|
||||
public var baseValue: AnyHashable?
|
||||
public var wasInitiallySelected: Bool = false
|
||||
|
||||
public var title: String?
|
||||
public var feedback: String?
|
||||
|
||||
//used to drive the EntryFieldView UI
|
||||
public var titleStateLabel: FormLabelModel
|
||||
public var feedbackStateLabel: FormLabelModel
|
||||
|
||||
public var isValid: Bool? = true {
|
||||
didSet { updateUI?() }
|
||||
}
|
||||
@ -60,6 +67,7 @@ import Foundation
|
||||
case accessibilityIdentifier
|
||||
case title
|
||||
case enabled
|
||||
case readOnly
|
||||
case feedback
|
||||
case errorMessage
|
||||
case errorTextColor
|
||||
@ -70,6 +78,7 @@ import Foundation
|
||||
case text
|
||||
case fieldKey
|
||||
case groupName
|
||||
case required
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -77,22 +86,24 @@ import Foundation
|
||||
//--------------------------------------------------
|
||||
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
guard enabled else { return nil }
|
||||
|
||||
if dynamicErrorMessage != nil {
|
||||
dynamicErrorMessage = nil
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
public func setValidity(_ valid: Bool, rule: RulesProtocol) {
|
||||
public func setValidity(_ valid: Bool, errorMessage: String?) {
|
||||
|
||||
if let fieldKey = fieldKey, let ruleErrorMessage = rule.errorMessage?[fieldKey] {
|
||||
if let ruleErrorMessage = errorMessage, fieldKey != nil {
|
||||
self.errorMessage = ruleErrorMessage
|
||||
}
|
||||
|
||||
self.isValid = valid
|
||||
updateUI?()
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
@ -100,6 +111,15 @@ import Foundation
|
||||
public init(with text: String) {
|
||||
self.text = text
|
||||
baseValue = text
|
||||
self.titleStateLabel = FormLabelModel(text: "")
|
||||
self.feedbackStateLabel = FormLabelModel(text: "")
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
public func clear() {
|
||||
self.text = ""
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -115,16 +135,21 @@ import Foundation
|
||||
errorMessage = try typeContainer.decodeIfPresent(String.self, forKey: .errorMessage)
|
||||
errorTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .errorTextColor)
|
||||
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
|
||||
required = try typeContainer.decodeIfPresent(Bool.self, forKey: .required) ?? true
|
||||
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
|
||||
locked = try typeContainer.decodeIfPresent(Bool.self, forKey: .locked)
|
||||
selected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected)
|
||||
text = try typeContainer.decodeIfPresent(String.self, forKey: .text)
|
||||
hideBorders = try typeContainer.decodeIfPresent(Bool.self, forKey: .hideBorders) ?? false
|
||||
baseValue = text
|
||||
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
|
||||
|
||||
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
|
||||
self.groupName = groupName
|
||||
}
|
||||
self.titleStateLabel = FormLabelModel(text: title ?? "")
|
||||
self.feedbackStateLabel = FormLabelModel(model: LabelModel(text: feedback ?? "",
|
||||
fontStyle: FormLabelModel.defaultFontStyle,
|
||||
textColor: Color(uiColor: .mvmCoolGray6)))
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -142,7 +167,10 @@ import Foundation
|
||||
try container.encodeIfPresent(errorMessage, forKey: .errorMessage)
|
||||
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
|
||||
try container.encodeIfPresent(groupName, forKey: .groupName)
|
||||
|
||||
try container.encode(readOnly, forKey: .readOnly)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(required, forKey: .required)
|
||||
try container.encode(hideBorders, forKey: .hideBorders)
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ import UIKit
|
||||
textField.accessibilityValue = nil
|
||||
}
|
||||
|
||||
if textField.isSecureTextEntry {
|
||||
if !textField.isSecureTextEntry {
|
||||
showErrorView(error)
|
||||
}
|
||||
|
||||
@ -247,6 +247,10 @@ import UIKit
|
||||
/// Executes on UITextField.textDidChangeNotification (each character entry)
|
||||
@objc override func valueChanged() {
|
||||
super.valueChanged()
|
||||
if (textEntryFieldModel?.type == .email) {
|
||||
// remove spaces (either user entered Or auto-correct suggestion) for the email field
|
||||
textField.text = textField.text?.replacingOccurrences(of: " ", with: "")
|
||||
}
|
||||
validateText()
|
||||
}
|
||||
|
||||
@ -290,8 +294,7 @@ import UIKit
|
||||
resignFirstResponder()
|
||||
}
|
||||
|
||||
private func showErrorView(_ show: Bool) {
|
||||
|
||||
open func showErrorView(_ show: Bool) {
|
||||
if show {
|
||||
entryFieldContainer.addSubview(errorImage)
|
||||
|
||||
|
||||
@ -38,6 +38,14 @@
|
||||
public var displayFormat: String?
|
||||
public var displayMask: String?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
public override init(with text: String){
|
||||
super.init(with: text)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
@ -137,7 +145,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
open override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeIfPresent(placeholder, forKey: .placeholder)
|
||||
|
||||
@ -46,7 +46,7 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
if self.textView.isShowingPlaceholder {
|
||||
self.textView.textColor = self.textView.placeholderTextColor
|
||||
} else {
|
||||
self.textView.textColor = (enabled ? self.textViewEntryFieldModel?.enabledTextColor : self.textViewEntryFieldModel?.disabledTextColor)?.uiColor
|
||||
self.textView.textColor = (self.textView.isEnabled ? self.textViewEntryFieldModel?.enabledTextColor : self.textViewEntryFieldModel?.disabledTextColor)?.uiColor
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -282,8 +282,5 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
|
||||
adjustMarginConstraints(constant: 0)
|
||||
}
|
||||
|
||||
if !model.enabled {
|
||||
isEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,7 +95,7 @@ import MVMCore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public var disabledBackgroundColor: UIColor = .clear
|
||||
public var disabledBorderColor: UIColor = .mvmCoolGray3
|
||||
public var disabledCheckColor: UIColor = .mvmCoolGray3
|
||||
@ -423,7 +423,14 @@ import MVMCore
|
||||
checkAndBypassAnimations(selected: model.selected)
|
||||
}
|
||||
|
||||
isEnabled = model.enabled
|
||||
model.updateUI = { [weak self] in
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
guard let self = self else { return }
|
||||
self.isEnabled = model.enabled
|
||||
})
|
||||
}
|
||||
|
||||
isEnabled = model.enabled && !model.readOnly
|
||||
|
||||
if (model.action != nil || model.offAction != nil) {
|
||||
actionBlock = { [weak self] in
|
||||
|
||||
@ -13,7 +13,8 @@
|
||||
var selected: Bool { get set }
|
||||
}
|
||||
|
||||
@objcMembers public class CheckboxModel: MoleculeModelProtocol, SelectableMoleculeModelProtocol, FormFieldProtocol {
|
||||
@objcMembers public class CheckboxModel: MoleculeModelProtocol, SelectableMoleculeModelProtocol, FormFieldProtocol, UIUpdatableModelProtocol {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -23,6 +24,7 @@
|
||||
public var accessibilityIdentifier: String?
|
||||
public var selected: Bool = false
|
||||
public var enabled: Bool = true
|
||||
public var readOnly: Bool = false
|
||||
public var animated: Bool = true
|
||||
public var inverted: Bool = false
|
||||
public var round: Bool = false
|
||||
@ -42,6 +44,7 @@
|
||||
public var fieldKey: String?
|
||||
public var groupName: String = FormValidator.defaultGroupName
|
||||
public var baseValue: AnyHashable?
|
||||
public var updateUI: ActionBlock?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
@ -52,6 +55,7 @@
|
||||
case accessibilityIdentifier
|
||||
case checked
|
||||
case enabled
|
||||
case readOnly
|
||||
case inverted
|
||||
case animated
|
||||
case round
|
||||
@ -75,7 +79,10 @@
|
||||
// MARK: - Form Validation
|
||||
//--------------------------------------------------
|
||||
|
||||
public func formFieldValue() -> AnyHashable? { selected }
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
guard enabled else { return nil }
|
||||
return selected
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
@ -153,10 +160,8 @@
|
||||
self.inverted = inverted
|
||||
}
|
||||
|
||||
if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
|
||||
self.enabled = enabled
|
||||
}
|
||||
|
||||
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
|
||||
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
|
||||
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
|
||||
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
|
||||
|
||||
@ -186,7 +191,8 @@
|
||||
try container.encodeIfPresent(disabledCheckColor, forKey: .disabledCheckColor)
|
||||
try container.encodeIfPresent(animated, forKey: .animated)
|
||||
try container.encodeIfPresent(round, forKey: .round)
|
||||
try container.encodeIfPresent(enabled, forKey: .enabled)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(readOnly, forKey: .readOnly)
|
||||
try container.encodeModelIfPresent(action, forKey: .action)
|
||||
try container.encodeIfPresent(groupName, forKey: .groupName)
|
||||
try container.encodeModelIfPresent(offAction, forKey: .offAction)
|
||||
|
||||
@ -62,7 +62,7 @@ import UIKit
|
||||
heartPath.close()
|
||||
heart.path = heartPath.cgPath
|
||||
heart.fillColor = isSelected ? heartModel?.activeColor.cgColor : heartModel?.inActiveColor.cgColor
|
||||
heart.opacity = 1.0
|
||||
heart.opacity = isEnabled ? 1.0 : 0.5
|
||||
heart.lineWidth = 1
|
||||
heart.strokeColor = isSelected ? UIColor.clear.cgColor : UIColor.mvmBlack.cgColor
|
||||
return heart
|
||||
@ -88,7 +88,7 @@ import UIKit
|
||||
self.additionalData = additionalData
|
||||
guard let model = model as? HeartModel else { return }
|
||||
isSelected = model.isActive
|
||||
isEnabled = model.enabled
|
||||
isEnabled = model.enabled && !model.readOnly
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
// Created by Lekshmi S on 07/09/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import MVMCore
|
||||
|
||||
open class HeartModel: MoleculeModelProtocol, EnableableModelProtocol {
|
||||
|
||||
@ -21,8 +21,8 @@ open class HeartModel: MoleculeModelProtocol, EnableableModelProtocol {
|
||||
public var inActiveColor: Color = Color(uiColor: .clear)
|
||||
public var action: ActionModelProtocol = ActionNoopModel()
|
||||
public var enabled: Bool = true
|
||||
|
||||
//--------------------------------------------------
|
||||
public var readOnly: Bool = false
|
||||
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -35,8 +35,14 @@ open class HeartModel: MoleculeModelProtocol, EnableableModelProtocol {
|
||||
case inActiveColor
|
||||
case action
|
||||
case enabled
|
||||
case readOnly
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
public init() { }
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
@ -61,9 +67,8 @@ open class HeartModel: MoleculeModelProtocol, EnableableModelProtocol {
|
||||
if let action: ActionModelProtocol = try typeContainer.decodeModelIfPresent(codingKey: .action) {
|
||||
self.action = action
|
||||
}
|
||||
if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
|
||||
self.enabled = enabled
|
||||
}
|
||||
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
|
||||
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -76,5 +81,6 @@ open class HeartModel: MoleculeModelProtocol, EnableableModelProtocol {
|
||||
try container.encode(inActiveColor, forKey: .inActiveColor)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(readOnly, forKey: .readOnly)
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ open class RadioBox: Control, MFButtonProtocol {
|
||||
public override var isEnabled: Bool {
|
||||
didSet { updateAccessibility() }
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - MVMCoreViewProtocol
|
||||
//--------------------------------------------------
|
||||
@ -89,7 +89,7 @@ open class RadioBox: Control, MFButtonProtocol {
|
||||
accentColor = color
|
||||
}
|
||||
isSelected = model.selected
|
||||
isEnabled = model.enabled
|
||||
isEnabled = model.enabled && !model.readOnly
|
||||
}
|
||||
|
||||
open override func reset() {
|
||||
|
||||
@ -5,8 +5,9 @@
|
||||
// Created by Dhamodaram Nandi on 31/03/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
import MVMCore
|
||||
|
||||
@objcMembers public class RadioBoxModel: MoleculeModelProtocol {
|
||||
@objcMembers public class RadioBoxModel: MoleculeModelProtocol, EnableableModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -19,6 +20,7 @@
|
||||
public var selectedAccentColor: Color?
|
||||
public var selected: Bool = false
|
||||
public var enabled: Bool = true
|
||||
public var readOnly: Bool = false
|
||||
public var strikethrough: Bool = false
|
||||
public var fieldValue: String?
|
||||
public var action: ActionModelProtocol?
|
||||
@ -39,6 +41,15 @@
|
||||
case strikethrough
|
||||
case fieldValue
|
||||
case action
|
||||
case readOnly
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(text: String) {
|
||||
self.text = text
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -57,9 +68,8 @@
|
||||
selected = isSelected
|
||||
}
|
||||
|
||||
if let isEnabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
|
||||
enabled = isEnabled
|
||||
}
|
||||
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
|
||||
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
|
||||
|
||||
if let isStrikeTrough = try typeContainer.decodeIfPresent(Bool.self, forKey: .strikethrough) {
|
||||
strikethrough = isStrikeTrough
|
||||
@ -79,6 +89,7 @@
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encode(selected, forKey: .selected)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(readOnly, forKey: .readOnly)
|
||||
try container.encode(strikethrough, forKey: .strikethrough)
|
||||
try container.encodeIfPresent(fieldValue, forKey: .fieldValue)
|
||||
try container.encodeModelIfPresent(action, forKey: .action)
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
// Created by Dhamodaram Nandi on 31/03/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
import MVMCore
|
||||
|
||||
@objcMembers public class RadioBoxesModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -20,13 +21,15 @@
|
||||
public var fieldKey: String?
|
||||
public var groupName: String = FormValidator.defaultGroupName
|
||||
public var baseValue: AnyHashable?
|
||||
|
||||
public var enabled: Bool = true
|
||||
public var readOnly: Bool = false
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Returns the fieldValue of the selected box, otherwise the text of the selected box.
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
guard enabled else { return nil }
|
||||
let selectedBox = boxes.first { (box) -> Bool in
|
||||
return box.selected
|
||||
}
|
||||
@ -39,6 +42,8 @@
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case enabled
|
||||
case readOnly
|
||||
case selectedAccentColor
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
@ -48,6 +53,14 @@
|
||||
case groupName
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(with boxes: [RadioBoxModel]){
|
||||
self.boxes = boxes
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
@ -63,6 +76,8 @@
|
||||
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
|
||||
self.groupName = groupName
|
||||
}
|
||||
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
|
||||
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
|
||||
baseValue = formFieldValue()
|
||||
}
|
||||
|
||||
@ -75,5 +90,7 @@
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
|
||||
try container.encode(groupName, forKey: .groupName)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(readOnly, forKey: .readOnly)
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ import UIKit
|
||||
open override func draw(_ rect: CGRect) {
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
let color = isEnabled ? enabledColor.cgColor : disabledColor.cgColor
|
||||
let color = isEnabled == false ? disabledColor.cgColor : enabledColor.cgColor
|
||||
layer.cornerRadius = bounds.width * 0.5
|
||||
layer.borderColor = color
|
||||
layer.borderWidth = bounds.width * 0.0333
|
||||
@ -118,7 +118,8 @@ import UIKit
|
||||
}
|
||||
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
radioModel?.fieldValue
|
||||
guard let radioModel = radioModel, radioModel.enabled else { return nil }
|
||||
return radioModel.fieldValue
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -162,7 +163,7 @@ import UIKit
|
||||
guard let model = model as? RadioButtonModel else { return }
|
||||
|
||||
isSelected = model.state
|
||||
isEnabled = model.enabled
|
||||
isEnabled = model.enabled && !model.readOnly
|
||||
RadioButtonSelectionHelper.setupForRadioButtonGroup(model, self, delegateObject: delegateObject)
|
||||
}
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
public var accessibilityIdentifier: String?
|
||||
public var state: Bool = false
|
||||
public var enabled: Bool = true
|
||||
public var readOnly: Bool = false
|
||||
|
||||
/// The specific value to send to server. TODO: update this to be more generic.
|
||||
public var fieldValue: String?
|
||||
@ -42,6 +43,7 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
case fieldKey
|
||||
case groupName
|
||||
case action
|
||||
case readOnly
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -57,7 +59,10 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
// MARK: - Validation
|
||||
//--------------------------------------------------
|
||||
|
||||
public func formFieldValue() -> AnyHashable? { fieldValue }
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
guard enabled else { return nil }
|
||||
return fieldValue
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
@ -69,11 +74,9 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
|
||||
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
|
||||
@ -93,6 +96,7 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(state, forKey: .state)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(readOnly, forKey: .readOnly)
|
||||
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
|
||||
try container.encodeIfPresent(groupName, forKey: .groupName)
|
||||
try container.encodeIfPresent(fieldValue, forKey: .fieldValue)
|
||||
|
||||
@ -17,6 +17,8 @@
|
||||
private var selectedRadioButton: RadioButton?
|
||||
private var selectedRadioButtonModel: RadioButtonModel?
|
||||
public var baseValue: AnyHashable?
|
||||
public var enabled: Bool = true
|
||||
public var readOnly: Bool = false
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
@ -39,6 +41,8 @@
|
||||
} else {
|
||||
radioButton.isSelected = false
|
||||
}
|
||||
self.enabled = radioButtonModel.enabled
|
||||
self.readOnly = radioButtonModel.readOnly
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -75,5 +79,8 @@
|
||||
// MARK: - FormValidationFormFieldProtocol
|
||||
extension RadioButtonSelectionHelper {
|
||||
|
||||
public func formFieldValue() -> AnyHashable? { selectedRadioButtonModel?.fieldValue }
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
guard enabled else { return nil }
|
||||
return selectedRadioButtonModel?.fieldValue
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ open class RadioSwatch: Control, MFButtonProtocol {
|
||||
updateAccessibility()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
@ -64,7 +64,7 @@ open class RadioSwatch: Control, MFButtonProtocol {
|
||||
self.additionalData = additionalData
|
||||
bottomText.text = model.text
|
||||
isSelected = model.selected
|
||||
isEnabled = model.enabled
|
||||
isEnabled = model.enabled && !model.readOnly
|
||||
}
|
||||
|
||||
public override func reset() {
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
// Created by Scott Pfeil on 4/17/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
import MVMCore
|
||||
|
||||
|
||||
@objcMembers public class RadioSwatchModel: MoleculeModelProtocol {
|
||||
@objcMembers public class RadioSwatchModel: MoleculeModelProtocol, EnableableModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -19,6 +19,7 @@
|
||||
public var text: String?
|
||||
public var selected: Bool = false
|
||||
public var enabled: Bool = true
|
||||
public var readOnly: Bool = false
|
||||
public var strikethrough: Bool = false
|
||||
public var fieldValue: String?
|
||||
public var action: ActionModelProtocol?
|
||||
@ -38,8 +39,15 @@
|
||||
case strikethrough
|
||||
case fieldValue
|
||||
case action
|
||||
case readOnly
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init() {}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
@ -58,17 +66,15 @@
|
||||
if let selected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected) {
|
||||
self.selected = selected
|
||||
}
|
||||
|
||||
if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
|
||||
self.enabled = enabled
|
||||
}
|
||||
|
||||
|
||||
if let strikethrough = try typeContainer.decodeIfPresent(Bool.self, forKey: .strikethrough) {
|
||||
self.strikethrough = strikethrough
|
||||
}
|
||||
|
||||
fieldValue = try typeContainer.decodeIfPresent(String.self, forKey: .fieldValue)
|
||||
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
|
||||
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
|
||||
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -83,5 +89,6 @@
|
||||
try container.encode(strikethrough, forKey: .strikethrough)
|
||||
try container.encodeIfPresent(fieldValue, forKey: .fieldValue)
|
||||
try container.encodeModelIfPresent(action, forKey: .action)
|
||||
try container.encode(readOnly, forKey: .readOnly)
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
// Created by Lekshmi S on 31/03/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import MVMCore
|
||||
|
||||
@objcMembers public class RadioSwatchesModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -19,6 +19,8 @@
|
||||
public var fieldKey: String?
|
||||
public var groupName: String = FormValidator.defaultGroupName
|
||||
public var baseValue: AnyHashable?
|
||||
public var enabled: Bool = true
|
||||
public var readOnly: Bool = false
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
@ -26,6 +28,7 @@
|
||||
|
||||
/// Returns the fieldValue of the selected swatch, otherwise the text of selected swatch.
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
guard enabled else { return nil }
|
||||
let selectedSwatch = swatches.first { (swatch) -> Bool in
|
||||
return swatch.selected
|
||||
}
|
||||
@ -43,6 +46,16 @@
|
||||
case swatches
|
||||
case fieldKey
|
||||
case groupName
|
||||
case enabled
|
||||
case readOnly
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(with swatches: [RadioSwatchModel]){
|
||||
self.swatches = swatches
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -58,6 +71,8 @@
|
||||
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
|
||||
self.groupName = groupName
|
||||
}
|
||||
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
|
||||
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
|
||||
baseValue = formFieldValue()
|
||||
}
|
||||
|
||||
@ -69,5 +84,7 @@
|
||||
try container.encode(swatches, forKey: .swatches)
|
||||
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
|
||||
try container.encode(groupName, forKey: .groupName)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(readOnly, forKey: .readOnly)
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ public typealias ActionBlockConfirmation = () -> (Bool)
|
||||
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: isEnabled ? "AccToggleHint" : "AccDisabled")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Simple means to prevent user interaction with the toggle.
|
||||
public var isLocked: Bool = false {
|
||||
didSet { isUserInteractionEnabled = !isLocked }
|
||||
@ -384,7 +384,7 @@ public typealias ActionBlockConfirmation = () -> (Bool)
|
||||
isOn = model.selected
|
||||
changeStateNoAnimation(isOn)
|
||||
isAnimated = model.animated
|
||||
isEnabled = model.enabled
|
||||
isEnabled = model.enabled && !model.readOnly
|
||||
|
||||
if let accessibileString = model.accessibilityText {
|
||||
accessibilityLabel = accessibileString
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
|
||||
public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol {
|
||||
public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -18,6 +18,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
|
||||
public var selected: Bool = false
|
||||
public var animated: Bool = true
|
||||
public var enabled: Bool = true
|
||||
public var readOnly: Bool = false
|
||||
public var action: ActionModelProtocol?
|
||||
public var alternateAction: ActionModelProtocol?
|
||||
public var accessibilityText: String?
|
||||
@ -39,6 +40,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
|
||||
case state
|
||||
case animated
|
||||
case enabled
|
||||
case readOnly
|
||||
case action
|
||||
case backgroundColor
|
||||
case accessibilityIdentifier
|
||||
@ -56,7 +58,10 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
|
||||
// MARK: - Form Valdiation
|
||||
//--------------------------------------------------
|
||||
|
||||
public func formFieldValue() -> AnyHashable? { selected }
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
guard enabled else { return nil }
|
||||
return selected
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
@ -78,10 +83,6 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
|
||||
self.selected = state
|
||||
}
|
||||
|
||||
if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
|
||||
self.enabled = enabled
|
||||
}
|
||||
|
||||
if let animated = try typeContainer.decodeIfPresent(Bool.self, forKey: .animated) {
|
||||
self.animated = animated
|
||||
}
|
||||
@ -114,6 +115,8 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
|
||||
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
|
||||
self.groupName = groupName
|
||||
}
|
||||
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
|
||||
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -133,5 +136,6 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
|
||||
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
|
||||
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
|
||||
try container.encodeIfPresent(groupName, forKey: .groupName)
|
||||
try container.encode(readOnly, forKey: .readOnly)
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
import UIKit
|
||||
|
||||
|
||||
open class ArrowModel: MoleculeModelProtocol {
|
||||
open class ArrowModel: MoleculeModelProtocol, EnableableModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
import MVMCore
|
||||
|
||||
@objcMembers public class CaretViewModel: MoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -38,6 +38,12 @@ import Foundation
|
||||
case inverted
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init() {}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -20,6 +20,8 @@ open class BarsIndicatorView: CarouselIndicator {
|
||||
static let width: CGFloat = 24
|
||||
static let selectedHeight: CGFloat = 4
|
||||
static let unselectedHeight: CGFloat = 1
|
||||
static let selectedCornerRadius: CGFloat = 2
|
||||
static let unselectedCornerRadius: CGFloat = 0.5
|
||||
|
||||
var constraint: NSLayoutConstraint?
|
||||
|
||||
@ -38,6 +40,7 @@ open class BarsIndicatorView: CarouselIndicator {
|
||||
override func setupView() {
|
||||
super.setupView()
|
||||
isAccessibilityElement = true
|
||||
layer.cornerRadius = 2
|
||||
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "AccTabHint")
|
||||
widthAnchor.constraint(equalToConstant: BarsIndicatorView.IndicatorBar.width).isActive = true
|
||||
accessibilityTraits = .button
|
||||
@ -52,7 +55,7 @@ open class BarsIndicatorView: CarouselIndicator {
|
||||
stackView.axis = .horizontal
|
||||
stackView.alignment = .bottom
|
||||
stackView.distribution = .equalSpacing
|
||||
stackView.spacing = 6
|
||||
stackView.spacing = 4
|
||||
return stackView
|
||||
}()
|
||||
|
||||
@ -79,7 +82,7 @@ open class BarsIndicatorView: CarouselIndicator {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Colors the currently selected index, unique from other indicators
|
||||
public var currentIndicatorColor: UIColor {
|
||||
get { barsCarouselIndicatorModel?.currentIndicatorColor.uiColor ?? indicatorColor }
|
||||
@ -189,6 +192,7 @@ open class BarsIndicatorView: CarouselIndicator {
|
||||
let bar = IndicatorBar()
|
||||
setAccessibilityLabel(view: bar, index: index)
|
||||
bar.backgroundColor = isEnabled ? (index == currentIndex ? currentIndicatorColor : indicatorColor) : disabledIndicatorColor
|
||||
bar.layer.cornerRadius = index == currentIndex ? BarsIndicatorView.IndicatorBar.selectedCornerRadius : BarsIndicatorView.IndicatorBar.unselectedCornerRadius
|
||||
let barHeight = index == currentIndex ? BarsIndicatorView.IndicatorBar.selectedHeight : BarsIndicatorView.IndicatorBar.unselectedHeight
|
||||
let heightConstraint = bar.heightAnchor.constraint(equalToConstant: barHeight)
|
||||
heightConstraint.isActive = true
|
||||
@ -251,6 +255,7 @@ open class BarsIndicatorView: CarouselIndicator {
|
||||
barReferences.forEach {
|
||||
$0.backgroundColor = isEnabled ? indicatorColor : disabledIndicatorColor
|
||||
$0.constraint?.constant = IndicatorBar.unselectedHeight
|
||||
$0.layer.cornerRadius = IndicatorBar.unselectedCornerRadius
|
||||
}
|
||||
|
||||
balanceBarCount(numberOfPages - barReferences.count)
|
||||
@ -260,8 +265,10 @@ open class BarsIndicatorView: CarouselIndicator {
|
||||
let expression = { [self] in
|
||||
barReferences[previousIndex].backgroundColor = isEnabled ? indicatorColor : disabledIndicatorColor
|
||||
barReferences[previousIndex].constraint?.constant = IndicatorBar.unselectedHeight
|
||||
barReferences[previousIndex].layer.cornerRadius = IndicatorBar.unselectedCornerRadius
|
||||
barReferences[newIndex].backgroundColor = isEnabled ? currentIndicatorColor : disabledIndicatorColor
|
||||
barReferences[newIndex].constraint?.constant = IndicatorBar.selectedHeight
|
||||
barReferences[newIndex].layer.cornerRadius = IndicatorBar.selectedCornerRadius
|
||||
layoutIfNeeded()
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
// Created by Kevin Christiano on 1/30/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import VDSColorTokens
|
||||
|
||||
open class CarouselIndicator: Control, CarouselPageControlProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -71,13 +71,22 @@ open class CarouselIndicator: Control, CarouselPageControlProtocol {
|
||||
}
|
||||
|
||||
public var disabledIndicatorColor: UIColor {
|
||||
get { carouselIndicatorModel?.disabledIndicatorColor.uiColor ?? .mvmCoolGray3 }
|
||||
set { carouselIndicatorModel?.disabledIndicatorColor = Color(uiColor: newValue) }
|
||||
get {
|
||||
guard let model = carouselIndicatorModel else { return VDSColor.elementsSecondaryOnlight }
|
||||
return model.inverted ? model.disabledIndicatorColor_inverted.uiColor : model.disabledIndicatorColor.uiColor
|
||||
}
|
||||
set {
|
||||
if let model = carouselIndicatorModel, model.inverted {
|
||||
model.disabledIndicatorColor_inverted = Color(uiColor: newValue)
|
||||
} else {
|
||||
carouselIndicatorModel?.disabledIndicatorColor = Color(uiColor: newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var indicatorColor: UIColor {
|
||||
get {
|
||||
guard let model = carouselIndicatorModel else { return .mvmBlack }
|
||||
guard let model = carouselIndicatorModel else { return VDSColor.elementsPrimaryOnlight}
|
||||
return model.inverted ? model.indicatorColor_inverted.uiColor : model.indicatorColor.uiColor
|
||||
}
|
||||
set {
|
||||
|
||||
@ -7,9 +7,9 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import VDSColorTokens
|
||||
|
||||
|
||||
open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelProtocol {
|
||||
open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelProtocol, EnableableModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -30,9 +30,10 @@ open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelPro
|
||||
/// Set true to make the accessibility value as "Slide #currentPage of #totalPage", otherwise will be "Page #currentPage of #totalPage", default is false
|
||||
public var accessibilityHasSlidesInsteadOfPage: Bool = false
|
||||
public var enabled: Bool = true
|
||||
public var disabledIndicatorColor: Color = Color(uiColor: .mvmCoolGray3)
|
||||
public var indicatorColor: Color = Color(uiColor: .mvmBlack)
|
||||
public var indicatorColor_inverted: Color = Color(uiColor: .mvmWhite)
|
||||
public var disabledIndicatorColor: Color = Color(uiColor: VDSColor.elementsSecondaryOnlight)
|
||||
public var disabledIndicatorColor_inverted: Color = Color(uiColor: VDSColor.elementsSecondaryOndark)
|
||||
public var indicatorColor: Color = Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
public var indicatorColor_inverted: Color = Color(uiColor: VDSColor.elementsPrimaryOndark)
|
||||
public var position: CGFloat?
|
||||
|
||||
/// Allows sendActions() to trigger even if index is already at min/max index.
|
||||
|
||||
@ -44,7 +44,7 @@ open class NumericIndicatorView: CarouselIndicator {
|
||||
open override var isEnabled: Bool {
|
||||
didSet { setViewColor(isEnabled ? indicatorColor : disabledIndicatorColor) }
|
||||
}
|
||||
|
||||
|
||||
/// Sets the color for pageCount text, left arrow and right arrow.
|
||||
public override var indicatorColor: UIColor {
|
||||
get { super.indicatorColor }
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MVMCore
|
||||
|
||||
public enum CheckboxPosition: String, Codable {
|
||||
case center
|
||||
@ -16,9 +17,19 @@ public enum CheckboxPosition: String, Codable {
|
||||
|
||||
@objcMembers public class CheckboxLabelModel: MoleculeModelProtocol {
|
||||
public static var identifier: String = "checkboxLabel"
|
||||
public var moleculeName: String
|
||||
public var moleculeName: String = CheckboxLabelModel.identifier
|
||||
public var backgroundColor: Color?
|
||||
public var checkboxAlignment: CheckboxPosition?
|
||||
public var checkbox: CheckboxModel
|
||||
public var label: LabelModel
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(checkbox: CheckboxModel, label: LabelModel) {
|
||||
self.checkbox = checkbox
|
||||
self.label = label
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
import MVMCore
|
||||
|
||||
@objcMembers public class DashLineModel: MoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -43,6 +43,12 @@ import Foundation
|
||||
case isHidden
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init() {}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - codec
|
||||
//--------------------------------------------------
|
||||
|
||||
59
MVMCoreUI/Atomic/Atoms/Views/Label/FormLabel.swift
Normal file
59
MVMCoreUI/Atomic/Atoms/Views/Label/FormLabel.swift
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// StateLabel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Matt Bruce on 12/10/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Subclass of label that helps with different states
|
||||
public class FormLabel: Label {
|
||||
//properties used in setting label
|
||||
private var delegateObject: MVMCoreUIDelegateObject?
|
||||
private var additionalData: [AnyHashable: Any]?
|
||||
|
||||
//models that drive the label UI
|
||||
private var formModel: FormLabelModel!
|
||||
|
||||
//public properties
|
||||
public override var isEnabled: Bool {
|
||||
didSet{
|
||||
self.formModel.enabled = isEnabled
|
||||
self.set(with: isRequired ? formModel.model : formModel.requiredModel, delegateObject, additionalData)
|
||||
}
|
||||
}
|
||||
|
||||
public var isRequired: Bool = true {
|
||||
didSet{
|
||||
self.set(with: isRequired ? formModel.model : formModel.requiredModel, delegateObject, additionalData)
|
||||
}
|
||||
}
|
||||
|
||||
public override func reset(){
|
||||
super.reset()
|
||||
self.isEnabled = true
|
||||
}
|
||||
|
||||
/// Used in setting up the Label for use
|
||||
/// - Parameters:
|
||||
/// - text: If there is no Model, there should be a TEXT only version of the label that will be applied to the default font / color styles
|
||||
/// - model: Model takes priority over a text value. The model has its own text value that will be looked at to draw the screen, this model is used for both enabled/disabled models
|
||||
/// - delegateObject: passed in from the creator
|
||||
/// - additionalData: passed in from the creator
|
||||
public func setup(model: FormLabelModel, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?){
|
||||
self.additionalData = additionalData
|
||||
self.delegateObject = delegateObject
|
||||
self.formModel = model
|
||||
|
||||
//default to enabled state
|
||||
self.reset()
|
||||
}
|
||||
|
||||
/// Text change that will update both enabledModel and disabledModel text values
|
||||
/// - Parameter text: text you want to see
|
||||
public func set(text: String?){
|
||||
self.formModel.set(text: text ?? "")
|
||||
}
|
||||
}
|
||||
81
MVMCoreUI/Atomic/Atoms/Views/Label/FormLabelModel.swift
Normal file
81
MVMCoreUI/Atomic/Atoms/Views/Label/FormLabelModel.swift
Normal file
@ -0,0 +1,81 @@
|
||||
//
|
||||
// StateLabelModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Matt Bruce on 12/14/21.
|
||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class FormLabelModel: EnableableModelProtocol {
|
||||
static let defaultFontStyle = Styler.Font.RegularMicro
|
||||
static let defaultEnabledTextColor = Color(uiColor: .mvmBlack)
|
||||
static let defaultDisabledTextColor = Color(uiColor: .mvmCoolGray3)
|
||||
static let defaultRequiredTextColor = Color(uiColor: .mvmCoolGray6)
|
||||
|
||||
private var enabledModel: LabelModel
|
||||
private var disabledModel = LabelModel(fontStyle: FormLabelModel.defaultFontStyle, textColor: FormLabelModel.defaultDisabledTextColor)
|
||||
|
||||
//current state
|
||||
public var enabled: Bool = true
|
||||
|
||||
//model is based on current state
|
||||
public var model: LabelModel {
|
||||
return enabled ? enabledModel: disabledModel
|
||||
}
|
||||
|
||||
//init
|
||||
public init(model: LabelModel){
|
||||
|
||||
//ensure the fontStyle exist and if so,
|
||||
//make sure the disabledModel font matches
|
||||
//otherwise set it to defaultFontStyle
|
||||
if let modelFontStyle = model.fontStyle {
|
||||
self.disabledModel.fontStyle = modelFontStyle
|
||||
} else {
|
||||
model.fontStyle = FormLabelModel.defaultFontStyle
|
||||
}
|
||||
|
||||
//ensure the textColor is set
|
||||
//otherwise use the defaultEnabledTextColor
|
||||
if model.textColor == nil {
|
||||
model.textColor = FormLabelModel.defaultEnabledTextColor
|
||||
}
|
||||
|
||||
//set the enabledModel to the model passed in
|
||||
self.enabledModel = model
|
||||
|
||||
//make sure the enabled & disabled text match
|
||||
self.disabledModel.text = self.enabledModel.text
|
||||
}
|
||||
|
||||
public init(text: String){
|
||||
//create the enabled model
|
||||
self.enabledModel = LabelModel(fontStyle: FormLabelModel.defaultFontStyle, textColor: FormLabelModel.defaultEnabledTextColor)
|
||||
self.enabledModel.text = text
|
||||
|
||||
//make sure the enabled & disabled text match
|
||||
self.disabledModel.text = self.enabledModel.text
|
||||
}
|
||||
|
||||
public var requiredModel: LabelModel {
|
||||
let required = LabelModel(fontStyle: model.fontStyle!, textColor: model.textColor!)
|
||||
if enabled {
|
||||
required.attributes = [LabelAttributeColorModel(FormLabelModel.defaultRequiredTextColor, model.text.count + 1, 8)]
|
||||
}
|
||||
required.text = "\(model.text) Optional"
|
||||
return required
|
||||
}
|
||||
|
||||
//methods
|
||||
public func reset(){
|
||||
self.enabled = true
|
||||
}
|
||||
|
||||
//set text for state
|
||||
public func set(text:String){
|
||||
self.enabledModel.text = text
|
||||
self.disabledModel.text = text
|
||||
}
|
||||
}
|
||||
@ -238,7 +238,7 @@ public typealias ActionBlock = () -> ()
|
||||
case left
|
||||
}
|
||||
|
||||
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject? = nil, _ additionalData: [AnyHashable: Any]? = nil) {
|
||||
|
||||
clauses = []
|
||||
text = nil
|
||||
@ -256,21 +256,19 @@ public typealias ActionBlock = () -> ()
|
||||
* appropriately called.
|
||||
* Only other reference found of issue: https://www.thetopsites.net/article/58142205.shtml
|
||||
*/
|
||||
if #available(iOS 13, *) {
|
||||
if let attributedText = attributedText, let text = text, !text.isEmpty {
|
||||
let attributedString = NSMutableAttributedString(string: text)
|
||||
let range = NSRange(location: 0, length: text.count)
|
||||
for attribute in attributedText.attributes(at: 0, effectiveRange: nil) {
|
||||
if attribute.key == .underlineStyle {
|
||||
attributedString.addAttribute(.underlineStyle, value: 0, range: range)
|
||||
}
|
||||
if attribute.key == .strikethroughStyle {
|
||||
attributedString.addAttribute(.strikethroughStyle, value: 0, range: range)
|
||||
}
|
||||
if let attributedText = attributedText, let text = text, !text.isEmpty {
|
||||
let attributedString = NSMutableAttributedString(string: text)
|
||||
let range = NSRange(location: 0, length: text.count)
|
||||
for attribute in attributedText.attributes(at: 0, effectiveRange: nil) {
|
||||
if attribute.key == .underlineStyle {
|
||||
attributedString.addAttribute(.underlineStyle, value: 0, range: range)
|
||||
}
|
||||
if attribute.key == .strikethroughStyle {
|
||||
attributedString.addAttribute(.strikethroughStyle, value: 0, range: range)
|
||||
}
|
||||
|
||||
self.attributedText = attributedString
|
||||
}
|
||||
|
||||
self.attributedText = attributedString
|
||||
}
|
||||
|
||||
hero = labelModel.hero
|
||||
@ -297,8 +295,8 @@ public typealias ActionBlock = () -> ()
|
||||
accessibilityLabel = accessibilityText
|
||||
}
|
||||
|
||||
if let fontStyle = labelModel.fontStyle?.rawValue {
|
||||
MFStyler.styleLabel(self, withStyle: fontStyle, genericScaling: false)
|
||||
if let fontStyle = labelModel.fontStyle {
|
||||
fontStyle.styleLabel(self, genericScaling: false)
|
||||
standardFontSize = font.pointSize
|
||||
} else {
|
||||
let fontSize = labelModel.fontSize
|
||||
@ -430,7 +428,7 @@ public typealias ActionBlock = () -> ()
|
||||
label.accessibilityLabel = json?.optionalStringForKey("accessibilityText")
|
||||
|
||||
if let fontStyle = json?.optionalStringForKey("fontStyle") {
|
||||
MFStyler.styleLabel(label, withStyle: fontStyle, genericScaling: mvmLabel == nil)
|
||||
MFStyler.style(label: label, styleString: fontStyle, genericScaling: mvmLabel == nil)
|
||||
mvmLabel?.standardFontSize = label.font.pointSize
|
||||
} else {
|
||||
let fontSize = json?["fontSize"] as? CGFloat
|
||||
@ -492,7 +490,7 @@ public typealias ActionBlock = () -> ()
|
||||
|
||||
case "font":
|
||||
if let fontStyle = attribute.optionalStringForKey("style") {
|
||||
let styles = MFStyler.styleGetAttributedString("0", withStyle: fontStyle, genericScaling: mvmLabel == nil)
|
||||
let styles = MFStyler.getAttributedString(for: "0", styleString: fontStyle, genericScaling: mvmLabel == nil)
|
||||
attributedString.removeAttribute(.font, range: range)
|
||||
attributedString.removeAttribute(.foregroundColor, range: range)
|
||||
attributedString.addAttributes(styles.attributes(at: 0, effectiveRange: nil), range: range)
|
||||
@ -533,8 +531,7 @@ public typealias ActionBlock = () -> ()
|
||||
//------------------------------------------------------
|
||||
|
||||
public func setFontStyle(_ fontStyle: Styler.Font, _ scale: Bool = true) {
|
||||
font = fontStyle.getFont(false)
|
||||
textColor = .mvmBlack
|
||||
fontStyle.styleLabel(self, genericScaling: false)
|
||||
setScale(scale)
|
||||
}
|
||||
|
||||
@ -584,9 +581,8 @@ public typealias ActionBlock = () -> ()
|
||||
|
||||
/// Will remove the values contained in attributedText.
|
||||
func clearAttributes() {
|
||||
|
||||
guard let labelText = text,
|
||||
let attributes = attributedText?.attributes(at: 0, longestEffectiveRange: nil, in: NSRange(location: 0, length: labelText.count))
|
||||
guard let labelText = text, !labelText.isEmpty else { return }
|
||||
guard let attributes = attributedText?.attributes(at: 0, longestEffectiveRange: nil, in: NSRange(location: 0, length: labelText.count))
|
||||
else { return }
|
||||
|
||||
let attributedString = NSMutableAttributedString(string: labelText)
|
||||
|
||||
@ -24,10 +24,14 @@
|
||||
case textColor
|
||||
}
|
||||
|
||||
public init(_ textColor: Color?, _ location: Int, _ length: Int){
|
||||
self.textColor = textColor
|
||||
super.init(location, length)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
textColor = try typeContainer.decodeIfPresent(Color.self, forKey: .textColor)
|
||||
|
||||
@ -18,6 +18,14 @@
|
||||
var name: String?
|
||||
var size: CGFloat?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public override init(_ location: Int, _ length: Int) {
|
||||
super.init(location, length)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -18,6 +18,14 @@ class LabelAttributeImageModel: LabelAttributeModel {
|
||||
var name: String?
|
||||
var URL: String?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public override init(_ location: Int, _ length: Int) {
|
||||
super.init(location, length)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -18,10 +18,6 @@ import UIKit
|
||||
get { return model as? LineModel }
|
||||
}
|
||||
|
||||
var lineBackgroundColor: Color? {
|
||||
return (lineModel?.inverted ?? false) ? lineModel?.backgroundColor_inverted : lineModel?.backgroundColor
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
@ -50,28 +46,36 @@ import UIKit
|
||||
addLine(to: view, edge: edge, useMargin: useMargin)
|
||||
}
|
||||
|
||||
public init() {
|
||||
super.init(frame: .zero)
|
||||
model = LineModel(type: .secondary)
|
||||
setStyle(.secondary)
|
||||
}
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
model = LineModel(type: .secondary)
|
||||
setStyle(.secondary)
|
||||
}
|
||||
|
||||
public required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
model = LineModel(type: .secondary)
|
||||
setStyle(.secondary)
|
||||
}
|
||||
|
||||
public required init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
||||
super.init(model: model, delegateObject, additionalData)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
open func setStyle(_ style: LineModel.Style) {
|
||||
|
||||
switch style {
|
||||
case .standard:
|
||||
updateLineConstraints(constant: 1)
|
||||
backgroundColor = lineModel?.backgroundColor?.uiColor ?? .mvmCoolGray3
|
||||
case .thin:
|
||||
updateLineConstraints(constant: 1)
|
||||
backgroundColor = lineModel?.backgroundColor?.uiColor ?? .mvmBlack
|
||||
case .medium:
|
||||
updateLineConstraints(constant: 2)
|
||||
backgroundColor = lineModel?.backgroundColor?.uiColor ?? .mvmBlack
|
||||
case .heavy:
|
||||
updateLineConstraints(constant: 4)
|
||||
backgroundColor = lineModel?.backgroundColor?.uiColor ?? .mvmBlack
|
||||
case .none:
|
||||
updateLineConstraints(constant: 0)
|
||||
}
|
||||
lineModel?.type = style
|
||||
backgroundColor = lineModel?.backgroundColor?.uiColor
|
||||
updateLineConstraints(constant: lineModel?.thickness ?? 1)
|
||||
}
|
||||
|
||||
open func shouldBeVisible() -> Bool {
|
||||
@ -90,12 +94,10 @@ import UIKit
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
|
||||
heightConstraint = heightAnchor.constraint(equalToConstant: 1)
|
||||
heightConstraint?.isActive = true
|
||||
widthConstraint = widthAnchor.constraint(equalToConstant: 1)
|
||||
widthConstraint?.isActive = false
|
||||
setStyle(.standard)
|
||||
}
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
@ -107,23 +109,11 @@ import UIKit
|
||||
}
|
||||
|
||||
open override func reset() {
|
||||
setStyle(.standard)
|
||||
setStyle(.secondary)
|
||||
}
|
||||
|
||||
public override static func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
|
||||
guard let type = (model as? LineModel)?.type else { return 1 }
|
||||
|
||||
switch type {
|
||||
case .none:
|
||||
return 0
|
||||
case .medium:
|
||||
return 2
|
||||
case .heavy:
|
||||
return 4
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
return (model as? LineModel)?.thickness ?? 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
import VDSColorTokens
|
||||
|
||||
@objcMembers public class LineModel: MoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -30,13 +30,17 @@ import UIKit
|
||||
|
||||
/**
|
||||
The style of the line:
|
||||
- standard (1 height, silver)
|
||||
- thin (1 height, black)
|
||||
- secondary (1 height, silver)
|
||||
- primary (1 height, black)
|
||||
- standard (1 height, silver) - deprecated
|
||||
- thin (1 height, black) - deprecated
|
||||
- medium (2 height, black)
|
||||
- heavy (4 height, black)
|
||||
- none (hidden)
|
||||
*/
|
||||
public enum Style: String, Codable {
|
||||
case secondary
|
||||
case primary
|
||||
case standard
|
||||
case thin
|
||||
case medium
|
||||
@ -49,13 +53,47 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var identifier: String = "line"
|
||||
public var type: Style = .standard
|
||||
public var type: Style = .secondary
|
||||
public var frequency: Frequency? = .allExceptTop
|
||||
|
||||
//TODO: use color insted of backgroundColor. Needs server changes
|
||||
// public var color: Color?
|
||||
public var backgroundColor: Color?
|
||||
public var backgroundColor_inverted: Color = Color(uiColor: .mvmWhite)
|
||||
private var _backgroundColor: Color?
|
||||
public var backgroundColor: Color? {
|
||||
get {
|
||||
if let backgroundColor = _backgroundColor { return backgroundColor }
|
||||
if inverted {
|
||||
if type == .secondary || type == .standard { return Color(uiColor: VDSColor.paletteGray20) }
|
||||
return Color(uiColor: VDSColor.elementsPrimaryOndark)
|
||||
}
|
||||
if type == .secondary || type == .standard { return Color(uiColor: VDSColor.paletteGray85) }
|
||||
return Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
}
|
||||
set {
|
||||
_backgroundColor = newValue
|
||||
}
|
||||
}
|
||||
|
||||
private var _thickness: CGFloat?
|
||||
public var thickness: CGFloat {
|
||||
get {
|
||||
if let thickness = _thickness { return thickness }
|
||||
switch type {
|
||||
case .heavy:
|
||||
return 4
|
||||
case .medium:
|
||||
return 2
|
||||
case .none:
|
||||
return 0
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
}
|
||||
set {
|
||||
_thickness = newValue
|
||||
}
|
||||
}
|
||||
|
||||
public var inverted: Bool = false
|
||||
|
||||
// Use this to show vertical line
|
||||
@ -90,6 +128,7 @@ import UIKit
|
||||
case frequency
|
||||
case inverted
|
||||
case useVerticalLine
|
||||
case thickness
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -111,12 +150,9 @@ import UIKit
|
||||
self.inverted = inverted
|
||||
}
|
||||
|
||||
if let backgroundColor_inverted = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor_inverted) {
|
||||
self.backgroundColor_inverted = backgroundColor_inverted
|
||||
}
|
||||
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
useVerticalLine = try typeContainer.decodeIfPresent(Bool.self, forKey: .useVerticalLine)
|
||||
_thickness = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .thickness)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -125,8 +161,8 @@ import UIKit
|
||||
try container.encode(type, forKey: .type)
|
||||
try container.encode(inverted, forKey: .inverted)
|
||||
try container.encodeIfPresent(frequency, forKey: .frequency)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(backgroundColor_inverted, forKey: .backgroundColor_inverted)
|
||||
try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(useVerticalLine, forKey: .useVerticalLine)
|
||||
try container.encodeIfPresent(_thickness, forKey: .thickness)
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
import MVMCore
|
||||
|
||||
open class LoadingSpinnerModel: MoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -32,6 +32,12 @@ open class LoadingSpinnerModel: MoleculeModelProtocol {
|
||||
case diameter
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init() {}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
// Created by Lekshmi S on 15/09/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
import MVMCore
|
||||
|
||||
open class StarModel: MoleculeModelProtocol {
|
||||
|
||||
@ -30,6 +31,12 @@ open class StarModel: MoleculeModelProtocol {
|
||||
case size
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init() {}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
// Created by Lekshmi S on 21/09/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
import MVMCore
|
||||
|
||||
@objcMembers public class StarsModel: MoleculeModelProtocol {
|
||||
|
||||
@ -34,6 +35,14 @@
|
||||
case size
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(with stars: [StarModel]) {
|
||||
self.stars = stars
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -89,7 +89,7 @@ open class Video: View {
|
||||
})
|
||||
case .failed:
|
||||
if let errorObject = item.loadFailedError {
|
||||
MVMCoreLoggingHandler.shared()?.addError(toLog: errorObject)
|
||||
MVMCoreLoggingHandler.addError(toLog: errorObject)
|
||||
}
|
||||
default:
|
||||
break
|
||||
|
||||
@ -14,7 +14,7 @@ open class VisibleBehaviorForVideoModel: PageBehaviorModelProtocol {
|
||||
public var shouldAllowMultipleInstances: Bool = true
|
||||
public weak var videoModel: VideoModel?
|
||||
|
||||
init(with videoModel: VideoModel) {
|
||||
public init(with videoModel: VideoModel) {
|
||||
self.videoModel = videoModel
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,8 +170,11 @@ extension WebView : WKNavigationDelegate {
|
||||
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
||||
//validate request url
|
||||
//all validated link should be open in safari
|
||||
if (navigationAction.navigationType == .linkActivated), let urlString = navigationAction.request.url?.absoluteString.removingPercentEncoding, !urlString.contains("#") {
|
||||
MVMCoreActionHandler.shared()?.openURL(inWebView: navigationAction.request.url, actionInformation: nil, additionalData: nil, delegateObject: nil)
|
||||
if (navigationAction.navigationType == .linkActivated),
|
||||
let url = navigationAction.request.url,
|
||||
let urlString = url.absoluteString.removingPercentEncoding,
|
||||
!urlString.contains("#") {
|
||||
MVMCoreUIActionHandler.shared()?.openURL(inSafariWebView: url)
|
||||
decisionHandler(.cancel)
|
||||
} else {
|
||||
decisionHandler(.allow)
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MVMCore
|
||||
|
||||
@objcMembers public class WebViewModel: MoleculeModelProtocol {
|
||||
public static var identifier: String = "webview"
|
||||
@ -30,6 +31,12 @@ import Foundation
|
||||
case borderColor
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init() {}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
|
||||
@ -49,125 +49,28 @@ import UIKit
|
||||
}
|
||||
heightConstraint?.constant = graphObject.diameter
|
||||
|
||||
// iOS 12 uses the conic gradient and a mask for simplicity.
|
||||
if #available(iOS 12, *) {
|
||||
let gradient = CAGradientLayer()
|
||||
gradient.type = .conic
|
||||
gradient.startPoint = CGPoint(x: 0.5, y: 0.5)
|
||||
gradient.endPoint = CGPoint(x: 0.5, y: 0.0)
|
||||
gradient.frame = CGRect(x: 0, y: 0, width: graphObject.diameter, height: graphObject.diameter)
|
||||
gradient.colors = graphObject.colors.map({ (color) -> CGColor in
|
||||
return color.cgColor
|
||||
})
|
||||
gradientLayer = gradient
|
||||
layer.addSublayer(gradient)
|
||||
|
||||
let center = CGPoint(x: gradient.bounds.midX, y: gradient.bounds.midY)
|
||||
let radius = (graphObject.diameter - graphObject.lineWidth) / 2.0
|
||||
let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: (3 / 2 * .pi), endAngle: -(1 / 2 * .pi), clockwise: false)
|
||||
let mask = CAShapeLayer()
|
||||
mask.fillColor = UIColor.clear.cgColor
|
||||
mask.strokeColor = UIColor.white.cgColor
|
||||
mask.lineWidth = graphObject.lineWidth
|
||||
mask.path = path.cgPath
|
||||
gradient.mask = mask
|
||||
return
|
||||
}
|
||||
let gradient = CAGradientLayer()
|
||||
gradient.type = .conic
|
||||
gradient.startPoint = CGPoint(x: 0.5, y: 0.5)
|
||||
gradient.endPoint = CGPoint(x: 0.5, y: 0.0)
|
||||
gradient.frame = CGRect(x: 0, y: 0, width: graphObject.diameter, height: graphObject.diameter)
|
||||
gradient.colors = graphObject.colors.map({ (color) -> CGColor in
|
||||
return color.cgColor
|
||||
})
|
||||
gradientLayer = gradient
|
||||
layer.addSublayer(gradient)
|
||||
|
||||
//create circle path
|
||||
let radius = graphObject.diameter / 2.0
|
||||
|
||||
//begin point will be at the bottom, clockwise direction
|
||||
let path = UIBezierPath(arcCenter: CGPoint(x: radius
|
||||
, y: radius), radius: radius - graphObject.lineWidth/2.0, startAngle: CGFloat(Wheel.getPiValue(90.0)), endAngle: CGFloat(Wheel.getPiValue(90.0 + 360.0)), clockwise: true)
|
||||
path.lineWidth = graphObject.lineWidth
|
||||
|
||||
let circleLayer = CAShapeLayer()
|
||||
circleLayer.path = path.cgPath
|
||||
circleLayer.lineCap = .round
|
||||
circleLayer.lineWidth = graphObject.lineWidth
|
||||
circleLayer.fillColor = UIColor.clear.cgColor
|
||||
circleLayer.strokeColor = UIColor.black.cgColor
|
||||
|
||||
//create gradient layer
|
||||
let gradientLayer = createGradientLayer(graphObject)
|
||||
gradientLayer.mask = circleLayer
|
||||
layer.addSublayer(gradientLayer)
|
||||
self.gradientLayer = gradientLayer
|
||||
let center = CGPoint(x: gradient.bounds.midX, y: gradient.bounds.midY)
|
||||
let radius = (graphObject.diameter - graphObject.lineWidth) / 2.0
|
||||
let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: (3 / 2 * .pi), endAngle: -(1 / 2 * .pi), clockwise: false)
|
||||
let mask = CAShapeLayer()
|
||||
mask.fillColor = UIColor.clear.cgColor
|
||||
mask.strokeColor = UIColor.white.cgColor
|
||||
mask.lineWidth = graphObject.lineWidth
|
||||
mask.path = path.cgPath
|
||||
gradient.mask = mask
|
||||
}
|
||||
|
||||
/*
|
||||
create three gradient layer for circle layout.
|
||||
_____________
|
||||
| → | top layer for smooth gradient
|
||||
-------------
|
||||
| | |
|
||||
| ↑ | ↓ |
|
||||
| | |
|
||||
-------------
|
||||
*/
|
||||
func createGradientLayer(_ graphObject: WheelModel) -> CALayer {
|
||||
let containLayer = CALayer()
|
||||
containLayer.frame = CGRect(x: 0, y: 0, width: graphObject.diameter, height: graphObject.diameter)
|
||||
let radius = graphObject.diameter / 2.0
|
||||
|
||||
//create graident layers
|
||||
guard graphObject.colors.count > 1 else {
|
||||
containLayer.backgroundColor = graphObject.colors.first?.cgColor
|
||||
return containLayer
|
||||
}
|
||||
var topGradientHeight : CGFloat = 0.0
|
||||
var leftColors = graphObject.colors.prefix(through: graphObject.colors.count/2)
|
||||
let rightColors = graphObject.colors.suffix(from: graphObject.colors.count/2)
|
||||
|
||||
// make the top layer higher than line width for smooth look
|
||||
topGradientHeight = min(max(graphObject.lineWidth, 1.0/(1.0+CGFloat(graphObject.colors.count))*graphObject.diameter), graphObject.diameter)
|
||||
let topLayer = CAGradientLayer()
|
||||
topLayer.frame = CGRect(x: 0.0, y: 0.0, width: graphObject.diameter, height: topGradientHeight)
|
||||
//make the graident edge more smoothy
|
||||
topLayer.startPoint = CGPoint(x: 0.25, y: 0.0)
|
||||
topLayer.endPoint = CGPoint(x: 0.75, y: 0.0)
|
||||
//if number of colors is even, need to display gradient layer, otherwise make top layer as solid color layer
|
||||
if graphObject.colors.count % 2 == 0 {
|
||||
leftColors.removeLast()
|
||||
let firstColor = leftColors.last!.cgColor
|
||||
let secondColor = rightColors.first!.cgColor
|
||||
topLayer.colors = [firstColor, secondColor]
|
||||
} else {
|
||||
topLayer.backgroundColor = leftColors.last?.cgColor
|
||||
}
|
||||
containLayer.addSublayer(topLayer)
|
||||
|
||||
let leftLayer = CAGradientLayer()
|
||||
leftLayer.frame = CGRect(x: 0, y: topGradientHeight, width: radius, height: graphObject.diameter - topGradientHeight)
|
||||
leftLayer.startPoint = CGPoint(x: 0, y: 1)
|
||||
leftLayer.endPoint = CGPoint(x: 0, y: 0)
|
||||
|
||||
//count of graidentLayer.colors must be bigger than 1, otherwise set backgroundColor
|
||||
if leftColors.count > 1 {
|
||||
leftLayer.colors = leftColors.map({ (color) -> CGColor in
|
||||
return color.cgColor
|
||||
})
|
||||
} else {
|
||||
leftLayer.backgroundColor = leftColors.first?.cgColor
|
||||
}
|
||||
containLayer.addSublayer(leftLayer)
|
||||
|
||||
let rightLayer = CAGradientLayer()
|
||||
rightLayer.frame = CGRect(x: radius, y: topGradientHeight, width: radius, height: graphObject.diameter - topGradientHeight)
|
||||
rightLayer.startPoint = CGPoint(x: 0, y: 0)
|
||||
rightLayer.endPoint = CGPoint(x: 0, y: 1)
|
||||
if rightColors.count > 1 {
|
||||
rightLayer.colors = rightColors.map({ (color) -> CGColor in
|
||||
return color.cgColor
|
||||
})
|
||||
} else {
|
||||
rightLayer.backgroundColor = rightColors.first?.cgColor
|
||||
}
|
||||
containLayer.addSublayer(rightLayer)
|
||||
|
||||
return containLayer
|
||||
}
|
||||
//MARK: MVMCoreUIViewConstrainingProtocol
|
||||
public func needsToBeConstrained() -> Bool {
|
||||
return true
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
//
|
||||
// UIImageRenderingMode+Extension.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Nadigadda, Sumanth on 24/03/22.
|
||||
// Copyright © 2022 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
enum RenderingModeError: Error {
|
||||
case notAnRenderingMode
|
||||
}
|
||||
|
||||
extension UIImage.RenderingMode: RawRepresentable {
|
||||
|
||||
init?(rawValue: String) {
|
||||
switch rawValue {
|
||||
case "alwaysOriginal":
|
||||
self = .alwaysOriginal
|
||||
case "alwaysTemplate":
|
||||
self = .alwaysTemplate
|
||||
case "automatic":
|
||||
self = .automatic
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var rawValueString: String {
|
||||
switch self {
|
||||
case .alwaysOriginal:
|
||||
return "alwaysOriginal"
|
||||
case .alwaysTemplate:
|
||||
return "alwaysTemplate"
|
||||
case .automatic:
|
||||
return "automatic"
|
||||
@unknown default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UIImage.RenderingMode: Codable {
|
||||
public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.singleValueContainer()
|
||||
let string = try typeContainer.decode(String.self)
|
||||
guard let renderingMode = UIImage.RenderingMode(rawValue: string) else {
|
||||
throw RenderingModeError.notAnRenderingMode
|
||||
}
|
||||
self = renderingMode
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(rawValueString)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,123 @@
|
||||
//
|
||||
// TitleLockup.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Nadigadda, Sumanth on 04/05/22.
|
||||
// Copyright © 2022 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
@objcMembers open class TitleLockup: View {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Outlets
|
||||
//--------------------------------------------------
|
||||
|
||||
public let eyebrow = Label(fontStyle: .RegularBodySmall)
|
||||
public let title = Label(fontStyle: .RegularBodySmall)
|
||||
public let subTitle = Label(fontStyle: .RegularBodySmall)
|
||||
public lazy var stack: UIStackView = {
|
||||
let stack = UIStackView(arrangedSubviews: [eyebrow, title, subTitle])
|
||||
stack.translatesAutoresizingMaskIntoConstraints = false
|
||||
stack.axis = .vertical
|
||||
return stack
|
||||
}()
|
||||
|
||||
var castModel: TitleLockupModel? {
|
||||
get { return model as? TitleLockupModel }
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initialization
|
||||
//--------------------------------------------------
|
||||
|
||||
public convenience init() {
|
||||
self.init(frame: .zero)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - MFViewProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
addSubview(stack)
|
||||
NSLayoutConstraint.constraintPinSubview(toSuperview: stack)
|
||||
}
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
stack.updateView(size)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - MoleculeViewProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
stack.reset()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - MoleculeViewProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
guard let model = model as? TitleLockupModel else { return }
|
||||
stack.setCustomSpacing(model.defaultEyebrowTitleSpacing(), after: eyebrow)
|
||||
stack.setCustomSpacing(model.defaultTitleSubTitleSpacing(), after: title)
|
||||
stack.updateContainedMolecules(with: [model.eyebrow,
|
||||
model.title,
|
||||
model.subTitle],
|
||||
delegateObject, additionalData)
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 65
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Accessibility Helpers
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Returns the labels text in one message.
|
||||
func getAccessibilityMessage() -> String? {
|
||||
|
||||
var message = ""
|
||||
|
||||
if let eyebrowLabel = eyebrow.text {
|
||||
message += eyebrowLabel + ", "
|
||||
}
|
||||
|
||||
if let headlineLabel = title.text {
|
||||
message += headlineLabel + ", "
|
||||
}
|
||||
|
||||
if let bodyLabel = subTitle.text {
|
||||
message += bodyLabel
|
||||
}
|
||||
|
||||
return message.count > 0 ? message : nil
|
||||
}
|
||||
|
||||
/// Returns an array of the appropriate accessibility elements.
|
||||
func getAccessibilityElements() -> [Any]? {
|
||||
|
||||
var elements: [UIView] = []
|
||||
|
||||
if eyebrow.hasText {
|
||||
elements.append(eyebrow)
|
||||
}
|
||||
|
||||
if title.hasText {
|
||||
elements.append(title)
|
||||
}
|
||||
|
||||
if subTitle.hasText {
|
||||
elements.append(subTitle)
|
||||
}
|
||||
|
||||
return elements.count > 0 ? elements : nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,215 @@
|
||||
//
|
||||
// TitleLockupModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Nadigadda, Sumanth on 04/05/22.
|
||||
// Copyright © 2022 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import VDSColorTokens
|
||||
|
||||
public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtocol {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var identifier: String = "titleLockup"
|
||||
public var moleculeName: String = TitleLockupModel.identifier
|
||||
|
||||
public var eyebrow: LabelModel?
|
||||
public var title: LabelModel
|
||||
public var subTitle: LabelModel?
|
||||
|
||||
public var alignment: Alignment = .left {
|
||||
didSet {
|
||||
///Updating the text alignment for all labels
|
||||
if let textAlignment = NSTextAlignment(rawValue: alignment.rawValue) {
|
||||
eyebrow?.textAlignment = textAlignment
|
||||
title.textAlignment = textAlignment
|
||||
subTitle?.textAlignment = textAlignment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var inverted: Bool = false {
|
||||
didSet {
|
||||
///Updating the text color
|
||||
eyebrow?.textColor = titleColor
|
||||
title.textColor = titleColor
|
||||
subTitle?.textColor = subTitleColor
|
||||
}
|
||||
}
|
||||
|
||||
private var _backgroundColor: Color?
|
||||
public var backgroundColor: Color? {
|
||||
get {
|
||||
return inverted ? Color(uiColor: VDSColor.backgroundPrimaryDark) : Color(uiColor: VDSColor.backgroundPrimaryLight)
|
||||
}
|
||||
set {
|
||||
_backgroundColor = newValue
|
||||
}
|
||||
}
|
||||
|
||||
public var titleColor: Color? {
|
||||
return inverted ? Color(uiColor: VDSColor.elementsPrimaryOndark) : Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
}
|
||||
|
||||
public var subTitleColor: Color? {
|
||||
return inverted ? Color(uiColor: VDSColor.elementsSecondaryOndark) : Color(uiColor: VDSColor.elementsSecondaryOnlight)
|
||||
}
|
||||
|
||||
public var children: [MoleculeModelProtocol] {
|
||||
[eyebrow, title, subTitle].compactMap { (molecule: MoleculeModelProtocol?) in molecule }
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(eyebrow: LabelModel? = nil, title: LabelModel, subTitle: LabelModel? = nil) throws {
|
||||
self.eyebrow = eyebrow
|
||||
self.title = title
|
||||
self.subTitle = subTitle
|
||||
updateLabelAttributes()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Enum
|
||||
//--------------------------------------------------
|
||||
|
||||
public enum Alignment: String, Codable {
|
||||
case left
|
||||
case center
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Styling
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Returns the default fontStyle for the subtitle, based on the title fontStyle.
|
||||
func defaultSubtitleFontStyle() -> Styler.Font {
|
||||
switch title.fontStyle {
|
||||
case .RegularTitleXLarge, .RegularTitle2XLarge, .RegularFeatureXSmall:
|
||||
return .RegularBodyLarge
|
||||
case .RegularFeatureSmall, .RegularFeatureMedium:
|
||||
return .RegularTitleLarge
|
||||
default:
|
||||
return .RegularBodySmall
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the default spacing between the eyebrow and title, based on the title fontStyle.
|
||||
func defaultEyebrowTitleSpacing() -> CGFloat {
|
||||
switch title.fontStyle {
|
||||
case .RegularTitleXLarge, .RegularTitle2XLarge, .RegularFeatureXSmall, .RegularFeatureSmall:
|
||||
return Padding.Three
|
||||
case .RegularFeatureMedium:
|
||||
return subTitle?.fontStyle == .RegularBodyLarge ? Padding.Three : Padding.Four
|
||||
default:
|
||||
return Padding.Two
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the default spacing between the title and subTitle, based on the title fontStyle.
|
||||
func defaultTitleSubTitleSpacing() -> CGFloat {
|
||||
switch title.fontStyle {
|
||||
case .RegularTitleXLarge:
|
||||
return Padding.Three
|
||||
case .RegularTitle2XLarge, .RegularFeatureXSmall, .RegularFeatureSmall:
|
||||
return Padding.Four
|
||||
case .RegularFeatureMedium:
|
||||
return Padding.Five
|
||||
default:
|
||||
return Padding.Two
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case eyebrow
|
||||
case title
|
||||
case subTitle
|
||||
case inverted
|
||||
case alignment
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
title = try typeContainer.decodeMolecule(codingKey: .title)
|
||||
eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow)
|
||||
subTitle = try typeContainer.decodeMoleculeIfPresent(codingKey: .subTitle)
|
||||
|
||||
if let newAlignment = try typeContainer.decodeIfPresent(Alignment.self, forKey: .alignment) {
|
||||
alignment = newAlignment
|
||||
}
|
||||
|
||||
if let invertedStatus = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) {
|
||||
inverted = invertedStatus
|
||||
}
|
||||
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
|
||||
updateLabelAttributes()
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(eyebrow, forKey: .eyebrow)
|
||||
try container.encodeModel(title, forKey: .title)
|
||||
try container.encodeIfPresent(subTitle, forKey: .subTitle)
|
||||
try container.encode(alignment, forKey: .alignment)
|
||||
try container.encode(inverted, forKey: .inverted)
|
||||
try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Model updates
|
||||
//--------------------------------------------------
|
||||
|
||||
private func updateLabelAttributes() {
|
||||
// If subtitle style is not available, will set font style based on the component
|
||||
if subTitle?.fontStyle == nil {
|
||||
subTitle?.fontStyle = defaultSubtitleFontStyle()
|
||||
}
|
||||
|
||||
// If eyebrow style is not available, will set font style based on the component. Eyebrow and subtitle share the same font size
|
||||
if eyebrow?.fontStyle == nil {
|
||||
eyebrow?.fontStyle = subTitle?.fontStyle
|
||||
}
|
||||
|
||||
// Updating the text color
|
||||
if eyebrow?.textColor == nil {
|
||||
eyebrow?.textColor = subTitleColor
|
||||
}
|
||||
if title.textColor == nil {
|
||||
title.textColor = titleColor
|
||||
}
|
||||
if subTitle?.textColor == nil {
|
||||
subTitle?.textColor = subTitleColor
|
||||
}
|
||||
|
||||
// Updating the text alignment for all labels
|
||||
if let textAlignment = NSTextAlignment(rawValue: alignment.rawValue) {
|
||||
if eyebrow?.textAlignment == nil {
|
||||
eyebrow?.textAlignment = textAlignment
|
||||
}
|
||||
if title.textAlignment == nil {
|
||||
title.textAlignment = textAlignment
|
||||
}
|
||||
if subTitle?.textAlignment == nil {
|
||||
subTitle?.textAlignment = textAlignment
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -23,7 +23,7 @@ public class ListThreeColumnInternationalDataDividerModel: ListItemModel, Molecu
|
||||
// MARK: - Initializers
|
||||
//------------------------------------------------------
|
||||
|
||||
public init (leftLabel: LabelModel, centerLabel: LabelModel, rightLabel: LabelModel) {
|
||||
public init(leftLabel: LabelModel, centerLabel: LabelModel, rightLabel: LabelModel) {
|
||||
self.leftLabel = leftLabel
|
||||
self.centerLabel = centerLabel
|
||||
self.rightLabel = rightLabel
|
||||
|
||||
@ -33,7 +33,7 @@ open class HeaderView: Container {
|
||||
|
||||
public override func setupView() {
|
||||
super.setupView()
|
||||
line.setStyle(.heavy)
|
||||
line.setStyle(.none)
|
||||
addSubview(line)
|
||||
NSLayoutConstraint.pinViewBottom(toSuperview: line, useMargins: false, constant: 0).isActive = true
|
||||
NSLayoutConstraint.pinViewLeft(toSuperview: line, useMargins: true, constant: 0).isActive = true
|
||||
@ -43,7 +43,7 @@ open class HeaderView: Container {
|
||||
// MARK: - MoleculeViewProtocol
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
line.setStyle(.heavy)
|
||||
line.setStyle(.none)
|
||||
molecule?.reset()
|
||||
}
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ public class MoleculeHeaderView: MoleculeContainer {
|
||||
|
||||
public override func setupView() {
|
||||
super.setupView()
|
||||
line.setStyle(.heavy)
|
||||
line.setStyle(.none)
|
||||
addSubview(line)
|
||||
NSLayoutConstraint.pinViewBottom(toSuperview: line, useMargins: false, constant: 0).isActive = true
|
||||
NSLayoutConstraint.pinViewLeft(toSuperview: line, useMargins: true, constant: 0).isActive = true
|
||||
@ -40,7 +40,7 @@ public class MoleculeHeaderView: MoleculeContainer {
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
line.setStyle(.heavy)
|
||||
line.setStyle(.none)
|
||||
}
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
|
||||
@ -22,7 +22,7 @@ import Foundation
|
||||
|
||||
public override func setupView() {
|
||||
super.setupView()
|
||||
line.setStyle(.thin)
|
||||
line.setStyle(.primary)
|
||||
contentView.addSubview(line)
|
||||
NSLayoutConstraint.pinViewBottom(toSuperview: line, useMargins: false, constant: 0).isActive = true
|
||||
NSLayoutConstraint.pinViewLeft(toSuperview: line, useMargins: true, constant: 0).isActive = true
|
||||
@ -51,7 +51,7 @@ import Foundation
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
line.setStyle(.thin)
|
||||
line.setStyle(.primary)
|
||||
molecule?.reset()
|
||||
}
|
||||
|
||||
|
||||
@ -14,6 +14,13 @@
|
||||
public class override var identifier: String { "sectionHeader" }
|
||||
public var line: LineModel?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
public override init(with moleculeModel: MoleculeModelProtocol) {
|
||||
super.init(with: moleculeModel)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
@ -42,7 +49,7 @@
|
||||
bottomPadding = PaddingDefaultVerticalSpacing3
|
||||
}
|
||||
if line == nil {
|
||||
line = LineModel(type: .thin)
|
||||
line = LineModel(type: .primary)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
import MVMCore
|
||||
|
||||
@objcMembers public class RadioButtonLabelModel: MoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -16,7 +16,17 @@ import Foundation
|
||||
|
||||
public static var identifier: String = "radioButtonLabel"
|
||||
public var backgroundColor: Color?
|
||||
public var moleculeName: String
|
||||
public var moleculeName: String = RadioButtonLabelModel.identifier
|
||||
public var radioButton: RadioButtonModel
|
||||
public var label: LabelModel
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(radioButton: RadioButtonModel, label: LabelModel) {
|
||||
self.radioButton = radioButton
|
||||
self.label = label
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
// Created by Scott Pfeil on 5/28/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import VDSColorTokens
|
||||
|
||||
@objcMembers open class TabBar: UITabBar, MoleculeViewProtocol, TabBarProtocol, UITabBarDelegate {
|
||||
|
||||
@ -21,7 +21,6 @@
|
||||
delegate = self
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
line.addLine(to: self, edge: .top, useMargin: false)
|
||||
line.backgroundColor = .mvmCoolGray3
|
||||
set(with: model, delegateObject, additionalData)
|
||||
}
|
||||
|
||||
@ -34,47 +33,36 @@
|
||||
self.model = model
|
||||
|
||||
// Set appearance
|
||||
if #available(iOS 13.0, *) {
|
||||
let appearance = UITabBarAppearance()
|
||||
appearance.backgroundColor = model.backgroundColor?.uiColor
|
||||
set(tabItemAppearance: appearance.stackedLayoutAppearance, model: model)
|
||||
set(tabItemAppearance: appearance.inlineLayoutAppearance, model: model)
|
||||
set(tabItemAppearance: appearance.compactInlineLayoutAppearance, model: model)
|
||||
standardAppearance = appearance
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
backgroundColor = model.backgroundColor?.uiColor
|
||||
tintColor = model.selectedColor.uiColor
|
||||
unselectedItemTintColor = model.unSelectedColor.uiColor
|
||||
barTintColor = model.backgroundColor?.uiColor
|
||||
isTranslucent = false
|
||||
}
|
||||
let appearance = UITabBarAppearance()
|
||||
appearance.backgroundColor = model.backgroundColor?.uiColor
|
||||
set(tabItemAppearance: appearance.stackedLayoutAppearance, model: model)
|
||||
set(tabItemAppearance: appearance.inlineLayoutAppearance, model: model)
|
||||
set(tabItemAppearance: appearance.compactInlineLayoutAppearance, model: model)
|
||||
standardAppearance = appearance
|
||||
|
||||
// Add buttons
|
||||
var tabs: [UITabBarItem] = []
|
||||
for (index, tab) in model.tabs.enumerated() {
|
||||
let tabBarItem = UITabBarItem(title: tab.title, image: MVMCoreCache.shared()?.getImageFromRegisteredBundles(tab.image), tag: index)
|
||||
tabBarItem.accessibilityLabel = tab.accessibilityText
|
||||
if #available(iOS 13.0, *) {
|
||||
} else {
|
||||
tabBarItem.titlePositionAdjustment = UIOffset(horizontal: 0, vertical: -3)
|
||||
tabBarItem.setTitleTextAttributes([NSAttributedString.Key.font: MFFonts.mfFontTXRegular(8)], for: .normal)
|
||||
}
|
||||
tabs.append(tabBarItem)
|
||||
}
|
||||
setItems(tabs, animated: false)
|
||||
selectedItem = tabs[model.selectedTab]
|
||||
|
||||
guard let lineModel = line.lineModel else { return }
|
||||
lineModel.inverted = model.style == .dark
|
||||
line.set(with: lineModel, delegateObject, additionalData)
|
||||
}
|
||||
|
||||
/// Sets the item colors.
|
||||
@available(iOS 13.0, *)
|
||||
private func set(tabItemAppearance: UITabBarItemAppearance, model: TabBarModel) {
|
||||
tabItemAppearance.normal.iconColor = model.unSelectedColor.uiColor
|
||||
tabItemAppearance.normal.titleTextAttributes = [NSAttributedString.Key.foregroundColor: model.unSelectedColor.uiColor, NSAttributedString.Key.font: MFFonts.mfFontTXRegular(8)]
|
||||
tabItemAppearance.normal.titleTextAttributes = [NSAttributedString.Key.foregroundColor: model.unSelectedColor.uiColor, NSAttributedString.Key.font: MFFonts.mfFontTXBold(10)]
|
||||
tabItemAppearance.normal.titlePositionAdjustment = UIOffset(horizontal: 0, vertical: -3)
|
||||
|
||||
tabItemAppearance.selected.iconColor = model.selectedColor.uiColor
|
||||
tabItemAppearance.selected.titleTextAttributes = [NSAttributedString.Key.foregroundColor: model.selectedColor.uiColor, NSAttributedString.Key.font: MFFonts.mfFontTXRegular(8)]
|
||||
tabItemAppearance.selected.titleTextAttributes = [NSAttributedString.Key.foregroundColor: model.selectedColor.uiColor, NSAttributedString.Key.font: MFFonts.mfFontTXBold(10)]
|
||||
tabItemAppearance.selected.titlePositionAdjustment = UIOffset(horizontal: 0, vertical: -3)
|
||||
}
|
||||
|
||||
|
||||
@ -7,16 +7,55 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import VDSColorTokens
|
||||
|
||||
public class TabBarModel: MoleculeModelProtocol {
|
||||
open class TabBarModel: MoleculeModelProtocol {
|
||||
public static var identifier: String = "tabBar"
|
||||
public var backgroundColor: Color? = Color(uiColor: .white)
|
||||
public var tabs: [TabBarItemModel]
|
||||
public var selectedColor = Color(uiColor: .mvmBlack)
|
||||
public var unSelectedColor = Color(uiColor: .mvmCoolGray6)
|
||||
open var tabs: [TabBarItemModel]
|
||||
|
||||
private var _backgroundColor: Color?
|
||||
open var backgroundColor: Color? {
|
||||
get {
|
||||
if let backgroundColor = _backgroundColor { return backgroundColor }
|
||||
if let style = style,
|
||||
style == .dark { return Color(uiColor: VDSColor.backgroundPrimaryDark) }
|
||||
return Color(uiColor: VDSColor.backgroundPrimaryLight)
|
||||
}
|
||||
set {
|
||||
_backgroundColor = newValue
|
||||
}
|
||||
}
|
||||
|
||||
private var _selectedColor: Color?
|
||||
open var selectedColor: Color {
|
||||
get {
|
||||
if let selectedColor = _selectedColor { return selectedColor }
|
||||
if let style = style,
|
||||
style == .dark { return Color(uiColor: VDSColor.elementsPrimaryOndark) }
|
||||
return Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
}
|
||||
set {
|
||||
_selectedColor = newValue
|
||||
}
|
||||
}
|
||||
|
||||
private var _unSelectedColor: Color?
|
||||
open var unSelectedColor: Color {
|
||||
get {
|
||||
if let unSelectedColor = _unSelectedColor { return unSelectedColor }
|
||||
if let style = style,
|
||||
style == .dark { return Color(uiColor: VDSColor.elementsSecondaryOndark) }
|
||||
return Color(uiColor: VDSColor.elementsSecondaryOnlight)
|
||||
}
|
||||
set {
|
||||
_unSelectedColor = newValue
|
||||
}
|
||||
}
|
||||
|
||||
open var style: NavigationItemStyle? = .dark
|
||||
|
||||
// Must be capped to 0...(tabs.count - 1)
|
||||
public var selectedTab: Int = 0
|
||||
open var selectedTab: Int = 0
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
@ -25,6 +64,7 @@ public class TabBarModel: MoleculeModelProtocol {
|
||||
case selectedColor
|
||||
case unSelectedColor
|
||||
case selectedTab
|
||||
case style
|
||||
}
|
||||
|
||||
public init(with tabs: [TabBarItemModel]) {
|
||||
@ -46,24 +86,28 @@ public class TabBarModel: MoleculeModelProtocol {
|
||||
if let index = try typeContainer.decodeIfPresent(Int.self, forKey: .selectedTab) {
|
||||
selectedTab = index
|
||||
}
|
||||
if let navStyle = try typeContainer.decodeIfPresent(NavigationItemStyle.self, forKey: .style) {
|
||||
style = navStyle
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
open func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(tabs, forKey: .tabs)
|
||||
try container.encode(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encode(selectedColor, forKey: .selectedColor)
|
||||
try container.encode(unSelectedColor, forKey: .unSelectedColor)
|
||||
try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(_selectedColor, forKey: .selectedColor)
|
||||
try container.encodeIfPresent(_unSelectedColor, forKey: .unSelectedColor)
|
||||
try container.encode(selectedTab, forKey: .selectedTab)
|
||||
try container.encodeIfPresent(style, forKey: .style)
|
||||
}
|
||||
}
|
||||
|
||||
public class TabBarItemModel: Codable {
|
||||
var title: String?
|
||||
var image: String
|
||||
var action: ActionModelProtocol
|
||||
var accessibilityText: String?
|
||||
open class TabBarItemModel: Codable {
|
||||
open var title: String?
|
||||
open var image: String
|
||||
open var action: ActionModelProtocol
|
||||
open var accessibilityText: String?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case title
|
||||
@ -86,7 +130,7 @@ public class TabBarItemModel: Codable {
|
||||
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
open func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeIfPresent(title, forKey: .title)
|
||||
try container.encode(image, forKey: .image)
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import VDSColorTokens
|
||||
|
||||
@objc public protocol TabsDelegate {
|
||||
func shouldSelectItem(_ indexPath: IndexPath, tabs: Tabs) -> Bool
|
||||
@ -15,7 +16,6 @@ import UIKit
|
||||
|
||||
@objcMembers open class Tabs: View, MVMCoreUIViewConstrainingProtocol, MFButtonProtocol {
|
||||
|
||||
|
||||
public var tabsModel: TabsModel? {
|
||||
get { return model as? TabsModel }
|
||||
}
|
||||
@ -24,7 +24,7 @@ import UIKit
|
||||
var additionalData: [AnyHashable: Any]?
|
||||
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
public var collectionView: UICollectionView?
|
||||
public var collectionView: CollectionView?
|
||||
|
||||
let bottomScrollView = UIScrollView(frame: .zero)
|
||||
let bottomContentView = View()
|
||||
@ -39,17 +39,15 @@ import UIKit
|
||||
weak public var delegate: TabsDelegate?
|
||||
|
||||
//control var
|
||||
public var heightConstraint: NSLayoutConstraint?
|
||||
public var selectedIndex: Int = 0
|
||||
public var paddingBeforeFirstTab: Bool = true
|
||||
|
||||
//constant
|
||||
let TabCellId = "TabCell"
|
||||
public let sectionPadding: CGFloat = 20.0
|
||||
public let cellSpacing: CGFloat = 34.0
|
||||
public let cellHeight: CGFloat = 27.0
|
||||
public let itemSpacing: CGFloat = 20.0
|
||||
public let cellHeight: CGFloat = 28.0
|
||||
public let selectionLineHeight: CGFloat = 4.0
|
||||
public let selectionLineWidth: CGFloat = 32.0
|
||||
public let minimumItemWidth: CGFloat = 32.0
|
||||
public let selectionLineMovingTime: TimeInterval = 0.2
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -64,11 +62,12 @@ import UIKit
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
collectionView?.updateView(size)
|
||||
}
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
backgroundColor = .white
|
||||
backgroundColor = VDSColor.backgroundPrimaryLight
|
||||
addSubview(bottomLine)
|
||||
setupCollectionView()
|
||||
setupSelectionLine()
|
||||
@ -77,9 +76,9 @@ import UIKit
|
||||
|
||||
func setupCollectionView () {
|
||||
layout.scrollDirection = .horizontal
|
||||
layout.minimumLineSpacing = cellSpacing
|
||||
layout.minimumLineSpacing = 0
|
||||
|
||||
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||||
let collectionView = CollectionView(frame: .zero, collectionViewLayout: layout)
|
||||
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||
collectionView.register(TabItemCell.self, forCellWithReuseIdentifier: TabCellId)
|
||||
collectionView.backgroundColor = .clear
|
||||
@ -96,7 +95,7 @@ import UIKit
|
||||
bottomScrollView.delegate = self
|
||||
addSubview(bottomScrollView)
|
||||
bottomScrollView.addSubview(bottomContentView)
|
||||
selectionLine.backgroundColor = .mvmRed
|
||||
selectionLine.backgroundColor = VDSColor.paletteRed
|
||||
bottomContentView.addSubview(selectionLine)
|
||||
bringSubviewToFront(bottomScrollView)
|
||||
}
|
||||
@ -114,7 +113,7 @@ import UIKit
|
||||
selectionLine.heightAnchor.constraint(equalToConstant: selectionLineHeight).isActive = true
|
||||
selectionLineLeftConstraint = selectionLine.leftAnchor.constraint(equalTo: bottomContentView.leftAnchor)
|
||||
selectionLineLeftConstraint?.isActive = true
|
||||
selectionLineWidthConstraint = selectionLine.widthAnchor.constraint(equalToConstant: selectionLineWidth)
|
||||
selectionLineWidthConstraint = selectionLine.widthAnchor.constraint(equalToConstant: minimumItemWidth)
|
||||
selectionLineWidthConstraint?.isActive = true
|
||||
NSLayoutConstraint.constraintPinSubview(toSuperview: bottomContentView)
|
||||
|
||||
@ -155,8 +154,7 @@ import UIKit
|
||||
self.delegateObject = delegateObject
|
||||
self.additionalData = additionalData
|
||||
selectedIndex = tabsModel?.selectedIndex ?? 0
|
||||
// TODO: Commented out until we have model support for bar color. Should also do unselected color.
|
||||
//selectionLine.backgroundColor = tabsModel?.selectedColor.uiColor
|
||||
selectionLine.backgroundColor = tabsModel?.selectedBarColor.uiColor
|
||||
reloadData()
|
||||
}
|
||||
}
|
||||
@ -171,10 +169,11 @@ extension Tabs: UICollectionViewDataSource {
|
||||
}
|
||||
|
||||
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
guard let labelModel = tabsModel?.tabs[indexPath.row].label, let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TabCellId, for: indexPath) as? TabItemCell else {
|
||||
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TabCellId, for: indexPath) as? TabItemCell else {
|
||||
return UICollectionViewCell()
|
||||
}
|
||||
cell.updateCell(labelModel: labelModel, indexPath: indexPath, delegateObject: delegateObject, additionalData: additionalData, selected: indexPath.row == selectedIndex, tabsModel: tabsModel)
|
||||
cell.updateCell(indexPath: indexPath, delegateObject: delegateObject, additionalData: additionalData, selected: indexPath.row == selectedIndex, tabsModel: tabsModel)
|
||||
updateView(collectionView.bounds.width)
|
||||
return cell
|
||||
}
|
||||
}
|
||||
@ -182,10 +181,16 @@ extension Tabs: UICollectionViewDataSource {
|
||||
extension Tabs: UICollectionViewDelegateFlowLayout {
|
||||
|
||||
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
|
||||
guard self.collectionView(collectionView, numberOfItemsInSection: indexPath.section) != 2 else {
|
||||
// If two tabs, take up the screen
|
||||
let insets = self.collectionView(collectionView, layout: collectionViewLayout, insetForSectionAt: indexPath.section)
|
||||
let width = (collectionView.bounds.width / 2.0) - insets.left - insets.right
|
||||
return CGSize(width: width, height: cellHeight)
|
||||
}
|
||||
guard let labelModel = tabsModel?.tabs[indexPath.row].label else {
|
||||
return .zero
|
||||
}
|
||||
return CGSize(width: getLabelWidth(labelModel).width, height: cellHeight)
|
||||
return CGSize(width: max(minimumItemWidth, getLabelWidth(labelModel).width), height: cellHeight)
|
||||
}
|
||||
|
||||
//pre calculate the width of the collection cell
|
||||
@ -200,7 +205,7 @@ extension Tabs: UICollectionViewDelegateFlowLayout {
|
||||
|
||||
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
|
||||
guard section == 0 else {
|
||||
return UIEdgeInsets(top: 0, left: sectionPadding, bottom: 0, right: 0)
|
||||
return UIEdgeInsets(top: 0, left: itemSpacing, bottom: 0, right: 0)
|
||||
}
|
||||
guard paddingBeforeFirstTab else {
|
||||
return .zero
|
||||
@ -209,7 +214,11 @@ extension Tabs: UICollectionViewDelegateFlowLayout {
|
||||
}
|
||||
|
||||
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
|
||||
return sectionPadding
|
||||
// If two tabs, take up the screen, no space between items
|
||||
guard self.collectionView(collectionView, numberOfItemsInSection: section) != 2 else {
|
||||
return 0
|
||||
}
|
||||
return itemSpacing
|
||||
}
|
||||
|
||||
public func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
|
||||
@ -237,7 +246,7 @@ extension Tabs: UICollectionViewDelegateFlowLayout {
|
||||
guard let collect = collectionView, tabsModel?.tabs.count ?? 0 > 0 else { return }
|
||||
|
||||
collect.selectItem(at: indexPath, animated: animated, scrollPosition: .centeredHorizontally)
|
||||
guard let tabCell = collect.cellForItem(at: indexPath) as? TabItemCell, let tabsModel = self.tabsModel else { return }
|
||||
guard let tabCell = collect.cellForItem(at: indexPath) as? TabItemCell, let tabsModel = tabsModel else { return }
|
||||
moveSelectionLine(toIndex: indexPath, animated: animated, cell: tabCell)
|
||||
tabCell.label.textColor = tabsModel.selectedColor.uiColor
|
||||
tabCell.updateAccessibility(indexPath: indexPath, selected: true, tabsModel: tabsModel)
|
||||
@ -270,15 +279,13 @@ extension Tabs: UIScrollViewDelegate {
|
||||
//-------------------------------------------------
|
||||
extension Tabs {
|
||||
func moveSelectionLine(toIndex indexPath: IndexPath, animated: Bool, cell: TabItemCell) {
|
||||
guard let collect = self.collectionView else {return}
|
||||
guard let collect = collectionView else {return}
|
||||
|
||||
let size = collectionView(collect, layout: layout, sizeForItemAt: indexPath)
|
||||
let barWidth = max(size.width, selectionLineWidth)
|
||||
let animationBlock = {
|
||||
[weak self] in
|
||||
let x = cell.frame.origin.x
|
||||
self?.selectionLineWidthConstraint?.constant = barWidth
|
||||
self?.selectionLineLeftConstraint?.constant = x + (size.width - barWidth) / 2.0
|
||||
self?.selectionLineWidthConstraint?.constant = size.width
|
||||
self?.selectionLineLeftConstraint?.constant = cell.frame.origin.x
|
||||
self?.bottomContentView.layoutIfNeeded()
|
||||
}
|
||||
if animated {
|
||||
@ -287,11 +294,31 @@ extension Tabs {
|
||||
animationBlock()
|
||||
}
|
||||
}
|
||||
|
||||
/// Adjust the line based on the percentage
|
||||
func progress(from index: Int, toIndex: Int, percentage: CGFloat) {
|
||||
let fromIndexPath = IndexPath(row: index, section: 0)
|
||||
let toIndexPath = IndexPath(row: toIndex, section: 0)
|
||||
guard let collection = collectionView,
|
||||
let fromCell = collection.cellForItem(at: fromIndexPath),
|
||||
let toCell = collection.cellForItem(at: toIndexPath) else { return }
|
||||
|
||||
// setting the width for percentage
|
||||
selectionLineWidthConstraint?.constant = (toCell.bounds.width - fromCell.bounds.width) * percentage + fromCell.bounds.width
|
||||
|
||||
// setting the x for percentage
|
||||
let originalX = fromCell.frame.origin.x
|
||||
let toX = toCell.frame.origin.x
|
||||
let xDifference = toX - originalX
|
||||
let finalX = (xDifference * percentage) + originalX
|
||||
selectionLineLeftConstraint?.constant = finalX
|
||||
|
||||
bottomContentView.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
@objcMembers public class TabItemCell: CollectionViewCell {
|
||||
public let label = Label()
|
||||
public var labelModel: LabelModel?
|
||||
|
||||
public override func setupView() {
|
||||
super.setupView()
|
||||
@ -300,14 +327,19 @@ extension Tabs {
|
||||
label.baselineAdjustment = .alignCenters
|
||||
}
|
||||
|
||||
public func updateCell(labelModel: LabelModel, indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, selected: Bool, tabsModel: TabsModel?) {
|
||||
public override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
label.updateView(size)
|
||||
}
|
||||
|
||||
public func updateCell(indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, selected: Bool, tabsModel: TabsModel?) {
|
||||
guard let tabsModel = tabsModel else { return }
|
||||
label.reset()
|
||||
label.set(with: labelModel, delegateObject, additionalData)
|
||||
self.labelModel = labelModel
|
||||
label.set(with: tabsModel.tabs[indexPath.row].label, delegateObject, additionalData)
|
||||
if selected {
|
||||
label.textColor = tabsModel?.selectedColor.uiColor ?? .black
|
||||
label.textColor = tabsModel.selectedColor.uiColor
|
||||
} else {
|
||||
label.textColor = .mvmCoolGray6
|
||||
label.textColor = tabsModel.unselectedColor.uiColor
|
||||
}
|
||||
updateAccessibility(indexPath: indexPath, selected: selected, tabsModel: tabsModel)
|
||||
}
|
||||
|
||||
@ -7,22 +7,78 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import VDSColorTokens
|
||||
|
||||
public class TabsModel: MoleculeModelProtocol {
|
||||
open class TabsModel: MoleculeModelProtocol {
|
||||
public static var identifier: String = "tabs"
|
||||
public var backgroundColor: Color?
|
||||
public var tabs: [TabItemModel]
|
||||
public var selectedColor = Color(uiColor: .black)
|
||||
open var tabs: [TabItemModel]
|
||||
|
||||
open var style: NavigationItemStyle?
|
||||
|
||||
private var _backgroundColor: Color?
|
||||
open var backgroundColor: Color? {
|
||||
get {
|
||||
if let backgroundColor = _backgroundColor { return backgroundColor }
|
||||
if let style = style,
|
||||
style == .dark { return Color(uiColor: VDSColor.backgroundPrimaryDark) }
|
||||
return Color(uiColor: VDSColor.backgroundPrimaryLight)
|
||||
}
|
||||
set {
|
||||
_backgroundColor = newValue
|
||||
}
|
||||
}
|
||||
|
||||
private var _selectedColor: Color?
|
||||
open var selectedColor: Color {
|
||||
get {
|
||||
if let selectedColor = _selectedColor { return selectedColor }
|
||||
if let style = style,
|
||||
style == .dark { return Color(uiColor: VDSColor.elementsPrimaryOndark) }
|
||||
return Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
}
|
||||
set {
|
||||
_selectedColor = newValue
|
||||
}
|
||||
}
|
||||
|
||||
private var _unselectedColor: Color?
|
||||
open var unselectedColor: Color {
|
||||
get {
|
||||
if let unselectedColor = _unselectedColor { return unselectedColor }
|
||||
if let style = style,
|
||||
style == .dark { return Color(uiColor: VDSColor.elementsSecondaryOndark) }
|
||||
return Color(uiColor: VDSColor.elementsSecondaryOnlight)
|
||||
}
|
||||
set {
|
||||
_unselectedColor = newValue
|
||||
}
|
||||
}
|
||||
|
||||
private var _selectedBarColor: Color?
|
||||
open var selectedBarColor: Color {
|
||||
get {
|
||||
if let selectedBarColor = _selectedBarColor { return selectedBarColor }
|
||||
if let style = style,
|
||||
style == .dark { return Color(uiColor: VDSColor.elementsPrimaryOndark) }
|
||||
return Color(uiColor: VDSColor.paletteRed)
|
||||
}
|
||||
set {
|
||||
_selectedBarColor = newValue
|
||||
}
|
||||
}
|
||||
|
||||
// Must be capped to 0...(tabs.count - 1)
|
||||
public var selectedIndex: Int = 0
|
||||
open var selectedIndex: Int = 0
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case tabs
|
||||
case backgroundColor
|
||||
case selectedColor
|
||||
case unselectedColor
|
||||
case selectedBarColor
|
||||
case selectedIndex
|
||||
case moleculeName
|
||||
case style
|
||||
}
|
||||
|
||||
public init(with tabs: [TabItemModel]) {
|
||||
@ -33,31 +89,35 @@ public class TabsModel: MoleculeModelProtocol {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
tabs = try typeContainer.decode([TabItemModel].self, forKey: .tabs)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .selectedColor) {
|
||||
selectedColor = color
|
||||
}
|
||||
_selectedColor = try typeContainer.decodeIfPresent(Color.self, forKey: .selectedColor)
|
||||
_unselectedColor = try typeContainer.decodeIfPresent(Color.self, forKey: .unselectedColor)
|
||||
_selectedBarColor = try typeContainer.decodeIfPresent(Color.self, forKey: .selectedBarColor)
|
||||
style = try typeContainer.decodeIfPresent(NavigationItemStyle.self, forKey: .style)
|
||||
if let index = try typeContainer.decodeIfPresent(Int.self, forKey: .selectedIndex) {
|
||||
selectedIndex = index
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
open func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(tabs, forKey: .tabs)
|
||||
try container.encode(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encode(selectedColor, forKey: .selectedColor)
|
||||
try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(_selectedColor, forKey: .selectedColor)
|
||||
try container.encodeIfPresent(_unselectedColor, forKey: .unselectedColor)
|
||||
try container.encodeIfPresent(_selectedBarColor, forKey: .selectedBarColor)
|
||||
try container.encode(selectedIndex, forKey: .selectedIndex)
|
||||
try container.encodeIfPresent(style, forKey: .style)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class TabItemModel: Codable {
|
||||
var label: LabelModel
|
||||
var action: ActionModelProtocol?
|
||||
open class TabItemModel: Codable {
|
||||
open var label: LabelModel
|
||||
open var action: ActionModelProtocol?
|
||||
|
||||
init(label: LabelModel) {
|
||||
public init(label: LabelModel) {
|
||||
self.label = label
|
||||
}
|
||||
|
||||
@ -66,14 +126,26 @@ public class TabItemModel: Codable {
|
||||
case action
|
||||
}
|
||||
|
||||
open func setDefaults() {
|
||||
if label.textAlignment == nil {
|
||||
label.textAlignment = .center
|
||||
}
|
||||
}
|
||||
|
||||
public init(with label: LabelModel, action: ActionModelProtocol?) {
|
||||
self.label = label
|
||||
self.action = action
|
||||
setDefaults()
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
label = try typeContainer.decode(LabelModel.self, forKey: .label)
|
||||
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
|
||||
setDefaults()
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
open func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeModel(label, forKey: .label)
|
||||
try container.encodeModelIfPresent(action, forKey: .action)
|
||||
|
||||
@ -50,13 +50,17 @@ public class TwoButtonViewModel: ParentMoleculeModelProtocol {
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
primaryButton = try typeContainer.decodeMoleculeIfPresent(codingKey: .primaryButton)
|
||||
if primaryButton?.style == nil {
|
||||
primaryButton?.style = .primary
|
||||
|
||||
//set context value for 'primary' style to be set for the primaryButton in case the
|
||||
//property is not returned in the JSON and once decoded, this value is removed from the context
|
||||
try decoder.setContext(value: Styler.Button.Style.primary, for: "style") {
|
||||
self.primaryButton = try typeContainer.decodeMoleculeIfPresent(codingKey: .primaryButton)
|
||||
}
|
||||
secondaryButton = try typeContainer.decodeMoleculeIfPresent(codingKey: .secondaryButton)
|
||||
if secondaryButton?.style == nil {
|
||||
secondaryButton?.style = .secondary
|
||||
|
||||
//set context value for 'secondary' style to be set for the primaryButton in case the
|
||||
//property is not returned in the JSON and once decoded, this value is removed from the context
|
||||
try decoder.setContext(value: Styler.Button.Style.secondary, for: "style") {
|
||||
self.secondaryButton = try typeContainer.decodeMoleculeIfPresent(codingKey: .secondaryButton)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -42,6 +42,15 @@ class AccordionListItemModel: MoleculeListItemModel {
|
||||
hideArrow = true
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(with moleculeModel: MoleculeModelProtocol, molecules:[ListItemModelProtocol & MoleculeModelProtocol]) {
|
||||
self.molecules = molecules
|
||||
super.init(with: moleculeModel)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
|
||||
@objcMembers open class CarouselItemModel: MoleculeCollectionItemModel, CarouselItemModelProtocol {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -18,8 +19,16 @@
|
||||
public var peakingArrowColor: Color?
|
||||
public var analyticsData: JSONValueDictionary?
|
||||
public var fieldValue: String?
|
||||
public var enabled: Bool = true
|
||||
public var readOnly: Bool = false
|
||||
public var fieldKey: String?
|
||||
public var groupName: String = FormValidator.defaultGroupName
|
||||
public var baseValue: AnyHashable?
|
||||
|
||||
public func formFieldValue() -> AnyHashable? { fieldValue }
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
guard enabled else { return nil }
|
||||
return fieldValue
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
@ -30,6 +39,10 @@
|
||||
case peakingArrowColor
|
||||
case analyticsData
|
||||
case fieldValue
|
||||
case fieldKey
|
||||
case groupName
|
||||
case enabled
|
||||
case readOnly
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -42,6 +55,17 @@
|
||||
peakingArrowColor = try typeContainer.decodeIfPresent(Color.self, forKey: .peakingArrowColor)
|
||||
analyticsData = try typeContainer.decodeIfPresent(JSONValueDictionary.self, forKey: .analyticsData)
|
||||
fieldValue = try typeContainer.decodeIfPresent(String.self, forKey: .fieldValue)
|
||||
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
|
||||
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
|
||||
self.groupName = groupName
|
||||
}
|
||||
baseValue = fieldValue
|
||||
if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
|
||||
self.enabled = enabled
|
||||
}
|
||||
if let readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) {
|
||||
self.readOnly = readOnly
|
||||
}
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
@ -52,5 +76,7 @@
|
||||
try container.encodeIfPresent(peakingArrowColor, forKey: .peakingArrowColor)
|
||||
try container.encodeIfPresent(analyticsData, forKey: .analyticsData)
|
||||
try container.encodeIfPresent(fieldValue, forKey: .fieldValue)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(readOnly, forKey: .readOnly)
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,4 +14,14 @@ public class ActionDetailWithImageModel: MoleculeModelProtocol {
|
||||
public var backgroundColor: Color?
|
||||
public var headlineBodyButton: HeadlineBodyButtonModel
|
||||
public var image: ImageViewModel
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(headlineBodyButton: HeadlineBodyButtonModel, image: ImageViewModel) {
|
||||
self.headlineBodyButton = headlineBodyButton
|
||||
self.image = image
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import MVMCore
|
||||
|
||||
public class CornerLabelsModel: ParentMoleculeModelProtocol {
|
||||
public static var identifier: String = "cornerLabels"
|
||||
@ -20,7 +21,7 @@ public class CornerLabelsModel: ParentMoleculeModelProtocol {
|
||||
[molecule, topLeftLabel, topRightLabel, bottomLeftLabel, bottomRightLabel].compactMap { $0 }
|
||||
}
|
||||
|
||||
init(with molecule: MoleculeModelProtocol?) {
|
||||
public init(with molecule: MoleculeModelProtocol?) {
|
||||
self.molecule = molecule
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MVMCore
|
||||
|
||||
public class LabelToggleModel: MoleculeModelProtocol {
|
||||
public static var identifier: String = "labelToggle"
|
||||
@ -15,7 +16,7 @@ public class LabelToggleModel: MoleculeModelProtocol {
|
||||
public var label: LabelModel
|
||||
public var toggle: ToggleModel
|
||||
|
||||
init(_ label: LabelModel, _ toggle: ToggleModel) {
|
||||
public init(_ label: LabelModel, _ toggle: ToggleModel) {
|
||||
self.label = label
|
||||
self.toggle = toggle
|
||||
}
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
// Created by Scott Pfeil on 5/18/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
public class NavigationImageButtonModel: NavigationButtonModelProtocol, MoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -17,6 +19,7 @@ public class NavigationImageButtonModel: NavigationButtonModelProtocol, Molecule
|
||||
public var image: String
|
||||
public var action: ActionModelProtocol
|
||||
public var accessibilityText: String?
|
||||
public var imageRenderingMode: UIImage.RenderingMode = .automatic
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
@ -37,6 +40,7 @@ public class NavigationImageButtonModel: NavigationButtonModelProtocol, Molecule
|
||||
case accessibilityIdentifier
|
||||
case moleculeName
|
||||
case accessibilityText
|
||||
case imageRenderingMode
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -49,6 +53,9 @@ public class NavigationImageButtonModel: NavigationButtonModelProtocol, Molecule
|
||||
image = try typeContainer.decode(String.self, forKey: .image)
|
||||
action = try typeContainer.decodeModel(codingKey: .action)
|
||||
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
|
||||
if let mode = try typeContainer.decodeIfPresent(UIImage.RenderingMode.self, forKey: .imageRenderingMode) {
|
||||
imageRenderingMode = mode
|
||||
}
|
||||
}
|
||||
|
||||
open func encode(to encoder: Encoder) throws {
|
||||
@ -58,6 +65,7 @@ public class NavigationImageButtonModel: NavigationButtonModelProtocol, Molecule
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
|
||||
try container.encodeIfPresent(imageRenderingMode, forKey: .imageRenderingMode)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -66,7 +74,7 @@ public class NavigationImageButtonModel: NavigationButtonModelProtocol, Molecule
|
||||
|
||||
/// Convenience function that creates a BarButtonItem for the model.
|
||||
public func createNavigationItemButton(delegateObject: MVMCoreUIDelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) -> UIBarButtonItem {
|
||||
let uiImage = MVMCoreCache.shared()?.getImageFromRegisteredBundles(image)
|
||||
let uiImage = MVMCoreCache.shared()?.getImageFromRegisteredBundles(image)?.withRenderingMode(imageRenderingMode)
|
||||
let buttonItem = ImageBarButtonItem.create(with: uiImage, model: self, delegateObject: delegateObject, additionalData: additionalData)
|
||||
buttonItem.accessibilityIdentifier = accessibilityIdentifier ?? image
|
||||
if let accessibilityString = accessibilityText {
|
||||
|
||||
@ -6,6 +6,12 @@
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import VDSColorTokens
|
||||
|
||||
public enum NavigationItemStyle: String, Codable {
|
||||
case light
|
||||
case dark
|
||||
}
|
||||
|
||||
open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -14,12 +20,39 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
|
||||
|
||||
open class var identifier: String { "navigationBar" }
|
||||
|
||||
private let defaultHidesSystemBackButton = true
|
||||
|
||||
open var title: String?
|
||||
open var hidden: Bool
|
||||
open var backgroundColor: Color?
|
||||
open var tintColor: Color
|
||||
open var line: LineModel?
|
||||
open var hidden = false
|
||||
open var line: LineModel? = LineModel(type: .secondary)
|
||||
open var hidesSystemBackButton = true
|
||||
open var style: NavigationItemStyle?
|
||||
|
||||
private var _backgroundColor: Color?
|
||||
open var backgroundColor: Color? {
|
||||
get {
|
||||
if let backgroundColor = _backgroundColor { return backgroundColor }
|
||||
if let style = style,
|
||||
style == .dark { return Color(uiColor: VDSColor.backgroundPrimaryDark) }
|
||||
return Color(uiColor: VDSColor.backgroundPrimaryLight)
|
||||
}
|
||||
set {
|
||||
_backgroundColor = newValue
|
||||
}
|
||||
}
|
||||
|
||||
private var _tintColor: Color?
|
||||
open var tintColor: Color {
|
||||
get {
|
||||
if let tintColor = _tintColor { return tintColor }
|
||||
if let style = style,
|
||||
style == .dark { return Color(uiColor: VDSColor.elementsPrimaryOndark) }
|
||||
return Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
}
|
||||
set {
|
||||
_tintColor = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/// If true, we add the button in the backButton property. If false we do not add the button. If nil, we add the button if the controller is not the bottom of the stack
|
||||
open var alwaysShowBackButton: Bool?
|
||||
@ -28,17 +61,13 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
|
||||
open var additionalLeftButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
|
||||
open var additionalRightButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
|
||||
open var titleView: MoleculeModelProtocol?
|
||||
open var titleOffset: UIOffset? = UIOffset(horizontal: -CGFloat.greatestFiniteMagnitude, vertical: 0)
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init() {
|
||||
hidden = false
|
||||
backgroundColor = Color(uiColor: .mvmWhite)
|
||||
tintColor = Color(uiColor: .mvmBlack)
|
||||
line = LineModel(type: .standard)
|
||||
}
|
||||
public init() {}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
@ -51,11 +80,14 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
|
||||
case backgroundColor
|
||||
case tintColor
|
||||
case line
|
||||
case hidesSystemBackButton
|
||||
case alwaysShowBackButton
|
||||
case backButton
|
||||
case additionalLeftButtons
|
||||
case additionalRightButtons
|
||||
case titleView
|
||||
case style
|
||||
case titleOffset
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -65,15 +97,27 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
title = try typeContainer.decodeIfPresent(String.self, forKey: .title)
|
||||
hidden = try typeContainer.decodeIfPresent(Bool.self, forKey: .hidden) ?? false
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) ?? Color(uiColor: .mvmWhite)
|
||||
tintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .tintColor) ?? Color(uiColor: .mvmBlack)
|
||||
line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) ?? LineModel(type: .standard)
|
||||
if let hidden = try typeContainer.decodeIfPresent(Bool.self, forKey: .hidden) {
|
||||
self.hidden = hidden
|
||||
}
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
_tintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .tintColor)
|
||||
if let line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) {
|
||||
self.line = line
|
||||
}
|
||||
if let hidesSystemBackButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .hidesSystemBackButton) {
|
||||
self.hidesSystemBackButton = hidesSystemBackButton
|
||||
}
|
||||
alwaysShowBackButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .alwaysShowBackButton)
|
||||
backButton = try typeContainer.decodeModelIfPresent(codingKey: .backButton)
|
||||
additionalLeftButtons = try typeContainer.decodeModelsIfPresent(codingKey: .additionalLeftButtons)
|
||||
additionalRightButtons = try typeContainer.decodeModelsIfPresent(codingKey: .additionalRightButtons)
|
||||
titleView = try typeContainer.decodeModelIfPresent(codingKey: .titleView)
|
||||
style = try typeContainer.decodeIfPresent(NavigationItemStyle.self, forKey: .style)
|
||||
if let titleOffset = try typeContainer.decodeIfPresent(UIOffset.self, forKey: .titleOffset) {
|
||||
self.titleOffset = titleOffset
|
||||
}
|
||||
line?.inverted = style == .dark
|
||||
}
|
||||
|
||||
open func encode(to encoder: Encoder) throws {
|
||||
@ -81,14 +125,17 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(title, forKey: .title)
|
||||
try container.encode(hidden, forKey: .hidden)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encode(tintColor, forKey: .tintColor)
|
||||
try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(_tintColor, forKey: .tintColor)
|
||||
try container.encodeIfPresent(line, forKey: .line)
|
||||
try container.encode(hidesSystemBackButton, forKey: .hidesSystemBackButton)
|
||||
try container.encodeIfPresent(alwaysShowBackButton, forKey: .alwaysShowBackButton)
|
||||
try container.encodeModelIfPresent(backButton, forKey: .backButton)
|
||||
try container.encodeModelsIfPresent(additionalLeftButtons, forKey: .additionalLeftButtons)
|
||||
try container.encodeModelsIfPresent(additionalRightButtons, forKey: .additionalRightButtons)
|
||||
try container.encodeModelIfPresent(titleView, forKey: .titleView)
|
||||
try container.encodeIfPresent(style, forKey: .style)
|
||||
try container.encodeIfPresent(titleOffset, forKey: .titleOffset)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ public class BGImageHeadlineBodyButtonModel: ContainerModel, MoleculeModelProtoc
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
init(headlineBody: HeadlineBodyModel, image: ImageViewModel) {
|
||||
public init(headlineBody: HeadlineBodyModel, image: ImageViewModel) {
|
||||
self.headlineBody = headlineBody
|
||||
self.image = image
|
||||
super.init()
|
||||
|
||||
@ -54,27 +54,27 @@ open class HeadlineBody: View {
|
||||
}
|
||||
|
||||
public func styleLandingPageHeader() {
|
||||
headlineLabel.setFontStyle(.Title2XLarge)
|
||||
messageLabel.setFontStyle(.RegularBodySmall)
|
||||
spaceBetweenLabelsConstant = Padding.Two
|
||||
headlineLabel.setFontStyle(.RegularTitle2XLarge)
|
||||
messageLabel.setFontStyle(.RegularTitleMedium)
|
||||
spaceBetweenLabelsConstant = Padding.Four
|
||||
}
|
||||
|
||||
public func stylePageHeader() {
|
||||
headlineLabel.setFontStyle(.BoldTitleLarge)
|
||||
headlineLabel.setFontStyle(.RegularTitleLarge)
|
||||
messageLabel.setFontStyle(.RegularBodyLarge)
|
||||
spaceBetweenLabelsConstant = Padding.Two
|
||||
}
|
||||
|
||||
public func styleListItem() {
|
||||
headlineLabel.setFontStyle(.RegularTitleSmall)
|
||||
messageLabel.setFontStyle(.RegularBodySmall)
|
||||
spaceBetweenLabelsConstant = Padding.One
|
||||
}
|
||||
|
||||
public func styleListItem() {
|
||||
headlineLabel.setFontStyle(.BoldBodySmall)
|
||||
messageLabel.setFontStyle(.RegularBodySmall)
|
||||
spaceBetweenLabelsConstant = 0
|
||||
}
|
||||
|
||||
public func styleListItemDivider() {
|
||||
headlineLabel.setFontStyle(.BoldTitleMedium)
|
||||
headlineLabel.setFontStyle(.BoldTitleSmall)
|
||||
messageLabel.setFontStyle(.RegularBodySmall)
|
||||
spaceBetweenLabelsConstant = 0
|
||||
spaceBetweenLabelsConstant = Padding.Two
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
// Created by Scott Pfeil on 1/22/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import MVMCore
|
||||
|
||||
public class HeadlineBodyButtonModel: MoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -20,6 +20,16 @@ public class HeadlineBodyButtonModel: MoleculeModelProtocol {
|
||||
public var button: ButtonModel
|
||||
public var buttonHeadlinePadding: CGFloat
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(headlineBody: HeadlineBodyModel, button: ButtonModel, buttonHeadlinePadding: CGFloat) {
|
||||
self.headlineBody = headlineBody
|
||||
self.button = button
|
||||
self.buttonHeadlinePadding = buttonHeadlinePadding
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Method
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -22,7 +22,7 @@ public class HeadlineBodyCaretLinkImageModel: ContainerModel, MoleculeModelProto
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
init(headlineBody: HeadlineBodyModel, image: ImageViewModel) {
|
||||
public init(headlineBody: HeadlineBodyModel, image: ImageViewModel) {
|
||||
self.headlineBody = headlineBody
|
||||
self.image = image
|
||||
super.init()
|
||||
|
||||
@ -20,6 +20,15 @@ import Foundation
|
||||
case list
|
||||
case numberColor
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(numberColor: Color, molecules: [StackItemModelProtocol & MoleculeModelProtocol], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) {
|
||||
self.numberColor = numberColor
|
||||
super.init(molecules: molecules, axis: axis, spacing: spacing)
|
||||
}
|
||||
|
||||
// Numbered list model comes in the from of list = [MoleculeModelProtocol]
|
||||
public required init(from decoder: Decoder) throws {
|
||||
|
||||
@ -22,7 +22,17 @@ import Foundation
|
||||
case bulletChar
|
||||
case bulletColor
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(bulletChar: String, bulletColor: Color, molecules: [StackItemModelProtocol & MoleculeModelProtocol], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) {
|
||||
self.bulletChar = bulletChar
|
||||
self.bulletColor = bulletColor
|
||||
super.init(molecules: molecules, axis: axis, spacing: spacing)
|
||||
}
|
||||
|
||||
// Numbered list model comes in the from of list = [MoleculeModelProtocol]
|
||||
public required init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
@ -36,7 +46,7 @@ import Foundation
|
||||
for molecule in list {
|
||||
models.append(MoleculeStackItemModel(with: StringAndMoleculeModel(string: bulletChar, molecule: molecule, stringColor: bulletColor)))
|
||||
}
|
||||
super.init(molecules: models, spacing: 0)
|
||||
super.init(molecules: models, spacing: Padding.Four)
|
||||
}
|
||||
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
|
||||
@ -37,6 +37,8 @@ import UIKit
|
||||
public var baseValue: AnyHashable?
|
||||
public var fieldKey: String?
|
||||
public var groupName: String = FormValidator.defaultGroupName
|
||||
public var enabled: Bool = true
|
||||
public var readOnly: Bool = false
|
||||
|
||||
public var selectable = false
|
||||
public var selectedIndex: Int?
|
||||
@ -46,6 +48,8 @@ import UIKit
|
||||
}
|
||||
|
||||
public func formFieldValue() -> AnyHashable? {
|
||||
guard enabled else { return nil }
|
||||
|
||||
guard selectable else {
|
||||
// Use visible item value, else index
|
||||
if let fieldValue = molecules[index].formFieldValue() {
|
||||
@ -84,6 +88,8 @@ import UIKit
|
||||
case fieldKey
|
||||
case selectable
|
||||
case selectedIndex
|
||||
case enabled
|
||||
case readOnly
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -117,10 +123,16 @@ import UIKit
|
||||
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
|
||||
self.groupName = groupName
|
||||
}
|
||||
if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
|
||||
self.enabled = enabled
|
||||
}
|
||||
if let readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) {
|
||||
self.readOnly = readOnly
|
||||
}
|
||||
baseValue = formFieldValue()
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
@ -142,6 +154,8 @@ import UIKit
|
||||
try container.encode(index, forKey: .index)
|
||||
try container.encode(selectable, forKey: .selectable)
|
||||
try container.encode(selectedIndex, forKey: .selectedIndex)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(readOnly, forKey: .readOnly)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,17 +7,13 @@
|
||||
//
|
||||
|
||||
|
||||
public protocol CarouselItemModelProtocol: ContainerModelProtocol {
|
||||
public protocol CarouselItemModelProtocol: FormFieldProtocol, ContainerModelProtocol {
|
||||
var analyticsData: JSONValueDictionary? { get set }
|
||||
func formFieldValue() -> AnyHashable?
|
||||
}
|
||||
|
||||
public extension CarouselItemModelProtocol {
|
||||
|
||||
var analyticsData: JSONValueDictionary? {
|
||||
get { nil }
|
||||
set { analyticsData = newValue }
|
||||
}
|
||||
|
||||
func formFieldValue() -> AnyHashable? { nil }
|
||||
}
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
//
|
||||
// ClearableModelProtocol.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Matt Bruce on 1/11/22.
|
||||
// Copyright © 2022 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol ClearableModelProtocol {
|
||||
func clear()
|
||||
}
|
||||
@ -9,6 +9,6 @@
|
||||
import Foundation
|
||||
|
||||
|
||||
public protocol EnableableModelProtocol {
|
||||
public protocol EnableableModelProtocol: AnyObject {
|
||||
var enabled: Bool { get set }
|
||||
}
|
||||
|
||||
@ -20,4 +20,5 @@ public protocol NavigationItemModelProtocol {
|
||||
var additionalLeftButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]? { get set }
|
||||
var additionalRightButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]? { get set }
|
||||
var titleView: MoleculeModelProtocol? { get set }
|
||||
var titleOffset: UIOffset? { get }
|
||||
}
|
||||
|
||||
@ -23,4 +23,33 @@ public protocol MoleculeDelegateProtocol: AnyObject {
|
||||
extension MoleculeDelegateProtocol {
|
||||
|
||||
public func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) { }
|
||||
|
||||
public func getModuleWithName(_ moleculeName: String) -> MoleculeModelProtocol? {
|
||||
let moduleJSON: [AnyHashable: Any]? = getModuleWithName(moleculeName)
|
||||
guard let moduleJSON = moduleJSON as? [String: Any],
|
||||
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 [String : Any]) as? MoleculeModelProtocol
|
||||
} catch {
|
||||
MVMCoreUILoggingHandler.logDebugMessage(withDelegate: "error: \(error)")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
extension MoleculeDelegateProtocol where Self: TemplateProtocol {
|
||||
public func getRootMolecules() -> [MoleculeModelProtocol] {
|
||||
templateModel?.rootMolecules ?? []
|
||||
}
|
||||
}
|
||||
|
||||
extension MoleculeDelegateProtocol where Self: MVMCoreViewControllerProtocol {
|
||||
public func getModuleWithName(_ name: String?) -> [AnyHashable : Any]? {
|
||||
guard let name = name else { return nil }
|
||||
return loadObject??.modulesJSON?.optionalDictionaryForKey(name)
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ public extension ModelRegistry {
|
||||
return type
|
||||
} catch {
|
||||
if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: #function) {
|
||||
MVMCoreLoggingHandler.shared()?.addError(toLog: errorObject)
|
||||
MVMCoreLoggingHandler.addError(toLog: errorObject)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user