diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index b9fad525..6ae8f347 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -95,6 +95,10 @@ 0AE14F64238315D2005417F8 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE14F63238315D2005417F8 /* TextField.swift */; }; 31BE15CB23D8924D00452370 /* CheckboxLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */; }; 31BE15CC23D8924D00452370 /* CheckboxModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31BE15CA23D8924C00452370 /* CheckboxModel.swift */; }; + 5248BFEC23F12E350059236A /* ListThreeColumnPlanDataDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5248BFEA23F12E350059236A /* ListThreeColumnPlanDataDivider.swift */; }; + 5248BFED23F12E350059236A /* ListThreeColumnPlanDataDividerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5248BFEB23F12E350059236A /* ListThreeColumnPlanDataDividerModel.swift */; }; + 8D24041123E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D24041023E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift */; }; + 8D24041523E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D24041423E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift */; }; 9432A79F23DB47BA00719041 /* EntryFieldContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9432A79E23DB47BA00719041 /* EntryFieldContainer.swift */; }; 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F3236B77BB006A1E82 /* GraphView.swift */; }; 943784F6236B77BB006A1E82 /* GraphViewAnimationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */; }; @@ -414,6 +418,10 @@ 0AE14F63238315D2005417F8 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = ""; }; 31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxLabelModel.swift; sourceTree = ""; }; 31BE15CA23D8924C00452370 /* CheckboxModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxModel.swift; sourceTree = ""; }; + 5248BFEA23F12E350059236A /* ListThreeColumnPlanDataDivider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListThreeColumnPlanDataDivider.swift; sourceTree = ""; }; + 5248BFEB23F12E350059236A /* ListThreeColumnPlanDataDividerModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListThreeColumnPlanDataDividerModel.swift; sourceTree = ""; }; + 8D24041023E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconWithRightCaret.swift; sourceTree = ""; }; + 8D24041423E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconWithRightCaretModel.swift; sourceTree = ""; }; 9402C34F23A2CEA3004B974C /* LeftRightLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeftRightLabelModel.swift; sourceTree = ""; }; 9432A79E23DB47BA00719041 /* EntryFieldContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntryFieldContainer.swift; sourceTree = ""; }; 943784F3236B77BB006A1E82 /* GraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphView.swift; sourceTree = ""; }; @@ -944,6 +952,49 @@ path = Items; sourceTree = ""; }; + D22B38E923F4E07800490EF6 /* DesignedComponents */ = { + isa = PBXGroup; + children = ( + D22B38EC23F4E10700490EF6 /* SectionDividers */, + D22B38EA23F4E08B00490EF6 /* List */, + ); + path = DesignedComponents; + sourceTree = ""; + }; + D22B38EA23F4E08B00490EF6 /* List */ = { + isa = PBXGroup; + children = ( + D22B38EB23F4E0AE00490EF6 /* LeftVariable */, + ); + path = List; + sourceTree = ""; + }; + D22B38EB23F4E0AE00490EF6 /* LeftVariable */ = { + isa = PBXGroup; + children = ( + 8D24041423E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift */, + 8D24041023E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift */, + ); + path = LeftVariable; + sourceTree = ""; + }; + D22B38EC23F4E10700490EF6 /* SectionDividers */ = { + isa = PBXGroup; + children = ( + D22B38ED23F4E11100490EF6 /* ThreeColumn */, + ); + path = SectionDividers; + sourceTree = ""; + }; + D22B38ED23F4E11100490EF6 /* ThreeColumn */ = { + isa = PBXGroup; + children = ( + 5248BFEB23F12E350059236A /* ListThreeColumnPlanDataDividerModel.swift */, + 5248BFEA23F12E350059236A /* ListThreeColumnPlanDataDivider.swift */, + ); + path = ThreeColumn; + sourceTree = ""; + }; D22D1F582204D2590077CEC0 /* Legacy */ = { isa = PBXGroup; children = ( @@ -1046,6 +1097,7 @@ D29DF10E21E67A77003B2FB9 /* Molecules */ = { isa = PBXGroup; children = ( + D22B38E923F4E07800490EF6 /* DesignedComponents */, D22479912316A9EF003FCCF9 /* Items */, D224798F2316A99F003FCCF9 /* LeftRightViews */, D224798E2316A995003FCCF9 /* HorizontalCombinationViews */, @@ -1547,6 +1599,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 5248BFED23F12E350059236A /* ListThreeColumnPlanDataDividerModel.swift in Sources */, 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */, 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */, 31BE15CC23D8924D00452370 /* CheckboxModel.swift in Sources */, @@ -1645,6 +1698,7 @@ 31BE15CB23D8924D00452370 /* CheckboxLabelModel.swift in Sources */, D260105523CEA7DC00764D80 /* MVMCoreUISwitch+Model.swift in Sources */, D29DF13021E6851E003B2FB9 /* MVMCoreUITopAlertShortView.m in Sources */, + 5248BFEC23F12E350059236A /* ListThreeColumnPlanDataDivider.swift in Sources */, 0ABD136D237CAD1E0081388D /* DateDropdownEntryField.swift in Sources */, 0A7EF85B23D8A52800B2AAD1 /* EntryFieldModel.swift in Sources */, 94F217B723E0BF6100A47C06 /* PrimaryButtonView.m in Sources */, @@ -1695,6 +1749,7 @@ 94AF4A3F23E9D13900676048 /* MFCaretButton.m in Sources */, D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */, D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */, + 8D24041523E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift in Sources */, D28A838F23CCDEDE00DFE4FC /* TwoButtonViewModel.swift in Sources */, 012A88B1238C880100FE3DA1 /* CarouselPagingModelProtocol.swift in Sources */, D29DF2C921E7BFC6003B2FB9 /* MFSizeObject.m in Sources */, @@ -1707,6 +1762,7 @@ D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */, D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */, 0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */, + 8D24041123E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift in Sources */, D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */, DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */, 0A21DB89235E06EF00C160A2 /* MFMdnTextField.m in Sources */, diff --git a/MVMCoreUI/Atoms/Views/CircleProgressModel.swift b/MVMCoreUI/Atoms/Views/CircleProgressModel.swift index feb69083..c4f55bef 100644 --- a/MVMCoreUI/Atoms/Views/CircleProgressModel.swift +++ b/MVMCoreUI/Atoms/Views/CircleProgressModel.swift @@ -17,6 +17,7 @@ public enum GraphStyle: String, Codable { } public class CircleProgressModel: MoleculeModelProtocol { + public static var identifier: String = "circleProgress" public var style: GraphStyle = .unlimited { didSet { diff --git a/MVMCoreUI/Atoms/Views/Label/Label.swift b/MVMCoreUI/Atoms/Views/Label/Label.swift index 576f66b9..013f7f11 100644 --- a/MVMCoreUI/Atoms/Views/Label/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label/Label.swift @@ -752,7 +752,6 @@ extension Label { /// Applied to existing text. Removes underlines of tappable links and assoated actionable clauses. @objc public func clearActionableClauses() { - guard let attributedText = attributedText else { return } let mutableAttributedString = NSMutableAttributedString(attributedString: attributedText) diff --git a/MVMCoreUI/Atoms/Views/Label/LabelAttributeColorModel.swift b/MVMCoreUI/Atoms/Views/Label/LabelAttributeColorModel.swift index 26f1fa54..01183614 100644 --- a/MVMCoreUI/Atoms/Views/Label/LabelAttributeColorModel.swift +++ b/MVMCoreUI/Atoms/Views/Label/LabelAttributeColorModel.swift @@ -9,6 +9,9 @@ import UIKit @objcMembers public class LabelAttributeColorModel: LabelAttributeModel { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- override public class var identifier: String { return "color" @@ -16,14 +19,21 @@ import UIKit var textColor: String? + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case textColor } + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - self.textColor = try typeContainer.decodeIfPresent(String.self, forKey: .textColor) + textColor = try typeContainer.decodeIfPresent(String.self, forKey: .textColor) try super.init(from: decoder) } diff --git a/MVMCoreUI/Atoms/Views/Label/LabelAttributeFontModel.swift b/MVMCoreUI/Atoms/Views/Label/LabelAttributeFontModel.swift index 88ae728d..2e9e6e1c 100644 --- a/MVMCoreUI/Atoms/Views/Label/LabelAttributeFontModel.swift +++ b/MVMCoreUI/Atoms/Views/Label/LabelAttributeFontModel.swift @@ -8,7 +8,12 @@ import UIKit + @objcMembers public class LabelAttributeFontModel: LabelAttributeModel { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + override public class var identifier: String { return "font" } @@ -17,17 +22,25 @@ import UIKit var name: String? var size: CGFloat? + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case style case name case size } + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - self.style = try typeContainer.decodeIfPresent(String.self, forKey: .style) - self.name = try typeContainer.decodeIfPresent(String.self, forKey: .name) - self.size = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .size) + style = try typeContainer.decodeIfPresent(String.self, forKey: .style) + name = try typeContainer.decodeIfPresent(String.self, forKey: .name) + size = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .size) try super.init(from: decoder) } diff --git a/MVMCoreUI/Atoms/Views/Label/LabelAttributeImageModel.swift b/MVMCoreUI/Atoms/Views/Label/LabelAttributeImageModel.swift index 0095a589..1980353c 100644 --- a/MVMCoreUI/Atoms/Views/Label/LabelAttributeImageModel.swift +++ b/MVMCoreUI/Atoms/Views/Label/LabelAttributeImageModel.swift @@ -9,7 +9,10 @@ import UIKit class LabelAttributeImageModel: LabelAttributeModel { - + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + override public class var identifier: String { return "image" } @@ -18,17 +21,25 @@ class LabelAttributeImageModel: LabelAttributeModel { var name: String? var URL: String? + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case size case name case URL } + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - self.size = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .size) - self.name = try typeContainer.decodeIfPresent(String.self, forKey: .name) - self.URL = try typeContainer.decodeIfPresent(String.self, forKey: .URL) + size = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .size) + name = try typeContainer.decodeIfPresent(String.self, forKey: .name) + URL = try typeContainer.decodeIfPresent(String.self, forKey: .URL) try super.init(from: decoder) } diff --git a/MVMCoreUI/Atoms/Views/Label/LabelAttributeModel.swift b/MVMCoreUI/Atoms/Views/Label/LabelAttributeModel.swift index ae2768ab..22bb10d8 100644 --- a/MVMCoreUI/Atoms/Views/Label/LabelAttributeModel.swift +++ b/MVMCoreUI/Atoms/Views/Label/LabelAttributeModel.swift @@ -9,6 +9,17 @@ import Foundation @objcMembers open class LabelAttributeModel: Model { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public static var categoryName: String { + return "\(LabelAttributeModel.self)" + } + + public static var categoryCodingKey: String { + return "type" + } public class var identifier: String { return "" @@ -18,17 +29,25 @@ import Foundation var location: Int var length: Int + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case type case location case length } + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - self.type = try typeContainer.decode(String.self, forKey: .type) - self.location = try typeContainer.decode(Int.self, forKey: .location) - self.length = try typeContainer.decode(Int.self, forKey: .length) + type = try typeContainer.decode(String.self, forKey: .type) + location = try typeContainer.decode(Int.self, forKey: .location) + length = try typeContainer.decode(Int.self, forKey: .length) } public func encode(to encoder: Encoder) throws { @@ -37,5 +56,4 @@ import Foundation try container.encode(location, forKey: .location) try container.encode(length, forKey: .length) } - } diff --git a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift index 242e299a..1c54b891 100644 --- a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift +++ b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift @@ -357,6 +357,10 @@ import UIKit loadImage(withName: imageName, format: nil, width: width, height: height, customFallbackImage: nil, completionHandler: completionHandler) } + public func loadImage(withName imageName: String?, width: NSNumber?, height: NSNumber?, customFallbackImage: String?, completionHandler: @escaping MVMCoreGetImageBlock) { + loadImage(withName: imageName, format: nil, width: width, height: height, customFallbackImage: customFallbackImage, completionHandler: completionHandler) + } + public func loadImage(withName imageName: String?, format: String?, width: NSNumber?, height: NSNumber?, customFallbackImage: String?) { loadImage(withName: imageName, format: format, width: width, height: height, customFallbackImage: customFallbackImage, completionHandler: defaultCompletionBlock()) } diff --git a/MVMCoreUI/BaseControllers/MFViewController+Model.swift b/MVMCoreUI/BaseControllers/MFViewController+Model.swift index 6cedf93c..1ddbd4ab 100644 --- a/MVMCoreUI/BaseControllers/MFViewController+Model.swift +++ b/MVMCoreUI/BaseControllers/MFViewController+Model.swift @@ -9,41 +9,35 @@ import Foundation extension MFViewController: MoleculeDelegateProtocol { - public func getModuleWithName(_ name: String?) -> [AnyHashable : Any]? { - guard let name = name else { - return nil - } + + public func getModuleWithName(_ name: String?) -> [AnyHashable: Any]? { + guard let name = name else { return nil } + return loadObject?.modulesJSON?.optionalDictionaryForKey(name) } - public func getModuleWithName(_ moduleName: String) -> MoleculeModelProtocol? { - guard let moduleJSON = loadObject?.modulesJSON?.optionalDictionaryForKey(moduleName), + public func getModuleWithName(_ moleculeName: String) -> MoleculeModelProtocol? { + guard let moduleJSON = loadObject?.modulesJSON?.optionalDictionaryForKey(moleculeName), let moleculeName = moduleJSON.optionalStringForKey("moleculeName"), - let modelType = ModelRegistry.getType(for: moleculeName) as? MoleculeModelProtocol.Type else { - return nil - } + let modelType = ModelRegistry.getType(for: moleculeName, with: MoleculeModelProtocol.self) + else { return nil } + do { - return try modelType.decode(jsonDict: moduleJSON) + return try modelType.decode(jsonDict: moduleJSON) as? MoleculeModelProtocol } catch { MVMCoreUILoggingHandler.logDebugMessage(withDelegate: "error: \(error)") } + return nil } - @objc public func moleculeLayoutUpdated(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) { - - } + @objc public func moleculeLayoutUpdated(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) { } - @objc public func addMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { - // Do nothing - } + @objc public func addMolecules(_ molecules: [[AnyHashable: Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { } - @objc public func removeMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { - // Do nothing - } + @objc public func removeMolecules(_ molecules: [[AnyHashable: Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { } } public extension MFViewController { - @objc func parsePageJSON() throws { - } + @objc func parsePageJSON() throws { } } diff --git a/MVMCoreUI/Models/Extensions/MoleculeModelHelper.swift b/MVMCoreUI/Models/Extensions/MoleculeModelHelper.swift index 599851bb..87460640 100644 --- a/MVMCoreUI/Models/Extensions/MoleculeModelHelper.swift +++ b/MVMCoreUI/Models/Extensions/MoleculeModelHelper.swift @@ -8,7 +8,9 @@ import Foundation -extension KeyedDecodingContainer where Key : CodingKey { + +extension KeyedDecodingContainer where Key: CodingKey { + private enum TypeCodingKey: String, CodingKey { case moleculeName } diff --git a/MVMCoreUI/Models/ModelProtocols/CarouselItemModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/CarouselItemModelProtocol.swift index 53a6cc10..093c9337 100644 --- a/MVMCoreUI/Models/ModelProtocols/CarouselItemModelProtocol.swift +++ b/MVMCoreUI/Models/ModelProtocols/CarouselItemModelProtocol.swift @@ -8,7 +8,8 @@ import Foundation + public protocol CarouselItemModelProtocol: ContainerModelProtocol, MoleculeModelProtocol { - var peakingUI: Bool? {get} - var peakingArrowColor: Color? {get} + var peakingUI: Bool? { get } + var peakingArrowColor: Color? { get } } diff --git a/MVMCoreUI/Models/ModelProtocols/CarouselPagingModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/CarouselPagingModelProtocol.swift index 5f593d3b..94b1277a 100644 --- a/MVMCoreUI/Models/ModelProtocols/CarouselPagingModelProtocol.swift +++ b/MVMCoreUI/Models/ModelProtocols/CarouselPagingModelProtocol.swift @@ -8,6 +8,7 @@ import Foundation + public protocol CarouselPagingModelProtocol: MoleculeModelProtocol { - var position: Float? {get} + var position: Float? { get } } diff --git a/MVMCoreUI/Models/ModelProtocols/ContainerModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/ContainerModelProtocol.swift index 304a4811..bc230731 100644 --- a/MVMCoreUI/Models/ModelProtocols/ContainerModelProtocol.swift +++ b/MVMCoreUI/Models/ModelProtocols/ContainerModelProtocol.swift @@ -8,6 +8,7 @@ import Foundation + public protocol ContainerModelProtocol { var horizontalAlignment: UIStackView.Alignment? { get set } var verticalAlignment: UIStackView.Alignment? { get set } diff --git a/MVMCoreUI/Models/ModelProtocols/DisableableModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/DisableableModelProtocol.swift index 1e49bd8c..db0cfd77 100644 --- a/MVMCoreUI/Models/ModelProtocols/DisableableModelProtocol.swift +++ b/MVMCoreUI/Models/ModelProtocols/DisableableModelProtocol.swift @@ -8,6 +8,7 @@ import Foundation + public protocol EnableableModelProtocol { var enabled: Bool { get set } } diff --git a/MVMCoreUI/Models/ModelProtocols/FormModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/FormModelProtocol.swift index aa298716..1224d5a9 100644 --- a/MVMCoreUI/Models/ModelProtocols/FormModelProtocol.swift +++ b/MVMCoreUI/Models/ModelProtocols/FormModelProtocol.swift @@ -8,6 +8,7 @@ import Foundation + public protocol FormModelProtocol: Model { var required: Bool? { get } var fieldKey: String? { get } diff --git a/MVMCoreUI/Models/ModelProtocols/ListItemModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/ListItemModelProtocol.swift index c6be0488..020c3cbe 100644 --- a/MVMCoreUI/Models/ModelProtocols/ListItemModelProtocol.swift +++ b/MVMCoreUI/Models/ModelProtocols/ListItemModelProtocol.swift @@ -8,6 +8,7 @@ import Foundation + public protocol ListItemModelProtocol: ContainerModelProtocol, MoleculeModelProtocol { var line: LineModel? { get set } var action: ActionModelProtocol? { get set } @@ -16,14 +17,14 @@ public protocol ListItemModelProtocol: ContainerModelProtocol, MoleculeModelProt } // Not a strict requirement. -extension ListItemModelProtocol { +public extension ListItemModelProtocol { - public var action: ActionModelProtocol? { + var action: ActionModelProtocol? { get { return nil } set { } } - public var style: String? { + var style: String? { get { return nil } set { } } diff --git a/MVMCoreUI/Models/ModelProtocols/MoleculeModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/MoleculeModelProtocol.swift index 85a91bcd..1ec0d13c 100644 --- a/MVMCoreUI/Models/ModelProtocols/MoleculeModelProtocol.swift +++ b/MVMCoreUI/Models/ModelProtocols/MoleculeModelProtocol.swift @@ -1,12 +1,22 @@ import Foundation + public protocol MoleculeModelProtocol: Model { var moleculeName: String? { get } var backgroundColor: Color? { get set} } -extension MoleculeModelProtocol { - public var moleculeName: String? { +public extension MoleculeModelProtocol { + + var moleculeName: String? { get { return Self.identifier } } + + static var categoryName: String { + return "\(MoleculeModelProtocol.self)" + } + + static var categoryCodingKey: String { + return "moleculeName" + } } diff --git a/MVMCoreUI/Models/ModelProtocols/PageModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/PageModelProtocol.swift index 8c6d1557..34b58818 100644 --- a/MVMCoreUI/Models/ModelProtocols/PageModelProtocol.swift +++ b/MVMCoreUI/Models/ModelProtocols/PageModelProtocol.swift @@ -8,7 +8,8 @@ import Foundation -public protocol PageModelProtocol: Model { + +public protocol PageModelProtocol { var pageType: String { get set } var screenHeading: String? { get set } var isAtomicTabs: Bool? { get set } diff --git a/MVMCoreUI/Models/ModelProtocols/TemplateModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/TemplateModelProtocol.swift index 66472da6..793baa0a 100644 --- a/MVMCoreUI/Models/ModelProtocols/TemplateModelProtocol.swift +++ b/MVMCoreUI/Models/ModelProtocols/TemplateModelProtocol.swift @@ -8,12 +8,22 @@ import Foundation -public protocol TemplateModelProtocol: PageModelProtocol { + +public protocol TemplateModelProtocol: PageModelProtocol, Model { var template: String { get } } -extension TemplateModelProtocol { - public var template: String { +public extension TemplateModelProtocol { + + var template: String { get { return Self.identifier } } + + static var categoryCodingKey: String { + return "template" + } + + static var categoryName: String { + return "\(TemplateModelProtocol.self)" + } } diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaret.swift b/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaret.swift new file mode 100644 index 00000000..62a19d01 --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaret.swift @@ -0,0 +1,74 @@ +// +// ListLeftVariableIconWithRightCaret.swift +// MVMCoreUI +// +// Created by Kruthika KP on 03/02/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation +import UIKit + +@objcMembers public class ListLeftVariableIconWithRightCaret: TableViewCell { + + //----------------------------------------------------- + // MARK: - Outlets + //------------------------------------------------------- + let leftImage = MFLoadImageView(pinnedEdges: .all) + let leftLabel = Label.commonLabelB2(true) + let rightLabel = Label.commonLabelB2(true) + let stack = Stack(frame: .zero) + + //----------------------------------------------------- + // MARK: - View Lifecycle + //------------------------------------------------------- + open override func updateView(_ size: CGFloat) { + super.updateView(size) + stack.updateView(size) + } + + override open func setupView() { + super.setupView() + guard leftImage.superview == nil else { + return + } + stack.translatesAutoresizingMaskIntoConstraints = false + stack.stackItems = [StackItem(andContain: leftImage),StackItem(andContain: leftLabel),StackItem(andContain: rightLabel)] + contentView.addSubview(stack) + containerHelper.constrainView(stack) + leftLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 901), for: .horizontal) + rightLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 902), for: .horizontal) + } + + //---------------------------------------------------- + // MARK: - Molecule + //------------------------------------------------------ + override open func reset() { + super.reset() + stack.reset() + } + + public override func setWithModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + super.setWithModel(model, delegateObject, additionalData) + guard let model = model as? ListLeftVariableIconWithRightCaretModel else { return} + leftImage.setWithModel(model.image, delegateObject, additionalData) + leftLabel.setWithModel(model.leftLabel, delegateObject, additionalData) + rightLabel.setWithModel(model.rightLabel, delegateObject, additionalData) + + // Create a stack model to use for the internal stack and set the alignment of labels + let leftImage = StackItemModel() + leftImage.horizontalAlignment = .fill + let leftLabel = StackItemModel() + leftLabel.horizontalAlignment = .fill + let rightLabel = StackItemModel() + rightLabel.horizontalAlignment = .trailing + let stackModel = StackModel(molecules: [leftImage,leftLabel,rightLabel]) + stackModel.axis = .horizontal + stack.model = stackModel + stack.restack() + } + + public override class func estimatedHeight(forRow molecule: MoleculeModelProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return 90 + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretModel.swift b/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretModel.swift new file mode 100644 index 00000000..cac928d3 --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretModel.swift @@ -0,0 +1,75 @@ +// +// ListLeftVariableIconWithRightCaretModel.swift +// MVMCoreUI +// +// Created by Kruthika KP on 03/02/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class ListLeftVariableIconWithRightCaretModel: ContainerModel, ListItemModelProtocol { + + public var line: LineModel? + public var style: String? = "standard" + public var hideArrow: Bool? = false + public var backgroundColor: Color? + public var action: ActionModelProtocol? + public static var identifier: String = "listLVImg" + public var image: ImageViewModel + public var leftLabel: LabelModel + public var rightLabel: LabelModel + + func setDefaults() { + if useHorizontalMargins == nil { + useHorizontalMargins = true + } + if useVerticalMargins == nil { + useVerticalMargins = true + } + if image.height == nil { + image.height = 30.0 + } + } + + public init(image: ImageViewModel, leftLabel: LabelModel, rightLabel: LabelModel) { + self.image = image + self.leftLabel = leftLabel + self.rightLabel = rightLabel + super.init() + setDefaults() + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case leftLabel + case rightLabel + case image + case action + case backgroundColor + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + leftLabel = try typeContainer.decode(LabelModel.self, forKey: .leftLabel) + rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel) + image = try typeContainer.decode(ImageViewModel.self, forKey: .image) + action = try typeContainer.decodeModelIfPresent(codingKey: .action, typeCodingKey: ActionCodingKey.actionType) + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + try super.init(from: decoder) + setDefaults() + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(leftLabel, forKey: .leftLabel) + try container.encode(rightLabel, forKey: .rightLabel) + try container.encode(image, forKey: .image) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + try container.encodeModelIfPresent(action, forKey: .action) + } +} + + diff --git a/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDivider.swift b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDivider.swift new file mode 100644 index 00000000..e685ce6b --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDivider.swift @@ -0,0 +1,66 @@ +// +// ThreeColumnPlanDataDividerList.swift +// MVMCoreUI +// +// Created by Acharya, Subhankar on 04/02/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers open class ListThreeColumnPlanDataDivider: TableViewCell { + + let leftHeadlineBody = HeadlineBody(frame: .zero) + let centerHeadLineBody = HeadlineBody(frame: .zero) + let rightHeadLineBody = HeadlineBody(frame: .zero) + let stack = Stack(frame: .zero) + + // MARK: - MFViewProtocol + open override func updateView(_ size: CGFloat) { + super.updateView(size) + stack.updateView(size) + } + + open override func setupView() { + super.setupView() + guard leftHeadlineBody.superview == nil else { + return + } + //using stackItems to align the three headlineBody + stack.translatesAutoresizingMaskIntoConstraints = false + stack.stackItems = [StackItem(andContain: leftHeadlineBody),StackItem(andContain: centerHeadLineBody),StackItem(andContain: rightHeadLineBody)] + contentView.addSubview(stack) + containerHelper.constrainView(stack) + } + + // MARK: - MVMCoreUIMoleculeViewProtocol + public override func setWithModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + super.setWithModel(model, delegateObject, additionalData) + guard let model = model as? ListThreeColumnPlanDataDividerModel else { return } + leftHeadlineBody.setWithModel(model.leftHeadlineBody, delegateObject, additionalData) + centerHeadLineBody.setWithModel(model.centerHeadlineBody, delegateObject, additionalData) + rightHeadLineBody.setWithModel(model.rightHeadlineBody, delegateObject, additionalData) + + // Create a stack model to use for the internal stack and set the alignment of models + let leftHeadlineBodyAlignment = StackItemModel(percent: 33) + leftHeadlineBodyAlignment.horizontalAlignment = .leading + let centerHeadLineBodyAlignment = StackItemModel(percent: 34) + centerHeadLineBodyAlignment.horizontalAlignment = .center + let rightHeadLineBodyAlignment = StackItemModel(percent: 33) + rightHeadLineBodyAlignment.horizontalAlignment = .trailing + let stackModel = StackModel(molecules: [leftHeadlineBodyAlignment,centerHeadLineBodyAlignment,rightHeadLineBodyAlignment]) + stackModel.axis = .horizontal + stack.model = stackModel + stack.restack() + } + + open override func reset() { + super.reset() + stack.reset() + } + + public override class func estimatedHeight(forRow molecule: MoleculeModelProtocol?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return 121 + } +} + diff --git a/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDividerModel.swift b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDividerModel.swift new file mode 100644 index 00000000..47e97a5a --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnPlanDataDividerModel.swift @@ -0,0 +1,67 @@ +// +// ThreeColumnPlanDataDividerListModel.swift +// MVMCoreUI +// +// Created by Acharya, Subhankar on 04/02/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + +public class ListThreeColumnPlanDataDividerModel: ContainerModel, ListItemModelProtocol { + public var hideArrow: Bool? + public var style: String? = "tallDivider" + public var line: LineModel? + public var backgroundColor: Color? + public static var identifier: String = "list3CHBDiv" + public var leftHeadlineBody: HeadlineBodyModel + public var centerHeadlineBody: HeadlineBodyModel + public var rightHeadlineBody: HeadlineBodyModel + + public init(leftHeadlineBody: HeadlineBodyModel, centerHeadlineBody:HeadlineBodyModel, rightHeadlineBody: HeadlineBodyModel) { + self.leftHeadlineBody = leftHeadlineBody + self.centerHeadlineBody = centerHeadlineBody + self.rightHeadlineBody = rightHeadlineBody + super.init() + setDefaults() + } + + /// Defaults to set + func setDefaults() { + if useHorizontalMargins == nil { + useHorizontalMargins = true + } + if useVerticalMargins == nil { + useVerticalMargins = true + } + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case leftHeadlineBody + case centerHeadlineBody + case rightHeadlineBody + case backgroundColor + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + leftHeadlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .leftHeadlineBody) + centerHeadlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .centerHeadlineBody) + rightHeadlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .rightHeadlineBody) + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + try super.init(from: decoder) + setDefaults() + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(leftHeadlineBody, forKey: .leftHeadlineBody) + try container.encode(centerHeadlineBody, forKey: .centerHeadlineBody) + try container.encode(rightHeadlineBody, forKey: .rightHeadlineBody) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + } +} + diff --git a/MVMCoreUI/Molecules/Items/StackItemModel.swift b/MVMCoreUI/Molecules/Items/StackItemModel.swift index f296986e..2058353c 100644 --- a/MVMCoreUI/Molecules/Items/StackItemModel.swift +++ b/MVMCoreUI/Molecules/Items/StackItemModel.swift @@ -8,7 +8,7 @@ import Foundation -@objcMembers public class StackItemModel: StackItemModelProtocol, MoleculeModelProtocol { +@objcMembers public class StackItemModel: ContainerModel, StackItemModelProtocol, MoleculeModelProtocol { public static var identifier: String = "simpleStackItem" public var backgroundColor: Color? public var spacing: CGFloat? @@ -19,4 +19,9 @@ import Foundation self.init() self.gone = gone } + + public convenience init(percent: Int) { + self.init() + self.percent = percent + } } diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift index 4796b2a2..6249e61e 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject+ModelExtension.swift @@ -11,7 +11,7 @@ import Foundation public extension MVMCoreUIMoleculeMappingObject { func register(viewClass: V.Type, viewModelClass: M.Type) { - ModelRegistry.register(viewModelClass) + try? ModelRegistry.register(viewModelClass) MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping.setObject(viewClass, forKey: viewModelClass.identifier as NSString) } diff --git a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift index caffd59f..6824fd52 100644 --- a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift +++ b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift @@ -18,13 +18,13 @@ import Foundation // Label MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Label.self, viewModelClass: LabelModel.self) - //need to move labelattributemodel to different method - ModelRegistry.register(LabelAttributeFontModel.self) - ModelRegistry.register(LabelAttributeColorModel.self) - //ModelRegistry.register(LabelAttributeImageModel.self) // We need to separate the registry by types due to collisions... - ModelRegistry.register(LabelAttributeUnderlineModel.self) - ModelRegistry.register(LabelAttributeStrikeThroughModel.self) - ModelRegistry.register(LabelAttributeActionModel.self) + // need to move labelattributemodel to different method + try? ModelRegistry.register(LabelAttributeFontModel.self) + try? ModelRegistry.register(LabelAttributeColorModel.self) + try? ModelRegistry.register(LabelAttributeImageModel.self) // We need to separate the registry by types due to collisions... + try? ModelRegistry.register(LabelAttributeUnderlineModel.self) + try? ModelRegistry.register(LabelAttributeStrikeThroughModel.self) + try? ModelRegistry.register(LabelAttributeActionModel.self) // Buttons MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: PillButton.self, viewModelClass: ButtonModel.self) @@ -40,7 +40,6 @@ import Foundation MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: DateDropdownEntryField.self, viewModelClass: DateDropdownEntryFieldModel.self) // Other Atoms - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Label.self, viewModelClass: LabelModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ProgressBar.self, viewModelClass: ProgressBarModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: MultiProgress.self, viewModelClass: MultiProgressBarModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: CaretView.self, viewModelClass: CaretViewModel.self) @@ -55,6 +54,8 @@ import Foundation // Horizontal Combination Molecules MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: StringAndMoleculeView.self, viewModelClass: StringAndMoleculeModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ImageHeadlineBody.self, viewModelClass: ImageHeadlineBodyModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListThreeColumnPlanDataDivider.self, viewModelClass: ListThreeColumnPlanDataDividerModel.self) + // Vertical Combination Molecules MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: HeadlineBody.self, viewModelClass: HeadlineBodyModel.self) @@ -70,6 +71,7 @@ import Foundation MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: HeadlineBodyToggle.self, viewModelClass: HeadlineBodyToggleModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: HeadlineBodyLinkToggle.self, viewModelClass: HeadlineBodyLinkToggleModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ActionDetailWithImage.self, viewModelClass: ActionDetailWithImageModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListLeftVariableIconWithRightCaret.self, viewModelClass: ListLeftVariableIconWithRightCaretModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListLeftVariableCheckboxWithRightCaretAllTextAndLinks.self, viewModelClass: ListLeftVariableCheckboxWithRightCaretAllTextAndLinksModel.self) // List items @@ -105,6 +107,6 @@ import Foundation MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping.setObject(MVMCoreUIPageControl.self, forKey: "barsPager" as NSString) // TODO: Need View - ModelRegistry.register(TabsModel.self) + try? ModelRegistry.register(TabsModel.self) } } diff --git a/MVMCoreUI/Templates/ListPageTemplateModel.swift b/MVMCoreUI/Templates/ListPageTemplateModel.swift index fe9c12c5..ff899319 100644 --- a/MVMCoreUI/Templates/ListPageTemplateModel.swift +++ b/MVMCoreUI/Templates/ListPageTemplateModel.swift @@ -9,7 +9,10 @@ import Foundation @objcMembers public class ListPageTemplateModel: TemplateModelProtocol { - + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "list" public var pageType: String @@ -21,12 +24,20 @@ import Foundation public var footer: MoleculeModelProtocol? public var line: LineModel? + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(pageType: String, screenHeading: String?, molecules: [ListItemModelProtocol]) { self.pageType = pageType self.screenHeading = screenHeading self.molecules = molecules } + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + private enum CodingKeys: String, CodingKey { case moleculeName case pageType @@ -38,6 +49,10 @@ import Foundation case isAtomicTabs } + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) pageType = try typeContainer.decode(String.self, forKey: .pageType) diff --git a/MVMCoreUI/Templates/TemplateProtocol.swift b/MVMCoreUI/Templates/TemplateProtocol.swift index 0498ec5d..63c66263 100644 --- a/MVMCoreUI/Templates/TemplateProtocol.swift +++ b/MVMCoreUI/Templates/TemplateProtocol.swift @@ -14,6 +14,7 @@ public protocol TemplateProtocol: class { } public extension TemplateProtocol where Self: MFViewController { + func parseTemplateJSON() throws { guard let pageJSON = self.loadObject?.pageJSON else { return } let data = try JSONSerialization.data(withJSONObject: pageJSON)