From d3e3a6809c168fe82d683d23a10c6735b10fd330 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 7 Jan 2020 11:08:00 -0500 Subject: [PATCH] container fixes for modal --- MVMCoreUI.xcodeproj/project.pbxproj | 32 ++- .../Atoms/Views/MFView+ModelExtension.swift | 1 + .../ViewConstrainingView+ModelExtension.swift | 9 +- MVMCoreUI/BaseClasses/View.swift | 5 +- MVMCoreUI/Containers/Container.swift | 33 ++- .../Models/ConstrainingMoleculeProtocol.swift | 19 -- .../Models/Container/ContainerModel.swift | 54 +++++ .../Container/ContainerModelProtocol.swift | 19 ++ .../Container/MoleculeContainerModel.swift | 34 +++ .../Models/ContainerMoleculeProtocol.swift | 17 -- MVMCoreUI/Models/Molecules/HeaderModel.swift | 37 +-- .../Models/Molecules/ListItemModel.swift | 25 +- .../Molecules/MoleculeStackItemModel.swift | 48 ++-- .../Models/Molecules/MoleculeStackModel.swift | 34 +-- .../Models/Molecules/SeperatorModel.swift | 15 -- MVMCoreUI/Molecules/Items/StackItem.swift | 79 +------ .../Molecules/ModelMoleculeViewProtocol.swift | 8 + MVMCoreUI/Molecules/ModuleMolecule.swift | 29 +-- MVMCoreUI/Molecules/MoleculeContainer.swift | 13 ++ MVMCoreUI/Molecules/StandardFooterView.swift | 12 - MVMCoreUI/Molecules/StandardHeaderView.swift | 10 +- .../EyebrowHeadlineBodyLink.swift | 41 +++- MVMCoreUI/Organisms/MoleculeStackView.swift | 214 +++++++++--------- .../MVMCoreUIMoleculeMappingObject.m | 3 +- .../OtherHandlers/MoleculeObjectMapping.swift | 1 - 25 files changed, 397 insertions(+), 395 deletions(-) delete mode 100644 MVMCoreUI/Models/ConstrainingMoleculeProtocol.swift create mode 100644 MVMCoreUI/Models/Container/ContainerModel.swift create mode 100644 MVMCoreUI/Models/Container/ContainerModelProtocol.swift create mode 100644 MVMCoreUI/Models/Container/MoleculeContainerModel.swift delete mode 100644 MVMCoreUI/Models/ContainerMoleculeProtocol.swift delete mode 100644 MVMCoreUI/Models/Molecules/SeperatorModel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index db24662f..4ff1fa87 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -12,12 +12,11 @@ 0105618E224BBE7700E1557D /* FormValidator+TextFields.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */; }; 0105618F224BBE7700E1557D /* FormValidator+FormParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */; }; 0116A4E5228B19640094F3ED /* RadioButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0116A4E4228B19640094F3ED /* RadioButtonModel.swift */; }; - 012A88EE239858E300FE3DA1 /* ContainerMoleculeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88ED239858E300FE3DA1 /* ContainerMoleculeProtocol.swift */; }; - 012CA98923849699003F810F /* SeperatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA98823849699003F810F /* SeperatorModel.swift */; }; + 012A88EE239858E300FE3DA1 /* ContainerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012A88ED239858E300FE3DA1 /* ContainerModel.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 */; }; + 012CA9BE2385C692003F810F /* ContainerModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012CA9BD2385C692003F810F /* ContainerModelProtocol.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 */; }; @@ -234,6 +233,7 @@ D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */; }; D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */; }; D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */; }; + D2DEDCB423C3D22700C44CC4 /* MoleculeContainerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DEDCB323C3D22700C44CC4 /* MoleculeContainerModel.swift */; }; D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */; }; D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */; }; D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */; }; @@ -253,12 +253,11 @@ 0105618B224BBE7700E1557D /* FormValidator+TextFields.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+TextFields.swift"; sourceTree = ""; }; 0105618C224BBE7700E1557D /* FormValidator+FormParams.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "FormValidator+FormParams.swift"; sourceTree = ""; }; 0116A4E4228B19640094F3ED /* RadioButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonModel.swift; sourceTree = ""; }; - 012A88ED239858E300FE3DA1 /* ContainerMoleculeProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerMoleculeProtocol.swift; sourceTree = ""; }; - 012CA98823849699003F810F /* SeperatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeperatorModel.swift; sourceTree = ""; }; + 012A88ED239858E300FE3DA1 /* ContainerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerModel.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 = ""; }; + 012CA9BD2385C692003F810F /* ContainerModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerModelProtocol.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 = ""; }; @@ -478,6 +477,7 @@ D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = ""; }; D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scroller.swift; sourceTree = ""; }; D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTemplate.swift; sourceTree = ""; }; + D2DEDCB323C3D22700C44CC4 /* MoleculeContainerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeContainerModel.swift; sourceTree = ""; }; D2E1FADA2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIDelegateObject.swift; sourceTree = ""; }; D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTableViewController.swift; sourceTree = ""; }; D2E1FAE02268E81D00AEFD8C /* MoleculeListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeListTemplate.swift; sourceTree = ""; }; @@ -508,11 +508,10 @@ 01509D96232803B200EF99AA /* Models */ = { isa = PBXGroup; children = ( + D2DEDCB223C3D17600C44CC4 /* Container */, 0AA33B322398134B0067DD0F /* Primitive Models */, 017BEB392360EEB40024EF95 /* PageModel.swift */, 01EB3683236097C0006832FA /* MoleculeProtocol.swift */, - 012A88ED239858E300FE3DA1 /* ContainerMoleculeProtocol.swift */, - 012CA9BD2385C692003F810F /* ConstrainingMoleculeProtocol.swift */, 946EE1B5237B663A0036751F /* Extensions */, 01EB368723609801006832FA /* Molecules */, ); @@ -533,7 +532,6 @@ 01EB368723609801006832FA /* Molecules */ = { isa = PBXGroup; children = ( - 012CA98823849699003F810F /* SeperatorModel.swift */, 01EB368923609801006832FA /* ListItemModel.swift */, 01EB368A23609801006832FA /* MoleculeStackItemModel.swift */, 01EB368B23609801006832FA /* MoleculeStackModel.swift */, @@ -1079,6 +1077,16 @@ path = BaseClasses; sourceTree = ""; }; + D2DEDCB223C3D17600C44CC4 /* Container */ = { + isa = PBXGroup; + children = ( + 012A88ED239858E300FE3DA1 /* ContainerModel.swift */, + 012CA9BD2385C692003F810F /* ContainerModelProtocol.swift */, + D2DEDCB323C3D22700C44CC4 /* MoleculeContainerModel.swift */, + ); + path = Container; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -1238,13 +1246,13 @@ buildActionMask = 2147483647; files = ( 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */, + D2DEDCB423C3D22700C44CC4 /* MoleculeContainerModel.swift in Sources */, D29DF32121ED0CBA003B2FB9 /* LabelView.m in Sources */, DBC4391822442197001AB423 /* CaretView.swift in Sources */, D29770F221F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m in Sources */, - 012CA9BE2385C692003F810F /* ConstrainingMoleculeProtocol.swift in Sources */, + 012CA9BE2385C692003F810F /* ContainerModelProtocol.swift in Sources */, D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */, 94C2D9A923872E5E0006CF46 /* LabelAttributeImageModel.swift in Sources */, - 012CA98923849699003F810F /* SeperatorModel.swift in Sources */, DBC4391922442197001AB423 /* DashLine.swift in Sources */, 0AA33B34239813C50067DD0F /* UIColor+Extension.swift in Sources */, 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */, @@ -1308,7 +1316,7 @@ D29DF26D21E6AA0B003B2FB9 /* FLAnimatedImageView.m in Sources */, D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */, D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */, - 012A88EE239858E300FE3DA1 /* ContainerMoleculeProtocol.swift in Sources */, + 012A88EE239858E300FE3DA1 /* ContainerModel.swift in Sources */, D2B18B94236214AD00A9AEDC /* NavigationController.swift in Sources */, D282AACB2243C61700C46919 /* ButtonView.swift in Sources */, D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.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 90377f84..6a6bf03f 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 { @@ -16,7 +15,7 @@ extension ViewConstrainingView { } if shouldSetupMoleculeFromJSON, - let moleculeObject = (model as? ConstrainingMoleculeProtocol)?.molecule { + let moleculeObject = (model as? MoleculeContainerModel)?.molecule { if molecule != nil { (molecule as? ModelMoleculeViewProtocol)?.setWithModel(moleculeObject, delegateObject, additionalData) } else { @@ -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 de76f739..9b194d48 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 { @@ -67,4 +71,3 @@ extension View: MVMCoreUIMoleculeViewProtocol { backgroundColor = .clear } } - diff --git a/MVMCoreUI/Containers/Container.swift b/MVMCoreUI/Containers/Container.swift index 58f7c849..f3f38899 100644 --- a/MVMCoreUI/Containers/Container.swift +++ b/MVMCoreUI/Containers/Container.swift @@ -8,13 +8,6 @@ import UIKit -public protocol ContainerModelProtocol: Model { - 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": @@ -184,6 +168,19 @@ public class ContainerHelper: NSObject { } } + 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) @@ -205,8 +202,6 @@ open class Container: View { 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) @@ -220,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/ConstrainingMoleculeProtocol.swift b/MVMCoreUI/Models/ConstrainingMoleculeProtocol.swift deleted file mode 100644 index 5cb24c4d..00000000 --- a/MVMCoreUI/Models/ConstrainingMoleculeProtocol.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// ConstrainingMoleculeProtocol.swift -// MVMCoreUI -// -// Created by Suresh, Kamlesh on 11/20/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import Foundation - -public protocol ConstrainingMoleculeProtocol: MoleculeProtocol { - var molecule: MoleculeProtocol? { get } -} - -extension ConstrainingMoleculeProtocol { - public var molecule: MoleculeProtocol? { - get { return nil } - } -} 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/ContainerMoleculeProtocol.swift b/MVMCoreUI/Models/ContainerMoleculeProtocol.swift deleted file mode 100644 index be3ffa60..00000000 --- a/MVMCoreUI/Models/ContainerMoleculeProtocol.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// ContainerMoleculeProtocol.swift -// MVMCoreUI -// -// Created by Suresh, Kamlesh on 12/4/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import Foundation - -protocol ContainerMoleculeProtocol: MoleculeProtocol { - var molecule: MoleculeProtocol? { get } - var useHorizontalMargins: Bool? { get } - var useVerticalMargins: Bool? { get } - var horizontalAlignment: String? { get } - var verticalAlignment: String? { get } -} diff --git a/MVMCoreUI/Models/Molecules/HeaderModel.swift b/MVMCoreUI/Models/Molecules/HeaderModel.swift index 28d538a0..c28d7080 100644 --- a/MVMCoreUI/Models/Molecules/HeaderModel.swift +++ b/MVMCoreUI/Models/Molecules/HeaderModel.swift @@ -8,33 +8,36 @@ import Foundation -@objcMembers public class HeaderModel: ConstrainingMoleculeProtocol { +@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: MoleculeProtocol? - - public init(molecule: MoleculeProtocol?) { - self.molecule = molecule - self.moleculeName = Self.identifier - } + public var line: LineModel? - enum CodingKeys: String, CodingKey { + enum HeaderCodingKeys: String, CodingKey { case moleculeName - case molecule - 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.molecule = try typeContainer.decodeMoleculeIfPresent(codingKey: .molecule) + 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(self.molecule, forKey: .molecule) + 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/MoleculeStackItemModel.swift b/MVMCoreUI/Models/Molecules/MoleculeStackItemModel.swift index b8d25952..a0e7825c 100644 --- a/MVMCoreUI/Models/Molecules/MoleculeStackItemModel.swift +++ b/MVMCoreUI/Models/Molecules/MoleculeStackItemModel.swift @@ -8,28 +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 init(molecule: MoleculeProtocol?) { - self.molecule = molecule - } - enum CodingKeys: String, CodingKey { - case moleculeName - case molecule - } - - required public init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - self.molecule = try typeContainer.decodeMoleculeIfPresent(codingKey: .molecule) + public var spacing: CGFloat? + public var percentage: Int? = 0 + public var gone: Bool = false + + enum MoleculeStackItemCodingKeys: String, CodingKey { + case spacing + case percentage + case gone } - 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.encode(gone, forKey: .gone) } } diff --git a/MVMCoreUI/Models/Molecules/MoleculeStackModel.swift b/MVMCoreUI/Models/Molecules/MoleculeStackModel.swift index 777fcbb1..530c7393 100644 --- a/MVMCoreUI/Models/Molecules/MoleculeStackModel.swift +++ b/MVMCoreUI/Models/Molecules/MoleculeStackModel.swift @@ -8,23 +8,19 @@ import Foundation -@objcMembers public class MoleculeStackModel: ContainerModelProtocol, MoleculeProtocol { +@objcMembers public class MoleculeStackModel: ContainerModel, MoleculeProtocol { public static var identifier: String = "moleculeStack" public var backgroundColor: String? - public var molecules: [StackItemModel] - public var axis: NSLayoutConstraint.Axis? = .vertical - public var spacing: CGFloat? - - public var horizontalAlignment: UIStackView.Alignment? - public var verticalAlignment: UIStackView.Alignment? - public var useHorizontalMargins: Bool? - public var useVerticalMargins: Bool? + public var molecules: [MoleculeStackItemModel] + public var axis: NSLayoutConstraint.Axis = .vertical + public var spacing: CGFloat = 16.0 - public init(molecules: [StackItemModel]) { + public init(molecules: [MoleculeStackItemModel]) { self.molecules = molecules + super.init() } - enum CodingKeys: String, CodingKey { + enum StackCodingKeys: String, CodingKey { case moleculeName case molecules case axis @@ -32,19 +28,23 @@ import Foundation } required public init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - molecules = try typeContainer.decodeMolecules(codingKey: .molecules) as! [StackItemModel] + 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 } - spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing) + 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) + 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?.rawValueString, forKey: .axis) + try container.encodeIfPresent(axis.rawValueString, forKey: .axis) try container.encodeIfPresent(spacing, forKey: .spacing) } } diff --git a/MVMCoreUI/Models/Molecules/SeperatorModel.swift b/MVMCoreUI/Models/Molecules/SeperatorModel.swift deleted file mode 100644 index 4c9689fd..00000000 --- a/MVMCoreUI/Models/Molecules/SeperatorModel.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// SeperatorModel.swift -// MVMCoreUI -// -// Created by Suresh, Kamlesh on 11/19/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import UIKit - -class SeperatorModel: MoleculeProtocol { - public static var identifier: String = "line" - public var backgroundColor: String? - public var type: String? -} diff --git a/MVMCoreUI/Molecules/Items/StackItem.swift b/MVMCoreUI/Molecules/Items/StackItem.swift index f976667d..e121a1ee 100644 --- a/MVMCoreUI/Molecules/Items/StackItem.swift +++ b/MVMCoreUI/Molecules/Items/StackItem.swift @@ -8,81 +8,8 @@ import UIKit -open class StackItemModel: ContainerModelProtocol, MoleculeProtocol { - public static var identifier: String = "stackItem" - public var backgroundColor: String? - public var view: StackItem? - - public var molecule: MoleculeProtocol - public var spacing: CGFloat? = 16 - public var percentage: Int? = 0 - public var verticalAlignment: UIStackView.Alignment? - public var horizontalAlignment: UIStackView.Alignment? - public var useHorizontalMargins: Bool? = false - public var useVerticalMargins: Bool? = false - public var gone: Bool? = false - - enum CodingKeys: String, CodingKey { - case molecule - case spacing - case percentage - case verticalAlignment - case horizontalAlignment - case useHorizontalMargins - case useVerticalMargins - case gone - } - - required public init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - molecule = try typeContainer.decodeMolecule(codingKey: .molecule) - spacing = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .spacing) - percentage = try typeContainer.decodeIfPresent(Int.self, forKey: .percentage) - 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) - } - useVerticalMargins = try typeContainer.decodeIfPresent(Bool.self, forKey: .useVerticalMargins) - useHorizontalMargins = try typeContainer.decodeIfPresent(Bool.self, forKey: .useHorizontalMargins) - gone = try typeContainer.decodeIfPresent(Bool.self, forKey: .gone) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encodeModel(molecule, forKey: .molecule) - try container.encodeIfPresent(spacing, forKey: .spacing) - try container.encodeIfPresent(percentage, forKey: .percentage) - try container.encodeIfPresent(ContainerHelper.getAlignmentString(for: verticalAlignment), forKey: .verticalAlignment) - try container.encodeIfPresent(ContainerHelper.getAlignmentString(for: horizontalAlignment), forKey: .horizontalAlignment) - try container.encodeIfPresent(useVerticalMargins, forKey: .useVerticalMargins) - try container.encodeIfPresent(useHorizontalMargins, forKey: .useHorizontalMargins) - try container.encodeIfPresent(gone, forKey: .gone) - } - - func update(with json: [AnyHashable: Any]?) { - gone = json?.boolForKey("gone") ?? (json == nil) - spacing = json?.optionalCGFloatForKey("spacing") - percentage = json?["percent"] as? Int - if let horizontalAlignmentString = json?.optionalStringForKey("horizontalAlignment") { - horizontalAlignment = ContainerHelper.getAlignment(for: horizontalAlignmentString) - } else { - horizontalAlignment = nil - } - - if let verticalAlignmentString = json?.optionalStringForKey("verticalAlignment") { - verticalAlignment = ContainerHelper.getAlignment(for: verticalAlignmentString) - } else { - verticalAlignment = nil - } - - useHorizontalMargins = json?.optionalBoolForKey("useHorizontalMargins") ?? false - useVerticalMargins = json?.optionalBoolForKey("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 98c1818c..6668d2be 100644 --- a/MVMCoreUI/Molecules/ModelMoleculeViewProtocol.swift +++ b/MVMCoreUI/Molecules/ModelMoleculeViewProtocol.swift @@ -10,4 +10,12 @@ import Foundation public protocol ModelMoleculeViewProtocol { func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String: AnyHashable]?) + + func nameForReuse(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> String? +} + +extension ModelMoleculeViewProtocol { + public func nameForReuse(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { + return nil + } } diff --git a/MVMCoreUI/Molecules/ModuleMolecule.swift b/MVMCoreUI/Molecules/ModuleMolecule.swift index 51d9a53a..e6ef0048 100644 --- a/MVMCoreUI/Molecules/ModuleMolecule.swift +++ b/MVMCoreUI/Molecules/ModuleMolecule.swift @@ -8,54 +8,33 @@ import UIKit -open class ModuleMoleculeModel: ContainerModelProtocol { +open class ModuleMoleculeModel: MoleculeProtocol { + public var backgroundColor: String? public static var identifier: String = "moduleMolecule" - - public var molecule: MoleculeProtocol? public var moduleName: String - public var horizontalAlignment: UIStackView.Alignment? = .fill - public var verticalAlignment: UIStackView.Alignment? = .fill - public var useHorizontalMargins: Bool? = false - public var useVerticalMargins: Bool? = false enum CodingKeys: String, CodingKey { - case molecule case moduleName - case horizontalAlignment - case verticalAlignment - case useHorizontalMargins - case useVerticalMargins } required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) moduleName = try typeContainer.decode(String.self, forKey:.moduleName) - 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) - } - useVerticalMargins = try typeContainer.decodeIfPresent(Bool.self, forKey: .useVerticalMargins) - useHorizontalMargins = try typeContainer.decodeIfPresent(Bool.self, forKey: .useHorizontalMargins) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(moduleName, forKey: .moduleName) - try container.encodeIfPresent(ContainerHelper.getAlignmentString(for: verticalAlignment), forKey: .verticalAlignment) - try container.encodeIfPresent(ContainerHelper.getAlignmentString(for: horizontalAlignment), forKey: .horizontalAlignment) - try container.encodeIfPresent(useVerticalMargins, forKey: .useVerticalMargins) - try container.encodeIfPresent(useHorizontalMargins, forKey: .useHorizontalMargins) } } open class ModuleMolecule: Container { var moduleMoleculeModel: ModuleMoleculeModel? { get { return model as? ModuleMoleculeModel } + } + public override func setupView() { super.setupView() - containerModel = ModuleMoleculeModel() } open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { diff --git a/MVMCoreUI/Molecules/MoleculeContainer.swift b/MVMCoreUI/Molecules/MoleculeContainer.swift index 14a5bb4a..0eea4414 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 cf44ef6a..c0994282 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() @@ -47,7 +49,7 @@ public class StandardHeaderView: MoleculeContainer { return } - if let seperatorModel = headerModel.seperator as? LineModel { + if let seperatorModel = headerModel.line { line?.setWithJSON(seperatorModel.toJSON(), delegateObject: delegateObject, additionalData: additionalData) } } @@ -75,8 +77,6 @@ public class StandardHeaderView: MoleculeContainer { 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 869bd23a..152411ea 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: StackItem(andContain: eyebrow)), lastItem: false) - stack.addStackItem(StackItemModel(with: StackItem(andContain: headline)), lastItem: false) - stack.addStackItem(StackItemModel(with: StackItem(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: StackItem(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.items[0].gone = !eyebrow.hasText headline.setWithJSON(json?.optionalDictionaryForKey("headline"), delegateObject: delegateObject, additionalData: additionalData) stack.items[1].gone = !headline.hasText @@ -50,13 +67,13 @@ import UIKit stack.items[2].gone = !body.hasText link.setWithJSON(json?.optionalDictionaryForKey("link"), delegateObject: delegateObject, additionalData: additionalData) stack.items[3].gone = link.titleLabel?.text?.count ?? 0 == 0 - stack.restack() + 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/MoleculeStackView.swift b/MVMCoreUI/Organisms/MoleculeStackView.swift index 31177540..3845ecdb 100644 --- a/MVMCoreUI/Organisms/MoleculeStackView.swift +++ b/MVMCoreUI/Organisms/MoleculeStackView.swift @@ -14,6 +14,7 @@ open class MoleculeStackView: Container { var stackModel: MoleculeStackModel? { get { return model as? MoleculeStackModel } } + var stackItems: [StackItem] = [] var moleculesShouldSetHorizontalMargins = false var moleculesShouldSetVerticalMargins = false @@ -27,15 +28,21 @@ open class MoleculeStackView: Container { /// Restacks the existing items. func restack() { - guard let stackItems = stackModel?.molecules else { return } - 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() { - guard let stackItems = stackModel?.molecules else { return } for item in stackItems { - item.view?.removeFromSuperview() + item.removeFromSuperview() } } @@ -76,9 +83,8 @@ open class MoleculeStackView: Container { super.updateView(size) directionalLayoutMargins.leading = 0 directionalLayoutMargins.trailing = 0 - guard let stackItems = stackModel?.molecules else { return } for item in stackItems { - item.view?.updateView(size) + item.updateView(size) } } @@ -86,64 +92,58 @@ open class MoleculeStackView: Container { public override func reset() { super.reset() backgroundColor = .clear - guard let stackItems = stackModel?.molecules else { return } for item in stackItems { - item.view?.reset() + item.reset() } } public override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { + let previousModel = stackModel super.setWithModel(model, delegateObject, additionalData) + removeAllItemViews() + + // 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) + } + } + 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<>" + } + 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 + ",") + } + } + } + name.append(">") + return name + } + open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { if model == nil { - model = MoleculeStackModel(molecules: []) - } - - let previousJSON = self.json - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - removeAllItemViews() - - // If the items in the stack are the same, just update previous items instead of re-allocating. - var items: [StackItemModel]? - if MoleculeStackView.name(forReuse: previousJSON, delegateObject: delegateObject) == MoleculeStackView.name(forReuse: json, delegateObject: delegateObject) { - items = stackModel?.molecules - } - stackModel?.molecules = [] - - guard let molecules = json?.arrayForKey(KeyMolecules) as? [[String: Any]] else { - return - } - - // Sets the stack attributes - stackModel?.axis - setAxisWithJSON(json) - spacing = json?.optionalCGFloatForKey("spacing") ?? 16 - - // Adds the molecules and sets the json. - for (index, map) in molecules.enumerated() { - var view: UIView? - var stackItemModel: StackItemModel - if let item = items?[index] { - stackItemModel = item - item.update(with: map) - view = item.view - (view as? MVMCoreUIMoleculeViewProtocol)?.setWithJSON(map, delegateObject: delegateObject, additionalData: nil) - addStackItem(item, lastItem: index == molecules.count - 1) - } else { - let stackItem = StackItem() - stackItem.setWithJSON(map, delegateObject: delegateObject, additionalData: additionalData) - view = stackItem - stackItemModel = StackItemModel(with: stackItem, json: map) - addStackItem(stackItemModel, lastItem: index == molecules.count - 1) - } - - stackItemModel.useHorizontalMargins = moleculesShouldSetHorizontalMargins - stackItemModel.useVerticalMargins = moleculesShouldSetVerticalMargins + 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]) } } @@ -198,78 +198,76 @@ open class MoleculeStackView: Container { } // MARK: - Adding to stack - /// Adds the view to the stack. - func addView(_ view: UIView, lastItem: Bool) { - addStackItem(StackItemModel(with: StackItem(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 { - items.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 - let verticalAlignment = stackItem.verticalAlignment ?? (stackItem.percentage == nil && axis == .vertical ? .fill : (axis == .vertical ? .leading : .center)) - let horizontalAlignment = stackItem.horizontalAlignment ?? (view.view as? MVMCoreUIViewConstrainingProtocol)?.horizontalAlignment?() ?? (axis == .vertical || stackItem.percentage == nil ? .fill : .leading) - view.containerHelper.alignHorizontal(horizontalAlignment) - view.containerHelper.alignVertical(verticalAlignment) + 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 = items.first { !$0.gone } == nil - if axis == .vertical { + 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 = items.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 = items.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) - } - items.append(stackItem) - } - - func setWithStackItems(_ items: [StackItemModel]) { - removeAllItemViews() - self.items.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) - } + stackItems.append(stackItem) } } 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 983fac13..ac96c44f 100644 --- a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift +++ b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift @@ -18,7 +18,6 @@ import Foundation ModelRegistry.register(ListItemModel.self) ModelRegistry.register(TextFieldModel.self) ModelRegistry.register(LineModel.self) - ModelRegistry.register(SeperatorModel.self) ModelRegistry.register(ProgressBarModel.self) ModelRegistry.register(MultiProgressBarModel.self) ModelRegistry.register(CaretViewModel.self)