This commit is contained in:
Kevin G Christiano 2020-10-19 09:24:57 -04:00
commit 24ed53366b
74 changed files with 1274 additions and 279 deletions

View File

@ -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 */,
);

View 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 }
}

View 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)
}
}

View File

@ -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)

View File

@ -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
}
}
}
}

View File

@ -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)

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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()
}

View File

@ -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)
}
}

View File

@ -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()
}

View File

@ -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)
}
}

View File

@ -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()
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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
}
}
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -10,7 +10,7 @@ import Foundation
import MVMCore
@objcMembers public class MoleculeListItemModel: ListItemModel, MoleculeModelProtocol {
@objcMembers public class MoleculeListItemModel: ListItemModel, MoleculeContainerModelProtocol, MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------

View File

@ -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)

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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)
}
}

View 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 }
}

View File

@ -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 {

View File

@ -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 {

View 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)
})
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View 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
}
}

View 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)
}
}

View 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)
}
}

View File

@ -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
//--------------------------------------------------

View File

@ -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) }
}
}

View File

@ -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

View File

@ -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;

View File

@ -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)
}
}

View File

@ -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) {

View File

@ -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)

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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 {

View File

@ -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;

View File

@ -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;