This commit is contained in:
Kevin G Christiano 2020-04-21 09:03:32 -04:00
commit e53cc6e57c
58 changed files with 1268 additions and 395 deletions

View File

@ -61,7 +61,6 @@
01EB3684236097C0006832FA /* MoleculeModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB3683236097C0006832FA /* MoleculeModelProtocol.swift */; };
01EB368F23609801006832FA /* LabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368823609801006832FA /* LabelModel.swift */; };
01EB369023609801006832FA /* MoleculeListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368923609801006832FA /* MoleculeListItemModel.swift */; };
01EB369223609801006832FA /* MoleculeStackModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368B23609801006832FA /* MoleculeStackModel.swift */; };
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 */; };
@ -145,6 +144,8 @@
8D448E5524050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D448E5424050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift */; };
8D4687E2242E2DE400802879 /* ListFourColumnDataUsageListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D4687E1242E2DE400802879 /* ListFourColumnDataUsageListItemModel.swift */; };
8D4687E4242E2DF300802879 /* ListFourColumnDataUsageListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D4687E3242E2DF300802879 /* ListFourColumnDataUsageListItem.swift */; };
8D8067D12444472F00203BE8 /* ListRightVariablePriceChangeAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D8067D02444472F00203BE8 /* ListRightVariablePriceChangeAllTextAndLinksModel.swift */; };
8D8067D32444473A00203BE8 /* ListRightVariablePriceChangeAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D8067D22444473A00203BE8 /* ListRightVariablePriceChangeAllTextAndLinks.swift */; };
8DD1E36E243B3CFB00D8F2DF /* ListThreeColumnInternationalDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DD1E36D243B3CFB00D8F2DF /* ListThreeColumnInternationalDataModel.swift */; };
8DD1E370243B3D0500D8F2DF /* ListThreeColumnInternationalData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DD1E36F243B3D0500D8F2DF /* ListThreeColumnInternationalData.swift */; };
8DEFA95C243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DEFA95B243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift */; };
@ -154,9 +155,9 @@
942C378C2412F4FA0066E45E /* ModalMoleculeListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 942C378B2412F4FA0066E45E /* ModalMoleculeListTemplate.swift */; };
942C378E2412F5B60066E45E /* ModalMoleculeStackTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 942C378D2412F5B60066E45E /* ModalMoleculeStackTemplate.swift */; };
9432A79F23DB47BA00719041 /* EntryFieldContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9432A79E23DB47BA00719041 /* EntryFieldContainer.swift */; };
943784F5236B77BB006A1E82 /* GraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F3236B77BB006A1E82 /* GraphView.swift */; };
943784F6236B77BB006A1E82 /* GraphViewAnimationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */; };
943820842432382400B43AF3 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943820832432382400B43AF3 /* WebView.swift */; };
943784F5236B77BB006A1E82 /* Wheel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F3236B77BB006A1E82 /* Wheel.swift */; };
943784F6236B77BB006A1E82 /* WheelAnimationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F4236B77BB006A1E82 /* WheelAnimationHandler.swift */; };
943820842432382400B43AF3 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943820832432382400B43AF3 /* WebView.swift */; };
94382086243238D100B43AF3 /* WebViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94382085243238D100B43AF3 /* WebViewModel.swift */; };
9445890C2385BCE300DE9FD4 /* ProgressBarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9445890B2385BCE300DE9FD4 /* ProgressBarModel.swift */; };
9445890E2385C3F800DE9FD4 /* MultiProgressModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9445890D2385C3F800DE9FD4 /* MultiProgressModel.swift */; };
@ -196,14 +197,22 @@
AA1EC59924373994003D6F50 /* ListThreeColumnSpeedTestDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1EC59824373994003D6F50 /* ListThreeColumnSpeedTestDivider.swift */; };
AA56A20F243C5EE900303286 /* ListTwoColumnSubsectionDividerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA56A20E243C5EE900303286 /* ListTwoColumnSubsectionDividerModel.swift */; };
AA56A211243C5EFC00303286 /* ListTwoColumnSubsectionDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA56A210243C5EFC00303286 /* ListTwoColumnSubsectionDivider.swift */; };
AA69AAF62445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA69AAF52445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift */; };
AA69AAF82445BF6800AF3D3B /* ListLeftVariableCheckboxBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA69AAF72445BF6800AF3D3B /* ListLeftVariableCheckboxBodyTextModel.swift */; };
AA85236C244435A20059CC1E /* RadioSwatchCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */; };
AAA74A172410C04600080241 /* HeadersH2NoButtonsBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */; };
AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */; };
AAB9C10824346F4B00151545 /* RadioSwatches.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB9C10724346F4B00151545 /* RadioSwatches.swift */; };
AAB9C10A243496DD00151545 /* RadioSwatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB9C109243496DD00151545 /* RadioSwatch.swift */; };
AAC6F167243332E400F295C1 /* RadioSwatchesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC6F166243332E400F295C1 /* RadioSwatchesModel.swift */; };
BB2C968F24330EA7006FF80C /* ListRightVariableTextLinkAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB2C968D24330EA7006FF80C /* ListRightVariableTextLinkAllTextAndLinksModel.swift */; };
BB2C969224330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB2C969124330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift */; };
BB47A586241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB47A585241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift */; };
BB47A588241615FA002BB23C /* ListOneColumnFullWidthTextDividerSubsection.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB47A587241615FA002BB23C /* ListOneColumnFullWidthTextDividerSubsection.swift */; };
BB54C5202434D92F0038326C /* ListRightVariableButtonAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB54C51E2434D92F0038326C /* ListRightVariableButtonAllTextAndLinks.swift */; };
BB54C5212434D92F0038326C /* ListRightVariableButtonAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB54C51F2434D92F0038326C /* ListRightVariableButtonAllTextAndLinksModel.swift */; };
BB55B51D244482C1002001AD /* ListRightVariablePriceChangeBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB55B51C244482C0002001AD /* ListRightVariablePriceChangeBodyText.swift */; };
BB55B51F244482D2002001AD /* ListRightVariablePriceChangeBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB55B51E244482D2002001AD /* ListRightVariablePriceChangeBodyTextModel.swift */; };
BB6C6AC0242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6C6ABE242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift */; };
BB6C6AC1242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6C6ABF242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift */; };
BB6C6AC824225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB6C6AC62422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift */; };
@ -228,9 +237,11 @@
C7F8012323E846C300396FBD /* ListRVWheelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F8012223E846C300396FBD /* ListRVWheelModel.swift */; };
D202AFE4242A5F5E00E5BEDF /* NSTextAlignment+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D202AFE3242A5F5E00E5BEDF /* NSTextAlignment+Extension.swift */; };
D202AFE6242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D202AFE5242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift */; };
D2092349244A51D40044AD09 /* RadioSwatchModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2092348244A51D40044AD09 /* RadioSwatchModel.swift */; };
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; };
D20FB165241A5D75004AFC3A /* NavigationItemModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20FB164241A5D75004AFC3A /* NavigationItemModelProtocol.swift */; };
D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; };
D21B7F602437C5BC00051ABF /* MoleculeStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21B7F5E2437C5BC00051ABF /* MoleculeStackView.swift */; };
D21B7F71243BAC1600051ABF /* CollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21B7F70243BAC1600051ABF /* CollectionViewCell.swift */; };
D21B7F73243BAC6800051ABF /* CollectionItemModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21B7F72243BAC6800051ABF /* CollectionItemModelProtocol.swift */; };
D21B7F75243BAC8900051ABF /* CarouselItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21B7F74243BAC8900051ABF /* CarouselItem.swift */; };
@ -291,7 +302,7 @@
D28A837D23CCA86A00DFE4FC /* TabsListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A837C23CCA86A00DFE4FC /* TabsListItemModel.swift */; };
D28A837F23CCA96400DFE4FC /* TabsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A837E23CCA96400DFE4FC /* TabsModel.swift */; };
D28A838123CCB0D800DFE4FC /* AccordionListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A838023CCB0D800DFE4FC /* AccordionListItemModel.swift */; };
D28A838323CCBD3F00DFE4FC /* CircleProgressModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A838223CCBD3F00DFE4FC /* CircleProgressModel.swift */; };
D28A838323CCBD3F00DFE4FC /* WheelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A838223CCBD3F00DFE4FC /* WheelModel.swift */; };
D28A838523CCCA8900DFE4FC /* ScrollerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A838423CCCA8900DFE4FC /* ScrollerModel.swift */; };
D28A838923CCCFCB00DFE4FC /* LinkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A838823CCCFCB00DFE4FC /* LinkModel.swift */; };
D28A838B23CCDA6B00DFE4FC /* ButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A838A23CCDA6B00DFE4FC /* ButtonModel.swift */; };
@ -399,7 +410,6 @@
D29E28D823D21AB800ACEA85 /* StringAndMoleculeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29E28D723D21AB800ACEA85 /* StringAndMoleculeView.swift */; };
D29E28DA23D21AFA00ACEA85 /* StringAndMoleculeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29E28D923D21AFA00ACEA85 /* StringAndMoleculeModel.swift */; };
D29E28DD23D7404C00ACEA85 /* ContainerHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29E28DC23D7404C00ACEA85 /* ContainerHelper.swift */; };
D2A5145F2211DDC100345BFB /* MoleculeStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A5145E2211DDC100345BFB /* MoleculeStackView.swift */; };
D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A5146022121FBF00345BFB /* MoleculeStackTemplate.swift */; };
D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A514622213643100345BFB /* MoleculeStackCenteredTemplate.swift */; };
D2A514672213885800345BFB /* MoleculeHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A514662213885800345BFB /* MoleculeHeaderView.swift */; };
@ -503,7 +513,6 @@
01EB368823609801006832FA /* LabelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LabelModel.swift; sourceTree = "<group>"; };
01EB368923609801006832FA /* MoleculeListItemModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeListItemModel.swift; sourceTree = "<group>"; };
01EB368A23609801006832FA /* MoleculeStackItemModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeStackItemModel.swift; sourceTree = "<group>"; };
01EB368B23609801006832FA /* MoleculeStackModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeStackModel.swift; sourceTree = "<group>"; };
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>"; };
@ -579,6 +588,8 @@
8D448E5424050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextAllTextAndLinksModel.swift; sourceTree = "<group>"; };
8D4687E1242E2DE400802879 /* ListFourColumnDataUsageListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListFourColumnDataUsageListItemModel.swift; sourceTree = "<group>"; };
8D4687E3242E2DF300802879 /* ListFourColumnDataUsageListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListFourColumnDataUsageListItem.swift; sourceTree = "<group>"; };
8D8067D02444472F00203BE8 /* ListRightVariablePriceChangeAllTextAndLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariablePriceChangeAllTextAndLinksModel.swift; sourceTree = "<group>"; };
8D8067D22444473A00203BE8 /* ListRightVariablePriceChangeAllTextAndLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariablePriceChangeAllTextAndLinks.swift; sourceTree = "<group>"; };
8DD1E36D243B3CFB00D8F2DF /* ListThreeColumnInternationalDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnInternationalDataModel.swift; sourceTree = "<group>"; };
8DD1E36F243B3D0500D8F2DF /* ListThreeColumnInternationalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnInternationalData.swift; sourceTree = "<group>"; };
8DEFA95B243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnDataUsageDividerModel.swift; sourceTree = "<group>"; };
@ -589,8 +600,8 @@
942C378B2412F4FA0066E45E /* ModalMoleculeListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalMoleculeListTemplate.swift; sourceTree = "<group>"; };
942C378D2412F5B60066E45E /* ModalMoleculeStackTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalMoleculeStackTemplate.swift; sourceTree = "<group>"; };
9432A79E23DB47BA00719041 /* EntryFieldContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntryFieldContainer.swift; sourceTree = "<group>"; };
943784F3236B77BB006A1E82 /* GraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphView.swift; sourceTree = "<group>"; };
943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphViewAnimationHandler.swift; sourceTree = "<group>"; };
943784F3236B77BB006A1E82 /* Wheel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Wheel.swift; sourceTree = "<group>"; };
943784F4236B77BB006A1E82 /* WheelAnimationHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WheelAnimationHandler.swift; sourceTree = "<group>"; };
943820832432382400B43AF3 /* WebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebView.swift; sourceTree = "<group>"; };
94382085243238D100B43AF3 /* WebViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewModel.swift; sourceTree = "<group>"; };
9445890B2385BCE300DE9FD4 /* ProgressBarModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarModel.swift; sourceTree = "<group>"; };
@ -629,14 +640,22 @@
AA1EC59824373994003D6F50 /* ListThreeColumnSpeedTestDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnSpeedTestDivider.swift; sourceTree = "<group>"; };
AA56A20E243C5EE900303286 /* ListTwoColumnSubsectionDividerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnSubsectionDividerModel.swift; sourceTree = "<group>"; };
AA56A210243C5EFC00303286 /* ListTwoColumnSubsectionDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnSubsectionDivider.swift; sourceTree = "<group>"; };
AA69AAF52445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableCheckboxBodyText.swift; sourceTree = "<group>"; };
AA69AAF72445BF6800AF3D3B /* ListLeftVariableCheckboxBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableCheckboxBodyTextModel.swift; sourceTree = "<group>"; };
AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchCollectionViewCell.swift; sourceTree = "<group>"; };
AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyText.swift; sourceTree = "<group>"; };
AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyTextModel.swift; sourceTree = "<group>"; };
AAB9C10724346F4B00151545 /* RadioSwatches.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatches.swift; sourceTree = "<group>"; };
AAB9C109243496DD00151545 /* RadioSwatch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatch.swift; sourceTree = "<group>"; };
AAC6F166243332E400F295C1 /* RadioSwatchesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchesModel.swift; sourceTree = "<group>"; };
BB2C968D24330EA7006FF80C /* ListRightVariableTextLinkAllTextAndLinksModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListRightVariableTextLinkAllTextAndLinksModel.swift; sourceTree = "<group>"; };
BB2C969124330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListRightVariableTextLinkAllTextAndLinks.swift; sourceTree = "<group>"; };
BB47A585241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextDividerSubsectionModel.swift; sourceTree = "<group>"; };
BB47A587241615FA002BB23C /* ListOneColumnFullWidthTextDividerSubsection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextDividerSubsection.swift; sourceTree = "<group>"; };
BB54C51E2434D92F0038326C /* ListRightVariableButtonAllTextAndLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListRightVariableButtonAllTextAndLinks.swift; sourceTree = "<group>"; };
BB54C51F2434D92F0038326C /* ListRightVariableButtonAllTextAndLinksModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListRightVariableButtonAllTextAndLinksModel.swift; sourceTree = "<group>"; };
BB55B51C244482C0002001AD /* ListRightVariablePriceChangeBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariablePriceChangeBodyText.swift; sourceTree = "<group>"; };
BB55B51E244482D2002001AD /* ListRightVariablePriceChangeBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariablePriceChangeBodyTextModel.swift; sourceTree = "<group>"; };
BB6C6ABE242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListOneColumnTextWithWhitespaceDividerTallModel.swift; sourceTree = "<group>"; };
BB6C6ABF242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListOneColumnTextWithWhitespaceDividerTall.swift; sourceTree = "<group>"; };
BB6C6AC62422528F005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListOneColumnTextWithWhitespaceDividerShort.swift; sourceTree = "<group>"; };
@ -661,9 +680,11 @@
C7F8012223E846C300396FBD /* ListRVWheelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRVWheelModel.swift; sourceTree = "<group>"; };
D202AFE3242A5F5E00E5BEDF /* NSTextAlignment+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSTextAlignment+Extension.swift"; sourceTree = "<group>"; };
D202AFE5242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionViewScrollPosition+Extension.swift"; sourceTree = "<group>"; };
D2092348244A51D40044AD09 /* RadioSwatchModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchModel.swift; sourceTree = "<group>"; };
D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = "<group>"; };
D20FB164241A5D75004AFC3A /* NavigationItemModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItemModelProtocol.swift; sourceTree = "<group>"; };
D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
D21B7F5E2437C5BC00051ABF /* MoleculeStackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeStackView.swift; sourceTree = "<group>"; };
D21B7F70243BAC1600051ABF /* CollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewCell.swift; sourceTree = "<group>"; };
D21B7F72243BAC6800051ABF /* CollectionItemModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionItemModelProtocol.swift; sourceTree = "<group>"; };
D21B7F74243BAC8900051ABF /* CarouselItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselItem.swift; sourceTree = "<group>"; };
@ -723,7 +744,7 @@
D28A837C23CCA86A00DFE4FC /* TabsListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsListItemModel.swift; sourceTree = "<group>"; };
D28A837E23CCA96400DFE4FC /* TabsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsModel.swift; sourceTree = "<group>"; };
D28A838023CCB0D800DFE4FC /* AccordionListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccordionListItemModel.swift; sourceTree = "<group>"; };
D28A838223CCBD3F00DFE4FC /* CircleProgressModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleProgressModel.swift; sourceTree = "<group>"; };
D28A838223CCBD3F00DFE4FC /* WheelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WheelModel.swift; sourceTree = "<group>"; };
D28A838423CCCA8900DFE4FC /* ScrollerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollerModel.swift; sourceTree = "<group>"; };
D28A838823CCCFCB00DFE4FC /* LinkModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkModel.swift; sourceTree = "<group>"; };
D28A838A23CCDA6B00DFE4FC /* ButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonModel.swift; sourceTree = "<group>"; };
@ -846,7 +867,6 @@
D29E28D723D21AB800ACEA85 /* StringAndMoleculeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringAndMoleculeView.swift; sourceTree = "<group>"; };
D29E28D923D21AFA00ACEA85 /* StringAndMoleculeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringAndMoleculeModel.swift; sourceTree = "<group>"; };
D29E28DC23D7404C00ACEA85 /* ContainerHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerHelper.swift; sourceTree = "<group>"; };
D2A5145E2211DDC100345BFB /* MoleculeStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeStackView.swift; sourceTree = "<group>"; };
D2A5146022121FBF00345BFB /* MoleculeStackTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeStackTemplate.swift; sourceTree = "<group>"; };
D2A514622213643100345BFB /* MoleculeStackCenteredTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeStackCenteredTemplate.swift; sourceTree = "<group>"; };
D2A514662213885800345BFB /* MoleculeHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeHeaderView.swift; sourceTree = "<group>"; };
@ -1112,6 +1132,10 @@
AA11A41E23F15D3100D7962F /* ListRightVariablePayments.swift */,
8D070BAF241B56530099AC56 /* ListRightVariableTotalDataModel.swift */,
8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */,
BB55B51E244482D2002001AD /* ListRightVariablePriceChangeBodyTextModel.swift */,
BB55B51C244482C0002001AD /* ListRightVariablePriceChangeBodyText.swift */,
8D8067D02444472F00203BE8 /* ListRightVariablePriceChangeAllTextAndLinksModel.swift */,
8D8067D22444473A00203BE8 /* ListRightVariablePriceChangeAllTextAndLinks.swift */,
C7F8012223E846C300396FBD /* ListRVWheelModel.swift */,
C7F8012023E8303200396FBD /* ListRVWheel.swift */,
);
@ -1300,8 +1324,7 @@
D260105A23D0BB7100764D80 /* StackModelProtocol.swift */,
D260106423D0CEA700764D80 /* StackModel.swift */,
D260105C23D0BCD400764D80 /* Stack.swift */,
01EB368B23609801006832FA /* MoleculeStackModel.swift */,
D2A5145E2211DDC100345BFB /* MoleculeStackView.swift */,
D21B7F5E2437C5BC00051ABF /* MoleculeStackView.swift */,
012A88AE238C626E00FE3DA1 /* CarouselModel.swift */,
D2A6390022CBB1820052ED1F /* Carousel.swift */,
);
@ -1362,6 +1385,8 @@
children = (
52B201D124081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift */,
52B201D024081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift */,
AA69AAF72445BF6800AF3D3B /* ListLeftVariableCheckboxBodyTextModel.swift */,
AA69AAF52445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift */,
522679C023FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinksModel.swift */,
522679BF23FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift */,
8D24041423E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift */,
@ -1448,6 +1473,11 @@
01004F2F22721C3800991ECC /* RadioButton.swift */,
31BE15CA23D8924C00452370 /* CheckboxModel.swift */,
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */,
AAC6F166243332E400F295C1 /* RadioSwatchesModel.swift */,
AAB9C10724346F4B00151545 /* RadioSwatches.swift */,
D2092348244A51D40044AD09 /* RadioSwatchModel.swift */,
AAB9C109243496DD00151545 /* RadioSwatch.swift */,
AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */,
);
path = Selectors;
sourceTree = "<group>";
@ -1695,9 +1725,9 @@
94C2D9822386F3E30006CF46 /* Label */,
31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */,
0A7BAFA2232BE63400FB8E22 /* CheckboxLabel.swift */,
D28A838223CCBD3F00DFE4FC /* CircleProgressModel.swift */,
943784F3236B77BB006A1E82 /* GraphView.swift */,
943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */,
D28A838223CCBD3F00DFE4FC /* WheelModel.swift */,
943784F3236B77BB006A1E82 /* Wheel.swift */,
943784F4236B77BB006A1E82 /* WheelAnimationHandler.swift */,
D260105223CEA61600764D80 /* ToggleModel.swift */,
0AA33B392398524F0067DD0F /* Toggle.swift */,
0AE98BB623FF18E9004C5109 /* ArrowModel.swift */,
@ -2060,10 +2090,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
AAC6F167243332E400F295C1 /* RadioSwatchesModel.swift in Sources */,
5248BFED23F12E350059236A /* ListThreeColumnPlanDataDividerModel.swift in Sources */,
0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */,
8D070BB0241B56530099AC56 /* ListRightVariableTotalDataModel.swift in Sources */,
943784F5236B77BB006A1E82 /* GraphView.swift in Sources */,
943784F5236B77BB006A1E82 /* Wheel.swift in Sources */,
31BE15CC23D8924D00452370 /* CheckboxModel.swift in Sources */,
8D3BA9BF2433789900D341BA /* ListThreeColumnInternationalDataDivider.swift in Sources */,
94C661DA23CCF4FB00D9FE5B /* UIColor+Extension.swift in Sources */,
@ -2076,6 +2107,7 @@
D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */,
D28A838923CCCFCB00DFE4FC /* LinkModel.swift in Sources */,
AA56A20F243C5EE900303286 /* ListTwoColumnSubsectionDividerModel.swift in Sources */,
AAB9C10824346F4B00151545 /* RadioSwatches.swift in Sources */,
94C2D9A923872E5E0006CF46 /* LabelAttributeImageModel.swift in Sources */,
DBC4391922442197001AB423 /* DashLine.swift in Sources */,
D264FAAA2440F97600D98315 /* CollectionView.swift in Sources */,
@ -2089,6 +2121,7 @@
94382086243238D100B43AF3 /* WebViewModel.swift in Sources */,
D27CD40E2322EEAF00C1DC07 /* TabsTableViewCell.swift in Sources */,
D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */,
D21B7F602437C5BC00051ABF /* MoleculeStackView.swift in Sources */,
0A6682A42434DB8D00AD3CA1 /* ListLeftVariableRadioButtonBodyTextModel.swift in Sources */,
D22D1F1F220343560077CEC0 /* MVMCoreUICheckMarkView.m in Sources */,
0A9D09202433796500D2E6C0 /* BarsIndicatorView.swift in Sources */,
@ -2106,6 +2139,7 @@
942C378C2412F4FA0066E45E /* ModalMoleculeListTemplate.swift in Sources */,
BB47A588241615FA002BB23C /* ListOneColumnFullWidthTextDividerSubsection.swift in Sources */,
012A88C8238DB02000FE3DA1 /* MoleculeDelegateProtocol.swift in Sources */,
8D8067D12444472F00203BE8 /* ListRightVariablePriceChangeAllTextAndLinksModel.swift in Sources */,
0A7EF86123D8AC2500B2AAD1 /* DigitEntryFieldModel.swift in Sources */,
DBC4392122491730001AB423 /* LabelWithInternalButton.swift in Sources */,
D224798C231450C8003FCCF9 /* HeadlineBodyToggle.swift in Sources */,
@ -2121,6 +2155,7 @@
012A88AD238C418100FE3DA1 /* TemplateProtocol.swift in Sources */,
BB6C6AC1242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift in Sources */,
D21B7F77243BB70700051ABF /* MoleculeCollectionItemModel.swift in Sources */,
AAB9C10A243496DD00151545 /* RadioSwatch.swift in Sources */,
D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */,
011D9602240DA20A000E3791 /* FormRuleWatcherFieldProtocol.swift in Sources */,
D264FAA1243CF66B00D98315 /* ContainerCollectionReusableView.swift in Sources */,
@ -2143,7 +2178,6 @@
D22D1F572204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m in Sources */,
D28A838B23CCDA6B00DFE4FC /* ButtonModel.swift in Sources */,
D21B7F71243BAC1600051ABF /* CollectionViewCell.swift in Sources */,
D2A5145F2211DDC100345BFB /* MoleculeStackView.swift in Sources */,
C7F8012323E846C300396FBD /* ListRVWheelModel.swift in Sources */,
D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */,
C695A69623C990BC00BFB94E /* DoughnutChart.swift in Sources */,
@ -2171,7 +2205,6 @@
0A21DB85235E06EF00C160A2 /* MFTextField.m in Sources */,
014AA72623C501E2006F3E93 /* ContainerModelProtocol.swift in Sources */,
AA11A42123F15D7000D7962F /* ListRightVariablePaymentsModel.swift in Sources */,
01EB369223609801006832FA /* MoleculeStackModel.swift in Sources */,
011D9626240EBB16000E3791 /* RadioButtonLabelModel.swift in Sources */,
AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */,
D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */,
@ -2181,12 +2214,14 @@
525019DE2406430800EED91C /* ListProgressBarData.swift in Sources */,
D28A837F23CCA96400DFE4FC /* TabsModel.swift in Sources */,
012A88EC238F084D00FE3DA1 /* FooterModel.swift in Sources */,
BB55B51F244482D2002001AD /* ListRightVariablePriceChangeBodyTextModel.swift in Sources */,
D2A514672213885800345BFB /* MoleculeHeaderView.swift in Sources */,
D29E28D823D21AB800ACEA85 /* StringAndMoleculeView.swift in Sources */,
01EB369023609801006832FA /* MoleculeListItemModel.swift in Sources */,
0A9D09212433796500D2E6C0 /* CarouselIndicatorModel.swift in Sources */,
D28A838323CCBD3F00DFE4FC /* CircleProgressModel.swift in Sources */,
EA5124FF2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift in Sources */,
D28A838323CCBD3F00DFE4FC /* WheelModel.swift in Sources */,
D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */,
0A9D091D2433796500D2E6C0 /* BarsCarouselIndicatorModel.swift in Sources */,
DBEFFA04225A829700230692 /* Label.swift in Sources */,
@ -2210,6 +2245,7 @@
0A21DB8B235E06EF00C160A2 /* MFDigitTextBox.m in Sources */,
D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */,
BB47A586241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift in Sources */,
AA69AAF82445BF6800AF3D3B /* ListLeftVariableCheckboxBodyTextModel.swift in Sources */,
D2B18B812360945C00A9AEDC /* View.swift in Sources */,
C6FA7D5423C77A4A00A3614A /* NumberedList.swift in Sources */,
D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */,
@ -2229,12 +2265,14 @@
D260105D23D0BCD400764D80 /* Stack.swift in Sources */,
0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */,
BB54C5212434D92F0038326C /* ListRightVariableButtonAllTextAndLinksModel.swift in Sources */,
D2092349244A51D40044AD09 /* RadioSwatchModel.swift in Sources */,
8DD1E370243B3D0500D8F2DF /* ListThreeColumnInternationalData.swift in Sources */,
D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */,
01EB368F23609801006832FA /* LabelModel.swift in Sources */,
0A6682AC243531C300AD3CA1 /* Padding.swift in Sources */,
AA1EC59924373994003D6F50 /* ListThreeColumnSpeedTestDivider.swift in Sources */,
942C378E2412F5B60066E45E /* ModalMoleculeStackTemplate.swift in Sources */,
8D8067D32444473A00203BE8 /* ListRightVariablePriceChangeAllTextAndLinks.swift in Sources */,
8D4687E4242E2DF300802879 /* ListFourColumnDataUsageListItem.swift in Sources */,
01F2A03223A4498200D954D8 /* CaretLinkModel.swift in Sources */,
0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */,
@ -2242,6 +2280,7 @@
D22479962316AF6E003FCCF9 /* HeadlineBodyLink.swift in Sources */,
D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */,
0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */,
BB55B51D244482C1002001AD /* ListRightVariablePriceChangeBodyText.swift in Sources */,
017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */,
D29DF18121E69E50003B2FB9 /* MFView.m in Sources */,
D28A837923C7D5BC00DFE4FC /* PageModelProtocol.swift in Sources */,
@ -2265,6 +2304,7 @@
C6FA7D5323C77A4A00A3614A /* StringAndMoleculeStack.swift in Sources */,
011D958524042432000E3791 /* RulesProtocol.swift in Sources */,
94AF4A3F23E9D13900676048 /* MFCaretButton.m in Sources */,
AA69AAF62445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift in Sources */,
D264FAA3243E632F00D98315 /* ProgrammaticCollectionViewController.swift in Sources */,
D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */,
D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */,
@ -2344,11 +2384,12 @@
0A21DB94235E24ED00C160A2 /* DigitEntryField.swift in Sources */,
AA56A211243C5EFC00303286 /* ListTwoColumnSubsectionDivider.swift in Sources */,
D264FA8C243BCD8E00D98315 /* CollectionTemplateModel.swift in Sources */,
AA85236C244435A20059CC1E /* RadioSwatchCollectionViewCell.swift in Sources */,
52B201D224081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift in Sources */,
D26C5A6B23F4A40D007AEECE /* ListItemModel.swift in Sources */,
0A21DB8D235E06EF00C160A2 /* MFDigitTextField.m in Sources */,
94AF4A4323E9D19E00676048 /* MFCaretView.m in Sources */,
943784F6236B77BB006A1E82 /* GraphViewAnimationHandler.swift in Sources */,
943784F6236B77BB006A1E82 /* WheelAnimationHandler.swift in Sources */,
011D95A1240453D0000E3791 /* RuleEqualsModel.swift in Sources */,
D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */,
011D95892404249B000E3791 /* FormHolderModelProtocol.swift in Sources */,

View File

@ -13,5 +13,4 @@ import UIKit
public var actionType: String
public var extraParameters: JSONValueDictionary?
public var analyticsData: JSONValueDictionary?
public var title: String?
}

View File

@ -22,8 +22,6 @@ public class ActionOpenPanelModel: ActionModelProtocol {
public var panel: Panel
public var extraParameters: JSONValueDictionary?
public var analyticsData: JSONValueDictionary?
// Temporary fix till server changes
public var title: String?
public init(panel: Panel) {
self.panel = panel

View File

@ -14,8 +14,6 @@ import Foundation
public var pageType: String
public var extraParameters: JSONValueDictionary?
public var analyticsData: JSONValueDictionary?
// Temporary fix till server changes
public var title: String?
public init(pageType: String) {
self.pageType = pageType

View File

@ -32,7 +32,7 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupW
public var disabledFillColor: Color?
public var disabledTextColor: Color?
public var disabledBorderColor: Color?
public var groupName: String = FormValidator.defaultGroupName
public var groupName: String = ""
public func setValidity(_ valid: Bool, group: FormGroupRule) {
enabled = valid

View File

@ -25,7 +25,7 @@ open class ExternalLink: Link {
guard let model = model as? ExternalLinkModel else { return }
exportImageView?.tintColor = model.textColor.uiColor
exportImageView?.tintColor = model.enabledColor.uiColor
}
//--------------------------------------------------

View File

@ -52,7 +52,7 @@ import UIKit
guard let model = model as? LinkModel else { return }
setTitle(model.title, for: .normal)
setTitleColor(model.textColor.uiColor, for: .normal)
setTitleColor(model.enabledColor.uiColor, for: .normal)
setTitleColor(model.disabledColor.uiColor, for: .disabled)
isEnabled = model.enabled
set(with: model.action, delegateObject: delegateObject, additionalData: additionalData)

View File

@ -21,7 +21,7 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol {
public var title: String
public var action: ActionModelProtocol
public var enabled = true
public var textColor = Color(uiColor: .mvmBlack)
public var enabledColor = Color(uiColor: .mvmBlack)
public var disabledColor = Color(uiColor: .mvmCoolGray6)
//--------------------------------------------------
@ -43,7 +43,7 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol {
case title
case action
case enabled
case textColor
case enabledColor
case disabledColor
}
@ -60,8 +60,8 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol {
if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
self.enabled = enabled
}
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .textColor) {
textColor = color
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledColor) {
enabledColor = color
}
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledColor) {
@ -76,7 +76,7 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol {
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeModel(action, forKey: .action)
try container.encode(enabled, forKey: .enabled)
try container.encode(textColor, forKey: .textColor)
try container.encode(enabledColor, forKey: .enabledColor)
try container.encode(disabledColor, forKey: .disabledColor)
}
}

View File

@ -39,7 +39,7 @@ open class RadioBox: Control {
super.setupView()
layer.delegate = self
layer.borderColor = UIColor.black.cgColor
layer.borderColor = UIColor.mvmCoolGray6.cgColor
layer.borderWidth = 1
label.numberOfLines = 1
@ -60,7 +60,7 @@ open class RadioBox: Control {
// MARK: - MoleculeViewProtocol
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? RadioBoxModel else { return }
isSelected = model.selected
@ -69,6 +69,15 @@ open class RadioBox: Control {
subTextLabel.text = model.subText
isOutOfStock = model.strikethrough
subTextLabelHeightConstraint?.isActive = (subTextLabel.text?.count ?? 0) == 0
if let color = model.selectedAccentColor?.uiColor {
accentColor = color
}
}
open override func reset() {
super.reset()
backgroundColor = .white
accentColor = .mvmRed
}
// MARK: - State Handling
@ -77,11 +86,12 @@ open class RadioBox: Control {
// Draw the strikethrough
strikeLayer?.removeFromSuperlayer()
if isOutOfStock {
let line = getStrikeThrough(color: .black, thickness: 1)
let line = getStrikeThrough(color: isSelected ? .black : .mvmCoolGray6, thickness: 1)
layer.addSublayer(line)
strikeLayer = line
}
// Draw the border
borderLayer?.removeFromSuperlayer()
if isSelected {
@ -98,6 +108,7 @@ open class RadioBox: Control {
if !isEnabled {
let mask = getMaskLayer()
layer.mask = mask
maskLayer = mask
}
}
@ -108,6 +119,7 @@ open class RadioBox: Control {
}
@objc open func selectBox() {
guard isEnabled else { return }
isSelected = true
radioBoxModel?.selected = isSelected
layer.setNeedsDisplay()
@ -131,7 +143,7 @@ open class RadioBox: Control {
let topLineLayer = CAShapeLayer()
topLineLayer.fillColor = nil
topLineLayer.strokeColor = UIColor.mvmRed.cgColor
topLineLayer.strokeColor = accentColor.cgColor
topLineLayer.lineWidth = 4
topLineLayer.path = topLinePath.cgPath
layer.addSublayer(topLineLayer)

View File

@ -8,7 +8,12 @@
import Foundation
open class RadioBoxCollectionViewCell: CollectionViewCell {
let radioBox = RadioBox()
public let radioBox = RadioBox()
open override func reset() {
super.reset()
backgroundColor = .clear
}
open override func setupView() {
super.setupView()

View File

@ -11,8 +11,8 @@ import Foundation
public static var identifier: String = "radioBox"
public var text: String
public var subText: String?
public var backgroundColor: Color? = Color(uiColor: .white)
public var selectedAccentColor = Color(uiColor: .mvmRed)
public var backgroundColor: Color?
public var selectedAccentColor: Color?
public var selected: Bool = false
public var enabled: Bool = true
public var strikethrough: Bool = false
@ -34,12 +34,8 @@ import Foundation
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
text = try typeContainer.decode(String.self, forKey: .text)
subText = try typeContainer.decodeIfPresent(String.self, forKey: .subText)
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .selectedAccentColor) {
selectedAccentColor = color
}
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) {
backgroundColor = color
}
selectedAccentColor = try typeContainer.decodeIfPresent(Color.self, forKey: .selectedAccentColor)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
if let isSelected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected) {
selected = isSelected
}
@ -58,7 +54,7 @@ import Foundation
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(text, forKey: .text)
try container.encodeIfPresent(subText, forKey: .subText)
try container.encode(selectedAccentColor, forKey: .selectedAccentColor)
try container.encodeIfPresent(selectedAccentColor, forKey: .selectedAccentColor)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encode(selected, forKey: .selected)
try container.encode(enabled, forKey: .enabled)

View File

@ -15,7 +15,11 @@ open class RadioBoxes: View {
private let boxWidth: CGFloat = 151.0
private let boxHeight: CGFloat = 64.0
private let itemSpacing: CGFloat = 8.0
private var numberOfColumns: CGFloat = 2.0
private var radioBoxesModel: RadioBoxesModel? {
return model as? RadioBoxesModel
}
private var delegateObject: MVMCoreUIDelegateObject?
/// The models for the molecules.
@ -42,7 +46,7 @@ open class RadioBoxes: View {
}
// MARK: - MoleculeViewProtocol
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
self.delegateObject = delegateObject
@ -94,7 +98,7 @@ open class RadioBoxes: View {
}
// Calculate the height
let rows = ceil(CGFloat(boxes.count) / 2.0)
let rows = ceil(CGFloat(boxes.count) / numberOfColumns)
let height = (rows * boxHeight) + ((rows - 1) * itemSpacing)
collectionViewHeight?.constant = height
}
@ -102,7 +106,7 @@ open class RadioBoxes: View {
extension RadioBoxes: UICollectionViewDelegateFlowLayout {
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let itemWidth: CGFloat = (collectionView.bounds.width - itemSpacing) / 2
let itemWidth: CGFloat = (collectionView.bounds.width - itemSpacing) / numberOfColumns
return CGSize(width: itemWidth, height: boxHeight)
}
}
@ -117,7 +121,16 @@ extension RadioBoxes: UICollectionViewDataSource {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RadioBoxCollectionViewCell", for: indexPath) as? RadioBoxCollectionViewCell else {
fatalError()
}
cell.reset()
cell.radioBox.isUserInteractionEnabled = false
if let color = radioBoxesModel?.boxesColor {
cell.radioBox.backgroundColor = color.uiColor
}
if let color = radioBoxesModel?.selectedAccentColor {
cell.radioBox.accentColor = color.uiColor
}
cell.set(with: molecule, delegateObject, nil)
cell.updateView(size ?? collectionView.bounds.width)
if molecule.selected {
@ -129,13 +142,18 @@ extension RadioBoxes: UICollectionViewDataSource {
}
extension RadioBoxes: UICollectionViewDelegate {
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
open func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
guard let molecule = boxes?[indexPath.row] else { return false }
return molecule.enabled
}
open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? RadioBoxCollectionViewCell else { return }
cell.radioBox.selectBox()
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
}
public func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
open func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? RadioBoxCollectionViewCell else { return }
cell.radioBox.deselectBox()
}

View File

@ -9,9 +9,10 @@
import Foundation
@objcMembers public class RadioBoxesModel: MoleculeModelProtocol, FormFieldProtocol {
public static var identifier: String = "radioBoxes"
public var boxes: [RadioBoxModel]
public var backgroundColor: Color?
public var selectedAccentColor: Color?
public var boxes: [RadioBoxModel]
public var boxesColor: Color?
public var fieldKey: String?
public var groupName: String = FormValidator.defaultGroupName
public var baseValue: AnyHashable?
@ -28,6 +29,7 @@ import Foundation
case moleculeName
case selectedAccentColor
case backgroundColor
case boxesColor
case boxes
case fieldKey
case groupName
@ -37,6 +39,7 @@ import Foundation
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
selectedAccentColor = try typeContainer.decodeIfPresent(Color.self, forKey: .selectedAccentColor)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
boxesColor = try typeContainer.decodeIfPresent(Color.self, forKey: .boxesColor)
boxes = try typeContainer.decode([RadioBoxModel].self, forKey: .boxes)
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {

View File

@ -90,6 +90,9 @@ import UIKit
/// The action performed when tapped.
func tapAction() {
if !isEnabled {
return
}
if let radioButtonModel = radioButtonSelectionHelper {
radioButtonModel.selected(self)
} else {

View File

@ -0,0 +1,166 @@
//
// RadioSwatch.swift
// MVMCoreUI
//
// Created by Lekshmi S on 01/04/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
import UIKit
open class RadioSwatch: Control {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public let bottomText = Label.createLabelRegularMicro(true)
private var circleLayer: CAShapeLayer?
private var selectedLayer: CALayer?
private var strikeLayer: CALayer?
private var maskLayer: CALayer?
public var radioSwatchModel: RadioSwatchModel? {
return model as? RadioSwatchModel
}
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
open override func updateView(_ size: CGFloat) {
super.updateView(size)
bottomText.updateView(size)
layer.setNeedsDisplay()
}
open override func setupView() {
super.setupView()
addSubview(bottomText)
bottomText.textAlignment = .center
NSLayoutConstraint.constraintPinSubview(bottomText, pinTop: true, topConstant: 38, pinBottom: true, bottomConstant: 0, pinLeft: true, leftConstant: 0, pinRight: true, rightConstant: 0)
addTarget(self, action: #selector(selectSwatch), for: .touchUpInside)
}
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? RadioSwatchModel else { return }
isSelected = model.selected
isEnabled = model.enabled
bottomText.text = model.text
}
public override func reset() {
super.reset()
isSelected = false
isEnabled = true
bottomText.text = nil
}
//------------------------------------------------------
// MARK: - State Handling
//------------------------------------------------------
open override func draw(_ layer: CALayer, in ctx: CGContext) {
//Draw the swatch
circleLayer?.removeFromSuperlayer()
let circle = getCircle(color: isSelected ? .mvmBlack : .mvmCoolGray6, thickness: 1)
layer.addSublayer(circle)
circleLayer = circle
//Draw the strikethrough
strikeLayer?.removeFromSuperlayer()
if radioSwatchModel?.strikethrough ?? false {
let line = getStrikeThrough(color: isSelected ? .mvmBlack : .mvmCoolGray6, thickness: 1)
layer.addSublayer(line)
strikeLayer = line
}
//Draw the selected layer
selectedLayer?.removeFromSuperlayer()
if isSelected {
let outerCircle = getSelectedLayer(color: isSelected ? .mvmBlack : .mvmCoolGray6, thickness: 1)
layer.addSublayer(outerCircle)
selectedLayer = outerCircle
bottomText.isHidden = false
} else {
bottomText.isHidden = true
}
//Handle Mask
maskLayer?.removeFromSuperlayer()
if !isEnabled {
let mask = getMaskLayer()
layer.mask = mask
maskLayer = mask
}
}
open override func layoutSubviews() {
super.layoutSubviews()
// Accounts for any size changes
layer.setNeedsDisplay()
}
@objc open func selectSwatch() {
guard isEnabled else { return }
isSelected = true
radioSwatchModel?.selected = isSelected
layer.setNeedsDisplay()
}
@objc open func deselectSwatch() {
isSelected = false
radioSwatchModel?.selected = isSelected
layer.setNeedsDisplay()
}
func getCircle(color: UIColor, thickness: CGFloat) -> CAShapeLayer {
let circle = CAShapeLayer()
circle.name = "innercircle"
circle.fillColor = radioSwatchModel?.color.cgColor ?? UIColor.blue.cgColor
circle.opacity = 1.0
circle.lineWidth = thickness
circle.strokeColor = color.cgColor
let circlePath = UIBezierPath(ovalIn: CGRect(x: 12, y: 1, width: 30, height: 30))
circle.path = circlePath.cgPath
return circle
}
func getStrikeThrough(color: UIColor, thickness: CGFloat) -> CAShapeLayer {
let strikeThrough = CAShapeLayer()
strikeThrough.name = "strikethrough"
strikeThrough.fillColor = nil
strikeThrough.opacity = 1.0
strikeThrough.lineWidth = thickness
strikeThrough.strokeColor = color.cgColor
let linePath = UIBezierPath()
linePath.move(to: CGPoint(x: 12, y: 31))
linePath.addLine(to: CGPoint(x: 42, y: 1))
strikeThrough.path = linePath.cgPath
return strikeThrough
}
func getSelectedLayer(color: UIColor, thickness: CGFloat) -> CAShapeLayer {
circleLayer?.path = UIBezierPath(ovalIn: CGRect(x: 15, y: 4, width: 24, height: 24)).cgPath
let circle = CAShapeLayer()
circle.name = "outercircle"
circle.fillColor = UIColor.clear.cgColor
circle.opacity = 1.0
circle.lineWidth = thickness
circle.strokeColor = color.cgColor
let circlePath = UIBezierPath(ovalIn: CGRect(x: 12, y: 1, width: 30, height: 30))
circle.path = circlePath.cgPath
return circle
}
func getMaskLayer() -> CALayer {
let mask = CALayer()
mask.backgroundColor = UIColor.white.cgColor
mask.opacity = 0.3
mask.frame = bounds
return mask
}
}

View File

@ -0,0 +1,23 @@
//
// RadioSwatchCollectionViewCell.swift
// MVMCoreUI
//
// Created by Lekshmi S on 13/04/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
open class RadioSwatchCollectionViewCell: CollectionViewCell {
public let radioSwatch = RadioSwatch()
open override func setupView() {
super.setupView()
addMolecule(radioSwatch)
MVMCoreUIUtility.setMarginsFor(contentView, leading: 0, top: 0, trailing: 0, bottom: 0)
}
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
guard let model = model as? RadioSwatchModel else { return }
radioSwatch.set(with: model, delegateObject, additionalData)
}
}

View File

@ -0,0 +1,64 @@
//
// RadioSwatchModel.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 4/17/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
@objcMembers public class RadioSwatchModel: MoleculeModelProtocol {
public static var identifier: String = "radioSwatch"
public var backgroundColor: Color?
public var color: Color = Color(uiColor: .mvmBlue)
public var text: String?
public var selected: Bool = false
public var enabled: Bool = true
public var strikethrough: Bool = false
public var fieldValue: String?
private enum CodingKeys: String, CodingKey {
case moleculeName
case backgroundColor
case color
case text
case selected
case enabled
case strikethrough
case fieldValue
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .color) {
self.color = color
}
text = try typeContainer.decodeIfPresent(String.self, forKey: .text)
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)
}
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)
try container.encode(color, forKey: .color)
try container.encodeIfPresent(text, forKey: .text)
try container.encode(selected, forKey: .selected)
try container.encode(enabled, forKey: .enabled)
try container.encode(strikethrough, forKey: .strikethrough)
try container.encodeIfPresent(fieldValue, forKey: .fieldValue)
}
}

View File

@ -0,0 +1,152 @@
//
// RadioSwatches.swift
// MVMCoreUI
//
// Created by Lekshmi S on 01/04/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
open class RadioSwatches: View {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public var collectionView: CollectionView!
public var swatches: [RadioSwatchModel]?
private var size: CGFloat?
private var delegateObject: MVMCoreUIDelegateObject?
//------------------------------------------------------
// MARK: - Constraints
//------------------------------------------------------
public var collectionViewHeight: NSLayoutConstraint?
private let cellSize: CGFloat = 54.0
private let itemSpacing: CGFloat = 8.0
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
open override func layoutSubviews() {
super.layoutSubviews()
// Accounts for any collection size changes
setHeight()
DispatchQueue.main.async {
self.collectionView.collectionViewLayout.invalidateLayout()
}
}
open override func setupView() {
super.setupView()
collectionView = createCollectionView()
addSubview(collectionView)
NSLayoutConstraint.constraintPinSubview(toSuperview: collectionView)
collectionViewHeight = collectionView.heightAnchor.constraint(equalToConstant: 100)
collectionViewHeight?.isActive = true
}
@objc override open func updateView(_ size: CGFloat) {
super.updateView(size)
self.size = size
collectionView.updateView(size)
}
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
self.delegateObject = delegateObject
guard let radioSwatchesModel = model as? RadioSwatchesModel else { return }
swatches = radioSwatchesModel.swatches
FormValidator.setupValidation(for: radioSwatchesModel, delegate: delegateObject?.formHolderDelegate)
collectionView.reloadData()
}
//------------------------------------------------------
// MARK: - Methods
//------------------------------------------------------
/// Creates the collection view.
open func createCollectionView() -> CollectionView {
let collection = CollectionView(frame: .zero, collectionViewLayout: createCollectionViewLayout())
collection.dataSource = self
collection.delegate = self
collection.register(RadioSwatchCollectionViewCell.self, forCellWithReuseIdentifier: "RadioSwatchCollectionViewCell")
return collection
}
/// Creates the layout for the collection.
open func createCollectionViewLayout() -> UICollectionViewLayout {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.minimumLineSpacing = itemSpacing
layout.minimumInteritemSpacing = itemSpacing
return layout
}
open func setHeight() {
guard let swatches = swatches, swatches.count > 0 else {
collectionViewHeight?.constant = 0
return
}
// Calculate the height
let swatchesInRow = floor(CGFloat(collectionView.bounds.width/(cellSize + itemSpacing)))
let numberOfRows = ceil(CGFloat(swatches.count)/swatchesInRow)
let height = (numberOfRows * cellSize) + (itemSpacing * (numberOfRows-1))
if let oldHeight = collectionViewHeight?.constant,
height != oldHeight {
// Notify delegate of height change, called async to avoid various race conditions caused while happening while laying out initially.
DispatchQueue.main.async {
self.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self)
}
}
collectionViewHeight?.constant = CGFloat(height)
}
}
//------------------------------------------------------
// MARK: - Delegate methods
//------------------------------------------------------
extension RadioSwatches: UICollectionViewDelegateFlowLayout {
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: cellSize, height: cellSize)
}
}
extension RadioSwatches: UICollectionViewDataSource {
open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return swatches?.count ?? 0
}
open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let molecule = swatches?[indexPath.row], let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RadioSwatchCollectionViewCell", for: indexPath) as? RadioSwatchCollectionViewCell else {
fatalError()
}
cell.reset()
cell.radioSwatch.isUserInteractionEnabled = false
cell.set(with: molecule, delegateObject, nil)
cell.updateView(size ?? collectionView.bounds.width)
if molecule.selected {
collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredVertically)
}
cell.layoutIfNeeded()
return cell
}
}
extension RadioSwatches: UICollectionViewDelegate {
open func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
guard let molecule = swatches?[indexPath.row] else { return false }
return molecule.enabled
}
open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? RadioSwatchCollectionViewCell else { return }
cell.radioSwatch.selectSwatch()
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
}
open func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? RadioSwatchCollectionViewCell else { return }
cell.radioSwatch.deselectSwatch()
}
}

View File

@ -0,0 +1,54 @@
//
// RadioSwatchesModel.swift
// MVMCoreUI
//
// Created by Lekshmi S on 31/03/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
@objcMembers public class RadioSwatchesModel: MoleculeModelProtocol, FormFieldProtocol {
public static var identifier: String = "radioSwatches"
public var backgroundColor: Color?
public var swatches: [RadioSwatchModel]
public var fieldKey: String?
public var groupName: String = FormValidator.defaultGroupName
public var baseValue: AnyHashable?
/// Returns the fieldValue of the selected swatch, otherwise the text of selected swatch.
public func formFieldValue() -> AnyHashable? {
let selectedSwatch = swatches.first { (swatch) -> Bool in
return swatch.selected
}
return selectedSwatch?.fieldValue ?? selectedSwatch?.text
}
private enum CodingKeys: String, CodingKey {
case moleculeName
case backgroundColor
case swatches
case fieldKey
case groupName
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
swatches = try typeContainer.decode([RadioSwatchModel].self, forKey: .swatches)
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
self.groupName = groupName
}
baseValue = formFieldValue()
}
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)
try container.encode(swatches, forKey: .swatches)
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
try container.encode(groupName, forKey: .groupName)
}
}

View File

@ -258,12 +258,12 @@ import UIKit
title = model.title
feedback = model.feedback
errorMessage = model.errorMessage
isEnabled = model.isEnabled
isEnabled = model.enabled
if let isLocked = model.isLocked {
if let isLocked = model.locked {
self.isLocked = isLocked
} else if let isSelected = model.isSelected{
} else if let isSelected = model.selected {
self.isSelected = isSelected
}
}

View File

@ -9,7 +9,7 @@
import Foundation
@objcMembers public class EntryFieldModel: MoleculeModelProtocol, FormFieldProtocol, FormRuleWatcherFieldProtocol {
@objcMembers public class EntryFieldModel: MoleculeModelProtocol, FormFieldProtocol, FormRuleWatcherFieldProtocol, EnableableModelProtocol {
//--------------------------------------------------
// MARK: - Properties
@ -23,9 +23,9 @@ import Foundation
public var title: String?
public var feedback: String?
public var errorMessage: String = ""
public var isEnabled: Bool = true
public var isLocked: Bool?
public var isSelected: Bool?
public var enabled: Bool = true
public var locked: Bool?
public var selected: Bool?
public var text: String?
public var fieldKey: String?
@ -52,14 +52,12 @@ import Foundation
private enum CodingKeys: String, CodingKey {
case moleculeName
case backgroundColor
case title = "label"
case isEnabled
case title
case enabled
case feedback
case errorMessage = "errorMsg"
case isLocked
case isSelected
case isValid
case isRequired = "required"
case errorMessage
case locked
case selected
case text
case fieldKey
case groupName
@ -84,10 +82,9 @@ import Foundation
title = try typeContainer.decodeIfPresent(String.self, forKey: .title)
feedback = try typeContainer.decodeIfPresent(String.self, forKey: .feedback)
errorMessage = try typeContainer.decodeIfPresent(String.self, forKey: .errorMessage) ?? ""
isEnabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .isEnabled) ?? true
isLocked = try typeContainer.decodeIfPresent(Bool.self, forKey: .isLocked)
isSelected = try typeContainer.decodeIfPresent(Bool.self, forKey: .isSelected)
isValid = try typeContainer.decodeIfPresent(Bool.self, forKey: .isValid)
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
locked = try typeContainer.decodeIfPresent(Bool.self, forKey: .locked)
selected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected)
text = try typeContainer.decodeIfPresent(String.self, forKey: .text)
baseValue = text
@ -104,12 +101,11 @@ import Foundation
try container.encodeIfPresent(title, forKey: .title)
try container.encodeIfPresent(feedback, forKey: .feedback)
try container.encode(errorMessage, forKey: .errorMessage)
try container.encode(isEnabled, forKey: .isEnabled)
try container.encode(isLocked, forKey: .isLocked)
try container.encode(isSelected, forKey: .isSelected)
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
try container.encodeIfPresent(isValid, forKey: .isValid)
try container.encode(enabled, forKey: .enabled)
try container.encode(locked, forKey: .locked)
try container.encode(selected, forKey: .selected)
try container.encodeIfPresent(text, forKey: .text)
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
try container.encodeIfPresent(groupName, forKey: .groupName)
}
}

View File

@ -314,14 +314,7 @@ import UIKit
break
}
if let regex = model.regex, !regex.isEmpty {
validationBlock = { enteredValue in
guard let value = enteredValue else { return false }
return MVMCoreUIUtility.validate(value, withRegularExpression: regex)
}
} else {
defaultValidationBlock()
}
defaultValidationBlock()
uiTextFieldDelegate = delegateObject?.uiTextFieldDelegate
observingTextFieldDelegate = delegateObject?.observingTextFieldDelegate

View File

@ -27,7 +27,6 @@
public var enabledTextColor: Color?
public var disabledTextColor: Color?
public var type: EntryType?
public var regex: String?
//--------------------------------------------------
// MARK: - Keys
@ -40,7 +39,6 @@
case enabledTextColor
case disabledTextColor
case type
case regex
}
//--------------------------------------------------
@ -55,7 +53,6 @@
enabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledTextColor)
disabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledTextColor)
type = try typeContainer.decodeIfPresent(EntryType.self, forKey: .type)
regex = try typeContainer.decodeIfPresent(String.self, forKey: .regex)
}
public override func encode(to encoder: Encoder) throws {
@ -67,6 +64,5 @@
try container.encodeIfPresent(enabledTextColor, forKey: .enabledTextColor)
try container.encodeIfPresent(disabledTextColor, forKey: .disabledTextColor)
try container.encodeIfPresent(type, forKey: .type)
try container.encodeIfPresent(regex, forKey: .regex)
}
}

View File

@ -14,8 +14,8 @@ import Foundation
// MARK: - Outlets
//------------------------------------------------------
let leftTextLabel = Label.commonLabelB1(true)
let rightTextLabel = Label.commonLabelB1(true)
let leftTextLabel = Label.createLabelBoldBodySmall(true)
let rightTextLabel = Label.createLabelBoldBodySmall(true)
//------------------------------------------------------
// MARK: - Constraints
@ -23,6 +23,29 @@ import Foundation
var rightTextLabelLeading: NSLayoutConstraint?
var leftTextLabelTrailing: NSLayoutConstraint?
var rightTextLabelTrailing: NSLayoutConstraint?
private func constrainLeftLabelOnly() {
deactivateMiddleConstraint()
leftTextLabelTrailing?.isActive = false
leftTextLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: leftTextLabel.trailingAnchor)
leftTextLabelTrailing?.isActive = true
}
private func constrainRightLabelOnly() {
deactivateMiddleConstraint()
rightTextLabelLeading?.isActive = false
rightTextLabelLeading = rightTextLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
rightTextLabelLeading?.isActive = true
}
private func deactivateMiddleConstraint() {
leftTextLabelTrailing?.isActive = false
rightTextLabelLeading?.isActive = false
}
//------------------------------------------------------
// MARK: - Initialization
@ -43,8 +66,6 @@ import Foundation
override open func setupView() {
super.setupView()
guard subviews.isEmpty else { return }
addSubview(leftTextLabel)
addSubview(rightTextLabel)
@ -67,7 +88,7 @@ import Foundation
// Resolves text layout issues found between both dynamically sized labels, number is not exact but performs as required.
if leftTextLabel.hasText && rightTextLabel.hasText {
let padding = MFStyler.defaultHorizontalPadding(forSize: size) * 2
let maximumTextWidth = (size - (padding + 16)) * 0.4
let maximumTextWidth = (size - (padding + Padding.Four)) * 0.4
// Subtracting 10 resolves issues of SE and iPad
rightTextLabel.preferredMaxLayoutWidth = round(maximumTextWidth) - 10
} else {
@ -84,57 +105,38 @@ import Foundation
leftTextLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true
leftTextLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true
let leftTextBottom = leftTextLabel.bottomAnchor.constraint(equalTo: bottomAnchor)
let leftTextBottom = bottomAnchor.constraint(equalTo: leftTextLabel.bottomAnchor)
leftTextBottom.priority = UILayoutPriority(249)
leftTextBottom.isActive = true
bottomAnchor.constraint(greaterThanOrEqualTo: leftTextLabel.bottomAnchor).isActive = true
rightTextLabelLeading = rightTextLabel.leadingAnchor.constraint(equalTo: leftTextLabel.trailingAnchor, constant: 16)
rightTextLabelLeading = rightTextLabel.leadingAnchor.constraint(equalTo: leftTextLabel.trailingAnchor, constant: Padding.Four)
rightTextLabelLeading?.isActive = true
rightTextLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true
let rightLayout = layoutMarginsGuide.trailingAnchor.constraint(equalTo: rightTextLabel.trailingAnchor)
rightLayout.priority = UILayoutPriority(rawValue: 995)
rightLayout.isActive = true
let rightTextBottom = rightTextLabel.bottomAnchor.constraint(equalTo: bottomAnchor)
rightTextLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: rightTextLabel.trailingAnchor)
rightTextLabelTrailing?.isActive = true
let rightTextBottom = bottomAnchor.constraint(equalTo: rightTextLabel.bottomAnchor)
rightTextBottom.priority = UILayoutPriority(rawValue: 249)
rightTextBottom.isActive = true
bottomAnchor.constraint(greaterThanOrEqualTo: rightTextLabel.bottomAnchor).isActive = true
let leftTextWidth = leftTextLabel.widthAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.widthAnchor, multiplier: 0.6)
let leftTextWidth = leftTextLabel.widthAnchor.constraint(equalTo: layoutMarginsGuide.widthAnchor, multiplier: 0.6)
leftTextWidth.priority = UILayoutPriority(rawValue: 995)
leftTextWidth.isActive = true
let rightTextWidth = rightTextLabel.widthAnchor.constraint(lessThanOrEqualTo: layoutMarginsGuide.widthAnchor, multiplier: 0.4)
rightTextWidth.priority = UILayoutPriority(rawValue: 906)
let rightTextWidth = rightTextLabel.widthAnchor.constraint(equalTo: layoutMarginsGuide.widthAnchor, multiplier: 0.4)
rightTextWidth.priority = UILayoutPriority(rawValue: 995)
rightTextWidth.isActive = true
leftTextLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 901), for: .horizontal)
rightTextLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 902), for: .horizontal)
leftTextLabel.setContentHuggingPriority(.required, for: .vertical)
rightTextLabel.setContentHuggingPriority(.required, for: .vertical)
rightTextLabel.setContentHuggingPriority(.required, for: .horizontal)
leftTextLabel.setContentCompressionResistancePriority(.required, for: .vertical)
rightTextLabel.setContentCompressionResistancePriority(.required, for: .vertical)
rightTextLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 902), for: .horizontal)
}
private func constrainLeftLabel() {
deactivateMiddleConstraint()
leftTextLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: leftTextLabel.trailingAnchor)
leftTextLabelTrailing?.isActive = true
}
private func constrainRightLabel() {
deactivateMiddleConstraint()
rightTextLabelLeading = rightTextLabel.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)
rightTextLabelLeading?.isActive = true
rightTextLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
}
override open func reset() {
@ -144,31 +146,31 @@ import Foundation
constrainBothLabels()
leftTextLabel.text = ""
rightTextLabel.text = ""
leftTextLabel.textAlignment = .left
rightTextLabel.textAlignment = .right
backgroundColor = nil
}
private func deactivateMiddleConstraint() {
leftTextLabelTrailing?.isActive = false
rightTextLabelLeading?.isActive = false
}
//------------------------------------------------------
// MARK: - Atomization
//------------------------------------------------------
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let leftRightLabelModel = model as? LeftRightLabelModel else {
return
}
guard let leftRightLabelModel = model as? LeftRightLabelModel else { return }
leftTextLabel.set(with: leftRightLabelModel.leftText, delegateObject, additionalData)
rightTextLabel.setOptional(with: leftRightLabelModel.rightText, delegateObject, additionalData)
// Label defaults to .left if no textAlignment value is provided in model.
rightTextLabel.textAlignment = leftRightLabelModel.rightText?.textAlignment ?? .right
if !leftTextLabel.hasText {
constrainRightLabel()
constrainRightLabelOnly()
} else if !rightTextLabel.hasText {
constrainLeftLabel()
constrainLeftLabelOnly()
}
}
}

View File

@ -9,39 +9,27 @@
import UIKit
@objcMembers open class MultiProgress: View {
private let stack = Stack<StackModel>()
var multiProgressModel: MultiProgressBarModel? {
get { return model as? MultiProgressBarModel }
}
///passing value to progressList creates corresponding progress bars
var progressList: Array<SingleProgressBarModel>? {
didSet {
for subview in subviews {
subview.removeFromSuperview()
}
guard (progressList?.count ?? 0) > 0 else {
return
}
var previous: UIView?
for progressObject in progressList! {
guard progressObject.progress > 0.0 else {
continue
}
let view = UIView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
addSubview(view)
view.backgroundColor = progressObject.progressColor.uiColor
view.widthAnchor.constraint(equalTo: widthAnchor, multiplier: progressObject.progress/100.0).isActive = true
view.leadingAnchor.constraint(equalTo: previous?.trailingAnchor ?? leadingAnchor).isActive = true
previous = view
NSLayoutConstraint.constraintPinSubview(view, pinTop: true, pinBottom: true, pinLeft: false, pinRight: false)
}
}
public required init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
super.init(frame: .zero)
set(with: model, delegateObject, additionalData)
}
var roundedRect: Bool = false {
public required init?(coder: NSCoder) {
super.init(coder: coder)
}
public override init(frame: CGRect) {
super.init(frame: frame)
}
var roundedCorners: Bool = false {
didSet {
if roundedRect {
if roundedCorners {
layer.cornerRadius = (thicknessConstraint?.constant ?? defaultHeight)/2
} else {
layer.cornerRadius = 0
@ -57,28 +45,53 @@ import UIKit
translatesAutoresizingMaskIntoConstraints = false
backgroundColor = .mfLightSilver()
clipsToBounds = true
addSubview(stack)
NSLayoutConstraint.constraintPinSubview(toSuperview: stack)
stack.backgroundColor = backgroundColor
stack.contentView.backgroundColor = .white
stack.model = StackModel(molecules: [], axis: .horizontal, spacing: 2)
stack.stackModel?.horizontalAlignment = .leading
if thicknessConstraint == nil {
thicknessConstraint = heightAnchor.constraint(equalToConstant: defaultHeight)
thicknessConstraint?.isActive = true
}
}
/// Creates the bars
open func set(with progressList: Array<SingleProgressBarModel>, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
stack.removeAllItemViews()
guard let stackModel = stack.stackModel else { return }
var views: [StackItem] = []
var models: [StackItemModel] = []
for progressObject in progressList {
guard progressObject.percent > 0.0 else { continue }
let model = StackItemModel(percent: Int(progressObject.percent), horizontalAlignment: .fill, verticalAlignment: .fill)
model.backgroundColor = progressObject.color
models.append(model)
views.append(StackItem())
}
stack.stackItems = views
stackModel.molecules = models
stack.set(with: stackModel, delegateObject, additionalData)
}
//MARK: - MoleculeViewProtocol
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let multiProgressModel = multiProgressModel else {
return
}
roundedRect = multiProgressModel.roundedRect ?? false
guard let multiProgressModel = multiProgressModel else { return }
roundedCorners = multiProgressModel.roundedCorners ?? false
thicknessConstraint?.constant = multiProgressModel.thickness ?? defaultHeight
progressList = multiProgressModel.progressList
stack.model?.backgroundColor = model.backgroundColor
set(with: multiProgressModel.progressList, delegateObject, additionalData)
}
open override func reset() {
super.reset()
backgroundColor = .mfLightSilver()
progressList = nil
stack.reset()
set(with: [], nil, nil)
}
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {

View File

@ -9,12 +9,12 @@
import Foundation
@objcMembers public class SingleProgressBarModel: Codable {
@Percent var progress: CGFloat
var progressColor: Color
@Percent var percent: CGFloat
var color: Color
init(_ progress: CGFloat, color: Color) {
self.progress = progress
self.progressColor = color
init(_ percent: CGFloat, color: Color) {
self.percent = percent
self.color = color
}
}
@ -23,13 +23,13 @@ import Foundation
public var progressList: [SingleProgressBarModel]
public var backgroundColor: Color?
public var thickness: CGFloat?
public var roundedRect: Bool?
public var roundedCorners: Bool?
private enum CodingKeys: String, CodingKey {
case moleculeName
case progressList
case thickness
case roundedRect
case roundedCorners
case backgroundColor
}
@ -42,7 +42,7 @@ import Foundation
progressList = try typeContainer.decode([SingleProgressBarModel].self, forKey: .progressList)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
thickness = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .thickness)
roundedRect = try typeContainer.decodeIfPresent(Bool.self, forKey: .roundedRect)
roundedCorners = try typeContainer.decodeIfPresent(Bool.self, forKey: .roundedCorners)
}
public func encode(to encoder: Encoder) throws {
@ -50,7 +50,7 @@ import Foundation
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(progressList, forKey: .progressList)
try container.encodeIfPresent(thickness, forKey: .thickness)
try container.encodeIfPresent(roundedRect, forKey: .roundedRect)
try container.encodeIfPresent(roundedCorners, forKey: .roundedCorners)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
}
}

View File

@ -14,7 +14,7 @@ import Foundation
var thickness: CGFloat = 8.0 {
willSet(newValue) {
heightAnchor.constraint(equalToConstant: newValue).isActive = true
if progressBarModel?.isRounded ?? false {
if progressBarModel?.roundedCorners ?? false {
layer.cornerRadius = newValue/2.0
} else {
progressViewStyle = .bar
@ -52,12 +52,11 @@ import Foundation
//MARK: - MoleculeViewProtocol
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
guard let progressBarModel = model as? ProgressBarModel else {
return
}
guard let progressBarModel = model as? ProgressBarModel else { return }
self.progressBarModel = progressBarModel
thickness = progressBarModel.thickness ?? 8
progress = Float((progressBarModel.percent)/100.0)
progressTintColor = progressBarModel.progressColor.uiColor
progressTintColor = progressBarModel.color.uiColor
if let backgroundColor = progressBarModel.backgroundColor {
trackTintColor = backgroundColor.uiColor
}

View File

@ -11,17 +11,17 @@ import Foundation
@objcMembers public class ProgressBarModel: MoleculeModelProtocol {
public static var identifier: String = "progressBar"
@Percent public var percent: CGFloat
public var progressColor: Color = Color(uiColor: .mfCerulean())
public var color: Color = Color(uiColor: .mfCerulean())
public var backgroundColor: Color? = Color(uiColor: .mfLightSilver())
public var isRounded: Bool?
public var roundedCorners: Bool?
public var thickness: CGFloat?
private enum CodingKeys: String, CodingKey {
case moleculeName
case isRounded = "roundRect"
case roundedCorners
case thickness
case percent
case progressColor
case color
case backgroundColor
}
@ -32,13 +32,13 @@ import Foundation
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
percent = try typeContainer.decode(CGFloat.self, forKey: .percent)
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .progressColor) {
progressColor = color
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .color) {
self.color = color
}
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) {
backgroundColor = color
}
isRounded = try typeContainer.decodeIfPresent(Bool.self, forKey: .isRounded)
roundedCorners = try typeContainer.decodeIfPresent(Bool.self, forKey: .roundedCorners)
thickness = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .thickness)
}
@ -46,9 +46,9 @@ import Foundation
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(percent, forKey: .percent)
try container.encode(progressColor, forKey: .progressColor)
try container.encode(color, forKey: .color)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeIfPresent(isRounded, forKey: .isRounded)
try container.encodeIfPresent(roundedCorners, forKey: .roundedCorners)
try container.encodeIfPresent(thickness, forKey: .thickness)
}
}

View File

@ -25,13 +25,13 @@ public typealias ActionBlockConfirmation = () -> (Bool)
//--------------------------------------------------
/// Holds the on and off colors for the container.
public var containerTintColor: (on: UIColor?, off: UIColor?)? = (on: .mvmGreen, off: .mvmBlack)
public var containerTintColor: (on: UIColor, off: UIColor) = (on: .mvmGreen, off: .mvmBlack)
/// Holds the on and off colors for the knob.
public var knobTintColor: (on: UIColor?, off: UIColor?)? = (on: .mvmWhite, off: .mvmWhite)
public var knobTintColor: (on: UIColor, off: UIColor) = (on: .mvmWhite, off: .mvmWhite)
/// Holds the on and off colors for the disabled state..
public var disabledTintColor: (container: UIColor?, knob: UIColor?)? = (container: .mvmCoolGray3, knob: .mvmWhite)
public var disabledTintColor: (container: UIColor, knob: UIColor) = (container: .mvmCoolGray3, knob: .mvmWhite)
/// Set this flag to false if you do not want to animate state changes.
public var isAnimated = true
@ -62,8 +62,8 @@ public typealias ActionBlockConfirmation = () -> (Bool)
didSet {
isUserInteractionEnabled = isEnabled
changeStateNoAnimation(isEnabled ? isOn : false)
backgroundColor = isEnabled ? containerTintColor?.off : disabledTintColor?.container
knobView.backgroundColor = isEnabled ? knobTintColor?.off : disabledTintColor?.knob
backgroundColor = isEnabled ? (isOn ? containerTintColor.on : containerTintColor.off) : disabledTintColor.container
knobView.backgroundColor = isEnabled ? (isOn ? knobTintColor.on : knobTintColor.off) : disabledTintColor.knob
}
}
@ -80,12 +80,12 @@ public typealias ActionBlockConfirmation = () -> (Bool)
if isAnimated {
UIView.animate(withDuration: 0.2, delay: 0.0, options: .curveEaseIn, animations: {
if self.isOn {
self.knobView.backgroundColor = self.knobTintColor?.on
self.backgroundColor = self.containerTintColor?.on
self.knobView.backgroundColor = self.knobTintColor.on
self.backgroundColor = self.containerTintColor.on
} else {
self.knobView.backgroundColor = self.knobTintColor?.off
self.backgroundColor = self.containerTintColor?.off
self.knobView.backgroundColor = self.knobTintColor.off
self.backgroundColor = self.containerTintColor.off
}
}, completion: nil)
@ -96,12 +96,12 @@ public typealias ActionBlockConfirmation = () -> (Bool)
}, completion: nil)
} else {
backgroundColor = isOn ? containerTintColor?.on : containerTintColor?.off
knobView.backgroundColor = isOn ? knobTintColor?.on : knobTintColor?.off
backgroundColor = isOn ? containerTintColor.on : containerTintColor.off
knobView.backgroundColor = isOn ? knobTintColor.on : knobTintColor.off
self.constrainKnob()
}
(model as? ToggleModel)?.state = isOn
toggleModel?.state = isOn
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
accessibilityValue = isOn ? MVMCoreUIUtility.hardcodedString(withKey: "AccOn") : MVMCoreUIUtility.hardcodedString(withKey: "AccOff")
setNeedsLayout()
@ -109,6 +109,10 @@ public typealias ActionBlockConfirmation = () -> (Bool)
}
}
public var toggleModel: ToggleModel? {
return model as? ToggleModel
}
//--------------------------------------------------
// MARK: - Delegate
//--------------------------------------------------
@ -189,7 +193,7 @@ public typealias ActionBlockConfirmation = () -> (Bool)
public override func setupView() {
super.setupView()
guard subviews.isEmpty else { return }
isAccessibilityElement = true
accessibilityTraits = .button
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "AccToggleHint")
@ -202,7 +206,7 @@ public typealias ActionBlockConfirmation = () -> (Bool)
widthConstraint?.isActive = true
layer.cornerRadius = Self.containerSize.height / 2.0
backgroundColor = containerTintColor?.off
backgroundColor = containerTintColor.off
addSubview(knobView)
@ -222,9 +226,9 @@ public typealias ActionBlockConfirmation = () -> (Bool)
public override func reset() {
super.reset()
backgroundColor = containerTintColor?.off
knobView.backgroundColor = knobTintColor?.off
isAnimated = false
backgroundColor = containerTintColor.off
knobView.backgroundColor = knobTintColor.off
isAnimated = true
isOn = false
constrainKnob()
didToggleAction = nil
@ -344,26 +348,14 @@ public typealias ActionBlockConfirmation = () -> (Bool)
FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate)
if let color = model.onTintColor?.uiColor {
containerTintColor?.on = color
}
if let color = model.offTintColor?.uiColor {
containerTintColor?.off = color
}
if let color = model.onKnobTintColor?.uiColor {
knobTintColor?.on = color
}
if let color = model.offKnobTintColor?.uiColor {
knobTintColor?.off = color
}
containerTintColor.on = model.onTintColor.uiColor
containerTintColor.off = model.offTintColor.uiColor
knobTintColor.on = model.onKnobTintColor.uiColor
knobTintColor.off = model.offKnobTintColor.uiColor
changeStateNoAnimation(model.state)
isAnimated = model.animated
isEnabled = model.enabled
if let actionMap = model.action?.toJSON() {
didToggleAction = { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) }
}

View File

@ -8,8 +8,12 @@
import UIKit
public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol {
public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "toggle"
public var backgroundColor: Color?
public var state: Bool = false
@ -18,10 +22,10 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
public var action: ActionModelProtocol?
public var alternateAction: ActionModelProtocol?
public var accessibilityText: String?
public var onTintColor: Color?
public var offTintColor: Color?
public var onKnobTintColor: Color?
public var offKnobTintColor: Color?
public var onTintColor: Color = Color(uiColor: .mvmGreen)
public var offTintColor: Color = Color(uiColor: .mvmBlack)
public var onKnobTintColor: Color = Color(uiColor: .mvmWhite)
public var offKnobTintColor: Color = Color(uiColor: .mvmWhite)
public var fieldKey: String?
public var groupName: String = FormValidator.defaultGroupName
@ -75,19 +79,35 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
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
}
if let animated = try typeContainer.decodeIfPresent(Bool.self, forKey: .animated) {
self.animated = animated
}
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
alternateAction = try typeContainer.decodeModelIfPresent(codingKey: .alternateAction)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
onTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .onTintColor)
offTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .offTintColor)
onKnobTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .onKnobTintColor)
offKnobTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .offKnobTintColor)
if let onTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .onTintColor) {
self.onTintColor = onTintColor
}
if let offTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .offTintColor) {
self.offTintColor = offTintColor
}
if let onKnobTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .onKnobTintColor) {
self.onKnobTintColor = onKnobTintColor
}
if let offKnobTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .offKnobTintColor) {
self.offKnobTintColor = offKnobTintColor
}
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
baseValue = state
@ -106,10 +126,10 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo
try container.encode(state, forKey: .state)
try container.encode(animated, forKey: .animated)
try container.encode(enabled, forKey: .enabled)
try container.encodeIfPresent(onTintColor, forKey: .onTintColor)
try container.encodeIfPresent(onKnobTintColor, forKey: .onKnobTintColor)
try container.encodeIfPresent(onKnobTintColor, forKey: .onKnobTintColor)
try container.encodeIfPresent(offKnobTintColor, forKey: .offKnobTintColor)
try container.encode(onTintColor, forKey: .onTintColor)
try container.encode(onKnobTintColor, forKey: .onKnobTintColor)
try container.encode(onKnobTintColor, forKey: .onKnobTintColor)
try container.encode(offKnobTintColor, forKey: .offKnobTintColor)
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
try container.encodeIfPresent(groupName, forKey: .groupName)

View File

@ -1,5 +1,5 @@
//
// GraphView.swift
// Wheel.swift
// MobileFirstFramework
//
// Created by Ryan on 10/24/19.
@ -8,12 +8,12 @@
import UIKit
@objcMembers open class GraphView: View, MVMCoreUIViewConstrainingProtocol {
@objcMembers open class Wheel: View, MVMCoreUIViewConstrainingProtocol {
var heightConstraint: NSLayoutConstraint?
var gradientLayer: CALayer?
var graphModel: CircleProgressModel? {
return model as? CircleProgressModel
var graphModel: WheelModel? {
return model as? WheelModel
}
// MARK: setup
@ -28,7 +28,7 @@ import UIKit
override open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? CircleProgressModel else { return }
guard let model = model as? WheelModel else { return }
createGraphCircle(model)
rotationAnimation(model)
}
@ -42,7 +42,7 @@ import UIKit
}
// MARK: circle
open func createGraphCircle(_ graphObject: CircleProgressModel) {
open func createGraphCircle(_ graphObject: WheelModel) {
if let sublayers = layer.sublayers {
for sublayer in sublayers {
sublayer.removeAllAnimations()
@ -56,7 +56,7 @@ import UIKit
//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(GraphView.getPiValue(90.0)), endAngle: CGFloat(GraphView.getPiValue(90.0 + 360.0)), clockwise: true)
, 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()
@ -83,7 +83,7 @@ import UIKit
| | |
-------------
*/
func createGradientLayer(_ graphObject: CircleProgressModel) -> CALayer {
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
@ -151,18 +151,18 @@ import UIKit
}
//MARK: Animation
func rotationAnimation(_ object: CircleProgressModel) {
func rotationAnimation(_ object: WheelModel) {
MVMCoreDispatchUtility.performBlock(onMainThread:{
let rotation = CABasicAnimation(keyPath: "transform.rotation")
let animationHandler = GraphViewAnimationHandler.shared
let animationHandler = WheelAnimationHandler.shared
let startAngle = animationHandler.getAnimationStartAngle(object.duration, CACurrentMediaTime())
if startAngle == 0.0 {
animationHandler.storeAnimation(object.duration, CACurrentMediaTime())
}
var fromValue = GraphView.getPiValue(0.0 + startAngle), toValue = GraphView.getPiValue(360.0 + startAngle)
var fromValue = Wheel.getPiValue(0.0 + startAngle), toValue = Wheel.getPiValue(360.0 + startAngle)
if !object.clockwise {
fromValue = GraphView.getPiValue(360.0 - startAngle)
toValue = GraphView.getPiValue(0.0 - startAngle)
fromValue = Wheel.getPiValue(360.0 - startAngle)
toValue = Wheel.getPiValue(0.0 - startAngle)
}
rotation.fromValue = fromValue
rotation.toValue = toValue
@ -180,7 +180,7 @@ import UIKit
}
extension GraphView: CAAnimationDelegate {
extension Wheel: CAAnimationDelegate {
public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if let object = graphModel {
rotationAnimation(object)

View File

@ -1,5 +1,5 @@
//
// GraphViewAnimationHandler.swift
// WheelAnimationHandler.swift
// MobileFirstFramework
//
// Created by Ryan on 10/29/19.
@ -8,12 +8,12 @@
import UIKit
@objcMembers open class GraphViewAnimationHandler: NSObject {
@objcMembers open class WheelAnimationHandler: NSObject {
/// duration : CACurrentMediaTime()
private var animations = [Double: Double]()
static let shared = GraphViewAnimationHandler()
static let shared = WheelAnimationHandler()
open func storeAnimation(_ duration: Double, _ currentTime: CFTimeInterval) {
guard animations[duration] == nil else {

View File

@ -1,5 +1,5 @@
//
// CircleProgressModel.swift
// WheelModel.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 1/13/20.
@ -16,9 +16,9 @@ public enum GraphStyle: String, Codable {
case unlimited, safetyMode
}
public class CircleProgressModel: MoleculeModelProtocol {
public class WheelModel: MoleculeModelProtocol {
public static var identifier: String = "circleProgress"
public static var identifier: String = "wheel"
public var style: GraphStyle = .unlimited {
didSet {
updateStyle()

View File

@ -37,8 +37,7 @@ import Foundation
/// Call to register all of the CoreUI molecules.
public static func registerObjects() {
// Stacks
MoleculeObjectMapping.shared()?.register(viewClass: MoleculeStackView.self, viewModelClass: MoleculeStackModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: Stack<StackModel>.self, viewModelClass: StackModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: MoleculeStackView.self, viewModelClass: StackModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: UnOrderedList.self, viewModelClass: UnOrderedListModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: NumberedList.self, viewModelClass: NumberedListModel.self)
@ -70,6 +69,7 @@ import Foundation
MoleculeObjectMapping.shared()?.register(viewClass: RadioButton.self, viewModelClass: RadioButtonModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: RadioBoxes.self, viewModelClass: RadioBoxesModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: Checkbox.self, viewModelClass: CheckboxModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: RadioSwatches.self, viewModelClass: RadioSwatchesModel.self)
// Other Atoms
MoleculeObjectMapping.shared()?.register(viewClass: ProgressBar.self, viewModelClass: ProgressBarModel.self)
@ -78,7 +78,7 @@ import Foundation
MoleculeObjectMapping.shared()?.register(viewClass: DashLine.self, viewModelClass: DashLineModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: MFLoadImageView.self, viewModelClass: ImageViewModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: Line.self, viewModelClass: LineModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: GraphView.self, viewModelClass: CircleProgressModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: Wheel.self, viewModelClass: WheelModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: Toggle.self, viewModelClass: ToggleModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: CheckboxLabel.self, viewModelClass: CheckboxLabelModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: Arrow.self, viewModelClass: ArrowModel.self)
@ -138,11 +138,14 @@ import Foundation
MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableCheckboxAllTextAndLinks.self, viewModelClass: ListLeftVariableCheckboxAllTextAndLinksModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableRadioButtonAndPaymentMethod.self, viewModelClass: ListLeftVariableRadioButtonAndPaymentMethodModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableRadioButtonBodyText.self, viewModelClass: ListLeftVariableRadioButtonBodyTextModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableCheckboxBodyText.self, viewModelClass: ListLeftVariableCheckboxBodyTextModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListRVWheel.self, viewModelClass: ListRVWheelModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListRightVariablePayments.self, viewModelClass: ListRightVariablePaymentsModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListRightVariableTotalData.self, viewModelClass: ListRightVariableTotalDataModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListRightVariableTextLinkAllTextAndLinks.self, viewModelClass: ListRightVariableTextLinkAllTextAndLinksModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListRightVariableButtonAllTextAndLinks.self, viewModelClass: ListRightVariableButtonAllTextAndLinksModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListRightVariablePriceChangeBodyText.self, viewModelClass: ListRightVariablePriceChangeBodyTextModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListRightVariablePriceChangeAllTextAndLinks.self, viewModelClass: ListRightVariablePriceChangeAllTextAndLinksModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListOneColumnFullWidthTextAllTextAndLinks.self, viewModelClass: ListOneColumnFullWidthTextAllTextAndLinksModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListOneColumnFullWidthTextBodyText.self, viewModelClass: ListOneColumnFullWidthTextBodyTextModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListTwoColumnCompareChanges.self, viewModelClass: ListTwoColumnCompareChangesModel.self)
@ -150,7 +153,7 @@ import Foundation
MoleculeObjectMapping.shared()?.register(viewClass: ListTwoColumnPriceDescription.self, viewModelClass: ListTwoColumnPriceDescriptionModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListThreeColumnInternationalData.self, viewModelClass: ListThreeColumnInternationalDataModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListFourColumnDataUsageListItem.self, viewModelClass: ListFourColumnDataUsageListItemModel.self)
// Designed Section Dividers
MoleculeObjectMapping.shared()?.register(viewClass: ListFourColumnDataUsageDivider.self, viewModelClass: ListFourColumnDataUsageDividerModel.self)
MoleculeObjectMapping.shared()?.register(viewClass: ListThreeColumnPlanDataDivider.self, viewModelClass: ListThreeColumnPlanDataDividerModel.self)

View File

@ -0,0 +1,55 @@
//
// ListLeftVariableCheckboxBodyText.swift
// MVMCoreUI
//
// Created by Lekshmi S on 14/04/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
@objcMembers open class ListLeftVariableCheckboxBodyText: TableViewCell {
//-----------------------------------------------------
// MARK: - Outlets
//-----------------------------------------------------
public let checkbox = Checkbox(frame: .zero)
public var headlineBody = HeadlineBody()
public var stack: Stack<StackModel>
//-----------------------------------------------------
// MARK: - Initializers
//-----------------------------------------------------
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
stack = Stack<StackModel>.createStack(with: [(view: checkbox, model: StackItemModel(horizontalAlignment: .fill)),
(view: headlineBody, model: StackItemModel(horizontalAlignment: .leading))],
axis: .horizontal)
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//-----------------------------------------------------
// MARK: - View Lifecycle
//-----------------------------------------------------
override open func setupView() {
super.setupView()
addMolecule(stack)
stack.restack()
}
//----------------------------------------------------
// MARK: - Molecule
//----------------------------------------------------
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? ListLeftVariableCheckboxBodyTextModel else { return }
checkbox.set(with: model.checkbox, delegateObject, additionalData)
headlineBody.set(with: model.headlineBody, delegateObject, additionalData)
}
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
return 90
}
}

View File

@ -0,0 +1,62 @@
//
// ListLeftVariableCheckboxBodyTextModel.swift
// MVMCoreUI
//
// Created by Lekshmi S on 14/04/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
open class ListLeftVariableCheckboxBodyTextModel: ListItemModel, MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "listLVCBBdy"
public var checkbox: CheckboxModel
public var headlineBody: HeadlineBodyModel
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init(checkbox: CheckboxModel, headlineBody: HeadlineBodyModel) {
self.checkbox = checkbox
self.headlineBody = headlineBody
super.init()
}
open override func setDefaults() {
super.setDefaults()
headlineBody.style = .item
if let headline = headlineBody.headline {
headline.hero = 0
}
}
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case moleculeName
case headlineBody
case checkbox
}
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
headlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .headlineBody)
checkbox = try typeContainer.decode(CheckboxModel.self, forKey: .checkbox)
try super.init(from: decoder)
}
open override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(headlineBody, forKey: .headlineBody)
try container.encode(checkbox, forKey: .checkbox)
}
}

View File

@ -71,9 +71,6 @@ import UIKit
}
public override func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
if radioButton.isEnabled {
radioButton.tapAction()
}
radioButton.tapAction()
}
}

View File

@ -8,7 +8,7 @@
import Foundation
@objcMembers open class ListRVWheel: TableViewCell {
let wheel = GraphView(frame: .zero)
let wheel = Wheel(frame: .zero)
let leftLabel = Label.commonLabelB1(true)
let rightLabel = Label.commonLabelB2(true)
var stack: Stack<StackModel>

View File

@ -11,9 +11,9 @@ public class ListRVWheelModel: ListItemModel, MoleculeModelProtocol {
public static var identifier: String = "listRVWheel"
public var leftLabel: LabelModel
public var rightLabel: LabelModel
public var wheel : CircleProgressModel
public var wheel: WheelModel
public init(leftLabel: LabelModel, rightLabel: LabelModel, wheel: CircleProgressModel) {
public init(leftLabel: LabelModel, rightLabel: LabelModel, wheel: WheelModel) {
self.leftLabel = leftLabel
self.rightLabel = rightLabel
self.wheel = wheel
@ -37,7 +37,7 @@ public class ListRVWheelModel: ListItemModel, MoleculeModelProtocol {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
leftLabel = try typeContainer.decode(LabelModel.self, forKey: .leftLabel)
rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel)
wheel = try typeContainer.decodeIfPresent(CircleProgressModel.self, forKey: .wheel) ?? CircleProgressModel()
wheel = try typeContainer.decodeIfPresent(WheelModel.self, forKey: .wheel) ?? WheelModel()
try super.init(from: decoder)
}

View File

@ -0,0 +1,82 @@
//
// ListRightVariablePriceChangeAllTextAndLinks.swift
// MVMCoreUI
//
// Created by Kruthika KP on 13/04/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
@objcMembers open class ListRightVariablePriceChangeAllTextAndLinks: TableViewCell {
//-----------------------------------------------------
// MARK: - Outlets
//-----------------------------------------------------
public let eyebrowHeadlineBodyLink = EyebrowHeadlineBodyLink(frame: .zero)
public let arrow = Arrow(frame: .zero)
public let rightLabel = Label.commonLabelB2(true)
private let stack: Stack<StackModel>
private let arrowStackItem: StackItem
private let rightLabelStackItem: StackItem
//-----------------------------------------------------
// MARK: - Initializers
//-----------------------------------------------------
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
let stackModel = StackModel(molecules: [StackItemModel(horizontalAlignment: .leading),
StackItemModel(horizontalAlignment: .fill),
StackItemModel(spacing: 6, horizontalAlignment: .fill)],
axis: .horizontal)
arrowStackItem = StackItem(andContain: arrow)
rightLabelStackItem = StackItem(andContain: rightLabel)
let stackItems = [StackItem(andContain: eyebrowHeadlineBodyLink), arrowStackItem, rightLabelStackItem]
stack = Stack<StackModel>(with: stackModel, stackItems: stackItems)
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//-----------------------------------------------------
// MARK: - View Lifecycle
//-----------------------------------------------------
open override func alignAccessoryToHero() -> CGPoint? {
let heroCenter = super.alignAccessoryToHero()
// Aligns the center of the right side items to the headline.
if let heroCenter = heroCenter {
let convertedPoint = stack.convert(heroCenter, from: self)
arrowStackItem.containerHelper.alignCenterVerticalConstraint?.constant = convertedPoint.y - stack.bounds.midY
rightLabelStackItem.containerHelper.alignCenterVerticalConstraint?.constant = convertedPoint.y - stack.bounds.midY
}
return heroCenter
}
open override func setupView() {
super.setupView()
rightLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal)
rightLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .horizontal)
rightLabel.numberOfLines = 1
arrow.pinHeightAndWidth()
addMolecule(stack)
stack.restack()
}
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? ListRightVariablePriceChangeAllTextAndLinksModel else { return }
eyebrowHeadlineBodyLink.set(with: model.eyebrowHeadlineBodyLink, delegateObject, additionalData)
rightLabel.set(with: model.rightLabel, delegateObject, additionalData)
arrow.set(with: model.arrow, delegateObject, additionalData)
}
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
return 121
}
}

View File

@ -0,0 +1,47 @@
//
// ListRightVariablePriceChangeAllTextAndLinksModel.swift
// MVMCoreUI
//
// Created by Kruthika KP on 13/04/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public class ListRightVariablePriceChangeAllTextAndLinksModel: ListItemModel, MoleculeModelProtocol {
public static var identifier: String = "listRVArwAll"
public var eyebrowHeadlineBodyLink: EyebrowHeadlineBodyLinkModel
public var rightLabel: LabelModel
public var arrow: ArrowModel
public init(eyebrowHeadlineBodyLink: EyebrowHeadlineBodyLinkModel, rightLabel: LabelModel, arrow: ArrowModel) {
self.eyebrowHeadlineBodyLink = eyebrowHeadlineBodyLink
self.rightLabel = rightLabel
self.arrow = arrow
super.init()
}
private enum CodingKeys: String, CodingKey {
case moleculeName
case eyebrowHeadlineBodyLink
case rightLabel
case arrow
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
eyebrowHeadlineBodyLink = try typeContainer.decode(EyebrowHeadlineBodyLinkModel.self, forKey: .eyebrowHeadlineBodyLink)
rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel)
arrow = try typeContainer.decode(ArrowModel.self, forKey: .arrow)
try super.init(from: decoder)
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(eyebrowHeadlineBodyLink, forKey: .eyebrowHeadlineBodyLink)
try container.encode(rightLabel, forKey: .rightLabel)
try container.encode(arrow, forKey: .arrow)
}
}

View File

@ -0,0 +1,70 @@
//
// ListRightVariablePriceChangeBodyText.swift
// MVMCoreUI
//
// Created by Dhamodaram Nandi on 13/04/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
@objcMembers open class ListRightVariablePriceChangeBodyText: TableViewCell {
//-----------------------------------------------------
// MARK: - Outlets
//-----------------------------------------------------
private let stack: Stack<StackModel>
public let headlineBody = HeadlineBody(frame: .zero)
public let arrow = Arrow(frame: .zero)
public let rightLabel = Label.commonLabelB2(true)
let arrowAndRightLabelStack: Stack<StackModel>
// MARK: - Initializers
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
arrowAndRightLabelStack = Stack<StackModel>.createStack(with: [(view: arrow, model: StackItemModel(horizontalAlignment: .fill)),
(view: rightLabel, model: StackItemModel(horizontalAlignment: .fill))],
axis: .horizontal, spacing: 6)
stack = Stack<StackModel>.createStack(with: [(view: headlineBody, model: StackItemModel(horizontalAlignment: .leading)),
(view: arrowAndRightLabelStack, model: StackItemModel(horizontalAlignment: .fill, verticalAlignment: .leading))],
axis: .horizontal)
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//-----------------------------------------------------
// MARK: - View Lifecycle
//-----------------------------------------------------
open override func setupView() {
super.setupView()
headlineBody.styleListItem()
rightLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 900), for: .horizontal)
rightLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 900), for: .horizontal)
rightLabel.numberOfLines = 1
arrow.pinHeightAndWidth()
addMolecule(stack)
stack.restack()
arrowAndRightLabelStack.restack()
}
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? ListRightVariablePriceChangeBodyTextModel else { return }
headlineBody.set(with: model.headlineBody, delegateObject, additionalData)
rightLabel.set(with: model.rightLabel, delegateObject, additionalData)
arrow.set(with: model.arrow, delegateObject, additionalData)
}
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
return 80
}
open override func reset() {
super.reset()
headlineBody.styleListItem()
}
}

View File

@ -0,0 +1,54 @@
//
// ListRightVariablePriceChangeBodyTextModel.swift
// MVMCoreUI
//
// Created by Dhamodaram Nandi on 13/04/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public class ListRightVariablePriceChangeBodyTextModel: ListItemModel, MoleculeModelProtocol {
public static var identifier: String = "listRVArwBdy"
public var headlineBody: HeadlineBodyModel
public var rightLabel: LabelModel
public var arrow: ArrowModel
public init(headlineBody: HeadlineBodyModel,rightLabel: LabelModel,arrow: ArrowModel) {
self.headlineBody = headlineBody
self.rightLabel = rightLabel
self.arrow = arrow
super.init()
}
/// Defaults to set
public override func setDefaults() {
super.setDefaults()
if let headline = headlineBody.headline {
headline.hero = 0
}
}
private enum CodingKeys: String, CodingKey {
case moleculeName
case headlineBody
case rightLabel
case arrow
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
headlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .headlineBody)
rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel)
arrow = try typeContainer.decode(ArrowModel.self, forKey: .arrow)
try super.init(from: decoder)
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(headlineBody, forKey: .headlineBody)
try container.encode(rightLabel, forKey: .rightLabel)
try container.encode(arrow, forKey: .arrow)
}
}

View File

@ -86,7 +86,7 @@ import Foundation
for item in model.sections {
stackItems.append(MoleculeStackItemModel(with: item))
}
let stack = MoleculeStackModel(molecules: stackItems)
let stack = StackModel(molecules: stackItems)
stack.verticalAlignment = .fill
colorLablesStack.set(with: stack, delegateObject, additionalData)
}

View File

@ -8,7 +8,7 @@
import Foundation
public protocol StackItemModelProtocol: MoleculeModelProtocol {
public protocol StackItemModelProtocol {
var spacing: CGFloat? { get set }
var percent: Int? { get set }
var gone: Bool { get set }

View File

@ -164,10 +164,12 @@ import UIKit
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? CornerLabelsModel else { return }
if middleView != nil {
(middleView as? MoleculeViewProtocol)?.set(with: model, delegateObject, additionalData)
} else if let moleculeModel = model.molecule, let molecule = MoleculeObjectMapping.shared()?.createMolecule(moleculeModel, delegateObject: delegateObject, additionalData: additionalData) {
addMiddleView(molecule)
if let moleculeModel = model.molecule {
if middleView != nil {
(middleView as? MoleculeViewProtocol)?.set(with: moleculeModel, delegateObject, additionalData)
} else if let molecule = MoleculeObjectMapping.shared()?.createMolecule(moleculeModel, delegateObject: delegateObject, additionalData: additionalData) {
addMiddleView(molecule)
}
}
topLeftLabel.setOptional(with: model.topLeftLabel, delegateObject, additionalData)

View File

@ -8,7 +8,7 @@
import Foundation
@objcMembers public class NumberedListModel: MoleculeStackModel {
@objcMembers public class NumberedListModel: StackModel {
public override class var identifier: String {
return "numberedList"
}
@ -28,8 +28,7 @@ import Foundation
for (index, molecule) in list.enumerated() {
models.append(MoleculeStackItemModel(with: StringAndMoleculeModel(string: "\(index+1).", molecule: molecule)))
}
super.init(molecules: models)
spacing = 0
super.init(molecules: models, spacing: 0)
}
public override func encode(to encoder: Encoder) throws {
@ -39,7 +38,7 @@ import Foundation
var models: [MoleculeModelProtocol] = []
for molecule in molecules {
models.append(molecule.molecule)
models.append(((molecule as! MoleculeStackItemModel).molecule as! StringAndMoleculeModel).molecule)
}
try container.encodeModels(models, forKey: .list)
}

View File

@ -11,8 +11,9 @@ import UIKit
// This class is only temporarily necessary. Eventually we will have initWithModel instad of just init for moleculeviews, which will remove this need.
open class StringAndMoleculeStack: MoleculeStackView {
override open func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
guard let model = stackModel else { return }
for stackItemModel in model.molecules {
guard let model = model as? StackModelProtocol,
let molcules = model.molecules as? [MoleculeStackItemModel] else { return }
for stackItemModel in molcules {
guard let stringAndMoleculeModel = stackItemModel.molecule as? StringAndMoleculeModel,
let molecule = MoleculeObjectMapping.shared()?.createMolecule(stringAndMoleculeModel.molecule, delegateObject: delegateObject
, additionalData: additionalData) else {

View File

@ -10,7 +10,6 @@ import Foundation
open class StringAndMoleculeView: View {
var label = Label.commonLabelB2(true)
var string: String
var molecule: MoleculeViewProtocol
var leftWidthConstraint: NSLayoutConstraint?
@ -28,7 +27,7 @@ open class StringAndMoleculeView: View {
// MARK: - Inits
public init(string: String, molecule: MoleculeViewProtocol) {
self.string = string
self.label.text = string
self.molecule = molecule
super.init(frame: .zero)
}

View File

@ -8,7 +8,7 @@
import Foundation
@objcMembers public class UnOrderedListModel: MoleculeStackModel {
@objcMembers public class UnOrderedListModel: StackModel {
public override class var identifier: String {
return "unOrderedList"
}
@ -33,8 +33,7 @@ import Foundation
for molecule in list {
models.append(MoleculeStackItemModel(with: StringAndMoleculeModel(string: bulletChar, molecule: molecule)))
}
super.init(molecules: models)
spacing = 0
super.init(molecules: models, spacing: 0)
}
public override func encode(to encoder: Encoder) throws {
@ -45,7 +44,7 @@ import Foundation
var models: [MoleculeModelProtocol] = []
for molecule in molecules {
models.append(molecule.molecule)
models.append(((molecule as! MoleculeStackItemModel).molecule as! StringAndMoleculeModel).molecule)
}
try container.encodeModels(models, forKey: .list)
}

View File

@ -1,54 +0,0 @@
//
// MoleculeStack.swift
// MVMCoreUI
//
// Created by Suresh, Kamlesh on 10/3/19.
// Copyright © 2019 Suresh, Kamlesh. All rights reserved.
//
// A stack that has a list molecule stack items.
import Foundation
@objcMembers public class MoleculeStackModel: ContainerModel, MoleculeModelProtocol, StackModelProtocol {
public class var identifier: String {
return "stack"
}
public var backgroundColor: Color?
public var molecules: [MoleculeStackItemModel]
public var axis: NSLayoutConstraint.Axis = .vertical
public var spacing: CGFloat = 16.0
public var useStackSpacingBeforeFirstItem = false
public init(molecules: [MoleculeStackItemModel]) {
self.molecules = molecules
super.init()
}
private enum CodingKeys: String, CodingKey {
case moleculeName
case molecules
case axis
case spacing
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
molecules = try typeContainer.decode([MoleculeStackItemModel].self, forKey: .molecules)
if let axisString = try typeContainer.decodeIfPresent(String.self, forKey: .axis), let optionalAxis = NSLayoutConstraint.Axis(rawValue: axisString) {
axis = optionalAxis
}
if let spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing) {
self.spacing = spacing
}
try super.init(from: decoder)
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(molecules, forKey: .molecules)
try container.encodeIfPresent(axis.rawValueString, forKey: .axis)
try container.encodeIfPresent(spacing, forKey: .spacing)
}
}

View File

@ -5,13 +5,12 @@
// Created by Scott Pfeil on 2/11/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
// This is a dynamic stack view that creates molecules if needed on set.
import UIKit
open class MoleculeStackView: Stack<MoleculeStackModel> {
open override var stackModel: MoleculeStackModel? {
get { return model as? MoleculeStackModel }
}
open class MoleculeStackView: Stack<StackModel> {
var previousModel: MoleculeModelProtocol?
/// Convenience function, adds a molecule to a MoleculeStackItem to the MoleculeStack
func setup(with views: [View], lastItem: Bool) {
@ -26,14 +25,16 @@ open class MoleculeStackView: Stack<MoleculeStackModel> {
if let stackModel = stackModel {
stackModel.molecules = models
} else {
model = MoleculeStackModel(molecules: models)
model = StackModel(molecules: models)
}
restack()
}
// MARK: - Adding to stack
/// Creates all of the stackItems for the stackItemModels
override open func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
/// Can be subclassed to create views when we get stack item models and have no views yet
open func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
guard let stackItemModels = stackModel?.molecules else { return }
for model in stackItemModels {
if let stackItem = MoleculeObjectMapping.shared()?.createMolecule(model, delegateObject: delegateObject, additionalData: additionalData) as? MoleculeStackItem {
@ -41,4 +42,20 @@ open class MoleculeStackView: Stack<MoleculeStackModel> {
}
}
}
open override func setStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
// If the items in the stack are different, clear them, create new ones.
if (previousModel == nil) || Self.nameForReuse(with: previousModel!, delegateObject) != Self.nameForReuse(with: model, delegateObject) {
removeAllItemViews()
stackItems = []
createStackItemsFromModel(model, delegateObject, additionalData)
} else {
super.setStackItemsFromModel(model, delegateObject, additionalData)
}
}
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
previousModel = self.model
super.set(with: model, delegateObject, additionalData)
}
}

View File

@ -147,18 +147,8 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
}
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
let previousModel = self.model
super.set(with: model, delegateObject, additionalData)
removeAllItemViews()
// If the items in the stack are different, clear them, create new ones.
if (previousModel == nil) || Self.nameForReuse(with: previousModel!, delegateObject) != Self.nameForReuse(with: model, delegateObject) {
stackItems = []
createStackItemsFromModel(model, delegateObject, additionalData)
} else {
setStackItemsFromModel(model, delegateObject, additionalData)
}
setStackItemsFromModel(model, delegateObject, additionalData)
restack()
}
@ -216,9 +206,6 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
// MARK: - Subclassables
//--------------------------------------------------
/// Can be subclassed to create views when we get stack item models and have no views yet
open func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { }
/// Can be subclassed to set stack items with model when we already have views
open func setStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
guard let models = stackModel?.molecules else { return }
@ -243,10 +230,10 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
}
/// Sets the stack with StackItems containing the passed in views and sets the StackModel with models.
open func set(with viewModels:[(view: UIView, model: T.AnyStackItemModel)]) {
open func set(with viewModels:[(view: UIView, model: StackItemModel)]) {
guard var stackModel = self.stackModel else { return }
var stackItems: [StackItem] = []
var models: [T.AnyStackItemModel] = []
var models: [StackItemModel] = []
for item in viewModels {
stackItems.append(StackItem(andContain: item.view))
models.append(item.model)
@ -307,7 +294,7 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
if let percent = model.percent {
let multiplier = CGFloat(percent) / 100.0
let constant = multiplier * totalSpacing
view.heightAnchor.constraint(equalTo: contentView.heightAnchor, multiplier: multiplier, constant: -constant).isActive = true
view.heightAnchor.constraint(equalTo: heightAnchor, multiplier: multiplier, constant: -constant).isActive = true
}
if lastItem {
pinView(contentView, toView: view, attribute: .bottom, relation: .equal, priority: .required, constant: 0)
@ -326,7 +313,7 @@ open class Stack<T>: Container where T: (StackModelProtocol & MoleculeModelProto
if let percent = model.percent {
let multiplier = CGFloat(percent) / 100.0
let constant = multiplier * totalSpacing
view.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: multiplier, constant: -constant).isActive = true
view.widthAnchor.constraint(equalTo: widthAnchor, multiplier: multiplier, constant: -constant).isActive = true
}
if lastItem {
pinView(contentView, toView: view, attribute: .right, relation: .equal, priority: .required, constant: 0)

View File

@ -8,17 +8,19 @@
import Foundation
@objcMembers public class StackModel: StackModelProtocol, MoleculeModelProtocol {
@objcMembers public class StackModel: ContainerModel, StackModelProtocol, MoleculeModelProtocol {
static let defaultSpacing: CGFloat = 16.0
public static var identifier: String = "simpleStack"
public class var identifier: String {
return "stack"
}
public var backgroundColor: Color?
public var molecules: [StackItemModel]
public var molecules: [StackItemModelProtocol & MoleculeModelProtocol]
public var axis: NSLayoutConstraint.Axis = .vertical
public var spacing: CGFloat = StackModel.defaultSpacing
public var useStackSpacingBeforeFirstItem = false
public init(molecules: [StackItemModel], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) {
public init(molecules: [StackItemModelProtocol & MoleculeModelProtocol], axis: NSLayoutConstraint.Axis? = nil, spacing: CGFloat? = nil) {
self.molecules = molecules
if let axis = axis {
self.axis = axis
@ -26,6 +28,7 @@ import Foundation
if let spacing = spacing {
self.spacing = spacing
}
super.init()
}
private enum CodingKeys: String, CodingKey {
@ -38,19 +41,20 @@ import Foundation
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
molecules = try typeContainer.decode([StackItemModel].self, forKey: .molecules)
molecules = try typeContainer.decodeModels(codingKey: .molecules)
if let axisString = try typeContainer.decodeIfPresent(String.self, forKey: .axis), let optionalAxis = NSLayoutConstraint.Axis(rawValue: axisString) {
axis = optionalAxis
}
if let spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing) {
self.spacing = spacing
}
try super.init(from: decoder)
}
public func encode(to encoder: Encoder) throws {
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(molecules, forKey: .molecules)
try container.encodeModels(molecules, forKey: .molecules)
try container.encodeIfPresent(axis.rawValueString, forKey: .axis)
try container.encodeIfPresent(spacing, forKey: .spacing)
try container.encode(moleculeName, forKey: .moleculeName)

View File

@ -9,9 +9,7 @@
import Foundation
public protocol StackModelProtocol {
associatedtype AnyStackItemModel: StackItemModelProtocol
var molecules: [AnyStackItemModel] { get set }
var molecules: [StackItemModelProtocol & MoleculeModelProtocol] { get set }
var axis: NSLayoutConstraint.Axis { get set }
var spacing: CGFloat { get set }
var useStackSpacingBeforeFirstItem: Bool { get set }

View File

@ -15,10 +15,10 @@ import Foundation
}
public var header: MoleculeModelProtocol?
public var moleculeStack: MoleculeStackModel
public var moleculeStack: StackModel
public var footer: MoleculeModelProtocol?
public init(pageType: String, moleculeStack: MoleculeStackModel) {
public init(pageType: String, moleculeStack: StackModel) {
self.moleculeStack = moleculeStack
super.init(pageType: pageType)
}
@ -31,7 +31,7 @@ import Foundation
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
moleculeStack = try typeContainer.decode(MoleculeStackModel.self, forKey: .stack)
moleculeStack = try typeContainer.decode(StackModel.self, forKey: .stack)
header = try typeContainer.decodeModelIfPresent(codingKey: .header)
footer = try typeContainer.decodeModelIfPresent(codingKey: .footer)
try super.init(from: decoder)

View File

@ -26,7 +26,7 @@ import UIKit
/// For subclasses that want to use a custom accessory view.
open var customAccessoryView = false
private var heroAccessoryCenter: CGPoint?
public var heroAccessoryCenter: CGPoint?
private var initialSetupPerformed = false
@ -97,7 +97,7 @@ import UIKit
// Ensures accessory view aligns to the center y derived from the
if let _ = heroAccessoryCenter {
alignAccessoryToHero()
_ = alignAccessoryToHero()
}
}
@ -215,14 +215,16 @@ import UIKit
}
/// NOTE: Should only be called when displayed or about to be displayed.
public func alignAccessoryToHero() {
public func alignAccessoryToHero() -> CGPoint? {
// Layout call required to force draw in memory to get dimensions of subviews.
layoutIfNeeded()
guard let heroLabel = findHeroLabel(views: contentView.subviews), let hero = heroLabel.hero else { return }
guard let heroLabel = findHeroLabel(views: contentView.subviews), let hero = heroLabel.hero else { return nil }
let rect = Label.boundingRect(forCharacterRange: NSRange(location: hero, length: 1), in: heroLabel)
accessoryView?.center.y = convert(UIView(frame: rect).center, from: heroLabel).y
let y = convert(UIView(frame: rect).center, from: heroLabel).y
accessoryView?.center.y = y
heroAccessoryCenter = accessoryView?.center
return heroAccessoryCenter ?? CGPoint(x: 0, y: y)
}
/// Traverses the view hierarchy for a 🦸 heroic Label.
@ -269,7 +271,7 @@ import UIKit
}
public func willDisplay() {
alignAccessoryToHero()
_ = alignAccessoryToHero()
}
// MARK: - Separator

View File

@ -236,10 +236,13 @@ import UIKit
}
// MARK: - View lifecycle
/// Called only once in viewDidLoad
open func initialLoad() {
observeForResponseJSONUpdates()
}
/// Called on screen size update.
open func updateViews() {
_ = formValidator?.validate()
}
@ -265,10 +268,7 @@ import UIKit
initialLoad()
}
// Handle data for first load. Dispatched to allow subclasses to finish their view did load implementations.
DispatchQueue.main.async {
self.handleNewDataAndUpdateUI()
}
handleNewDataAndUpdateUI()
}
open override func viewDidLayoutSubviews() {
@ -292,8 +292,10 @@ import UIKit
open override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Update the navigation bar ui when view is appearing
setNavigationController()
// Update the navigation bar ui when view is appearing. Can remove check in the future, see viewControllerReady
if manager == nil {
setNavigationController()
}
}
open override func viewDidAppear(_ animated: Bool) {
@ -326,6 +328,10 @@ import UIKit
// MARK: - MVMCoreViewManagerViewControllerProtocol
open func viewControllerReady(inManager manager: UIViewController & MVMCoreViewManagerProtocol) {
// TODO: This check and set aren't technically needed anymore. The one in viewwillappear should be enough. However, there is a timing issue with the manager where the screen lays out before the menu shows, so the screen grows off the screen. Can fix in the future.
if let _ = self.view {
setNavigationController()
}
// Janky way to track current page.
MVMCoreUISession.sharedGlobal()?.currentPageType = pageType
MVMCoreUILoggingHandler.shared()?.defaultLogPageState(forController: self)