merging
This commit is contained in:
commit
24ed53366b
@ -236,6 +236,8 @@
|
||||
AA997252247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA997251247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift */; };
|
||||
AAA74A172410C04600080241 /* HeadersH2NoButtonsBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */; };
|
||||
AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */; };
|
||||
AAA7CD69250641F90045B959 /* HeartModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA7CD68250641F90045B959 /* HeartModel.swift */; };
|
||||
AAA7CD6B250642080045B959 /* Heart.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA7CD6A250642080045B959 /* Heart.swift */; };
|
||||
AAA905DF24D1758700D1EFAB /* ListThreeColumnBillHistoryModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA905DE24D1758700D1EFAB /* ListThreeColumnBillHistoryModel.swift */; };
|
||||
AAA905E124D1759A00D1EFAB /* ListThreeColumnBillHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA905E024D1759A00D1EFAB /* ListThreeColumnBillHistory.swift */; };
|
||||
AAB7EDEF246ADA1600E54929 /* ListProgressBarThinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB7EDEE246ADA1600E54929 /* ListProgressBarThinModel.swift */; };
|
||||
@ -303,8 +305,12 @@
|
||||
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; };
|
||||
D20C7009250BF99B0095B21C /* TopNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20C7008250BF99B0095B21C /* TopNotificationModel.swift */; };
|
||||
D20C700B250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */; };
|
||||
D20F3B44252E00E4004B3F56 /* PageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20F3B43252E00E4004B3F56 /* PageProtocol.swift */; };
|
||||
D20F3B5E252F9B5E004B3F56 /* NavigationBarRefreshProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20F3B5D252F9B5D004B3F56 /* NavigationBarRefreshProtocol.swift */; };
|
||||
D20FB165241A5D75004AFC3A /* NavigationItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20FB164241A5D75004AFC3A /* NavigationItemModel.swift */; };
|
||||
D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; };
|
||||
D2169301251E51E7002A6324 /* SectionListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2169300251E51E7002A6324 /* SectionListTemplate.swift */; };
|
||||
D2169303251E53D9002A6324 /* SectionListTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2169302251E53D9002A6324 /* SectionListTemplateModel.swift */; };
|
||||
D21B7F602437C5BC00051ABF /* MoleculeStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21B7F5E2437C5BC00051ABF /* MoleculeStackView.swift */; };
|
||||
D21B7F71243BAC1600051ABF /* CollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21B7F70243BAC1600051ABF /* CollectionViewCell.swift */; };
|
||||
D21B7F73243BAC6800051ABF /* CollectionItemModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21B7F72243BAC6800051ABF /* CollectionItemModelProtocol.swift */; };
|
||||
@ -465,6 +471,10 @@
|
||||
D2CAC7CF2511052300C75681 /* CollapsableNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7CE2511052300C75681 /* CollapsableNotificationModel.swift */; };
|
||||
D2CAC7D12511058C00C75681 /* MVMCoreUITopAlertMainView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7D02511058C00C75681 /* MVMCoreUITopAlertMainView+Extension.swift */; };
|
||||
D2CAC7D3251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7D2251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift */; };
|
||||
D2D2FCF0252B72AF0033EAAA /* MoleculeSectionFooterModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D2FCEF252B72AF0033EAAA /* MoleculeSectionFooterModel.swift */; };
|
||||
D2D2FCF3252B72CF0033EAAA /* MoleculeSectionFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D2FCF2252B72CF0033EAAA /* MoleculeSectionFooter.swift */; };
|
||||
D2D3957A252FDBB300047B11 /* ModalSectionListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D39579252FDBB300047B11 /* ModalSectionListTemplate.swift */; };
|
||||
D2D3957D252FDBCD00047B11 /* ModalSectionListTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D3957C252FDBCD00047B11 /* ModalSectionListTemplateModel.swift */; };
|
||||
D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */; };
|
||||
D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */; };
|
||||
D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D90B41240463E100DD6EC9 /* MoleculeHeaderModel.swift */; };
|
||||
@ -482,6 +492,9 @@
|
||||
D2E2A99F23E07F8A000B42E6 /* PillButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2A99E23E07F8A000B42E6 /* PillButton.swift */; };
|
||||
D2E2A9A123E095AB000B42E6 /* ButtonModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2A9A023E095AB000B42E6 /* ButtonModelProtocol.swift */; };
|
||||
D2E2A9A323E096B1000B42E6 /* DisableableModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2A9A223E096B1000B42E6 /* DisableableModelProtocol.swift */; };
|
||||
D2EC7BD52527B7A600F540AF /* MoleculeSectionHeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EC7BD42527B7A600F540AF /* MoleculeSectionHeaderModel.swift */; };
|
||||
D2EC7BD92527B7CF00F540AF /* MoleculeSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EC7BD82527B7CF00F540AF /* MoleculeSectionHeader.swift */; };
|
||||
D2EC7BDD2527B83700F540AF /* SectionHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EC7BDC2527B83700F540AF /* SectionHeaderFooterView.swift */; };
|
||||
D2FA83D22513EA6900564112 /* NotificationXButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D12513EA6900564112 /* NotificationXButton.swift */; };
|
||||
D2FA83D42514F80C00564112 /* CollapsableNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D32514F80C00564112 /* CollapsableNotification.swift */; };
|
||||
D2FA83D62515021F00564112 /* CollapsableNotificationTopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */; };
|
||||
@ -729,6 +742,8 @@
|
||||
AA997251247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconAllTextLinks.swift; sourceTree = "<group>"; };
|
||||
AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyText.swift; sourceTree = "<group>"; };
|
||||
AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyTextModel.swift; sourceTree = "<group>"; };
|
||||
AAA7CD68250641F90045B959 /* HeartModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartModel.swift; sourceTree = "<group>"; };
|
||||
AAA7CD6A250642080045B959 /* Heart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Heart.swift; sourceTree = "<group>"; };
|
||||
AAA905DE24D1758700D1EFAB /* ListThreeColumnBillHistoryModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnBillHistoryModel.swift; sourceTree = "<group>"; };
|
||||
AAA905E024D1759A00D1EFAB /* ListThreeColumnBillHistory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnBillHistory.swift; sourceTree = "<group>"; };
|
||||
AAB7EDEE246ADA1600E54929 /* ListProgressBarThinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListProgressBarThinModel.swift; sourceTree = "<group>"; };
|
||||
@ -796,8 +811,12 @@
|
||||
D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = "<group>"; };
|
||||
D20C7008250BF99B0095B21C /* TopNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopNotificationModel.swift; sourceTree = "<group>"; };
|
||||
D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUITopAlertView+Extension.swift"; sourceTree = "<group>"; };
|
||||
D20F3B43252E00E4004B3F56 /* PageProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageProtocol.swift; sourceTree = "<group>"; };
|
||||
D20F3B5D252F9B5D004B3F56 /* NavigationBarRefreshProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarRefreshProtocol.swift; sourceTree = "<group>"; };
|
||||
D20FB164241A5D75004AFC3A /* NavigationItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItemModel.swift; sourceTree = "<group>"; };
|
||||
D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
|
||||
D2169300251E51E7002A6324 /* SectionListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionListTemplate.swift; sourceTree = "<group>"; };
|
||||
D2169302251E53D9002A6324 /* SectionListTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionListTemplateModel.swift; sourceTree = "<group>"; };
|
||||
D21B7F5E2437C5BC00051ABF /* MoleculeStackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeStackView.swift; sourceTree = "<group>"; };
|
||||
D21B7F70243BAC1600051ABF /* CollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewCell.swift; sourceTree = "<group>"; };
|
||||
D21B7F72243BAC6800051ABF /* CollectionItemModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionItemModelProtocol.swift; sourceTree = "<group>"; };
|
||||
@ -960,6 +979,10 @@
|
||||
D2CAC7CE2511052300C75681 /* CollapsableNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotificationModel.swift; sourceTree = "<group>"; };
|
||||
D2CAC7D02511058C00C75681 /* MVMCoreUITopAlertMainView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUITopAlertMainView+Extension.swift"; sourceTree = "<group>"; };
|
||||
D2CAC7D2251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUITopAlertExpandableView+Extension.swift"; sourceTree = "<group>"; };
|
||||
D2D2FCEF252B72AF0033EAAA /* MoleculeSectionFooterModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionFooterModel.swift; sourceTree = "<group>"; };
|
||||
D2D2FCF2252B72CF0033EAAA /* MoleculeSectionFooter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionFooter.swift; sourceTree = "<group>"; };
|
||||
D2D39579252FDBB300047B11 /* ModalSectionListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalSectionListTemplate.swift; sourceTree = "<group>"; };
|
||||
D2D3957C252FDBCD00047B11 /* ModalSectionListTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalSectionListTemplateModel.swift; sourceTree = "<group>"; };
|
||||
D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scroller.swift; sourceTree = "<group>"; };
|
||||
D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTemplate.swift; sourceTree = "<group>"; };
|
||||
D2D90B41240463E100DD6EC9 /* MoleculeHeaderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeHeaderModel.swift; sourceTree = "<group>"; };
|
||||
@ -976,6 +999,9 @@
|
||||
D2E2A99E23E07F8A000B42E6 /* PillButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillButton.swift; sourceTree = "<group>"; };
|
||||
D2E2A9A023E095AB000B42E6 /* ButtonModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonModelProtocol.swift; sourceTree = "<group>"; };
|
||||
D2E2A9A223E096B1000B42E6 /* DisableableModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisableableModelProtocol.swift; sourceTree = "<group>"; };
|
||||
D2EC7BD42527B7A600F540AF /* MoleculeSectionHeaderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionHeaderModel.swift; sourceTree = "<group>"; };
|
||||
D2EC7BD82527B7CF00F540AF /* MoleculeSectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionHeader.swift; sourceTree = "<group>"; };
|
||||
D2EC7BDC2527B83700F540AF /* SectionHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionHeaderFooterView.swift; sourceTree = "<group>"; };
|
||||
D2FA83D12513EA6900564112 /* NotificationXButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationXButton.swift; sourceTree = "<group>"; };
|
||||
D2FA83D32514F80C00564112 /* CollapsableNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotification.swift; sourceTree = "<group>"; };
|
||||
D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotificationTopView.swift; sourceTree = "<group>"; };
|
||||
@ -1589,6 +1615,8 @@
|
||||
D2092348244A51D40044AD09 /* RadioSwatchModel.swift */,
|
||||
AAB9C109243496DD00151545 /* RadioSwatch.swift */,
|
||||
AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */,
|
||||
AAA7CD68250641F90045B959 /* HeartModel.swift */,
|
||||
AAA7CD6A250642080045B959 /* Heart.swift */,
|
||||
);
|
||||
path = Selectors;
|
||||
sourceTree = "<group>";
|
||||
@ -1691,6 +1719,10 @@
|
||||
D264FAA4243F66A500D98315 /* CollectionTemplateItemProtocol.swift */,
|
||||
D264FA8B243BCD8E00D98315 /* CollectionTemplateModel.swift */,
|
||||
D264FA8D243BCD9A00D98315 /* CollectionTemplate.swift */,
|
||||
D2169302251E53D9002A6324 /* SectionListTemplateModel.swift */,
|
||||
D2169300251E51E7002A6324 /* SectionListTemplate.swift */,
|
||||
D2D3957C252FDBCD00047B11 /* ModalSectionListTemplateModel.swift */,
|
||||
D2D39579252FDBB300047B11 /* ModalSectionListTemplate.swift */,
|
||||
);
|
||||
path = Templates;
|
||||
sourceTree = "<group>";
|
||||
@ -1718,6 +1750,7 @@
|
||||
D29DF10E21E67A77003B2FB9 /* Molecules */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D2EC7BD22527A1E400F540AF /* HeadersAndFooters */,
|
||||
D2CAC7C9251104CB00C75681 /* TopNotification */,
|
||||
D2509ED42472EE0B001BFB9D /* NavigationBar */,
|
||||
D253BB9A24587023002DE544 /* OtherContainers */,
|
||||
@ -1726,12 +1759,6 @@
|
||||
D224798F2316A99F003FCCF9 /* LeftRightViews */,
|
||||
D224798E2316A995003FCCF9 /* HorizontalCombinationViews */,
|
||||
D224798D2316A988003FCCF9 /* VerticalCombinationViews */,
|
||||
01EB368C23609801006832FA /* HeaderModel.swift */,
|
||||
D256E9922412880000360572 /* Header.swift */,
|
||||
D2D90B41240463E100DD6EC9 /* MoleculeHeaderModel.swift */,
|
||||
D2A514662213885800345BFB /* MoleculeHeaderView.swift */,
|
||||
012A88EB238F084D00FE3DA1 /* FooterModel.swift */,
|
||||
D274CA322236A78900B01B62 /* FooterView.swift */,
|
||||
D260105723CF9CC500764D80 /* Doughnut */,
|
||||
);
|
||||
path = Molecules;
|
||||
@ -2033,6 +2060,7 @@
|
||||
0A5D59C323AD488600EFD9E9 /* Protocols */,
|
||||
0A7918F423F5E7EA00772FF4 /* ImageView.swift */,
|
||||
D272F5F82473163100BD1A8F /* BarButtonItem.swift */,
|
||||
D2EC7BDC2527B83700F540AF /* SectionHeaderFooterView.swift */,
|
||||
);
|
||||
path = BaseClasses;
|
||||
sourceTree = "<group>";
|
||||
@ -2077,8 +2105,10 @@
|
||||
children = (
|
||||
012A88C7238DB02000FE3DA1 /* MoleculeDelegateProtocol.swift */,
|
||||
017BEB47236230DB0024EF95 /* MoleculeViewProtocol.swift */,
|
||||
D20F3B43252E00E4004B3F56 /* PageProtocol.swift */,
|
||||
012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */,
|
||||
D28BA7442481652D00B75CB8 /* TabBarProtocol.swift */,
|
||||
D20F3B5D252F9B5D004B3F56 /* NavigationBarRefreshProtocol.swift */,
|
||||
011B58EE23A2AA850085F53C /* ModelProtocols */,
|
||||
);
|
||||
path = Protocols;
|
||||
@ -2100,6 +2130,23 @@
|
||||
path = TopNotification;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D2EC7BD22527A1E400F540AF /* HeadersAndFooters */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
01EB368C23609801006832FA /* HeaderModel.swift */,
|
||||
D256E9922412880000360572 /* Header.swift */,
|
||||
D2D90B41240463E100DD6EC9 /* MoleculeHeaderModel.swift */,
|
||||
D2A514662213885800345BFB /* MoleculeHeaderView.swift */,
|
||||
012A88EB238F084D00FE3DA1 /* FooterModel.swift */,
|
||||
D274CA322236A78900B01B62 /* FooterView.swift */,
|
||||
D2EC7BD42527B7A600F540AF /* MoleculeSectionHeaderModel.swift */,
|
||||
D2EC7BD82527B7CF00F540AF /* MoleculeSectionHeader.swift */,
|
||||
D2D2FCEF252B72AF0033EAAA /* MoleculeSectionFooterModel.swift */,
|
||||
D2D2FCF2252B72CF0033EAAA /* MoleculeSectionFooter.swift */,
|
||||
);
|
||||
path = HeadersAndFooters;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
@ -2231,6 +2278,7 @@
|
||||
943784F5236B77BB006A1E82 /* Wheel.swift in Sources */,
|
||||
31BE15CC23D8924D00452370 /* CheckboxModel.swift in Sources */,
|
||||
8D3BA9BF2433789900D341BA /* ListThreeColumnInternationalDataDivider.swift in Sources */,
|
||||
AAA7CD6B250642080045B959 /* Heart.swift in Sources */,
|
||||
94C661DA23CCF4FB00D9FE5B /* UIColor+Extension.swift in Sources */,
|
||||
D28A838123CCB0D800DFE4FC /* AccordionListItemModel.swift in Sources */,
|
||||
D2509ED62472EE2F001BFB9D /* NavigationImageButtonModel.swift in Sources */,
|
||||
@ -2250,9 +2298,11 @@
|
||||
BBC0C4FF24811DCA0087C44F /* TagModel.swift in Sources */,
|
||||
0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */,
|
||||
3265B30424BCA749000D154B /* HeadersH1NoButtonsBodyText.swift in Sources */,
|
||||
AAA7CD69250641F90045B959 /* HeartModel.swift in Sources */,
|
||||
D2FB151D23A40F1500C20E10 /* MoleculeStackItem.swift in Sources */,
|
||||
D28BA7452481652D00B75CB8 /* TabBarProtocol.swift in Sources */,
|
||||
AA11A41F23F15D3100D7962F /* ListRightVariablePayments.swift in Sources */,
|
||||
D2EC7BD92527B7CF00F540AF /* MoleculeSectionHeader.swift in Sources */,
|
||||
D28764AA2458980300CB882D /* ThreeLayerFillMiddleTemplate.swift in Sources */,
|
||||
0116A4E5228B19640094F3ED /* RadioButtonSelectionHelper.swift in Sources */,
|
||||
D2092353244F7D630044AD09 /* MVMCoreUIViewControllerMappingObject+Extension.swift in Sources */,
|
||||
@ -2268,6 +2318,7 @@
|
||||
AA2AD116244EE46800BBFFE3 /* ListDeviceComplexLinkMedium.swift in Sources */,
|
||||
AA7F32AD246C0F8C00C965BA /* ListLeftVariableRadioButtonAllTextAndLinks.swift in Sources */,
|
||||
D272F5F92473163100BD1A8F /* BarButtonItem.swift in Sources */,
|
||||
D2D2FCF3252B72CF0033EAAA /* MoleculeSectionFooter.swift in Sources */,
|
||||
0A9D09202433796500D2E6C0 /* BarsIndicatorView.swift in Sources */,
|
||||
D2E2A99423D8CCBC000B42E6 /* HeadlineBodyLinkModel.swift in Sources */,
|
||||
01004F3022721C3800991ECC /* RadioButton.swift in Sources */,
|
||||
@ -2345,6 +2396,7 @@
|
||||
525239C02407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift in Sources */,
|
||||
D2E2A99A23D8D6B4000B42E6 /* HeadlineBodyButtonModel.swift in Sources */,
|
||||
D202AFE6242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift in Sources */,
|
||||
D20F3B44252E00E4004B3F56 /* PageProtocol.swift in Sources */,
|
||||
8D084AD22410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift in Sources */,
|
||||
94C0150C2421564A005811A9 /* ActionCollapseNotificationModel.swift in Sources */,
|
||||
D2CAC7CB251104E100C75681 /* NotificationXButtonModel.swift in Sources */,
|
||||
@ -2422,11 +2474,13 @@
|
||||
D260105323CEA61600764D80 /* ToggleModel.swift in Sources */,
|
||||
014AA72523C501E2006F3E93 /* ContainerModel.swift in Sources */,
|
||||
0A7EF86523D8AFFF00B2AAD1 /* ItemDropdownEntryFieldModel.swift in Sources */,
|
||||
D2EC7BD52527B7A600F540AF /* MoleculeSectionHeaderModel.swift in Sources */,
|
||||
AAA905DF24D1758700D1EFAB /* ListThreeColumnBillHistoryModel.swift in Sources */,
|
||||
D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */,
|
||||
D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */,
|
||||
D2B18B94236214AD00A9AEDC /* NavigationController.swift in Sources */,
|
||||
0A9D09222433796500D2E6C0 /* CarouselIndicator.swift in Sources */,
|
||||
D20F3B5E252F9B5E004B3F56 /* NavigationBarRefreshProtocol.swift in Sources */,
|
||||
D29E28DA23D21AFA00ACEA85 /* StringAndMoleculeModel.swift in Sources */,
|
||||
D260105D23D0BCD400764D80 /* Stack.swift in Sources */,
|
||||
0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */,
|
||||
@ -2434,6 +2488,7 @@
|
||||
D2092349244A51D40044AD09 /* RadioSwatchModel.swift in Sources */,
|
||||
0A775F2824893937009EFB58 /* ThreeHeadlineBodyLinkModel.swift in Sources */,
|
||||
8DD1E370243B3D0500D8F2DF /* ListThreeColumnInternationalData.swift in Sources */,
|
||||
D2EC7BDD2527B83700F540AF /* SectionHeaderFooterView.swift in Sources */,
|
||||
D23EA802247EBED400D60C34 /* ImageBarButtonItem.swift in Sources */,
|
||||
AA45AA0B24BF0263007A6EA7 /* LockUpsPlanNamesModel.swift in Sources */,
|
||||
D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */,
|
||||
@ -2526,6 +2581,7 @@
|
||||
0AE98BB323FF0934004C5109 /* ExternalLinkModel.swift in Sources */,
|
||||
D20FB165241A5D75004AFC3A /* NavigationItemModel.swift in Sources */,
|
||||
AA2AD118244EE48C00BBFFE3 /* ListDeviceComplexLinkMediumModel.swift in Sources */,
|
||||
D2D3957A252FDBB300047B11 /* ModalSectionListTemplate.swift in Sources */,
|
||||
DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */,
|
||||
D28BA741248025A300B75CB8 /* TabBarModel.swift in Sources */,
|
||||
D224798A2314445E003FCCF9 /* LabelToggle.swift in Sources */,
|
||||
@ -2540,6 +2596,7 @@
|
||||
D2092355244FA0FD0044AD09 /* ThreeLayerTemplateModelProtocol.swift in Sources */,
|
||||
0AE14F64238315D2005417F8 /* TextField.swift in Sources */,
|
||||
0A51F3E22475CB73002E08B6 /* LoadingSpinnerModel.swift in Sources */,
|
||||
D2169303251E53D9002A6324 /* SectionListTemplateModel.swift in Sources */,
|
||||
0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */,
|
||||
BB105859248DEFF70069D008 /* UICollectionViewLeftAlignedLayout.swift in Sources */,
|
||||
D253BB9C245874F8002DE544 /* BGImageMolecule.swift in Sources */,
|
||||
@ -2623,6 +2680,7 @@
|
||||
AA104B1A24474A66004D2810 /* HeadersH2Buttons.swift in Sources */,
|
||||
C7192E7D23C301750050C2A0 /* HeadLineBodyCaretLinkImage.swift in Sources */,
|
||||
D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */,
|
||||
D2D2FCF0252B72AF0033EAAA /* MoleculeSectionFooterModel.swift in Sources */,
|
||||
BB1D17E2244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift in Sources */,
|
||||
D2FA83D42514F80C00564112 /* CollapsableNotification.swift in Sources */,
|
||||
0A7EF86323D8AFA000B2AAD1 /* BaseDropdownEntryFieldModel.swift in Sources */,
|
||||
@ -2636,6 +2694,7 @@
|
||||
D260105923D0A92900764D80 /* ContainerProtocol.swift in Sources */,
|
||||
BB6C6AC924225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift in Sources */,
|
||||
C695A69423C9909000BFB94E /* DoughnutChartModel.swift in Sources */,
|
||||
D2D3957D252FDBCD00047B11 /* ModalSectionListTemplateModel.swift in Sources */,
|
||||
8D4687E2242E2DE400802879 /* ListFourColumnDataUsageListItemModel.swift in Sources */,
|
||||
D29E28DD23D7404C00ACEA85 /* ContainerHelper.swift in Sources */,
|
||||
012A88C2238D7BCA00FE3DA1 /* CarouselItemModel.swift in Sources */,
|
||||
@ -2665,6 +2724,7 @@
|
||||
AA0A257A24766CA200862F64 /* ListLeftVariableIconWithRightCaretBodyText.swift in Sources */,
|
||||
011D95AD2406BB57000E3791 /* FormHolderProtocol.swift in Sources */,
|
||||
01509D932327ECFB00EF99AA /* ProgressBar.swift in Sources */,
|
||||
D2169301251E51E7002A6324 /* SectionListTemplate.swift in Sources */,
|
||||
0A6682AA2435125F00AD3CA1 /* Styler.swift in Sources */,
|
||||
D264FAA7243FE13B00D98315 /* RadioBox.swift in Sources */,
|
||||
);
|
||||
|
||||
114
MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift
Normal file
114
MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift
Normal file
@ -0,0 +1,114 @@
|
||||
//
|
||||
// Heart.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Lekshmi S on 07/09/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@objcMembers open class Heart: Control, MFButtonProtocol {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
private var heartLayer: CAShapeLayer?
|
||||
@objc public override var isSelected: Bool {
|
||||
didSet {
|
||||
heartModel?.isActive = isSelected
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
}
|
||||
public var delegateObject: MVMCoreUIDelegateObject?
|
||||
public var heartModel: HeartModel? {
|
||||
return model as? HeartModel
|
||||
}
|
||||
var additionalData: [AnyHashable: Any]?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
public var widthConstraint: NSLayoutConstraint?
|
||||
public var heightConstraint: NSLayoutConstraint?
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - State Handling
|
||||
//------------------------------------------------------
|
||||
open override func draw(_ rect: CGRect) {
|
||||
//Draw the heart
|
||||
heartLayer?.removeFromSuperlayer()
|
||||
let heart = drawHeart()
|
||||
layer.addSublayer(heart)
|
||||
heartLayer = heart
|
||||
}
|
||||
|
||||
func drawHeart() -> CAShapeLayer {
|
||||
let heart = CAShapeLayer()
|
||||
let rect = bounds
|
||||
let leftArc = rect.width * 0.4
|
||||
let rightArc = rect.height * 0.3
|
||||
let arcRadius = sqrt(leftArc*leftArc + rightArc*rightArc)/2
|
||||
let heartPath = UIBezierPath()
|
||||
//Left Hand Curve
|
||||
heartPath.addArc(withCenter: CGPoint(x: rect.width * 0.3, y: rect.height * 0.35), radius: arcRadius, startAngle: 135.degreesToRadians, endAngle: 315.degreesToRadians, clockwise: true)
|
||||
//Top Centre Dip
|
||||
heartPath.addLine(to: CGPoint(x: rect.width/2, y: rect.height * 0.2))
|
||||
//Right Hand Curve
|
||||
heartPath.addArc(withCenter: CGPoint(x: rect.width * 0.7, y: rect.height * 0.35), radius: arcRadius, startAngle: 225.degreesToRadians, endAngle: 45.degreesToRadians, clockwise: true)
|
||||
//Right Bottom Line
|
||||
heartPath.addLine(to: CGPoint(x: rect.width * 0.5, y: rect.height * 0.95))
|
||||
//Left Bottom Line
|
||||
heartPath.close()
|
||||
heart.path = heartPath.cgPath
|
||||
heart.fillColor = isSelected ? heartModel?.activeColor.cgColor : heartModel?.inActiveColor.cgColor
|
||||
heart.opacity = 1.0
|
||||
heart.lineWidth = 1
|
||||
heart.strokeColor = isSelected ? UIColor.clear.cgColor : UIColor.mvmBlack.cgColor
|
||||
return heart
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
addTarget(self, action: #selector(tapAction), for: .touchUpInside)
|
||||
widthConstraint = widthAnchor.constraint(equalToConstant: 22)
|
||||
widthConstraint?.isActive = true
|
||||
heightConstraint = heightAnchor.constraint(equalTo: widthAnchor, multiplier: 1)
|
||||
heightConstraint?.isActive = true
|
||||
isAccessibilityElement = true
|
||||
accessibilityTraits = .button
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
self.delegateObject = delegateObject
|
||||
self.additionalData = additionalData
|
||||
guard let model = model as? HeartModel else { return }
|
||||
isSelected = model.isActive
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
/// Adjust accessibility label based on selection of Heart.
|
||||
func updateAccessibilityLabel() {
|
||||
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_unfavorite_action_hint" : "heart_favorite_action_hint")
|
||||
accessibilityLabel = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_selected_state" : "heart_not_selected_state")
|
||||
}
|
||||
|
||||
func tapAction() {
|
||||
isSelected = !isSelected
|
||||
if let heartModel = heartModel {
|
||||
Button.performButtonAction(with: heartModel.action, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: heartModel)
|
||||
}
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
extension Int {
|
||||
var degreesToRadians: CGFloat { return CGFloat(self) * .pi / 180 }
|
||||
}
|
||||
65
MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift
Normal file
65
MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift
Normal file
@ -0,0 +1,65 @@
|
||||
//
|
||||
// HeartModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Lekshmi S on 07/09/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
open class HeartModel: MoleculeModelProtocol {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
public static var identifier: String = "heart"
|
||||
public var backgroundColor: Color?
|
||||
public var isActive: Bool = false
|
||||
public var activeColor: Color = Color(uiColor: .mvmRed)
|
||||
public var inActiveColor: Color = Color(uiColor: .clear)
|
||||
public var action: ActionModelProtocol = ActionNoopModel()
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case isActive
|
||||
case activeColor
|
||||
case inActiveColor
|
||||
case action
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
if let isActive = try typeContainer.decodeIfPresent(Bool.self, forKey: .isActive) {
|
||||
self.isActive = isActive
|
||||
}
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
if let activeColor = try typeContainer.decodeIfPresent(Color.self, forKey: .activeColor) {
|
||||
self.activeColor = activeColor
|
||||
}
|
||||
if let inActiveColor = try typeContainer.decodeIfPresent(Color.self, forKey: .inActiveColor) {
|
||||
self.inActiveColor = inActiveColor
|
||||
}
|
||||
if let action: ActionModelProtocol = try typeContainer.decodeModelIfPresent(codingKey: .action) {
|
||||
self.action = action
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(isActive, forKey: .isActive)
|
||||
try container.encode(activeColor, forKey: .activeColor)
|
||||
try container.encode(inActiveColor, forKey: .inActiveColor)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
}
|
||||
}
|
||||
@ -322,8 +322,11 @@ public typealias ActionBlock = () -> ()
|
||||
for attribute in attributes {
|
||||
let range = NSRange(location: attribute.location, length: attribute.length)
|
||||
switch attribute {
|
||||
case _ as LabelAttributeUnderlineModel:
|
||||
attributedString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: range)
|
||||
case let underlineAtt as LabelAttributeUnderlineModel:
|
||||
attributedString.addAttribute(.underlineStyle, value: underlineAtt.underlineValue.rawValue, range: range)
|
||||
if let underlineColor = underlineAtt.color?.uiColor {
|
||||
attributedString.addAttribute(.underlineColor, value: underlineColor, range: range)
|
||||
}
|
||||
|
||||
case _ as LabelAttributeStrikeThroughModel:
|
||||
attributedString.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.thick.rawValue, range: range)
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
@objcMembers public class LabelAttributeUnderlineModel: LabelAttributeModel {
|
||||
//--------------------------------------------------
|
||||
@ -16,15 +18,104 @@
|
||||
return "underline"
|
||||
}
|
||||
|
||||
/// This returns the NSUnderlineStyle used in NSAttributedValue. If there is a pattern, it will return
|
||||
/// a new NSUnderlineStyle derived from the bitmask of style | pattern.
|
||||
var underlineValue: NSUnderlineStyle {
|
||||
|
||||
if let pattern = pattern?.value() {
|
||||
return NSUnderlineStyle(rawValue: style.value() | pattern)
|
||||
} else {
|
||||
return NSUnderlineStyle(rawValue: style.value())
|
||||
}
|
||||
}
|
||||
|
||||
var color: Color?
|
||||
var style: UnderlineStyle = .single
|
||||
var pattern: UnderlineStyle.Pattern?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case color
|
||||
case style
|
||||
case pattern
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .color) {
|
||||
self.color = color
|
||||
}
|
||||
|
||||
if let style = try typeContainer.decodeIfPresent(UnderlineStyle.self, forKey: .style) {
|
||||
self.style = style
|
||||
}
|
||||
|
||||
if let pattern = try typeContainer.decodeIfPresent(UnderlineStyle.Pattern.self, forKey: .pattern) {
|
||||
self.pattern = pattern
|
||||
}
|
||||
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeIfPresent(color, forKey: .color)
|
||||
try container.encode(style, forKey: .style)
|
||||
try container.encodeIfPresent(pattern, forKey: .pattern)
|
||||
}
|
||||
}
|
||||
|
||||
public enum UnderlineStyle: String, Codable {
|
||||
case none
|
||||
case single
|
||||
case thick
|
||||
case double
|
||||
|
||||
func value() -> Int {
|
||||
switch self {
|
||||
case .none:
|
||||
return 0
|
||||
|
||||
case .single:
|
||||
return NSUnderlineStyle.single.rawValue
|
||||
|
||||
case .thick:
|
||||
return NSUnderlineStyle.thick.rawValue
|
||||
|
||||
case .double:
|
||||
return NSUnderlineStyle.double.rawValue
|
||||
}
|
||||
}
|
||||
|
||||
public enum Pattern: String, Codable {
|
||||
case dot
|
||||
case dash
|
||||
case dashDot
|
||||
case dashDotDot
|
||||
case byWord
|
||||
|
||||
func value() -> Int {
|
||||
switch self {
|
||||
case .dot:
|
||||
return NSUnderlineStyle.patternDot.rawValue
|
||||
|
||||
case .dash:
|
||||
return NSUnderlineStyle.patternDash.rawValue
|
||||
|
||||
case .dashDot:
|
||||
return NSUnderlineStyle.patternDashDot.rawValue
|
||||
|
||||
case .dashDotDot:
|
||||
return NSUnderlineStyle.patternDashDotDot.rawValue
|
||||
|
||||
case .byWord:
|
||||
return NSUnderlineStyle.byWord.rawValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,12 +35,12 @@ import Foundation
|
||||
}
|
||||
|
||||
/// Convenience function for legacy classes
|
||||
public func getMoleculeModelForJSON(_ json: [String: Any]) throws -> MoleculeModelProtocol? {
|
||||
public func getMoleculeModelForJSON(_ json: [String: Any], delegateObject: DelegateObject? = nil) throws -> MoleculeModelProtocol? {
|
||||
guard let moleculeName = json.optionalStringForKey(KeyMoleculeName),
|
||||
let type = ModelRegistry.getType(for: moleculeName, with: MoleculeModelProtocol.self) else {
|
||||
throw ModelRegistry.Error.decoderErrorModelNotMapped()
|
||||
}
|
||||
guard let model = try type.decode(jsonDict: json) as? MoleculeModelProtocol else {
|
||||
guard let model = try type.decode(jsonDict: json, delegateObject: delegateObject) as? MoleculeModelProtocol else {
|
||||
throw ModelRegistry.Error.decoderError
|
||||
}
|
||||
return model
|
||||
@ -87,7 +87,7 @@ import Foundation
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: RadioSwatches.self, viewModelClass: RadioSwatchesModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: Tags.self, viewModelClass: TagsModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: Tag.self, viewModelClass: TagModel.self)
|
||||
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: Heart.self, viewModelClass: HeartModel.self)
|
||||
|
||||
|
||||
// MARK:- Other Atoms
|
||||
@ -149,6 +149,9 @@ import Foundation
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: Scroller.self, viewModelClass: ScrollerModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: ModuleMolecule.self, viewModelClass: ModuleMoleculeModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: BGImageMolecule.self, viewModelClass: BGImageMoleculeModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: MoleculeSectionHeader.self, viewModelClass: MoleculeSectionHeaderModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: MoleculeSectionFooter.self, viewModelClass: MoleculeSectionFooterModel.self)
|
||||
|
||||
|
||||
// MARK:- Other Molecules
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: DoughnutChartView.self, viewModelClass: DoughnutChartModel.self)
|
||||
|
||||
@ -77,7 +77,7 @@ import Foundation
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 120
|
||||
}
|
||||
|
||||
|
||||
@ -75,7 +75,7 @@
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 120
|
||||
}
|
||||
|
||||
|
||||
@ -94,7 +94,7 @@
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 120
|
||||
}
|
||||
|
||||
|
||||
@ -59,7 +59,7 @@
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 121
|
||||
}
|
||||
|
||||
|
||||
@ -55,7 +55,7 @@
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 121
|
||||
}
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 121
|
||||
}
|
||||
|
||||
|
||||
@ -64,7 +64,7 @@
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 121
|
||||
}
|
||||
|
||||
|
||||
@ -90,7 +90,7 @@
|
||||
rightHeadlineBodyLink.body.setFontStyle(.RegularBodySmall)
|
||||
}
|
||||
|
||||
public override class func estimatedHeight(with molecule: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
public override class func estimatedHeight(with molecule: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 121
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
rightDropDown.set(with:model.rightDropDown, delegateObject, additionalData)
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 121
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@
|
||||
rightLabel.setFontStyle(.RegularBodySmall)
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 15
|
||||
}
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@ import Foundation
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 121
|
||||
}
|
||||
|
||||
|
||||
@ -53,9 +53,7 @@ import Foundation
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
|
||||
guard let model = model as? ListOneColumnFullWidthTextDividerSubsectionModel else { return }
|
||||
|
||||
headline.set(with: model.headline, delegateObject, additionalData)
|
||||
body.set(with: model.body, delegateObject, additionalData)
|
||||
stack.updateContainedMolecules(with: [model.headline, model.body], delegateObject, additionalData)
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
|
||||
@ -16,13 +16,13 @@ public class ListOneColumnFullWidthTextDividerSubsectionModel: ListItemModel, Mo
|
||||
|
||||
public static var identifier: String = "list1CTxtDiv3"
|
||||
public var headline: LabelModel
|
||||
public var body: LabelModel
|
||||
public var body: LabelModel?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(headline: LabelModel, body: LabelModel) {
|
||||
public init(headline: LabelModel, body: LabelModel?) {
|
||||
self.headline = headline
|
||||
self.body = body
|
||||
super.init()
|
||||
@ -54,7 +54,7 @@ public class ListOneColumnFullWidthTextDividerSubsectionModel: ListItemModel, Mo
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
headline = try typeContainer.decode(LabelModel.self, forKey: .headline)
|
||||
body = try typeContainer.decode(LabelModel.self, forKey: .body)
|
||||
body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body)
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
@ -63,6 +63,6 @@ public class ListOneColumnFullWidthTextDividerSubsectionModel: ListItemModel, Mo
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(headline, forKey: .headline)
|
||||
try container.encode(body, forKey: .body)
|
||||
try container.encodeIfPresent(body, forKey: .body)
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,9 +53,7 @@ import Foundation
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
|
||||
guard let model = model as? ListOneColumnTextWithWhitespaceDividerShortModel else { return }
|
||||
|
||||
headline.set(with: model.headline, delegateObject, additionalData)
|
||||
body.set(with: model.body, delegateObject, additionalData)
|
||||
stack.updateContainedMolecules(with: [model.headline, model.body], delegateObject, additionalData)
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
|
||||
@ -16,13 +16,13 @@ public class ListOneColumnTextWithWhitespaceDividerShortModel: ListItemModel, Mo
|
||||
|
||||
public static var identifier: String = "list1CTxtDiv1"
|
||||
public var headline: LabelModel
|
||||
public var body: LabelModel
|
||||
public var body: LabelModel?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(headline: LabelModel, body: LabelModel) {
|
||||
public init(headline: LabelModel, body: LabelModel?) {
|
||||
self.headline = headline
|
||||
self.body = body
|
||||
super.init()
|
||||
@ -54,7 +54,7 @@ public class ListOneColumnTextWithWhitespaceDividerShortModel: ListItemModel, Mo
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
headline = try typeContainer.decode(LabelModel.self, forKey: .headline)
|
||||
body = try typeContainer.decode(LabelModel.self, forKey: .body)
|
||||
body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body)
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
@ -63,6 +63,6 @@ public class ListOneColumnTextWithWhitespaceDividerShortModel: ListItemModel, Mo
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(headline, forKey: .headline)
|
||||
try container.encode(body, forKey: .body)
|
||||
try container.encodeIfPresent(body, forKey: .body)
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,9 +52,7 @@ import Foundation
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
|
||||
guard let model = model as? ListOneColumnTextWithWhitespaceDividerTallModel else { return }
|
||||
|
||||
headline.set(with: model.headline, delegateObject, additionalData)
|
||||
body.set(with: model.body, delegateObject, additionalData)
|
||||
stack.updateContainedMolecules(with: [model.headline, model.body], delegateObject, additionalData)
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
|
||||
@ -16,13 +16,13 @@ public class ListOneColumnTextWithWhitespaceDividerTallModel: ListItemModel, Mol
|
||||
|
||||
public static var identifier: String = "list1CTxtDiv2"
|
||||
public var headline: LabelModel
|
||||
public var body: LabelModel
|
||||
public var body: LabelModel?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(headline: LabelModel, body: LabelModel) {
|
||||
public init(headline: LabelModel, body: LabelModel?) {
|
||||
self.headline = headline
|
||||
self.body = body
|
||||
super.init()
|
||||
@ -54,7 +54,7 @@ public class ListOneColumnTextWithWhitespaceDividerTallModel: ListItemModel, Mol
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
headline = try typeContainer.decode(LabelModel.self, forKey: .headline)
|
||||
body = try typeContainer.decode(LabelModel.self, forKey: .body)
|
||||
body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body)
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
@ -63,6 +63,6 @@ public class ListOneColumnTextWithWhitespaceDividerTallModel: ListItemModel, Mol
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(headline, forKey: .headline)
|
||||
try container.encode(body, forKey: .body)
|
||||
try container.encodeIfPresent(body, forKey: .body)
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ import Foundation
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 120
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ import Foundation
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 121
|
||||
}
|
||||
|
||||
|
||||
@ -61,7 +61,7 @@ import Foundation
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 121
|
||||
}
|
||||
|
||||
|
||||
@ -60,7 +60,7 @@ import Foundation
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 121
|
||||
}
|
||||
|
||||
|
||||
@ -62,7 +62,7 @@ import Foundation
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 121
|
||||
}
|
||||
|
||||
|
||||
@ -61,7 +61,7 @@ import Foundation
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 121
|
||||
}
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ import Foundation
|
||||
updateAccessibilityLabel()
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 121
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
//
|
||||
// MoleculeSectionFooter.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 10/5/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers open class MoleculeSectionFooter: SectionHeaderFooterView {
|
||||
open var molecule: MoleculeViewProtocol?
|
||||
public let containerHelper = ContainerHelper()
|
||||
|
||||
/// Adds the molecule to the view.
|
||||
open func addMolecule(_ molecule: MoleculeViewProtocol) {
|
||||
contentView.addSubview(molecule)
|
||||
containerHelper.constrainView(molecule)
|
||||
self.molecule = molecule
|
||||
}
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
containerHelper.updateViewMargins(self, model: model as? MoleculeSectionFooterModel, size: size)
|
||||
contentView.directionalLayoutMargins = directionalLayoutMargins
|
||||
(molecule as? MVMCoreViewProtocol)?.updateView(size)
|
||||
}
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
guard let model = model as? MoleculeSectionFooterModel else { return }
|
||||
if molecule != nil {
|
||||
molecule?.set(with: model.molecule, delegateObject, additionalData)
|
||||
} else if let moleculeView = MoleculeObjectMapping.shared()?.createMolecule(model.molecule, delegateObject: delegateObject, additionalData: additionalData) {
|
||||
addMolecule(moleculeView)
|
||||
}
|
||||
containerHelper.set(with: model, for: molecule as? MVMCoreUIViewConstrainingProtocol)
|
||||
}
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
molecule?.reset()
|
||||
}
|
||||
|
||||
public override class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||
return MoleculeContainer.nameForReuse(with: model, delegateObject)
|
||||
}
|
||||
|
||||
public override class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||
return MoleculeContainer.requiredModules(with: model, delegateObject, error: error)
|
||||
}
|
||||
|
||||
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return MoleculeContainer.estimatedHeight(with: model, delegateObject) ?? 80.0
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
//
|
||||
// MoleculeSectionFooterModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 10/5/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers open class MoleculeSectionFooterModel: MoleculeContainerModel, SectionListHeaderFooterModel {
|
||||
public class override var identifier: String {
|
||||
return "sectionFooter"
|
||||
}
|
||||
|
||||
/// Defaults to set
|
||||
public override func setDefaults() {
|
||||
if useHorizontalMargins == nil {
|
||||
useHorizontalMargins = true
|
||||
}
|
||||
if useVerticalMargins == nil {
|
||||
useVerticalMargins = true
|
||||
}
|
||||
if topPadding == nil {
|
||||
topPadding = PaddingDefaultVerticalSpacing3
|
||||
}
|
||||
if bottomPadding == nil {
|
||||
bottomPadding = PaddingDefaultVerticalSpacing3
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
//
|
||||
// MoleculeSectionHeader.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 10/2/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers open class MoleculeSectionHeader: SectionHeaderFooterView {
|
||||
open var molecule: MoleculeViewProtocol?
|
||||
public let containerHelper = ContainerHelper()
|
||||
public let line = Line()
|
||||
|
||||
/// Adds the molecule to the view.
|
||||
open func addMolecule(_ molecule: MoleculeViewProtocol) {
|
||||
contentView.addSubview(molecule)
|
||||
containerHelper.constrainView(molecule)
|
||||
self.molecule = molecule
|
||||
}
|
||||
|
||||
public override func setupView() {
|
||||
super.setupView()
|
||||
line.setStyle(.thin)
|
||||
contentView.addSubview(line)
|
||||
NSLayoutConstraint.pinViewBottom(toSuperview: line, useMargins: false, constant: 0).isActive = true
|
||||
NSLayoutConstraint.pinViewLeft(toSuperview: line, useMargins: true, constant: 0).isActive = true
|
||||
NSLayoutConstraint.pinViewRight(toSuperview: line, useMargins: true, constant: 0).isActive = true
|
||||
}
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
containerHelper.updateViewMargins(self, model: model as? MoleculeSectionHeaderModel, size: size)
|
||||
contentView.directionalLayoutMargins = directionalLayoutMargins
|
||||
(molecule as? MVMCoreViewProtocol)?.updateView(size)
|
||||
line.updateView(size)
|
||||
}
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
guard let model = model as? MoleculeSectionHeaderModel else { return }
|
||||
if molecule != nil {
|
||||
molecule?.set(with: model.molecule, delegateObject, additionalData)
|
||||
} else if let moleculeView = MoleculeObjectMapping.shared()?.createMolecule(model.molecule, delegateObject: delegateObject, additionalData: additionalData) {
|
||||
addMolecule(moleculeView)
|
||||
}
|
||||
containerHelper.set(with: model, for: molecule as? MVMCoreUIViewConstrainingProtocol)
|
||||
line.setOptional(with: model.line, delegateObject, additionalData)
|
||||
}
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
line.setStyle(.thin)
|
||||
molecule?.reset()
|
||||
}
|
||||
|
||||
public override class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||
return MoleculeContainer.nameForReuse(with: model, delegateObject)
|
||||
}
|
||||
|
||||
public override class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||
return MoleculeContainer.requiredModules(with: model, delegateObject, error: error)
|
||||
}
|
||||
|
||||
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return MoleculeContainer.estimatedHeight(with: model, delegateObject) ?? 80.0
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
//
|
||||
// MoleculeSectionHeaderModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 10/2/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers open class MoleculeSectionHeaderModel: MoleculeContainerModel, SectionListHeaderFooterModel {
|
||||
public class override var identifier: String {
|
||||
return "sectionHeader"
|
||||
}
|
||||
public var line: LineModel?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case line
|
||||
case backgroundColor
|
||||
}
|
||||
|
||||
/// Defaults to set
|
||||
public override func setDefaults() {
|
||||
if useHorizontalMargins == nil {
|
||||
useHorizontalMargins = true
|
||||
}
|
||||
if useVerticalMargins == nil {
|
||||
useVerticalMargins = true
|
||||
}
|
||||
if topPadding == nil {
|
||||
topPadding = PaddingDefaultVerticalSpacing3
|
||||
}
|
||||
if bottomPadding == nil {
|
||||
bottomPadding = PaddingDefaultVerticalSpacing3
|
||||
}
|
||||
if line == nil {
|
||||
line = LineModel(type: .thin)
|
||||
}
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
try super.init(from: decoder)
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line)
|
||||
}
|
||||
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(line, forKey: .line)
|
||||
}
|
||||
}
|
||||
@ -34,26 +34,14 @@ open class MoleculeCollectionViewCell: CollectionViewCell {
|
||||
}
|
||||
|
||||
open override class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||
guard let moleculeModel = (model as? MoleculeCollectionItemModel)?.molecule else { return "\(self)<>" }
|
||||
let className = MoleculeObjectMapping.shared()?.getMoleculeClass(moleculeModel)
|
||||
let moleculeName = className?.nameForReuse(with: moleculeModel, delegateObject) ?? moleculeModel.moleculeName
|
||||
return "\(self)<\(moleculeName)>"
|
||||
return MoleculeContainer.nameForReuse(with: model, delegateObject)
|
||||
}
|
||||
|
||||
open override class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||
guard let moleculeModel = (model as? MoleculeCollectionItemModel)?.molecule,
|
||||
let theClass = MoleculeObjectMapping.shared()?.getMoleculeClass(moleculeModel)
|
||||
else { return nil }
|
||||
|
||||
return theClass.requiredModules(with: moleculeModel, delegateObject, error: error)
|
||||
return MoleculeContainer.requiredModules(with: model, delegateObject, error: error)
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
guard let model = model as? MoleculeCollectionItemModel,
|
||||
let classType = MoleculeObjectMapping.shared()?.getMoleculeClass(model.molecule),
|
||||
let height = classType.estimatedHeight(with: model.molecule, delegateObject)
|
||||
else { return 100 }
|
||||
|
||||
return height + (model.topPadding ?? 0) + (model.bottomPadding ?? 0)
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return MoleculeContainer.estimatedHeight(with: model, delegateObject) ?? 100
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ import Foundation
|
||||
import MVMCore
|
||||
|
||||
|
||||
@objcMembers public class MoleculeListItemModel: ListItemModel, MoleculeModelProtocol {
|
||||
@objcMembers public class MoleculeListItemModel: ListItemModel, MoleculeContainerModelProtocol, MoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
case spacing
|
||||
case percent
|
||||
case gone
|
||||
case moleculeName
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -54,6 +55,7 @@
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(spacing, forKey: .spacing)
|
||||
try container.encodeIfPresent(percent, forKey: .percent)
|
||||
try container.encode(gone, forKey: .gone)
|
||||
|
||||
@ -30,28 +30,16 @@ import UIKit
|
||||
}
|
||||
|
||||
public override class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||
guard let moleculeModel = (model as? MoleculeListItemModel)?.molecule else { return "\(self)<>" }
|
||||
|
||||
let className = MoleculeObjectMapping.shared()?.getMoleculeClass(moleculeModel)
|
||||
let moleculeName = className?.nameForReuse(with: moleculeModel, delegateObject) ?? moleculeModel.moleculeName
|
||||
|
||||
return "\(self)<\(moleculeName)>"
|
||||
return MoleculeContainer.nameForReuse(with: model, delegateObject)
|
||||
}
|
||||
|
||||
public override class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||
guard let moleculeModel = (model as? MoleculeListItemModel)?.molecule,
|
||||
let theClass = MoleculeObjectMapping.shared()?.getMoleculeClass(moleculeModel)
|
||||
else { return nil }
|
||||
|
||||
return theClass.requiredModules(with: moleculeModel, delegateObject, error: error)
|
||||
return MoleculeContainer.requiredModules(with: model, delegateObject, error: error)
|
||||
}
|
||||
|
||||
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
guard let moleculeModel = (model as? MoleculeListItemModel)?.molecule,
|
||||
let classType = MoleculeObjectMapping.shared()?.getMoleculeClass(moleculeModel),
|
||||
let height = classType.estimatedHeight(with: moleculeModel, delegateObject)
|
||||
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
guard let height = MoleculeContainer.estimatedHeight(with: model, delegateObject)
|
||||
else { return 80 }
|
||||
|
||||
return max(2 * PaddingDefaultVerticalSpacing3, height)
|
||||
return height
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,7 +157,7 @@ import UIKit
|
||||
bottomRightLabel.setFontStyle(.RegularMicro)
|
||||
}
|
||||
|
||||
public class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||
public class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return 34
|
||||
}
|
||||
|
||||
|
||||
@ -8,25 +8,25 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtocol {
|
||||
public class var identifier: String {
|
||||
open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtocol {
|
||||
open class var identifier: String {
|
||||
return "navigationBar"
|
||||
}
|
||||
|
||||
public var title: String?
|
||||
public var hidden: Bool
|
||||
public var backgroundColor: Color?
|
||||
public var tintColor: Color
|
||||
public var line: LineModel?
|
||||
public var hidesSystemBackButton = true
|
||||
open var title: String?
|
||||
open var hidden: Bool
|
||||
open var backgroundColor: Color?
|
||||
open var tintColor: Color
|
||||
open var line: LineModel?
|
||||
open var hidesSystemBackButton = true
|
||||
|
||||
/// If true, we add the button in the backButton property. If false we do not add the button. If nil, we add the button if the controller is not the bottom of the stack
|
||||
public var alwaysShowBackButton: Bool?
|
||||
public var backButton: (NavigationButtonModelProtocol & MoleculeModelProtocol)?
|
||||
open var alwaysShowBackButton: Bool?
|
||||
open var backButton: (NavigationButtonModelProtocol & MoleculeModelProtocol)?
|
||||
|
||||
public var additionalLeftButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
|
||||
public var additionalRightButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
|
||||
public var titleView: MoleculeModelProtocol?
|
||||
open var additionalLeftButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
|
||||
open var additionalRightButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]?
|
||||
open var titleView: MoleculeModelProtocol?
|
||||
|
||||
public init() {
|
||||
hidden = false
|
||||
@ -44,8 +44,6 @@ public class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProt
|
||||
case line
|
||||
case alwaysShowBackButton
|
||||
case backButton
|
||||
case showLeftPanelButton
|
||||
case showRightPanelButton
|
||||
case additionalLeftButtons
|
||||
case additionalRightButtons
|
||||
case titleView
|
||||
|
||||
@ -12,12 +12,11 @@ import UIKit
|
||||
open class MoleculeContainer: Container {
|
||||
|
||||
/// Can be overriden to change how the molecule is added to the hierarchy.
|
||||
public func addMolecule(_ molecule: UIView) {
|
||||
open func addMolecule(_ molecule: UIView) {
|
||||
addAndContain(molecule)
|
||||
}
|
||||
|
||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
if let casteModel = model as? MoleculeContainerModelProtocol {
|
||||
if view != nil {
|
||||
(view as? MoleculeViewProtocol)?.set(with: casteModel.molecule, delegateObject, additionalData)
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
|
||||
open class MoleculeContainerModel: ContainerModel, MoleculeContainerModelProtocol, MoleculeModelProtocol {
|
||||
public class var identifier: String {
|
||||
open class var identifier: String {
|
||||
return "container"
|
||||
}
|
||||
public var backgroundColor: Color?
|
||||
@ -41,7 +41,7 @@ open class MoleculeContainerModel: ContainerModel, MoleculeContainerModelProtoco
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
open override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public class CollapsableNotificationModel: NotificationModel {
|
||||
open class CollapsableNotificationModel: NotificationModel {
|
||||
public class override var identifier: String {
|
||||
return "collapsableNotification"
|
||||
}
|
||||
@ -19,12 +19,12 @@ public class CollapsableNotificationModel: NotificationModel {
|
||||
public var initiallyCollapsed = false
|
||||
public var pages: [String]?
|
||||
|
||||
init(with topLabel: LabelModel, headline: LabelModel) {
|
||||
public init(with topLabel: LabelModel, headline: LabelModel) {
|
||||
self.topLabel = topLabel
|
||||
super.init(with: headline)
|
||||
}
|
||||
|
||||
override func setDefault() {
|
||||
open override func setDefault() {
|
||||
super.setDefault()
|
||||
if topLabel.textColor == nil {
|
||||
topLabel.textColor = Color(uiColor: .white)
|
||||
@ -61,7 +61,7 @@ public class CollapsableNotificationModel: NotificationModel {
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
open override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public class NotificationModel: MoleculeModelProtocol {
|
||||
open class NotificationModel: MoleculeModelProtocol {
|
||||
public class var identifier: String {
|
||||
return "notification"
|
||||
}
|
||||
@ -18,11 +18,11 @@ public class NotificationModel: MoleculeModelProtocol {
|
||||
public var button: ButtonModel?
|
||||
public var closeButton: NotificationXButtonModel?
|
||||
|
||||
init(with headline: LabelModel) {
|
||||
public init(with headline: LabelModel) {
|
||||
self.headline = headline
|
||||
}
|
||||
|
||||
func setDefault() {
|
||||
open func setDefault() {
|
||||
if backgroundColor == nil {
|
||||
backgroundColor = Color(uiColor: .mvmGreen())
|
||||
}
|
||||
@ -59,7 +59,7 @@ public class NotificationModel: MoleculeModelProtocol {
|
||||
setDefault()
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
open func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
|
||||
@ -42,6 +42,7 @@
|
||||
|
||||
headlineBody.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
||||
headlineBody.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
|
||||
rightAnchor.constraint(greaterThanOrEqualTo: headlineBody.rightAnchor).isActive = true
|
||||
var constraint = rightAnchor.constraint(equalTo: headlineBody.rightAnchor)
|
||||
constraint.priority = .defaultHigh
|
||||
constraint.isActive = true
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
//
|
||||
// NavigationBarRefreshProtocol.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 10/8/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// A protocol to inform that we should refresh the navigation bar ui.
|
||||
@objc public protocol NavigationBarRefreshProtocol {
|
||||
@objc func refreshNavigationUI()
|
||||
}
|
||||
|
||||
extension UIViewController: NavigationBarRefreshProtocol {
|
||||
|
||||
/// Convenience function to refresh the navigation bar ui. A separate function for others to use.
|
||||
@objc public static func refreshNavigationUI(for viewController: UIViewController) {
|
||||
guard let model = (viewController as? PageProtocol)?.pageModel?.navigationBar else { return }
|
||||
if let navigationController = viewController.navigationController {
|
||||
NavigationController.setNavigationItem(navigationController: navigationController, navigationItemModel: model, viewController: viewController)
|
||||
MVMCoreUISplitViewController.setNavigationBarUI(for: viewController, navigationController: navigationController, navigationItemModel: model)
|
||||
}
|
||||
if let manager = ((viewController as? MVMCoreViewManagerViewControllerProtocol)?.manager as? NavigationBarRefreshProtocol) {
|
||||
// Refresh the manager if possible.
|
||||
manager.refreshNavigationUI()
|
||||
}
|
||||
}
|
||||
|
||||
public func refreshNavigationUI() {
|
||||
UIViewController.refreshNavigationUI(for: self)
|
||||
}
|
||||
}
|
||||
13
MVMCoreUI/Atomic/Protocols/PageProtocol.swift
Normal file
13
MVMCoreUI/Atomic/Protocols/PageProtocol.swift
Normal file
@ -0,0 +1,13 @@
|
||||
//
|
||||
// PageProtocol.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 10/7/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol PageProtocol {
|
||||
var pageModel: PageModelProtocol? { get set }
|
||||
}
|
||||
@ -23,7 +23,7 @@ public extension TemplateProtocol where Self: ViewController {
|
||||
let decoder = JSONDecoder()
|
||||
try decoder.add(delegateObject: delegateObjectIVar)
|
||||
self.templateModel = try decodeTemplate(using: decoder, from: data)
|
||||
self.pageModel = templateModel as? MVMControllerModelProtocol
|
||||
self.model = templateModel as? MVMControllerModelProtocol
|
||||
}
|
||||
|
||||
func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> TemplateModel {
|
||||
|
||||
@ -18,6 +18,15 @@ import Foundation
|
||||
}
|
||||
public var molecules: [ListItemModelProtocol & MoleculeModelProtocol]?
|
||||
public var line: LineModel?
|
||||
|
||||
/// This template requires content.
|
||||
func validateModelHasContent() throws {
|
||||
if header == nil,
|
||||
molecules?.count ?? 0 == 0,
|
||||
footer == nil {
|
||||
throw ModelRegistry.Error.decoderOther(message: "List template requires atleast one of the following: header, footer, molecules")
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
@ -47,6 +56,7 @@ import Foundation
|
||||
molecules = try typeContainer.decodeModelsIfPresent(codingKey: .molecules)
|
||||
line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line)
|
||||
try super.init(from: decoder)
|
||||
try validateModelHasContent()
|
||||
}
|
||||
|
||||
open override func encode(to encoder: Encoder) throws {
|
||||
|
||||
30
MVMCoreUI/Atomic/Templates/ModalSectionListTemplate.swift
Normal file
30
MVMCoreUI/Atomic/Templates/ModalSectionListTemplate.swift
Normal file
@ -0,0 +1,30 @@
|
||||
//
|
||||
// ModalSectionListTemplate.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 10/8/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
open class ModalSectionListTemplate: SectionListTemplate {
|
||||
|
||||
// For subclassing the model.
|
||||
open override func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> ModalSectionListTemplateModel {
|
||||
return try decoder.decode(ModalSectionListTemplateModel.self, from: data)
|
||||
}
|
||||
|
||||
override open func handleNewData() {
|
||||
super.handleNewData()
|
||||
_ = MVMCoreUICommonViewsUtility.addCloseButton(to: view, action: {[weak self] _ in
|
||||
guard let self = self else { return }
|
||||
guard let model = self.templateModel as? ModalSectionListTemplateModel,
|
||||
let actionMap = model.closeAction else {
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: ActionBackModel().toJSON(), additionalData: nil, delegateObject: self.delegateObjectIVar)
|
||||
return
|
||||
}
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: actionMap.toJSON(), additionalData: nil, delegateObject: self.delegateObjectIVar)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
//
|
||||
// ModalSectionListTemplateModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 10/8/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers public class ModalSectionListTemplateModel: SectionListTemplateModel {
|
||||
public override class var identifier: String {
|
||||
return "modalSectionList"
|
||||
}
|
||||
public var closeAction: ActionModelProtocol?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case closeAction
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
closeAction = try typeContainer.decodeModelIfPresent(codingKey: .closeAction)
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeModelIfPresent(closeAction, forKey: .closeAction)
|
||||
}
|
||||
}
|
||||
@ -14,24 +14,15 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
// MARK: - Stored Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public var moleculesInfo: [(identifier: String, class: AnyClass, molecule: (ListItemModelProtocol & MoleculeModelProtocol))]?
|
||||
public var moleculesInfo: [(identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)]?
|
||||
|
||||
var observer: NSKeyValueObservation?
|
||||
|
||||
public var templateModel: ListPageTemplateModel?
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Computed Properties
|
||||
//--------------------------------------------------
|
||||
open override func parsePageJSON() throws {
|
||||
try parseTemplate(json: loadObject?.pageJSON)
|
||||
try super.parsePageJSON()
|
||||
}
|
||||
|
||||
// For subclassing the model.
|
||||
open func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> ListPageTemplateModel {
|
||||
return try decoder.decode(ListPageTemplateModel.self, from: data)
|
||||
}
|
||||
|
||||
open override var loadObject: MVMCoreLoadObject? {
|
||||
didSet {
|
||||
@ -50,6 +41,16 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func parsePageJSON() throws {
|
||||
try parseTemplate(json: loadObject?.pageJSON)
|
||||
try super.parsePageJSON()
|
||||
}
|
||||
|
||||
// For subclassing the model.
|
||||
open func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> ListPageTemplateModel {
|
||||
return try decoder.decode(ListPageTemplateModel.self, from: data)
|
||||
}
|
||||
|
||||
open override func viewForTop() -> UIView {
|
||||
guard let headerModel = templateModel?.header,
|
||||
@ -72,21 +73,6 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
return molecule
|
||||
}
|
||||
|
||||
open override func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject>) -> Bool {
|
||||
|
||||
guard super.shouldFinishProcessingLoad(loadObject, error: error) else { return false }
|
||||
|
||||
// This template requires atleast one of the three layers.
|
||||
if templateModel?.header == nil,
|
||||
templateModel?.molecules?.count ?? 0 == 0,
|
||||
templateModel?.footer == nil,
|
||||
let errorObject = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess), messageToLog: "List template requires atleast one of the following: header, footer, molecules", code: CoreUIErrorCode.ErrorCodeListMolecule.rawValue, domain: ErrorDomainNative, location: String(describing: self)) {
|
||||
error.pointee = errorObject
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
open override func handleNewData() {
|
||||
topViewOutsideOfScrollArea = templateModel?.anchorHeader ?? false
|
||||
bottomViewOutsideOfScrollArea = templateModel?.anchorFooter ?? false
|
||||
@ -109,7 +95,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
guard let moleculeInfo = moleculesInfo?[indexPath.row],
|
||||
guard let moleculeInfo = getMoleculeInfo(for: indexPath),
|
||||
let estimatedHeight = (moleculeInfo.class as? MoleculeViewProtocol.Type)?.estimatedHeight(with: moleculeInfo.molecule, delegateObject() as? MVMCoreUIDelegateObject)
|
||||
else { return 0 }
|
||||
|
||||
@ -122,7 +108,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
|
||||
open override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
guard let moleculeInfo = moleculesInfo?[indexPath.row],
|
||||
guard let moleculeInfo = getMoleculeInfo(for: indexPath),
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: moleculeInfo.identifier)
|
||||
else { return UITableViewCell() }
|
||||
|
||||
@ -175,7 +161,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
var indexPaths: [IndexPath] = []
|
||||
|
||||
for molecule in molecules {
|
||||
if let info = self.getMoleculeInfo(with: molecule) {
|
||||
if let info = self.createMoleculeInfo(with: molecule) {
|
||||
self.tableView?.register(info.class, forCellReuseIdentifier: info.identifier)
|
||||
let index = indexPath.row + 1 + indexPaths.count
|
||||
self.moleculesInfo?.insert(info, at: index)
|
||||
@ -211,8 +197,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
// MARK: - Convenience
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Returns the (identifier, class) of the molecule for the given map.
|
||||
func getMoleculeInfo(with listItem: (ListItemModelProtocol & MoleculeModelProtocol)?) -> (identifier: String, class: AnyClass, molecule: ListItemModelProtocol & MoleculeModelProtocol)? {
|
||||
/// Returns the (identifier, class) of the molecule for the given model.
|
||||
func createMoleculeInfo(with listItem: MoleculeModelProtocol?) -> (identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)? {
|
||||
|
||||
guard let listItem = listItem,
|
||||
let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(listItem)
|
||||
@ -223,14 +209,19 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
return (moleculeName, moleculeClass, listItem)
|
||||
}
|
||||
|
||||
/// Returns the (identifier, class) of the molecule for the indexPath.
|
||||
func getMoleculeInfo(for indexPath: IndexPath) -> (identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)? {
|
||||
return moleculesInfo?[indexPath.row]
|
||||
}
|
||||
|
||||
/// Sets up the molecule list and ensures no errors loading all content.
|
||||
func getMoleculeInfoList() -> [(identifier: String, class: AnyClass, molecule: (ListItemModelProtocol & MoleculeModelProtocol))]? {
|
||||
func getMoleculeInfoList() -> [(identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)]? {
|
||||
|
||||
var moleculeList: [(identifier: String, class: AnyClass, molecule: ListItemModelProtocol & MoleculeModelProtocol)] = []
|
||||
var moleculeList: [(identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)] = []
|
||||
|
||||
if let molecules = templateModel?.molecules {
|
||||
for molecule in molecules {
|
||||
if let info = getMoleculeInfo(with: molecule) {
|
||||
if let info = createMoleculeInfo(with: molecule) {
|
||||
moleculeList.append(info)
|
||||
}
|
||||
}
|
||||
|
||||
137
MVMCoreUI/Atomic/Templates/SectionListTemplate.swift
Normal file
137
MVMCoreUI/Atomic/Templates/SectionListTemplate.swift
Normal file
@ -0,0 +1,137 @@
|
||||
//
|
||||
// SectionListTemplate.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 9/25/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
open class SectionListTemplate: MoleculeListTemplate {
|
||||
|
||||
public var sectionMoleculesInfo: [(header: (identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)?, footer: (identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)?, rows: [(identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)])]?
|
||||
|
||||
open override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
tableView.sectionHeaderHeight = UITableView.automaticDimension
|
||||
}
|
||||
|
||||
override func setup() {
|
||||
// Create quick reference
|
||||
var sectionList: [(header: (identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)?, footer: (identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)?, rows: [(identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)])] = []
|
||||
|
||||
if let sections = (templateModel as? SectionListTemplateModel)?.sections {
|
||||
for section in sections {
|
||||
let header = createMoleculeInfo(with: section.header)
|
||||
let footer = createMoleculeInfo(with: section.footer)
|
||||
var rows: [(identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)] = []
|
||||
for row in section.rows {
|
||||
if let rowInfo = createMoleculeInfo(with: row) {
|
||||
rows.append(rowInfo)
|
||||
}
|
||||
}
|
||||
sectionList.append((header: header, footer: footer, rows: rows))
|
||||
}
|
||||
}
|
||||
|
||||
sectionMoleculesInfo = sectionList.count > 0 ? sectionList : nil
|
||||
}
|
||||
|
||||
override func getMoleculeInfo(for indexPath: IndexPath) -> (identifier: String, class: AnyClass, molecule: MoleculeModelProtocol)? {
|
||||
return sectionMoleculesInfo?[indexPath.section].rows[indexPath.row]
|
||||
}
|
||||
|
||||
open override func createTableView() -> TableView {
|
||||
let tableView = TableView(frame: .zero, style: .plain)
|
||||
tableView.backgroundColor = .clear
|
||||
tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.insetsContentViewsToSafeArea = false
|
||||
return tableView
|
||||
}
|
||||
|
||||
// For subclassing the model.
|
||||
open override func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> SectionListTemplateModel {
|
||||
return try decoder.decode(SectionListTemplateModel.self, from: data)
|
||||
}
|
||||
|
||||
open override func registerWithTable() {
|
||||
super.registerWithTable()
|
||||
guard let sections = sectionMoleculesInfo else { return }
|
||||
for section in sections {
|
||||
if let header = section.header {
|
||||
tableView.register(header.class, forHeaderFooterViewReuseIdentifier: header.identifier)
|
||||
}
|
||||
if let footer = section.footer {
|
||||
tableView.register(footer.class, forHeaderFooterViewReuseIdentifier: footer.identifier)
|
||||
}
|
||||
for row in section.rows {
|
||||
tableView.register(row.class, forCellReuseIdentifier: row.identifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
|
||||
guard let moleculeInfo = sectionMoleculesInfo?[section].header else {
|
||||
return CGFloat.leastNormalMagnitude
|
||||
}
|
||||
let estimatedHeight = (moleculeInfo.class as? MoleculeViewProtocol.Type)?.estimatedHeight(with: moleculeInfo.molecule, delegateObject() as? MVMCoreUIDelegateObject)
|
||||
return estimatedHeight ?? 80
|
||||
}
|
||||
|
||||
public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
guard (sectionMoleculesInfo?[section].header) != nil else {
|
||||
return CGFloat.leastNormalMagnitude
|
||||
}
|
||||
return UITableView.automaticDimension
|
||||
}
|
||||
|
||||
public func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat {
|
||||
guard let moleculeInfo = sectionMoleculesInfo?[section].footer else {
|
||||
return CGFloat.leastNormalMagnitude
|
||||
}
|
||||
let estimatedHeight = (moleculeInfo.class as? MoleculeViewProtocol.Type)?.estimatedHeight(with: moleculeInfo.molecule, delegateObject() as? MVMCoreUIDelegateObject)
|
||||
return estimatedHeight ?? 80
|
||||
}
|
||||
|
||||
public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
|
||||
guard (sectionMoleculesInfo?[section].footer) != nil else {
|
||||
return CGFloat.leastNormalMagnitude
|
||||
}
|
||||
return UITableView.automaticDimension
|
||||
}
|
||||
|
||||
public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
guard let sectionInfo = sectionMoleculesInfo?[section],
|
||||
let headerInfo = sectionInfo.header else { return nil }
|
||||
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerInfo.identifier)
|
||||
(header as? MoleculeViewProtocol)?.reset()
|
||||
(header as? MoleculeViewProtocol)?.set(with: headerInfo.molecule, delegateObjectIVar, nil)
|
||||
(header as? MVMCoreViewProtocol)?.updateView(tableView.bounds.width)
|
||||
// Neded to fix an apple defect where the cell is not the correct size on certain devices for certain cells
|
||||
header?.layoutIfNeeded()
|
||||
return header
|
||||
}
|
||||
|
||||
public func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
|
||||
guard let sectionInfo = sectionMoleculesInfo?[section],
|
||||
let footerInfo = sectionInfo.footer else { return nil }
|
||||
let footer = tableView.dequeueReusableHeaderFooterView(withIdentifier: footerInfo.identifier)
|
||||
(footer as? MoleculeViewProtocol)?.reset()
|
||||
(footer as? MoleculeViewProtocol)?.set(with: footerInfo.molecule, delegateObjectIVar, nil)
|
||||
(footer as? MVMCoreViewProtocol)?.updateView(tableView.bounds.width)
|
||||
// Neded to fix an apple defect where the cell is not the correct size on certain devices for certain cells
|
||||
footer?.layoutIfNeeded()
|
||||
return footer
|
||||
}
|
||||
|
||||
open override func getNumberOfSections() -> Int {
|
||||
return sectionMoleculesInfo?.count ?? 0
|
||||
}
|
||||
|
||||
open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return sectionMoleculesInfo?[section].rows.count ?? 0
|
||||
}
|
||||
}
|
||||
91
MVMCoreUI/Atomic/Templates/SectionListTemplateModel.swift
Normal file
91
MVMCoreUI/Atomic/Templates/SectionListTemplateModel.swift
Normal file
@ -0,0 +1,91 @@
|
||||
//
|
||||
// SectionListTemplateModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 9/25/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol SectionListHeaderFooterModel {
|
||||
|
||||
}
|
||||
|
||||
@objcMembers open class SectionModel: Codable {
|
||||
public var header: (SectionListHeaderFooterModel & MoleculeModelProtocol)?
|
||||
public var footer: (SectionListHeaderFooterModel & MoleculeModelProtocol)?
|
||||
public var rows: [ListItemModelProtocol & MoleculeModelProtocol]
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case header
|
||||
case footer
|
||||
case rows
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
header = try typeContainer.decodeModelIfPresent(codingKey: .header)
|
||||
footer = try typeContainer.decodeModelIfPresent(codingKey: .footer)
|
||||
rows = try typeContainer.decodeModels(codingKey: .rows)
|
||||
}
|
||||
|
||||
open func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeModelIfPresent(header, forKey: .header)
|
||||
try container.encodeModelIfPresent(footer, forKey: .footer)
|
||||
try container.encodeModels(rows, forKey: .rows)
|
||||
}
|
||||
}
|
||||
|
||||
@objcMembers open class SectionListTemplateModel: ListPageTemplateModel {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
open override class var identifier: String {
|
||||
return "sectionList"
|
||||
}
|
||||
|
||||
public var sections: [SectionModel]
|
||||
|
||||
override func validateModelHasContent() throws {
|
||||
if header == nil,
|
||||
sections.count == 0,
|
||||
footer == nil {
|
||||
throw ModelRegistry.Error.decoderOther(message: "Section List template requires atleast one of the following: header, footer, sections")
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case sections
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
sections = try typeContainer.decode([SectionModel].self, forKey: .sections)
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
open override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(sections, forKey: .sections)
|
||||
}
|
||||
}
|
||||
85
MVMCoreUI/BaseClasses/SectionHeaderFooterView.swift
Normal file
85
MVMCoreUI/BaseClasses/SectionHeaderFooterView.swift
Normal file
@ -0,0 +1,85 @@
|
||||
//
|
||||
// SectionHeaderFooterView.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 10/2/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers open class SectionHeaderFooterView: UITableViewHeaderFooterView, MoleculeViewProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
open var model: MoleculeModelProtocol?
|
||||
|
||||
private var initialSetupPerformed = false
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initialization
|
||||
//--------------------------------------------------
|
||||
|
||||
public override init(reuseIdentifier: String?) {
|
||||
super.init(reuseIdentifier: reuseIdentifier)
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
public required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
public func initialSetup() {
|
||||
if !initialSetupPerformed {
|
||||
initialSetupPerformed = true
|
||||
setupView()
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - MoleculeViewProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
self.model = model
|
||||
if let backgroundColor = model.backgroundColor {
|
||||
contentView.backgroundColor = backgroundColor.uiColor
|
||||
}
|
||||
}
|
||||
|
||||
open func reset() {
|
||||
contentView.backgroundColor = .white
|
||||
}
|
||||
|
||||
// MARK: Overridables
|
||||
// Base classes need to implement these functions otherwise swift won't respect the subclass functions and use the ones in the protocol extension instead.
|
||||
open class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
|
||||
return model.moleculeName
|
||||
}
|
||||
|
||||
open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
return nil
|
||||
}
|
||||
|
||||
open class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MARK:- MVMCoreViewProtocol
|
||||
extension SectionHeaderFooterView: MVMCoreViewProtocol {
|
||||
|
||||
open func updateView(_ size: CGFloat) { }
|
||||
|
||||
/// Will be called only once.
|
||||
open func setupView() {
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
insetsLayoutMarginsFromSafeArea = false
|
||||
preservesSuperviewLayoutMargins = false
|
||||
contentView.insetsLayoutMarginsFromSafeArea = false
|
||||
contentView.preservesSuperviewLayoutMargins = false
|
||||
MVMCoreUIUtility.setMarginsFor(self, leading: 0, top: 0, trailing: 0, bottom: 0)
|
||||
}
|
||||
}
|
||||
@ -63,6 +63,16 @@ open class ScrollingViewController: ViewController {
|
||||
registerForKeyboardNotifications()
|
||||
}
|
||||
|
||||
open override func handleNewData() {
|
||||
super.handleNewData()
|
||||
// will change scrollView indicatorStyle automatically on the basis of backgroundColor
|
||||
var greyScale: CGFloat = 0
|
||||
if view.backgroundColor?.getWhite(&greyScale, alpha: nil) ?? false {
|
||||
scrollView.indicatorStyle = greyScale > 0.5 ? .black : .white
|
||||
}
|
||||
scrollView.flashScrollIndicators()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keyboard Handling
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -8,15 +8,23 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
@objc open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMCoreViewManagerViewControllerProtocol, MoleculeDelegateProtocol, FormHolderProtocol, MVMCoreActionDelegateProtocol, MVMCoreLoadDelegateProtocol, UITextFieldDelegate, UITextViewDelegate, ObservingTextFieldDelegate, MVMCoreUIDetailViewProtocol {
|
||||
@objc open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMCoreViewManagerViewControllerProtocol, MoleculeDelegateProtocol, FormHolderProtocol, MVMCoreActionDelegateProtocol, MVMCoreLoadDelegateProtocol, UITextFieldDelegate, UITextViewDelegate, ObservingTextFieldDelegate, MVMCoreUIDetailViewProtocol, PageProtocol {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc public var pageType: String?
|
||||
@objc public var loadObject: MVMCoreLoadObject?
|
||||
public var pageModel: MVMControllerModelProtocol?
|
||||
public var model: MVMControllerModelProtocol?
|
||||
public var pageModel: PageModelProtocol? {
|
||||
get {
|
||||
return model
|
||||
}
|
||||
set {
|
||||
model = newValue as? MVMControllerModelProtocol
|
||||
}
|
||||
}
|
||||
|
||||
/// Set if this page is containted in a manager.
|
||||
public var manager: (UIViewController & MVMCoreViewManagerProtocol)?
|
||||
@ -111,9 +119,15 @@ import UIKit
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
self.handleNewDataAndUpdateUI()
|
||||
|
||||
// Update navigation bar if showing.
|
||||
if MVMCoreUIUtility.getCurrentVisibleController() == self {
|
||||
// Update navigation bar if showing.
|
||||
self.setNavigationBar()
|
||||
self.manager?.refreshNavigationUI()
|
||||
}
|
||||
// Update splitview properties
|
||||
if self == MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() {
|
||||
MVMCoreUISplitViewController.main()?.setBottomProgressBarProgress(self.bottomProgress() ?? 0)
|
||||
self.updateTabBar()
|
||||
}
|
||||
})
|
||||
} catch {
|
||||
@ -127,7 +141,7 @@ import UIKit
|
||||
pageType = loadObject.pageType
|
||||
self.loadObject = loadObject
|
||||
|
||||
// Verifies all modules needed are loaded. TODO: change to ViewController
|
||||
// Verifies all modules needed are loaded.
|
||||
guard ViewController.verifyRequiredModulesLoaded(for: loadObject, error: error) else { return false }
|
||||
|
||||
// Parse the model for the page.
|
||||
@ -214,18 +228,18 @@ import UIKit
|
||||
/// Creates a legacy navigation model.
|
||||
open func createDefaultLegacyNavigationModel() -> NavigationItemModel {
|
||||
let navigationModel = NavigationItemModel()
|
||||
navigationModel.title = pageModel?.screenHeading
|
||||
navigationModel.title = model?.screenHeading
|
||||
return navigationModel
|
||||
}
|
||||
|
||||
/// Processes any new data. Called after the page is loaded the first time and on response updates for this page,
|
||||
open func handleNewData() {
|
||||
if formValidator == nil {
|
||||
let rules = pageModel?.formRules
|
||||
let rules = model?.formRules
|
||||
formValidator = FormValidator(rules)
|
||||
}
|
||||
|
||||
if let backgroundColor = pageModel?.backgroundColor {
|
||||
if let backgroundColor = model?.backgroundColor {
|
||||
view.backgroundColor = backgroundColor.uiColor
|
||||
}
|
||||
|
||||
@ -234,16 +248,16 @@ import UIKit
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Navigation Item (Move to model base)
|
||||
// MARK: - Navigation Item
|
||||
//--------------------------------------------------
|
||||
|
||||
open func getNavigationModel() -> NavigationItemModelProtocol? {
|
||||
// TODO: remove legacy. Temporary, convert legacy to navigation model.
|
||||
if pageModel?.navigationBar == nil {
|
||||
if model?.navigationBar == nil {
|
||||
let navigationItem = createDefaultLegacyNavigationModel()
|
||||
pageModel?.navigationBar = navigationItem
|
||||
model?.navigationBar = navigationItem
|
||||
}
|
||||
return pageModel?.navigationBar
|
||||
return model?.navigationBar
|
||||
}
|
||||
|
||||
/// Sets the navigation item for this view controller.
|
||||
@ -252,70 +266,22 @@ import UIKit
|
||||
let navigationController = navigationController
|
||||
else { return }
|
||||
|
||||
// We additionally want our left items
|
||||
navigationItem.leftItemsSupplementBackButton = true
|
||||
|
||||
// Utilize helper function to set the navigation item state.
|
||||
NavigationController.setNavigationItem(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: self)
|
||||
}
|
||||
|
||||
/// Sets the appearance of the navigation bar based on the model.
|
||||
open func setNavigationBar() {
|
||||
let viewController = manager ?? self
|
||||
guard let navigationItemModel = getNavigationModel(),
|
||||
let navigationController = viewController.navigationController else {
|
||||
let navigationController = navigationController else {
|
||||
MVMCoreUISession.sharedGlobal()?.splitViewController?.parent?.setNeedsStatusBarAppearanceUpdate()
|
||||
return
|
||||
}
|
||||
|
||||
// Utilize helper function to set the split view and navigation item state.
|
||||
MVMCoreUISplitViewController.setNavigationBarUI(for: viewController, navigationController: navigationController, navigationItemModel: navigationItemModel, leftPanelAccessible: isMasterInitiallyAccessible(), rightPanelAccessible: isSupportInitiallyAccessible(), progress: bottomProgress() ?? 0)
|
||||
MVMCoreUISplitViewController.setNavigationBarUI(for: self, navigationController: navigationController, navigationItemModel: navigationItemModel)
|
||||
}
|
||||
|
||||
// Eventually will be moved to server
|
||||
open func isMasterInitiallyAccessible() -> Bool {
|
||||
if loadObject?.pageJSON?.boolForKey(KeyHideMainMenu) ?? false {
|
||||
return false
|
||||
}
|
||||
return MVMCoreUISession.sharedGlobal()?.launchAppLoadedSuccessfully ?? false
|
||||
}
|
||||
|
||||
// Eventually will be moved to server
|
||||
open func isSupportInitiallyAccessible() -> Bool {
|
||||
if loadObject?.pageJSON?.boolForKey(KeyHideMainMenu) ?? false {
|
||||
return false
|
||||
}
|
||||
return (MVMCoreUISession.sharedGlobal()?.launchAppLoadedSuccessfully ?? false) || showRightPanelForScreenBeforeLaunchApp()
|
||||
}
|
||||
|
||||
open func showRightPanelForScreenBeforeLaunchApp() -> Bool {
|
||||
return loadObject?.pageJSON?.lenientBoolForKey("showRightPanel") ?? false
|
||||
}
|
||||
|
||||
// Eventually will be moved to separate button in navigation item model
|
||||
open func isOverridingRightButton() -> Bool {
|
||||
guard let rightPanelLink = loadObject?.pageJSON?.optionalDictionaryForKey("rightPanelButtonLink")
|
||||
else { return false }
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: rightPanelLink, additionalData: nil, delegateObject: delegateObject())
|
||||
return true
|
||||
}
|
||||
|
||||
// Eventually will be moved to separate button in navigation item model
|
||||
open func isOverridingLeftButton() -> Bool {
|
||||
guard let leftPanelLink = loadObject?.pageJSON?.optionalDictionaryForKey("leftPanelButtonLink")
|
||||
else { return false }
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: leftPanelLink, additionalData: nil, delegateObject: delegateObject())
|
||||
return true
|
||||
}
|
||||
|
||||
// Eventually will be moved to Model
|
||||
open func bottomProgress() -> Float? {
|
||||
guard let progressString = loadObject?.pageJSON?.optionalStringForKey(KeyProgressPercent),
|
||||
let progress = Float(progressString)
|
||||
else { return nil }
|
||||
|
||||
return progress / Float(100)
|
||||
}
|
||||
//--------------------------------------------------
|
||||
// MARK: - TabBar
|
||||
//--------------------------------------------------
|
||||
@ -324,7 +290,7 @@ import UIKit
|
||||
guard MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() == self else { return }
|
||||
MVMCoreUISplitViewController.main()?.tabBar?.delegateObject = delegateObjectIVar
|
||||
|
||||
if let index = (pageModel as? TabPageModelProtocol)?.tabBarIndex {
|
||||
if let index = (model as? TabPageModelProtocol)?.tabBarIndex {
|
||||
MVMCoreUISplitViewController.main()?.tabBar?.highlightTab(at: index)
|
||||
} else if let index = loadObject?.requestParameters?.actionMap?["tabBarIndex"] as? Int {
|
||||
MVMCoreUISplitViewController.main()?.tabBar?.highlightTab(at: index)
|
||||
@ -335,7 +301,7 @@ import UIKit
|
||||
self.tabBarIndex = index
|
||||
}
|
||||
|
||||
if let hidden = (pageModel as? TabPageModelProtocol)?.tabBarHidden {
|
||||
if let hidden = (model as? TabPageModelProtocol)?.tabBarHidden {
|
||||
MVMCoreUISplitViewController.main()?.updateTabBarShowing(!hidden)
|
||||
} else if let hidden = loadObject?.requestParameters?.actionMap?["tabBarHidden"] as? Bool {
|
||||
MVMCoreUISplitViewController.main()?.updateTabBarShowing(!hidden)
|
||||
@ -398,14 +364,15 @@ import UIKit
|
||||
}
|
||||
|
||||
open func pageShown() {
|
||||
// Update the navigation bar ui when view is appearing.
|
||||
// Update split view properties if this is the current detail controller.
|
||||
if self == MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() {
|
||||
MVMCoreUISplitViewController.main()?.setupPanels()
|
||||
MVMCoreUISplitViewController.main()?.setBottomProgressBarProgress(bottomProgress() ?? 0)
|
||||
updateTabBar()
|
||||
}
|
||||
setNavigationBar()
|
||||
|
||||
// Update tab if needed.
|
||||
updateTabBar()
|
||||
// Update the navigation bar ui when view is appearing.
|
||||
setNavigationBar()
|
||||
|
||||
// Track.
|
||||
MVMCoreUISession.sharedGlobal()?.currentPageType = pageType
|
||||
@ -472,13 +439,17 @@ import UIKit
|
||||
MVMCoreUISession.sharedGlobal()?.splitViewController?.showRightPanel(animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Override this method to avoid adding form params.
|
||||
open func addFormParams(_ requestParameters: MVMCoreRequestParameters) {
|
||||
formValidator?.addFormParams(requestParameters: requestParameters)
|
||||
}
|
||||
//--------------------------------------------------
|
||||
// MARK: - MVMCoreActionDelegateProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
open func handleOpenPage(for requestParameters: MVMCoreRequestParameters, actionInformation: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) {
|
||||
formValidator?.addFormParams(requestParameters: requestParameters)
|
||||
addFormParams(requestParameters)
|
||||
requestParameters.parentPageType = loadObject?.pageJSON?.optionalStringForKey("parentPageType")
|
||||
MVMCoreActionHandler.defaultHandleOpenPage(for: requestParameters, additionalData: additionalData, delegateObject: delegateObject())
|
||||
}
|
||||
@ -526,6 +497,51 @@ import UIKit
|
||||
setNavigationBar()
|
||||
}
|
||||
|
||||
public func isLeftPanelAccessible() -> Bool {
|
||||
// TODO: Remove when hamburger menu is fully phased out.
|
||||
if loadObject?.pageJSON?.boolForKey(KeyHideMainMenu) ?? false {
|
||||
return false
|
||||
}
|
||||
return MVMCoreUISession.sharedGlobal()?.launchAppLoadedSuccessfully ?? false
|
||||
}
|
||||
|
||||
public func isRightPanelAccessible() -> Bool {
|
||||
// TODO: Remove when FAB is 100%.
|
||||
if loadObject?.pageJSON?.boolForKey(KeyHideMainMenu) ?? false {
|
||||
return false
|
||||
}
|
||||
return (MVMCoreUISession.sharedGlobal()?.launchAppLoadedSuccessfully ?? false) || showRightPanelForScreenBeforeLaunchApp()
|
||||
}
|
||||
|
||||
open func showRightPanelForScreenBeforeLaunchApp() -> Bool {
|
||||
return loadObject?.pageJSON?.lenientBoolForKey("showRightPanel") ?? false
|
||||
}
|
||||
|
||||
// TODO: make molecular
|
||||
open func isOverridingRightButton() -> Bool {
|
||||
guard let rightPanelLink = loadObject?.pageJSON?.optionalDictionaryForKey("rightPanelButtonLink")
|
||||
else { return false }
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: rightPanelLink, additionalData: nil, delegateObject: delegateObject())
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO: make molecular
|
||||
open func isOverridingLeftButton() -> Bool {
|
||||
guard let leftPanelLink = loadObject?.pageJSON?.optionalDictionaryForKey("leftPanelButtonLink")
|
||||
else { return false }
|
||||
MVMCoreActionHandler.shared()?.handleAction(with: leftPanelLink, additionalData: nil, delegateObject: delegateObject())
|
||||
return true
|
||||
}
|
||||
|
||||
// Eventually will be moved to Model
|
||||
open func bottomProgress() -> Float? {
|
||||
guard let progressString = loadObject?.pageJSON?.optionalStringForKey(KeyProgressPercent),
|
||||
let progress = Float(progressString)
|
||||
else { return nil }
|
||||
|
||||
return progress / Float(100)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - UITextFieldDelegate
|
||||
//--------------------------------------------------
|
||||
@ -594,6 +610,6 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
|
||||
func executeBehaviors<T>(_ behaviorBlock:(_ behavior:T)->Void) {
|
||||
pageModel?.behaviors?.compactMap({ $0 as? T }).forEach { behaviorBlock($0) }
|
||||
model?.behaviors?.compactMap({ $0 as? T }).forEach { behaviorBlock($0) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +48,7 @@ import UIKit
|
||||
viewController.navigationItem.title = navigationItemModel.title
|
||||
viewController.navigationItem.accessibilityLabel = navigationItemModel.title
|
||||
viewController.navigationItem.hidesBackButton = navigationItemModel.hidesSystemBackButton
|
||||
viewController.navigationItem.leftItemsSupplementBackButton = !navigationItemModel.hidesSystemBackButton
|
||||
setNavigationButtons(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
|
||||
setNavigationTitleView(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
|
||||
}
|
||||
@ -58,7 +59,7 @@ import UIKit
|
||||
var leftItems: [UIBarButtonItem] = []
|
||||
if navigationItemModel.alwaysShowBackButton != false {
|
||||
if let backButtonModel = navigationItemModel.backButton,
|
||||
navigationController.viewControllers.count > 1 || navigationItemModel.alwaysShowBackButton ?? false {
|
||||
MVMCoreNavigationHandler.shared()?.getViewControllers(for: navigationController)?.count ?? 0 > 1 || navigationItemModel.alwaysShowBackButton ?? false {
|
||||
leftItems.append(backButtonModel.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
|
||||
}
|
||||
if let leftItemModels = navigationItemModel.additionalLeftButtons {
|
||||
@ -94,23 +95,7 @@ import UIKit
|
||||
navigationController.separatorView?.isHidden = navigationItemModel.line?.type ?? .standard == .none
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience setter for legacy files
|
||||
public static func setNavigationItem(navigationController: UINavigationController, navigationJSON: [String: Any], viewController: UIViewController) throws {
|
||||
guard let barModel = try MoleculeObjectMapping.shared()?.getMoleculeModelForJSON(navigationJSON) as? (MoleculeModelProtocol & NavigationItemModelProtocol) else {
|
||||
throw ModelRegistry.Error.decoderOther(message: "Model not a bar model")
|
||||
}
|
||||
setNavigationItem(navigationController: navigationController, navigationItemModel: barModel, viewController: viewController)
|
||||
}
|
||||
|
||||
/// Convenience setter for legacy files
|
||||
public static func setNavigationBarUI(navigationController: UINavigationController, navigationJSON: [String: Any], viewController: UIViewController) throws {
|
||||
guard let barModel = try MoleculeObjectMapping.shared()?.getMoleculeModelForJSON(navigationJSON) as? (MoleculeModelProtocol & NavigationItemModelProtocol) else {
|
||||
throw ModelRegistry.Error.decoderOther(message: "Model not a bar model")
|
||||
}
|
||||
setNavigationBarUI(navigationController: navigationController, navigationItemModel: barModel, viewController: viewController)
|
||||
}
|
||||
|
||||
|
||||
/// Convenience function for setting the navigation titleView.
|
||||
public static func setNavigationTitleView(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol?, viewController: UIViewController) {
|
||||
let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject
|
||||
|
||||
@ -15,6 +15,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@optional
|
||||
|
||||
/// Returns if the left panel should be accessible.
|
||||
- (BOOL)isLeftPanelAccessible;
|
||||
|
||||
/// Returns if the right panel should be accessible.
|
||||
- (BOOL)isRightPanelAccessible;
|
||||
|
||||
- (void)panelWillAppear:(nonnull NSObject <MVMCoreUIPanelProtocol>*)panel;
|
||||
- (void)panelWillAppear:(nonnull NSObject <MVMCoreUIPanelProtocol>*)panel overtakingDetail:(BOOL)willOvertake;
|
||||
- (void)panelDidAppear:(nonnull NSObject <MVMCoreUIPanelProtocol>*)panel;
|
||||
|
||||
@ -10,32 +10,29 @@ import Foundation
|
||||
|
||||
public extension MVMCoreUISplitViewController {
|
||||
|
||||
/// Convenience function. Sets the navigation and split view properties for the view controller. Optional parameters use current value if not set.
|
||||
static func setNavigationBarUI(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol, leftPanelAccessible: Bool? = nil, rightPanelAccessible: Bool? = nil, progress: Float? = nil) {
|
||||
/// Convenience function. Sets the navigation and split view properties for the view controller. Panel access is determined if view controller is a detail view protocol.
|
||||
static func setNavigationBarUI(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) {
|
||||
guard let splitView = MVMCoreUISplitViewController.main(),
|
||||
navigationController == splitView.navigationController,
|
||||
navigationController.topViewController == viewController else {
|
||||
NavigationController.setNavigationBarUI(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
|
||||
return
|
||||
/// Not the split view navigation controller, skip split functions.
|
||||
NavigationController.setNavigationBarUI(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
|
||||
return
|
||||
}
|
||||
splitView.set(for: viewController, navigationController: navigationController, navigationItemModel: navigationItemModel, leftPanelAccessible: leftPanelAccessible, rightPanelAccessible: rightPanelAccessible, progress: progress)
|
||||
splitView.set(for: viewController, navigationController: navigationController, navigationItemModel: navigationItemModel)
|
||||
}
|
||||
|
||||
/// Sets the navigation item for the view controller based on the model and splitview controller
|
||||
private func set(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol, leftPanelAccessible: Bool? = nil, rightPanelAccessible: Bool? = nil, progress: Float? = nil) {
|
||||
private func set(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) {
|
||||
NavigationController.setNavigationBarUI(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
|
||||
|
||||
setLeftPanelIsAccessible(leftPanelAccessible ?? leftPanelIsAccessible, for: viewController, updateNavigationButtons: false)
|
||||
setRightPanelIsAccessible(rightPanelAccessible ?? rightPanelIsAccessible, for: viewController, updateNavigationButtons: false)
|
||||
setLeftPanelIsAccessible((viewController as? MVMCoreUIDetailViewProtocol)?.isLeftPanelAccessible?() ?? false, for: viewController, updateNavigationButtons: false)
|
||||
setRightPanelIsAccessible((viewController as? MVMCoreUIDetailViewProtocol)?.isRightPanelAccessible?() ?? false, for: viewController, updateNavigationButtons: false)
|
||||
|
||||
setLeftNavigationButtons(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
|
||||
setRightNavigationButtons(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
|
||||
|
||||
setNavigationIconColor(navigationItemModel.tintColor.uiColor)
|
||||
|
||||
if let progress = progress {
|
||||
setBottomProgressBarProgress(progress)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the left navigation items for the view controller based on model and splitview.
|
||||
@ -48,7 +45,7 @@ public extension MVMCoreUISplitViewController {
|
||||
if let forceBackButton = navigationItemModel?.alwaysShowBackButton {
|
||||
showBackButton = forceBackButton
|
||||
} else {
|
||||
showBackButton = navigationController.viewControllers.count > 1
|
||||
showBackButton = MVMCoreNavigationHandler.shared()?.getViewControllers(for: navigationController)?.count ?? 0 > 1
|
||||
}
|
||||
if showBackButton {
|
||||
if let backButtonModel = navigationItemModel?.backButton {
|
||||
@ -107,20 +104,4 @@ public extension MVMCoreUISplitViewController {
|
||||
|
||||
viewController.navigationItem.setRightBarButtonItems(rightItems.count > 0 ? rightItems : nil, animated: !DisableAnimations.boolValue)
|
||||
}
|
||||
|
||||
// MARK: - Legacy Functions
|
||||
/// Convenience setter for legacy files. Sets the navigation item for the view controller based on the json and splitview controller
|
||||
@objc static func setNavigationBarUI(for viewController: UIViewController, navigationController: UINavigationController, navigationJSON: [String: Any], leftPanelAccessible: Bool, rightPanelAccessible: Bool, progress: NSNumber?) throws {
|
||||
guard let navigationItemModel = try MoleculeObjectMapping.shared()?.getMoleculeModelForJSON(navigationJSON) as? (MoleculeModelProtocol & NavigationItemModelProtocol) else {
|
||||
throw ModelRegistry.Error.decoderOther(message: "Model not a bar model")
|
||||
}
|
||||
guard let splitView = MVMCoreUISplitViewController.main(),
|
||||
navigationController == splitView.navigationController,
|
||||
navigationController.topViewController == viewController else {
|
||||
NavigationController.setNavigationBarUI(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
|
||||
return
|
||||
}
|
||||
let progress = progress?.floatValue
|
||||
splitView.set(for: viewController, navigationController: navigationController, navigationItemModel: navigationItemModel, leftPanelAccessible: leftPanelAccessible, rightPanelAccessible: rightPanelAccessible, progress: progress)
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,7 +241,7 @@ CGFloat const PanelAnimationDuration = 0.2;
|
||||
|
||||
- (void)setLeftNavigationItemForViewController:(UIViewController * _Nonnull)viewController accessible:(BOOL)accessible extended:(BOOL)extended {
|
||||
NSMutableArray *leftBarButtonItems = [NSMutableArray array];
|
||||
if ([viewController.navigationController.viewControllers count] > 1) {
|
||||
if (viewController.navigationController && [MVMCoreNavigationHandler.sharedNavigationHandler getViewControllersForNavigationController:viewController.navigationController].count > 1) {
|
||||
[leftBarButtonItems addObject:self.backButton];
|
||||
}
|
||||
if ((accessible && !extended) && self.leftPanelButton) {
|
||||
|
||||
@ -20,6 +20,8 @@ public extension MVMCoreUIViewControllerMappingObject {
|
||||
|
||||
register(template: MoleculeListTemplate.self)
|
||||
add(toTemplateViewControllerMapping: ["modalList": MVMCoreViewControllerProgrammaticMappingObject(with: ModalMoleculeListTemplate.self)!])
|
||||
add(toTemplateViewControllerMapping: [SectionListTemplateModel.identifier: MVMCoreViewControllerProgrammaticMappingObject(with: SectionListTemplate.self)!])
|
||||
add(toTemplateViewControllerMapping: [ModalSectionListTemplateModel.identifier: MVMCoreViewControllerProgrammaticMappingObject(with: ModalSectionListTemplate.self)!])
|
||||
|
||||
register(template: ThreeLayerTemplate.self)
|
||||
register(template: ThreeLayerCenterTemplate.self)
|
||||
|
||||
@ -67,6 +67,11 @@
|
||||
"AccOff" = "off";
|
||||
"AccToggleHint" = "double tap to toggle";
|
||||
|
||||
// MARK: Heart
|
||||
"heart_favorite_action_hint" = "Double tap to favorite";
|
||||
"heart_unfavorite_action_hint" = "Double tap to unfavorite";
|
||||
"heart_selected_state" = "Favorited";
|
||||
"heart_not_selected_state" = "Un-favorited";
|
||||
|
||||
// MARK: Carousel
|
||||
"MVMCoreUIPageControl_currentpage_index" = "page %@ of %d";
|
||||
|
||||
@ -49,6 +49,11 @@
|
||||
"AccOn" = "encendido";
|
||||
"AccOff" = "apagado";
|
||||
"AccToggleHint" = "toca dos veces para alternar";
|
||||
// Heart
|
||||
"heart_favorite_action_hint" = "Toca dos veces en favorito";
|
||||
"heart_unfavorite_action_hint" = "Toca dos veces para dejar de marcar como favorito";
|
||||
"heart_selected_state" = "Favoritos";
|
||||
"heart_not_selected_state" = "No favorito";
|
||||
// Carousel
|
||||
"MVMCoreUIPageControl_currentpage_index" = "página %@ de %d";
|
||||
"MVMCoreUIPageControlslides_currentpage_index" = "diapositiva %@ of %d";
|
||||
|
||||
@ -51,6 +51,13 @@
|
||||
"AccOn" = "encendido";
|
||||
"AccOff" = "apagado";
|
||||
"AccToggleHint" = "toca dos veces para alternar";
|
||||
|
||||
// Heart
|
||||
"heart_favorite_action_hint" = "Toca dos veces en favorito";
|
||||
"heart_unfavorite_action_hint" = "Toca dos veces para dejar de marcar como favorito";
|
||||
"heart_selected_state" = "Favoritos";
|
||||
"heart_not_selected_state" = "No favorito";
|
||||
|
||||
// Carousel
|
||||
"MVMCoreUIPageControl_currentpage_index" = "página %@ de %d";
|
||||
"MVMCoreUIPageControlslides_currentpage_index" = "diapositiva %@ of %d";
|
||||
|
||||
@ -21,14 +21,17 @@ public extension MVMCoreUITopAlertView {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(viewControllerChanged(notification:)), name: NSNotification.Name(rawValue: MVMCoreNotificationViewControllerChanged), object: nil)
|
||||
}
|
||||
|
||||
@objc func getDelegateObject() -> MVMCoreUIDelegateObject {
|
||||
// TODO: Top alert view is current delegate. Should move to current view controller eventually?
|
||||
return MVMCoreUIDelegateObject.create(withDelegateForAll: self)
|
||||
}
|
||||
|
||||
/// Checks for new top alert json
|
||||
@objc func responseJSONUpdated(notification: Notification) {
|
||||
guard let responseJSON = (notification.userInfo?[String(describing: MVMCoreLoadObject.self)] as? MVMCoreLoadObject)?.responseJSON,
|
||||
let json = responseJSON.optionalDictionaryForKey("TopNotification") else { return }
|
||||
|
||||
// TODO: Top alert view is current delegate. Should move to current view controller eventually?
|
||||
let delegateObject = MVMCoreUIDelegateObject.create(withDelegateForAll: self)
|
||||
showTopAlert(with: json, delegateObject: delegateObject)
|
||||
let json = responseJSON.optionalDictionaryForKey("TopNotification"),
|
||||
let model = decodeTopNotification(with: json, delegateObject: getDelegateObject()) else { return }
|
||||
showTopAlert(with: model)
|
||||
}
|
||||
|
||||
/// When a detail page changes, check top alerts.
|
||||
@ -37,24 +40,55 @@ public extension MVMCoreUITopAlertView {
|
||||
MVMCoreAlertHandler.shared()?.checkPagesDependency(for: controller.pageType)
|
||||
}
|
||||
|
||||
/// Shows the top alert with the json payload.
|
||||
func showTopAlert(with json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) {
|
||||
/// Decodes the json into a TopNotificationModel
|
||||
func decodeTopNotification(with json: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?) -> TopNotificationModel? {
|
||||
do {
|
||||
let model = try TopNotificationModel.decode(json: json, delegateObject: delegateObject)
|
||||
showTopAlert(with: model, delegateObject: delegateObject)
|
||||
return try TopNotificationModel.decode(json: json, delegateObject: delegateObject)
|
||||
} catch {
|
||||
if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: "\(self)") {
|
||||
MVMCoreUILoggingHandler.shared()?.addError(toLog: errorObject)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Shows the top alert with the model.
|
||||
func showTopAlert(with model: TopNotificationModel, delegateObject: MVMCoreUIDelegateObject?) {
|
||||
func showTopAlert(with model: TopNotificationModel) {
|
||||
let object = model.createTopAlertObject()
|
||||
MVMCoreAlertHandler.shared()?.showTopAlert(with: object)
|
||||
}
|
||||
|
||||
/// Updates the current top alert molecule with the new object
|
||||
@objc func updateMolecule(with topAlertObject: MVMCoreTopAlertObject) {
|
||||
guard topAlertObject.type == self.topAlertObject?.type else { return }
|
||||
let delegateObject = getDelegateObject()
|
||||
guard let newJson = topAlertObject.json,
|
||||
let newModel = decodeTopNotification(with: newJson, delegateObject: delegateObject),
|
||||
let newModelName = MoleculeObjectMapping.shared()?.getMoleculeClass(newModel.molecule)?.nameForReuse(with: newModel.molecule, delegateObject),
|
||||
let currentJson = self.topAlertObject?.json,
|
||||
let currentModel = decodeTopNotification(with: currentJson, delegateObject: delegateObject),
|
||||
let currentModelName = MoleculeObjectMapping.shared()?.getMoleculeClass(currentModel.molecule)?.nameForReuse(with: currentModel.molecule, delegateObject),
|
||||
newModelName == currentModelName,
|
||||
let molecule = currentAlert as? MoleculeViewProtocol else {
|
||||
// Log that we couldn't update.
|
||||
if let errorObject = MVMCoreErrorObject(title: nil, message: nil, messageToLog: nil, code: ErrorCode.parsingJSON.rawValue, domain: ErrorDomainNative, location: "TopNotification update \(String(describing: topAlertObject.type))") {
|
||||
MVMCoreUILoggingHandler.shared()?.addError(toLog: errorObject)
|
||||
}
|
||||
return
|
||||
}
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
// Update molecule
|
||||
molecule.reset()
|
||||
molecule.set(with: newModel.molecule, delegateObject, nil)
|
||||
(molecule as? MVMCoreViewProtocol)?.updateView(self.bounds.width)
|
||||
|
||||
// Update status bar.
|
||||
guard let statusBarDelegate = molecule as? StatusBarUI else { return }
|
||||
let statusBarUI = statusBarDelegate.getStatusBarUI()
|
||||
self.setStatusBarColor(statusBarUI.color, statusBarStyle: statusBarUI.style)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the top alert molecule to use and status bar color legacy style.
|
||||
@objc func molecule(for topAlertObject: MVMCoreTopAlertObject, statusBarColor: AutoreleasingUnsafeMutablePointer<UIColor?>?, statusBarStyle: UnsafeMutablePointer<UIStatusBarStyle>?) -> UIView? {
|
||||
do {
|
||||
|
||||
@ -27,6 +27,9 @@
|
||||
// Current top alert object
|
||||
@property (strong, nullable, nonatomic) MVMCoreTopAlertObject *topAlertObject;
|
||||
|
||||
/// Current top alert view.
|
||||
@property (weak, nullable, nonatomic, readonly) UIView *currentAlert;
|
||||
|
||||
// Returns the top alert view
|
||||
+ (nullable instancetype)sharedGlobal;
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed.";
|
||||
@property (strong, nonatomic) NSLayoutConstraint *statusBarBottomConstraint;
|
||||
|
||||
@property (weak, nonatomic) UIView *alertView;
|
||||
@property (weak, nonatomic) UIView *currentAlert;
|
||||
@property (weak, nullable, nonatomic, readwrite) UIView *currentAlert;
|
||||
@property (strong, nonatomic) NSLayoutConstraint *height;
|
||||
|
||||
@property (weak, nonatomic) MVMCoreUITopAlertExpandableView *topAlertClearspotView;
|
||||
@ -181,6 +181,10 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed.";
|
||||
});
|
||||
}
|
||||
|
||||
- (void)updateTopAlertWith:(MVMCoreTopAlertObject *)topAlertObject {
|
||||
[self updateMoleculeWith:topAlertObject];
|
||||
}
|
||||
|
||||
- (void)setStatusBarColor:(nullable UIColor *)statusBarColor statusBarStyle:(UIStatusBarStyle)style {
|
||||
self.statusBarView.backgroundColor = statusBarColor;
|
||||
self.statusBarStyle = style;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user