diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 2864d545..18eaaf7b 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -22,7 +22,7 @@ 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 */; }; - 012A88DA238ED42E00FE3DA1 /* StackPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA9DF23888AC8003F810F /* StackPageTemplateModel.swift */; }; + 012A88DA238ED42E00FE3DA1 /* (null) in Sources */ = {isa = PBXBuildFile; }; 012A88DB238ED45900FE3DA1 /* CarouselModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88AE238C626E00FE3DA1 /* CarouselModel.swift */; }; 012A88EC238F084D00FE3DA1 /* FooterModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88EB238F084D00FE3DA1 /* FooterModel.swift */; }; 012A88EE239858E300FE3DA1 /* ContainerMoleculeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88ED239858E300FE3DA1 /* ContainerMoleculeProtocol.swift */; }; @@ -30,9 +30,16 @@ 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 */; }; - 012CA9DE2388723E003F810F /* ListPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA9DD2388723E003F810F /* ListPageTemplateModel.swift */; }; - 012CA9E223888AED003F810F /* StackCenteredPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA9E123888AED003F810F /* StackCenteredPageTemplateModel.swift */; }; - 012CA9E423888B1B003F810F /* ThreeLayerPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA9E323888B1B003F810F /* ThreeLayerPageTemplateModel.swift */; }; + 012CA9DE2388723E003F810F /* (null) in Sources */ = {isa = PBXBuildFile; }; + 012CA9E223888AED003F810F /* (null) in Sources */ = {isa = PBXBuildFile; }; + 012CA9E423888B1B003F810F /* (null) in Sources */ = {isa = PBXBuildFile; }; + 014AA72423C501E2006F3E93 /* MoleculeContainerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014AA72123C501E2006F3E93 /* MoleculeContainerModel.swift */; }; + 014AA72523C501E2006F3E93 /* ContainerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014AA72223C501E2006F3E93 /* ContainerModel.swift */; }; + 014AA72623C501E2006F3E93 /* ContainerModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014AA72323C501E2006F3E93 /* ContainerModelProtocol.swift */; }; + 014AA72D23C5059B006F3E93 /* StackPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014AA72823C5059B006F3E93 /* StackPageTemplateModel.swift */; }; + 014AA72E23C5059B006F3E93 /* StackCenteredPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014AA72923C5059B006F3E93 /* StackCenteredPageTemplateModel.swift */; }; + 014AA72F23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014AA72A23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift */; }; + 014AA73123C5059B006F3E93 /* ListPageTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 014AA72C23C5059B006F3E93 /* ListPageTemplateModel.swift */; }; 01509D8F2327EC6F00EF99AA /* MoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */; }; 01509D912327ECE600EF99AA /* CornerLabels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01509D902327ECE600EF99AA /* CornerLabels.swift */; }; 01509D932327ECFB00EF99AA /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01509D922327ECFB00EF99AA /* ProgressBar.swift */; }; @@ -87,6 +94,7 @@ 94C2D9AB23872EB50006CF46 /* LabelAttributeActionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9AA23872EB50006CF46 /* LabelAttributeActionModel.swift */; }; D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; }; D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; }; + D21EE53C23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */; }; D224798A2314445E003FCCF9 /* LabelSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479892314445E003FCCF9 /* LabelSwitch.swift */; }; D224798C231450C8003FCCF9 /* HeadlineBodySwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D224798B231450C8003FCCF9 /* HeadlineBodySwitch.swift */; }; D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */; }; @@ -285,10 +293,13 @@ 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 = ""; }; - 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 = ""; }; + 014AA72123C501E2006F3E93 /* MoleculeContainerModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeContainerModel.swift; sourceTree = ""; }; + 014AA72223C501E2006F3E93 /* ContainerModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContainerModel.swift; sourceTree = ""; }; + 014AA72323C501E2006F3E93 /* ContainerModelProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContainerModelProtocol.swift; sourceTree = ""; }; + 014AA72823C5059B006F3E93 /* StackPageTemplateModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackPageTemplateModel.swift; sourceTree = ""; }; + 014AA72923C5059B006F3E93 /* StackCenteredPageTemplateModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackCenteredPageTemplateModel.swift; sourceTree = ""; }; + 014AA72A23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThreeLayerPageTemplateModel.swift; sourceTree = ""; }; + 014AA72C23C5059B006F3E93 /* ListPageTemplateModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListPageTemplateModel.swift; sourceTree = ""; }; 01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeTableViewCell.swift; sourceTree = ""; }; 01509D902327ECE600EF99AA /* CornerLabels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CornerLabels.swift; sourceTree = ""; }; 01509D922327ECFB00EF99AA /* ProgressBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; @@ -343,6 +354,7 @@ 94C2D9AA23872EB50006CF46 /* LabelAttributeActionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeActionModel.swift; sourceTree = ""; }; D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = ""; }; D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; + D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSLayoutConstraintAxis+Extension.swift"; sourceTree = ""; }; D22479892314445E003FCCF9 /* LabelSwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelSwitch.swift; sourceTree = ""; }; D224798B231450C8003FCCF9 /* HeadlineBodySwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodySwitch.swift; sourceTree = ""; }; D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutConstraintExtension.swift; sourceTree = ""; }; @@ -553,10 +565,6 @@ 012A889A238898C600FE3DA1 /* Template */ = { isa = PBXGroup; children = ( - 012CA9DD2388723E003F810F /* ListPageTemplateModel.swift */, - 012CA9DF23888AC8003F810F /* StackPageTemplateModel.swift */, - 012CA9E123888AED003F810F /* StackCenteredPageTemplateModel.swift */, - 012CA9E323888B1B003F810F /* ThreeLayerPageTemplateModel.swift */, ); path = Template; sourceTree = ""; @@ -569,9 +577,32 @@ path = "Primitive Models"; sourceTree = ""; }; + 014AA72023C501E2006F3E93 /* Container */ = { + isa = PBXGroup; + children = ( + 014AA72123C501E2006F3E93 /* MoleculeContainerModel.swift */, + 014AA72223C501E2006F3E93 /* ContainerModel.swift */, + 014AA72323C501E2006F3E93 /* ContainerModelProtocol.swift */, + ); + path = Container; + sourceTree = ""; + }; + 014AA72723C5059B006F3E93 /* Template */ = { + isa = PBXGroup; + children = ( + 014AA72823C5059B006F3E93 /* StackPageTemplateModel.swift */, + 014AA72923C5059B006F3E93 /* StackCenteredPageTemplateModel.swift */, + 014AA72A23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift */, + 014AA72C23C5059B006F3E93 /* ListPageTemplateModel.swift */, + ); + path = Template; + sourceTree = ""; + }; 01509D96232803B200EF99AA /* Models */ = { isa = PBXGroup; children = ( + 014AA72723C5059B006F3E93 /* Template */, + 014AA72023C501E2006F3E93 /* Container */, 011B58EE23A2AA850085F53C /* ModelProtocols */, 012A88EF23985E0100FE3DA1 /* Primitive Models */, 012A889A238898C600FE3DA1 /* Template */, @@ -932,6 +963,7 @@ D29DF2A821E7B2F9003B2FB9 /* MVMCoreUIConstants.m */, 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */, 0A209CD223A7E2810068F8B0 /* UIStackViewAlignment+Extension.swift */, + D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */, ); path = Utility; sourceTree = ""; @@ -1299,7 +1331,7 @@ buildActionMask = 2147483647; files = ( 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */, - 012CA9E423888B1B003F810F /* ThreeLayerPageTemplateModel.swift in Sources */, + 012CA9E423888B1B003F810F /* (null) in Sources */, 9402C35023A2CEA3004B974C /* LeftRightLabelModel.swift in Sources */, D29DF32121ED0CBA003B2FB9 /* LabelView.m in Sources */, DBC4391822442197001AB423 /* CaretView.swift in Sources */, @@ -1340,19 +1372,23 @@ D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */, D29DF12E21E6851E003B2FB9 /* MVMCoreUITopAlertView.m in Sources */, D29DF2CF21E7C104003B2FB9 /* MFLoadingViewController.m in Sources */, + 014AA72F23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift in Sources */, D22D1F572204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m in Sources */, 01DF567021FA5AB300CC099B /* TextFieldListFormViewController.swift in Sources */, D2A5145F2211DDC100345BFB /* MoleculeStackView.swift in Sources */, D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */, D29DF24D21E6A177003B2FB9 /* MFTextField.m in Sources */, + 014AA72D23C5059B006F3E93 /* StackPageTemplateModel.swift in Sources */, 012A88C4238D86E600FE3DA1 /* CollectionCellMoleculeProtocol.swift in Sources */, 0189255C239AA7EB004E8AFF /* ModuleDelegateProtocol.swift in Sources */, 94C2D9AB23872EB50006CF46 /* LabelAttributeActionModel.swift in Sources */, + 014AA73123C5059B006F3E93 /* ListPageTemplateModel.swift in Sources */, 017BEB4023620A230024EF95 /* TextFieldModel.swift in Sources */, D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */, D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */, 94C2D9A723872DA90006CF46 /* LabelAttributeColorModel.swift in Sources */, D2755D7B23689C7500485468 /* TableViewCell.swift in Sources */, + 014AA72623C501E2006F3E93 /* ContainerModelProtocol.swift in Sources */, 01EB369223609801006832FA /* MoleculeStackModel.swift in Sources */, 012CA99E2385A2D3003F810F /* MFView+ModelExtension.swift in Sources */, D29DF25421E6A177003B2FB9 /* MFMdnTextField.m in Sources */, @@ -1371,6 +1407,7 @@ D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */, D2B18B812360945C00A9AEDC /* View.swift in Sources */, D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */, + 014AA72523C501E2006F3E93 /* ContainerModel.swift in Sources */, D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */, D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */, 012A88EE239858E300FE3DA1 /* ContainerMoleculeProtocol.swift in Sources */, @@ -1379,8 +1416,8 @@ D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */, 01EB368F23609801006832FA /* LabelModel.swift in Sources */, 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */, - 012CA9E223888AED003F810F /* StackCenteredPageTemplateModel.swift in Sources */, - 012A88DA238ED42E00FE3DA1 /* StackPageTemplateModel.swift in Sources */, + 012CA9E223888AED003F810F /* (null) in Sources */, + 012A88DA238ED42E00FE3DA1 /* (null) in Sources */, 01F2A03223A4498200D954D8 /* CaretButtonModel.swift in Sources */, 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */, 011B58F023A2AA980085F53C /* ListItemModelProtocol.swift in Sources */, @@ -1395,6 +1432,7 @@ 017BEB7F23676E870024EF95 /* MoleculeObjectMapping.swift in Sources */, D274CA332236A78900B01B62 /* StandardFooterView.swift in Sources */, D29DF2BF21E7BEA4003B2FB9 /* MVMCoreUITabBarPageControlViewController.m in Sources */, + 014AA72423C501E2006F3E93 /* MoleculeContainerModel.swift in Sources */, D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */, 011B58F223A2AE2C0085F53C /* DropDownListItemModel.swift in Sources */, 94C2D9842386F3F80006CF46 /* LabelAttributeModel.swift in Sources */, @@ -1411,7 +1449,7 @@ D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */, D2FB151B23A2B65B00C20E10 /* MoleculeContainer.swift in Sources */, D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */, - 012CA9DE2388723E003F810F /* ListPageTemplateModel.swift in Sources */, + 012CA9DE2388723E003F810F /* (null) in Sources */, D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */, D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */, DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */, @@ -1459,11 +1497,13 @@ 0A1214A022C11A18007C7030 /* ActionDetailWithImage.swift in Sources */, D2B18B922361E65A00A9AEDC /* CoreUIObject.swift in Sources */, D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */, + 014AA72E23C5059B006F3E93 /* StackCenteredPageTemplateModel.swift in Sources */, D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */, D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */, 012A88C2238D7BCA00FE3DA1 /* CarouselItemModel.swift in Sources */, D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */, D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */, + D21EE53C23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift in Sources */, 01509D8F2327EC6F00EF99AA /* MoleculeTableViewCell.swift in Sources */, 0105618D224BBE7700E1557D /* FormValidator.swift in Sources */, 01509D912327ECE600EF99AA /* CornerLabels.swift in Sources */, diff --git a/MVMCoreUI/Atoms/Views/MFView+ModelExtension.swift b/MVMCoreUI/Atoms/Views/MFView+ModelExtension.swift index 44973370..bfeb7312 100644 --- a/MVMCoreUI/Atoms/Views/MFView+ModelExtension.swift +++ b/MVMCoreUI/Atoms/Views/MFView+ModelExtension.swift @@ -16,6 +16,7 @@ extension MFView { } } } + extension ModelMoleculeViewProtocol where Self: MFView { func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String: AnyHashable]?) { setUpDefaultWithModel(model, delegateObject, additionalData) diff --git a/MVMCoreUI/Atoms/Views/ViewConstrainingView+ModelExtension.swift b/MVMCoreUI/Atoms/Views/ViewConstrainingView+ModelExtension.swift index 181a187d..bd6312f2 100644 --- a/MVMCoreUI/Atoms/Views/ViewConstrainingView+ModelExtension.swift +++ b/MVMCoreUI/Atoms/Views/ViewConstrainingView+ModelExtension.swift @@ -8,7 +8,6 @@ import Foundation - extension ViewConstrainingView { public func setUpWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String: AnyHashable]?) { if self.constrainedView == nil { @@ -30,7 +29,7 @@ extension ViewConstrainingView { (molecule as? ModelMoleculeViewProtocol)?.setWithModel(model, delegateObject, additionalData) } - if let containerMoleculeModel = model as? ContainerMoleculeProtocol { + if let containerMoleculeModel = model as? ContainerModelProtocol { if let useHorizontalMargins = containerMoleculeModel.useHorizontalMargins { updateViewHorizontalDefaults = useHorizontalMargins } @@ -39,10 +38,10 @@ extension ViewConstrainingView { } if let horizontalAlignment = containerMoleculeModel.horizontalAlignment { - alignHorizontal(ViewConstrainingView.getAlignmentFor(horizontalAlignment, defaultAlignment: .fill)) + alignHorizontal(horizontalAlignment) } if let verticalAlignment = containerMoleculeModel.verticalAlignment { - alignVertical(ViewConstrainingView.getAlignmentFor(verticalAlignment, defaultAlignment: .fill)) + alignVertical(verticalAlignment) } } diff --git a/MVMCoreUI/BaseClasses/View.swift b/MVMCoreUI/BaseClasses/View.swift index ec029b96..8ae6dfa7 100644 --- a/MVMCoreUI/BaseClasses/View.swift +++ b/MVMCoreUI/BaseClasses/View.swift @@ -36,6 +36,10 @@ import UIKit } } + public func nameForReuse(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { + return model?.moleculeName + } + open func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { self.model = model if let backgroundColorString = model?.backgroundColor { @@ -71,4 +75,3 @@ extension View: MVMCoreUIMoleculeViewProtocol { } } - diff --git a/MVMCoreUI/Containers/Container.swift b/MVMCoreUI/Containers/Container.swift index e2b4e723..f1998aac 100644 --- a/MVMCoreUI/Containers/Container.swift +++ b/MVMCoreUI/Containers/Container.swift @@ -8,13 +8,6 @@ import UIKit -public protocol ContainerModelProtocol { - var horizontalAlignment: UIStackView.Alignment? { get set } - var verticalAlignment: UIStackView.Alignment? { get set } - var useHorizontalMargins: Bool? { get set } - var useVerticalMargins: Bool? { get set } -} - public class ContainerHelper: NSObject { var leftConstraint: NSLayoutConstraint? var topConstraint: NSLayoutConstraint? @@ -145,15 +138,6 @@ public class ContainerHelper: NSObject { } } - func set(with model: ContainerModelProtocol) { - if let horizontalAlignment = model.horizontalAlignment { - alignHorizontal(horizontalAlignment) - } - if let verticalAlignment = model.verticalAlignment { - alignVertical(verticalAlignment) - } - } - static func getAlignment(for string: String) -> UIStackView.Alignment? { switch string { case "leading": @@ -169,6 +153,34 @@ public class ContainerHelper: NSObject { } } + static func getAlignmentString(for alignment: UIStackView.Alignment?) -> String? { + switch alignment { + case .leading: + return "leading" + case .trailing: + return "trailing" + case .center: + return "center" + case .fill: + return "fill" + default: + return nil + } + } + + func updateViewMargins(_ view: UIView, model: ContainerModelProtocol?, size: CGFloat) { + MFStyler.setMarginsFor(view, size: size, defaultHorizontal: model?.useHorizontalMargins ?? false, top: (model?.useVerticalMargins ?? false) ? (model?.topMarginPadding ?? 0) : 0, bottom: (model?.useVerticalMargins ?? false) ? (model?.bottomMarginPadding ?? 0) : 0) + } + + func set(with model: ContainerModelProtocol) { + if let horizontalAlignment = model.horizontalAlignment { + alignHorizontal(horizontalAlignment) + } + if let verticalAlignment = model.verticalAlignment { + alignVertical(verticalAlignment) + } + } + func set(with JSON: [AnyHashable: Any]?, for contained: UIView) { if let horizontalAlignmentString = JSON?.optionalStringForKey("horizontalAlignment"), let alignment = ContainerHelper.getAlignment(for: horizontalAlignmentString) ?? (contained as? MVMCoreUIViewConstrainingProtocol)?.horizontalAlignment?() { alignHorizontal(alignment) @@ -185,12 +197,17 @@ public class ContainerHelper: NSObject { } open class Container: View { - var containerModel: ContainerModelProtocol? var view: UIView? let containerHelper = ContainerHelper() + var containerModel: ContainerModelProtocol? { + get { return model as? ContainerModelProtocol } + } - var topMarginPadding: CGFloat = 0 - var bottomMarginPadding: CGFloat = 0 + override open func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + super.setWithModel(model, delegateObject, additionalData) + guard let containerModel = model as? ContainerModelProtocol else { return } + containerHelper.set(with: containerModel) + } } // MARK: - MVMCoreViewProtocol @@ -198,7 +215,7 @@ public extension Container { override func updateView(_ size: CGFloat) { super.updateView(size) (view as? MVMCoreViewProtocol)?.updateView(size) - MFStyler.setMarginsFor(self, size: size, defaultHorizontal: containerModel?.useHorizontalMargins ?? true, top: containerModel?.useHorizontalMargins ?? true ? topMarginPadding : 0, bottom: containerModel?.useHorizontalMargins ?? true ? bottomMarginPadding : 0) + containerHelper.updateViewMargins(self, model: containerModel, size: size) } /// Will be called only once. diff --git a/MVMCoreUI/Models/Container/ContainerModel.swift b/MVMCoreUI/Models/Container/ContainerModel.swift new file mode 100644 index 00000000..9930ab5c --- /dev/null +++ b/MVMCoreUI/Models/Container/ContainerModel.swift @@ -0,0 +1,54 @@ +// +// ContainerModel.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 12/4/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class ContainerModel: ContainerModelProtocol, Codable { + public var horizontalAlignment: UIStackView.Alignment? + public var verticalAlignment: UIStackView.Alignment? + public var useHorizontalMargins: Bool? + + public var useVerticalMargins: Bool? + public var topMarginPadding: CGFloat? + public var bottomMarginPadding: CGFloat? + + enum CodingKeys: String, CodingKey { + case verticalAlignment + case horizontalAlignment + case useHorizontalMargins + case useVerticalMargins + case topMarginPadding + case bottomMarginPadding + } + + public init() {} + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + if let verticalAlignmentString = try typeContainer.decodeIfPresent(String.self, forKey: .verticalAlignment) { + verticalAlignment = ContainerHelper.getAlignment(for: verticalAlignmentString) + } + if let horizontalAlignmentString = try typeContainer.decodeIfPresent(String.self, forKey: .horizontalAlignment) { + horizontalAlignment = ContainerHelper.getAlignment(for: horizontalAlignmentString) + } + useHorizontalMargins = try typeContainer.decodeIfPresent(Bool.self, forKey: .useHorizontalMargins) + useVerticalMargins = try typeContainer.decodeIfPresent(Bool.self, forKey: .useVerticalMargins) + topMarginPadding = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .topMarginPadding) + bottomMarginPadding = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .bottomMarginPadding) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(ContainerHelper.getAlignmentString(for: verticalAlignment), forKey: .verticalAlignment) + try container.encodeIfPresent(ContainerHelper.getAlignmentString(for: horizontalAlignment), forKey: .horizontalAlignment) + try container.encodeIfPresent(useHorizontalMargins, forKey: .useHorizontalMargins) + try container.encodeIfPresent(useVerticalMargins, forKey: .useVerticalMargins) + try container.encodeIfPresent(topMarginPadding, forKey: .topMarginPadding) + try container.encodeIfPresent(bottomMarginPadding, forKey: .bottomMarginPadding) + } +} diff --git a/MVMCoreUI/Models/Container/ContainerModelProtocol.swift b/MVMCoreUI/Models/Container/ContainerModelProtocol.swift new file mode 100644 index 00000000..304a4811 --- /dev/null +++ b/MVMCoreUI/Models/Container/ContainerModelProtocol.swift @@ -0,0 +1,19 @@ +// +// ContainerModelProtocol.swift +// MVMCoreUI +// +// Created by Suresh, Kamlesh on 11/20/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol ContainerModelProtocol { + var horizontalAlignment: UIStackView.Alignment? { get set } + var verticalAlignment: UIStackView.Alignment? { get set } + var useHorizontalMargins: Bool? { get set } + + var useVerticalMargins: Bool? { get set } + var topMarginPadding: CGFloat? { get set } + var bottomMarginPadding: CGFloat? { get set } +} diff --git a/MVMCoreUI/Models/Container/MoleculeContainerModel.swift b/MVMCoreUI/Models/Container/MoleculeContainerModel.swift new file mode 100644 index 00000000..c29fcd2a --- /dev/null +++ b/MVMCoreUI/Models/Container/MoleculeContainerModel.swift @@ -0,0 +1,34 @@ +// +// MoleculeContainerModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 1/6/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class MoleculeContainerModel: ContainerModel { + public var molecule: MoleculeProtocol + + enum MoleculeContainerCodingKeys: String, CodingKey { + case molecule + } + + public init(with moleculeModel: MoleculeProtocol) { + molecule = moleculeModel + super.init() + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: MoleculeContainerCodingKeys.self) + molecule = try typeContainer.decodeMolecule(codingKey: .molecule) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: MoleculeContainerCodingKeys.self) + try container.encodeModel(molecule, forKey: .molecule) + } +} diff --git a/MVMCoreUI/Models/Extensions/ModelHelper.swift b/MVMCoreUI/Models/Extensions/ModelHelper.swift index 66ed89ab..7c73f264 100644 --- a/MVMCoreUI/Models/Extensions/ModelHelper.swift +++ b/MVMCoreUI/Models/Extensions/ModelHelper.swift @@ -13,14 +13,17 @@ extension KeyedDecodingContainer where Key : CodingKey { case moleculeName } + /// Decodes the molecule model with the given coding key based on moleculeName public func decodeMolecule(codingKey: KeyedDecodingContainer.Key) throws -> MoleculeProtocol { return try decodeModel(codingKey: codingKey, typeCodingKey: TypeCodingKey.moleculeName) } + /// Decodes the molecule model with the given coding key based on moleculeName, optional public func decodeMoleculeIfPresent(codingKey: KeyedDecodingContainer.Key) throws -> MoleculeProtocol? { return try decodeModelIfPresent(codingKey: codingKey, typeCodingKey: TypeCodingKey.moleculeName) } + /// Decodes the list of molecule models with the given coding key based on moleculeName public func decodeMolecules(codingKey: KeyedDecodingContainer.Key) throws -> [MoleculeProtocol] { guard let models = try decodeModels(codingKey: codingKey, typeCodingKey: TypeCodingKey.moleculeName) as? [MoleculeProtocol] else { throw ModelRegistry.Error.decoderError @@ -28,7 +31,8 @@ extension KeyedDecodingContainer where Key : CodingKey { return models } - public func decodeArrayIfPresent(codingKey: KeyedDecodingContainer.Key) throws -> [MoleculeProtocol]? { + /// Decodes the list of molecule models with the given coding key based on moleculeName, optional + public func decodeMoleculesIfPresent(codingKey: KeyedDecodingContainer.Key) throws -> [MoleculeProtocol]? { return try decodeModelsIfPresent(codingKey: codingKey, typeCodingKey: TypeCodingKey.moleculeName) as? [MoleculeProtocol] } } diff --git a/MVMCoreUI/Models/Molecules/HeaderModel.swift b/MVMCoreUI/Models/Molecules/HeaderModel.swift index 63ff20fa..c28d7080 100644 --- a/MVMCoreUI/Models/Molecules/HeaderModel.swift +++ b/MVMCoreUI/Models/Molecules/HeaderModel.swift @@ -8,37 +8,36 @@ import Foundation -@objcMembers public class HeaderModel: ContainerMoleculeProtocol { +@objcMembers public class HeaderModel: MoleculeContainerModel, MoleculeProtocol { public static var identifier: String = "header" public var moleculeName: String? public var backgroundColor: String? - public var molecule: MoleculeProtocol - public var seperator: LineModel? - - public init(molecule: MoleculeProtocol){ - self.molecule = molecule - } + public var line: LineModel? - enum CodingKeys: String, CodingKey { + enum HeaderCodingKeys: String, CodingKey { case moleculeName - case molecule - case backgroundColor - case separator + case line } 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.backgroundColor = try typeContainer.decodeIfPresent(String.self, forKey: .backgroundColor) - self.molecule = try typeContainer.decodeMolecule(codingKey: .molecule) - self.seperator = try typeContainer.decodeIfPresent(LineModel.self, forKey: .separator) + try super.init(from: decoder) + let typeContainer = try decoder.container(keyedBy: HeaderCodingKeys.self) + moleculeName = try typeContainer.decode(String.self, forKey: .moleculeName) + line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) + + // Default Values + if topMarginPadding == nil { + topMarginPadding = PaddingDefaultVerticalSpacing + } + if bottomMarginPadding == nil { + bottomMarginPadding = PaddingDefaultVerticalSpacing + } } - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: HeaderCodingKeys.self) try container.encode(moleculeName, forKey: .moleculeName) - try container.encodeModelIfPresent(molecule, forKey: .molecule) - try container.encodeIfPresent(self.backgroundColor, forKey: .backgroundColor) - try container.encodeIfPresent(self.seperator, forKey: .separator) + try container.encode(line, forKey: .line) } } diff --git a/MVMCoreUI/Models/Molecules/ListItemModel.swift b/MVMCoreUI/Models/Molecules/ListItemModel.swift index 70dcf379..80263c9f 100644 --- a/MVMCoreUI/Models/Molecules/ListItemModel.swift +++ b/MVMCoreUI/Models/Molecules/ListItemModel.swift @@ -8,33 +8,30 @@ import Foundation -@objcMembers public class ListItemModel: MoleculeProtocol { +@objcMembers public class ListItemModel: MoleculeContainerModel, MoleculeProtocol { public static var identifier: String = "listItem" - public var molecule: MoleculeProtocol? public var backgroundColor: String? public var action: ActionModel? + public var line: LineModel? - public init(molecule: MoleculeProtocol?, actionMap: ActionModel?) { - self.molecule = molecule - self.action = actionMap - } - - enum CodingKeys: String, CodingKey { + enum ListItemCodingKeys: String, CodingKey { case moleculeName - case molecule case action + case line } required public init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - self.molecule = try typeContainer.decodeMoleculeIfPresent(codingKey: .molecule) + try super.init(from: decoder) + let typeContainer = try decoder.container(keyedBy: ListItemCodingKeys.self) self.action = try typeContainer.decodeIfPresent(ActionModel.self, forKey: .action) + line = try typeContainer.decodeIfPresent(LineModel.self, forKey: .line) } - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: ListItemCodingKeys.self) try container.encode(moleculeName, forKey: .moleculeName) - try container.encodeModelIfPresent(self.molecule, forKey: .molecule) try container.encodeIfPresent(action, forKey: .action) + try container.encodeIfPresent(line, forKey: .line) } } diff --git a/MVMCoreUI/Models/Molecules/ModuleMoleculeModel.swift b/MVMCoreUI/Models/Molecules/ModuleMoleculeModel.swift index 9b7ebf01..6e170b03 100644 --- a/MVMCoreUI/Models/Molecules/ModuleMoleculeModel.swift +++ b/MVMCoreUI/Models/Molecules/ModuleMoleculeModel.swift @@ -8,8 +8,22 @@ import Foundation -public class ModuleMoleculeModel: MoleculeProtocol { +open class ModuleMoleculeModel: MoleculeProtocol { + public var backgroundColor: String? public static var identifier: String = "moduleMolecule" public var moduleName: String - public var backgroundColor: String? + + enum CodingKeys: String, CodingKey { + case moduleName + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + moduleName = try typeContainer.decode(String.self, forKey:.moduleName) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moduleName, forKey: .moduleName) + } } diff --git a/MVMCoreUI/Models/Molecules/MoleculeStackItemModel.swift b/MVMCoreUI/Models/Molecules/MoleculeStackItemModel.swift index 70402061..a0e7825c 100644 --- a/MVMCoreUI/Models/Molecules/MoleculeStackItemModel.swift +++ b/MVMCoreUI/Models/Molecules/MoleculeStackItemModel.swift @@ -8,61 +8,38 @@ import Foundation -@objcMembers public class MoleculeStackItemModel: MoleculeProtocol { +@objcMembers public class MoleculeStackItemModel: MoleculeContainerModel, MoleculeProtocol { public static var identifier: String = "stackItem" - - public var molecule: MoleculeProtocol? public var backgroundColor: String? - public var spacing: CGFloat? - public var percentage: Int? - public var verticalAlignment: String? - public var horizontalAlignment: String? - public var gone: Bool? - public var useHorizontalMargins: Bool? - public var useVerticalMargins: Bool? - - public init(molecule: MoleculeProtocol) { - self.molecule = molecule - } - - enum CodingKeys: String, CodingKey { - case moleculeName - case molecule - case backgroundColor + public var percentage: Int? = 0 + public var gone: Bool = false + + enum MoleculeStackItemCodingKeys: String, CodingKey { case spacing case percentage - case verticalAlignment - case horizontalAlignment case gone - case useHorizontalMargins - case useVerticalMargins - } - - required public init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - self.molecule = try typeContainer.decodeMoleculeIfPresent(codingKey: .molecule) - self.backgroundColor = try typeContainer.decodeIfPresent(String.self, forKey: .backgroundColor) - - self.spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing) - self.percentage = try typeContainer.decodeIfPresent(Int.self, forKey: .percentage) - self.verticalAlignment = try typeContainer.decodeIfPresent(String.self, forKey: .verticalAlignment) - self.horizontalAlignment = try typeContainer.decodeIfPresent(String.self, forKey: .horizontalAlignment) - self.gone = try typeContainer.decodeIfPresent(Bool.self, forKey: .gone) - self.useHorizontalMargins = try typeContainer.decodeIfPresent(Bool.self, forKey: .useHorizontalMargins) - self.useVerticalMargins = try typeContainer.decodeIfPresent(Bool.self, forKey: .useVerticalMargins) } - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(moleculeName, forKey: .moleculeName) - try container.encodeModelIfPresent(self.molecule, forKey: .molecule) + public override init(with moleculeModel: MoleculeProtocol) { + super.init(with: moleculeModel) + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: MoleculeStackItemCodingKeys.self) + spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing) + percentage = try typeContainer.decodeIfPresent(Int.self, forKey: .percentage) + if let gone = try typeContainer.decodeIfPresent(Bool.self, forKey: .gone) { + self.gone = gone + } + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: MoleculeStackItemCodingKeys.self) try container.encodeIfPresent(spacing, forKey: .spacing) try container.encodeIfPresent(percentage, forKey: .percentage) - try container.encodeIfPresent(verticalAlignment, forKey: .verticalAlignment) - try container.encodeIfPresent(horizontalAlignment, forKey: .horizontalAlignment) - try container.encodeIfPresent(gone, forKey: .gone) - try container.encodeIfPresent(useHorizontalMargins, forKey: .useHorizontalMargins) - try container.encodeIfPresent(useVerticalMargins, forKey: .useVerticalMargins) + try container.encode(gone, forKey: .gone) } } diff --git a/MVMCoreUI/Models/Molecules/MoleculeStackModel.swift b/MVMCoreUI/Models/Molecules/MoleculeStackModel.swift index b50e1ae6..530c7393 100644 --- a/MVMCoreUI/Models/Molecules/MoleculeStackModel.swift +++ b/MVMCoreUI/Models/Molecules/MoleculeStackModel.swift @@ -8,36 +8,43 @@ import Foundation -@objcMembers public class MoleculeStackModel: MoleculeProtocol { - +@objcMembers public class MoleculeStackModel: ContainerModel, MoleculeProtocol { public static var identifier: String = "moleculeStack" public var backgroundColor: String? - public var molecules: [MoleculeStackItemModel]? - public var axis: String? - public var spacing: Float? + public var molecules: [MoleculeStackItemModel] + public var axis: NSLayoutConstraint.Axis = .vertical + public var spacing: CGFloat = 16.0 - enum CodingKeys: String, CodingKey { + public init(molecules: [MoleculeStackItemModel]) { + self.molecules = molecules + super.init() + } + + enum StackCodingKeys: String, CodingKey { case moleculeName case molecules case axis case spacing - case backgroundColor } required public init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - molecules = try typeContainer.decodeIfPresent([MoleculeStackItemModel].self, forKey: .molecules) - axis = try typeContainer.decodeIfPresent(String.self, forKey: .axis) - spacing = try typeContainer.decodeIfPresent(Float.self, forKey: .spacing) - backgroundColor = try typeContainer.decodeIfPresent(String.self, forKey: .backgroundColor) + let typeContainer = try decoder.container(keyedBy: StackCodingKeys.self) + molecules = try typeContainer.decodeMolecules(codingKey: .molecules) as! [MoleculeStackItemModel] + if let axisString = try typeContainer.decodeIfPresent(String.self, forKey: .axis), let optionalAxis = NSLayoutConstraint.Axis(rawValue: axisString) { + axis = optionalAxis + } + if let spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing) { + self.spacing = spacing + } + try super.init(from: decoder) } - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encodeIfPresent(moleculeName, forKey: .moleculeName) + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: StackCodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) try container.encodeIfPresent(molecules, forKey: .molecules) - try container.encodeIfPresent(axis, forKey: .axis) + try container.encodeIfPresent(axis.rawValueString, forKey: .axis) try container.encodeIfPresent(spacing, forKey: .spacing) - try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) } } diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index 96841596..9bfab3f3 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -27,7 +27,7 @@ import UIKit return "\(self)<>" } let className = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(moleculeModel) as? ModelMoleculeViewProtocol - let moleculeName = (className as? ModelMoleculeViewProtocol.Type)?.name(forReuse: molecule, delegateObject: delegateObject) ?? moleculeModel.moleculeName ?? "" + let moleculeName = className?.nameForReuse(molecule, delegateObject) ?? moleculeModel.moleculeName ?? "" return "\(self)<\(moleculeName)>" } diff --git a/MVMCoreUI/Molecules/Items/StackItem.swift b/MVMCoreUI/Molecules/Items/StackItem.swift index bc79428e..e121a1ee 100644 --- a/MVMCoreUI/Molecules/Items/StackItem.swift +++ b/MVMCoreUI/Molecules/Items/StackItem.swift @@ -8,47 +8,8 @@ import UIKit -open class StackItemView: MoleculeContainer { -} - -open class StackItemModel: ContainerModelProtocol { - public var view: StackItemView - public var spacing: CGFloat? - public var percentage: Int? - public var verticalAlignment: UIStackView.Alignment? - public var horizontalAlignment: UIStackView.Alignment? - public var useHorizontalMargins: Bool? = false - public var useVerticalMargins: Bool? = false - public var gone = false - - init(with view: StackItemView) { - self.view = view - view.containerModel = self - } - - init(with view: StackItemView, stackItemModel: MoleculeStackItemModel?) { - self.view = view - update(with: stackItemModel) - } - - func update(with stackItemModel: MoleculeStackItemModel?) { - gone = stackItemModel?.gone ?? false - spacing = stackItemModel?.spacing - percentage = stackItemModel?.percentage - - if let alignment = stackItemModel?.verticalAlignment { - verticalAlignment = ContainerHelper.getAlignment(for: alignment) - } else { - verticalAlignment = nil - } - if let alignment = stackItemModel?.horizontalAlignment { - horizontalAlignment = ContainerHelper.getAlignment(for: alignment) - } else { - horizontalAlignment = nil - } - useHorizontalMargins = stackItemModel?.useHorizontalMargins ?? false - useVerticalMargins = stackItemModel?.useVerticalMargins ?? false +open class StackItem: MoleculeContainer { + var stackItemModel: MoleculeStackItemModel? { + get { return model as? MoleculeStackItemModel } } } - - diff --git a/MVMCoreUI/Molecules/ModelMoleculeViewProtocol.swift b/MVMCoreUI/Molecules/ModelMoleculeViewProtocol.swift index fa1b30a8..0d9f2906 100644 --- a/MVMCoreUI/Molecules/ModelMoleculeViewProtocol.swift +++ b/MVMCoreUI/Molecules/ModelMoleculeViewProtocol.swift @@ -10,12 +10,12 @@ import Foundation public protocol ModelMoleculeViewProtocol { func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String: AnyHashable]?) - static func name(forReuse molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> String? + func nameForReuse(_ model: 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? { + public func nameForReuse(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { return nil } public static func estimatedHeight(forRow molecule: MoleculeProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { diff --git a/MVMCoreUI/Molecules/ModuleMolecule.swift b/MVMCoreUI/Molecules/ModuleMolecule.swift index b05585c4..fa82cb89 100644 --- a/MVMCoreUI/Molecules/ModuleMolecule.swift +++ b/MVMCoreUI/Molecules/ModuleMolecule.swift @@ -8,26 +8,20 @@ import UIKit -//struct ModuleMoleculeModel: ContainerModelProtocol { -// var horizontalAlignment: UIStackView.Alignment? = .fill -// var verticalAlignment: UIStackView.Alignment? = .fill -// var useHorizontalMargins: Bool? = false -// var useVerticalMargins: Bool? = false -//} +open class ModuleMolecule: Container { -open class ModuleMolecule: ViewConstrainingView, ModelMoleculeViewProtocol { - open var moduleMolecule: (UIView & MVMCoreUIMoleculeViewProtocol & ModelMoleculeViewProtocol)? - + var moduleMoleculeModel: ModuleMoleculeModel? { + get { return model as? ModuleMoleculeModel } + } + public override func setupView() { super.setupView() - //containerModel = ModuleMoleculeModel() } - - public func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String: AnyHashable]?) { + + public override 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 moduleModel = delegateObject?.moduleProtocol?.getModuleWithName(moduleMoleculeModel.moduleName) as? MoleculeProtocol else { @@ -53,33 +47,36 @@ open class ModuleMolecule: ViewConstrainingView, ModelMoleculeViewProtocol { } } - 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 { - // Critical error - return 0 - } - return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.estimatedHeight?(forRow: module, delegateObject: delegateObject) ?? 0 - } + #warning("Kamlesh: uncomment below code") + //TODO: Kamlesh: uncomment below code - 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 { - // Critical error - return "moduleMolecule<>" - } - return "moduleMolecule<" + (MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.name?(forReuse: module, delegateObject: delegateObject) ?? module.stringForkey(KeyMoleculeName)) + ">" - } - - public override class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { - let moduleName = json?.optionalStringForKey("moduleName") - if moduleName == nil || delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) == nil { - if let errorObject = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess), code: CoreUIErrorCode.ErrorCodeModuleMolecule.rawValue, domain: ErrorDomainNative, location: String(describing: self)) { - error?.pointee = errorObject - MVMCoreUILoggingHandler.shared()?.addError(toLog: errorObject) - } - } - if let moduleName = moduleName { - return [moduleName] - } - return nil - } +// 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 { +// // Critical error +// return 0 +// } +// return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.estimatedHeight?(forRow: module, delegateObject: delegateObject) ?? 0 +// } +// +// 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 { +// // Critical error +// return "moduleMolecule<>" +// } +// return "moduleMolecule<" + (MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.name?(forReuse: module, delegateObject: delegateObject) ?? module.stringForkey(KeyMoleculeName)) + ">" +// } +// +// public override class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { +// let moduleName = json?.optionalStringForKey("moduleName") +// if moduleName == nil || delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) == nil { +// if let errorObject = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess), code: CoreUIErrorCode.ErrorCodeModuleMolecule.rawValue, domain: ErrorDomainNative, location: String(describing: self)) { +// error?.pointee = errorObject +// MVMCoreUILoggingHandler.shared()?.addError(toLog: errorObject) +// } +// } +// if let moduleName = moduleName { +// return [moduleName] +// } +// return nil +// } } diff --git a/MVMCoreUI/Molecules/MoleculeContainer.swift b/MVMCoreUI/Molecules/MoleculeContainer.swift index 56ae491d..ed8555fb 100644 --- a/MVMCoreUI/Molecules/MoleculeContainer.swift +++ b/MVMCoreUI/Molecules/MoleculeContainer.swift @@ -24,4 +24,17 @@ open class MoleculeContainer: Container { } super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) } + + public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + if let casteModel = model as? MoleculeContainerModel { + if view != nil { + (view as? ModelMoleculeViewProtocol)?.setWithModel(casteModel.molecule, delegateObject, additionalData) + } else { + if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(casteModel.molecule, delegateObject) { + addAndContain(molecule) + } + } + } + super.setWithModel(model, delegateObject, additionalData) + } } diff --git a/MVMCoreUI/Molecules/StandardFooterView.swift b/MVMCoreUI/Molecules/StandardFooterView.swift index a83611cc..e433ec88 100644 --- a/MVMCoreUI/Molecules/StandardFooterView.swift +++ b/MVMCoreUI/Molecules/StandardFooterView.swift @@ -9,22 +9,10 @@ import UIKit open class StandardFooterView: MoleculeContainer { - open override func setupView() { - super.setupView() - topMarginPadding = PaddingDefaultVerticalSpacing - bottomMarginPadding = PaddingDefaultVerticalSpacing - } - public class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { if let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) { return height + PaddingDefaultVerticalSpacing + PaddingDefaultVerticalSpacing } return 42 } - - open override func reset() { - super.reset() - topMarginPadding = PaddingDefaultVerticalSpacing - bottomMarginPadding = PaddingDefaultVerticalSpacing - } } diff --git a/MVMCoreUI/Molecules/StandardHeaderView.swift b/MVMCoreUI/Molecules/StandardHeaderView.swift index bbf6e44e..686aac3b 100644 --- a/MVMCoreUI/Molecules/StandardHeaderView.swift +++ b/MVMCoreUI/Molecules/StandardHeaderView.swift @@ -11,6 +11,10 @@ import UIKit public class StandardHeaderView: MoleculeContainer { var line: Line? + var headerModel: HeaderModel? { + get { return model as? HeaderModel } + } + // MARK: - MVMCoreViewProtocol open override func updateView(_ size: CGFloat) { super.updateView(size) @@ -19,8 +23,6 @@ public class StandardHeaderView: MoleculeContainer { public override func setupView() { super.setupView() - topMarginPadding = PaddingDefaultVerticalSpacing - bottomMarginPadding = PaddingDefaultVerticalSpacing guard line == nil else { return } let line = Line() @@ -41,30 +43,20 @@ public class StandardHeaderView: MoleculeContainer { } open override 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) -// -// // This molecule will by default handle margins. -// (molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(false) -// (molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(false) + super.setWithModel(model, delegateObject, additionalData) guard let headerModel = model as? HeaderModel else { return } - if let seperatorModel = headerModel.seperator as? LineModel { + if let seperatorModel = headerModel.line { line?.setWithJSON(seperatorModel.toJSON(), delegateObject: delegateObject, additionalData: additionalData) } } - open override func reset() { super.reset() line?.style = .heavy - topMarginPadding = PaddingDefaultVerticalSpacing - bottomMarginPadding = PaddingDefaultVerticalSpacing } public class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift index 0cd5a235..975c4851 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift @@ -8,12 +8,25 @@ import UIKit +struct EyebrowHeadlineBodyLinkModel: MoleculeProtocol { + static var identifier: String = "eyebrowHeadlineBodyLink" + var backgroundColor: String? + + public var eyeBrow: LabelModel? + public var headline: LabelModel? + public var body: LabelModel? + public var link: LineModel? +} + @objcMembers open class EyebrowHeadlineBodyLink: ViewConstrainingView { let stack = MoleculeStackView(frame: .zero) let eyebrow = Label.commonLabelB3(true) let headline = Label.commonLabelB1(true) let body = Label.commonLabelB2(true) let link = MFTextButton(nil, constrainHeight: false, forWidth: MVMCoreUIUtility.getWidth()) + var casteModel: EyebrowHeadlineBodyLinkModel? { + get { return model as? EyebrowHeadlineBodyLinkModel } + } // MARK: - MFViewProtocol open override func setupView() { @@ -21,17 +34,21 @@ import UIKit guard stack.superview == nil else { return } - stack.spacing = 0 - addSubview(stack) - pinView(toSuperView: stack) - stack.addStackItem(StackItemModel(with: StackItemView(andContain: eyebrow)), lastItem: false) - stack.addStackItem(StackItemModel(with: StackItemView(andContain: headline)), lastItem: false) - stack.addStackItem(StackItemModel(with: StackItemView(andContain: body)), lastItem: false) + let eyebrowStackItem = MoleculeStackItemModel(with: casteModel!.eyeBrow!) + let headlineStackItem = MoleculeStackItemModel(with: casteModel!.headline!) + let bodyStackItem = MoleculeStackItemModel(with: casteModel!.body!) + let linkStackItem = MoleculeStackItemModel(with: casteModel!.link!) // To visually take into account the extra padding in the intrinsic content of a button. - let stackItem = StackItemModel(with: StackItemView(andContain: link)) - stackItem.spacing = -6 - stack.addStackItem(stackItem, lastItem: true) + linkStackItem.spacing = -6 + + let stackModel = MoleculeStackModel(molecules: [eyebrowStackItem,headlineStackItem,bodyStackItem,linkStackItem]) + stackModel.spacing = 0 + stack.model = stackModel + stack.stackItems = [StackItem(andContain: eyebrow),StackItem(andContain: headline),StackItem(andContain: body),StackItem(andContain: link)] + + addSubview(stack) + pinView(toSuperView: stack) } open override func updateView(_ size: CGFloat) { @@ -42,7 +59,7 @@ import UIKit // MARK: - MVMCoreUIMoleculeViewProtocol open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - eyebrow.setWithJSON(json?.optionalDictionaryForKey("eyebrow"), delegateObject: delegateObject, additionalData: additionalData) + /* eyebrow.setWithJSON(json?.optionalDictionaryForKey("eyebrow"), delegateObject: delegateObject, additionalData: additionalData) stack.stackItems[0].gone = !eyebrow.hasText headline.setWithJSON(json?.optionalDictionaryForKey("headline"), delegateObject: delegateObject, additionalData: additionalData) stack.stackItems[1].gone = !headline.hasText @@ -50,13 +67,13 @@ import UIKit stack.stackItems[2].gone = !body.hasText link.setWithJSON(json?.optionalDictionaryForKey("link"), delegateObject: delegateObject, additionalData: additionalData) stack.stackItems[3].gone = link.titleLabel?.text?.count ?? 0 == 0 - stack.restack() + stack.restack()*/ } open override func reset() { super.reset() stack.reset() - stack.spacing = 0 + stack.stackModel?.spacing = 0 eyebrow.styleB3(true) headline.styleB1(true) body.styleB2(true) diff --git a/MVMCoreUI/Organisms/Carousel.swift b/MVMCoreUI/Organisms/Carousel.swift index 3adba7a7..50ca800a 100644 --- a/MVMCoreUI/Organisms/Carousel.swift +++ b/MVMCoreUI/Organisms/Carousel.swift @@ -169,7 +169,7 @@ open class Carousel: ViewConstrainingView, ModelMoleculeViewProtocol { /// Returns the (identifier, class) of the molecule for the given map. 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 { + let moleculeName = (className as? ModelMoleculeViewProtocol)?.nameForReuse(molecule, delegateObject) ?? molecule.moleculeName else { return nil } return (moleculeName, className, molecule) diff --git a/MVMCoreUI/Organisms/MoleculeStackView.swift b/MVMCoreUI/Organisms/MoleculeStackView.swift index 30de32a8..eb0317cd 100644 --- a/MVMCoreUI/Organisms/MoleculeStackView.swift +++ b/MVMCoreUI/Organisms/MoleculeStackView.swift @@ -10,41 +10,16 @@ import UIKit open class MoleculeStackView: Container { var contentView: UIView = MVMCoreUICommonViewsUtility.commonView() - var stackItems: [StackItemModel] = [] var useStackSpacingBeforeFirstItem = false - var moleculeStackModel: MoleculeStackModel? + var stackModel: MoleculeStackModel? { + get { return model as? MoleculeStackModel } + } + var stackItems: [StackItem] = [] var moleculesShouldSetHorizontalMargins = false var moleculesShouldSetVerticalMargins = false - - /// For setting the direction of the stack - var axis: NSLayoutConstraint.Axis = .vertical { - didSet { - if axis != oldValue { - restack() - } - } - } - - /// The spacing to use between each item in the stack. - var spacing: CGFloat = 16 { - didSet { - if spacing != oldValue { - restack() - } - } - } // MARK: - Helpers - public func setAxisWithJSON(_ json: [AnyHashable: Any]?) { - switch json?.optionalStringForKey("axis") { - case "horizontal": - axis = .horizontal - default: - axis = .vertical - } - } - public func pinView(_ view: UIView, toView: UIView, attribute: NSLayoutConstraint.Attribute, relation: NSLayoutConstraint.Relation, priority: UILayoutPriority, constant: CGFloat) { let constraint = NSLayoutConstraint(item: view, attribute: attribute, relatedBy: relation, toItem: toView, attribute: attribute, multiplier: 1.0, constant: constant) constraint.priority = priority @@ -53,13 +28,21 @@ open class MoleculeStackView: Container { /// Restacks the existing items. func restack() { - setWithStackItems(stackItems) + removeAllItemViews() + let stackItems = self.stackItems + self.stackItems = [] + let lastItem = stackItems.last(where: { (item) -> Bool in + return !item.stackItemModel!.gone + }) + for item in stackItems { + addStackItem(item, lastItem: item === lastItem) + } } /// Removes all stack items views from the view. func removeAllItemViews() { for item in stackItems { - item.view.removeFromSuperview() + item.removeFromSuperview() } } @@ -101,7 +84,7 @@ open class MoleculeStackView: Container { directionalLayoutMargins.leading = 0 directionalLayoutMargins.trailing = 0 for item in stackItems { - item.view.updateView(size) + item.updateView(size) } } @@ -110,62 +93,57 @@ open class MoleculeStackView: Container { super.reset() backgroundColor = .clear for item in stackItems { - item.view.reset() + item.reset() } } - - //TODO: Model, Change to model + public override 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) + let previousModel = stackModel + super.setWithModel(model, delegateObject, additionalData) removeAllItemViews() - - // If the items in the stack are the same, just update previous items instead of re-allocating. - var items: [StackItemModel]? - - if let previousModel = previousModel { - let previoudReuseName = MoleculeStackView.name(forReuse: previousModel, delegateObject: delegateObject) - let currentReuseName = MoleculeStackView.name(forReuse: model, delegateObject: delegateObject) - if previoudReuseName == currentReuseName { - items = self.stackItems + + // If the items in the stack are different, clear them, create new ones. + if (previousModel == nil) || nameForReuse(previousModel, delegateObject) != nameForReuse(model, delegateObject) { + stackItems = [] + createStackItemsFromModel(with: delegateObject) + } else if let models = stackModel?.molecules { + for (index, element) in models.enumerated() { + stackItems[index].setWithModel(element, delegateObject, additionalData) } } - - self.stackItems = [] - - guard let molecules = model.molecules else { - return + + restack() + stackModel?.useHorizontalMargins = moleculesShouldSetHorizontalMargins + stackModel?.useVerticalMargins = moleculesShouldSetVerticalMargins + } + + public override func nameForReuse(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { + // This will aggregate names of molecules to make an id. + guard let model = model as? MoleculeStackModel else { + return "stack<>" } - - // Sets the stack attributes - //setAxisWithJSON(json) - spacing = CGFloat(model.spacing ?? 16) - - for (index, stackItemModel) in molecules.enumerated() { - if let moleculeModel = stackItemModel.molecule { - var view: UIView? - if let item = items?[index] { - item.update(with: stackItemModel) - view = item.view - (view as? ModelMoleculeViewProtocol)?.setWithModel(moleculeModel, delegateObject, nil) - addStackItem(item, lastItem: index == molecules.count - 1) - } else if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(moleculeModel, delegateObject, true) as? StackItemView { - view = moleculeView - addStackItem(StackItemModel(with: moleculeView, stackItemModel: stackItemModel), lastItem: index == molecules.count - 1) - } - (view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(moleculesShouldSetHorizontalMargins) - (view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(moleculesShouldSetVerticalMargins) + var name = "stack<" + for case let item in model.molecules { + if let moleculeName = item.molecule.moleculeName { + if let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping[moleculeName] as? ModelMoleculeViewProtocol, let nameForReuse = moleculeClass.nameForReuse(item.molecule, delegateObject) { + name.append(nameForReuse + ",") + } else { + name.append(moleculeName + ",") + } } - - stackItemModel.useHorizontalMargins = moleculesShouldSetHorizontalMargins - stackItemModel.useVerticalMargins = moleculesShouldSetVerticalMargins + } + name.append(">") + return name + } + + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + if model == nil { + let data = try! JSONSerialization.data(withJSONObject: json!) + let decoder = JSONDecoder() + let model = try! decoder.decode(MoleculeStackModel.self, from: data) + setWithModel(model, delegateObject, additionalData as? [String : AnyHashable]) + } else { + setWithModel(model, delegateObject, additionalData as? [String : AnyHashable]) } } @@ -221,79 +199,76 @@ open class MoleculeStackView: Container { } // MARK: - Adding to stack - /// Adds the view to the stack. - func addView(_ view: UIView, lastItem: Bool) { - addStackItem(StackItemModel(with: StackItemView(andContain: view)), lastItem: lastItem) + /// Creates all of the stackItems for the stackItemModels + func createStackItemsFromModel(with delegate: MVMCoreUIDelegateObject?) { + guard let stackItemModels = stackModel?.molecules else { return } + for model in stackItemModels { + if let stackItem = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(model, delegate) as? StackItem { + stackItems.append(stackItem) + } + } } - /// Adds the stack item to the stack. - func addStackItem(_ stackItem: StackItemModel, lastItem: Bool) { - guard !stackItem.gone else { - stackItems.append(stackItem) + /// Adds the view to the stack. + func addView(_ view: View, lastItem: Bool) { + guard let model = view.model else { return } + let stackItem = StackItem(andContain: view) + stackItem.model = MoleculeStackItemModel(with: model) + addStackItem(stackItem, lastItem: lastItem) + } + + /// Adds the stack item view + private func addStackItem(_ stackItem: StackItem, lastItem: Bool) { + let stackModel = self.stackModel! + let model = stackItem.stackItemModel! + guard !model.gone else { + // Gone views do not show return } - let view = stackItem.view - contentView.addSubview(view) - view.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(stackItem) + stackItem.translatesAutoresizingMaskIntoConstraints = false - let spacing = stackItem.spacing ?? self.spacing - if let view = view as? MVMCoreUIViewConstrainingProtocol { - let verticalAlignment = stackItem.verticalAlignment ?? (stackItem.percentage == nil && axis == .vertical ? .fill : (axis == .vertical ? .leading : .center)) - let horizontalAlignment = stackItem.horizontalAlignment ?? view.alignment?() ?? (axis == .vertical || stackItem.percentage == nil ? .fill : .leading) - view.alignHorizontal?(horizontalAlignment) - view.alignVertical?(verticalAlignment) - } - let first = stackItems.first { !$0.gone } == nil - if axis == .vertical { + let spacing = model.spacing ?? stackModel.spacing + let verticalAlignment = model.verticalAlignment ?? (stackItem.view as? MVMCoreUIViewConstrainingProtocol)?.verticalAlignment?() ?? (model.percentage == nil && stackModel.axis == .vertical ? .fill : (stackModel.axis == .vertical ? .leading : .center)) + let horizontalAlignment = model.horizontalAlignment ?? (stackItem.view as? MVMCoreUIViewConstrainingProtocol)?.horizontalAlignment?() ?? (stackModel.axis == .vertical || model.percentage == nil ? .fill : .leading) + stackItem.containerHelper.alignHorizontal(horizontalAlignment) + stackItem.containerHelper.alignVertical(verticalAlignment) + + let first = stackItems.first { !($0.stackItemModel?.gone ?? false) } == nil + if stackModel.axis == .vertical { if first { - pinView(view, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: useStackSpacingBeforeFirstItem ? spacing : stackItem.spacing ?? 0) - } else if let previousView = stackItems.last(where: { stackItem in - return !stackItem.gone - })?.view { - view.topAnchor.constraint(equalTo: previousView.bottomAnchor, constant: spacing).isActive = true + pinView(stackItem, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: useStackSpacingBeforeFirstItem ? spacing : model.spacing ?? 0) + } else if let previousView = stackItems.last(where: { item in + return !item.stackItemModel!.gone + }) { + stackItem.topAnchor.constraint(equalTo: previousView.bottomAnchor, constant: spacing).isActive = true } - pinView(view, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: 0) - pinView(contentView, toView: view, attribute: .trailing, relation: .equal, priority: .required, constant: 0) - if let percent = stackItem.percentage { - view.heightAnchor.constraint(equalTo: contentView.heightAnchor, multiplier: CGFloat(percent)/100.0).isActive = true + pinView(stackItem, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: 0) + pinView(contentView, toView: stackItem, attribute: .trailing, relation: .equal, priority: .required, constant: 0) + if let percent = model.percentage { + stackItem.heightAnchor.constraint(equalTo: contentView.heightAnchor, multiplier: CGFloat(percent)/100.0).isActive = true } if lastItem { - pinView(contentView, toView: view, attribute: .bottom, relation: .equal, priority: .required, constant: 0) + pinView(contentView, toView: stackItem, attribute: .bottom, relation: .equal, priority: .required, constant: 0) } } else { if first { // First horizontal item has no spacing by default unless told otherwise. - pinView(view, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: useStackSpacingBeforeFirstItem ? spacing : stackItem.spacing ?? 0) - } else if let previousView = stackItems.last(where: { stackItem in - return !stackItem.gone - })?.view { - view.leftAnchor.constraint(equalTo: previousView.rightAnchor, constant: spacing).isActive = true + pinView(stackItem, toView: contentView, attribute: .leading, relation: .equal, priority: .required, constant: useStackSpacingBeforeFirstItem ? spacing : model.spacing ?? 0) + } else if let previousView = stackItems.last(where: { item in + return !item.stackItemModel!.gone + }) { + stackItem.leftAnchor.constraint(equalTo: previousView.rightAnchor, constant: spacing).isActive = true } - pinView(view, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: 0) - pinView(contentView, toView: view, attribute: .bottom, relation: .equal, priority: .required, constant: 0) - if let percent = stackItem.percentage { - view.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: CGFloat(percent)/100.0).isActive = true + pinView(stackItem, toView: contentView, attribute: .top, relation: .equal, priority: .required, constant: 0) + pinView(contentView, toView: stackItem, attribute: .bottom, relation: .equal, priority: .required, constant: 0) + if let percent = model.percentage { + stackItem.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: CGFloat(percent)/100.0).isActive = true + } + if lastItem { + pinView(contentView, toView: stackItem, attribute: .right, relation: .equal, priority: .required, constant: 0) } - } - if lastItem { - pinView(contentView, toView: view, attribute: .right, relation: .equal, priority: .required, constant: 0) } stackItems.append(stackItem) } - - func setWithStackItems(_ items: [StackItemModel]) { - removeAllItemViews() - stackItems.removeAll() - var previousPresentItem: StackItemModel? = nil - for item in items { - if !item.gone { - previousPresentItem = item - } - addStackItem(item, lastItem: false) - } - if let lastView = previousPresentItem?.view { - let attribute: NSLayoutConstraint.Attribute = axis == .vertical ? .bottom : .right - pinView(contentView, toView: lastView, attribute: attribute, relation: .equal, priority: .required, constant: 0) - } - } } diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 378332b6..c656ab2f 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -67,7 +67,8 @@ @"tabsListItem": TabsTableViewCell.class, @"dropDownListItem": DropDownFilterTableViewCell.class, @"headlineBodyButton": HeadlineBodyButton.class, - @"eyebrowHeadlineBodyLink": EyebrowHeadlineBodyLink.class + @"eyebrowHeadlineBodyLink": EyebrowHeadlineBodyLink.class, + @"stackItem": StackItem.class } mutableCopy]; }); return mapping; diff --git a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift index a26e2c85..d66c1558 100644 --- a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift +++ b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift @@ -31,7 +31,7 @@ import Foundation ModelRegistry.register(LabelAttributeStrikeThroughModel.self) ModelRegistry.register(LabelAttributeActionModel.self) // - ModelRegistry.register(ModuleMoleculeModel.self) + //ModelRegistry.register(ModuleMoleculeModel.self) ModelRegistry.register(LeftRightLabelModel.self) } } diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index 3ba28ecc..94c0d009 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -178,7 +178,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol func getMoleculeInfo(with listItem: ListItemModelProtocol?) -> (identifier: String, class: AnyClass, molecule: ListItemModelProtocol)? { guard let listItem = listItem, let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(listItem), - let moleculeName = (moleculeClass as? ModelMoleculeViewProtocol.Type)?.name(forReuse: listItem, delegateObject: delegateObject() as? MVMCoreUIDelegateObject) ?? listItem.molecule.moleculeName else { + let moleculeName = (moleculeClass as? ModelMoleculeViewProtocol)?.nameForReuse(listItem, delegateObject() as? MVMCoreUIDelegateObject) ?? listItem.molecule.moleculeName else { return nil } return (moleculeName, moleculeClass, listItem) diff --git a/MVMCoreUI/Utility/NSLayoutConstraintAxis+Extension.swift b/MVMCoreUI/Utility/NSLayoutConstraintAxis+Extension.swift new file mode 100644 index 00000000..05d13bcd --- /dev/null +++ b/MVMCoreUI/Utility/NSLayoutConstraintAxis+Extension.swift @@ -0,0 +1,56 @@ +// +// NSLayoutConstraintAxis+Extension.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 12/20/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import Foundation + +/** + When using this class in codable for a String value from server. + + Example use case.... + + var axis: NSLayoutConstraint.Axis + + enum CodingKeys: String, CodingKey { + case axis + } + + required public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + let word = try container.decode(String.self, forKey: .axis) + axis = NSLayoutConstraint.Axis(rawValue: axis)! + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(axis.rawValueString, forKey: .axis) + } + */ +extension NSLayoutConstraint.Axis: RawRepresentable { + + init?(rawValue: String) { + switch rawValue { + case "horizontal": + self = .horizontal + case "vertical": + self = .vertical + default: + return nil + } + } + + var rawValueString: String { + switch self { + case .horizontal: + return "horizontal" + case .vertical: + return "vertical" + @unknown default: + return "" + } + } +}