diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index d8399580..ffa63ba7 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -12,11 +12,23 @@ 0105618E224BBE7700E1557D /* FormValidator+TextFields.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */; }; 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */; }; 0116A4E5228B19640094F3ED /* RadioButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0116A4E4228B19640094F3ED /* RadioButtonModel.swift */; }; + 012A889C23889E8400FE3DA1 /* TemplateModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A889B23889E8400FE3DA1 /* TemplateModelProtocol.swift */; }; + 012A88AD238C418100FE3DA1 /* TemplateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */; }; + 012A88AF238C626E00FE3DA1 /* CarouselModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88AE238C626E00FE3DA1 /* CarouselModel.swift */; }; + 012A88B1238C880100FE3DA1 /* PagingMoleculeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88B0238C880100FE3DA1 /* PagingMoleculeProtocol.swift */; }; + 012A88C2238D7BCA00FE3DA1 /* CarouselItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88C1238D7BCA00FE3DA1 /* CarouselItemModel.swift */; }; + 012A88C4238D86E600FE3DA1 /* CollectionCellMoleculeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88C3238D86E600FE3DA1 /* CollectionCellMoleculeProtocol.swift */; }; + 012A88C6238DA34000FE3DA1 /* ModuleMoleculeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88C5238DA34000FE3DA1 /* ModuleMoleculeModel.swift */; }; + 012A88C8238DB02000FE3DA1 /* ModelMoleculeDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88C7238DB02000FE3DA1 /* ModelMoleculeDelegateProtocol.swift */; }; 012CA98923849699003F810F /* SeperatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA98823849699003F810F /* SeperatorModel.swift */; }; 012CA99A2384A687003F810F /* MFTextField+ModelExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA9992384A687003F810F /* MFTextField+ModelExtension.swift */; }; 012CA99C23859FDC003F810F /* ViewConstrainingView+ModelExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA99B23859FDC003F810F /* ViewConstrainingView+ModelExtension.swift */; }; 012CA99E2385A2D3003F810F /* MFView+ModelExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA99D2385A2D3003F810F /* MFView+ModelExtension.swift */; }; 012CA9BE2385C692003F810F /* ConstrainingMoleculeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA9BD2385C692003F810F /* ConstrainingMoleculeProtocol.swift */; }; + 012CA9DE2388723E003F810F /* ListPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA9DD2388723E003F810F /* ListPageTemplateModel.swift */; }; + 012CA9E023888AC8003F810F /* StackPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA9DF23888AC8003F810F /* StackPageTemplateModel.swift */; }; + 012CA9E223888AED003F810F /* StackCenteredPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA9E123888AED003F810F /* StackCenteredPageTemplateModel.swift */; }; + 012CA9E423888B1B003F810F /* ThreeLayerPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA9E323888B1B003F810F /* ThreeLayerPageTemplateModel.swift */; }; 01509D8F2327EC6F00EF99AA /* MoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */; }; 01509D912327ECE600EF99AA /* CornerLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01509D902327ECE600EF99AA /* CornerLabels.swift */; }; 01509D932327ECFB00EF99AA /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01509D922327ECFB00EF99AA /* ProgressBar.swift */; }; @@ -232,11 +244,23 @@ 0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+TextFields.swift"; sourceTree = ""; }; 0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+FormParams.swift"; sourceTree = ""; }; 0116A4E4228B19640094F3ED /* RadioButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonModel.swift; sourceTree = ""; }; + 012A889B23889E8400FE3DA1 /* TemplateModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateModelProtocol.swift; sourceTree = ""; }; + 012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateProtocol.swift; sourceTree = ""; }; + 012A88AE238C626E00FE3DA1 /* CarouselModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselModel.swift; sourceTree = ""; }; + 012A88B0238C880100FE3DA1 /* PagingMoleculeProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PagingMoleculeProtocol.swift; sourceTree = ""; }; + 012A88C1238D7BCA00FE3DA1 /* CarouselItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselItemModel.swift; sourceTree = ""; }; + 012A88C3238D86E600FE3DA1 /* CollectionCellMoleculeProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionCellMoleculeProtocol.swift; sourceTree = ""; }; + 012A88C5238DA34000FE3DA1 /* ModuleMoleculeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModuleMoleculeModel.swift; sourceTree = ""; }; + 012A88C7238DB02000FE3DA1 /* ModelMoleculeDelegateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelMoleculeDelegateProtocol.swift; sourceTree = ""; }; 012CA98823849699003F810F /* SeperatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeperatorModel.swift; sourceTree = ""; }; 012CA9992384A687003F810F /* MFTextField+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFTextField+ModelExtension.swift"; sourceTree = ""; }; 012CA99B23859FDC003F810F /* ViewConstrainingView+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ViewConstrainingView+ModelExtension.swift"; sourceTree = ""; }; 012CA99D2385A2D3003F810F /* MFView+ModelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MFView+ModelExtension.swift"; sourceTree = ""; }; 012CA9BD2385C692003F810F /* ConstrainingMoleculeProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConstrainingMoleculeProtocol.swift; sourceTree = ""; }; + 012CA9DD2388723E003F810F /* ListPageTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListPageTemplateModel.swift; sourceTree = ""; }; + 012CA9DF23888AC8003F810F /* StackPageTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackPageTemplateModel.swift; sourceTree = ""; }; + 012CA9E123888AED003F810F /* StackCenteredPageTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackCenteredPageTemplateModel.swift; sourceTree = ""; }; + 012CA9E323888B1B003F810F /* ThreeLayerPageTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerPageTemplateModel.swift; sourceTree = ""; }; 01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeTableViewCell.swift; sourceTree = ""; }; 01509D902327ECE600EF99AA /* CornerLabels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; sourceTree = ""; }; 01509D922327ECFB00EF99AA /* ProgressBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; @@ -462,11 +486,27 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 012A889A238898C600FE3DA1 /* Template */ = { + isa = PBXGroup; + children = ( + 012A889B23889E8400FE3DA1 /* TemplateModelProtocol.swift */, + 017BEB392360EEB40024EF95 /* PageModel.swift */, + 012CA9DD2388723E003F810F /* ListPageTemplateModel.swift */, + 012CA9DF23888AC8003F810F /* StackPageTemplateModel.swift */, + 012CA9E123888AED003F810F /* StackCenteredPageTemplateModel.swift */, + 012CA9E323888B1B003F810F /* ThreeLayerPageTemplateModel.swift */, + ); + path = Template; + sourceTree = ""; + }; 01509D96232803B200EF99AA /* Models */ = { isa = PBXGroup; children = ( - 017BEB392360EEB40024EF95 /* PageModel.swift */, + 012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */, 01EB3683236097C0006832FA /* MoleculeProtocol.swift */, + 012A88B0238C880100FE3DA1 /* PagingMoleculeProtocol.swift */, + 012A88C3238D86E600FE3DA1 /* CollectionCellMoleculeProtocol.swift */, + 012A889A238898C600FE3DA1 /* Template */, 012CA9BD2385C692003F810F /* ConstrainingMoleculeProtocol.swift */, 946EE1B5237B663A0036751F /* Extensions */, 01EB368723609801006832FA /* Molecules */, @@ -498,6 +538,9 @@ 017BEB3F23620A230024EF95 /* TextFieldModel.swift */, 017BEB4123620AD20024EF95 /* FormModelProtocol.swift */, 017BEB7A236763000024EF95 /* LineModel.swift */, + 012A88AE238C626E00FE3DA1 /* CarouselModel.swift */, + 012A88C1238D7BCA00FE3DA1 /* CarouselItemModel.swift */, + 012A88C5238DA34000FE3DA1 /* ModuleMoleculeModel.swift */, ); path = Molecules; sourceTree = ""; @@ -900,6 +943,7 @@ D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */, D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */, D296E1402295EBBA0051EBE7 /* MoleculeDelegateProtocol.h */, + 012A88C7238DB02000FE3DA1 /* ModelMoleculeDelegateProtocol.swift */, D2A514562211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.h */, D2A514572211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m */, 017BEB432362192F0024EF95 /* MVMCoreUIMoleculeMappingObject+ModelExtension.swift */, @@ -1135,6 +1179,7 @@ buildActionMask = 2147483647; files = ( 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */, + 012CA9E423888B1B003F810F /* ThreeLayerPageTemplateModel.swift in Sources */, D29DF32121ED0CBA003B2FB9 /* LabelView.m in Sources */, DBC4391822442197001AB423 /* CaretView.swift in Sources */, D29770F221F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m in Sources */, @@ -1157,11 +1202,13 @@ D29DF25321E6A177003B2FB9 /* MFDigitTextField.m in Sources */, D2B18B7F2360913400A9AEDC /* Control.swift in Sources */, D29DF12F21E6851E003B2FB9 /* MVMCoreUITopAlertMainView.m in Sources */, + 012A88C8238DB02000FE3DA1 /* ModelMoleculeDelegateProtocol.swift in Sources */, DBC4392122491730001AB423 /* LabelWithInternalButton.swift in Sources */, D224798C231450C8003FCCF9 /* HeadlineBodySwitch.swift in Sources */, 017BEB442362192F0024EF95 /* MVMCoreUIMoleculeMappingObject+ModelExtension.swift in Sources */, D29DF17C21E69E1F003B2FB9 /* MFTextButton.m in Sources */, D29DF2C521E7BF57003B2FB9 /* MFTabBarSwipeAnimator.m in Sources */, + 012A88AD238C418100FE3DA1 /* TemplateProtocol.swift in Sources */, D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */, 01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */, D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */, @@ -1173,6 +1220,7 @@ D2A5145F2211DDC100345BFB /* MoleculeStackView.swift in Sources */, D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */, D29DF24D21E6A177003B2FB9 /* MFTextField.m in Sources */, + 012A88C4238D86E600FE3DA1 /* CollectionCellMoleculeProtocol.swift in Sources */, 017BEB4023620A230024EF95 /* TextFieldModel.swift in Sources */, D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */, D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */, @@ -1181,6 +1229,8 @@ 012CA99E2385A2D3003F810F /* MFView+ModelExtension.swift in Sources */, D29DF25421E6A177003B2FB9 /* MFMdnTextField.m in Sources */, D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */, + 012A88AF238C626E00FE3DA1 /* CarouselModel.swift in Sources */, + 012CA9E023888AC8003F810F /* StackPageTemplateModel.swift in Sources */, D2A514672213885800345BFB /* StandardHeaderView.swift in Sources */, 01EB369023609801006832FA /* ListItemModel.swift in Sources */, DBEFFA04225A829700230692 /* Label.swift in Sources */, @@ -1198,6 +1248,7 @@ D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */, 01EB368F23609801006832FA /* LabelModel.swift in Sources */, 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */, + 012CA9E223888AED003F810F /* StackCenteredPageTemplateModel.swift in Sources */, 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */, D22479962316AF6E003FCCF9 /* HeadlineBodyTextButton.swift in Sources */, D29DF2AE21E7B3A4003B2FB9 /* MFTextView.m in Sources */, @@ -1214,12 +1265,14 @@ D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */, 01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */, D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */, + 012A88B1238C880100FE3DA1 /* PagingMoleculeProtocol.swift in Sources */, D29DF2C921E7BFC6003B2FB9 /* MFSizeObject.m in Sources */, D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */, D2A6390122CBB1820052ED1F /* Carousel.swift in Sources */, D29DF2C721E7BF57003B2FB9 /* MFTabBarInteractor.m in Sources */, D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */, D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */, + 012CA9DE2388723E003F810F /* ListPageTemplateModel.swift in Sources */, D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */, D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */, DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */, @@ -1238,6 +1291,7 @@ D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */, 01EB369323609801006832FA /* HeaderModel.swift in Sources */, D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */, + 012A88C6238DA34000FE3DA1 /* ModuleMoleculeModel.swift in Sources */, D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */, D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */, 943784F6236B77BB006A1E82 /* GraphViewAnimationHandler.swift in Sources */, @@ -1246,6 +1300,7 @@ D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */, D29DF11821E6805F003B2FB9 /* NSLayoutConstraint+MFConvenience.m in Sources */, D29DF26C21E6AA0B003B2FB9 /* FLAnimatedImage.m in Sources */, + 012A889C23889E8400FE3DA1 /* TemplateModelProtocol.swift in Sources */, D29770FC21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m in Sources */, D29DF25121E6A177003B2FB9 /* MFDigitTextBox.m in Sources */, DBC4391B224421A0001AB423 /* CaretButton.swift in Sources */, @@ -1260,6 +1315,7 @@ D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */, D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */, D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */, + 012A88C2238D7BCA00FE3DA1 /* CarouselItemModel.swift in Sources */, D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */, D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */, 01509D8F2327EC6F00EF99AA /* MoleculeTableViewCell.swift in Sources */, diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m index 4983020e..29f2c9be 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView.m +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView.m @@ -352,46 +352,6 @@ } - (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { - // Only treated as a container if we are constraining a molecule. - if (!self.constrainedView) { - [super setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; - } - [self.molecule setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; - if (self.shouldSetupMoleculeFromJSON) { - NSDictionary *moleculeJSON = [json dict:KeyMolecule]; - if (self.molecule) { - [self.molecule setWithJSON:moleculeJSON delegateObject:delegateObject additionalData:additionalData]; - } else if (moleculeJSON) { - UIView *molecule = [[MVMCoreUIMoleculeMappingObject sharedMappingObject] createMoleculeForJSON:moleculeJSON delegateObject:delegateObject constrainIfNeeded:true]; - if (molecule) { - [self addMolecule:molecule]; - } - self.molecule = molecule; - [self setMoleculeAccessibility]; - } - } else { - [self.molecule setWithJSON:json delegateObject:delegateObject additionalData:additionalData]; - } - - NSNumber *useHorizontalMargins = [json optionalNumberForKey:@"useHorizontalMargins"]; - if (useHorizontalMargins) { - self.updateViewHorizontalDefaults = [useHorizontalMargins boolValue]; - } - NSNumber *useVerticalMargins = [json optionalNumberForKey:@"useVerticalMargins"]; - if (useVerticalMargins) { - self.updateViewVerticalDefaults = [useVerticalMargins boolValue]; - } - - // Set the alignment for the stack in the containing view. The json driven value is for the axis direction alignment. - NSString *alignment = [json string:@"horizontalAlignment"]; - if (alignment) { - [self alignHorizontal:[ViewConstrainingView getAlignmentForString:alignment defaultAlignment:UIStackViewAlignmentFill]]; - } - alignment = [json string:@"verticalAlignment"]; - if (alignment) { - [self alignVertical:[ViewConstrainingView getAlignmentForString:alignment defaultAlignment:UIStackViewAlignmentFill]]; - } - if ([self.molecule respondsToSelector:@selector(copyBackgroundColor)] && [self.molecule performSelector:@selector(copyBackgroundColor)]) { self.backgroundColor = self.molecule.backgroundColor; } diff --git a/MVMCoreUI/BaseControllers/MFViewController+Model.swift b/MVMCoreUI/BaseControllers/MFViewController+Model.swift index 924ce4c7..159a3260 100644 --- a/MVMCoreUI/BaseControllers/MFViewController+Model.swift +++ b/MVMCoreUI/BaseControllers/MFViewController+Model.swift @@ -11,16 +11,19 @@ import Foundation public extension MFViewController { @objc func parsePageJSON() { - guard let pageJSON = loadObject?.pageJSON as? [String: AnyHashable] else { - return - } - do { - let pageData = try JSONSerialization.data(withJSONObject: pageJSON) - let decoder = JSONDecoder() - let pageModel = try decoder.decode(PageModel.self, from: pageData) - self.pageModel = pageModel - } catch { - MVMCoreUILoggingHandler.logDebugMessage(withDelegate: "error: \(error)") - } + + (self as? TemplateProtocol)?.parseTemplateJSON() +// guard let pageJSON = loadObject?.pageJSON as? [String: AnyHashable] else { +// return +// } +// do { +// let pageData = try JSONSerialization.data(withJSONObject: pageJSON) +// let decoder = JSONDecoder() +// +// let pageModel = try decoder.decode(PageModel.self, from: pageData) +// self.pageModel = pageModel +// } catch { +// MVMCoreUILoggingHandler.logDebugMessage(withDelegate: "error: \(error)") +// } } } diff --git a/MVMCoreUI/Models/CollectionCellMoleculeProtocol.swift b/MVMCoreUI/Models/CollectionCellMoleculeProtocol.swift new file mode 100644 index 00000000..a6a6d95d --- /dev/null +++ b/MVMCoreUI/Models/CollectionCellMoleculeProtocol.swift @@ -0,0 +1,14 @@ +// +// CollectionCellMoleculeProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/26/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol CollectionCellMoleculeProtocol: MoleculeProtocol { + var peakingUI: Bool? {get} + var peakingArrowColor: String? {get} +} diff --git a/MVMCoreUI/Models/Extensions/ModelHelper.swift b/MVMCoreUI/Models/Extensions/ModelHelper.swift index 661280a9..da5e0d56 100644 --- a/MVMCoreUI/Models/Extensions/ModelHelper.swift +++ b/MVMCoreUI/Models/Extensions/ModelHelper.swift @@ -8,7 +8,7 @@ import Foundation -extension KeyedDecodingContainer where Key : CodingKey{ +extension KeyedDecodingContainer where Key : CodingKey { private enum TypeCodingKey: String, CodingKey { case moleculeName } diff --git a/MVMCoreUI/Models/Molecules/CarouselItemModel.swift b/MVMCoreUI/Models/Molecules/CarouselItemModel.swift new file mode 100644 index 00000000..a2359f03 --- /dev/null +++ b/MVMCoreUI/Models/Molecules/CarouselItemModel.swift @@ -0,0 +1,42 @@ +// +// CarouselItemModel.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/26/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + + +@objcMembers public class CarouselItemModel: MoleculeProtocol { + public static var identifier: String = "carouselItem" + public var moleculeName: String + public var backgroundColor: String? + public var molecule: MoleculeProtocol? + + public init(molecule: MoleculeProtocol?, backgroundColor: String?) { + self.molecule = molecule + self.moleculeName = Self.identifier + self.backgroundColor = backgroundColor + } + enum CodingKeys: String, CodingKey { + case moleculeName + case molecule + case backgroundColor + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + self.moleculeName = try typeContainer.decode(String.self, forKey: .moleculeName) + self.molecule = try typeContainer.decodeIfPresent(codingKey: .molecule) + self.backgroundColor = try typeContainer.decode(String.self, forKey: .backgroundColor) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(backgroundColor, forKey: .backgroundColor) + try container.encodeIfPresent(self.molecule, forKey: .molecule) + } +} diff --git a/MVMCoreUI/Models/Molecules/CarouselModel.swift b/MVMCoreUI/Models/Molecules/CarouselModel.swift new file mode 100644 index 00000000..9fce489a --- /dev/null +++ b/MVMCoreUI/Models/Molecules/CarouselModel.swift @@ -0,0 +1,74 @@ +// +// CarouselModel.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/25/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers public class CarouselModel: MoleculeProtocol { + + public static var identifier: String = "carousel" + public var moleculeName: String + public var molecules: [CarouselItemModel] + + public var spacing: Float? + public var border: Bool? + public var loop: Bool? + public var height: Float? + public var itemWidthPercent: Float? + public var itemAlignment: String? + public var pagingMolecule: PagingMoleculeProtocol? + + public init(molecules: [CarouselItemModel], spacing: Float?, border: Bool?, loop: Bool?, height: Float?, itemWidthPercent: Float?, itemAlignment: String?, pagingMolecule: PagingMoleculeProtocol?){ + self.moleculeName = Self.identifier + self.molecules = molecules + self.spacing = spacing + self.border = border + self.loop = loop + self.height = height + self.itemWidthPercent = itemWidthPercent + self.itemAlignment = itemAlignment + self.pagingMolecule = pagingMolecule + } + + enum CodingKeys: String, CodingKey { + case moleculeName + case molecules + case spacing + case border + case loop + case height + case itemWidthPercent + case itemAlignment + case pagingMolecule + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + self.moleculeName = try typeContainer.decode(String.self, forKey: .moleculeName) + self.molecules = try typeContainer.decode([CarouselItemModel].self, forKey: .molecules) + self.spacing = try typeContainer.decode(Float.self, forKey: .spacing) + self.border = try typeContainer.decode(Bool.self, forKey: .border) + self.loop = try typeContainer.decode(Bool.self, forKey: .loop) + self.height = try typeContainer.decode(Float.self, forKey: .height) + self.itemWidthPercent = try typeContainer.decode(Float.self, forKey: .itemWidthPercent) + self.itemAlignment = try typeContainer.decode(String.self, forKey: .itemAlignment) + self.pagingMolecule = try typeContainer.decodeIfPresent(codingKey: .pagingMolecule) as? PagingMoleculeProtocol + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(molecules, forKey: .molecules) + try container.encode(spacing, forKey: .spacing) + try container.encode(border, forKey: .border) + try container.encode(loop, forKey: .loop) + try container.encode(height, forKey: .height) + try container.encode(itemWidthPercent, forKey: .itemWidthPercent) + try container.encode(itemAlignment, forKey: .itemAlignment) + try container.encodeIfPresent(self.pagingMolecule, forKey: .pagingMolecule) + } +} diff --git a/MVMCoreUI/Models/Molecules/ListItemModel.swift b/MVMCoreUI/Models/Molecules/ListItemModel.swift index a903299a..b2da3db1 100644 --- a/MVMCoreUI/Models/Molecules/ListItemModel.swift +++ b/MVMCoreUI/Models/Molecules/ListItemModel.swift @@ -14,16 +14,26 @@ import Foundation public var molecule: MoleculeProtocol? public var actionMap: ActionMapModel? - public init(molecule: MoleculeProtocol?, actionMap: ActionMapModel?) { + public var hideArrow: Bool? + public var separator: SeperatorModel? + public var style: String? + + public init(molecule: MoleculeProtocol?, actionMap: ActionMapModel?, hideArrow: Bool?, separator: SeperatorModel?, style: String?) { self.molecule = molecule self.actionMap = actionMap self.moleculeName = Self.identifier + self.hideArrow = hideArrow + self.separator = separator + self.style = style } enum CodingKeys: String, CodingKey { case moleculeName case molecule case actionMap + case hideArrow + case separator + case style } required public init(from decoder: Decoder) throws { @@ -31,6 +41,10 @@ import Foundation self.moleculeName = try typeContainer.decode(String.self, forKey: .moleculeName) self.molecule = try typeContainer.decodeIfPresent(codingKey: .molecule) self.actionMap = try typeContainer.decodeIfPresent(ActionMapModel.self, forKey: .actionMap) + + self.hideArrow = try typeContainer.decode(Bool.self, forKey: .hideArrow) + self.separator = try typeContainer.decode(SeperatorModel.self, forKey: .hideArrow) + self.style = try typeContainer.decode(String.self, forKey: .style) } public func encode(to encoder: Encoder) throws { @@ -38,5 +52,9 @@ import Foundation try container.encode(moleculeName, forKey: .moleculeName) try container.encodeIfPresent(self.molecule, forKey: .molecule) try container.encodeIfPresent(actionMap, forKey: .actionMap) + + try container.encodeIfPresent(hideArrow, forKey: .hideArrow) + try container.encodeIfPresent(separator, forKey: .separator) + try container.encodeIfPresent(style, forKey: .style) } } diff --git a/MVMCoreUI/Models/Molecules/ModuleMoleculeModel.swift b/MVMCoreUI/Models/Molecules/ModuleMoleculeModel.swift new file mode 100644 index 00000000..15ce347f --- /dev/null +++ b/MVMCoreUI/Models/Molecules/ModuleMoleculeModel.swift @@ -0,0 +1,14 @@ +// +// ModuleMoleculeModel.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/26/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +class ModuleMoleculeModel: MoleculeProtocol { + public static var identifier: String = "moduleMolecule" + public var moduleName: String +} diff --git a/MVMCoreUI/Models/Molecules/MoleculeStackItemModel.swift b/MVMCoreUI/Models/Molecules/MoleculeStackItemModel.swift index 5bceda3e..9c75b582 100644 --- a/MVMCoreUI/Models/Molecules/MoleculeStackItemModel.swift +++ b/MVMCoreUI/Models/Molecules/MoleculeStackItemModel.swift @@ -10,27 +10,56 @@ import Foundation @objcMembers public class MoleculeStackItemModel: MoleculeProtocol { public static var identifier: String = "stackItem" - public var moleculeName: String? + public var moleculeName: String public var molecule: MoleculeProtocol? - public init(molecule: MoleculeProtocol?) { + public var spacing: CGFloat? + public var percentage: Int? + public var verticalAlignment: String? + public var horizontalAlignment: String? + public var gone = false + + public init(molecule: MoleculeProtocol?, spacing: CGFloat?, percentage: Int?, verticalAlignment: String?, horizontalAlignment: String?, gone: Bool = false) { self.molecule = molecule self.moleculeName = Self.identifier + + self.spacing = spacing + self.percentage = percentage + self.verticalAlignment = verticalAlignment + self.horizontalAlignment = horizontalAlignment + self.gone = gone } enum CodingKeys: String, CodingKey { case moleculeName case molecule + case spacing + case percentage + case verticalAlignment + case horizontalAlignment + case gone } required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) self.moleculeName = try typeContainer.decode(String.self, forKey: .moleculeName) self.molecule = try typeContainer.decodeIfPresent(codingKey: .molecule) + + self.spacing = try typeContainer.decode(CGFloat.self, forKey: .spacing) + self.percentage = try typeContainer.decode(Int.self, forKey: .percentage) + self.verticalAlignment = try typeContainer.decode(String.self, forKey: .verticalAlignment) + self.horizontalAlignment = try typeContainer.decode(String.self, forKey: .horizontalAlignment) + self.gone = try typeContainer.decode(Bool.self, forKey: .gone) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(moleculeName, forKey: .moleculeName) try container.encodeIfPresent(self.molecule, forKey: .molecule) + + try container.encode(spacing, forKey: .spacing) + try container.encode(percentage, forKey: .percentage) + try container.encode(verticalAlignment, forKey: .verticalAlignment) + try container.encode(horizontalAlignment, forKey: .horizontalAlignment) + try container.encode(gone, forKey: .gone) } } diff --git a/MVMCoreUI/Models/Molecules/MoleculeStackModel.swift b/MVMCoreUI/Models/Molecules/MoleculeStackModel.swift index 30c15822..bad35824 100644 --- a/MVMCoreUI/Models/Molecules/MoleculeStackModel.swift +++ b/MVMCoreUI/Models/Molecules/MoleculeStackModel.swift @@ -14,17 +14,20 @@ import Foundation public var moleculeName: String? public var molecules: [MoleculeStackItemModel]? public var axis: String? + public var spacing: Float? - public init(axis: String?, molecules: [MoleculeStackItemModel]?) { + public init(axis: String?, molecules: [MoleculeStackItemModel]?, spacing: Float?) { self.axis = axis self.molecules = molecules self.moleculeName = Self.identifier + self.spacing = spacing } enum CodingKeys: String, CodingKey { case moleculeName case molecules case axis + case spacing } required public init(from decoder: Decoder) throws { @@ -32,6 +35,7 @@ import Foundation self.moleculeName = try typeContainer.decodeIfPresent(String.self, forKey: .moleculeName) self.molecules = try typeContainer.decode([MoleculeStackItemModel].self, forKey: .molecules) self.axis = try typeContainer.decodeIfPresent(String.self, forKey: .axis) + self.spacing = try typeContainer.decodeIfPresent(Float.self, forKey: .spacing) } public func encode(to encoder: Encoder) throws { @@ -39,5 +43,6 @@ import Foundation try container.encode(moleculeName, forKey: .moleculeName) try container.encodeIfPresent(molecules, forKey: .molecules) try container.encode(axis, forKey: .axis) + try container.encode(spacing, forKey: .spacing) } } diff --git a/MVMCoreUI/Models/Molecules/SeperatorModel.swift b/MVMCoreUI/Models/Molecules/SeperatorModel.swift index 705f904c..cdc1cb3c 100644 --- a/MVMCoreUI/Models/Molecules/SeperatorModel.swift +++ b/MVMCoreUI/Models/Molecules/SeperatorModel.swift @@ -8,7 +8,7 @@ import UIKit -class SeperatorModel: MoleculeProtocol { +@objcMembers public class SeperatorModel: MoleculeProtocol { public static var identifier: String = "line" public var type: String? } diff --git a/MVMCoreUI/Models/PagingMoleculeProtocol.swift b/MVMCoreUI/Models/PagingMoleculeProtocol.swift new file mode 100644 index 00000000..af1ce14a --- /dev/null +++ b/MVMCoreUI/Models/PagingMoleculeProtocol.swift @@ -0,0 +1,13 @@ +// +// PagingMoleculeProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/25/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol PagingMoleculeProtocol: MoleculeProtocol { + var position: Float? {get} +} diff --git a/MVMCoreUI/Models/Template/ListPageTemplateModel.swift b/MVMCoreUI/Models/Template/ListPageTemplateModel.swift new file mode 100644 index 00000000..2ad31cdc --- /dev/null +++ b/MVMCoreUI/Models/Template/ListPageTemplateModel.swift @@ -0,0 +1,24 @@ +// +// ListPageTemplate.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/22/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers public class ListPageTemplateModel: TemplateModelProtocol { + + public static var identifier: String = "listTemplate" + + public var pageType: String + + public var screenHeading: String + + public var isAtomicTabs: Bool? + + public var header: MoleculeStackModel? + public var molecules: [ListItemModel]? + public var footer: MoleculeStackModel? +} diff --git a/MVMCoreUI/Models/PageModel.swift b/MVMCoreUI/Models/Template/PageModel.swift similarity index 100% rename from MVMCoreUI/Models/PageModel.swift rename to MVMCoreUI/Models/Template/PageModel.swift diff --git a/MVMCoreUI/Models/Template/StackCenteredPageTemplateModel.swift b/MVMCoreUI/Models/Template/StackCenteredPageTemplateModel.swift new file mode 100644 index 00000000..27eaa362 --- /dev/null +++ b/MVMCoreUI/Models/Template/StackCenteredPageTemplateModel.swift @@ -0,0 +1,21 @@ +// +// StackCenteredPageTemplate.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/22/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers public class StackCenteredPageTemplateModel: TemplateModelProtocol { + + public static var identifier: String = "stackCenterTemplate" + + public var pageType: String + + public var screenHeading: String + + public var isAtomicTabs: Bool? + +} diff --git a/MVMCoreUI/Models/Template/StackPageTemplateModel.swift b/MVMCoreUI/Models/Template/StackPageTemplateModel.swift new file mode 100644 index 00000000..e1030f35 --- /dev/null +++ b/MVMCoreUI/Models/Template/StackPageTemplateModel.swift @@ -0,0 +1,24 @@ +// +// StackPageTemplate.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/22/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + + +@objcMembers public class StackPageTemplateModel: TemplateModelProtocol { + public static var identifier: String = "moleculeStack" + + public var pageType: String + + public var screenHeading: String + + public var isAtomicTabs: Bool? + + public var header: MoleculeStackModel? + public var moleculeStack: MoleculeStackModel? + public var footer: MoleculeStackModel? +} diff --git a/MVMCoreUI/Models/Template/TemplateModelProtocol.swift b/MVMCoreUI/Models/Template/TemplateModelProtocol.swift new file mode 100644 index 00000000..3eeb9673 --- /dev/null +++ b/MVMCoreUI/Models/Template/TemplateModelProtocol.swift @@ -0,0 +1,22 @@ +// +// TemplateModelProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/22/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol TemplateModelProtocol: Model { + var template: String { get } + var pageType: String { get set } + var screenHeading: String { get set } + var isAtomicTabs: Bool? { get set } +} + +extension TemplateModelProtocol { + public var template: String { + get { return Self.identifier } + } +} diff --git a/MVMCoreUI/Models/Template/ThreeLayerPageTemplateModel.swift b/MVMCoreUI/Models/Template/ThreeLayerPageTemplateModel.swift new file mode 100644 index 00000000..658a021f --- /dev/null +++ b/MVMCoreUI/Models/Template/ThreeLayerPageTemplateModel.swift @@ -0,0 +1,24 @@ +// +// ThreeLayerPageTemplateModel.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/22/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers public class ThreeLayerPageTemplateModel: TemplateModelProtocol { + + public static var identifier: String = "threeLayer" + + public var pageType: String + + public var screenHeading: String + + public var isAtomicTabs: Bool? + + public var header: MoleculeStackModel? + public var middle: MoleculeStackModel? + public var footer: MoleculeStackModel? +} diff --git a/MVMCoreUI/Models/TemplateProtocol.swift b/MVMCoreUI/Models/TemplateProtocol.swift new file mode 100644 index 00000000..90e3e635 --- /dev/null +++ b/MVMCoreUI/Models/TemplateProtocol.swift @@ -0,0 +1,29 @@ +// +// ModelTemplateProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/25/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol TemplateProtocol { + var templateModel: TemplateModelProtocol? {get} + func parseTemplateJSON() + func templateData() -> Data? +} + +extension TemplateProtocol where Self: MFViewController { + public func templateData() -> Data? { + guard let pageJSON = loadObject?.pageJSON as? [String: AnyHashable] else { + return nil + } + do { + return try JSONSerialization.data(withJSONObject: pageJSON) + } catch { + MVMCoreUILoggingHandler.logDebugMessage(withDelegate: "error: \(error)") + return nil + } + } +} diff --git a/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift index 75249f7d..bc97be16 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift @@ -8,7 +8,8 @@ import UIKit -open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol { +open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol, ModelMoleculeViewProtocol { + open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)? open var json: [AnyHashable: Any]? @@ -64,47 +65,50 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi peakingRightArrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true NSLayoutConstraint.scalingPinViewRight(toSuper: peakingRightArrow, ratio: ratio, anchor: contentView.widthAnchor) } - - public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - self.json = json - - if let useHorizontalMargins = json?.optionalBoolForKey("useHorizontalMargins") { + + + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + guard let collectionModel = model as? CollectionCellMoleculeProtocol else { + return + } + + if let useHorizontalMargins = collectionModel.useHorizontalMargins { updateViewHorizontalDefaults = useHorizontalMargins } - if let useVerticalMargins = json?.optionalBoolForKey("useVerticalMargins") { + if let useVerticalMargins = collectionModel.useVerticalMargins { updateViewVerticalDefaults = useVerticalMargins } - // Handles peaking. - allowsPeaking = json?.optionalBoolForKey("peakingUI") ?? true - if let peakingArrowColor = json?.optionalStringForKey("peakingArrowColor") { + allowsPeaking = collectionModel.peakingUI ?? false + if let peakingArrowColor = collectionModel.peakingArrowColor { let color = UIColor.mfGet(forHex: peakingArrowColor) peakingLeftArrow.tintColor = color peakingRightArrow.tintColor = color } - - if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) { - backgroundColor = UIColor.mfGet(forHex: backgroundColorString) + + if let backgroundColorString = collectionModel.backgroundColor { + backgroundColor = UIColor.mfGet(forHex: backgroundColorString) } - - guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule) else { + + guard let moleculeModel = collectionModel.molecule else { return } + if molecule == nil { - if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) { + if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(moleculeModel, delegateObject, true) { contentView.insertSubview(moleculeView, at: 0) NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: true).values)) molecule = moleculeView } } else { - molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) + (molecule as? ModelMoleculeViewProtocol)?.setWithModel(moleculeModel, delegateObject, additionalData) } + // This molecule will handle spacing by default. if let castView = molecule as? MVMCoreUIViewConstrainingProtocol { castView.shouldSetHorizontalMargins?(false) castView.shouldSetVerticalMargins?(false) } - accessibilityElements = molecule?.subviews } diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index 4769b7e5..7963b819 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -9,30 +9,27 @@ import UIKit @objcMembers open class MoleculeTableViewCell: TableViewCell { - - // MARK: - MVMCoreUIMoleculeViewProtocol - public override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - - guard molecule == nil, let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule), let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) else { return } + + public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + super.setWithModel(model, delegateObject, additionalData) + + guard let model = model, + let moleculeModel = (model as? ConstrainingMoleculeProtocol)?.molecule, + let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(moleculeModel, delegateObject, true) else { + return + } addMolecule(moleculeView) } - - public override class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) else { - return 80 - } - return max(2 * PaddingDefaultVerticalSpacing3, height) - } - - public override class func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { - guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else { + + public override class func name(forReuse molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> String? { + guard let moleculeModel = molecule?.molecule else { return "\(self)<>" } - let moleculeName = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) ?? "" + let className = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(moleculeModel) as? ModelMoleculeViewProtocol + let moleculeName = (className as? ModelMoleculeViewProtocol.Type)?.name(forReuse: molecule, delegateObject: delegateObject) ?? moleculeModel.moleculeName ?? "" return "\(self)<\(moleculeName)>" } - + public class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let theClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON) else { diff --git a/MVMCoreUI/Molecules/Items/TableViewCell.swift b/MVMCoreUI/Molecules/Items/TableViewCell.swift index cc531d75..7a097b5e 100644 --- a/MVMCoreUI/Molecules/Items/TableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/TableViewCell.swift @@ -8,9 +8,11 @@ import UIKit -@objcMembers open class TableViewCell: UITableViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol { +@objcMembers open class TableViewCell: UITableViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol, ModelMoleculeViewProtocol { + open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)? - open var json: [AnyHashable: Any]? + open var listItemModel: ListItemModel? + open var json: [String: Any]? // In updateView, will set padding to default. open var updateViewHorizontalDefaults = true @@ -136,46 +138,47 @@ import UIKit contentView.insetsLayoutMarginsFromSafeArea = false contentView.preservesSuperviewLayoutMargins = false } - - // MARK: - MVMCoreUIMoleculeViewProtocol - public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - self.json = json - - guard let json = json else { return } - - style(with: json.optionalStringForKey("style")) - - if let useHorizontalMargins = json.optionalBoolForKey("useHorizontalMargins") { + + //TODO: Model, Change to model + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + guard let model = model as? ListItemModel else { + return + } + + self.listItemModel = model + style(with: model.style) + + if let useHorizontalMargins = model.useHorizontalMargins { updateViewHorizontalDefaults = useHorizontalMargins } - - if (json.optionalBoolForKey("useVerticalMargins") ?? true) == false { + + if (model.useVerticalMargins ?? true) == false { topMarginPadding = 0 bottomMarginPadding = 0 } - - if let backgroundColorString = json.optionalStringForKey(KeyBackgroundColor) { + + if let backgroundColorString = model.backgroundColor { backgroundColor = UIColor.mfGet(forHex: backgroundColorString) } - + // Add the caret if there is an action and it's not declared hidden. if !customAccessoryView { - if let _ = json.optionalDictionaryForKey("actionMap"), !json.boolForKey("hideArrow") { + if let _ = model.actionMap, !(model.hideArrow ?? false) { addCaretViewAccessory() } else { accessoryView = nil } } - + // override the separator - if let separator = json.optionalDictionaryForKey("separator") { + if let separator = model.separator { addSeparatorsIfNeeded() - bottomSeparatorView?.setWithJSON(separator, delegateObject: delegateObject, additionalData: additionalData) + (bottomSeparatorView as? ModelMoleculeViewProtocol)?.setWithModel(separator, nil, nil) } - - guard let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { return } - molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) - + + guard let moleculeModel = model.molecule else { return } + (molecule as? ModelMoleculeViewProtocol)?.setWithModel(moleculeModel, delegateObject, additionalData) + // This molecule will by default handle margins. if let castView = molecule as? MVMCoreUIViewConstrainingProtocol { castView.shouldSetHorizontalMargins?(false) @@ -189,18 +192,20 @@ import UIKit styleStandard() backgroundColor = .white } - - public class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) else { + + public static func estimatedHeight(forRow molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + guard let moleculeModel = molecule?.molecule, + let classType = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(moleculeModel) as? ModelMoleculeViewProtocol.Type, + let height = classType.estimatedHeight(forRow: moleculeModel, delegateObject: delegateObject) else { return 80 } return max(2 * PaddingDefaultVerticalSpacing3, height) } - - public class func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { - return molecule?.optionalStringForKey(KeyMoleculeName) ?? "" + + + public class func name(forReuse molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> String? { + return molecule?.moleculeName ?? "" } - // MARK: - Arrow /// Adds the standard mvm style caret to the accessory view @objc public func addCaretViewAccessory() { @@ -247,6 +252,7 @@ import UIKit // MARK: - MoleculeListCellProtocol /// For when the separator between cells shows using json and frequency. Default is type: standard, frequency: allExceptTop. + //TODO: Change to model public func setSeparatorWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, indexPath: IndexPath) { addSeparatorsIfNeeded() if let json = json { @@ -263,7 +269,8 @@ import UIKit } public func didSelectCell(atIndex indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - if let actionMap = json?.optionalDictionaryForKey("actionMap") { + //TODO: Use object when handleAction is rewrote to handle action model + if let actionMap = self.listItemModel?.actionMap?.toJSON() { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) } } diff --git a/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift b/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift index 1a1796cd..b75f4600 100644 --- a/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift @@ -38,12 +38,13 @@ import UIKit } // MARK: - MoleculeDelegateProtocol - public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + + public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + super.setWithModel(model, delegateObject, additionalData) self.delegateObject = delegateObject tabs.reloadData() } - + public override func reset() { super.reset() topMarginPadding = 8 @@ -51,17 +52,21 @@ import UIKit } } +//TODO: Models changes + extension TabsTableViewCell: TopTabbarDelegate { public func shouldSelectItem(at index: Int, topTabbar: TopTabbar) -> Bool { - if let moleculesArrays = json?.arrayForKey(KeyMolecules), let molecules = moleculesArrays[topTabbar.selectedIndex] as? [[AnyHashable: Any]] { + if let moleculesArrays = json?.arrayForKey(KeyMolecules), + let molecules = moleculesArrays[topTabbar.selectedIndex] as? [[AnyHashable: Any]] { delegateObject?.moleculeDelegate?.removeMolecules?(molecules, sender: self, animation: index < tabs.selectedIndex ? .right : .left) } previousTabIndex = tabs.selectedIndex return true } - + public func topTabbar(_ topTabbar: TopTabbar, didSelectItemAt index: Int) { - if let moleculesArrays = json?.arrayForKey(KeyMolecules), let molecules = moleculesArrays[index] as? [[AnyHashable: Any]] { + if let moleculesArrays = json?.arrayForKey(KeyMolecules), + let molecules = moleculesArrays[index] as? [[AnyHashable: Any]] { delegateObject?.moleculeDelegate?.addMolecules?(molecules, sender: self, animation: index < previousTabIndex ? .left : .right) } } @@ -71,7 +76,7 @@ extension TabsTableViewCell: TopTabbarDataSource { public func number(ofTopTabbarItems topTabbar: TopTabbar) -> Int { return json?.optionalDictionaryForKey("tabs")?.optionalArrayForKey("tabs")?.count ?? 0 } - + public func topTabbar(_ topTabbar: TopTabbar, titleForItemAt index: Int) -> String? { guard let tabs = json?.optionalDictionaryForKey("tabs")?.arrayForKey("tabs"), let label = tabs[index] as? [AnyHashable: Any], let title = label.optionalStringForKey(KeyText) else { return "Select" diff --git a/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h b/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h index 2c52324b..e67dc964 100644 --- a/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h +++ b/MVMCoreUI/Molecules/MVMCoreUIMoleculeViewProtocol.h @@ -14,15 +14,10 @@ @protocol MVMCoreUIMoleculeViewProtocol -/// Sets up the ui based on the json -- (void)setWithJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData; - @optional -// optional func setWithModel(_ model: MoleculeProtocol, _ delegateObject: MVMCoreUIDelegateObject, _ additionalData: [String: AnyHashable]) -//Type arguments cannot be applied to non-parameterized class 'NSObject' -//- (void)setWithModel:(nullable NSObject*)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData; - +/// Sets up the ui based on the json +- (void)setWithJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject additionalData:(nullable NSDictionary *)additionalData; /// Called after init to provide an early setter for any molecule specific logic - (void)setAsMolecule; diff --git a/MVMCoreUI/Molecules/ModelMoleculeViewProtocol.swift b/MVMCoreUI/Molecules/ModelMoleculeViewProtocol.swift index 98c1818c..fa1b30a8 100644 --- a/MVMCoreUI/Molecules/ModelMoleculeViewProtocol.swift +++ b/MVMCoreUI/Molecules/ModelMoleculeViewProtocol.swift @@ -10,4 +10,15 @@ import Foundation public protocol ModelMoleculeViewProtocol { func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String: AnyHashable]?) + static func name(forReuse molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> String? + static func estimatedHeight(forRow molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? +} + +extension ModelMoleculeViewProtocol { + public static func name(forReuse molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> String? { + return nil + } + public static func estimatedHeight(forRow molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return nil + } } diff --git a/MVMCoreUI/Molecules/ModuleMolecule.swift b/MVMCoreUI/Molecules/ModuleMolecule.swift index 77acc007..ab252b5e 100644 --- a/MVMCoreUI/Molecules/ModuleMolecule.swift +++ b/MVMCoreUI/Molecules/ModuleMolecule.swift @@ -8,7 +8,7 @@ import UIKit -open class ModuleMolecule: ViewConstrainingView { +open class ModuleMolecule: ViewConstrainingView, ModelMoleculeViewProtocol { open var moduleMolecule: (UIView & MVMCoreUIMoleculeViewProtocol)? @@ -16,33 +16,65 @@ open class ModuleMolecule: ViewConstrainingView { super.updateView(size) moduleMolecule?.updateView(size) } - - // MARK: - MVMCoreUIMoleculeViewProtocol - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - - guard let moduleName = json?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { - // Critical error - return + + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String: AnyHashable]?) { + #warning("This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView.") + //TODO: This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView. + setUpWithModel(model, delegateObject, additionalData) + + guard let moduleMoleculeModel = model as? ModuleMoleculeModel, + let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleMoleculeModel.moduleName) else { + // Critical error + return } - if moduleMolecule == nil { - if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: module, delegateObject: delegateObject, constrainIfNeeded: true) { - addSubview(moleculeView) - NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: false).values)) - moduleMolecule = moleculeView - - isAccessibilityElement = false - if moleculeView.accessibilityElements != nil { - accessibilityElements = moleculeView.accessibilityElements - } else { - accessibilityElements = [moleculeView] - } - } - } else { - moduleMolecule?.setWithJSON(module, delegateObject: delegateObject, additionalData: additionalData) - } +// if moduleMolecule == nil { +// MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(<#T##model: MoleculeProtocol##MoleculeProtocol#>, <#T##delegateObject: MVMCoreUIDelegateObject?##MVMCoreUIDelegateObject?#>, <#T##constrainIfNeeded: Bool##Bool#>) +// if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: module, delegateObject: delegateObject, constrainIfNeeded: true) { +// addSubview(moleculeView) +// NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: false).values)) +// moduleMolecule = moleculeView +// +// isAccessibilityElement = false +// if moleculeView.accessibilityElements != nil { +// accessibilityElements = moleculeView.accessibilityElements +// } else { +// accessibilityElements = [moleculeView] +// } +// } +// } else { +// moduleMolecule?.setWithJSON(module, delegateObject: delegateObject, additionalData: additionalData) +// } + } + +// // MARK: - MVMCoreUIMoleculeViewProtocol +// open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { +// super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) +// +// guard let moduleName = json?.optionalStringForKey("moduleName"), +// let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { +// // Critical error +// return +// } +// +// if moduleMolecule == nil { +// if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: module, delegateObject: delegateObject, constrainIfNeeded: true) { +// addSubview(moleculeView) +// NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: false).values)) +// moduleMolecule = moleculeView +// +// isAccessibilityElement = false +// if moleculeView.accessibilityElements != nil { +// accessibilityElements = moleculeView.accessibilityElements +// } else { +// accessibilityElements = [moleculeView] +// } +// } +// } else { +// moduleMolecule?.setWithJSON(module, delegateObject: delegateObject, additionalData: additionalData) +// } +// } open override func setAsMolecule() { super.setAsMolecule() @@ -55,7 +87,8 @@ open class ModuleMolecule: ViewConstrainingView { } public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - guard let moduleName = json?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { + guard let moduleName = json?.optionalStringForKey("moduleName"), + let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { // Critical error return 0 } @@ -63,7 +96,8 @@ open class ModuleMolecule: ViewConstrainingView { } public override class func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { - guard let moduleName = molecule?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { + guard let moduleName = molecule?.optionalStringForKey("moduleName"), + let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { // Critical error return "moduleMolecule<>" } diff --git a/MVMCoreUI/Molecules/Scroller.swift b/MVMCoreUI/Molecules/Scroller.swift index e4289bc3..7f179a07 100644 --- a/MVMCoreUI/Molecules/Scroller.swift +++ b/MVMCoreUI/Molecules/Scroller.swift @@ -27,19 +27,41 @@ import UIKit constraint.priority = UILayoutPriority(rawValue: 999) constraint.isActive = true } - - open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { + + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + //super.setWithModel(model, delegateObject, additionalData) + #warning("This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView.") + //TODO: This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView. + setUpWithModel(model, delegateObject, additionalData) + + guard let model = model, + let moleculeModel = (model as? ConstrainingMoleculeProtocol)?.molecule else { return } + if molecule == nil { - if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) { + if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(moleculeModel, delegateObject, true) { contentView.addSubview(moleculeView) pinView(toSuperView: moleculeView) molecule = moleculeView } } else { - molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) + (molecule as? ModelMoleculeViewProtocol)?.setWithModel(moleculeModel, delegateObject, additionalData) } } + +// open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { +// guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { +// return +// } +// if molecule == nil { +// if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) { +// contentView.addSubview(moleculeView) +// pinView(toSuperView: moleculeView) +// molecule = moleculeView +// } +// } else { +// molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) +// } +// } } diff --git a/MVMCoreUI/Molecules/StandardHeaderView.swift b/MVMCoreUI/Molecules/StandardHeaderView.swift index 100173fc..32b14bb2 100644 --- a/MVMCoreUI/Molecules/StandardHeaderView.swift +++ b/MVMCoreUI/Molecules/StandardHeaderView.swift @@ -56,7 +56,6 @@ public class StandardHeaderView: ViewConstrainingView, ModelMoleculeViewProtocol } open func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { - //TODO: Need to create setWithModel in ViewConstraining View #warning("This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView.") //TODO: This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView. diff --git a/MVMCoreUI/Organisms/Carousel.swift b/MVMCoreUI/Organisms/Carousel.swift index d0efcce3..116f1135 100644 --- a/MVMCoreUI/Organisms/Carousel.swift +++ b/MVMCoreUI/Organisms/Carousel.swift @@ -8,7 +8,8 @@ import UIKit -open class Carousel: ViewConstrainingView { +open class Carousel: ViewConstrainingView, ModelMoleculeViewProtocol { + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) /// The current index of the collection view. Includes dummy cells when looping. @@ -28,7 +29,7 @@ open class Carousel: ViewConstrainingView { var numberOfPages = 0 /// The json for the molecules. - var molecules: [[AnyHashable: Any]]? + var molecules: [MoleculeProtocol]? /// The horizontal alignment of the cell in the collection view. Only noticeable if the itemWidthPercent is less than 100%. var itemAlignment = UICollectionView.ScrollPosition.left @@ -79,25 +80,37 @@ open class Carousel: ViewConstrainingView { } // MARK: - MVMCoreUIMoleculeViewProtocol - open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + //TODO: Model, Change to model + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + guard let caroselModel = model as? CarouselModel else { + return + } + + #warning("This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView.") + //TODO: This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView. + setUpWithModel(caroselModel, delegateObject, additionalData) + collectionView.backgroundColor = backgroundColor collectionView.layer.borderColor = backgroundColor?.cgColor - collectionView.layer.borderWidth = (json?.boolForKey("border") ?? false) ? 1 : 0 + collectionView.layer.borderWidth = (caroselModel.border ?? false) ? 1 : 0 backgroundColor = .white - registerCells(with: json, delegateObject: delegateObject) - setupLayout(with: json) - prepareMolecules(with: json) - itemWidthPercent = (json?.optionalCGFloatForKey("itemWidthPercent") ?? 100) / 100 - setAlignment(with: json?.optionalStringForKey("itemAlignment")) - if let height = json?.optionalCGFloatForKey("height") { - collectionViewHeight?.constant = height + + registerCells(with: caroselModel, delegateObject: delegateObject) + setupLayout(with: caroselModel) + prepareMolecules(with: caroselModel) + itemWidthPercent = CGFloat((caroselModel.itemWidthPercent ?? 100) / 100) + setAlignment(with: caroselModel.itemAlignment) + + if let height = caroselModel.height { + collectionViewHeight?.constant = CGFloat(height) collectionViewHeight?.isActive = true } - setupPagingMolecule(json: json?.optionalDictionaryForKey("pagingMolecule"), delegateObject: delegateObject) + + setupPagingMolecule(caroselModel.pagingMolecule, delegateObject: delegateObject) collectionView.reloadData() } - + + open override func shouldSetHorizontalMargins(_ shouldSet: Bool) { super.shouldSetHorizontalMargins(shouldSet) updateViewHorizontalDefaults = false @@ -105,24 +118,25 @@ open class Carousel: ViewConstrainingView { // MARK: - JSON Setters /// Updates the layout being used - func setupLayout(with json:[AnyHashable: Any]?) { + + func setupLayout(with carouselModel: CarouselModel?) { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .horizontal - layout.minimumLineSpacing = json?["spacing"] as? CGFloat ?? 1 + layout.minimumLineSpacing = CGFloat(carouselModel?.spacing ?? 1) layout.minimumInteritemSpacing = 0 collectionView.collectionViewLayout = layout } - - func prepareMolecules(with json: [AnyHashable: Any]?) { - guard let newMolecules = json?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] else { + + func prepareMolecules(with carouselModel: CarouselModel?) { + guard let newMolecules = carouselModel?.molecules else { numberOfPages = 0 molecules = nil return } - + numberOfPages = newMolecules.count molecules = newMolecules - if json?.boolForKey("loop") ?? false && newMolecules.count > 2 { + if carouselModel?.loop ?? false && newMolecules.count > 2 { // Sets up the row data with buffer cells on each side (for illusion of endless scroll... also has one more buffer cell on each side in case we can peek that cell). loop = true molecules?.insert(newMolecules.last!, at: 0) @@ -132,36 +146,33 @@ open class Carousel: ViewConstrainingView { } pageIndex = 0 } - + + /// Sets up the paging molecule + open func setupPagingMolecule(_ molecule: PagingMoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) { + var pagingView: (UIView & MVMCoreUIPagingProtocol)? = nil + if let molecule = molecule { + pagingView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(molecule, delegateObject, true) as? (UIView & MVMCoreUIPagingProtocol) + } + addPaging(view: pagingView, position: (CGFloat(molecule?.position ?? 20))) + } + /// Registers the cells with the collection view - func registerCells(with json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) { - if let molecules = json?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] { - for molecule in molecules { - if let info = getMoleculeInfo(with: molecule, delegateObject: delegateObject) { - collectionView.register(info.class, forCellWithReuseIdentifier: info.identifier) - } + func registerCells(with carouselModel: CarouselModel, delegateObject: MVMCoreUIDelegateObject?) { + for molecule in carouselModel.molecules { + if let info = getMoleculeInfo(with: molecule, delegateObject: delegateObject) { + collectionView.register(info.class, forCellWithReuseIdentifier: info.identifier) } } } - - /// Sets up the paging molecule - open func setupPagingMolecule(json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) { - var pagingView: (UIView & MVMCoreUIPagingProtocol)? = nil - if let json = json { - pagingView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: json, delegateObject: delegateObject, constrainIfNeeded: true) as? (UIView & MVMCoreUIPagingProtocol) - } - addPaging(view: pagingView, position: (json?.optionalCGFloatForKey("position") ?? 20)) - } // MARK: - Convenience /// Returns the (identifier, class) of the molecule for the given map. - func getMoleculeInfo(with molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> (identifier: String, class: AnyClass, molecule: [AnyHashable: Any])? { - guard let molecule = molecule, - let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule), - let moleculeName = moleculeClass.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) else { - return nil + func getMoleculeInfo(with molecule: MoleculeProtocol, delegateObject: MVMCoreUIDelegateObject?) -> (identifier: String, class: AnyClass, molecule: MoleculeProtocol)? { + guard let className = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(molecule) , + let moleculeName = (className as? ModelMoleculeViewProtocol.Type)?.name(forReuse: molecule, delegateObject: delegateObject) ?? molecule.moleculeName else { + return nil } - return (moleculeName, moleculeClass, molecule) + return (moleculeName, className, molecule) } /// Sets the alignment from the string. @@ -272,9 +283,9 @@ extension Carousel: UICollectionViewDataSource { return UICollectionViewCell() } let cell = collectionView.dequeueReusableCell(withReuseIdentifier: moleculeInfo.identifier, for: indexPath) - if let protocolCell = cell as? MVMCoreUIMoleculeViewProtocol { + if let protocolCell = cell as? MVMCoreUIMoleculeViewProtocol & ModelMoleculeViewProtocol { protocolCell.reset?() - protocolCell.setWithJSON(moleculeInfo.molecule, delegateObject: nil, additionalData: nil) + protocolCell.setWithModel(moleculeInfo.molecule, nil, nil) protocolCell.updateView(collectionView.bounds.width) } setAccessiblity(cell, index: indexPath.row) diff --git a/MVMCoreUI/Organisms/MoleculeStackView.swift b/MVMCoreUI/Organisms/MoleculeStackView.swift index cafe21b0..c47ca142 100644 --- a/MVMCoreUI/Organisms/MoleculeStackView.swift +++ b/MVMCoreUI/Organisms/MoleculeStackView.swift @@ -20,21 +20,22 @@ public class StackItem { self.view = view } - init(with view: UIView, json: [AnyHashable: Any]?) { + init(with view: UIView, stackItemModel: MoleculeStackItemModel?) { self.view = view - update(with: json) + update(with: stackItemModel) } - func update(with json: [AnyHashable: Any]?) { - gone = json?.boolForKey("gone") ?? (json == nil) - spacing = json?.optionalCGFloatForKey("spacing") - percentage = json?["percent"] as? Int - if let alignment = json?.stringOptionalWithChainOfKeysOrIndexes([KeyMolecule,"verticalAlignment"]) { + func update(with stackItemModel: MoleculeStackItemModel?) { + gone = stackItemModel?.gone ?? false + spacing = stackItemModel?.spacing + percentage = stackItemModel?.percentage + + if let alignment = stackItemModel?.verticalAlignment { verticalAlignment = ViewConstrainingView.getAlignmentFor(alignment, defaultAlignment: .fill) } else { verticalAlignment = nil } - if let alignment = json?.stringOptionalWithChainOfKeysOrIndexes([KeyMolecule,"horizontalAlignment"]) { + if let alignment = stackItemModel?.horizontalAlignment { horizontalAlignment = ViewConstrainingView.getAlignmentFor(alignment, defaultAlignment: .fill) } else { horizontalAlignment = nil @@ -42,10 +43,11 @@ public class StackItem { } } -public class MoleculeStackView: ViewConstrainingView { +public class MoleculeStackView: ViewConstrainingView, ModelMoleculeViewProtocol { var contentView: UIView = MVMCoreUICommonViewsUtility.commonView() var items: [StackItem] = [] var useStackSpacingBeforeFirstItem = false + var moleculeStackModel: MoleculeStackModel? private var moleculesShouldSetHorizontalMargins = false private var moleculesShouldSetVerticalMargins = false @@ -144,44 +146,53 @@ public class MoleculeStackView: ViewConstrainingView { } } } - - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - let previousJSON = self.json - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + + //TODO: Model, Change to model + public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + guard let model = model as? MoleculeStackModel else { + return + } + let previousModel = self.moleculeStackModel + self.moleculeStackModel = model + + #warning("This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView.") + //TODO: This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView. + setUpWithModel(model, delegateObject, additionalData) removeAllItemViews() // If the items in the stack are the same, just update previous items instead of re-allocating. var items: [StackItem]? - if MoleculeStackView.name(forReuse: previousJSON, delegateObject: delegateObject) == MoleculeStackView.name(forReuse: json, delegateObject: delegateObject) { + + if MoleculeStackView.name(forReuse: previousModel, delegateObject: delegateObject) == MoleculeStackView.name(forReuse: model, delegateObject: delegateObject) { items = self.items } self.items = [] - guard let molecules = json?.arrayForKey(KeyMolecules) as? [[String: Any]] else { + guard let molecules = model.molecules else { return } - + // Sets the stack attributes - setAxisWithJSON(json) - spacing = json?.optionalCGFloatForKey("spacing") ?? 16 - - // Adds the molecules and sets the json. - for (index, map) in molecules.enumerated() { - if let moleculeJSON = map.optionalDictionaryForKey(KeyMolecule) { + //setAxisWithJSON(json) + spacing = CGFloat(model.spacing ?? 16) + + for (index, moleculeContainer) in molecules.enumerated() { + if let stackItemModel = moleculeContainer.molecule as? MoleculeStackItemModel { var view: UIView? - if let item = items?[index] { - item.update(with: map) - view = item.view - (view as? MVMCoreUIMoleculeViewProtocol)?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: nil) - addStackItem(item, lastItem: index == molecules.count - 1) - } else if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) { - view = molecule - addStackItem(StackItem(with: molecule, json: map), lastItem: index == molecules.count - 1) - } - (view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(moleculesShouldSetHorizontalMargins) - (view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(moleculesShouldSetVerticalMargins) + if let item = items?[index] { + item.update(with: stackItemModel) + view = item.view + (view as? ModelMoleculeViewProtocol)?.setWithModel(stackItemModel, delegateObject, nil) + addStackItem(item, lastItem: index == molecules.count - 1) + } else if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(stackItemModel, delegateObject, true) { + view = moleculeView + addStackItem(StackItem(with: moleculeView, stackItemModel: stackItemModel), lastItem: index == molecules.count - 1) + } + (view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(moleculesShouldSetHorizontalMargins) + (view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(moleculesShouldSetVerticalMargins) } } + } public override class func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift index 650264fc..0fb7370e 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift @@ -8,9 +8,15 @@ import Foundation - public extension MVMCoreUIMoleculeMappingObject { + func getMoleculeClass(_ model: MoleculeProtocol) -> AnyClass? { + if let moleculeName = model.moleculeName { + return moleculeMapping.object(forKey: moleculeName) as? AnyClass + } + return nil + } + func createMolecule(_ model: MoleculeProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> (UIView & MVMCoreUIMoleculeViewProtocol)? { return createMolecule(model, delegateObject, false) } @@ -25,7 +31,7 @@ public extension MVMCoreUIMoleculeMappingObject { if let molecule = molecule as? ModelMoleculeViewProtocol { molecule.setWithModel(model, delegateObject, nil) } else { - molecule.setWithJSON(model.dictionary, delegateObject: delegateObject, additionalData: nil) + molecule.setWithJSON?(model.dictionary, delegateObject: delegateObject, additionalData: nil) } } diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h index 776566c8..6c1a84b2 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.h @@ -29,10 +29,10 @@ - (nullable UIView *)createMoleculeForName:(nonnull NSString *)name; /// Creates the molecule for the molecule json. -- (nullable UIView *)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject; - -/// Creates the molecule for the molecule json. Also checks if the molecule needs to be constrained for a stack/list style situation. -- (nullable UIView *)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject constrainIfNeeded:(BOOL)constrainIfNeeded; +//- (nullable UIView *)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject; +// +///// Creates the molecule for the molecule json. Also checks if the molecule needs to be constrained for a stack/list style situation. +//- (nullable UIView *)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject constrainIfNeeded:(BOOL)constrainIfNeeded; #pragma mark - Convenience diff --git a/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift b/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift new file mode 100644 index 00000000..2120333e --- /dev/null +++ b/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift @@ -0,0 +1,14 @@ +// +// MoleculeDelegateProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/26/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol ModelMoleculeDelegateProtocol { + func addMolecules(_ molecules: [MoleculeProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) + func removeMolecules(_ molecules: [MoleculeProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) +} diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index e6182bf7..0d645e35 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -8,9 +8,26 @@ import UIKit -open class MoleculeListTemplate: ThreeLayerTableViewController { - public var moleculesInfo: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])]? +open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol, ModelMoleculeDelegateProtocol { + + public var moleculesInfo: [(identifier: String, class: AnyClass, molecule: MoleculeProtocol)]? var observer: NSKeyValueObservation? + + public var templateModel: TemplateModelProtocol? + + public func parseTemplateJSON() { + guard let templateData = templateData() else { + return + } + + do { + let decoder = JSONDecoder() + let templateModel = try decoder.decode(ListPageTemplateModel.self, from: templateData) + self.templateModel = templateModel + } catch { + MVMCoreUILoggingHandler.logDebugMessage(withDelegate: "error: \(error)") + } + } open override var loadObject: MVMCoreLoadObject? { didSet { @@ -27,21 +44,17 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { } open override func viewForTop() -> UIView { -// guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), -// let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { -// return super.viewForTop() -// } - guard let moleculeModel = pageModel?.header, - let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(moleculeModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { - return super.viewForTop() + guard let headerModel = (templateModel as? ListPageTemplateModel)?.header, + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(headerModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { + return super.viewForTop() } return molecule } override open func viewForBottom() -> UIView { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), - let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { - return super.viewForBottom() + guard let footerModel = (templateModel as? ListPageTemplateModel)?.footer, + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(footerModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { + return super.viewForBottom() } return molecule } @@ -64,7 +77,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { open override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { guard let moleculeInfo = moleculesInfo?[indexPath.row], - let estimatedHeight = moleculeInfo.class.estimatedHeight?(forRow: moleculeInfo.molecule, delegateObject: delegateObject() as? MVMCoreUIDelegateObject) else { + let estimatedHeight = (moleculeInfo.class as? ModelMoleculeViewProtocol.Type)?.estimatedHeight(forRow: moleculeInfo.molecule, delegateObject: delegateObject() as? MVMCoreUIDelegateObject) else { return 0 } return estimatedHeight @@ -85,7 +98,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { } if let protocolCell = cell as? MVMCoreUIMoleculeViewProtocol { protocolCell.reset?() - protocolCell.setWithJSON(moleculeInfo.molecule, delegateObject: delegate, additionalData: nil) + (protocolCell as? ModelMoleculeViewProtocol)?.setWithModel(moleculeInfo.molecule, delegate, nil) protocolCell.updateView(tableView.bounds.width) } return cell @@ -126,56 +139,58 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { } } } - - open override func addMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { + + public func addMolecules(_ molecules: [MoleculeProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { // This dispatch is needed to fix a race condition that can occur if this function is called during the table setup. - DispatchQueue.main.async { - guard let indexPath = self.tableView?.indexPath(for: sender) else { return } - var indexPaths: [IndexPath] = [] - for molecule in molecules { - if let info = self.getMoleculeInfo(with: molecule) { - self.tableView?.register(info.class, forCellReuseIdentifier: info.identifier) - let index = indexPath.row + 1 + indexPaths.count - self.moleculesInfo?.insert(info, at: index) - indexPaths.append(IndexPath(row: index, section: 0)) - } - } - self.tableView?.insertRows(at: indexPaths, with: animation) - self.updateViewConstraints() - self.view.layoutIfNeeded() - } + DispatchQueue.main.async { + guard let indexPath = self.tableView?.indexPath(for: sender) else { return } + var indexPaths: [IndexPath] = [] + for molecule in molecules { + if let info = self.getMoleculeInfo(with: molecule) { + self.tableView?.register(info.class, forCellReuseIdentifier: info.identifier) + let index = indexPath.row + 1 + indexPaths.count + self.moleculesInfo?.insert(info, at: index) + indexPaths.append(IndexPath(row: index, section: 0)) + } + } + self.tableView?.insertRows(at: indexPaths, with: animation) + self.updateViewConstraints() + self.view.layoutIfNeeded() + } } - - open override func removeMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { + public func removeMolecules(_ molecules: [MoleculeProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { var indexPaths: [IndexPath] = [] - for molecule in molecules { - if let removeIndex = moleculesInfo?.firstIndex(where: { (moleculeInfo) -> Bool in - return NSDictionary(dictionary: molecule).isEqual(to: moleculeInfo.molecule) - }) { - moleculesInfo?.remove(at: removeIndex) - indexPaths.append(IndexPath(row: removeIndex + indexPaths.count, section: 0)) - } - } + //TODO: cehck for molecule protocola eqality +// for molecule in molecules { +// if let removeIndex = moleculesInfo?.firstIndex(where: { (moleculeInfo) -> Bool in +// return molecule == moleculeInfo.molecule +// }) { +// moleculesInfo?.remove(at: removeIndex) +// indexPaths.append(IndexPath(row: removeIndex + indexPaths.count, section: 0)) +// } +// } self.tableView?.deleteRows(at: indexPaths, with: animation) self.updateViewConstraints() self.view.layoutIfNeeded() } + + // MARK: - Convenience /// Returns the (identifier, class) of the molecule for the given map. - func getMoleculeInfo(with molecule: [AnyHashable: Any]?) -> (identifier: String, class: AnyClass, molecule: [AnyHashable: Any])? { + func getMoleculeInfo(with molecule: MoleculeProtocol?) -> (identifier: String, class: AnyClass, molecule: MoleculeProtocol)? { guard let molecule = molecule, - let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule), - let moleculeName = moleculeClass.name?(forReuse: molecule, delegateObject: delegateObject() as? MVMCoreUIDelegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) else { + let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(molecule), + let moleculeName = (moleculeClass as? ModelMoleculeViewProtocol.Type)?.name(forReuse: molecule, delegateObject: delegateObject() as? MVMCoreUIDelegateObject) ?? molecule.moleculeName else { return nil } return (moleculeName, moleculeClass, molecule) } /// Sets up the molecule list and ensures no errors loading all content. - func getMoleculeInfoList() -> [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])]? { - var moleculeList: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])] = [] - if let molecules = loadObject?.pageJSON?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] { + func getMoleculeInfoList() -> [(identifier: String, class: AnyClass, molecule: MoleculeProtocol)]? { + var moleculeList: [(identifier: String, class: AnyClass, molecule: MoleculeProtocol)] = [] + if let molecules = (templateModel as? ListPageTemplateModel)?.molecules { for molecule in molecules { if let info = getMoleculeInfo(with: molecule) { moleculeList.append(info) @@ -187,8 +202,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { /// Sets up the header, footer, molecule list and ensures no errors loading all content. func setup() { - var moleculeList: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])] = [] - if let molecules = loadObject?.pageJSON?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] { + var moleculeList: [(identifier: String, class: AnyClass, molecule: MoleculeProtocol)] = [] + if let molecules = loadObject?.pageJSON?.optionalArrayForKey(KeyMolecules) as? [MoleculeProtocol] { for molecule in molecules { if let info = getMoleculeInfo(with: molecule) { moleculeList.append(info) diff --git a/MVMCoreUI/Templates/MoleculeStackTemplate.swift b/MVMCoreUI/Templates/MoleculeStackTemplate.swift index dad4d5ef..dacbd2cb 100644 --- a/MVMCoreUI/Templates/MoleculeStackTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeStackTemplate.swift @@ -8,8 +8,24 @@ import UIKit -open class MoleculeStackTemplate: ThreeLayerViewController { +open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol { + var observer: NSKeyValueObservation? + public var templateModel: TemplateModelProtocol? + + public func parseTemplateJSON() { + guard let templateData = templateData() else { + return + } + + do { + let decoder = JSONDecoder() + let templateModel = try decoder.decode(StackPageTemplateModel.self, from: templateData) + self.templateModel = templateModel + } catch { + MVMCoreUILoggingHandler.logDebugMessage(withDelegate: "error: \(error)") + } + } open override var loadObject: MVMCoreLoadObject? { didSet { @@ -30,29 +46,29 @@ open class MoleculeStackTemplate: ThreeLayerViewController { } open override func viewForTop() -> UIView? { - guard let moleculeModel = pageModel?.header, - let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(moleculeModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { - return nil + guard let headerModel = (templateModel as? StackPageTemplateModel)?.header, + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(headerModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { + return nil } -// guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { -// return nil -// } return molecule } open override func viewForMiddle() -> UIView? { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("moleculeStack") else { - return nil + + guard let moleculeStackModel = (templateModel as? StackPageTemplateModel)?.moleculeStack else { + return nil } + let stack = MoleculeStackView(frame: .zero) stack.useStackSpacingBeforeFirstItem = true - stack.setWithJSON(moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, additionalData: nil) + stack.setWithModel(moleculeStackModel, delegateObject() as? MVMCoreUIDelegateObject, nil) return stack } override open func viewForBottom() -> UIView? { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { - return nil + guard let footerModel = (templateModel as? StackPageTemplateModel)?.footer, + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(footerModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { + return nil } return molecule } diff --git a/MVMCoreUI/Templates/ThreeLayerTemplate.swift b/MVMCoreUI/Templates/ThreeLayerTemplate.swift index 20475a6b..f87a1e29 100644 --- a/MVMCoreUI/Templates/ThreeLayerTemplate.swift +++ b/MVMCoreUI/Templates/ThreeLayerTemplate.swift @@ -8,7 +8,23 @@ import UIKit -@objcMembers open class ThreeLayerTemplate: ThreeLayerViewController { +@objcMembers open class ThreeLayerTemplate: ThreeLayerViewController, TemplateProtocol { + + public var templateModel: TemplateModelProtocol? + + public func parseTemplateJSON() { + guard let templateData = templateData() else { + return + } + + do { + let decoder = JSONDecoder() + let templateModel = try decoder.decode(StackPageTemplateModel.self, from: templateData) + self.templateModel = templateModel + } catch { + MVMCoreUILoggingHandler.logDebugMessage(withDelegate: "error: \(error)") + } + } override open func viewDidLoad() { super.viewDidLoad() @@ -20,24 +36,28 @@ import UIKit super.newDataBuildScreen() heightConstraint?.isActive = true } - + + open override func viewForTop() -> UIView? { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { - return nil + guard let headerModel = (templateModel as? ThreeLayerPageTemplateModel)?.header, + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(headerModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { + return nil } return molecule } open override func viewForMiddle() -> UIView? { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("middle"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { - return nil + guard let middleModel = (templateModel as? ThreeLayerPageTemplateModel)?.middle, + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(middleModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { + return nil } return molecule } override open func viewForBottom() -> UIView? { - guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else { - return nil + guard let footerModel = (templateModel as? ThreeLayerPageTemplateModel)?.footer, + let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(footerModel, delegateObject() as? MVMCoreUIDelegateObject, true) else { + return nil } return molecule }