diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 8efde844..2cfff3cf 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -12,17 +12,33 @@ 0105618E224BBE7700E1557D /* FormValidator+TextFields.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */; }; 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */; }; 0116A4E5228B19640094F3ED /* RadioButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0116A4E4228B19640094F3ED /* RadioButtonModel.swift */; }; - 012A88EE239858E300FE3DA1 /* ContainerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88ED239858E300FE3DA1 /* ContainerModel.swift */; }; + 011B58F023A2AA980085F53C /* ListItemModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011B58EF23A2AA980085F53C /* ListItemModelProtocol.swift */; }; + 011B58F223A2AE2C0085F53C /* DropDownListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011B58F123A2AE2C0085F53C /* DropDownListItemModel.swift */; }; + 011B58F423A2CCC80085F53C /* DropDownModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011B58F323A2CCC80085F53C /* DropDownModel.swift */; }; + 012A889C23889E8400FE3DA1 /* TemplateModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A889B23889E8400FE3DA1 /* TemplateModelProtocol.swift */; }; + 012A88AD238C418100FE3DA1 /* TemplateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */; }; + 012A88B1238C880100FE3DA1 /* PagingMoleculeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88B0238C880100FE3DA1 /* PagingMoleculeProtocol.swift */; }; + 012A88C2238D7BCA00FE3DA1 /* CarouselItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88C1238D7BCA00FE3DA1 /* CarouselItemModel.swift */; }; + 012A88C4238D86E600FE3DA1 /* CollectionCellMoleculeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88C3238D86E600FE3DA1 /* CollectionCellMoleculeProtocol.swift */; }; + 012A88C6238DA34000FE3DA1 /* ModuleMoleculeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88C5238DA34000FE3DA1 /* ModuleMoleculeModel.swift */; }; + 012A88C8238DB02000FE3DA1 /* ModelMoleculeDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88C7238DB02000FE3DA1 /* ModelMoleculeDelegateProtocol.swift */; }; + 012A88DB238ED45900FE3DA1 /* CarouselModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88AE238C626E00FE3DA1 /* CarouselModel.swift */; }; + 012A88EC238F084D00FE3DA1 /* FooterModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88EB238F084D00FE3DA1 /* FooterModel.swift */; }; + 012A88F123985E0100FE3DA1 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88F023985E0100FE3DA1 /* Color.swift */; }; 012CA99A2384A687003F810F /* MFTextField+ModelExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA9992384A687003F810F /* MFTextField+ModelExtension.swift */; }; - 012CA99C23859FDC003F810F /* ViewConstrainingView+ModelExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA99B23859FDC003F810F /* ViewConstrainingView+ModelExtension.swift */; }; 012CA99E2385A2D3003F810F /* MFView+ModelExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA99D2385A2D3003F810F /* MFView+ModelExtension.swift */; }; - 012CA9BE2385C692003F810F /* ContainerModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA9BD2385C692003F810F /* ContainerModelProtocol.swift */; }; + 014AA72423C501E2006F3E93 /* MoleculeContainerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014AA72123C501E2006F3E93 /* MoleculeContainerModel.swift */; }; + 014AA72523C501E2006F3E93 /* ContainerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014AA72223C501E2006F3E93 /* ContainerModel.swift */; }; + 014AA72623C501E2006F3E93 /* ContainerModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014AA72323C501E2006F3E93 /* ContainerModelProtocol.swift */; }; + 014AA72D23C5059B006F3E93 /* StackPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014AA72823C5059B006F3E93 /* StackPageTemplateModel.swift */; }; + 014AA72E23C5059B006F3E93 /* StackCenteredPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014AA72923C5059B006F3E93 /* StackCenteredPageTemplateModel.swift */; }; + 014AA72F23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014AA72A23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift */; }; + 014AA73123C5059B006F3E93 /* ListPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014AA72C23C5059B006F3E93 /* ListPageTemplateModel.swift */; }; 01509D8F2327EC6F00EF99AA /* MoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */; }; 01509D912327ECE600EF99AA /* CornerLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01509D902327ECE600EF99AA /* CornerLabels.swift */; }; 01509D932327ECFB00EF99AA /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01509D922327ECFB00EF99AA /* ProgressBar.swift */; }; 01509D952327ED1900EF99AA /* HeadlineBodyTextButtonSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01509D942327ED1900EF99AA /* HeadlineBodyTextButtonSwitch.swift */; }; 017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */; }; - 017BEB3A2360EEB40024EF95 /* PageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017BEB392360EEB40024EF95 /* PageModel.swift */; }; 017BEB3C2361EA1D0024EF95 /* MFViewController+Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017BEB3B2361EA1D0024EF95 /* MFViewController+Model.swift */; }; 017BEB4023620A230024EF95 /* TextFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017BEB3F23620A230024EF95 /* TextFieldModel.swift */; }; 017BEB4223620AD20024EF95 /* FormModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017BEB4123620AD20024EF95 /* FormModelProtocol.swift */; }; @@ -41,6 +57,7 @@ 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 */; }; 0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */; }; 0A1B4A96233BB18F005B3FB4 /* CheckboxWithLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */; }; 0A209CD323A7E2810068F8B0 /* UIStackViewAlignment+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A209CD223A7E2810068F8B0 /* UIStackViewAlignment+Extension.swift */; }; @@ -49,7 +66,7 @@ 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; }; 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; }; 0AA33B34239813C50067DD0F /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B33239813C50067DD0F /* UIColor+Extension.swift */; }; - 0AA33B36239813EE0067DD0F /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B35239813EE0067DD0F /* Color.swift */; }; + 9402C35023A2CEA3004B974C /* LeftRightLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9402C34F23A2CEA3004B974C /* LeftRightLabelModel.swift */; }; 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F3236B77BB006A1E82 /* GraphView.swift */; }; 943784F6236B77BB006A1E82 /* GraphViewAnimationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */; }; 9445890C2385BCE300DE9FD4 /* ProgressBarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9445890B2385BCE300DE9FD4 /* ProgressBarModel.swift */; }; @@ -90,7 +107,7 @@ D260D7B122D65BDD007E7233 /* MVMCoreUIPageControl.h in Headers */ = {isa = PBXBuildFile; fileRef = D260D7AF22D65BDD007E7233 /* MVMCoreUIPageControl.h */; settings = {ATTRIBUTES = (Public, ); }; }; D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */ = {isa = PBXBuildFile; fileRef = D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */; }; D260D7B622D68514007E7233 /* MVMCoreUIPagingProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368A23609801006832FA /* MoleculeStackItemModel.swift */; }; + D268C70C2386DFFD007F2C1C /* StackItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368A23609801006832FA /* StackItemModel.swift */; }; D268C70E238C22D7007F2C1C /* DropDownFilterTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */; }; D268C712238D6699007F2C1C /* DropDown.swift in Sources */ = {isa = PBXBuildFile; fileRef = D268C711238D6699007F2C1C /* DropDown.swift */; }; D274CA332236A78900B01B62 /* StandardFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D274CA322236A78900B01B62 /* StandardFooterView.swift */; }; @@ -100,8 +117,16 @@ D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AAB3223FDDAE00C46919 /* MFLoadImageView.swift */; }; D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AAB9224131D100C46919 /* MFTransparentGIFView.swift */; }; D282AACB2243C61700C46919 /* ButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AACA2243C61700C46919 /* ButtonView.swift */; }; - D296E13C229598BF0051EBE7 /* MoleculeListCellProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D296E13B2295969C0051EBE7 /* MoleculeListCellProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D296E1412295EBBA0051EBE7 /* MoleculeDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D296E1402295EBBA0051EBE7 /* MoleculeDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D28A837723C79FC600DFE4FC /* MFCustomButton+ActionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A837623C79FC600DFE4FC /* MFCustomButton+ActionModel.swift */; }; + D28A837923C7D5BC00DFE4FC /* PageModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A837823C7D5BC00DFE4FC /* PageModelProtocol.swift */; }; + D28A837B23C928DA00DFE4FC /* MoleculeListCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A837A23C928DA00DFE4FC /* MoleculeListCellProtocol.swift */; }; + 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 */; }; + D28A838523CCCA8900DFE4FC /* ScrollerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A838423CCCA8900DFE4FC /* ScrollerModel.swift */; }; + D28A838723CCCF6500DFE4FC /* MFTextButton+ModelExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A838623CCCF6500DFE4FC /* MFTextButton+ModelExtension.swift */; }; + D28A838923CCCFCB00DFE4FC /* LinkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A838823CCCFCB00DFE4FC /* LinkModel.swift */; }; D296E14722A5984C0051EBE7 /* MVMCoreUIViewConstrainingProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */; }; D29770C921F7C4AE00B2F0D0 /* TopLabelsView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -235,7 +260,6 @@ D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */; }; D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */; }; D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */; }; - D2DEDCB423C3D22700C44CC4 /* MoleculeContainerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DEDCB323C3D22700C44CC4 /* MoleculeContainerModel.swift */; }; D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */; }; D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */; }; D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */; }; @@ -255,17 +279,33 @@ 0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+TextFields.swift"; sourceTree = ""; }; 0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+FormParams.swift"; sourceTree = ""; }; 0116A4E4228B19640094F3ED /* RadioButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonModel.swift; sourceTree = ""; }; - 012A88ED239858E300FE3DA1 /* ContainerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerModel.swift; sourceTree = ""; }; + 011B58EF23A2AA980085F53C /* ListItemModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemModelProtocol.swift; sourceTree = ""; }; + 011B58F123A2AE2C0085F53C /* DropDownListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropDownListItemModel.swift; sourceTree = ""; }; + 011B58F323A2CCC80085F53C /* DropDownModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropDownModel.swift; sourceTree = ""; }; + 012A889B23889E8400FE3DA1 /* TemplateModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateModelProtocol.swift; sourceTree = ""; }; + 012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateProtocol.swift; sourceTree = ""; }; + 012A88AE238C626E00FE3DA1 /* CarouselModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselModel.swift; sourceTree = ""; }; + 012A88B0238C880100FE3DA1 /* PagingMoleculeProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagingMoleculeProtocol.swift; sourceTree = ""; }; + 012A88C1238D7BCA00FE3DA1 /* CarouselItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselItemModel.swift; sourceTree = ""; }; + 012A88C3238D86E600FE3DA1 /* CollectionCellMoleculeProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionCellMoleculeProtocol.swift; sourceTree = ""; }; + 012A88C5238DA34000FE3DA1 /* ModuleMoleculeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModuleMoleculeModel.swift; sourceTree = ""; }; + 012A88C7238DB02000FE3DA1 /* ModelMoleculeDelegateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelMoleculeDelegateProtocol.swift; sourceTree = ""; }; + 012A88EB238F084D00FE3DA1 /* FooterModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FooterModel.swift; sourceTree = ""; }; + 012A88F023985E0100FE3DA1 /* Color.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; 012CA9992384A687003F810F /* MFTextField+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFTextField+ModelExtension.swift"; sourceTree = ""; }; - 012CA99B23859FDC003F810F /* ViewConstrainingView+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ViewConstrainingView+ModelExtension.swift"; sourceTree = ""; }; 012CA99D2385A2D3003F810F /* MFView+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFView+ModelExtension.swift"; sourceTree = ""; }; - 012CA9BD2385C692003F810F /* ContainerModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerModelProtocol.swift; sourceTree = ""; }; + 014AA72123C501E2006F3E93 /* MoleculeContainerModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeContainerModel.swift; sourceTree = ""; }; + 014AA72223C501E2006F3E93 /* ContainerModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContainerModel.swift; sourceTree = ""; }; + 014AA72323C501E2006F3E93 /* ContainerModelProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContainerModelProtocol.swift; sourceTree = ""; }; + 014AA72823C5059B006F3E93 /* StackPageTemplateModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackPageTemplateModel.swift; sourceTree = ""; }; + 014AA72923C5059B006F3E93 /* StackCenteredPageTemplateModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackCenteredPageTemplateModel.swift; sourceTree = ""; }; + 014AA72A23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThreeLayerPageTemplateModel.swift; sourceTree = ""; }; + 014AA72C23C5059B006F3E93 /* ListPageTemplateModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListPageTemplateModel.swift; sourceTree = ""; }; 01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeTableViewCell.swift; sourceTree = ""; }; 01509D902327ECE600EF99AA /* CornerLabels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; sourceTree = ""; }; 01509D922327ECFB00EF99AA /* ProgressBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; 01509D942327ED1900EF99AA /* HeadlineBodyTextButtonSwitch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeadlineBodyTextButtonSwitch.swift; sourceTree = ""; }; 017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadioButtonLabel.swift; sourceTree = ""; }; - 017BEB392360EEB40024EF95 /* PageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageModel.swift; sourceTree = ""; }; 017BEB3B2361EA1D0024EF95 /* MFViewController+Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFViewController+Model.swift"; sourceTree = ""; }; 017BEB3F23620A230024EF95 /* TextFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldModel.swift; sourceTree = ""; }; 017BEB4123620AD20024EF95 /* FormModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormModelProtocol.swift; sourceTree = ""; }; @@ -280,10 +320,11 @@ 01EB3683236097C0006832FA /* MoleculeProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeProtocol.swift; sourceTree = ""; }; 01EB368823609801006832FA /* LabelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LabelModel.swift; sourceTree = ""; }; 01EB368923609801006832FA /* ListItemModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListItemModel.swift; sourceTree = ""; }; - 01EB368A23609801006832FA /* MoleculeStackItemModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeStackItemModel.swift; sourceTree = ""; }; + 01EB368A23609801006832FA /* StackItemModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackItemModel.swift; sourceTree = ""; }; 01EB368B23609801006832FA /* MoleculeStackModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeStackModel.swift; sourceTree = ""; }; 01EB368C23609801006832FA /* HeaderModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderModel.swift; sourceTree = ""; }; 01EB368D23609801006832FA /* HeadlineBodyModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeadlineBodyModel.swift; sourceTree = ""; }; + 01F2A03123A4498200D954D8 /* CaretLinkModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaretLinkModel.swift; sourceTree = ""; }; 0A12149F22C11A17007C7030 /* ActionDetailWithImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionDetailWithImage.swift; sourceTree = ""; }; 0A209CD223A7E2810068F8B0 /* UIStackViewAlignment+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIStackViewAlignment+Extension.swift"; sourceTree = ""; }; 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.swift"; sourceTree = ""; }; @@ -292,7 +333,7 @@ 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = ""; }; 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxWithLabelView.swift; sourceTree = ""; }; 0AA33B33239813C50067DD0F /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = ""; }; - 0AA33B35239813EE0067DD0F /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; + 9402C34F23A2CEA3004B974C /* LeftRightLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeftRightLabelModel.swift; sourceTree = ""; }; 943784F3236B77BB006A1E82 /* GraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphView.swift; sourceTree = ""; }; 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphViewAnimationHandler.swift; sourceTree = ""; }; 9445890B2385BCE300DE9FD4 /* ProgressBarModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarModel.swift; sourceTree = ""; }; @@ -342,8 +383,16 @@ D282AAB3223FDDAE00C46919 /* MFLoadImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MFLoadImageView.swift; sourceTree = ""; }; D282AAB9224131D100C46919 /* MFTransparentGIFView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MFTransparentGIFView.swift; sourceTree = ""; }; D282AACA2243C61700C46919 /* ButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonView.swift; sourceTree = ""; }; - D296E13B2295969C0051EBE7 /* MoleculeListCellProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MoleculeListCellProtocol.h; sourceTree = ""; }; - D296E1402295EBBA0051EBE7 /* MoleculeDelegateProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MoleculeDelegateProtocol.h; sourceTree = ""; }; + D28A837623C79FC600DFE4FC /* MFCustomButton+ActionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFCustomButton+ActionModel.swift"; sourceTree = ""; }; + D28A837823C7D5BC00DFE4FC /* PageModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageModelProtocol.swift; sourceTree = ""; }; + D28A837A23C928DA00DFE4FC /* MoleculeListCellProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeListCellProtocol.swift; sourceTree = ""; }; + D28A837C23CCA86A00DFE4FC /* TabsListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsListItemModel.swift; sourceTree = ""; }; + D28A837E23CCA96400DFE4FC /* TabsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsModel.swift; sourceTree = ""; }; + D28A838023CCB0D800DFE4FC /* AccordionListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccordionListItemModel.swift; sourceTree = ""; }; + D28A838223CCBD3F00DFE4FC /* CircleProgressModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleProgressModel.swift; sourceTree = ""; }; + D28A838423CCCA8900DFE4FC /* ScrollerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollerModel.swift; sourceTree = ""; }; + D28A838623CCCF6500DFE4FC /* MFTextButton+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFTextButton+ModelExtension.swift"; sourceTree = ""; }; + D28A838823CCCFCB00DFE4FC /* LinkModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkModel.swift; sourceTree = ""; }; D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewConstrainingProtocol.h; sourceTree = ""; }; D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TopLabelsView.m; sourceTree = ""; }; D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TopLabelsView.h; sourceTree = ""; }; @@ -481,7 +530,6 @@ D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = ""; }; D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scroller.swift; sourceTree = ""; }; D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTemplate.swift; sourceTree = ""; }; - D2DEDCB323C3D22700C44CC4 /* MoleculeContainerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeContainerModel.swift; sourceTree = ""; }; D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIDelegateObject.swift; sourceTree = ""; }; D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTableViewController.swift; sourceTree = ""; }; D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeListTemplate.swift; sourceTree = ""; }; @@ -509,13 +557,57 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 011B58EE23A2AA850085F53C /* ModelProtocols */ = { + isa = PBXGroup; + children = ( + 017BEB4123620AD20024EF95 /* FormModelProtocol.swift */, + 012A88C3238D86E600FE3DA1 /* CollectionCellMoleculeProtocol.swift */, + 012A88B0238C880100FE3DA1 /* PagingMoleculeProtocol.swift */, + 01EB3683236097C0006832FA /* MoleculeProtocol.swift */, + 012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */, + 012A889B23889E8400FE3DA1 /* TemplateModelProtocol.swift */, + D28A837823C7D5BC00DFE4FC /* PageModelProtocol.swift */, + 011B58EF23A2AA980085F53C /* ListItemModelProtocol.swift */, + ); + path = ModelProtocols; + sourceTree = ""; + }; + 012A88EF23985E0100FE3DA1 /* Primitive Models */ = { + isa = PBXGroup; + children = ( + 012A88F023985E0100FE3DA1 /* Color.swift */, + ); + path = "Primitive Models"; + sourceTree = ""; + }; + 014AA72023C501E2006F3E93 /* Container */ = { + isa = PBXGroup; + children = ( + 014AA72123C501E2006F3E93 /* MoleculeContainerModel.swift */, + 014AA72223C501E2006F3E93 /* ContainerModel.swift */, + 014AA72323C501E2006F3E93 /* ContainerModelProtocol.swift */, + ); + path = Container; + sourceTree = ""; + }; + 014AA72723C5059B006F3E93 /* Template */ = { + isa = PBXGroup; + children = ( + 014AA72823C5059B006F3E93 /* StackPageTemplateModel.swift */, + 014AA72923C5059B006F3E93 /* StackCenteredPageTemplateModel.swift */, + 014AA72A23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift */, + 014AA72C23C5059B006F3E93 /* ListPageTemplateModel.swift */, + ); + path = Template; + sourceTree = ""; + }; 01509D96232803B200EF99AA /* Models */ = { isa = PBXGroup; children = ( - D2DEDCB223C3D17600C44CC4 /* Container */, - 0AA33B322398134B0067DD0F /* Primitive Models */, - 017BEB392360EEB40024EF95 /* PageModel.swift */, - 01EB3683236097C0006832FA /* MoleculeProtocol.swift */, + 014AA72723C5059B006F3E93 /* Template */, + 014AA72023C501E2006F3E93 /* Container */, + 011B58EE23A2AA850085F53C /* ModelProtocols */, + 012A88EF23985E0100FE3DA1 /* Primitive Models */, 946EE1B5237B663A0036751F /* Extensions */, 01EB368723609801006832FA /* Molecules */, ); @@ -540,11 +632,14 @@ 01EB368923609801006832FA /* ListItemModel.swift */, 01EB368A23609801006832FA /* MoleculeStackItemModel.swift */, 01EB368B23609801006832FA /* MoleculeStackModel.swift */, + 011B58F323A2CCC80085F53C /* DropDownModel.swift */, 01EB368C23609801006832FA /* HeaderModel.swift */, - 01EB368D23609801006832FA /* HeadlineBodyModel.swift */, + 012A88EB238F084D00FE3DA1 /* FooterModel.swift */, 017BEB3F23620A230024EF95 /* TextFieldModel.swift */, - 017BEB4123620AD20024EF95 /* FormModelProtocol.swift */, 017BEB7A236763000024EF95 /* LineModel.swift */, + 012A88AE238C626E00FE3DA1 /* CarouselModel.swift */, + 012A88C1238D7BCA00FE3DA1 /* CarouselItemModel.swift */, + 012A88C5238DA34000FE3DA1 /* ModuleMoleculeModel.swift */, ); path = Molecules; sourceTree = ""; @@ -557,14 +652,6 @@ path = Protocols; sourceTree = ""; }; - 0AA33B322398134B0067DD0F /* Primitive Models */ = { - isa = PBXGroup; - children = ( - 0AA33B35239813EE0067DD0F /* Color.swift */, - ); - path = "Primitive Models"; - sourceTree = ""; - }; 946EE1B5237B663A0036751F /* Extensions */ = { isa = PBXGroup; children = ( @@ -641,6 +728,7 @@ isa = PBXGroup; children = ( D2A638FC22CA98280052ED1F /* HeadlineBody.swift */, + 01EB368D23609801006832FA /* HeadlineBodyModel.swift */, D22479952316AF6D003FCCF9 /* HeadlineBodyTextButton.swift */, D27CD40F2339057800C1DC07 /* EyebrowHeadlineBodyLink.swift */, ); @@ -652,6 +740,7 @@ children = ( D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */, D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */, + D28A837E23CCA96400DFE4FC /* TabsModel.swift */, ); path = HorizontalCombinationViews; sourceTree = ""; @@ -668,6 +757,7 @@ D22479902316A9CB003FCCF9 /* Organisms */ = { isa = PBXGroup; children = ( + 01EB368B23609801006832FA /* MoleculeStackModel.swift */, D2A5145E2211DDC100345BFB /* MoleculeStackView.swift */, D2A6390022CBB1820052ED1F /* Carousel.swift */, ); @@ -679,10 +769,15 @@ children = ( D2755D7A23689C7500485468 /* TableViewCell.swift */, 01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */, + 01EB368923609801006832FA /* ListItemModel.swift */, D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */, + D28A838023CCB0D800DFE4FC /* AccordionListItemModel.swift */, D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */, + D28A837C23CCA86A00DFE4FC /* TabsListItemModel.swift */, D27CD40D2322EEAF00C1DC07 /* TabsTableViewCell.swift */, + 011B58F123A2AE2C0085F53C /* DropDownListItemModel.swift */, D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */, + 01EB368A23609801006832FA /* StackItemModel.swift */, D2FB151C23A40F1500C20E10 /* StackItem.swift */, ); path = Items; @@ -718,7 +813,6 @@ D29DF0CE21E404D4003B2FB9 /* MVMCoreUI */ = { isa = PBXGroup; children = ( - D29DF10D21E67A70003B2FB9 /* Atoms */, 01509D96232803B200EF99AA /* Models */, D2B18B7D236090D500A9AEDC /* BaseClasses */, 01C74D87224298E2009C25A3 /* FormUIHelpers */, @@ -731,6 +825,7 @@ D22D1F582204D2590077CEC0 /* Legacy */, D29DF10F21E67A7D003B2FB9 /* BaseControllers */, D29DF11E21E6851E003B2FB9 /* TopAlert */, + D29DF10D21E67A70003B2FB9 /* Atoms */, D29DF10E21E67A77003B2FB9 /* Molecules */, D22479902316A9CB003FCCF9 /* Organisms */, D29DF0DF21E418B2003B2FB9 /* Templates */, @@ -745,7 +840,7 @@ children = ( D2A5146022121FBF00345BFB /* MoleculeStackTemplate.swift */, D2A514622213643100345BFB /* MoleculeStackCenteredTemplate.swift */, - D296E13B2295969C0051EBE7 /* MoleculeListCellProtocol.h */, + D28A837A23C928DA00DFE4FC /* MoleculeListCellProtocol.swift */, D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */, D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */, ); @@ -786,6 +881,7 @@ D274CA322236A78900B01B62 /* StandardFooterView.swift */, 0116A4E4228B19640094F3ED /* RadioButtonModel.swift */, D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */, + D28A838423CCCA8900DFE4FC /* ScrollerModel.swift */, D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */, 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */, 017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */, @@ -905,13 +1001,17 @@ isa = PBXGroup; children = ( DBC4391A224421A0001AB423 /* CaretButton.swift */, + 01F2A03123A4498200D954D8 /* CaretLinkModel.swift */, D29DF25821E6A22D003B2FB9 /* MFButtonProtocol.h */, D29DF16B21E69E1F003B2FB9 /* ButtonDelegateProtocol.h */, D29DF16A21E69E1F003B2FB9 /* MFCustomButton.h */, D29DF17021E69E1F003B2FB9 /* MFCustomButton.m */, + D28A837623C79FC600DFE4FC /* MFCustomButton+ActionModel.swift */, D29DF16C21E69E1F003B2FB9 /* PrimaryButton.h */, D29DF17121E69E1F003B2FB9 /* PrimaryButton.m */, D282AACA2243C61700C46919 /* ButtonView.swift */, + D28A838823CCCFCB00DFE4FC /* LinkModel.swift */, + D28A838623CCCF6500DFE4FC /* MFTextButton+ModelExtension.swift */, D29DF16D21E69E1F003B2FB9 /* MFTextButton.h */, D29DF17221E69E1F003B2FB9 /* MFTextButton.m */, ); @@ -933,10 +1033,10 @@ DBC4391722442197001AB423 /* DashLine.swift */, 944589202385D6E900DE9FD4 /* DashLineModel.swift */, DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */, + 9402C34F23A2CEA3004B974C /* LeftRightLabelModel.swift */, 012CA99D2385A2D3003F810F /* MFView+ModelExtension.swift */, D29DF28721E7AC2B003B2FB9 /* ViewConstrainingView.h */, D29DF28821E7AC2B003B2FB9 /* ViewConstrainingView.m */, - 012CA99B23859FDC003F810F /* ViewConstrainingView+ModelExtension.swift */, D282AAB9224131D100C46919 /* MFTransparentGIFView.swift */, D282AAB3223FDDAE00C46919 /* MFLoadImageView.swift */, 944589222385DA9500DE9FD4 /* ImageViewModel.swift */, @@ -959,6 +1059,7 @@ 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */, 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */, 01004F2F22721C3800991ECC /* RadioButton.swift */, + D28A838223CCBD3F00DFE4FC /* CircleProgressModel.swift */, 943784F3236B77BB006A1E82 /* GraphView.swift */, 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */, ); @@ -1015,7 +1116,7 @@ D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */, D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */, D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */, - D296E1402295EBBA0051EBE7 /* MoleculeDelegateProtocol.h */, + 012A88C7238DB02000FE3DA1 /* ModelMoleculeDelegateProtocol.swift */, D2A514562211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.h */, D2A514572211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m */, 017BEB432362192F0024EF95 /* MVMCoreUIMoleculeMappingObject+ModelExtension.swift */, @@ -1091,16 +1192,6 @@ path = BaseClasses; sourceTree = ""; }; - D2DEDCB223C3D17600C44CC4 /* Container */ = { - isa = PBXGroup; - children = ( - 012A88ED239858E300FE3DA1 /* ContainerModel.swift */, - 012CA9BD2385C692003F810F /* ContainerModelProtocol.swift */, - D2DEDCB323C3D22700C44CC4 /* MoleculeContainerModel.swift */, - ); - path = Container; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -1160,7 +1251,6 @@ D29DF12D21E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.h in Headers */, D29DF24E21E6A177003B2FB9 /* MFDigitTextField.h in Headers */, D29770F321F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.h in Headers */, - D296E1412295EBBA0051EBE7 /* MoleculeDelegateProtocol.h in Headers */, D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */, D29770FD21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h in Headers */, D29DF17421E69E1F003B2FB9 /* MFCustomButton.h in Headers */, @@ -1170,7 +1260,6 @@ D29DF2A121E7AF4E003B2FB9 /* MVMCoreUIUtility.h in Headers */, D29DF17621E69E1F003B2FB9 /* PrimaryButton.h in Headers */, D29DF2C821E7BFC1003B2FB9 /* MFSizeObject.h in Headers */, - D296E13C229598BF0051EBE7 /* MoleculeListCellProtocol.h in Headers */, D29DF32021ED0CBA003B2FB9 /* LabelView.h in Headers */, D29770C921F7C4AE00B2F0D0 /* TopLabelsView.h in Headers */, D29DF2E121E9240B003B2FB9 /* MVMCoreUIPanelProtocol.h in Headers */, @@ -1261,12 +1350,13 @@ files = ( 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */, 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */, - D2DEDCB423C3D22700C44CC4 /* MoleculeContainerModel.swift in Sources */, + 9402C35023A2CEA3004B974C /* LeftRightLabelModel.swift in Sources */, D29DF32121ED0CBA003B2FB9 /* LabelView.m in Sources */, + D28A838123CCB0D800DFE4FC /* AccordionListItemModel.swift in Sources */, DBC4391822442197001AB423 /* CaretView.swift in Sources */, D29770F221F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m in Sources */, - 012CA9BE2385C692003F810F /* ContainerModelProtocol.swift in Sources */, D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */, + D28A838923CCCFCB00DFE4FC /* LinkModel.swift in Sources */, 94C2D9A923872E5E0006CF46 /* LabelAttributeImageModel.swift in Sources */, DBC4391922442197001AB423 /* DashLine.swift in Sources */, 0AA33B34239813C50067DD0F /* UIColor+Extension.swift in Sources */, @@ -1288,6 +1378,7 @@ D29DF25321E6A177003B2FB9 /* MFDigitTextField.m in Sources */, D2B18B7F2360913400A9AEDC /* Control.swift in Sources */, D29DF12F21E6851E003B2FB9 /* MVMCoreUITopAlertMainView.m in Sources */, + 012A88C8238DB02000FE3DA1 /* ModelMoleculeDelegateProtocol.swift in Sources */, DBC4392122491730001AB423 /* LabelWithInternalButton.swift in Sources */, D224798C231450C8003FCCF9 /* HeadlineBodySwitch.swift in Sources */, 017BEB442362192F0024EF95 /* MVMCoreUIMoleculeMappingObject+ModelExtension.swift in Sources */, @@ -1295,32 +1386,43 @@ D29DF17C21E69E1F003B2FB9 /* MFTextButton.m in Sources */, 9445891F2385D2E900DE9FD4 /* CaretViewModel.swift in Sources */, D29DF2C521E7BF57003B2FB9 /* MFTabBarSwipeAnimator.m in Sources */, + 012A88AD238C418100FE3DA1 /* TemplateProtocol.swift in Sources */, D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */, 01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */, D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */, D29DF12E21E6851E003B2FB9 /* MVMCoreUITopAlertView.m in Sources */, - 017BEB3A2360EEB40024EF95 /* PageModel.swift in Sources */, D29DF2CF21E7C104003B2FB9 /* MFLoadingViewController.m in Sources */, + D28A837B23C928DA00DFE4FC /* MoleculeListCellProtocol.swift in Sources */, + 014AA72F23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift in Sources */, D22D1F572204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m in Sources */, D2A5145F2211DDC100345BFB /* MoleculeStackView.swift in Sources */, D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */, + D28A838723CCCF6500DFE4FC /* MFTextButton+ModelExtension.swift in Sources */, D29DF24D21E6A177003B2FB9 /* MFTextField.m in Sources */, C695A69623C990BC00BFB94E /* DoughnutChart.swift in Sources */, + 014AA72D23C5059B006F3E93 /* StackPageTemplateModel.swift in Sources */, + 012A88C4238D86E600FE3DA1 /* CollectionCellMoleculeProtocol.swift in Sources */, 94C2D9AB23872EB50006CF46 /* LabelAttributeActionModel.swift in Sources */, + 014AA73123C5059B006F3E93 /* ListPageTemplateModel.swift in Sources */, 017BEB4023620A230024EF95 /* TextFieldModel.swift in Sources */, D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */, D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */, 94C2D9A723872DA90006CF46 /* LabelAttributeColorModel.swift in Sources */, D2755D7B23689C7500485468 /* TableViewCell.swift in Sources */, + 014AA72623C501E2006F3E93 /* ContainerModelProtocol.swift in Sources */, 01EB369223609801006832FA /* MoleculeStackModel.swift in Sources */, 012CA99E2385A2D3003F810F /* MFView+ModelExtension.swift in Sources */, D29DF25421E6A177003B2FB9 /* MFMdnTextField.m in Sources */, D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */, 944589232385DA9600DE9FD4 /* ImageViewModel.swift in Sources */, D213347723843825008E41B3 /* Line.swift in Sources */, + D28A837723C79FC600DFE4FC /* MFCustomButton+ActionModel.swift in Sources */, + D28A837F23CCA96400DFE4FC /* TabsModel.swift in Sources */, + 012A88EC238F084D00FE3DA1 /* FooterModel.swift in Sources */, D2A514672213885800345BFB /* StandardHeaderView.swift in Sources */, 01EB369023609801006832FA /* ListItemModel.swift in Sources */, - D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */, + D28A838323CCBD3F00DFE4FC /* CircleProgressModel.swift in Sources */, + D268C70C2386DFFD007F2C1C /* StackItemModel.swift in Sources */, DBEFFA04225A829700230692 /* Label.swift in Sources */, D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */, 01509D952327ED1900EF99AA /* HeadlineBodyTextButtonSwitch.swift in Sources */, @@ -1329,20 +1431,22 @@ D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */, D2B18B812360945C00A9AEDC /* View.swift in Sources */, D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */, + 014AA72523C501E2006F3E93 /* ContainerModel.swift in Sources */, D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */, D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */, - 012A88EE239858E300FE3DA1 /* ContainerModel.swift in Sources */, D2B18B94236214AD00A9AEDC /* NavigationController.swift in Sources */, D282AACB2243C61700C46919 /* ButtonView.swift in Sources */, D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */, 01EB368F23609801006832FA /* LabelModel.swift in Sources */, 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */, + 01F2A03223A4498200D954D8 /* CaretLinkModel.swift in Sources */, 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */, + 011B58F023A2AA980085F53C /* ListItemModelProtocol.swift in Sources */, D22479962316AF6E003FCCF9 /* HeadlineBodyTextButton.swift in Sources */, - 0AA33B36239813EE0067DD0F /* Color.swift in Sources */, D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */, 017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */, D29DF18121E69E50003B2FB9 /* MFView.m in Sources */, + D28A837923C7D5BC00DFE4FC /* PageModelProtocol.swift in Sources */, D29DF18321E69E54003B2FB9 /* SeparatorView.m in Sources */, D29DF17A21E69E1F003B2FB9 /* MFCustomButton.m in Sources */, 017BEB7B236763000024EF95 /* LineModel.swift in Sources */, @@ -1350,11 +1454,14 @@ 017BEB7F23676E870024EF95 /* MoleculeObjectMapping.swift in Sources */, D274CA332236A78900B01B62 /* StandardFooterView.swift in Sources */, D29DF2BF21E7BEA4003B2FB9 /* MVMCoreUITabBarPageControlViewController.m in Sources */, + 014AA72423C501E2006F3E93 /* MoleculeContainerModel.swift in Sources */, D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */, + 011B58F223A2AE2C0085F53C /* DropDownListItemModel.swift in Sources */, 94C2D9842386F3F80006CF46 /* LabelAttributeModel.swift in Sources */, 944589212385D6E900DE9FD4 /* DashLineModel.swift in Sources */, D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */, D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */, + 012A88B1238C880100FE3DA1 /* PagingMoleculeProtocol.swift in Sources */, D29DF2C921E7BFC6003B2FB9 /* MFSizeObject.m in Sources */, 9445890E2385C3F800DE9FD4 /* MultiProgressModel.swift in Sources */, D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */, @@ -1369,6 +1476,7 @@ D224798A2314445E003FCCF9 /* LabelSwitch.swift in Sources */, D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */, 017BEB4223620AD20024EF95 /* FormModelProtocol.swift in Sources */, + 012A88DB238ED45900FE3DA1 /* CarouselModel.swift in Sources */, D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */, D29DF17B21E69E1F003B2FB9 /* PrimaryButton.m in Sources */, 017BEB4A236235BA0024EF95 /* ModelMoleculeViewProtocol.swift in Sources */, @@ -1382,6 +1490,8 @@ D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */, 01EB369323609801006832FA /* HeaderModel.swift in Sources */, D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */, + D28A837D23CCA86A00DFE4FC /* TabsListItemModel.swift in Sources */, + 012A88C6238DA34000FE3DA1 /* ModuleMoleculeModel.swift in Sources */, 94C2D9A123872BCC0006CF46 /* LabelAttributeUnderlineModel.swift in Sources */, D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */, D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */, @@ -1391,7 +1501,11 @@ D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */, D29DF11821E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m in Sources */, 94C2D9A323872C110006CF46 /* LabelAttributeStrikeThroughModel.swift in Sources */, + 011B58F423A2CCC80085F53C /* DropDownModel.swift in Sources */, + D28A838523CCCA8900DFE4FC /* ScrollerModel.swift in Sources */, D29DF26C21E6AA0B003B2FB9 /* FLAnimatedImage.m in Sources */, + 012A88F123985E0100FE3DA1 /* Color.swift in Sources */, + 012A889C23889E8400FE3DA1 /* TemplateModelProtocol.swift in Sources */, D29770FC21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m in Sources */, D29DF25121E6A177003B2FB9 /* MFDigitTextBox.m in Sources */, DBC4391B224421A0001AB423 /* CaretButton.swift in Sources */, @@ -1401,13 +1515,14 @@ D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */, D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */, 0105618E224BBE7700E1557D /* FormValidator+TextFields.swift in Sources */, - 012CA99C23859FDC003F810F /* ViewConstrainingView+ModelExtension.swift in Sources */, 0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */, D2B18B922361E65A00A9AEDC /* CoreUIObject.swift in Sources */, D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */, + 014AA72E23C5059B006F3E93 /* StackCenteredPageTemplateModel.swift in Sources */, D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */, C695A69423C9909000BFB94E /* DoughnutChartModel.swift in Sources */, D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */, + 012A88C2238D7BCA00FE3DA1 /* CarouselItemModel.swift in Sources */, D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */, D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */, D21EE53C23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift in Sources */, diff --git a/MVMCoreUI/Atoms/Buttons/CaretButton.swift b/MVMCoreUI/Atoms/Buttons/CaretButton.swift index 6c9de088..16b571d1 100644 --- a/MVMCoreUI/Atoms/Buttons/CaretButton.swift +++ b/MVMCoreUI/Atoms/Buttons/CaretButton.swift @@ -8,7 +8,7 @@ // -open class CaretButton: MFCustomButton, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol { +open class CaretButton: MFCustomButton, MVMCoreUIMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol, ModelMoleculeViewProtocol { //------------------------------------------------------ // MARK: - Constants @@ -132,6 +132,20 @@ open class CaretButton: MFCustomButton, MVMCoreUIMoleculeViewProtocol, MVMCoreUI } } + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + guard let caretLinkModel = model as? CaretLinkModel else { return } + if let color = caretLinkModel.backgroundColor { + backgroundColor = color.uiColor + } + enabledColor = caretLinkModel.enabledColor.uiColor + if let color = caretLinkModel.disabledColor { + disabledColor = color.uiColor + } + isEnabled = caretLinkModel.enabled + set(with: caretLinkModel.action, delegateObject: delegateObject, additionalData: additionalData) + setTitle(caretLinkModel.label.text, for: .normal) + } + public func needsToBeConstrained() -> Bool { return true } diff --git a/MVMCoreUI/Atoms/Buttons/CaretLinkModel.swift b/MVMCoreUI/Atoms/Buttons/CaretLinkModel.swift new file mode 100644 index 00000000..3cc77a54 --- /dev/null +++ b/MVMCoreUI/Atoms/Buttons/CaretLinkModel.swift @@ -0,0 +1,60 @@ +// +// CaretLinkModel.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 12/13/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation +import MVMCore + +public class CaretLinkModel: MoleculeProtocol { + public static var identifier: String = "caretLink" + public var backgroundColor: Color? + public var label: LabelModel + public var action: ActionProtocol + public var enabledColor: Color = Color(uiColor: .black) + public var disabledColor: Color? = Color(uiColor: .mfSilver()) + public var enabled: Bool = true + + public init(label: LabelModel, action: ActionProtocol) { + self.label = label + self.action = action + } + + enum CodingKeys: String, CodingKey { + case backgroundColor + case label + case action + case enabledColor + case disabledColor + case enabled + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + label = try typeContainer.decode(LabelModel.self, forKey: .label) + if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledColor) { + enabledColor = color + } + if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledColor) { + disabledColor = color + } + if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { + self.enabled = enabled + } + action = try typeContainer.decodeModel(codingKey: .action, typeCodingKey: ActionCodingKey.type) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(label, forKey: .label) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + try container.encodeModel(action, forKey: .action) + try container.encode(enabled, forKey: .enabledColor) + try container.encodeIfPresent(disabledColor, forKey: .disabledColor) + try container.encode(enabled, forKey: .enabled) + } +} diff --git a/MVMCoreUI/Atoms/Buttons/LinkModel.swift b/MVMCoreUI/Atoms/Buttons/LinkModel.swift new file mode 100644 index 00000000..6b3ff39e --- /dev/null +++ b/MVMCoreUI/Atoms/Buttons/LinkModel.swift @@ -0,0 +1,53 @@ +// +// LinkModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 1/13/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + +public class LinkModel: MoleculeProtocol { + public static var identifier: String = "link" + public var backgroundColor: Color? + public var title: String + public var action: ActionProtocol + public var enabled = true + public var textColor = Color(uiColor: .mfTextButton()) + + public init(title: String, action: ActionProtocol) { + self.title = title + self.action = action + } + + enum CodingKeys: String, CodingKey { + case backgroundColor + case title + case action + case enabled + case textColor + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + title = try typeContainer.decode(String.self, forKey: .title) + action = try typeContainer.decodeModel(codingKey: .action, typeCodingKey: ActionCodingKey.type) + 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 + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(title, forKey: .title) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + try container.encodeModel(action, forKey: .action) + try container.encode(enabled, forKey: .enabled) + try container.encode(textColor, forKey: .textColor) + } +} diff --git a/MVMCoreUI/Atoms/Buttons/MFCustomButton+ActionModel.swift b/MVMCoreUI/Atoms/Buttons/MFCustomButton+ActionModel.swift new file mode 100644 index 00000000..b967db48 --- /dev/null +++ b/MVMCoreUI/Atoms/Buttons/MFCustomButton+ActionModel.swift @@ -0,0 +1,23 @@ +// +// MFCustomButton+ActionModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 1/9/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public extension MFCustomButton { + func set(with action: ActionProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + buttonDelegate = delegateObject?.buttonDelegate + add({ [weak self] sender in + guard let self = self else { return } + if let data = try? action.encode(using: JSONEncoder()), + let actionMap = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.init()) as? [AnyHashable: Any], + delegateObject?.buttonDelegate?.button?(self, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true { + MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) + } + }, for: .touchUpInside) + } +} diff --git a/MVMCoreUI/Atoms/Buttons/MFTextButton+ModelExtension.swift b/MVMCoreUI/Atoms/Buttons/MFTextButton+ModelExtension.swift new file mode 100644 index 00000000..a6df6745 --- /dev/null +++ b/MVMCoreUI/Atoms/Buttons/MFTextButton+ModelExtension.swift @@ -0,0 +1,24 @@ +// +// MFTextButton_ModelExtension.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 1/13/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + +// temporary until link is finished +extension MFTextButton: ModelMoleculeViewProtocol { + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + guard let model = model as? LinkModel else { return } + setTitle(model.title, for: .normal) + setTitleColor(model.textColor.uiColor, for: .normal) + isEnabled = model.enabled + backgroundColor = model.backgroundColor?.uiColor + //TODO: Use object when handleAction is rewrote to handle action model + if let actionMap = model.action.toJSON() { + MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) + } + } +} diff --git a/MVMCoreUI/Atoms/TextFields/MFTextField+ModelExtension.swift b/MVMCoreUI/Atoms/TextFields/MFTextField+ModelExtension.swift index 81f00282..e0c5ce0f 100644 --- a/MVMCoreUI/Atoms/TextFields/MFTextField+ModelExtension.swift +++ b/MVMCoreUI/Atoms/TextFields/MFTextField+ModelExtension.swift @@ -16,11 +16,11 @@ enum TextType: String { } extension MFTextField: ModelMoleculeViewProtocol { // - public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { //TODO: Need to create setWithModel in ViewConstraining View #warning("This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView.") //TODO: This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView. - setUpWithModel(model, delegateObject, additionalData) + setUpDefaultWithModel(model, delegateObject, additionalData) guard let textFieldModel = model as? TextFieldModel, let delegateObject = delegateObject else { @@ -38,7 +38,9 @@ extension MFTextField: ModelMoleculeViewProtocol { formText = textFieldModel.label as NSString? text = textFieldModel.value as NSString? - enable(textFieldModel.disabled) + if let disabled = textFieldModel.disabled { + enable(disabled) + } errMessage = textFieldModel.errorMsg fieldKey = textFieldModel.fieldKey groupName = textFieldModel.groupName diff --git a/MVMCoreUI/Atoms/Views/CaretView.swift b/MVMCoreUI/Atoms/Views/CaretView.swift index fa34efc1..653bfef0 100644 --- a/MVMCoreUI/Atoms/Views/CaretView.swift +++ b/MVMCoreUI/Atoms/Views/CaretView.swift @@ -99,47 +99,24 @@ open class CaretView: View { //------------------------------------------------------ // Default values for view. - @objc open func setAsMolecule() { + @objc open override func setAsMolecule() { defaultState() } - - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - // Configure class properties with JSON values - guard let dictionary = json else { return } - - if let strokeColorHex = dictionary["strokeColor"] as? String { - strokeColor = UIColor.mfGet(forHex: strokeColorHex) - } - - if let isHiddenValue = dictionary[KeyIsHidden] as? Bool { - isHidden = isHiddenValue - } - - if let isOpaqueValue = dictionary[KeyIsOpaque] as? Bool { - isOpaque = isOpaqueValue - } - - if let lineWidthValue = dictionary["lineWidth"] as? CGFloat { - lineWidth = lineWidthValue - } + + public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + guard let json = json, let model = try? Self.decodeJSONToModel(json: json, type: CaretViewModel.self) else { return } + setWithModel(model, delegateObject, additionalData) } - override public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + //MARK: - MVMCoreMoleculeViewProtocol + override public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.setWithModel(model, delegateObject, additionalData) guard let caretModel = model as? CaretViewModel else { return } - if let strokeColorHex = caretModel.strokeColor { - strokeColor = UIColor.mfGet(forHex: strokeColorHex) - } - - if let isHiddenValue = caretModel.isHidden { - isHidden = isHiddenValue - } - - if let isOpaqueValue = caretModel.isOpaque { - isOpaque = isOpaqueValue - } + strokeColor = caretModel.strokeColor.uiColor + isHidden = caretModel.isHidden ?? false + isOpaque = caretModel.isOpaque ?? false if let lineWidthValue = caretModel.lineWidth { lineWidth = lineWidthValue diff --git a/MVMCoreUI/Atoms/Views/CaretViewModel.swift b/MVMCoreUI/Atoms/Views/CaretViewModel.swift index 481d086f..f26a150f 100644 --- a/MVMCoreUI/Atoms/Views/CaretViewModel.swift +++ b/MVMCoreUI/Atoms/Views/CaretViewModel.swift @@ -11,10 +11,37 @@ import Foundation @objcMembers public class CaretViewModel: MoleculeProtocol { public static var identifier: String = "caretView" - public var backgroundColor: String? - - public var strokeColor: String? + public var backgroundColor: Color? + public var strokeColor: Color = Color(uiColor: .black) public var isHidden: Bool? public var isOpaque: Bool? public var lineWidth: CGFloat? + + enum CodingKeys: String, CodingKey { + case backgroundColor + case strokeColor + case isHidden + case isOpaque + case lineWidth + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + if let strokeColor = try typeContainer.decodeIfPresent(Color.self, forKey: .strokeColor) { + self.strokeColor = strokeColor + } + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + isHidden = try typeContainer.decodeIfPresent(Bool.self, forKey: .isHidden) + isOpaque = try typeContainer.decodeIfPresent(Bool.self, forKey: .isOpaque) + lineWidth = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .lineWidth) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(strokeColor, forKey: .strokeColor) + try container.encodeIfPresent(isHidden, forKey: .isHidden) + try container.encodeIfPresent(isOpaque, forKey: .isOpaque) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + try container.encodeIfPresent(lineWidth, forKey: .lineWidth) + } } diff --git a/MVMCoreUI/Atoms/Views/CircleProgressModel.swift b/MVMCoreUI/Atoms/Views/CircleProgressModel.swift new file mode 100644 index 00000000..20f49dc0 --- /dev/null +++ b/MVMCoreUI/Atoms/Views/CircleProgressModel.swift @@ -0,0 +1,128 @@ +// +// CircleProgressModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 1/13/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + +public enum GraphSize: String, Codable { + case small, medium, large +} + +public enum GraphStyle: String, Codable { + case unlimited, safetyMode +} + +public class CircleProgressModel: MoleculeProtocol { + public static var identifier: String = "circleProgress" + public var style: GraphStyle = .unlimited { + didSet { + updateStyle() + } + } + + public var size: GraphSize = .small { + didSet { + updateSize() + } + } + public var diameter: CGFloat = 24 + public var lineWidth: CGFloat = 5 + public var clockwise: Bool = true + public var duration : Double = 1.0 + public var colors = [Color]() + public var backgroundColor: Color? + + public init() {} + + enum CircleProgressCodingKeys: String, CodingKey { + case style + case size + case diameter + case lineWidth + case clockwise + case duration + case colors + case backgroundColor + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CircleProgressCodingKeys.self) + if let style = try typeContainer.decodeIfPresent(GraphStyle.self, forKey: .style) { + self.style = style + } + if let size = try typeContainer.decodeIfPresent(GraphSize.self, forKey: .size) { + self.size = size + } + if let diameter = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .diameter) { + self.diameter = diameter + } + if let lineWidth = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .lineWidth) { + self.lineWidth = lineWidth + } + if let clockwise = try typeContainer.decodeIfPresent(Bool.self, forKey: .clockwise) { + self.clockwise = clockwise + } + if let duration = try typeContainer.decodeIfPresent(Double.self, forKey: .duration) { + self.duration = duration + } + if let colors = try typeContainer.decodeIfPresent([Color].self, forKey: .colors) { + self.colors = colors + } + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CircleProgressCodingKeys.self) + try container.encode(style, forKey: .style) + try container.encode(size, forKey: .size) + try container.encode(diameter, forKey: .diameter) + try container.encode(lineWidth, forKey: .lineWidth) + try container.encode(clockwise, forKey: .clockwise) + try container.encode(duration, forKey: .duration) + try container.encode(colors, forKey: .colors) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + } + + func getCGColorsFromArray(_ colorArray: [String]) -> [Color] { + return colorArray.map { (colorString) -> Color in + return Color(uiColor: UIColor.mfGet(forHex: colorString)) + } + } + + func updateStyle() { + switch style { + case .unlimited: + duration = 1.0 + clockwise = true + //current style, only the end part shows darker look + colors = getCGColorsFromArray(["#007AB8","#007AB8","#033554"]) + break + case .safetyMode: + duration = 1.5 + clockwise = true + colors = getCGColorsFromArray(["#CC4D0F","#CC4D0F","AB0309"]) + break + } + } + + func updateSize() { + switch size { + case .small: + diameter = MFSizeObject(standardSize: 20)?.getValueBasedOnApplicationWidth() ?? 20 + lineWidth = MFSizeObject(standardSize: 4)?.getValueBasedOnApplicationWidth() ?? 4 + break + case .medium: + diameter = MFSizeObject(standardSize: 100)?.getValueBasedOnApplicationWidth() ?? 100 + lineWidth = MFSizeObject(standardSize: 8)?.getValueBasedOnApplicationWidth() ?? 8 + break + case .large: + diameter = MFSizeObject(standardSize: 180)?.getValueBasedOnApplicationWidth() ?? 180 + lineWidth = MFSizeObject(standardSize: 12)?.getValueBasedOnApplicationWidth() ?? 12 + break + } + } +} diff --git a/MVMCoreUI/Atoms/Views/DashLine.swift b/MVMCoreUI/Atoms/Views/DashLine.swift index 937b7313..94bd987c 100644 --- a/MVMCoreUI/Atoms/Views/DashLine.swift +++ b/MVMCoreUI/Atoms/Views/DashLine.swift @@ -15,8 +15,11 @@ open class DashLine: View { // MARK: - Properties //------------------------------------------------------ - @objc public var dashColor: UIColor? - @objc public var dashLayer: CAShapeLayer? + var dashModel: DashLineModel? { + get { return model as? DashLineModel } + } + + @objc private var dashLayer: CAShapeLayer? //------------------------------------------------------ // MARK: - Lifecycle @@ -53,7 +56,7 @@ open class DashLine: View { dashLayer.lineCap = .round dashLayer.lineDashPattern = [NSNumber(value: 2), NSNumber(value: 2)] dashLayer.path = path.cgPath - dashLayer.strokeColor = dashColor?.cgColor ?? UIColor.mfLighterGray().cgColor + dashLayer.strokeColor = dashModel?.dashColor.uiColor.cgColor ?? UIColor.mfLighterGray().cgColor dashLayer.fillColor = UIColor.clear.cgColor dashLayer.backgroundColor = backgroundColor?.cgColor ?? UIColor.white.cgColor self.dashLayer = dashLayer @@ -64,36 +67,27 @@ open class DashLine: View { //------------------------------------------------------ // Default values for view. - @objc open func setAsMolecule() { + @objc open override func setAsMolecule() { backgroundColor = .clear isHidden = false } open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - - // Configure class properties with JSON values - guard let jsonDictionary = json else { return } - - if let isHiddenValue = jsonDictionary[KeyIsHidden] as? Bool { - isHidden = isHiddenValue - } - - if let dashColorHex = jsonDictionary["dashColor"] as? String { - dashColor = UIColor.mfGet(forHex: dashColorHex) - } + guard let json = json, let model = try? Self.decodeJSONToModel(json: json, type: DashLineModel.self) else { return } + setWithModel(model, delegateObject, additionalData) } - public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { - guard let dashLineModel = model as? DashLineModel else { + //MARK: - MVMCoreMoleculeViewProtocol + public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.setWithModel(model, delegateObject, additionalData) + guard let dashLineModel = dashModel else { return } - dashColor = UIColor.mfGet(forHex: dashLineModel.dashColor) if let isHiddenValue = dashLineModel.isHidden { isHidden = isHiddenValue } if let backgroundColor = dashLineModel.backgroundColor { - dashLayer?.backgroundColor = UIColor.mfGet(forHex: backgroundColor).cgColor + dashLayer?.backgroundColor = backgroundColor.uiColor.cgColor } } } diff --git a/MVMCoreUI/Atoms/Views/DashLineModel.swift b/MVMCoreUI/Atoms/Views/DashLineModel.swift index 6fff83c7..ec6b8a15 100644 --- a/MVMCoreUI/Atoms/Views/DashLineModel.swift +++ b/MVMCoreUI/Atoms/Views/DashLineModel.swift @@ -10,9 +10,34 @@ import Foundation @objcMembers public class DashLineModel: MoleculeProtocol { public static var identifier: String = "dashLine" - public var moleculeName: String - public var backgroundColor: String? + public var backgroundColor: Color? - public var dashColor: String + public var dashColor: Color = Color(uiColor: .mfLighterGray()) public var isHidden: Bool? + + public init(dashColor: Color) { + self.dashColor = dashColor + } + + enum CodingKeys: String, CodingKey { + case backgroundColor + case dashColor + case isHidden + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + if let dashColor = try typeContainer.decodeIfPresent(Color.self, forKey: .dashColor) { + self.dashColor = dashColor + } + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + isHidden = try typeContainer.decodeIfPresent(Bool.self, forKey: .isHidden) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(dashColor, forKey: .dashColor) + try container.encodeIfPresent(isHidden, forKey: .isHidden) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + } } diff --git a/MVMCoreUI/Atoms/Views/GraphView.swift b/MVMCoreUI/Atoms/Views/GraphView.swift index ca63c67f..cda77660 100644 --- a/MVMCoreUI/Atoms/Views/GraphView.swift +++ b/MVMCoreUI/Atoms/Views/GraphView.swift @@ -8,113 +8,13 @@ import UIKit - -enum GraphSize: String { - case small, medium, large -} - -enum GraphStyle: String { - case unlimited, safetyMode -} - -///Graph Object contains properties -public struct GraphObject { - - var style: GraphStyle { - didSet { - updateStyle() - } - } - var size: GraphSize { - didSet { - updateSize() - } - } - var diameter: CGFloat = 24 - var lineWidth: CGFloat = 5 - var clockwise: Bool = true - var duration : Double = 1.0 - var colors = [CGColor]() - - public init(_ json: [AnyHashable : Any]?) { - style = .unlimited - size = .small - guard let json = json else { - return - } - if let styleString = json.optionalStringForKey("style") { - style = GraphStyle(rawValue: styleString) ?? .unlimited - } - if let sizeString = json.optionalStringForKey("size") { - size = GraphSize(rawValue: sizeString) ?? .small - } - updateStyle() - updateSize() - if let diameter = json.optionalCGFloatForKey("diameter") { - self.diameter = diameter - } - if let lineWidth = json.optionalCGFloatForKey("lineWidth") { - self.lineWidth = lineWidth - } - if let clockwise = json.optionalBoolForKey("clockwise") { - self.clockwise = clockwise - } - if let duration = json["duration"] as? Double { - self.duration = duration - } - if let colorArray = json.optionalArrayForKey("colors") as? [String] { - colors = getCGColorsFromArray(colorArray) - } - } - - func getCGColorsFromArray(_ colorArray: [String]) -> [CGColor] { - return colorArray.map { (colorString) -> CGColor in - return UIColor.mfGet(forHex: colorString).cgColor - } - } - - mutating func updateStyle() { - switch style { - case .unlimited: - duration = 1.0 - clockwise = true - //current style, only the end part shows darker look - colors = getCGColorsFromArray(["#007AB8","#007AB8","#033554"]) - break - case .safetyMode: - duration = 1.5 - clockwise = true - colors = getCGColorsFromArray(["#CC4D0F","#CC4D0F","AB0309"]) - break - } - } - - //those are - mutating func updateSize() { - switch size { - case .small: - diameter = MFSizeObject(standardSize: 20)?.getValueBasedOnApplicationWidth() ?? 20 - lineWidth = MFSizeObject(standardSize: 4)?.getValueBasedOnApplicationWidth() ?? 4 - break - case .medium: - diameter = MFSizeObject(standardSize: 100)?.getValueBasedOnApplicationWidth() ?? 100 - lineWidth = MFSizeObject(standardSize: 8)?.getValueBasedOnApplicationWidth() ?? 8 - break - case .large: - diameter = MFSizeObject(standardSize: 180)?.getValueBasedOnApplicationWidth() ?? 180 - lineWidth = MFSizeObject(standardSize: 12)?.getValueBasedOnApplicationWidth() ?? 12 - break - } - } -} - - @objcMembers open class GraphView: View, MVMCoreUIViewConstrainingProtocol { var heightConstraint: NSLayoutConstraint? var gradientLayer: CALayer? - var graphObject: GraphObject? - + var graphModel: CircleProgressModel? { + return model as? CircleProgressModel + } // MARK: setup open override func setupView() { @@ -126,16 +26,16 @@ public struct GraphObject { widthAnchor.constraint(equalTo: heightAnchor).isActive = true } - override open func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + override open func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.setWithModel(model, delegateObject, additionalData) + guard let model = model as? CircleProgressModel else { return } + createGraphCircle(model) + rotationAnimation(model) } - override open func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - let object = GraphObject(json) - graphObject = object - createGraphCircle(object) - rotationAnimation(object) + override open func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + guard let json = json, let model = try? Self.decodeJSONToModel(json: json, type: CircleProgressModel.self) else { return } + setWithModel(model, delegateObject, additionalData) } class func getAngle(_ piValue: Double) -> Double { @@ -147,7 +47,7 @@ public struct GraphObject { } // MARK: circle - open func createGraphCircle(_ graphObject: GraphObject) { + open func createGraphCircle(_ graphObject: CircleProgressModel) { if let sublayers = layer.sublayers { for sublayer in sublayers { sublayer.removeAllAnimations() @@ -188,14 +88,14 @@ public struct GraphObject { | | | ------------- */ - func createGradientLayer(_ graphObject: GraphObject) -> CALayer { + func createGradientLayer(_ graphObject: CircleProgressModel) -> CALayer { let containLayer = CALayer() containLayer.frame = CGRect(x: 0, y: 0, width: graphObject.diameter, height: graphObject.diameter) let radius = graphObject.diameter / 2.0 //create graident layers guard graphObject.colors.count > 1 else { - containLayer.backgroundColor = graphObject.colors.first + containLayer.backgroundColor = graphObject.colors.first?.uiColor.cgColor return containLayer } var topGradientHeight : CGFloat = 0.0 @@ -214,7 +114,7 @@ public struct GraphObject { leftColors.removeLast() topLayer.colors = [leftColors.last!, rightColors.first!] } else { - topLayer.backgroundColor = leftColors.last + topLayer.backgroundColor = leftColors.last?.uiColor.cgColor } containLayer.addSublayer(topLayer) @@ -227,7 +127,7 @@ public struct GraphObject { if leftColors.count > 1 { leftLayer.colors = Array(leftColors) } else { - leftLayer.backgroundColor = leftColors.first + leftLayer.backgroundColor = leftColors.first?.uiColor.cgColor } containLayer.addSublayer(leftLayer) @@ -238,7 +138,7 @@ public struct GraphObject { if rightColors.count > 1 { rightLayer.colors = Array(rightColors) } else { - rightLayer.backgroundColor = rightColors.first + rightLayer.backgroundColor = rightColors.first?.uiColor.cgColor } containLayer.addSublayer(rightLayer) @@ -250,7 +150,7 @@ public struct GraphObject { } //MARK: Animation - func rotationAnimation(_ object: GraphObject) { + func rotationAnimation(_ object: CircleProgressModel) { MVMCoreDispatchUtility.performBlock(onMainThread:{ let rotation = CABasicAnimation(keyPath: "transform.rotation") let animationHandler = GraphViewAnimationHandler.shared @@ -281,7 +181,7 @@ public struct GraphObject { extension GraphView: CAAnimationDelegate { public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { - if let object = graphObject { + if let object = graphModel { rotationAnimation(object) } } diff --git a/MVMCoreUI/Atoms/Views/ImageViewModel.swift b/MVMCoreUI/Atoms/Views/ImageViewModel.swift index 16c32d8f..0944c36e 100644 --- a/MVMCoreUI/Atoms/Views/ImageViewModel.swift +++ b/MVMCoreUI/Atoms/Views/ImageViewModel.swift @@ -10,8 +10,7 @@ import Foundation @objcMembers public class ImageViewModel: MoleculeProtocol { public static var identifier: String = "image" - public var moleculeName: String - public var backgroundColor: String? + public var backgroundColor: Color? public var image: String public var accessibilityText: String? diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index b37e74fb..28f0078f 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -218,7 +218,7 @@ public typealias ActionBlock = () -> () case left } - public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { clauses = [] guard let labelModel = model as? LabelModel else { return } attributedText = nil @@ -235,8 +235,8 @@ public typealias ActionBlock = () -> () } makeWholeViewClickable = labelModel.makeWholeViewClickable ?? false - if let backgroundColorHex = labelModel.backgroundColor, !backgroundColorHex.isEmpty { - backgroundColor = UIColor.mfGet(forHex: backgroundColorHex) + if let backgroundColor = labelModel.backgroundColor { + self.backgroundColor = backgroundColor.uiColor } if let accessibilityText = labelModel.accessibilityText { accessibilityLabel = accessibilityText diff --git a/MVMCoreUI/Atoms/Views/LabelModel/LabelModel.swift b/MVMCoreUI/Atoms/Views/LabelModel/LabelModel.swift index 2b87186f..90c694a0 100644 --- a/MVMCoreUI/Atoms/Views/LabelModel/LabelModel.swift +++ b/MVMCoreUI/Atoms/Views/LabelModel/LabelModel.swift @@ -12,7 +12,7 @@ import Foundation @objcMembers public class LabelModel: MoleculeProtocol { public static var identifier: String = "label" public var moleculeName: String? - public var backgroundColor: String? + public var backgroundColor: Color? public var text: String public var accessibilityText: String? @@ -52,7 +52,7 @@ import Foundation self.text = try typeContainer.decode(String.self, forKey: .text) self.accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText) self.textColor = try typeContainer.decodeIfPresent(String.self, forKey: .textColor) - self.backgroundColor = try typeContainer.decodeIfPresent(String.self, forKey: .backgroundColor) + self.backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) self.fontStyle = try typeContainer.decodeIfPresent(String.self, forKey: .fontStyle) self.fontName = try typeContainer.decodeIfPresent(String.self, forKey: .fontName) self.fontSize = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .fontSize) diff --git a/MVMCoreUI/Atoms/Views/LeftRightLabelModel.swift b/MVMCoreUI/Atoms/Views/LeftRightLabelModel.swift new file mode 100644 index 00000000..5e091446 --- /dev/null +++ b/MVMCoreUI/Atoms/Views/LeftRightLabelModel.swift @@ -0,0 +1,16 @@ +// +// LeftRightLabelModel.swift +// MVMCoreUI +// +// Created by Ryan on 12/12/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers public class LeftRightLabelModel: MoleculeProtocol { + public static var identifier: String = "leftRightLabel" + public var backgroundColor: Color? + public var leftText: LabelModel + public var rightText: LabelModel +} diff --git a/MVMCoreUI/Atoms/Views/LeftRightLabelView.swift b/MVMCoreUI/Atoms/Views/LeftRightLabelView.swift index a059aef5..5e128e26 100644 --- a/MVMCoreUI/Atoms/Views/LeftRightLabelView.swift +++ b/MVMCoreUI/Atoms/Views/LeftRightLabelView.swift @@ -9,7 +9,7 @@ import Foundation -@objcMembers open class LeftRightLabelView: ViewConstrainingView { +@objcMembers open class LeftRightLabelView: View { //------------------------------------------------------ // MARK: - Outlets //------------------------------------------------------ @@ -28,7 +28,7 @@ import Foundation // MARK: - Initialization //------------------------------------------------------ - public init() { + public override init() { super.init(frame: .zero) } @@ -176,4 +176,20 @@ import Foundation constrainLeftLabel() } } + + //MARK: - MVMCoreMoleculeViewProtocol + + open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.setWithModel(model, delegateObject, additionalData) + guard let leftRightLabelModel = model as? LeftRightLabelModel else { + return + } + leftTextLabel.setWithModel(leftRightLabelModel.leftText, delegateObject, additionalData) + rightTextLabel.setWithModel(leftRightLabelModel.rightText, delegateObject, additionalData) + if !leftTextLabel.hasText { + constrainRightLabel() + } else if !rightTextLabel.hasText { + constrainLeftLabel() + } + } } diff --git a/MVMCoreUI/Atoms/Views/Line.swift b/MVMCoreUI/Atoms/Views/Line.swift index d5f4f4b6..d7cbc5e8 100644 --- a/MVMCoreUI/Atoms/Views/Line.swift +++ b/MVMCoreUI/Atoms/Views/Line.swift @@ -9,42 +9,35 @@ import UIKit @objcMembers open class Line: View { + var lineModel: LineModel? { + get { return model as? LineModel } + } public var heightConstraint: NSLayoutConstraint? - public enum Style: String, Codable { - case standard - case thin - case medium - case heavy - case none - } - - public var style = Style.standard { - didSet { - switch style { - case .standard: - heightConstraint?.constant = 1 - backgroundColor = .mfSilver() - case .thin: - heightConstraint?.constant = 1 - backgroundColor = .black - case .medium: - heightConstraint?.constant = 2 - backgroundColor = .black - case .heavy: - heightConstraint?.constant = 4 - backgroundColor = .black - case .none: - heightConstraint?.constant = 0 - } + open func setStyle(_ style: LineModel.Style) { + switch style { + case .standard: + heightConstraint?.constant = 1 + backgroundColor = .mfSilver() + case .thin: + heightConstraint?.constant = 1 + backgroundColor = .black + case .medium: + heightConstraint?.constant = 2 + backgroundColor = .black + case .heavy: + heightConstraint?.constant = 4 + backgroundColor = .black + case .none: + heightConstraint?.constant = 0 } } // MARK: - Helpers open func shouldBeVisible() -> Bool { - guard let type = json?.optionalStringForKey(KeyType) else { return false } - return type != "none" + guard let type = lineModel?.type else { return false } + return type != .none } public convenience init(pinTo view: UIView, edge: UIRectEdge, useMargin: Bool) { @@ -56,26 +49,33 @@ import UIKit // MARK: - MVMCoreViewProtocol open override func setupView() { super.setupView() - backgroundColor = .black heightConstraint = heightAnchor.constraint(equalToConstant: 1) heightConstraint?.isActive = true + setStyle(.standard) } // MARK: - MVMCoreUIMoleculeViewProtocol open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { // If no type, default to standard. - if let typeString = json?.optionalStringForKey(KeyType), let type = Style.init(rawValue: typeString) { - style = type + if let typeString = json?.optionalStringForKey(KeyType), let type = LineModel.Style.init(rawValue: typeString) { + setStyle(type) } else { - style = .standard + setStyle(.standard) } super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) } + open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + if let lineModel = model as? LineModel { + setStyle(lineModel.type ?? .standard) + } + super.setWithModel(model, delegateObject, additionalData) + } + open override func reset() { - style = .standard + setStyle(.standard) } open func copyBackgroundColor() -> Bool { @@ -83,7 +83,7 @@ import UIKit } public static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - guard let type = json?.optionalStringForKey(KeyType), let style = Style(rawValue: type) else { return 1 } + guard let type = json?.optionalStringForKey(KeyType), let style = LineModel.Style(rawValue: type) else { return 1 } switch style { case .none: return 0 diff --git a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift index 95b00cd7..7be1187a 100644 --- a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift +++ b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift @@ -209,7 +209,7 @@ import UIKit } } - public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { guard let imageModel = model as? ImageViewModel else { return } @@ -289,7 +289,7 @@ import UIKit self?.addConstraints(width: width, height: height, size: image?.size) self?.loadingSpinnerHeightConstraint?.constant = 0 if layoutWillChange { - self?.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated?(self!) + self?.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self!) } completionHandler(image,data,isFallbackImage) })} diff --git a/MVMCoreUI/Atoms/Views/MFView+ModelExtension.swift b/MVMCoreUI/Atoms/Views/MFView+ModelExtension.swift index bfeb7312..2ba216d7 100644 --- a/MVMCoreUI/Atoms/Views/MFView+ModelExtension.swift +++ b/MVMCoreUI/Atoms/Views/MFView+ModelExtension.swift @@ -9,16 +9,16 @@ import Foundation extension MFView { - public func setUpDefaultWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String: AnyHashable]?) { + public func setUpDefaultWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { self.model = model - if let backgroundColorString = model?.backgroundColor { - backgroundColor = UIColor.mfGet(for: backgroundColorString) + if let backgroundColor = model?.backgroundColor { + self.backgroundColor = backgroundColor.uiColor } } } extension ModelMoleculeViewProtocol where Self: MFView { - func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String: AnyHashable]?) { + func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { setUpDefaultWithModel(model, delegateObject, additionalData) } } diff --git a/MVMCoreUI/Atoms/Views/MultiProgress.swift b/MVMCoreUI/Atoms/Views/MultiProgress.swift index 6f35bcc5..e5978c9c 100644 --- a/MVMCoreUI/Atoms/Views/MultiProgress.swift +++ b/MVMCoreUI/Atoms/Views/MultiProgress.swift @@ -8,8 +8,11 @@ import UIKit -@objcMembers open class MultiProgress: ViewConstrainingView, ModelMoleculeViewProtocol { - +@objcMembers open class MultiProgress: View { + var multiProgressModel: MultiProgressBarModel? { + get { return model as? MultiProgressBarModel } + } + ///passing value to progressList creates corresponding progress bars var progressList: Array? { didSet { @@ -27,7 +30,7 @@ import UIKit let view = UIView(frame: .zero) view.translatesAutoresizingMaskIntoConstraints = false addSubview(view) - view.backgroundColor = UIColor.mfGet(forHex: progressObject.color) + view.backgroundColor = progressObject.color.uiColor view.widthAnchor.constraint(equalTo: widthAnchor, multiplier: progressObject.progress).isActive = true view.leadingAnchor.constraint(equalTo: previous?.trailingAnchor ?? leadingAnchor).isActive = true previous = view @@ -60,8 +63,10 @@ import UIKit } } - public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { - guard let multiProgressModel = model as? MultiProgressBarModel else { + //MARK: - MVMCoreMoleculeViewProtocol + public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.setWithModel(model, delegateObject, additionalData) + guard let multiProgressModel = multiProgressModel else { return } roundedRect = multiProgressModel.roundedRect ?? false @@ -76,9 +81,8 @@ import UIKit progressList = nil } - override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - thicknessConstraint?.constant = json?.optionalCGFloatForKey("thickness") ?? defaultHeight - roundedRect = json?.optionalBoolForKey("roundedRect") ?? false + public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + guard let json = json, let model = try? Self.decodeJSONToModel(json: json, type: MultiProgressBarModel.self) else { return } + setWithModel(model, delegateObject, additionalData) } } diff --git a/MVMCoreUI/Atoms/Views/MultiProgressModel.swift b/MVMCoreUI/Atoms/Views/MultiProgressModel.swift index 25522070..b0251ff6 100644 --- a/MVMCoreUI/Atoms/Views/MultiProgressModel.swift +++ b/MVMCoreUI/Atoms/Views/MultiProgressModel.swift @@ -8,41 +8,47 @@ import Foundation - @objcMembers public class SingleProgressBarModel: Codable { - var progress: CGFloat - var color: String + @Percent var progress: CGFloat + var color: Color + + init(_ progress: CGFloat, color: Color) { + self.progress = progress + self.color = color + } } @objcMembers public class MultiProgressBarModel: MoleculeProtocol { public static var identifier: String = "multiProgressBar" - public var moleculeName: String - public var backgroundColor: String? public var progressList: [SingleProgressBarModel] + public var backgroundColor: Color? public var thickness: CGFloat? public var roundedRect: Bool? enum CodingKeys: String, CodingKey { - case moleculeName case progressList case thickness case roundedRect + case backgroundColor + } + + public init(_ progressList: [SingleProgressBarModel]) { + self.progressList = progressList } required public init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - self.moleculeName = try typeContainer.decode(String.self, forKey: .moleculeName) - self.progressList = try typeContainer.decode([SingleProgressBarModel].self, forKey: .progressList) - self.thickness = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .thickness) - self.roundedRect = try typeContainer.decodeIfPresent(Bool.self, forKey: .roundedRect) + 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) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(moleculeName, forKey: .moleculeName) - try container.encodeIfPresent(progressList, forKey: .progressList) + try container.encode(progressList, forKey: .progressList) try container.encodeIfPresent(thickness, forKey: .thickness) try container.encodeIfPresent(roundedRect, forKey: .roundedRect) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) } } diff --git a/MVMCoreUI/Atoms/Views/ProgressBar.swift b/MVMCoreUI/Atoms/Views/ProgressBar.swift index 79e64fcc..bbf5a5de 100644 --- a/MVMCoreUI/Atoms/Views/ProgressBar.swift +++ b/MVMCoreUI/Atoms/Views/ProgressBar.swift @@ -9,11 +9,12 @@ import Foundation @objcMembers open class ProgressBar: UIProgressView, MVMCoreViewProtocol, ModelMoleculeViewProtocol, MVMCoreUIMoleculeViewProtocol { - var isRounded = false + var progressBarModel: ProgressBarModel? + var thickness: CGFloat = 8.0 { willSet(newValue) { heightAnchor.constraint(equalToConstant: newValue).isActive = true - if isRounded { + if progressBarModel?.isRounded ?? false { layer.cornerRadius = newValue/2.0 } else { progressViewStyle = .bar @@ -40,7 +41,6 @@ import Foundation public func setupView() { clipsToBounds = true translatesAutoresizingMaskIntoConstraints = false - isRounded = false thickness = 8 progress = 0 progressTintColor = UIColor.mfCerulean() @@ -50,43 +50,26 @@ import Foundation public func updateView(_ size: CGFloat) { } - public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String: AnyHashable]?) { + //MARK: - MVMCoreMoleculeViewProtocol + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { guard let progressBarModel = model as? ProgressBarModel else { return } - isRounded = progressBarModel.isRounded ?? false thickness = progressBarModel.thickness ?? 8 - progress = (progressBarModel.percentage ?? 0)/100.0 - if let progressColor = progressBarModel.progressColor { - progressTintColor = UIColor.mfGet(forHex: progressColor) - } + progress = Float((progressBarModel.percent)/100.0) + progressTintColor = progressBarModel.progressColor.uiColor if let backgroundColor = progressBarModel.backgroundColor { - trackTintColor = UIColor.mfGet(forHex: backgroundColor) + trackTintColor = backgroundColor.uiColor } } // MARK: - MVMCoreUIMoleculeViewProtocol - public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - if let isRounded = json?.optionalBoolForKey("roundedRect") { - self.isRounded = isRounded - } - if let thickness = json?.optionalCGFloatForKey("thickness") { - self.thickness = thickness - } - // as? Float returns nil, apple defect. - if let percentage = json?["percent"] as? CGFloat { - progress = Float(percentage/100.0) - } - if let progressColor = json?.optionalStringForKey("progressColor") { - progressTintColor = UIColor.mfGet(forHex: progressColor) - } - if let backgroundColor = json?.optionalStringForKey("backgroundColor") { - trackTintColor = UIColor.mfGet(forHex: backgroundColor) - } + public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + guard let json = json, let model = try? Self.decodeJSONToModel(json: json, type: ProgressBarModel.self) else { return } + setWithModel(model, delegateObject, additionalData) } public func reset() { - isRounded = false thickness = 8 progress = 0 progressTintColor = UIColor.mfCerulean() diff --git a/MVMCoreUI/Atoms/Views/ProgressBarModel.swift b/MVMCoreUI/Atoms/Views/ProgressBarModel.swift index 3450fc87..1850c411 100644 --- a/MVMCoreUI/Atoms/Views/ProgressBarModel.swift +++ b/MVMCoreUI/Atoms/Views/ProgressBarModel.swift @@ -10,42 +10,45 @@ import Foundation @objcMembers public class ProgressBarModel: MoleculeProtocol { public static var identifier: String = "progressbar" - public var moleculeName: String - + @Percent public var percent: CGFloat + public var progressColor: Color = Color(uiColor: .mfCerulean()) + public var backgroundColor: Color? = Color(uiColor: .mfLightSilver()) public var isRounded: Bool? public var thickness: CGFloat? - ///from 0 to 100 - public var percentage: Float - public var progressColor: String? - public var backgroundColor: String? enum CodingKeys: String, CodingKey { case moleculeName case isRounded = "roundRect" case thickness - case percentage = "percent" + case percent case progressColor case backgroundColor } + public init(_ percent: CGFloat) { + self.percent = percent + } + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - self.moleculeName = try typeContainer.decode(String.self, forKey: .moleculeName) - self.isRounded = try typeContainer.decodeIfPresent(Bool.self, forKey: .isRounded) - self.thickness = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .thickness) - self.percentage = try typeContainer.decode(Float.self, forKey: .percentage) - self.progressColor = try typeContainer.decodeIfPresent(String.self, forKey: .progressColor) - self.backgroundColor = try typeContainer.decodeIfPresent(String.self, forKey: .backgroundColor) - + 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: .backgroundColor) { + backgroundColor = color + } + isRounded = try typeContainer.decodeIfPresent(Bool.self, forKey: .isRounded) + thickness = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .thickness) } public func encode(to encoder: Encoder) throws { 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.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(isRounded, forKey: .isRounded) try container.encodeIfPresent(thickness, forKey: .thickness) - try container.encodeIfPresent(percentage, forKey: .percentage) - try container.encodeIfPresent(progressColor, forKey: .progressColor) - try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) } } diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView+ModelExtension.swift b/MVMCoreUI/Atoms/Views/ViewConstrainingView+ModelExtension.swift deleted file mode 100644 index 6a6bf03f..00000000 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView+ModelExtension.swift +++ /dev/null @@ -1,89 +0,0 @@ -// -// ViewConstrainingView+ModelExtension.swift -// MVMCoreUI -// -// Created by Suresh, Kamlesh on 11/20/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import Foundation - -extension ViewConstrainingView { - public func setUpWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String: AnyHashable]?) { - if self.constrainedView == nil { - setUpDefaultWithModel(model, delegateObject, additionalData) - } - - if shouldSetupMoleculeFromJSON, - let moleculeObject = (model as? MoleculeContainerModel)?.molecule { - if molecule != nil { - (molecule as? ModelMoleculeViewProtocol)?.setWithModel(moleculeObject, delegateObject, additionalData) - } else { - if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(moleculeObject, delegateObject, true) { - addMolecule(molecule) - self.molecule = molecule - setMoleculeAccessibility() - } - } - } else { - (molecule as? ModelMoleculeViewProtocol)?.setWithModel(model, delegateObject, additionalData) - } - - if let containerMoleculeModel = model as? ContainerModelProtocol { - if let useHorizontalMargins = containerMoleculeModel.useHorizontalMargins { - updateViewHorizontalDefaults = useHorizontalMargins - } - if let useVerticalMargins = containerMoleculeModel.useVerticalMargins { - updateViewVerticalDefaults = useVerticalMargins - } - - if let horizontalAlignment = containerMoleculeModel.horizontalAlignment { - alignHorizontal(horizontalAlignment) - } - if let verticalAlignment = containerMoleculeModel.verticalAlignment { - alignVertical(verticalAlignment) - } - } - - #warning("work on the below") - // let copyBackgroundColor = self.copyBackgroundColor?() - // if copyBackgroundColor { - // - // } - } -} - -extension ModelMoleculeViewProtocol where Self: ViewConstrainingView { - public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String: AnyHashable]?) { - setUpWithModel(model, delegateObject, additionalData) - } -} - -/* -- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { - // Only treated as a container if we are constraining a molecule. - - NSNumber *useHorizontalMargins = [json optionalNumberForKey:@"useHorizontalMargins"]; - if (useHorizontalMargins) { - self.updateViewHorizontalDefaults = [useHorizontalMargins boolValue]; - } - NSNumber *useVerticalMargins = [json optionalNumberForKey:@"useVerticalMargins"]; - if (useVerticalMargins) { - self.updateViewVerticalDefaults = [useVerticalMargins boolValue]; - } - - // Set the alignment for the stack in the containing view. The json driven value is for the axis direction alignment. - NSString *alignment = [json string:@"horizontalAlignment"]; - if (alignment) { - [self alignHorizontal:[ViewConstrainingView getAlignmentForString:alignment defaultAlignment:UIStackViewAlignmentFill]]; - } - alignment = [json string:@"verticalAlignment"]; - if (alignment) { - [self alignVertical:[ViewConstrainingView getAlignmentForString:alignment defaultAlignment:UIStackViewAlignmentFill]]; - } - - if ([self.molecule respondsToSelector:@selector(copyBackgroundColor)] && [self.molecule performSelector:@selector(copyBackgroundColor)]) { - self.backgroundColor = self.molecule.backgroundColor; - } -} -*/ diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m index 1de41832..54a12612 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m @@ -342,8 +342,8 @@ self.updateViewVerticalDefaults = NO; self.topMarginPadding = PaddingDefaultVerticalSpacing3; self.bottomMarginPadding = PaddingDefaultVerticalSpacing3; - if ([self.molecule respondsToSelector:@selector(alignment)]) { - [self alignHorizontal:[(UIView *)self.molecule alignment]]; + if ([self.molecule respondsToSelector:@selector(horizontalAlignment)]) { + [self alignHorizontal:[(UIView *)self.molecule horizontalAlignment]]; } [self alignVertical:UIStackViewAlignmentFill]; if ([self.molecule respondsToSelector:@selector(reset)]) { @@ -352,45 +352,6 @@ } - (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { - // Only treated as a container if we are constraining a molecule. - if (!self.constrainedView) { - [super setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; - } - if (self.shouldSetupMoleculeFromJSON) { - NSDictionary *moleculeJSON = [json dict:KeyMolecule]; - if (self.molecule) { - [self.molecule setWithJSON:moleculeJSON delegateObject:delegateObject additionalData:additionalData]; - } else if (moleculeJSON) { - UIView *molecule = [[MVMCoreUIMoleculeMappingObject sharedMappingObject] createMoleculeForJSON:moleculeJSON delegateObject:delegateObject constrainIfNeeded:true]; - if (molecule) { - [self addMolecule:molecule]; - } - self.molecule = molecule; - [self setMoleculeAccessibility]; - } - } else { - [self.molecule setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; - } - - NSNumber *useHorizontalMargins = [json optionalNumberForKey:@"useHorizontalMargins"]; - if (useHorizontalMargins) { - self.updateViewHorizontalDefaults = [useHorizontalMargins boolValue]; - } - NSNumber *useVerticalMargins = [json optionalNumberForKey:@"useVerticalMargins"]; - if (useVerticalMargins) { - self.updateViewVerticalDefaults = [useVerticalMargins boolValue]; - } - - // Set the alignment for the stack in the containing view. The json driven value is for the axis direction alignment. - NSString *alignment = [json string:@"horizontalAlignment"]; - if (alignment) { - [self alignHorizontal:[ViewConstrainingView getAlignmentForString:alignment defaultAlignment:UIStackViewAlignmentFill]]; - } - alignment = [json string:@"verticalAlignment"]; - if (alignment) { - [self alignVertical:[ViewConstrainingView getAlignmentForString:alignment defaultAlignment:UIStackViewAlignmentFill]]; - } - if ([self.molecule respondsToSelector:@selector(copyBackgroundColor)] && [self.molecule performSelector:@selector(copyBackgroundColor)]) { self.backgroundColor = self.molecule.backgroundColor; } diff --git a/MVMCoreUI/BaseClasses/Control.swift b/MVMCoreUI/BaseClasses/Control.swift index 0b03ba27..915e0891 100644 --- a/MVMCoreUI/BaseClasses/Control.swift +++ b/MVMCoreUI/BaseClasses/Control.swift @@ -8,13 +8,14 @@ import UIKit -@objcMembers open class Control: UIControl { +@objcMembers open class Control: UIControl, ModelMoleculeViewProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- public var json: [AnyHashable: Any]? - + public var model: MoleculeProtocol? + private var initialSetupPerformed = false //-------------------------------------------------- @@ -47,6 +48,14 @@ import UIKit setupView() } } + + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + self.model = model + if let backgroundColor = model?.backgroundColor { + self.backgroundColor = backgroundColor.uiColor + } + } + } // MARK: - AppleGuidelinesProtocol diff --git a/MVMCoreUI/BaseClasses/View.swift b/MVMCoreUI/BaseClasses/View.swift index 9b194d48..45631d93 100644 --- a/MVMCoreUI/BaseClasses/View.swift +++ b/MVMCoreUI/BaseClasses/View.swift @@ -40,10 +40,10 @@ import UIKit return model?.moleculeName } - open func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + open func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { self.model = model - if let backgroundColorString = model?.backgroundColor { - backgroundColor = UIColor.mfGet(for: backgroundColorString) + if let backgroundColor = model?.backgroundColor { + self.backgroundColor = backgroundColor.uiColor } } } @@ -70,4 +70,8 @@ extension View: MVMCoreUIMoleculeViewProtocol { open func reset() { backgroundColor = .clear } + + open func setAsMolecule() { + + } } diff --git a/MVMCoreUI/BaseControllers/MFViewController+Model.swift b/MVMCoreUI/BaseControllers/MFViewController+Model.swift index 924ce4c7..88f05360 100644 --- a/MVMCoreUI/BaseControllers/MFViewController+Model.swift +++ b/MVMCoreUI/BaseControllers/MFViewController+Model.swift @@ -8,19 +8,30 @@ import Foundation +extension MFViewController: MoleculeDelegateProtocol { + public func getModuleWithName(_ name: String?) -> [AnyHashable : Any]? { + guard let name = name else { + return nil + } + return loadObject?.modulesJSON?.optionalDictionaryForKey(name) + } -public extension MFViewController { - @objc func parsePageJSON() { - guard let pageJSON = loadObject?.pageJSON as? [String: AnyHashable] else { - return + public func getModuleWithName(_ moduleName: String) -> MoleculeProtocol? { + guard let moduleJSON = loadObject?.modulesJSON?.optionalDictionaryForKey(moduleName), + let moleculeName = moduleJSON.optionalStringForKey("moleculeName"), + let modelType = ModelRegistry.getType(for: moleculeName) as? MoleculeProtocol.Type else { + return nil } do { - let pageData = try JSONSerialization.data(withJSONObject: pageJSON) - let decoder = JSONDecoder() - let pageModel = try decoder.decode(PageModel.self, from: pageData) - self.pageModel = pageModel + return try modelType.decode(jsonDict: moduleJSON) } catch { MVMCoreUILoggingHandler.logDebugMessage(withDelegate: "error: \(error)") } + return nil + } +} + +public extension MFViewController { + @objc func parsePageJSON() { } } diff --git a/MVMCoreUI/BaseControllers/MFViewController.h b/MVMCoreUI/BaseControllers/MFViewController.h index be8c3bd2..cd96a07f 100644 --- a/MVMCoreUI/BaseControllers/MFViewController.h +++ b/MVMCoreUI/BaseControllers/MFViewController.h @@ -27,21 +27,17 @@ #import #import #import -#import @class MainMenuViewController; @class MVMCoreUITabBarPageControlViewController; @class MVMAnimationManager; @class DelegateObject; -@class PageModel; -@interface MFViewController : UIViewController +@interface MFViewController : UIViewController // Stores the load object that this screen was loaded with. @property (nullable, strong, nonatomic) MVMCoreLoadObject *loadObject; -@property (nullable, strong, nonatomic) PageModel *pageModel; - // The current selected text field. @property (nullable, weak, nonatomic) __block id selectedField; diff --git a/MVMCoreUI/BaseControllers/MFViewController.m b/MVMCoreUI/BaseControllers/MFViewController.m index 153af17f..1d97efd9 100644 --- a/MVMCoreUI/BaseControllers/MFViewController.m +++ b/MVMCoreUI/BaseControllers/MFViewController.m @@ -834,15 +834,6 @@ } } -#pragma mark - MoleculeDelegateProtocol - -- (NSDictionary *)getModuleWithName:(NSString *)name { - if (!name) { - return nil; - } - return [self.loadObject.modulesJSON dict:name]; -} - #pragma mark - adobe analytics - (nullable NSArray *)additionalActionsToTrackWithMainActionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData { diff --git a/MVMCoreUI/Containers/Container.swift b/MVMCoreUI/Containers/Container.swift index f3f38899..ab495b81 100644 --- a/MVMCoreUI/Containers/Container.swift +++ b/MVMCoreUI/Containers/Container.swift @@ -172,11 +172,11 @@ public class ContainerHelper: NSObject { MFStyler.setMarginsFor(view, size: size, defaultHorizontal: model?.useHorizontalMargins ?? false, top: (model?.useVerticalMargins ?? false) ? (model?.topMarginPadding ?? 0) : 0, bottom: (model?.useVerticalMargins ?? false) ? (model?.bottomMarginPadding ?? 0) : 0) } - func set(with model: ContainerModelProtocol) { - if let horizontalAlignment = model.horizontalAlignment { + func set(with model: ContainerModelProtocol, for contained: MVMCoreUIViewConstrainingProtocol?) { + if let horizontalAlignment = model.horizontalAlignment ?? contained?.horizontalAlignment?() { alignHorizontal(horizontalAlignment) } - if let verticalAlignment = model.verticalAlignment { + if let verticalAlignment = model.verticalAlignment ?? contained?.verticalAlignment?() { alignVertical(verticalAlignment) } } @@ -203,10 +203,10 @@ open class Container: View { get { return model as? ContainerModelProtocol } } - override open func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + override open func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.setWithModel(model, delegateObject, additionalData) guard let containerModel = model as? ContainerModelProtocol else { return } - containerHelper.set(with: containerModel) + containerHelper.set(with: containerModel, for: view as? MVMCoreUIViewConstrainingProtocol) } } @@ -250,7 +250,7 @@ public extension Container { (view as? MVMCoreUIMoleculeViewProtocol)?.reset?() } - func setAsMolecule() { + override func setAsMolecule() { (view as? MVMCoreUIMoleculeViewProtocol)?.setAsMolecule?() } } diff --git a/MVMCoreUI/Containers/NavigationController.swift b/MVMCoreUI/Containers/NavigationController.swift index 353ea861..623b2f47 100644 --- a/MVMCoreUI/Containers/NavigationController.swift +++ b/MVMCoreUI/Containers/NavigationController.swift @@ -29,7 +29,7 @@ import UIKit let navigationController = self.init() style(navigationController.navigationBar) navigationController.separatorView = Line(pinTo: navigationController.navigationBar, edge: .bottom, useMargin: false) - navigationController.separatorView?.style = .standard + navigationController.separatorView?.setStyle(.standard) MVMCoreUISession.sharedGlobal()?.navigationController = navigationController MVMCoreNavigationHandler.shared()?.viewControllerToPresentOn = navigationController MVMCoreNavigationHandler.shared()?.navigationController = navigationController diff --git a/MVMCoreUI/MVMCoreUI.h b/MVMCoreUI/MVMCoreUI.h index 795298b3..a71be907 100644 --- a/MVMCoreUI/MVMCoreUI.h +++ b/MVMCoreUI/MVMCoreUI.h @@ -20,8 +20,6 @@ FOUNDATION_EXPORT const unsigned char MVMCoreUIVersionString[]; #import #import #import -#import -#import #import #pragma mark - TopAlert diff --git a/MVMCoreUI/Models/Extensions/ModelHelper.swift b/MVMCoreUI/Models/Extensions/ModelHelper.swift index 7c73f264..72bb5f8f 100644 --- a/MVMCoreUI/Models/Extensions/ModelHelper.swift +++ b/MVMCoreUI/Models/Extensions/ModelHelper.swift @@ -35,4 +35,17 @@ extension KeyedDecodingContainer where Key : CodingKey { public func decodeMoleculesIfPresent(codingKey: KeyedDecodingContainer.Key) throws -> [MoleculeProtocol]? { return try decodeModelsIfPresent(codingKey: codingKey, typeCodingKey: TypeCodingKey.moleculeName) as? [MoleculeProtocol] } + + /// Decodes an array with arrays of molecules based on the identifiers, optional. + public func decodeMolecules2DIfPresent(codingKey: KeyedDecodingContainer.Key) throws -> [[MoleculeProtocol]]? { + return try decodeModels2DIfPresent(codingKey: codingKey, typeCodingKey: TypeCodingKey.moleculeName) as? [[MoleculeProtocol]] + } + + /// Decodes an array with arrays of models based on the identifiers. + public func decodeMolecules2D(codingKey: KeyedDecodingContainer.Key) throws -> [[MoleculeProtocol]] { + guard let models = try decodeModels2D(codingKey: codingKey, typeCodingKey: TypeCodingKey.moleculeName) as? [[MoleculeProtocol]] else { + throw ModelRegistry.Error.decoderError + } + return models + } } diff --git a/MVMCoreUI/Models/ModelProtocols/CollectionCellMoleculeProtocol.swift b/MVMCoreUI/Models/ModelProtocols/CollectionCellMoleculeProtocol.swift new file mode 100644 index 00000000..3dbdc694 --- /dev/null +++ b/MVMCoreUI/Models/ModelProtocols/CollectionCellMoleculeProtocol.swift @@ -0,0 +1,14 @@ +// +// CollectionCellMoleculeProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/26/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol CollectionCellMoleculeProtocol: ContainerModelProtocol, MoleculeProtocol { + var peakingUI: Bool? {get} + var peakingArrowColor: Color? {get} +} diff --git a/MVMCoreUI/Models/Molecules/FormModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/FormModelProtocol.swift similarity index 100% rename from MVMCoreUI/Models/Molecules/FormModelProtocol.swift rename to MVMCoreUI/Models/ModelProtocols/FormModelProtocol.swift diff --git a/MVMCoreUI/Models/ModelProtocols/ListItemModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/ListItemModelProtocol.swift new file mode 100644 index 00000000..7a990d61 --- /dev/null +++ b/MVMCoreUI/Models/ModelProtocols/ListItemModelProtocol.swift @@ -0,0 +1,35 @@ +// +// ListItemModelProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 12/12/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol ListItemModelProtocol: ContainerModelProtocol, MoleculeProtocol { + var line: LineModel? { get set } + var action: ActionProtocol? { get set } + var hideArrow: Bool? { get set } + var style: String? { get set } +} + +// Not a strict requirement. +extension ListItemModelProtocol { + public var action: ActionProtocol? { + get { + return nil + } + set { + } + } + + public var style: String? { + get { + return nil + } + set { + } + } +} diff --git a/MVMCoreUI/Models/MoleculeProtocol.swift b/MVMCoreUI/Models/ModelProtocols/MoleculeProtocol.swift similarity index 55% rename from MVMCoreUI/Models/MoleculeProtocol.swift rename to MVMCoreUI/Models/ModelProtocols/MoleculeProtocol.swift index 53f0fee4..b8117e60 100644 --- a/MVMCoreUI/Models/MoleculeProtocol.swift +++ b/MVMCoreUI/Models/ModelProtocols/MoleculeProtocol.swift @@ -2,16 +2,11 @@ import Foundation public protocol MoleculeProtocol: Model { var moleculeName: String? { get } - var backgroundColor: String? { get } - var dictionary: [AnyHashable: Any]? { get } + var backgroundColor: Color? { get set} } extension MoleculeProtocol { public var moleculeName: String? { get { return Self.identifier } } - - public var dictionary: [AnyHashable: Any]? { - return toJSON() - } } diff --git a/MVMCoreUI/Models/ModelProtocols/PageModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/PageModelProtocol.swift new file mode 100644 index 00000000..8c6d1557 --- /dev/null +++ b/MVMCoreUI/Models/ModelProtocols/PageModelProtocol.swift @@ -0,0 +1,15 @@ +// +// PageModelProtocol.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 1/9/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol PageModelProtocol: Model { + var pageType: String { get set } + var screenHeading: String? { get set } + var isAtomicTabs: Bool? { get set } +} diff --git a/MVMCoreUI/Models/ModelProtocols/PagingMoleculeProtocol.swift b/MVMCoreUI/Models/ModelProtocols/PagingMoleculeProtocol.swift new file mode 100644 index 00000000..af1ce14a --- /dev/null +++ b/MVMCoreUI/Models/ModelProtocols/PagingMoleculeProtocol.swift @@ -0,0 +1,13 @@ +// +// PagingMoleculeProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/25/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol PagingMoleculeProtocol: MoleculeProtocol { + var position: Float? {get} +} diff --git a/MVMCoreUI/Models/ModelProtocols/TemplateModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/TemplateModelProtocol.swift new file mode 100644 index 00000000..66472da6 --- /dev/null +++ b/MVMCoreUI/Models/ModelProtocols/TemplateModelProtocol.swift @@ -0,0 +1,19 @@ +// +// TemplateModelProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/22/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol TemplateModelProtocol: PageModelProtocol { + var template: String { get } +} + +extension TemplateModelProtocol { + public var template: String { + get { return Self.identifier } + } +} diff --git a/MVMCoreUI/Models/ModelProtocols/TemplateProtocol.swift b/MVMCoreUI/Models/ModelProtocols/TemplateProtocol.swift new file mode 100644 index 00000000..eb4463d5 --- /dev/null +++ b/MVMCoreUI/Models/ModelProtocols/TemplateProtocol.swift @@ -0,0 +1,28 @@ +// +// ModelTemplateProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/25/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol TemplateProtocol: class { + associatedtype TemplateModel: TemplateModelProtocol + var templateModel: TemplateModel? { get set } +} + +public extension TemplateProtocol where Self: MFViewController { + func parseTemplateJSON() { + guard let pageJSON = self.loadObject?.pageJSON else { return } + do { + let data = try JSONSerialization.data(withJSONObject: pageJSON) + let decoder = JSONDecoder() + let templateModel = try decoder.decode(TemplateModel.self, from: data) + self.templateModel = templateModel + } catch { + MVMCoreUILoggingHandler.logDebugMessage(withDelegate: "error: \(error)") + } + } +} diff --git a/MVMCoreUI/Models/Molecules/CarouselItemModel.swift b/MVMCoreUI/Models/Molecules/CarouselItemModel.swift new file mode 100644 index 00000000..e86b89c3 --- /dev/null +++ b/MVMCoreUI/Models/Molecules/CarouselItemModel.swift @@ -0,0 +1,39 @@ +// +// CarouselItemModel.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/26/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + + +@objcMembers public class CarouselItemModel: MoleculeContainerModel, CollectionCellMoleculeProtocol { + public static var identifier: String = "carouselItem" + public var backgroundColor: Color? + public var peakingUI: Bool? + public var peakingArrowColor: Color? + + enum CarouselItemCodingKeys: String, CodingKey { + case backgroundColor + case peakingUI + case peakingArrowColor + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CarouselItemCodingKeys.self) + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + peakingUI = try typeContainer.decodeIfPresent(Bool.self, forKey: .peakingUI) + peakingArrowColor = try typeContainer.decodeIfPresent(Color.self, forKey: .peakingArrowColor) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CarouselItemCodingKeys.self) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + try container.encodeIfPresent(peakingUI, forKey: .peakingUI) + try container.encodeIfPresent(peakingArrowColor, forKey: .peakingArrowColor) + } +} diff --git a/MVMCoreUI/Models/Molecules/CarouselModel.swift b/MVMCoreUI/Models/Molecules/CarouselModel.swift new file mode 100644 index 00000000..9b55f97a --- /dev/null +++ b/MVMCoreUI/Models/Molecules/CarouselModel.swift @@ -0,0 +1,67 @@ +// +// CarouselModel.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/25/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers public class CarouselModel: MoleculeProtocol { + public static var identifier: String = "carousel" + public var backgroundColor: Color? + public var molecules: [CarouselItemModel] + + public var spacing: Float? + public var border: Bool? + public var loop: Bool? + public var height: Float? + public var itemWidthPercent: Float? + public var itemAlignment: String? + public var pagingMolecule: PagingMoleculeProtocol? + + public init(molecules: [CarouselItemModel]){ + self.molecules = molecules + } + + enum CodingKeys: String, CodingKey { + case moleculeName + case backgroundColor + case molecules + case spacing + case border + case loop + case height + case itemWidthPercent + case itemAlignment + case pagingMolecule + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + self.molecules = try typeContainer.decode([CarouselItemModel].self, forKey: .molecules) + self.backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + self.spacing = try typeContainer.decode(Float.self, forKey: .spacing) + self.border = try typeContainer.decode(Bool.self, forKey: .border) + self.loop = try typeContainer.decode(Bool.self, forKey: .loop) + self.height = try typeContainer.decode(Float.self, forKey: .height) + self.itemWidthPercent = try typeContainer.decode(Float.self, forKey: .itemWidthPercent) + self.itemAlignment = try typeContainer.decode(String.self, forKey: .itemAlignment) + self.pagingMolecule = try typeContainer.decodeMoleculeIfPresent(codingKey: .pagingMolecule) as? PagingMoleculeProtocol + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(moleculeName, forKey: .moleculeName) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + try container.encode(molecules, forKey: .molecules) + try container.encode(spacing, forKey: .spacing) + try container.encode(border, forKey: .border) + try container.encode(loop, forKey: .loop) + try container.encode(height, forKey: .height) + try container.encode(itemWidthPercent, forKey: .itemWidthPercent) + try container.encode(itemAlignment, forKey: .itemAlignment) + try container.encodeModelIfPresent(pagingMolecule, forKey: .pagingMolecule) + } +} diff --git a/MVMCoreUI/Models/Molecules/DoughnutChartModel.swift b/MVMCoreUI/Models/Molecules/DoughnutChartModel.swift index 15ecab85..7aab35fd 100644 --- a/MVMCoreUI/Models/Molecules/DoughnutChartModel.swift +++ b/MVMCoreUI/Models/Molecules/DoughnutChartModel.swift @@ -9,7 +9,7 @@ import Foundation @objcMembers public class DoughnutChartModel: MoleculeProtocol { - public var backgroundColor: String? + public var backgroundColor: Color? public static var identifier: String = "doughnutChart" public var title: LabelModel? public var subtitle: LabelModel? @@ -20,7 +20,7 @@ import Foundation @objcMembers public class ChartItemModel: MoleculeProtocol { - public var backgroundColor: String? + public var backgroundColor: Color? public var label: LabelModel public var percent: CGFloat public var color: String diff --git a/MVMCoreUI/Models/Molecules/DropDownModel.swift b/MVMCoreUI/Models/Molecules/DropDownModel.swift new file mode 100644 index 00000000..95caa2b6 --- /dev/null +++ b/MVMCoreUI/Models/Molecules/DropDownModel.swift @@ -0,0 +1,22 @@ +// +// DropDownModel.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 12/12/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + + +@objcMembers public class DropDownModel: MoleculeProtocol { + public static var identifier: String = "dropDownModel" + public var backgroundColor: Color? + public var label: String + public var options: [String] + + public init(label: String, options: [String]) { + self.label = label + self.options = options + } +} diff --git a/MVMCoreUI/Models/Molecules/FooterModel.swift b/MVMCoreUI/Models/Molecules/FooterModel.swift new file mode 100644 index 00000000..757e2fd5 --- /dev/null +++ b/MVMCoreUI/Models/Molecules/FooterModel.swift @@ -0,0 +1,31 @@ +// +// FooterModel.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/27/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + + +@objcMembers public class FooterModel: MoleculeContainerModel, MoleculeProtocol { + public static var identifier: String = "footer" + public var backgroundColor: Color? + + enum FooterCodingKeys: String, CodingKey { + case backgroundColor + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: FooterCodingKeys.self) + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: FooterCodingKeys.self) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + } +} diff --git a/MVMCoreUI/Models/Molecules/HeaderModel.swift b/MVMCoreUI/Models/Molecules/HeaderModel.swift index c28d7080..1e4ab9f2 100644 --- a/MVMCoreUI/Models/Molecules/HeaderModel.swift +++ b/MVMCoreUI/Models/Molecules/HeaderModel.swift @@ -10,19 +10,18 @@ import Foundation @objcMembers public class HeaderModel: MoleculeContainerModel, MoleculeProtocol { public static var identifier: String = "header" - public var moleculeName: String? - public var backgroundColor: String? + public var backgroundColor: Color? public var line: LineModel? enum HeaderCodingKeys: String, CodingKey { case moleculeName case line + case backgroundColor } required public init(from decoder: Decoder) throws { try super.init(from: decoder) let typeContainer = try decoder.container(keyedBy: HeaderCodingKeys.self) - moleculeName = try typeContainer.decode(String.self, forKey: .moleculeName) line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) // Default Values @@ -39,5 +38,6 @@ import Foundation var container = encoder.container(keyedBy: HeaderCodingKeys.self) try container.encode(moleculeName, forKey: .moleculeName) try container.encode(line, forKey: .line) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) } } diff --git a/MVMCoreUI/Models/Molecules/LabelModel.swift b/MVMCoreUI/Models/Molecules/LabelModel.swift index 0886524a..859627d5 100644 --- a/MVMCoreUI/Models/Molecules/LabelModel.swift +++ b/MVMCoreUI/Models/Molecules/LabelModel.swift @@ -11,5 +11,7 @@ import Foundation @objcMembers public class LabelModel: MoleculeProtocol { public static var identifier: String = "label" + public var moleculeName: String? public var text: String? + public var spacing: Int? } diff --git a/MVMCoreUI/Models/Molecules/LineModel.swift b/MVMCoreUI/Models/Molecules/LineModel.swift index e00ba1fc..88e09be0 100644 --- a/MVMCoreUI/Models/Molecules/LineModel.swift +++ b/MVMCoreUI/Models/Molecules/LineModel.swift @@ -9,11 +9,43 @@ import UIKit @objcMembers public class LineModel: MoleculeProtocol { + + /* + The frequency of the line in a moleculeList. + all (between all cells, above top, below bottom) + allExceptTop (between all cells, below bottom) + allExceptBottom (between all cells, above top) + between (between all cells) + */ + public enum Frequency: String, Codable { + case all + case allExceptTop + case allExceptBottom + case between + } + + /* + The style of the line. + standard (1 height, silver) + thin (1 height, black) + medium (2 height, black) + heavy (4 height, black) + none (hidden) + */ + public enum Style: String, Codable { + case standard + case thin + case medium + case heavy + case none + } + public static var identifier: String = "line" - public var backgroundColor: String? - public var type: String? - - public init(type: String?) { - self.type = type + public var type: Style? = .standard + public var frequency: Frequency? = .allExceptTop + public var backgroundColor: Color? + + public init(type: Style) { + self.type = type } } diff --git a/MVMCoreUI/Models/Molecules/ModuleMoleculeModel.swift b/MVMCoreUI/Models/Molecules/ModuleMoleculeModel.swift new file mode 100644 index 00000000..56259942 --- /dev/null +++ b/MVMCoreUI/Models/Molecules/ModuleMoleculeModel.swift @@ -0,0 +1,33 @@ +// +// ModuleMoleculeModel.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/26/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +open class ModuleMoleculeModel: MoleculeProtocol { + public var backgroundColor: Color? + public static var identifier: String = "moduleMolecule" + public var moduleName: String + + enum CodingKeys: String, CodingKey { + case moduleName + } + + public init(_ moduleName: String) { + self.moduleName = moduleName + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + moduleName = try typeContainer.decode(String.self, forKey:.moduleName) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moduleName, forKey: .moduleName) + } +} diff --git a/MVMCoreUI/Models/Molecules/TextFieldModel.swift b/MVMCoreUI/Models/Molecules/TextFieldModel.swift index f9b11d5f..3a76bbb3 100644 --- a/MVMCoreUI/Models/Molecules/TextFieldModel.swift +++ b/MVMCoreUI/Models/Molecules/TextFieldModel.swift @@ -11,10 +11,10 @@ import UIKit @objcMembers public class TextFieldModel: MoleculeProtocol, FormModelProtocol { public static var identifier: String = "textField" - public var backgroundColor: String? + public var backgroundColor: Color? - public var editable = true - public var disabled = false + public var editable: Bool? + public var disabled: Bool? public var errorMsg: String? public var label: String? public var type: String? diff --git a/MVMCoreUI/Models/PageModel.swift b/MVMCoreUI/Models/PageModel.swift deleted file mode 100644 index a47c78e1..00000000 --- a/MVMCoreUI/Models/PageModel.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// Page.swift -// MVMCoreUI -// -// Created by Suresh, Kamlesh on 10/23/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import UIKit - -@objcMembers public class PageModel: Codable { - public var template: String? - public var pageType: String? - public var screenHeading: String? - public var isAtomicTabs: Bool? = false - public var header: HeaderModel? - public var molecules: [ListItemModel]? - public var moleculeStack: MoleculeStackModel? -} diff --git a/MVMCoreUI/Models/Template/ListPageTemplateModel.swift b/MVMCoreUI/Models/Template/ListPageTemplateModel.swift new file mode 100644 index 00000000..61729c99 --- /dev/null +++ b/MVMCoreUI/Models/Template/ListPageTemplateModel.swift @@ -0,0 +1,67 @@ +// +// ListPageTemplate.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/22/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers public class ListPageTemplateModel: TemplateModelProtocol { + + public static var identifier: String = "listTemplate" + + public var pageType: String + public var screenHeading: String? + public var isAtomicTabs: Bool? + + public var header: MoleculeProtocol? + public var molecules: [ListItemModelProtocol] + public var footer: MoleculeProtocol? + public var line: LineModel? + + public init(pageType: String, screenHeading: String?, molecules: [ListItemModelProtocol]) { + self.pageType = pageType + self.screenHeading = screenHeading + self.molecules = molecules + } + + enum CodingKeys: String, CodingKey { + case moleculeName + case pageType + case screenHeading + case molecules + case header + case footer + case line + case isAtomicTabs + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + pageType = try typeContainer.decode(String.self, forKey: .pageType) + screenHeading = try typeContainer.decodeIfPresent(String.self, forKey: .screenHeading) + + guard let molecules = try typeContainer.decodeMolecules(codingKey: .molecules) as? [ListItemModelProtocol] else { + throw JSONError.pathNotFound + } + self.molecules = molecules + isAtomicTabs = try typeContainer.decodeIfPresent(Bool.self, forKey: .isAtomicTabs) + header = try typeContainer.decodeMoleculeIfPresent(codingKey: .header) + footer = try typeContainer.decodeMoleculeIfPresent(codingKey: .footer) + line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(pageType, forKey: .pageType) + try container.encodeIfPresent(screenHeading, forKey: .screenHeading) + try container.encodeModels(molecules, forKey: .molecules) + try container.encodeIfPresent(isAtomicTabs, forKey: .isAtomicTabs) + try container.encodeModelIfPresent(header, forKey: .header) + try container.encodeModelIfPresent(footer, forKey: .footer) + try container.encode(line, forKey: .line) + } +} + diff --git a/MVMCoreUI/Models/Template/StackCenteredPageTemplateModel.swift b/MVMCoreUI/Models/Template/StackCenteredPageTemplateModel.swift new file mode 100644 index 00000000..804103c4 --- /dev/null +++ b/MVMCoreUI/Models/Template/StackCenteredPageTemplateModel.swift @@ -0,0 +1,21 @@ +// +// StackCenteredPageTemplate.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/22/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers public class StackCenteredPageTemplateModel: TemplateModelProtocol { + + public static var identifier: String = "stackCenterTemplate" + + public var pageType: String + + public var screenHeading: String? + + public var isAtomicTabs: Bool? + +} diff --git a/MVMCoreUI/Models/Template/StackPageTemplateModel.swift b/MVMCoreUI/Models/Template/StackPageTemplateModel.swift new file mode 100644 index 00000000..9cce36ab --- /dev/null +++ b/MVMCoreUI/Models/Template/StackPageTemplateModel.swift @@ -0,0 +1,58 @@ +// +// StackPageTemplate.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/22/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + + +@objcMembers public class StackPageTemplateModel: TemplateModelProtocol { + public static var identifier: String = "moleculeStack" + + public var pageType: String + + public var screenHeading: String? + + public var isAtomicTabs: Bool? + + public var header: MoleculeProtocol? + public var moleculeStack: MoleculeStackModel + public var footer: MoleculeProtocol? + + public init(pageType: String, moleculeStack: MoleculeStackModel) { + self.pageType = pageType + self.moleculeStack = moleculeStack + } + + enum CodingKeys: String, CodingKey { + case pageType + case screenHeading + case header + case footer + case moleculeStack + case isAtomicTabs + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + pageType = try typeContainer.decode(String.self, forKey: .pageType) + moleculeStack = try typeContainer.decode(MoleculeStackModel.self, forKey: .moleculeStack) + screenHeading = try typeContainer.decodeIfPresent(String.self, forKey: .screenHeading) + isAtomicTabs = try typeContainer.decodeIfPresent(Bool.self, forKey: .isAtomicTabs) + header = try typeContainer.decodeMoleculeIfPresent(codingKey: .header) + footer = try typeContainer.decodeMoleculeIfPresent(codingKey: .footer) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(pageType, forKey: .pageType) + try container.encode(moleculeStack, forKey: .moleculeStack) + try container.encodeIfPresent(screenHeading, forKey: .screenHeading) + try container.encodeIfPresent(isAtomicTabs, forKey: .isAtomicTabs) + try container.encodeModelIfPresent(header, forKey: .header) + try container.encodeModelIfPresent(footer, forKey: .footer) + } +} diff --git a/MVMCoreUI/Models/Template/ThreeLayerPageTemplateModel.swift b/MVMCoreUI/Models/Template/ThreeLayerPageTemplateModel.swift new file mode 100644 index 00000000..5d4d1b25 --- /dev/null +++ b/MVMCoreUI/Models/Template/ThreeLayerPageTemplateModel.swift @@ -0,0 +1,59 @@ +// +// ThreeLayerPageTemplateModel.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/22/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers public class ThreeLayerPageTemplateModel: TemplateModelProtocol { + public static var identifier: String = "threeLayer" + + public var pageType: String + + public var screenHeading: String? + + public var isAtomicTabs: Bool? + + public var header: MoleculeProtocol? + public var middle: MoleculeProtocol? + public var footer: MoleculeProtocol? + + public init(pageType: String, header: MoleculeProtocol?, middle: MoleculeProtocol?, footer: MoleculeProtocol?) { + self.pageType = pageType + self.header = header + self.middle = middle + self.footer = footer + } + + enum CodingKeys: String, CodingKey { + case pageType + case screenHeading + case header + case footer + case middle + case isAtomicTabs + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + pageType = try typeContainer.decode(String.self, forKey: .pageType) + screenHeading = try typeContainer.decodeIfPresent(String.self, forKey: .screenHeading) + isAtomicTabs = try typeContainer.decodeIfPresent(Bool.self, forKey: .isAtomicTabs) + header = try typeContainer.decodeMoleculeIfPresent(codingKey: .header) + header = try typeContainer.decodeMoleculeIfPresent(codingKey: .middle) + footer = try typeContainer.decodeMoleculeIfPresent(codingKey: .footer) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(pageType, forKey: .pageType) + try container.encodeIfPresent(screenHeading, forKey: .screenHeading) + try container.encodeIfPresent(isAtomicTabs, forKey: .isAtomicTabs) + try container.encodeModelIfPresent(header, forKey: .header) + try container.encodeModelIfPresent(header, forKey: .middle) + try container.encodeModelIfPresent(footer, forKey: .footer) + } +} diff --git a/MVMCoreUI/Molecules/DoughnutChart.swift b/MVMCoreUI/Molecules/DoughnutChart.swift index ac19af7d..d7f25ac6 100644 --- a/MVMCoreUI/Molecules/DoughnutChart.swift +++ b/MVMCoreUI/Molecules/DoughnutChart.swift @@ -47,7 +47,7 @@ open class DoughnutChart: View, MVMCoreUIViewConstrainingProtocol { clearLayers() } - public func setAsMolecule() { + public override func setAsMolecule() { titleLabel.setAsMolecule() subTitleLabel.setAsMolecule() } @@ -93,8 +93,8 @@ open class DoughnutChart: View, MVMCoreUIViewConstrainingProtocol { containerLayer.transform = CATransform3DMakeRotation(1 * .pi, 0.0, 0.0, 1.0) } - - open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + + open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { super.setWithModel(model, delegateObject, additionalData) clearLayers() guard let doughnutChartModel = model as? DoughnutChartModel else { @@ -107,7 +107,7 @@ open class DoughnutChart: View, MVMCoreUIViewConstrainingProtocol { updateLabelContainer() drawGraph() } - + func drawGraph() { clearLayers() let widthHeight = sizeObject.getValueBasedOnApplicationWidth() diff --git a/MVMCoreUI/Molecules/DoughnutChartView.swift b/MVMCoreUI/Molecules/DoughnutChartView.swift index 95e23440..a54c04d4 100644 --- a/MVMCoreUI/Molecules/DoughnutChartView.swift +++ b/MVMCoreUI/Molecules/DoughnutChartView.swift @@ -70,7 +70,7 @@ import Foundation colorLablesStack.reset() } - open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { super.setWithModel(model, delegateObject, additionalData) doughnutChart.clearLayers() colorLablesStack.removeAllItemViews() @@ -94,8 +94,7 @@ import Foundation class ColorViewLabelsStack: MoleculeStackView { var dougnutChartModel: DoughnutChartModel? - - override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { let previousModel = self.dougnutChartModel removeAllItemViews() guard let dougnutChartModel = model as? DoughnutChartModel else { @@ -158,11 +157,11 @@ class ColorViewWithLabel: View, MVMCoreUIViewConstrainingProtocol { label.reset() } - func setAsMolecule() { + override func setAsMolecule() { label.setAsMolecule() } - override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { super.setWithModel(model, delegateObject, additionalData) guard let chartItemModel = model as? ChartItemModel else { return diff --git a/MVMCoreUI/Molecules/HeadlineBodyButton.swift b/MVMCoreUI/Molecules/HeadlineBodyButton.swift index 87efc9b6..02852d51 100644 --- a/MVMCoreUI/Molecules/HeadlineBodyButton.swift +++ b/MVMCoreUI/Molecules/HeadlineBodyButton.swift @@ -9,7 +9,7 @@ import UIKit -@objcMembers open class HeadlineBodyButton: ViewConstrainingView { +@objcMembers open class HeadlineBodyButton: View { //------------------------------------------------------ // MARK: - Outlets //------------------------------------------------------ @@ -33,7 +33,7 @@ import UIKit // MARK: - Initialization //------------------------------------------------------ - public init() { + public override init() { super.init(frame: .zero) } diff --git a/MVMCoreUI/Molecules/HorizontalCombinationViews/TabsModel.swift b/MVMCoreUI/Molecules/HorizontalCombinationViews/TabsModel.swift new file mode 100644 index 00000000..0e358871 --- /dev/null +++ b/MVMCoreUI/Molecules/HorizontalCombinationViews/TabsModel.swift @@ -0,0 +1,50 @@ +// +// TabsModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 1/13/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + +public class TabsModel: MoleculeProtocol { + public static var identifier: String = "tabs" + public var backgroundColor: Color? + public var tabs: [LabelModel] + public var selectedColor = Color(uiColor: .mfTomatoRed()) + + // Must be capped to 0...(tabs.count - 1) + public var selectedIndex: Int = 0 + + enum TabsCodingKeys: String, CodingKey { + case tabs + case backgroundColor + case selectedColor + case selectedIndex + } + + public init(with tabs: [LabelModel]) { + self.tabs = tabs + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: TabsCodingKeys.self) + tabs = try typeContainer.decode([LabelModel].self, forKey: .tabs) + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .selectedColor) { + selectedColor = color + } + if let index = try typeContainer.decodeIfPresent(Int.self, forKey: .selectedIndex) { + selectedIndex = index + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: TabsCodingKeys.self) + try container.encode(tabs, forKey: .tabs) + try container.encode(backgroundColor, forKey: .backgroundColor) + try container.encode(selectedColor, forKey: .selectedColor) + try container.encode(selectedIndex, forKey: .selectedIndex) + } +} diff --git a/MVMCoreUI/Molecules/Items/AccordionListItemModel.swift b/MVMCoreUI/Molecules/Items/AccordionListItemModel.swift new file mode 100644 index 00000000..d5519288 --- /dev/null +++ b/MVMCoreUI/Molecules/Items/AccordionListItemModel.swift @@ -0,0 +1,46 @@ +// +// AccordionListItemModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 1/13/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + +class AccordionListItemModel: MoleculeContainerModel, ListItemModelProtocol { + public static var identifier: String = "accordionListItem" + public var molecules: [ListItemModelProtocol] + public var backgroundColor: Color? + public var hideLineWhenExpanded: Bool = false + public var hideArrow: Bool? = true + public var line: LineModel? + + enum AccordionListItemCodingKeys: String, CodingKey { + case molecules + case backgroundColor + case hideLineWhenExpanded + case hideArrow + case line + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: AccordionListItemCodingKeys.self) + molecules = try typeContainer.decodeMolecules(codingKey: .molecules) as! [ListItemModelProtocol] + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) + if let hideLine = try typeContainer.decodeIfPresent(Bool.self, forKey: .hideLineWhenExpanded) { + hideLineWhenExpanded = hideLine + } + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: AccordionListItemCodingKeys.self) + try container.encodeModels(molecules, forKey: .molecules) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + try container.encodeIfPresent(hideLineWhenExpanded, forKey: .hideLineWhenExpanded) + try container.encodeIfPresent(line, forKey: .line) + } +} diff --git a/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift index 075d33f1..db4e322e 100644 --- a/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift @@ -9,6 +9,7 @@ import UIKit @objcMembers public class AccordionMoleculeTableViewCell: MoleculeTableViewCell { + var accordionListItemModel: AccordionListItemModel? let accordionButton = createAccordionButton() static func createAccordionButton() -> MFCustomButton { @@ -26,20 +27,20 @@ import UIKit accessoryView = accordionButton } - public override func didSelectCell(atIndex indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + override public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { accordionButton.isSelected = !accordionButton.isSelected accordionButton.setTitle(accordionButton.isSelected ? "-" : "+", for: .normal) - guard let molecules = json?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] else { + guard let molecules = accordionListItemModel?.molecules else { return } if accordionButton.isSelected { - delegateObject?.moleculeDelegate?.addMolecules?(molecules, sender: self, animation: .automatic) + delegateObject?.moleculeDelegate?.addMolecules(molecules, sender: self, animation: .automatic) } else { - delegateObject?.moleculeDelegate?.removeMolecules?(molecules, sender: self, animation: .automatic) + delegateObject?.moleculeDelegate?.removeMolecules(molecules, sender: self, animation: .automatic) } - if (json?.boolForKey("hideSeparatorWhenExpanded") ?? false) && (self.bottomSeparatorView?.shouldBeVisible() ?? false) { + if (accordionListItemModel?.hideLineWhenExpanded ?? false) && (self.bottomSeparatorView?.shouldBeVisible() ?? false) { bottomSeparatorView?.isHidden = accordionButton.isSelected } } diff --git a/MVMCoreUI/Molecules/Items/DropDownFilterTableViewCell.swift b/MVMCoreUI/Molecules/Items/DropDownFilterTableViewCell.swift index 31a6cc61..4df2e7e2 100644 --- a/MVMCoreUI/Molecules/Items/DropDownFilterTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/DropDownFilterTableViewCell.swift @@ -9,6 +9,7 @@ import UIKit @objcMembers public class DropDownFilterTableViewCell: TableViewCell { + var dropDownListItemModel: DropDownListItemModel? let dropDown = DropDown(forDropDownWithBothDelegates: nil) var delegateObject: MVMCoreUIDelegateObject? var previousIndex = NSNotFound @@ -20,7 +21,6 @@ import UIKit guard let dropDown = dropDown, dropDown.superview == nil else { return } - bottomMarginPadding = 0 dropDown.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(dropDown) @@ -35,14 +35,12 @@ import UIKit guard change.newValue != change.oldValue, let self = self, let options = self.dropDown?.json?.optionalArrayForKey("options") as? [NSString], let index = options.firstIndex(of: change.newValue!! as NSString), - let moleculesArrays = self.json?.arrayForKey(KeyMolecules) as? [[[AnyHashable: Any]]] else { return } + let molecules = self.dropDownListItemModel?.molecules else { return } if self.previousIndex != NSNotFound { - let previousMolecules = moleculesArrays[self.previousIndex] - self.delegateObject?.moleculeDelegate?.removeMolecules?(previousMolecules, sender: self, animation: .fade) + self.delegateObject?.moleculeDelegate?.removeMolecules(molecules[self.previousIndex], sender: self, animation: .fade) } - let molecules = moleculesArrays[index] - self.delegateObject?.moleculeDelegate?.addMolecules?(molecules, sender: self, animation: .fade) + self.delegateObject?.moleculeDelegate?.addMolecules(molecules[index], sender: self, animation: .fade) self.previousIndex = index } } @@ -51,20 +49,19 @@ import UIKit super.updateView(size) dropDown?.updateView(size) } - - // MARK: - MoleculeDelegateProtocol - public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - bottomSeparatorView?.style = .none + + public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + dropDownListItemModel = model as? DropDownListItemModel self.delegateObject = delegateObject - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + super.setWithModel(model, delegateObject, additionalData) + dropDown?.mfTextFieldDelegate = delegateObject?.uiTextFieldDelegate as? MFTextFieldDelegate dropDown?.uiTextFieldDelegate = delegateObject?.uiTextFieldDelegate - dropDown?.setWithJSON(json?.optionalDictionaryForKey("dropDown"), delegateObject: delegateObject, additionalData: additionalData) + dropDown?.setWithModel(dropDownListItemModel, delegateObject, additionalData) } public override func reset() { super.reset() - bottomMarginPadding = 0 - bottomSeparatorView?.style = .none + bottomSeparatorView?.setStyle(.none) } } diff --git a/MVMCoreUI/Molecules/Items/DropDownListItemModel.swift b/MVMCoreUI/Molecules/Items/DropDownListItemModel.swift new file mode 100644 index 00000000..64e8c69b --- /dev/null +++ b/MVMCoreUI/Molecules/Items/DropDownListItemModel.swift @@ -0,0 +1,51 @@ +// +// DropDownListItemModel.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 12/12/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers public class DropDownListItemModel: MoleculeContainerModel, ListItemModelProtocol { + public static var identifier: String = "dropDownListItem" + public var molecules: [[ListItemModelProtocol]] + public var dropDown: DropDownModel + public var backgroundColor: Color? + public var line: LineModel? = LineModel(type: .none) + public var hideArrow: Bool? = true + + public init(molecule: MoleculeProtocol, molecules: [[ListItemModelProtocol]], dropDown: DropDownModel) { + self.molecules = molecules + self.dropDown = dropDown + super.init(with: molecule) + } + + enum DropDownCodingKeys: String, CodingKey { + case molecules + case dropDown + case line + case backgroundColor + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: DropDownCodingKeys.self) + molecules = try typeContainer.decodeMolecules2D(codingKey: .molecules) as! [[ListItemModelProtocol]] + dropDown = try typeContainer.decode(DropDownModel.self, forKey: .dropDown) + if let lineModel = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) { + line = lineModel + } + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: DropDownCodingKeys.self) + try container.encodeModels2D(molecules, forKey: .molecules) + try container.encode(dropDown, forKey: .dropDown) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + try container.encodeIfPresent(line, forKey: .line) + } +} diff --git a/MVMCoreUI/Molecules/Items/ListItemModel.swift b/MVMCoreUI/Molecules/Items/ListItemModel.swift new file mode 100644 index 00000000..bef2cb84 --- /dev/null +++ b/MVMCoreUI/Molecules/Items/ListItemModel.swift @@ -0,0 +1,47 @@ +// +// ListItem.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 10/3/19. +// Copyright © 2019 Suresh, Kamlesh. All rights reserved. +// + +import Foundation +import MVMCore + +@objcMembers public class ListItemModel: MoleculeContainerModel, ListItemModelProtocol { + public static var identifier: String = "listItem" + public var backgroundColor: Color? + public var action: ActionProtocol? + public var hideArrow: Bool? + public var line: LineModel? + public var style: String? + + enum ListItemCodingKeys: String, CodingKey { + case backgroundColor + case action + case hideArrow + case line + case style + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: ListItemCodingKeys.self) + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + action = try typeContainer.decodeModelIfPresent(codingKey: .action, typeCodingKey: ActionCodingKey.type) + hideArrow = try typeContainer.decodeIfPresent(Bool.self, forKey: .hideArrow) + line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) + style = try typeContainer.decodeIfPresent(String.self, forKey: .style) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: ListItemCodingKeys.self) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + try container.encodeModelIfPresent(action, forKey: .action) + try container.encodeIfPresent(hideArrow, forKey: .hideArrow) + try container.encodeIfPresent(line, forKey: .line) + try container.encodeIfPresent(style, forKey: .style) + } +} diff --git a/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift index 35b3ed04..b396dde6 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift @@ -8,7 +8,8 @@ import UIKit -open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol { +open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeViewProtocol, ModelMoleculeViewProtocol { + open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)? open var json: [AnyHashable: Any]? public let containerHelper = ContainerHelper() @@ -65,40 +66,39 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi peakingRightArrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true NSLayoutConstraint.scalingPinViewRight(toSuper: peakingRightArrow, ratio: ratio, anchor: contentView.widthAnchor) } - - public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - self.json = json - - if let useHorizontalMargins = json?.optionalBoolForKey("useHorizontalMargins") { + + + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + guard let collectionModel = model as? CarouselItemModel else { + return + } + + if let useHorizontalMargins = collectionModel.useHorizontalMargins { updateViewHorizontalDefaults = useHorizontalMargins } - if let useVerticalMargins = json?.optionalBoolForKey("useVerticalMargins") { + if let useVerticalMargins = collectionModel.useVerticalMargins { updateViewVerticalDefaults = useVerticalMargins } - // Handles peaking. - allowsPeaking = json?.optionalBoolForKey("peakingUI") ?? true - if let peakingArrowColor = json?.optionalStringForKey("peakingArrowColor") { - let color = UIColor.mfGet(forHex: peakingArrowColor) + allowsPeaking = collectionModel.peakingUI ?? false + if let peakingArrowColor = collectionModel.peakingArrowColor { + let color = peakingArrowColor.uiColor peakingLeftArrow.tintColor = color peakingRightArrow.tintColor = color } - - if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) { - backgroundColor = UIColor.mfGet(forHex: backgroundColorString) - } - - guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule) else { - return + + if let backgroundColor = collectionModel.backgroundColor { + self.backgroundColor = backgroundColor.uiColor } + if molecule == nil { - if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: false) { + if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(collectionModel.molecule, delegateObject, true) { contentView.insertSubview(moleculeView, at: 0) containerHelper.constrainView(moleculeView) molecule = moleculeView } } else { - molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) + (molecule as? ModelMoleculeViewProtocol)?.setWithModel(collectionModel.molecule, delegateObject, additionalData) } guard let molecule = molecule else { return } diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index 7cd3a900..1fee9e20 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -11,37 +11,26 @@ import UIKit @objcMembers open class MoleculeTableViewCell: TableViewCell { // MARK: - MVMCoreUIMoleculeViewProtocol - public override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) - { - guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule) else { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.setWithModel(model, delegateObject, additionalData) + + guard let model = model, + let moleculeModel = (model as? ListItemModel)?.molecule, + let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(moleculeModel, delegateObject, true) else { return } - if molecule == nil { - if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: false) { - addMolecule(moleculeView) - } - } else { - molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) - } - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + addMolecule(moleculeView) } - - public override class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) else { - return 80 - } - return max(2 * PaddingDefaultVerticalSpacing3, height) - } - - public override class func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { - guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else { + + public override class func name(forReuse molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> String? { + guard let moleculeModel = (molecule as? ListItemModel)?.molecule else { return "\(self)<>" } - let moleculeName = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) ?? "" + let className = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(moleculeModel) as? ModelMoleculeViewProtocol + let moleculeName = className?.nameForReuse(molecule, delegateObject) ?? moleculeModel.moleculeName ?? "" return "\(self)<\(moleculeName)>" } - + public class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let theClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON) else { @@ -49,4 +38,13 @@ import UIKit } return theClass.requiredModules?(moleculeJSON, delegateObject: delegateObject, error: error) } + + public static func estimatedHeight(forRow molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + guard let moleculeModel = (molecule as? MoleculeContainerModel)?.molecule, + let classType = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(moleculeModel) as? ModelMoleculeViewProtocol.Type, + let height = classType.estimatedHeight(forRow: moleculeModel, delegateObject: delegateObject) else { + return 80 + } + return max(2 * PaddingDefaultVerticalSpacing3, height) + } } diff --git a/MVMCoreUI/Molecules/Items/StackItem.swift b/MVMCoreUI/Molecules/Items/StackItem.swift index e121a1ee..59c30962 100644 --- a/MVMCoreUI/Molecules/Items/StackItem.swift +++ b/MVMCoreUI/Molecules/Items/StackItem.swift @@ -9,7 +9,7 @@ import UIKit open class StackItem: MoleculeContainer { - var stackItemModel: MoleculeStackItemModel? { - get { return model as? MoleculeStackItemModel } + var stackItemModel: StackItemModel? { + get { return model as? StackItemModel } } } diff --git a/MVMCoreUI/Models/Molecules/MoleculeStackItemModel.swift b/MVMCoreUI/Molecules/Items/StackItemModel.swift similarity index 91% rename from MVMCoreUI/Models/Molecules/MoleculeStackItemModel.swift rename to MVMCoreUI/Molecules/Items/StackItemModel.swift index a0e7825c..a5128f1b 100644 --- a/MVMCoreUI/Models/Molecules/MoleculeStackItemModel.swift +++ b/MVMCoreUI/Molecules/Items/StackItemModel.swift @@ -8,9 +8,9 @@ import Foundation -@objcMembers public class MoleculeStackItemModel: MoleculeContainerModel, MoleculeProtocol { +@objcMembers public class StackItemModel: MoleculeContainerModel, MoleculeProtocol { public static var identifier: String = "stackItem" - public var backgroundColor: String? + public var backgroundColor: Color? public var spacing: CGFloat? public var percentage: Int? = 0 public var gone: Bool = false diff --git a/MVMCoreUI/Molecules/Items/TableViewCell.swift b/MVMCoreUI/Molecules/Items/TableViewCell.swift index b1aa92a5..3cf51ab6 100644 --- a/MVMCoreUI/Molecules/Items/TableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/TableViewCell.swift @@ -8,13 +8,11 @@ import UIKit -@objcMembers open class TableViewCell: UITableViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol { - open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)? - open var json: [AnyHashable: Any]? - public let containerHelper = ContainerHelper() +@objcMembers open class TableViewCell: UITableViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol, ModelMoleculeViewProtocol { - // In updateView, will set padding to default. - open var updateViewHorizontalDefaults = true + open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)? + open var listItemModel: ListItemModelProtocol? + public let containerHelper = ContainerHelper() // For the accessory view convenience. private var caretView: CaretView? @@ -24,19 +22,10 @@ import UIKit // For separation between cells. public var topSeparatorView: Line? public var bottomSeparatorView: Line? - public enum SeparatorFrequency: String { - case all - case allExceptTop - case allExceptBottom - case between - } /// For subclasses that want to use a custom accessory view. open var customAccessoryView = false - open var topMarginPadding: CGFloat = 24 - open var bottomMarginPadding: CGFloat = 24 - private var heroAccessoryCenter: CGPoint? // MARK: - Styling @@ -60,38 +49,38 @@ import UIKit } open func styleStandard() { - topMarginPadding = 24 - bottomMarginPadding = 24 - topSeparatorView?.style = .none - bottomSeparatorView?.style = .standard + listItemModel?.topMarginPadding = 24 + listItemModel?.bottomMarginPadding = 24 + topSeparatorView?.setStyle(.none) + bottomSeparatorView?.setStyle(.standard) } open func styleTallDivider() { - topMarginPadding = 48 - bottomMarginPadding = 16 - topSeparatorView?.style = .none - bottomSeparatorView?.style = .thin + listItemModel?.topMarginPadding = 48 + listItemModel?.bottomMarginPadding = 16 + topSeparatorView?.setStyle(.none) + bottomSeparatorView?.setStyle(.thin) } open func styleShortDivider() { - topMarginPadding = 32 - bottomMarginPadding = 16 - topSeparatorView?.style = .none - bottomSeparatorView?.style = .thin + listItemModel?.topMarginPadding = 32 + listItemModel?.bottomMarginPadding = 16 + topSeparatorView?.setStyle(.none) + bottomSeparatorView?.setStyle(.thin) } open func styleFooter() { - topMarginPadding = 24 - bottomMarginPadding = 0 - topSeparatorView?.style = .none - bottomSeparatorView?.style = .none + listItemModel?.topMarginPadding = 24 + listItemModel?.bottomMarginPadding = 0 + topSeparatorView?.setStyle(.none) + bottomSeparatorView?.setStyle(.none) } open func styleNone() { - topMarginPadding = 0 - bottomMarginPadding = 0 - topSeparatorView?.style = .none - bottomSeparatorView?.style = .none + listItemModel?.topMarginPadding = 0 + listItemModel?.bottomMarginPadding = 0 + topSeparatorView?.setStyle(.none) + bottomSeparatorView?.setStyle(.none) } /// Adds the molecule to the view. @@ -123,7 +112,7 @@ import UIKit // MARK: - MFViewProtocol public func updateView(_ size: CGFloat) { - MFStyler.setMarginsFor(self, size: size, defaultHorizontal: updateViewHorizontalDefaults, top: topMarginPadding, bottom: bottomMarginPadding) + containerHelper.updateViewMargins(self, model: listItemModel, size: size) if accessoryView != nil { // Smaller left margin if accessory view. @@ -151,63 +140,47 @@ import UIKit contentView.insetsLayoutMarginsFromSafeArea = false contentView.preservesSuperviewLayoutMargins = false } - - // MARK: - MVMCoreUIMoleculeViewProtocol - public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - self.json = json - - guard let json = json else { return } - - style(with: json.optionalStringForKey("style")) - - if let useHorizontalMargins = json.optionalBoolForKey("useHorizontalMargins") { - updateViewHorizontalDefaults = useHorizontalMargins + + //TODO: Model, Change to model + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + guard let model = model as? ListItemModelProtocol else { + return } - - if (json.optionalBoolForKey("useVerticalMargins") ?? true) == false { - topMarginPadding = 0 - bottomMarginPadding = 0 + + self.listItemModel = model + style(with: model.style) + + if let backgroundColor = model.backgroundColor { + self.backgroundColor = backgroundColor.uiColor } - - if let backgroundColorString = json.optionalStringForKey(KeyBackgroundColor) { - backgroundColor = UIColor.mfGet(forHex: backgroundColorString) - } - + // Add the caret if there is an action and it's not declared hidden. if !customAccessoryView { - if let _ = json.optionalDictionaryForKey("actionMap"), !json.boolForKey("hideArrow") { + if let _ = model.action, !(model.hideArrow ?? false) { addCaretViewAccessory() } else { accessoryView = nil } } - + // override the separator - if let separator = json.optionalDictionaryForKey("separator") { + if let separator = model.line { addSeparatorsIfNeeded() - bottomSeparatorView?.setWithJSON(separator, delegateObject: delegateObject, additionalData: additionalData) + bottomSeparatorView?.setWithModel(separator, nil, nil) } guard let molecule = molecule else { return } - containerHelper.set(with: json, for: molecule) + containerHelper.set(with: model, for: molecule as? MVMCoreUIViewConstrainingProtocol) } public func reset() { molecule?.reset?() - updateViewHorizontalDefaults = true styleStandard() backgroundColor = .white } - - public class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) else { - return 80 - } - return max(2 * PaddingDefaultVerticalSpacing3, height) - } - - public class func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { - return molecule?.optionalStringForKey(KeyMoleculeName) ?? "" + + public class func name(forReuse molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> String? { + return molecule?.moleculeName ?? "" } // MARK: - Arrow @@ -258,23 +231,21 @@ import UIKit // MARK: - MoleculeListCellProtocol /// For when the separator between cells shows using json and frequency. Default is type: standard, frequency: allExceptTop. - public func setSeparatorWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, indexPath: IndexPath) { + public func setLines(with model: LineModel?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?, indexPath: IndexPath) { addSeparatorsIfNeeded() - if let json = json { - topSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - bottomSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - if let separatorFrequencyString = json.optionalStringForKey("frequency"), let separatorFrequency = SeparatorFrequency(rawValue: separatorFrequencyString) { - setSeparatorFrequency(separatorFrequency, indexPath: indexPath) - } + if let model = model { + topSeparatorView?.setWithModel(model, delegateObject, additionalData) + bottomSeparatorView?.setWithModel(model, delegateObject, additionalData) } else { - topSeparatorView?.style = .standard - bottomSeparatorView?.style = .standard - setSeparatorFrequency(TableViewCell.SeparatorFrequency.allExceptTop, indexPath: indexPath) + topSeparatorView?.setStyle(.standard) + bottomSeparatorView?.setStyle(.standard) } + setSeparatorFrequency(model?.frequency ?? .allExceptTop, indexPath: indexPath) } - public func didSelectCell(atIndex indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - if let actionMap = json?.optionalDictionaryForKey("actionMap") { + public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + //TODO: Use object when handleAction is rewrote to handle action model + if let actionMap = self.listItemModel?.action?.toJSON() { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) } } @@ -287,7 +258,7 @@ import UIKit open func addSeparatorsIfNeeded() { if topSeparatorView == nil { let line = Line() - line.style = .none + line.setStyle(.none) addSubview(line) NSLayoutConstraint.pinViewTop(toSuperview: line, useMargins: false, constant: 0).isActive = true NSLayoutConstraint.pinViewLeft(toSuperview: line, useMargins: true, constant: 0).isActive = true @@ -296,7 +267,7 @@ import UIKit } if bottomSeparatorView == nil { let line = Line() - line.style = .none + line.setStyle(.none) addSubview(line) NSLayoutConstraint.pinViewBottom(toSuperview: line, useMargins: false, constant: 0).isActive = true NSLayoutConstraint.pinViewLeft(toSuperview: line, useMargins: true, constant: 0).isActive = true @@ -306,7 +277,7 @@ import UIKit } /// For when the separator between cells shows. - public func setSeparatorFrequency(_ separatorFrequency: SeparatorFrequency, indexPath: IndexPath) { + public func setSeparatorFrequency(_ separatorFrequency: LineModel.Frequency, indexPath: IndexPath) { switch separatorFrequency { case .all: if indexPath.row == 0 { diff --git a/MVMCoreUI/Molecules/Items/TabsListItemModel.swift b/MVMCoreUI/Molecules/Items/TabsListItemModel.swift new file mode 100644 index 00000000..d27b9097 --- /dev/null +++ b/MVMCoreUI/Molecules/Items/TabsListItemModel.swift @@ -0,0 +1,54 @@ +// +// TabsListItemModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 1/13/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + +public class TabsListItemModel: ContainerModel, ListItemModelProtocol { + public static var identifier: String = "tabsListItem" + var tabs: TabsModel + var molecules: [[ListItemModelProtocol]] + + public var backgroundColor: Color? + public var hideArrow: Bool? = true + public var line: LineModel? = LineModel(type: .standard) + + enum TabsListItemCodingKeys: String, CodingKey { + case tabs + case molecules + case backgroundColor + case line + } + + public init(with tabs: TabsModel, molecules: [[ListItemModelProtocol]]) { + self.tabs = tabs + self.molecules = molecules + super.init() + self.topMarginPadding = 8 + self.bottomMarginPadding = 0 + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: TabsListItemCodingKeys.self) + tabs = try typeContainer.decode(TabsModel.self, forKey: .tabs) + molecules = try typeContainer.decodeMolecules2D(codingKey: .molecules) as! [[ListItemModelProtocol]] + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + if let lineModel = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) { + line = lineModel + } + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: TabsListItemCodingKeys.self) + try container.encode(tabs, forKey: .tabs) + try container.encodeModels2D(molecules, forKey: .molecules) + try container.encode(backgroundColor, forKey: .backgroundColor) + try container.encodeIfPresent(line, forKey: .line) + } +} diff --git a/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift b/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift index 1a1796cd..99d2d9ab 100644 --- a/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift @@ -9,6 +9,7 @@ import UIKit @objcMembers public class TabsTableViewCell: TableViewCell { + var tabsListItemModel: TabsListItemModel? let tabs = TopTabbar(frame: .zero) var delegateObject: MVMCoreUIDelegateObject? var previousTabIndex = 0 @@ -20,8 +21,6 @@ import UIKit return } tabs.paddingBeforeFirstTab = false - topMarginPadding = 8 - bottomMarginPadding = 0 tabs.translatesAutoresizingMaskIntoConstraints = false tabs.delegate = self @@ -38,42 +37,42 @@ import UIKit } // MARK: - MoleculeDelegateProtocol - public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + + public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.setWithModel(model, delegateObject, additionalData) self.delegateObject = delegateObject tabs.reloadData() } - + public override func reset() { super.reset() - topMarginPadding = 8 - bottomMarginPadding = 0 + tabs.reset() } } extension TabsTableViewCell: TopTabbarDelegate { public func shouldSelectItem(at index: Int, topTabbar: TopTabbar) -> Bool { - if let moleculesArrays = json?.arrayForKey(KeyMolecules), let molecules = moleculesArrays[topTabbar.selectedIndex] as? [[AnyHashable: Any]] { - delegateObject?.moleculeDelegate?.removeMolecules?(molecules, sender: self, animation: index < tabs.selectedIndex ? .right : .left) + if let molecules = tabsListItemModel?.molecules[topTabbar.selectedIndex] { + delegateObject?.moleculeDelegate?.removeMolecules(molecules, sender: self, animation: index < tabs.selectedIndex ? .right : .left) } previousTabIndex = tabs.selectedIndex return true } - + public func topTabbar(_ topTabbar: TopTabbar, didSelectItemAt index: Int) { - if let moleculesArrays = json?.arrayForKey(KeyMolecules), let molecules = moleculesArrays[index] as? [[AnyHashable: Any]] { - delegateObject?.moleculeDelegate?.addMolecules?(molecules, sender: self, animation: index < previousTabIndex ? .left : .right) + if let molecules = tabsListItemModel?.molecules[index] { + delegateObject?.moleculeDelegate?.addMolecules(molecules, sender: self, animation: index < previousTabIndex ? .left : .right) } } } extension TabsTableViewCell: TopTabbarDataSource { public func number(ofTopTabbarItems topTabbar: TopTabbar) -> Int { - return json?.optionalDictionaryForKey("tabs")?.optionalArrayForKey("tabs")?.count ?? 0 + return tabsListItemModel?.tabs.tabs.count ?? 0 } - + public func topTabbar(_ topTabbar: TopTabbar, titleForItemAt index: Int) -> String? { - guard let tabs = json?.optionalDictionaryForKey("tabs")?.arrayForKey("tabs"), let label = tabs[index] as? [AnyHashable: Any], let title = label.optionalStringForKey(KeyText) else { + guard let title = tabsListItemModel?.tabs.tabs[index].text else { return "Select" } return title diff --git a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift index 79110460..eca878ab 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift @@ -8,7 +8,7 @@ import UIKit -@objcMembers open class HeadlineBodySwitch: ViewConstrainingView { +@objcMembers open class HeadlineBodySwitch: View { public let headlineBody = HeadlineBody(frame: .zero) public let mvmSwitch = MVMCoreUISwitch.mvmSwitchDefault() @@ -27,13 +27,27 @@ import UIKit headlineBody.styleListItem() let view = MVMCoreUICommonViewsUtility.commonView() addSubview(view) - pinView(toSuperView: view) + NSLayoutConstraint.constraintPinSubview(toSuperview: view) view.addSubview(headlineBody) view.addSubview(mvmSwitch) NSLayoutConstraint.pinSubviewsCenter(leftView: headlineBody, rightView: mvmSwitch) } + + //MARK: - MVMCoreMoleculeViewProtocol + + open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.setWithModel(model, delegateObject, additionalData) +// guard let headlineModel = model as? headlinebodyswitch +// headlineBody.setWithModel(mode, <#T##delegateObject: MVMCoreUIDelegateObject?##MVMCoreUIDelegateObject?#>, <#T##additionalData: [String : AnyHashable]?##[String : AnyHashable]?#>) + } + + public static func estimatedHeight(forRow molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return 30 + } + + // MARK: - MVMCoreUIMoleculeViewProtocol open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) @@ -41,12 +55,11 @@ import UIKit mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData) } - open override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + open class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 30 } open override func setAsMolecule() { - super.setAsMolecule() headlineBody.setAsMolecule() (mvmSwitch as MVMCoreUIMoleculeViewProtocol).setAsMolecule?() headlineBody.styleListItem() diff --git a/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h b/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h index 2c52324b..e67dc964 100644 --- a/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h +++ b/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h @@ -14,15 +14,10 @@ @protocol MVMCoreUIMoleculeViewProtocol -/// Sets up the ui based on the json -- (void)setWithJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData; - @optional -// optional func setWithModel(_ model: MoleculeProtocol, _ delegateObject: MVMCoreUIDelegateObject, _ additionalData: [String: AnyHashable]) -//Type arguments cannot be applied to non-parameterized class 'NSObject' -//- (void)setWithModel:(nullable NSObject*)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData; - +/// Sets up the ui based on the json +- (void)setWithJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData; /// Called after init to provide an early setter for any molecule specific logic - (void)setAsMolecule; diff --git a/MVMCoreUI/Molecules/ModelMoleculeViewProtocol.swift b/MVMCoreUI/Molecules/ModelMoleculeViewProtocol.swift index 6668d2be..de8e4d4f 100644 --- a/MVMCoreUI/Molecules/ModelMoleculeViewProtocol.swift +++ b/MVMCoreUI/Molecules/ModelMoleculeViewProtocol.swift @@ -9,13 +9,27 @@ import Foundation public protocol ModelMoleculeViewProtocol { - func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String: AnyHashable]?) - + func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) func nameForReuse(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> String? + static func estimatedHeight(forRow molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? + static func requiredModules(_ molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? } extension ModelMoleculeViewProtocol { public func nameForReuse(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { return nil } + public static func estimatedHeight(forRow molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return nil + } + public static func requiredModules(_ molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { + return nil + } + + // Temporary + public static func decodeJSONToModel(json: [AnyHashable: Any], type: T.Type) throws -> T where T : Decodable { + let data = try JSONSerialization.data(withJSONObject: json) + let decoder = JSONDecoder() + return try decoder.decode(type, from: data) + } } diff --git a/MVMCoreUI/Molecules/ModuleMolecule.swift b/MVMCoreUI/Molecules/ModuleMolecule.swift index e6ef0048..e2411ec0 100644 --- a/MVMCoreUI/Molecules/ModuleMolecule.swift +++ b/MVMCoreUI/Molecules/ModuleMolecule.swift @@ -8,27 +8,9 @@ import UIKit -open class ModuleMoleculeModel: MoleculeProtocol { - public var backgroundColor: String? - public static var identifier: String = "moduleMolecule" - public var moduleName: String - - enum CodingKeys: String, CodingKey { - case moduleName - } - - required public init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - moduleName = try typeContainer.decode(String.self, forKey:.moduleName) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(moduleName, forKey: .moduleName) - } -} - open class ModuleMolecule: Container { + + open var moduleMolecule: (UIView & MVMCoreUIMoleculeViewProtocol & ModelMoleculeViewProtocol)? var moduleMoleculeModel: ModuleMoleculeModel? { get { return model as? ModuleMoleculeModel } } @@ -37,56 +19,66 @@ open class ModuleMolecule: Container { super.setupView() } - open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { - #warning("need to change getter to get moduleModel instead to use.") + public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.setWithModel(model, delegateObject, additionalData) - } - // MARK: - MVMCoreUIMoleculeViewProtocol - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - - guard let moduleName = json?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { - // Critical error - return + guard let moduleMoleculeModel = model as? ModuleMoleculeModel, + let moduleModel = delegateObject?.moleculeDelegate?.getModuleWithName(moduleMoleculeModel.moduleName) else { + // Critical error + return } - if view == nil { - if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: module, delegateObject: delegateObject, constrainIfNeeded: false) { - addAndContain(moleculeView) + if moduleMolecule == nil { + if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(moduleModel, delegateObject, true) { + addSubview(moleculeView) + NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: false).values)) + moduleMolecule = moleculeView as? (UIView & MVMCoreUIMoleculeViewProtocol & ModelMoleculeViewProtocol) + + isAccessibilityElement = false + if moleculeView.accessibilityElements != nil { + accessibilityElements = moleculeView.accessibilityElements + } else { + accessibilityElements = [moleculeView] + } } } else { - (view as? MVMCoreUIMoleculeViewProtocol)?.setWithJSON(module, delegateObject: delegateObject, additionalData: additionalData) + moduleMolecule?.setWithModel(model, delegateObject, additionalData) } } - - public class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - guard let moduleName = json?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { - // Critical error - return 0 + + public static func estimatedHeight(forRow molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + + guard let moduleMolecule = molecule as? ModuleMoleculeModel, + let moduleModel = delegateObject?.moleculeDelegate?.getModuleWithName(moduleMolecule.moduleName), + let classType = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(moduleModel) as? ModelMoleculeViewProtocol.Type, + let height = classType.estimatedHeight(forRow: moduleModel, delegateObject: delegateObject)else { + // Critical error + return 0 } - return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.estimatedHeight?(forRow: module, delegateObject: delegateObject) ?? 0 + return height } - - public class func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { - guard let moduleName = molecule?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { - // Critical error + + public override func nameForReuse(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { + guard let moduleMolecule = model as? ModuleMoleculeModel, + let moduleModel = delegateObject?.moleculeDelegate?.getModuleWithName(moduleMolecule.moduleName), + let classType = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(moduleModel) as? ModelMoleculeViewProtocol, + let name = classType.nameForReuse(moduleModel, delegateObject) else { + // Critical error return "moduleMolecule<>" } - return "moduleMolecule<" + (MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.name?(forReuse: module, delegateObject: delegateObject) ?? module.stringForkey(KeyMoleculeName)) + ">" + return name } - - public class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { - let moduleName = json?.optionalStringForKey("moduleName") - if moduleName == nil || delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) == nil { + + public static func requiredModules(_ molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { + + guard let moduleName = (molecule as? ModuleMoleculeModel)?.moduleName, + let _ = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { if let errorObject = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess), code: CoreUIErrorCode.ErrorCodeModuleMolecule.rawValue, domain: ErrorDomainNative, location: String(describing: self)) { error?.pointee = errorObject MVMCoreUILoggingHandler.shared()?.addError(toLog: errorObject) } + return nil } - if let moduleName = moduleName { - return [moduleName] - } - return nil + return [moduleName] } } diff --git a/MVMCoreUI/Molecules/MoleculeContainer.swift b/MVMCoreUI/Molecules/MoleculeContainer.swift index 0eea4414..f45ca482 100644 --- a/MVMCoreUI/Molecules/MoleculeContainer.swift +++ b/MVMCoreUI/Molecules/MoleculeContainer.swift @@ -20,12 +20,12 @@ open class MoleculeContainer: Container { addAndContain(molecule) } } else { - (view as? MVMCoreUIMoleculeViewProtocol)?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) + (view as? MVMCoreUIMoleculeViewProtocol)?.setWithJSON?(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) } super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) } - public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { if let casteModel = model as? MoleculeContainerModel { if view != nil { (view as? ModelMoleculeViewProtocol)?.setWithModel(casteModel.molecule, delegateObject, additionalData) diff --git a/MVMCoreUI/Molecules/Scroller.swift b/MVMCoreUI/Molecules/Scroller.swift index e4289bc3..451eba75 100644 --- a/MVMCoreUI/Molecules/Scroller.swift +++ b/MVMCoreUI/Molecules/Scroller.swift @@ -8,7 +8,7 @@ import UIKit -@objcMembers open class Scroller: ViewConstrainingView { +@objcMembers open class Scroller: Container { public let scrollView = UIScrollView(frame: .zero) public let contentView = MVMCoreUICommonViewsUtility.commonView() @@ -20,26 +20,27 @@ import UIKit translatesAutoresizingMaskIntoConstraints = false scrollView.translatesAutoresizingMaskIntoConstraints = false addSubview(scrollView) - pinView(toSuperView: scrollView) + NSLayoutConstraint.constraintPinSubview(toSuperview: scrollView) + contentView.translatesAutoresizingMaskIntoConstraints = false scrollView.addSubview(contentView) NSLayoutConstraint.constraintPinSubview(toSuperview: contentView) let constraint = contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, multiplier: 1.0) constraint.priority = UILayoutPriority(rawValue: 999) constraint.isActive = true } - - open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { - return - } - if molecule == nil { - if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) { - contentView.addSubview(moleculeView) - pinView(toSuperView: moleculeView) - molecule = moleculeView + + public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + if let casteModel = model as? ScrollerModel { + if view != nil { + (view as? ModelMoleculeViewProtocol)?.setWithModel(casteModel.molecule, delegateObject, additionalData) + } else { + if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(casteModel.molecule, delegateObject) { + contentView.addSubview(molecule) + molecule.translatesAutoresizingMaskIntoConstraints = false + containerHelper.constrainView(molecule) + } } - } else { - molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) } + super.setWithModel(model, delegateObject, additionalData) } } diff --git a/MVMCoreUI/Molecules/ScrollerModel.swift b/MVMCoreUI/Molecules/ScrollerModel.swift new file mode 100644 index 00000000..3fa225fb --- /dev/null +++ b/MVMCoreUI/Molecules/ScrollerModel.swift @@ -0,0 +1,14 @@ +// +// ScrollerModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 1/13/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + +public class ScrollerModel: MoleculeContainerModel, MoleculeProtocol { + public static var identifier: String = "scroller" + public var backgroundColor: Color? +} diff --git a/MVMCoreUI/Molecules/StandardHeaderView.swift b/MVMCoreUI/Molecules/StandardHeaderView.swift index c0994282..c13638d8 100644 --- a/MVMCoreUI/Molecules/StandardHeaderView.swift +++ b/MVMCoreUI/Molecules/StandardHeaderView.swift @@ -26,7 +26,7 @@ public class StandardHeaderView: MoleculeContainer { guard line == nil else { return } let line = Line() - line.style = .heavy + line.setStyle(.heavy) addSubview(line) NSLayoutConstraint.pinViewBottom(toSuperview: line, useMargins: false, constant: 0).isActive = true NSLayoutConstraint.pinViewLeft(toSuperview: line, useMargins: true, constant: 0).isActive = true @@ -42,7 +42,7 @@ public class StandardHeaderView: MoleculeContainer { } } - open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.setWithModel(model, delegateObject, additionalData) guard let headerModel = model as? HeaderModel else { @@ -53,30 +53,10 @@ public class StandardHeaderView: MoleculeContainer { line?.setWithJSON(seperatorModel.toJSON(), delegateObject: delegateObject, additionalData: additionalData) } } - -// open func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { -// //TODO: Need to create setWithModel in ViewConstraining View -// -// #warning("This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView.") -// //TODO: This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView. -// setUpWithModel(model, delegateObject, additionalData) -// -// // This molecule will by default handle margins. -// (molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(false) -// (molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(false) -// -// guard let headerModel = model as? HeaderModel else { -// return -// } -// -// if let seperatorModel = headerModel.seperator as? LineModel { -// line?.setWithJSON(seperatorModel.toJSON(), delegateObject: delegateObject, additionalData: additionalData) -// } -// } open override func reset() { super.reset() - line?.style = .heavy + line?.setStyle(.heavy) } public class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift index 152411ea..1262994f 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift @@ -10,7 +10,7 @@ import UIKit struct EyebrowHeadlineBodyLinkModel: MoleculeProtocol { static var identifier: String = "eyebrowHeadlineBodyLink" - var backgroundColor: String? + var backgroundColor: Color? public var eyeBrow: LabelModel? public var headline: LabelModel? @@ -18,7 +18,7 @@ struct EyebrowHeadlineBodyLinkModel: MoleculeProtocol { public var link: LineModel? } -@objcMembers open class EyebrowHeadlineBodyLink: ViewConstrainingView { +@objcMembers open class EyebrowHeadlineBodyLink: Container { let stack = MoleculeStackView(frame: .zero) let eyebrow = Label.commonLabelB3(true) let headline = Label.commonLabelB1(true) @@ -34,10 +34,10 @@ struct EyebrowHeadlineBodyLinkModel: MoleculeProtocol { guard stack.superview == nil else { return } - let eyebrowStackItem = MoleculeStackItemModel(with: casteModel!.eyeBrow!) - let headlineStackItem = MoleculeStackItemModel(with: casteModel!.headline!) - let bodyStackItem = MoleculeStackItemModel(with: casteModel!.body!) - let linkStackItem = MoleculeStackItemModel(with: casteModel!.link!) + let eyebrowStackItem = StackItemModel(with: casteModel!.eyeBrow!) + let headlineStackItem = StackItemModel(with: casteModel!.headline!) + let bodyStackItem = StackItemModel(with: casteModel!.body!) + let linkStackItem = StackItemModel(with: casteModel!.link!) // To visually take into account the extra padding in the intrinsic content of a button. linkStackItem.spacing = -6 @@ -48,7 +48,7 @@ struct EyebrowHeadlineBodyLinkModel: MoleculeProtocol { stack.stackItems = [StackItem(andContain: eyebrow),StackItem(andContain: headline),StackItem(andContain: body),StackItem(andContain: link)] addSubview(stack) - pinView(toSuperView: stack) + NSLayoutConstraint.constraintPinSubview(toSuperview: stack) } open override func updateView(_ size: CGFloat) { @@ -57,17 +57,23 @@ struct EyebrowHeadlineBodyLinkModel: MoleculeProtocol { } // MARK: - MVMCoreUIMoleculeViewProtocol + + open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + super.setWithModel(model, delegateObject, additionalData) + eyebrow.setWithModel(casteModel?.eyeBrow, delegateObject, additionalData) + headline.setWithModel(casteModel?.headline, delegateObject, additionalData) + body.setWithModel(casteModel?.body, delegateObject, additionalData) + link.setWithModel(casteModel?.link, delegateObject, additionalData) + + (stack.stackItems[0].model as? StackItemModel)?.gone = !eyebrow.hasText + (stack.stackItems[1].model as? StackItemModel)?.gone = !headline.hasText + (stack.stackItems[2].model as? StackItemModel)?.gone = !body.hasText + (stack.stackItems[3].model as? StackItemModel)?.gone = ((link.titleLabel?.text?.count) ?? 0) == 0 + stack.restack() + } open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - /*eyebrow.setWithJSON(json?.optionalDictionaryForKey("eyebrow"), delegateObject: delegateObject, additionalData: additionalData) - stack.items[0].gone = !eyebrow.hasText - headline.setWithJSON(json?.optionalDictionaryForKey("headline"), delegateObject: delegateObject, additionalData: additionalData) - stack.items[1].gone = !headline.hasText - body.setWithJSON(json?.optionalDictionaryForKey("body"), delegateObject: delegateObject, additionalData: additionalData) - stack.items[2].gone = !body.hasText - link.setWithJSON(json?.optionalDictionaryForKey("link"), delegateObject: delegateObject, additionalData: additionalData) - stack.items[3].gone = link.titleLabel?.text?.count ?? 0 == 0 - stack.restack()*/ + guard let json = json, let model = try? Self.decodeJSONToModel(json: json, type: EyebrowHeadlineBodyLinkModel.self) else { return } + setWithModel(model, delegateObject, additionalData) } open override func reset() { @@ -79,7 +85,7 @@ struct EyebrowHeadlineBodyLinkModel: MoleculeProtocol { body.styleB2(true) } - public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public static func estimatedHeight(forRow molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { return 65 } } diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift index d236fc37..1d1f154a 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift @@ -8,7 +8,7 @@ import UIKit -open class HeadlineBody: ViewConstrainingView { +open class HeadlineBody: View { let headlineLabel = Label.commonLabelH2(true) let messageLabel = Label.commonLabelB2(true) var spaceBetweenLabelsConstant = PaddingTwo @@ -81,7 +81,7 @@ open class HeadlineBody: ViewConstrainingView { let view = MVMCoreUICommonViewsUtility.commonView() addSubview(view) - pinView(toSuperView: view) + NSLayoutConstraint.constraintPinSubview(toSuperview: view) view.addSubview(headlineLabel) view.addSubview(messageLabel) @@ -118,6 +118,19 @@ open class HeadlineBody: ViewConstrainingView { spaceBetweenLabels?.constant = 0 } } + + public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + + super.setWithModel(model, delegateObject, additionalData) + guard let headlineBodyModel = model as? HeadlineBodyModel else { + return + } + + style(with: headlineBodyModel.style) + + headlineLabel.setWithModel(headlineBodyModel.headline, delegateObject, additionalData) + messageLabel.setWithModel(headlineBodyModel.body, delegateObject, additionalData) + } // MARK: - MVMCoreUIMoleculeViewProtocol open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { @@ -127,6 +140,7 @@ open class HeadlineBody: ViewConstrainingView { let headlineJSON = json?.optionalDictionaryForKey("headline") headlineLabel.setWithJSON(headlineJSON, delegateObject: delegateObject, additionalData: additionalData) + let bodyJSON = json?.optionalDictionaryForKey("body") messageLabel.setWithJSON(bodyJSON, delegateObject: delegateObject, additionalData: additionalData) } @@ -136,7 +150,7 @@ open class HeadlineBody: ViewConstrainingView { stylePageHeader() } - public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 58 } } diff --git a/MVMCoreUI/Models/Molecules/HeadlineBodyModel.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift similarity index 60% rename from MVMCoreUI/Models/Molecules/HeadlineBodyModel.swift rename to MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift index 76337703..6ce51d3e 100644 --- a/MVMCoreUI/Models/Molecules/HeadlineBodyModel.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift @@ -10,11 +10,14 @@ import Foundation @objcMembers public class HeadlineBodyModel: MoleculeProtocol { public static var identifier: String = "headlineBody" - public var backgroundColor: String? - public var headline: LabelModel? + public var headline: LabelModel + public var body: LabelModel + public var style: String? + public var backgroundColor: Color? - public init(headline: LabelModel?) { + public init(headline: LabelModel, body: LabelModel) { self.headline = headline + self.body = body } } diff --git a/MVMCoreUI/Organisms/Carousel.swift b/MVMCoreUI/Organisms/Carousel.swift index d0efcce3..181ae372 100644 --- a/MVMCoreUI/Organisms/Carousel.swift +++ b/MVMCoreUI/Organisms/Carousel.swift @@ -8,7 +8,8 @@ import UIKit -open class Carousel: ViewConstrainingView { +open class Carousel: ViewConstrainingView, ModelMoleculeViewProtocol { + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) /// The current index of the collection view. Includes dummy cells when looping. @@ -28,13 +29,13 @@ open class Carousel: ViewConstrainingView { var numberOfPages = 0 /// The json for the molecules. - var molecules: [[AnyHashable: Any]]? + var molecules: [MoleculeProtocol]? /// The horizontal alignment of the cell in the collection view. Only noticeable if the itemWidthPercent is less than 100%. var itemAlignment = UICollectionView.ScrollPosition.left /// From 0-1. The item width as a percent of the carousel width. - var itemWidthPercent: CGFloat = 1 + var itemWidthPercent: Float = 1 /// The height of the carousel. Default is 300. var collectionViewHeight: NSLayoutConstraint? @@ -79,25 +80,37 @@ open class Carousel: ViewConstrainingView { } // MARK: - MVMCoreUIMoleculeViewProtocol - open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + //TODO: Model, Change to model + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + guard let caroselModel = model as? CarouselModel else { + return + } + + #warning("This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView.") + //TODO: This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView. + setUpDefaultWithModel(model, delegateObject, additionalData) + collectionView.backgroundColor = backgroundColor collectionView.layer.borderColor = backgroundColor?.cgColor - collectionView.layer.borderWidth = (json?.boolForKey("border") ?? false) ? 1 : 0 + collectionView.layer.borderWidth = (caroselModel.border ?? false) ? 1 : 0 backgroundColor = .white - registerCells(with: json, delegateObject: delegateObject) - setupLayout(with: json) - prepareMolecules(with: json) - itemWidthPercent = (json?.optionalCGFloatForKey("itemWidthPercent") ?? 100) / 100 - setAlignment(with: json?.optionalStringForKey("itemAlignment")) - if let height = json?.optionalCGFloatForKey("height") { - collectionViewHeight?.constant = height + + registerCells(with: caroselModel, delegateObject: delegateObject) + setupLayout(with: caroselModel) + prepareMolecules(with: caroselModel) + itemWidthPercent = (caroselModel.itemWidthPercent ?? 100) / 100 + setAlignment(with: caroselModel.itemAlignment) + + if let height = caroselModel.height { + collectionViewHeight?.constant = CGFloat(height) collectionViewHeight?.isActive = true } - setupPagingMolecule(json: json?.optionalDictionaryForKey("pagingMolecule"), delegateObject: delegateObject) + + setupPagingMolecule(caroselModel.pagingMolecule, delegateObject: delegateObject) collectionView.reloadData() } - + + open override func shouldSetHorizontalMargins(_ shouldSet: Bool) { super.shouldSetHorizontalMargins(shouldSet) updateViewHorizontalDefaults = false @@ -105,24 +118,25 @@ open class Carousel: ViewConstrainingView { // MARK: - JSON Setters /// Updates the layout being used - func setupLayout(with json:[AnyHashable: Any]?) { + + func setupLayout(with carouselModel: CarouselModel?) { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .horizontal - layout.minimumLineSpacing = json?["spacing"] as? CGFloat ?? 1 + layout.minimumLineSpacing = CGFloat(carouselModel?.spacing ?? 1) layout.minimumInteritemSpacing = 0 collectionView.collectionViewLayout = layout } - - func prepareMolecules(with json: [AnyHashable: Any]?) { - guard let newMolecules = json?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] else { + + func prepareMolecules(with carouselModel: CarouselModel?) { + guard let newMolecules = carouselModel?.molecules else { numberOfPages = 0 molecules = nil return } - + numberOfPages = newMolecules.count molecules = newMolecules - if json?.boolForKey("loop") ?? false && newMolecules.count > 2 { + if carouselModel?.loop ?? false && newMolecules.count > 2 { // Sets up the row data with buffer cells on each side (for illusion of endless scroll... also has one more buffer cell on each side in case we can peek that cell). loop = true molecules?.insert(newMolecules.last!, at: 0) @@ -132,36 +146,33 @@ open class Carousel: ViewConstrainingView { } pageIndex = 0 } - + + /// Sets up the paging molecule + open func setupPagingMolecule(_ molecule: PagingMoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) { + var pagingView: (UIView & MVMCoreUIPagingProtocol)? = nil + if let molecule = molecule { + pagingView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(molecule, delegateObject, true) as? (UIView & MVMCoreUIPagingProtocol) + } + addPaging(view: pagingView, position: (CGFloat(molecule?.position ?? 20))) + } + /// Registers the cells with the collection view - func registerCells(with json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) { - if let molecules = json?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] { - for molecule in molecules { - if let info = getMoleculeInfo(with: molecule, delegateObject: delegateObject) { - collectionView.register(info.class, forCellWithReuseIdentifier: info.identifier) - } + func registerCells(with carouselModel: CarouselModel, delegateObject: MVMCoreUIDelegateObject?) { + for molecule in carouselModel.molecules { + if let info = getMoleculeInfo(with: molecule, delegateObject: delegateObject) { + collectionView.register(info.class, forCellWithReuseIdentifier: info.identifier) } } } - - /// Sets up the paging molecule - open func setupPagingMolecule(json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) { - var pagingView: (UIView & MVMCoreUIPagingProtocol)? = nil - if let json = json { - pagingView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: json, delegateObject: delegateObject, constrainIfNeeded: true) as? (UIView & MVMCoreUIPagingProtocol) - } - addPaging(view: pagingView, position: (json?.optionalCGFloatForKey("position") ?? 20)) - } // MARK: - Convenience /// Returns the (identifier, class) of the molecule for the given map. - func getMoleculeInfo(with molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> (identifier: String, class: AnyClass, molecule: [AnyHashable: Any])? { - guard let molecule = molecule, - let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule), - let moleculeName = moleculeClass.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) else { - return nil + func getMoleculeInfo(with molecule: MoleculeProtocol, delegateObject: MVMCoreUIDelegateObject?) -> (identifier: String, class: AnyClass, molecule: MoleculeProtocol)? { + guard let className = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(molecule) , + let moleculeName = (className as? ModelMoleculeViewProtocol)?.nameForReuse(molecule, delegateObject) ?? molecule.moleculeName else { + return nil } - return (moleculeName, moleculeClass, molecule) + return (moleculeName, className, molecule) } /// Sets the alignment from the string. @@ -252,7 +263,7 @@ open class Carousel: ViewConstrainingView { extension Carousel: UICollectionViewDelegateFlowLayout { public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { - let itemWidth = collectionView.bounds.width * itemWidthPercent + let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent) return CGSize(width: itemWidth, height: collectionView.bounds.height) } @@ -272,9 +283,9 @@ extension Carousel: UICollectionViewDataSource { return UICollectionViewCell() } let cell = collectionView.dequeueReusableCell(withReuseIdentifier: moleculeInfo.identifier, for: indexPath) - if let protocolCell = cell as? MVMCoreUIMoleculeViewProtocol { + if let protocolCell = cell as? MVMCoreUIMoleculeViewProtocol & ModelMoleculeViewProtocol { protocolCell.reset?() - protocolCell.setWithJSON(moleculeInfo.molecule, delegateObject: nil, additionalData: nil) + protocolCell.setWithModel(moleculeInfo.molecule, nil, nil) protocolCell.updateView(collectionView.bounds.width) } setAccessiblity(cell, index: indexPath.row) @@ -322,7 +333,7 @@ extension Carousel: UIScrollViewDelegate { } // Checks if the user is not paging but attempting to drag endlessly and goes out of bounds. Caps the index. if let separatorWidth = (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing { - let itemWidth = collectionView.bounds.width * itemWidthPercent + let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent) let index = scrollView.contentOffset.x / (itemWidth + separatorWidth) let lastCellIndex = collectionView(collectionView, numberOfItemsInSection: 0) - 1 if index < 1 { @@ -359,7 +370,7 @@ extension Carousel: UIScrollViewDelegate { } // We switch cards if we pass the velocity threshold or position threshold (currently 50%). - let itemWidth = collectionView.bounds.width * itemWidthPercent + let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent) var cellToSwipeTo = Int(scrollView.contentOffset.x/(itemWidth + separatorWidth) + 0.5) let lastCellIndex = collectionView(collectionView, numberOfItemsInSection: 0) - 1 let velocityThreshold: CGFloat = 1.1 diff --git a/MVMCoreUI/Models/Molecules/MoleculeStackModel.swift b/MVMCoreUI/Organisms/MoleculeStackModel.swift similarity index 89% rename from MVMCoreUI/Models/Molecules/MoleculeStackModel.swift rename to MVMCoreUI/Organisms/MoleculeStackModel.swift index 530c7393..73c7c0a5 100644 --- a/MVMCoreUI/Models/Molecules/MoleculeStackModel.swift +++ b/MVMCoreUI/Organisms/MoleculeStackModel.swift @@ -10,12 +10,12 @@ import Foundation @objcMembers public class MoleculeStackModel: ContainerModel, MoleculeProtocol { public static var identifier: String = "moleculeStack" - public var backgroundColor: String? - public var molecules: [MoleculeStackItemModel] + public var backgroundColor: Color? + public var molecules: [StackItemModel] public var axis: NSLayoutConstraint.Axis = .vertical public var spacing: CGFloat = 16.0 - public init(molecules: [MoleculeStackItemModel]) { + public init(molecules: [StackItemModel]) { self.molecules = molecules super.init() } @@ -29,7 +29,7 @@ import Foundation required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: StackCodingKeys.self) - molecules = try typeContainer.decodeMolecules(codingKey: .molecules) as! [MoleculeStackItemModel] + molecules = try typeContainer.decodeMolecules(codingKey: .molecules) as! [StackItemModel] if let axisString = try typeContainer.decodeIfPresent(String.self, forKey: .axis), let optionalAxis = NSLayoutConstraint.Axis(rawValue: axisString) { axis = optionalAxis } diff --git a/MVMCoreUI/Organisms/MoleculeStackView.swift b/MVMCoreUI/Organisms/MoleculeStackView.swift index 3845ecdb..738333d9 100644 --- a/MVMCoreUI/Organisms/MoleculeStackView.swift +++ b/MVMCoreUI/Organisms/MoleculeStackView.swift @@ -81,8 +81,6 @@ open class MoleculeStackView: Container { public override func updateView(_ size: CGFloat) { super.updateView(size) - directionalLayoutMargins.leading = 0 - directionalLayoutMargins.trailing = 0 for item in stackItems { item.updateView(size) } @@ -97,7 +95,7 @@ open class MoleculeStackView: Container { } } - public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { let previousModel = stackModel super.setWithModel(model, delegateObject, additionalData) removeAllItemViews() @@ -141,9 +139,9 @@ open class MoleculeStackView: Container { let data = try! JSONSerialization.data(withJSONObject: json!) let decoder = JSONDecoder() let model = try! decoder.decode(MoleculeStackModel.self, from: data) - setWithModel(model, delegateObject, additionalData as? [String : AnyHashable]) + setWithModel(model, delegateObject, additionalData) } else { - setWithModel(model, delegateObject, additionalData as? [String : AnyHashable]) + setWithModel(model, delegateObject, additionalData) } } @@ -212,7 +210,7 @@ open class MoleculeStackView: Container { func addView(_ view: View, lastItem: Bool) { guard let model = view.model else { return } let stackItem = StackItem(andContain: view) - stackItem.model = MoleculeStackItemModel(with: model) + stackItem.model = StackItemModel(with: model) addStackItem(stackItem, lastItem: lastItem) } diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift b/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift index c0c8211f..f64162db 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIDelegateObject.swift @@ -12,8 +12,8 @@ open class MVMCoreUIDelegateObject: DelegateObject { public weak var formValidationProtocol: FormValidationProtocol? public weak var buttonDelegate: ButtonDelegateProtocol? public weak var uiTextFieldDelegate: UITextFieldDelegate? - public weak var moleculeDelegate: MoleculeDelegateProtocol? - + public var moleculeDelegate: MoleculeDelegateProtocol? + open override func setAll(withDelegate delegate: Any) { super.setAll(withDelegate: delegate) formValidationProtocol = delegate as? FormValidationProtocol @@ -26,3 +26,4 @@ open class MVMCoreUIDelegateObject: DelegateObject { return controller?.delegateObject?() as? MVMCoreUIDelegateObject } } + diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift index 650264fc..45ce1bab 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift @@ -8,9 +8,15 @@ import Foundation - public extension MVMCoreUIMoleculeMappingObject { + func getMoleculeClass(_ model: MoleculeProtocol) -> AnyClass? { + if let moleculeName = model.moleculeName { + return moleculeMapping.object(forKey: moleculeName) as? AnyClass + } + return nil + } + func createMolecule(_ model: MoleculeProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> (UIView & MVMCoreUIMoleculeViewProtocol)? { return createMolecule(model, delegateObject, false) } @@ -21,21 +27,21 @@ public extension MVMCoreUIMoleculeMappingObject { return nil } - let setData = {(molecule: UIView & MVMCoreUIMoleculeViewProtocol) in + let setData = {() in if let molecule = molecule as? ModelMoleculeViewProtocol { molecule.setWithModel(model, delegateObject, nil) } else { - molecule.setWithJSON(model.dictionary, delegateObject: delegateObject, additionalData: nil) + molecule.setWithJSON?(model.toJSON(), delegateObject: delegateObject, additionalData: nil) } } if constrainIfNeeded, let castMolecule = molecule as? MVMCoreUIViewConstrainingProtocol, castMolecule.needsToBeConstrained?() ?? false { - let view = ViewConstrainingView(molecule: molecule, alignment: castMolecule.alignment?() ?? .fill) - setData(view) + let view = ViewConstrainingView(molecule: molecule, alignment: castMolecule.horizontalAlignment?() ?? .fill) + setData() return view } else { - setData(molecule) + setData() return molecule } } diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 4b597288..7fa326af 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -35,7 +35,7 @@ @"twoButtonView": TwoButtonView.class, @"footer": StandardFooterView.class, @"caretView": CaretView.class, - @"caretButton": CaretButton.class, + @"caretLink": CaretButton.class, @"textField": MFTextField.class, @"dropDown": DropDown.class, @"digitTextField": MFDigitTextField.class, @@ -122,7 +122,7 @@ // Check if we need to constrain this view. UIView *castMolecule = [molecule conformsToProtocol:@protocol(MVMCoreUIViewConstrainingProtocol)] ? (UIView *)molecule : nil; if (constrainIfNeeded && [castMolecule respondsToSelector:@selector(needsToBeConstrained)] && [castMolecule needsToBeConstrained]) { - molecule = [[ViewConstrainingView alloc] initWithMolecule:molecule alignment:[castMolecule respondsToSelector:@selector(alignment)] ? [castMolecule alignment] : UIStackViewAlignmentFill]; + molecule = [[ViewConstrainingView alloc] initWithMolecule:molecule alignment:[castMolecule respondsToSelector:@selector(horizontalAlignment)] ? [castMolecule horizontalAlignment] : UIStackViewAlignmentFill]; } [molecule setWithJSON:json delegateObject:delegateObject additionalData:nil]; return molecule; diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIViewConstrainingProtocol.h b/MVMCoreUI/OtherHandlers/MVMCoreUIViewConstrainingProtocol.h index a2ac2340..12aaacdb 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIViewConstrainingProtocol.h +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIViewConstrainingProtocol.h @@ -15,9 +15,6 @@ /// Notifies the creator that the view may not be suitable to be shown on its own and it needs to be added to a view to help with layout. - (BOOL)needsToBeConstrained; -/// The alignment if constrained. -- (UIStackViewAlignment)alignment __deprecated; - /// The alignment if constrained. - (UIStackViewAlignment)horizontalAlignment; diff --git a/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift b/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift new file mode 100644 index 00000000..1611930a --- /dev/null +++ b/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift @@ -0,0 +1,46 @@ +// +// MoleculeDelegateProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/26/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol MoleculeDelegateProtocol { + + /// returns a module for the corresponding module name. + func getModuleWithName(_ name: String?) -> [AnyHashable : Any]? + func getModuleWithName(_ moleculeName: String) -> MoleculeProtocol? + + /// Notifies the delegate that the molecule layout update. Should be called when the layout may change due to an async method. + func moleculeLayoutUpdated(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) //optional + + /// Asks the delegate to add or remove molecules. + //optional + func addMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) + func removeMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) + + //optional + func addMolecules(_ molecules: [ListItemModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) + func removeMolecules(_ molecules: [ListItemModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) +} + +extension MoleculeDelegateProtocol { + public func moleculeLayoutUpdated(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) { + // Do Nothing + } + public func addMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { + // Do nothpublic ing + } + public func removeMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { + // Do nothing + } + public func addMolecules(_ molecules: [ListItemModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { + // Do nothpublic ing + } + public func removeMolecules(_ molecules: [ListItemModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { + // Do nothing + } +} diff --git a/MVMCoreUI/OtherHandlers/ModuleDelegateProtocol.swift b/MVMCoreUI/OtherHandlers/ModuleDelegateProtocol.swift new file mode 100644 index 00000000..70c271ce --- /dev/null +++ b/MVMCoreUI/OtherHandlers/ModuleDelegateProtocol.swift @@ -0,0 +1,14 @@ +// +// ModuleDelegateProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 12/6/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + + +public protocol ModuleDelegateProtocol { + func getModuleWithName(_ moleculeName: String) -> Model? +} diff --git a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift index 651d18a7..49045ef8 100644 --- a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift +++ b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift @@ -14,8 +14,7 @@ import Foundation ModelRegistry.register(HeaderModel.self) ModelRegistry.register(HeadlineBodyModel.self) ModelRegistry.register(MoleculeStackModel.self) - ModelRegistry.register(MoleculeStackItemModel.self) - ModelRegistry.register(ListItemModel.self) + ModelRegistry.register(StackItemModel.self) ModelRegistry.register(TextFieldModel.self) ModelRegistry.register(LineModel.self) ModelRegistry.register(ProgressBarModel.self) @@ -23,12 +22,27 @@ import Foundation ModelRegistry.register(CaretViewModel.self) ModelRegistry.register(DashLineModel.self) ModelRegistry.register(ImageViewModel.self) + ModelRegistry.register(TabsModel.self) + ModelRegistry.register(ScrollerModel.self) + // list items + ModelRegistry.register(ListItemModel.self) + ModelRegistry.register(DropDownListItemModel.self) + ModelRegistry.register(AccordionListItemModel.self) + ModelRegistry.register(TabsListItemModel.self) + + //need to move labelattributemodel to different method ModelRegistry.register(LabelAttributeFontModel.self) ModelRegistry.register(LabelAttributeColorModel.self) ModelRegistry.register(LabelAttributeImageModel.self) ModelRegistry.register(LabelAttributeUnderlineModel.self) ModelRegistry.register(LabelAttributeStrikeThroughModel.self) ModelRegistry.register(LabelAttributeActionModel.self) + + // + //ModelRegistry.register(ModuleMoleculeModel.self) + ModelRegistry.register(LeftRightLabelModel.self) + ModelRegistry.register(CaretViewModel.self) + ModelRegistry.register(CaretLinkModel.self) ModelRegistry.register(DoughnutChartModel.self) } } diff --git a/MVMCoreUI/Templates/MoleculeListCellProtocol.h b/MVMCoreUI/Templates/MoleculeListCellProtocol.h deleted file mode 100644 index 3fa19a02..00000000 --- a/MVMCoreUI/Templates/MoleculeListCellProtocol.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// MoleculeListCellProtocol.h -// MVMCoreUI -// -// Created by Scott Pfeil on 5/22/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// -#import -@class MVMCoreUIDelegateObject; - -@protocol MoleculeListCellProtocol -@optional - -/// Can set the separator according to what the moleculeList commands. -- (void)setSeparatorWithJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData indexPath:(nonnull NSIndexPath *)indexPath; - -/// Handle action -- (void)didSelectCellAtIndex:(nonnull NSIndexPath *)indexPath delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData; - -- (void)willDisplay; - -@end diff --git a/MVMCoreUI/Templates/MoleculeListCellProtocol.swift b/MVMCoreUI/Templates/MoleculeListCellProtocol.swift new file mode 100644 index 00000000..5d9b9525 --- /dev/null +++ b/MVMCoreUI/Templates/MoleculeListCellProtocol.swift @@ -0,0 +1,32 @@ +// +// MoleculeListCellProtocol.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 1/10/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol MoleculeListCellProtocol { + /// Can set the separator according to what the moleculeList commands. + func setLines(with model: LineModel?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, indexPath: IndexPath) + + /// Handle action when cell is pressed + func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) + + /// Called by the list when the cell will display. + func willDisplay() +} + +// Default implementation does nothing +extension MoleculeListCellProtocol { + public func setLines(with model: LineModel?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, indexPath: IndexPath) { + } + + public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + } + + func willDisplay() { + } +} diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index c941d9ce..03f4e0fc 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -8,9 +8,15 @@ import UIKit -open class MoleculeListTemplate: ThreeLayerTableViewController { - public var moleculesInfo: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])]? +open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol { + + public var moleculesInfo: [(identifier: String, class: AnyClass, molecule: ListItemModelProtocol)]? var observer: NSKeyValueObservation? + + public var templateModel: ListPageTemplateModel? + public override func parsePageJSON() { + parseTemplateJSON() + } open override var loadObject: MVMCoreLoadObject? { didSet { @@ -27,21 +33,17 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { } open override func viewForTop() -> UIView { -// guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), -// let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { -// return super.viewForTop() -// } - guard let moleculeModel = pageModel?.header, - let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(moleculeModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { - return super.viewForTop() + guard let headerModel = templateModel?.header, + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(headerModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { + return super.viewForTop() } return molecule } override open func viewForBottom() -> UIView { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), - let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { - return super.viewForBottom() + guard let footerModel = templateModel?.footer, + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(footerModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { + return super.viewForBottom() } return molecule } @@ -64,7 +66,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { open override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { guard let moleculeInfo = moleculesInfo?[indexPath.row], - let estimatedHeight = moleculeInfo.class.estimatedHeight?(forRow: moleculeInfo.molecule, delegateObject: delegateObject() as? MVMCoreUIDelegateObject) else { + let estimatedHeight = (moleculeInfo.class as? ModelMoleculeViewProtocol.Type)?.estimatedHeight(forRow: moleculeInfo.molecule, delegateObject: delegateObject() as? MVMCoreUIDelegateObject) else { return 0 } return estimatedHeight @@ -83,23 +85,23 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { let moleculeCell = cell as? MVMCoreUIMoleculeViewProtocol moleculeCell?.reset?() if let protocolCell = cell as? MoleculeListCellProtocol { - protocolCell.setSeparatorWithJSON?(loadObject?.pageJSON?.optionalDictionaryForKey("separator"), delegateObject: delegate, additionalData: nil, indexPath: indexPath) + protocolCell.setLines(with: templateModel?.line, delegateObject: delegate, additionalData: nil, indexPath: indexPath) } - moleculeCell?.setWithJSON(moleculeInfo.molecule, delegateObject: delegate, additionalData: nil) - moleculeCell?.updateView(tableView.bounds.width) + (moleculeCell as? ModelMoleculeViewProtocol)?.setWithModel(moleculeInfo.molecule, delegate, nil) + moleculeCell?.updateView(tableView.bounds.width) return cell } open override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { if let protocolCell = cell as? MoleculeListCellProtocol { - protocolCell.willDisplay?() + protocolCell.willDisplay() } } open override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if let cell = tableView.cellForRow(at: indexPath) as? MoleculeListCellProtocol { - cell.didSelectCell?(atIndex: indexPath, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, additionalData: nil) + cell.didSelectCell(at: indexPath, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, additionalData: nil) } } @@ -116,7 +118,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { } // MARK: - MoleculeDelegateProtocol - open override func moleculeLayoutUpdated(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) { + open func moleculeLayoutUpdated(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) { if let tableView = tableView { let point = molecule.convert(molecule.bounds.origin, to: tableView) if let indexPath = tableView.indexPathForRow(at: point), tableView.indexPathsForVisibleRows?.contains(indexPath) ?? false { @@ -125,31 +127,31 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { } } } - - open override func addMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { + + public func addMolecules(_ molecules: [ListItemModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { // This dispatch is needed to fix a race condition that can occur if this function is called during the table setup. - DispatchQueue.main.async { - guard let indexPath = self.tableView?.indexPath(for: sender) else { return } - var indexPaths: [IndexPath] = [] - for molecule in molecules { - if let info = self.getMoleculeInfo(with: molecule) { - self.tableView?.register(info.class, forCellReuseIdentifier: info.identifier) - let index = indexPath.row + 1 + indexPaths.count - self.moleculesInfo?.insert(info, at: index) - indexPaths.append(IndexPath(row: index, section: 0)) - } - } - self.tableView?.insertRows(at: indexPaths, with: animation) - self.updateViewConstraints() - self.view.layoutIfNeeded() - } + DispatchQueue.main.async { + guard let indexPath = self.tableView?.indexPath(for: sender) else { return } + var indexPaths: [IndexPath] = [] + for molecule in molecules { + if let info = self.getMoleculeInfo(with: molecule) { + self.tableView?.register(info.class, forCellReuseIdentifier: info.identifier) + let index = indexPath.row + 1 + indexPaths.count + self.moleculesInfo?.insert(info, at: index) + indexPaths.append(IndexPath(row: index, section: 0)) + } + } + self.tableView?.insertRows(at: indexPaths, with: animation) + self.updateViewConstraints() + self.view.layoutIfNeeded() + } } - - open override func removeMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { + public func removeMolecules(_ molecules: [ListItemModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { var indexPaths: [IndexPath] = [] + //TODO: cehck for molecule protocola eqality for molecule in molecules { if let removeIndex = moleculesInfo?.firstIndex(where: { (moleculeInfo) -> Bool in - return NSDictionary(dictionary: molecule).isEqual(to: moleculeInfo.molecule) + return molecule.toJSONString() == moleculeInfo.molecule.toJSONString() }) { moleculesInfo?.remove(at: removeIndex) indexPaths.append(IndexPath(row: removeIndex + indexPaths.count, section: 0)) @@ -162,19 +164,19 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { // MARK: - Convenience /// Returns the (identifier, class) of the molecule for the given map. - func getMoleculeInfo(with molecule: [AnyHashable: Any]?) -> (identifier: String, class: AnyClass, molecule: [AnyHashable: Any])? { - guard let molecule = molecule, - let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule), - let moleculeName = moleculeClass.name?(forReuse: molecule, delegateObject: delegateObject() as? MVMCoreUIDelegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) else { + func getMoleculeInfo(with listItem: ListItemModelProtocol?) -> (identifier: String, class: AnyClass, molecule: ListItemModelProtocol)? { + guard let listItem = listItem, + let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(listItem), + let moleculeName = (moleculeClass as? ModelMoleculeViewProtocol)?.nameForReuse(listItem, delegateObject() as? MVMCoreUIDelegateObject) ?? listItem.moleculeName else { return nil } - return (moleculeName, moleculeClass, molecule) + return (moleculeName, moleculeClass, listItem) } /// Sets up the molecule list and ensures no errors loading all content. - func getMoleculeInfoList() -> [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])]? { - var moleculeList: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])] = [] - if let molecules = loadObject?.pageJSON?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] { + func getMoleculeInfoList() -> [(identifier: String, class: AnyClass, molecule: ListItemModelProtocol)]? { + var moleculeList: [(identifier: String, class: AnyClass, molecule: ListItemModelProtocol)] = [] + if let molecules = templateModel?.molecules { for molecule in molecules { if let info = getMoleculeInfo(with: molecule) { moleculeList.append(info) @@ -186,15 +188,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { /// Sets up the header, footer, molecule list and ensures no errors loading all content. func setup() { - var moleculeList: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])] = [] - if let molecules = loadObject?.pageJSON?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] { - for molecule in molecules { - if let info = getMoleculeInfo(with: molecule) { - moleculeList.append(info) - } - } - } - moleculesInfo = moleculeList + moleculesInfo = getMoleculeInfoList() } /// Adds modules from requiredModules() to the MVMCoreViewControllerMapping.requiredModules map. diff --git a/MVMCoreUI/Templates/MoleculeStackTemplate.swift b/MVMCoreUI/Templates/MoleculeStackTemplate.swift index ee4af899..3dc9a58c 100644 --- a/MVMCoreUI/Templates/MoleculeStackTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeStackTemplate.swift @@ -8,8 +8,13 @@ import UIKit -open class MoleculeStackTemplate: ThreeLayerViewController { +open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol { + var observer: NSKeyValueObservation? + public var templateModel: StackPageTemplateModel? + public override func parsePageJSON() { + parseTemplateJSON() + } open override var loadObject: MVMCoreLoadObject? { didSet { @@ -30,30 +35,30 @@ open class MoleculeStackTemplate: ThreeLayerViewController { } open override func viewForTop() -> UIView? { - guard let moleculeModel = pageModel?.header, - let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(moleculeModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { - return nil + guard let headerModel = templateModel?.header, + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(headerModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { + return nil } -// guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { -// return nil -// } return molecule } open override func viewForMiddle() -> UIView? { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("moleculeStack") else { - return nil + + guard let moleculeStackModel = templateModel?.moleculeStack else { + return nil } + let stack = MoleculeStackView(frame: .zero) stack.useStackSpacingBeforeFirstItem = true stack.moleculesShouldSetHorizontalMargins = true - stack.setWithJSON(moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, additionalData: nil) + stack.setWithModel(moleculeStackModel, delegateObject() as? MVMCoreUIDelegateObject, nil) return stack } override open func viewForBottom() -> UIView? { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { - return nil + guard let footerModel = templateModel?.footer, + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(footerModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { + return nil } return molecule } diff --git a/MVMCoreUI/Templates/ThreeLayerTemplate.swift b/MVMCoreUI/Templates/ThreeLayerTemplate.swift index 20475a6b..67326d09 100644 --- a/MVMCoreUI/Templates/ThreeLayerTemplate.swift +++ b/MVMCoreUI/Templates/ThreeLayerTemplate.swift @@ -8,8 +8,13 @@ import UIKit -@objcMembers open class ThreeLayerTemplate: ThreeLayerViewController { +@objcMembers open class ThreeLayerTemplate: ThreeLayerViewController, TemplateProtocol { + public var templateModel: ThreeLayerPageTemplateModel? + public override func parsePageJSON() { + parseTemplateJSON() + } + override open func viewDidLoad() { super.viewDidLoad() bottomViewOutsideOfScroll = true @@ -20,24 +25,28 @@ import UIKit super.newDataBuildScreen() heightConstraint?.isActive = true } - + + open override func viewForTop() -> UIView? { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { - return nil + guard let headerModel = templateModel?.header, + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(headerModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { + return nil } return molecule } open override func viewForMiddle() -> UIView? { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("middle"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { - return nil + guard let middleModel = templateModel?.middle, + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(middleModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { + return nil } return molecule } override open func viewForBottom() -> UIView? { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { - return nil + guard let footerModel = templateModel?.footer, + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(footerModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { + return nil } return molecule }