diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index b47d64d3..f395d21b 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -84,10 +84,12 @@ 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; }; 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; }; 0AA33B3A2398524F0067DD0F /* Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B392398524F0067DD0F /* Toggle.swift */; }; - 0ABD136B237B193A0081388D /* EntryFieldContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD136A237B193A0081388D /* EntryFieldContainer.swift */; }; 0ABD136D237CAD1E0081388D /* DateDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */; }; 0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */; }; + 0ACDF26B23DA0AC2002044B2 /* EntryFieldContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ACDF26A23DA0AC2002044B2 /* EntryFieldContainer.swift */; }; 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 */; }; 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F3236B77BB006A1E82 /* GraphView.swift */; }; 943784F6236B77BB006A1E82 /* GraphViewAnimationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */; }; 9445890C2385BCE300DE9FD4 /* ProgressBarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9445890B2385BCE300DE9FD4 /* ProgressBarModel.swift */; }; @@ -305,6 +307,7 @@ D2E2A99823D8D63C000B42E6 /* ActionDetailWithImageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2A99723D8D63C000B42E6 /* ActionDetailWithImageModel.swift */; }; D2E2A99A23D8D6B4000B42E6 /* HeadlineBodyButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2A99923D8D6B4000B42E6 /* HeadlineBodyButtonModel.swift */; }; D2E2A99C23D8D975000B42E6 /* ImageHeadlineBodyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2A99B23D8D975000B42E6 /* ImageHeadlineBodyModel.swift */; }; + D2E2A99D23DA3217000B42E6 /* UIStackViewAlignment+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A209CD223A7E2810068F8B0 /* UIStackViewAlignment+Extension.swift */; }; D2FB151B23A2B65B00C20E10 /* MoleculeContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */; }; D2FB151D23A40F1500C20E10 /* MoleculeStackItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FB151C23A40F1500C20E10 /* MoleculeStackItem.swift */; }; DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB06250A2293456500B72DD3 /* LeftRightLabelView.swift */; }; @@ -384,10 +387,12 @@ 0A8321AE2355FE9500CB7F00 /* DigitBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigitBox.swift; sourceTree = ""; }; 0AA33B33239813C50067DD0F /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = ""; }; 0AA33B392398524F0067DD0F /* Toggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toggle.swift; sourceTree = ""; }; - 0ABD136A237B193A0081388D /* EntryFieldContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryFieldContainer.swift; sourceTree = ""; }; 0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryField.swift; sourceTree = ""; }; 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryField.swift; sourceTree = ""; }; + 0ACDF26A23DA0AC2002044B2 /* EntryFieldContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntryFieldContainer.swift; sourceTree = ""; }; 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 = ""; }; 9402C34F23A2CEA3004B974C /* LeftRightLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeftRightLabelModel.swift; sourceTree = ""; }; 943784F3236B77BB006A1E82 /* GraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphView.swift; sourceTree = ""; }; 943784F4236B77BB006A1E82 /* GraphViewAnimationHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphViewAnimationHandler.swift; sourceTree = ""; }; @@ -697,7 +702,7 @@ isa = PBXGroup; children = ( D29E28DE23D740FC00ACEA85 /* Container */, - 0ABD136A237B193A0081388D /* EntryFieldContainer.swift */, + 0ACDF26A23DA0AC2002044B2 /* EntryFieldContainer.swift */, 014AA72123C501E2006F3E93 /* MoleculeContainerModel.swift */, D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */, ); @@ -1160,7 +1165,9 @@ D268C711238D6699007F2C1C /* DropDown.swift */, DBC4391C2245232D001AB423 /* LabelWithInternalButton.swift */, 94C2D9822386F3E30006CF46 /* Label */, + 31BE15CA23D8924C00452370 /* CheckboxModel.swift */, 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */, + 31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */, 0A7BAFA2232BE63400FB8E22 /* CheckboxWithLabelView.swift */, 01004F2F22721C3800991ECC /* RadioButton.swift */, D28A838223CCBD3F00DFE4FC /* CircleProgressModel.swift */, @@ -1491,6 +1498,7 @@ files = ( 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */, 943784F5236B77BB006A1E82 /* GraphView.swift in Sources */, + 31BE15CC23D8924D00452370 /* CheckboxModel.swift in Sources */, 94C661DA23CCF4FB00D9FE5B /* UIColor+Extension.swift in Sources */, D29DF32121ED0CBA003B2FB9 /* LabelView.m in Sources */, D28A838123CCB0D800DFE4FC /* AccordionListItemModel.swift in Sources */, @@ -1532,6 +1540,7 @@ D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */, D260106323D0C05000764D80 /* StackItemModel.swift in Sources */, D2E2A99823D8D63C000B42E6 /* ActionDetailWithImageModel.swift in Sources */, + D2E2A99D23DA3217000B42E6 /* UIStackViewAlignment+Extension.swift in Sources */, 01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */, 0A21DB7F235DECC500C160A2 /* EntryField.swift in Sources */, D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */, @@ -1577,6 +1586,7 @@ DBEFFA04225A829700230692 /* Label.swift in Sources */, D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */, 01509D952327ED1900EF99AA /* HeadlineBodyTextButtonSwitch.swift in Sources */, + 31BE15CB23D8924D00452370 /* CheckboxLabelModel.swift in Sources */, D260105523CEA7DC00764D80 /* MVMCoreUISwitch+Model.swift in Sources */, D29DF13021E6851E003B2FB9 /* MVMCoreUITopAlertShortView.m in Sources */, 0ABD136D237CAD1E0081388D /* DateDropdownEntryField.swift in Sources */, @@ -1614,6 +1624,7 @@ 017BEB7F23676E870024EF95 /* MoleculeObjectMapping.swift in Sources */, D274CA332236A78900B01B62 /* FooterView.swift in Sources */, D29DF2BF21E7BEA4003B2FB9 /* MVMCoreUITabBarPageControlViewController.m in Sources */, + 0ACDF26B23DA0AC2002044B2 /* EntryFieldContainer.swift in Sources */, 014AA72423C501E2006F3E93 /* MoleculeContainerModel.swift in Sources */, D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */, 011B58F223A2AE2C0085F53C /* DropDownListItemModel.swift in Sources */, @@ -1696,7 +1707,6 @@ D2B18B922361E65A00A9AEDC /* CoreUIObject.swift in Sources */, D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */, 014AA72E23C5059B006F3E93 /* StackCenteredPageTemplateModel.swift in Sources */, - 0ABD136B237B193A0081388D /* EntryFieldContainer.swift in Sources */, D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */, D260105923D0A92900764D80 /* ContainerProtocol.swift in Sources */, C695A69423C9909000BFB94E /* DoughnutChartModel.swift in Sources */, diff --git a/MVMCoreUI/Atoms/Views/Checkbox.swift b/MVMCoreUI/Atoms/Views/Checkbox.swift index 50571e30..27bed31e 100644 --- a/MVMCoreUI/Atoms/Views/Checkbox.swift +++ b/MVMCoreUI/Atoms/Views/Checkbox.swift @@ -76,6 +76,27 @@ import MVMCore } } + open override var isEnabled: Bool { + didSet { + + isUserInteractionEnabled = isEnabled + + if isEnabled { + layer.borderColor = borderColor.cgColor + backgroundColor = isSelected ? checkedBackgroundColor : unCheckedBackgroundColor + setShapeLayerStrokeColor(checkColor) + } else { + layer.borderColor = disabledBorderColor.cgColor + backgroundColor = disabledBackgroundColor + setShapeLayerStrokeColor(disabledCheckColor) + } + } + } + + public var disabledBackgroundColor: UIColor = .clear + public var disabledBorderColor: UIColor = .mvmCoolGray3 + public var disabledCheckColor: UIColor = .mvmCoolGray3 + /// Color of the check mark. public var checkColor: UIColor = .black { didSet { @@ -107,7 +128,6 @@ import MVMCore if !updateSelectionOnly { layoutIfNeeded() shapeLayer?.removeAllAnimations() - updateCheckboxUI(isSelected: isSelected, isAnimated: isAnimated) FormValidator.enableByValidationWith(delegate: delegateObject?.formValidationProtocol) updateAccessibilityLabel() @@ -154,16 +174,12 @@ import MVMCore public convenience init(isChecked: Bool) { self.init(frame: .zero) - updateSelectionOnly = true - isSelected = isChecked - updateSelectionOnly = false + checkAndBypassAnimations(selected: isChecked) } public convenience init(checkedBackgroundColor: UIColor, unCheckedBackgroundColor: UIColor, isChecked: Bool = false) { self.init(frame: .zero) - updateSelectionOnly = true - isSelected = isChecked - updateSelectionOnly = false + checkAndBypassAnimations(selected: isChecked) self.checkedBackgroundColor = checkedBackgroundColor self.unCheckedBackgroundColor = unCheckedBackgroundColor } @@ -177,8 +193,6 @@ import MVMCore drawShapeLayer() layer.cornerRadius = isRound ? cornerRadiusValue : 0 - layer.borderWidth = borderWidth - layer.borderColor = borderColor.cgColor } open override func setupView() { @@ -228,7 +242,7 @@ import MVMCore self.shapeLayer = shapeLayer shapeLayer.frame = bounds layer.addSublayer(shapeLayer) - shapeLayer.strokeColor = checkColor.cgColor + shapeLayer.strokeColor = isEnabled ? checkColor.cgColor : disabledCheckColor.cgColor shapeLayer.fillColor = UIColor.clear.cgColor shapeLayer.path = checkMarkPath() shapeLayer.lineJoin = .miter @@ -268,9 +282,7 @@ import MVMCore DispatchQueue.main.async { - self.updateSelectionOnly = true - self.isSelected = selected - self.updateSelectionOnly = false + self.checkAndBypassAnimations(selected: selected) self.drawShapeLayer() self.shapeLayer?.removeAllAnimations() self.updateCheckboxUI(isSelected: selected, isAnimated: animated) @@ -313,23 +325,6 @@ import MVMCore } } - func isEnabled(_ enabled: Bool) { - - isUserInteractionEnabled = enabled - - if enabled { - layer.borderColor = borderColor.cgColor - backgroundColor = isSelected ? checkedBackgroundColor : unCheckedBackgroundColor - alpha = 1.0 - setShapeLayerStrokeColor(checkColor) - } else { - layer.borderColor = UIColor.mfSilver().cgColor - backgroundColor = .clear - alpha = DisableOppacity - setShapeLayerStrokeColor(UIColor.mfSilver()) - } - } - private func setShapeLayerStrokeColor(_ color: UIColor) { if let shapeLayer = shapeLayer { @@ -345,13 +340,19 @@ import MVMCore widthConstraint?.isActive = isActive } + private func checkAndBypassAnimations(selected: Bool) { + updateSelectionOnly = true + isSelected = selected + updateSelectionOnly = false + } + //-------------------------------------------------- // MARK: - UITouch //-------------------------------------------------- open override func touchesEnded(_ touches: Set, with event: UIEvent?) { - sendActions(for: .touchUpInside) + sendActions(for: .touchUpInside) } override open func accessibilityActivate() -> Bool { @@ -370,7 +371,7 @@ import MVMCore open override func reset() { super.reset() - isEnabled(true) + isEnabled = true shapeLayer?.removeAllAnimations() shapeLayer?.removeFromSuperlayer() shapeLayer = nil @@ -379,9 +380,7 @@ import MVMCore borderWidth = 1.0 checkColor = .black checkWidth = 2.0 - updateSelectionOnly = true - isSelected = false - updateSelectionOnly = false + checkAndBypassAnimations(selected: false) } open func setAsMolecule() { @@ -424,16 +423,14 @@ import MVMCore layer.borderWidth = borderWidth } - if let isChecked = dictionary["isChecked"] as? Bool, isChecked { - updateSelectionOnly = true - isSelected = isChecked - updateSelectionOnly = false - } - if let checkColorHex = dictionary["checkColor"] as? String { checkColor = UIColor.mfGet(forHex: checkColorHex) } + if let isChecked = dictionary["isChecked"] as? Bool, isChecked { + checkAndBypassAnimations(selected: isChecked) + } + if let unCheckedBackgroundColorHex = dictionary["unCheckedBackgroundColor"] as? String { unCheckedBackgroundColor = UIColor.mfGet(forHex: unCheckedBackgroundColorHex) } @@ -451,13 +448,57 @@ import MVMCore } if let enabled = dictionary["isEnabled"] as? Bool { - isEnabled(enabled) + isEnabled = enabled } if let actionMap = dictionary.optionalDictionaryForKey("action") { actionBlock = { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) } } } + + public override func setWithModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.setWithModel(model, delegateObject, additionalData) + + guard let model = model as? CheckboxModel else { return } + + self.delegateObject = delegateObject + FormValidator.setupValidation(molecule: self, delegate: delegateObject?.formValidationProtocol) + + groupName = model.groupName + fieldValue = model.value + isRequired = model.required + + if let fieldKey = model.fieldKey { + self.fieldKey = fieldKey + } + + borderColor = model.borderColor.uiColor + borderWidth = model.borderWidth + + checkColor = model.checkColor.uiColor + unCheckedBackgroundColor = model.unCheckedBackgroundColor.uiColor + checkedBackgroundColor = model.checkedBackgroundColor.uiColor + disabledCheckColor = model.disabledCheckColor.uiColor + disabledBorderColor = model.disabledBorderColor.uiColor + disabledBackgroundColor = model.disabledBackgroundColor.uiColor + + isAnimated = model.isAnimated + isRound = model.isRound + + if model.isChecked { + checkAndBypassAnimations(selected: model.isChecked) + } + + isEnabled = model.isEnabled + + if let action = model.action { + actionBlock = { + if let actionMap = action.toJSON() { + MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) + } + } + } + } } // MARK:- FormValidationProtocol diff --git a/MVMCoreUI/Atoms/Views/CheckboxLabelModel.swift b/MVMCoreUI/Atoms/Views/CheckboxLabelModel.swift new file mode 100644 index 00000000..5a9d09f0 --- /dev/null +++ b/MVMCoreUI/Atoms/Views/CheckboxLabelModel.swift @@ -0,0 +1,24 @@ +// +// CheckboxWithLabelViewModel.swift +// MVMCoreUI +// +// Created by Chintakrinda, Arun Kumar (Arun) on 21/01/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public enum CheckboxPosition: String, Codable { + case center + case top + case bottom +} + +@objcMembers public class CheckboxLabelModel: MoleculeModelProtocol { + public static var identifier: String = "checkboxLabel" + public var backgroundColor: Color? + + public var checkboxAlignment: CheckboxPosition? + public var checkbox: CheckboxModel + public var label: LabelModel +} diff --git a/MVMCoreUI/Atoms/Views/CheckboxModel.swift b/MVMCoreUI/Atoms/Views/CheckboxModel.swift new file mode 100644 index 00000000..aa5dedb4 --- /dev/null +++ b/MVMCoreUI/Atoms/Views/CheckboxModel.swift @@ -0,0 +1,106 @@ +// +// CheckboxModel.swift +// MVMCoreUI +// +// Created by Chintakrinda, Arun Kumar (Arun) on 21/01/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers public class CheckboxModel: MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public static var identifier: String = "checkbox" + public var backgroundColor: Color? + + public var groupName: String? + public var value: String? + public var fieldKey: String? + public var required: Bool = false + public var borderColor: Color = Color(uiColor: .black) + public var borderWidth: CGFloat = 1 + public var isChecked: Bool = false + public var checkColor: Color = Color(uiColor: .black) + public var unCheckedBackgroundColor: Color = Color(uiColor: .clear) + public var checkedBackgroundColor: Color = Color(uiColor: .clear) + public var isAnimated: Bool = true + public var isRound: Bool = false + public var isEnabled: Bool = true + public var action: ActionModelProtocol? + public var disabledBackgroundColor: Color = Color(uiColor: .clear) + public var disabledBorderColor: Color = Color(uiColor: .mvmCoolGray3) + public var disabledCheckColor: Color = Color(uiColor: .mvmCoolGray3) + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case groupName + case value + case fieldKey + case required + case borderColor + case borderWidth + case isChecked + case checkColor + case unCheckedBackgroundColor + case checkedBackgroundColor + case disabledBackgroundColor + case disabledCheckColor + case disabledBorderColor + case isAnimated + case isRound + case isEnabled + case action + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) + value = try typeContainer.decodeIfPresent(String.self, forKey: .value) + fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey) + required = try typeContainer.decodeIfPresent(Bool.self, forKey: .required) ?? false + borderWidth = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .borderWidth) ?? 1 + borderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .borderColor) ?? Color(uiColor: .black) + checkColor = try typeContainer.decodeIfPresent(Color.self, forKey: .checkColor) ?? Color(uiColor: .black) + unCheckedBackgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .unCheckedBackgroundColor) ?? Color(uiColor: .clear) + checkedBackgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .checkedBackgroundColor) ?? Color(uiColor: .clear) + disabledBackgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledBackgroundColor) ?? Color(uiColor: .clear) + disabledBorderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledBorderColor) ?? Color(uiColor: .mvmCoolGray3) + disabledCheckColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledCheckColor) ?? Color(uiColor: .mvmCoolGray3) + isChecked = try typeContainer.decodeIfPresent(Bool.self, forKey: .isChecked) ?? false + isAnimated = try typeContainer.decodeIfPresent(Bool.self, forKey: .isAnimated) ?? true + isRound = try typeContainer.decodeIfPresent(Bool.self, forKey: .isRound) ?? false + isEnabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .isEnabled) ?? true + action = try typeContainer.decodeModelIfPresent(codingKey: .action, typeCodingKey: ActionCodingKey.actionType) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(groupName, forKey: .groupName) + try container.encodeIfPresent(value, forKey: .value) + try container.encodeIfPresent(fieldKey, forKey: .fieldKey) + try container.encodeIfPresent(required, forKey: .required) + try container.encodeIfPresent(borderColor, forKey: .borderColor) + try container.encode(borderWidth, forKey: .borderWidth) + try container.encode(isChecked, forKey: .isChecked) + try container.encodeIfPresent(checkColor, forKey: .checkColor) + try container.encodeIfPresent(unCheckedBackgroundColor, forKey: .unCheckedBackgroundColor) + try container.encodeIfPresent(checkedBackgroundColor, forKey: .checkedBackgroundColor) + try container.encodeIfPresent(disabledBorderColor, forKey: .disabledBorderColor) + try container.encodeIfPresent(disabledBackgroundColor, forKey: .disabledBackgroundColor) + try container.encodeIfPresent(disabledCheckColor, forKey: .disabledCheckColor) + try container.encodeIfPresent(isAnimated, forKey: .isAnimated) + try container.encodeIfPresent(isRound, forKey: .isRound) + try container.encodeIfPresent(isEnabled, forKey: .isEnabled) + try container.encodeModelIfPresent(action, forKey: .action) + } +} diff --git a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift index 229efe2a..bc23db73 100644 --- a/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift +++ b/MVMCoreUI/Atoms/Views/CheckboxWithLabelView.swift @@ -21,12 +21,6 @@ public var checkboxPosition: CheckboxPosition = .center - public enum CheckboxPosition: String { - case center - case top - case bottom - } - //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- @@ -120,6 +114,17 @@ checkboxCenterYConstraint?.isActive = false } } + + open override func setWithModel(_ model: MoleculeModelProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + guard let checkBoxWithLabelModel = model as? CheckboxLabelModel else { return } + + if let checkboxAlignment = checkBoxWithLabelModel.checkboxAlignment { + alignCheckbox(checkboxAlignment) + } + + checkbox.setWithModel(checkBoxWithLabelModel.checkbox, delegateObject, additionalData) + label.setWithModel(checkBoxWithLabelModel.label, delegateObject, additionalData) + } } // MARK: - Molecular diff --git a/MVMCoreUI/Atoms/Views/DashLine.swift b/MVMCoreUI/Atoms/Views/DashLine.swift index dcfc4270..cbee1eb8 100644 --- a/MVMCoreUI/Atoms/Views/DashLine.swift +++ b/MVMCoreUI/Atoms/Views/DashLine.swift @@ -19,8 +19,6 @@ open class DashLine: View { get { return model as? DashLineModel } } - // Legacy - @objc public var dashColor: UIColor? @objc private var dashLayer: CAShapeLayer? //------------------------------------------------------ @@ -70,7 +68,7 @@ open class DashLine: View { dashLayer.lineCap = .round dashLayer.lineDashPattern = [NSNumber(value: 2), NSNumber(value: 2)] dashLayer.path = path.cgPath - dashLayer.strokeColor = dashModel?.dashColor.uiColor.cgColor ?? dashColor?.cgColor ?? UIColor.mfLighterGray().cgColor + dashLayer.strokeColor = dashModel?.dashColor.cgColor dashLayer.fillColor = UIColor.clear.cgColor dashLayer.backgroundColor = backgroundColor?.cgColor ?? UIColor.white.cgColor self.dashLayer = dashLayer @@ -81,7 +79,7 @@ open class DashLine: View { //------------------------------------------------------ // Default values for view. - @objc open override func setAsMolecule() { + @objc open override func reset() { backgroundColor = .clear isHidden = false } diff --git a/MVMCoreUI/Atoms/Views/Label/Label.swift b/MVMCoreUI/Atoms/Views/Label/Label.swift index b2953227..208676df 100644 --- a/MVMCoreUI/Atoms/Views/Label/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label/Label.swift @@ -315,7 +315,7 @@ public typealias ActionBlock = () -> () } case let actionAtt as LabelAttributeActionModel: addTappableLinkAttribute(range: NSRange(location: range.location, length: range.length)) { - if let data = try? actionAtt.encode(using: JSONEncoder()), let actionMap = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.init()) as? [AnyHashable: Any] { + if let data = try? actionAtt.action.encode(using: JSONEncoder()), let actionMap = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.init()) as? [AnyHashable: Any] { MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) } } diff --git a/MVMCoreUI/BaseClasses/Button.swift b/MVMCoreUI/BaseClasses/Button.swift index 0c5d4bec..0a382705 100644 --- a/MVMCoreUI/BaseClasses/Button.swift +++ b/MVMCoreUI/BaseClasses/Button.swift @@ -12,8 +12,8 @@ public typealias ButtonAction = (Button) -> () //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - public var model: MoleculeModelProtocol? - public var actionModel: ActionModelProtocol? + open var model: MoleculeModelProtocol? + open var actionModel: ActionModelProtocol? private var initialSetupPerformed = false @@ -23,7 +23,7 @@ public typealias ButtonAction = (Button) -> () // MARK: - Delegate //-------------------------------------------------- - public weak var buttonDelegate: ButtonDelegateProtocol? + open weak var buttonDelegate: ButtonDelegateProtocol? //-------------------------------------------------- // MARK: - Initializers @@ -48,6 +48,7 @@ public typealias ButtonAction = (Button) -> () // MARK: - Setup //-------------------------------------------------- + /// Required to be called any init. Ensures setupView() only gets called once public func initialSetup() { if !initialSetupPerformed { @@ -60,16 +61,17 @@ public typealias ButtonAction = (Button) -> () // MARK: - Methods //-------------------------------------------------- - public func addActionBlock( event: Event, _ buttonBlock: @escaping ButtonAction) { + /// Adds a block to be performed for the given event. + open func addActionBlock(event: Event, _ buttonBlock: @escaping ButtonAction) { self.buttonAction = buttonBlock addTarget(self, action: #selector(callActionBlock(_:)), for: event) } - func callActionBlock(_ sender: Button) { + @objc private func callActionBlock(_ sender: Button) { buttonAction?(self) } - public func set(with actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + open func set(with actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { self.actionModel = actionModel buttonDelegate = delegateObject?.buttonDelegate @@ -104,14 +106,13 @@ public typealias ButtonAction = (Button) -> () } } - // MARK: - MVMCoreViewProtocol extension Button: MVMCoreViewProtocol { - public func updateView(_ size: CGFloat) {} + open func updateView(_ size: CGFloat) {} /// Will be called only once. - public func setupView() { + open func setupView() { translatesAutoresizingMaskIntoConstraints = false insetsLayoutMarginsFromSafeArea = false titleLabel?.numberOfLines = 0 @@ -121,7 +122,7 @@ extension Button: MVMCoreViewProtocol { // MARK: - MVMCoreUIMoleculeViewProtocol extension Button: MVMCoreUIMoleculeViewProtocol { - public func reset() { + open func reset() { backgroundColor = .clear } } diff --git a/MVMCoreUI/BaseClasses/Control.swift b/MVMCoreUI/BaseClasses/Control.swift index ed1c1874..d73e0fef 100644 --- a/MVMCoreUI/BaseClasses/Control.swift +++ b/MVMCoreUI/BaseClasses/Control.swift @@ -13,7 +13,7 @@ import UIKit // MARK: - Properties //-------------------------------------------------- open var json: [AnyHashable: Any]? - public var model: MoleculeModelProtocol? + open var model: MoleculeModelProtocol? private var initialSetupPerformed = false @@ -78,10 +78,10 @@ extension Control: AppleGuidelinesProtocol { // MARK: - MVMCoreViewProtocol extension Control: MVMCoreViewProtocol { - public func updateView(_ size: CGFloat) {} + open func updateView(_ size: CGFloat) {} /// Will be called only once. - public func setupView() { + open func setupView() { translatesAutoresizingMaskIntoConstraints = false insetsLayoutMarginsFromSafeArea = false } @@ -97,7 +97,7 @@ extension Control: MVMCoreUIMoleculeViewProtocol { } } - public func reset() { + open func reset() { backgroundColor = .clear } } diff --git a/MVMCoreUI/Containers/Container.swift.orig b/MVMCoreUI/Containers/Container.swift.orig deleted file mode 100644 index f5ef4a69..00000000 --- a/MVMCoreUI/Containers/Container.swift.orig +++ /dev/null @@ -1,265 +0,0 @@ -// -// Container.swift -// MVMCoreUI -// -// Created by Scott Pfeil on 12/11/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -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? - var bottomConstraint: NSLayoutConstraint? - var rightConstraint: NSLayoutConstraint? - - var alignCenterHorizontalConstraint: NSLayoutConstraint? - var alignCenterLeftConstraint: NSLayoutConstraint? - var alignCenterRightConstraint: NSLayoutConstraint? - - var alignCenterVerticalConstraint: NSLayoutConstraint? - var alignCenterTopConstraint: NSLayoutConstraint? - var alignCenterBottomConstraint: NSLayoutConstraint? - - var leftLowConstraint: NSLayoutConstraint? - var topLowConstraint: NSLayoutConstraint? - var bottomLowConstraint: NSLayoutConstraint? - var rightLowConstraint: NSLayoutConstraint? - - func constrainView(_ view: UIView) { - guard let margins = view.superview?.layoutMarginsGuide else { return } - leftConstraint = view.leftAnchor.constraint(equalTo: margins.leftAnchor) - leftConstraint?.isActive = true - - topConstraint = view.topAnchor.constraint(equalTo: margins.topAnchor) - topConstraint?.isActive = true - - rightConstraint = margins.rightAnchor.constraint(equalTo: view.rightAnchor) - rightConstraint?.isActive = true - - bottomConstraint = margins.bottomAnchor.constraint(equalTo: view.bottomAnchor) - bottomConstraint?.isActive = true - - alignCenterHorizontalConstraint = view.centerXAnchor.constraint(equalTo: margins.centerXAnchor) - alignCenterLeftConstraint = view.leftAnchor.constraint(greaterThanOrEqualTo: margins.leftAnchor) - alignCenterRightConstraint = margins.rightAnchor.constraint(greaterThanOrEqualTo: view.rightAnchor) - - alignCenterVerticalConstraint = view.centerYAnchor.constraint(equalTo: margins.centerYAnchor) - alignCenterTopConstraint = view.topAnchor.constraint(greaterThanOrEqualTo: margins.topAnchor) - alignCenterBottomConstraint = margins.bottomAnchor.constraint(greaterThanOrEqualTo: view.bottomAnchor) - - leftLowConstraint = view.leftAnchor.constraint(equalTo: margins.leftAnchor) - leftLowConstraint?.priority = UILayoutPriority(rawValue: 200) - leftLowConstraint?.isActive = true - - topLowConstraint = view.topAnchor.constraint(equalTo: margins.topAnchor) - topLowConstraint?.priority = UILayoutPriority(rawValue: 200) - topLowConstraint?.isActive = true - - rightLowConstraint = margins.rightAnchor.constraint(equalTo: view.rightAnchor) - rightLowConstraint?.priority = UILayoutPriority(rawValue: 200) - rightLowConstraint?.isActive = true - - bottomLowConstraint = margins.bottomAnchor.constraint(equalTo: view.bottomAnchor) - bottomLowConstraint?.priority = UILayoutPriority(rawValue: 200) - bottomLowConstraint?.isActive = true - - setAccessibility(view) - } - - func setAccessibility(_ view: UIView) { - guard let superView = view.superview else { return } - superView.isAccessibilityElement = false - if let elements = view.accessibilityElements { - superView.accessibilityElements = elements - } else { - superView.accessibilityElements = [view] - } - } - - func alignHorizontal(_ alignment: UIStackView.Alignment) { - switch alignment { - case .center: - alignCenterHorizontalConstraint?.isActive = true - alignCenterLeftConstraint?.isActive = true - alignCenterRightConstraint?.isActive = true - leftConstraint?.isActive = false - rightConstraint?.isActive = false - case .leading: - alignCenterHorizontalConstraint?.isActive = false - alignCenterLeftConstraint?.isActive = false - alignCenterRightConstraint?.isActive = true - leftConstraint?.isActive = true - rightConstraint?.isActive = false - case .trailing: - alignCenterHorizontalConstraint?.isActive = false - alignCenterLeftConstraint?.isActive = true - alignCenterRightConstraint?.isActive = false - leftConstraint?.isActive = false - rightConstraint?.isActive = true - case .fill: - alignCenterHorizontalConstraint?.isActive = false - alignCenterLeftConstraint?.isActive = false - alignCenterRightConstraint?.isActive = false - leftConstraint?.isActive = true - rightConstraint?.isActive = true - default: break - } - } - - func alignVertical(_ alignment: UIStackView.Alignment) { - switch alignment { - case .center: - alignCenterVerticalConstraint?.isActive = true - alignCenterTopConstraint?.isActive = true - alignCenterBottomConstraint?.isActive = true - topConstraint?.isActive = false - bottomConstraint?.isActive = false - case .leading: - alignCenterVerticalConstraint?.isActive = false - alignCenterTopConstraint?.isActive = false - alignCenterBottomConstraint?.isActive = true - topConstraint?.isActive = true - bottomConstraint?.isActive = false - case .trailing: - alignCenterVerticalConstraint?.isActive = false - alignCenterTopConstraint?.isActive = true - alignCenterBottomConstraint?.isActive = false - topConstraint?.isActive = false - bottomConstraint?.isActive = true - case .fill: - alignCenterVerticalConstraint?.isActive = false - alignCenterTopConstraint?.isActive = false - alignCenterBottomConstraint?.isActive = false - topConstraint?.isActive = true - bottomConstraint?.isActive = true - default: break - } - } - - 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": - return .leading - case "trailing": - return .trailing - case "center": - return .center - case "fill": - return .fill - default: - return nil - } - } - - static func getAlignmentString(for alignment: UIStackView.Alignment?) -> String? { - switch alignment { - case .leading: - return "leading" - case .trailing: - return "trailing" - case .center: - return "center" - case .fill: - return "fill" - default: - return nil - } - } - - func 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) - } else if let alignment = (contained as? MVMCoreUIViewConstrainingProtocol)?.horizontalAlignment?() { - alignHorizontal(alignment) - } - - if let verticalAlignmentString = JSON?.optionalStringForKey("verticalAlignment"), let alignment = ContainerHelper.getAlignment(for: verticalAlignmentString) ?? (contained as? MVMCoreUIViewConstrainingProtocol)?.verticalAlignment?() { - alignVertical(alignment) - } else if let alignment = (contained as? MVMCoreUIViewConstrainingProtocol)?.verticalAlignment?() { - alignVertical(alignment) - } - } -} - -open class Container: View { -<<<<<<< HEAD -======= - var containerModel: ContainerModelProtocol? ->>>>>>> e36d487d326f710d7302c6d9bcb758d209ad329c - var view: UIView? - let containerHelper = ContainerHelper() - var containerModel: ContainerModelProtocol? { - get { return model as? ContainerModelProtocol } - } - var topMarginPadding: CGFloat = 0 - var bottomMarginPadding: CGFloat = 0 - - override open func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { - super.setWithModel(model, delegateObject, additionalData) - guard let containerModel = model as? ContainerModelProtocol else { return } - containerHelper.set(with: containerModel) - } -} - -// MARK: - MVMCoreViewProtocol -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) - } - - /// Will be called only once. - override func setupView() { - super.setupView() - backgroundColor = .clear - } - - func addAndContain(_ view: UIView) { - view.translatesAutoresizingMaskIntoConstraints = false - addSubview(view) - containerHelper.constrainView(view) - self.view = view - } - - convenience init(andContain view: UIView) { - self.init() - addAndContain(view) - } -} - -// MARK: - MVMCoreUIMoleculeViewProtocol -public extension Container { - override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - guard let view = view else { return } - containerHelper.set(with: json, for: view) - } - - override func reset() { - super.reset() - (view as? MVMCoreUIMoleculeViewProtocol)?.reset?() - } - - func setAsMolecule() { - (view as? MVMCoreUIMoleculeViewProtocol)?.setAsMolecule?() - } -} diff --git a/MVMCoreUI/Containers/views/EntryFieldContainer.swift b/MVMCoreUI/Containers/views/EntryFieldContainer.swift deleted file mode 100644 index 96a51a8f..00000000 --- a/MVMCoreUI/Containers/views/EntryFieldContainer.swift +++ /dev/null @@ -1,285 +0,0 @@ -// -// EntryFieldContainer.swift -// MVMCoreUI -// -// Created by Kevin Christiano on 11/12/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import UIKit - - -@objcMembers open class EntryFieldContainer: View { - //-------------------------------------------------- - // MARK: - Drawing Properties - //-------------------------------------------------- - - /// The bottom border line. Height is dynamic based on scenario. - public var bottomBar: CAShapeLayer? = { - let layer = CAShapeLayer() - layer.backgroundColor = UIColor.black.cgColor - layer.drawsAsynchronously = true - layer.anchorPoint = CGPoint(x: 0.5, y: 1.0); - return layer - }() - - /// Total control over the drawn top, bottom, left and right borders. - public var disableAllBorders = false { - didSet { - bottomBar?.isHidden = disableAllBorders - } - } - - private(set) var fieldState: FieldState = .original { - didSet (oldState) { - // Will not update if new state is the same as old. - if fieldState != oldState { - DispatchQueue.main.async { [weak self] in - guard let self = self else { return } - - self.fieldState.setStateUI(for: self) - } - } - } - } - - /// Determines if the top, left, and right borders should be drawn. - private var hideBorders = false - - public var borderStrokeColor: UIColor = .mfSilver() - private var borderPath: UIBezierPath = UIBezierPath() - - //-------------------------------------------------- - // MARK: - Property Observers - //-------------------------------------------------- - - private var _isEnabled: Bool = true - private var _showError: Bool = false - private var _isLocked: Bool = false - private var _isSelected: Bool = false - - public var isEnabled: Bool { - get { return _isEnabled } - set (enabled) { - - _isEnabled = enabled - _isLocked = false - _isSelected = false - _showError = false - - fieldState = enabled ? .original : .disabled - } - } - - public var showError: Bool { - get { return _showError } - set (error) { - - _showError = error - _isEnabled = true - _isLocked = false - _isSelected = false - - fieldState = error ? .error : .original - } - } - - public var isLocked: Bool { - get { return _isLocked } - set (locked) { - - _isLocked = locked - _isEnabled = true - _isSelected = false - _showError = false - - fieldState = locked ? .locked : .original - } - } - - public var isSelected: Bool { - get { return _isSelected } - set (selected) { - - _isSelected = selected - _isLocked = false - _isEnabled = true - - if _showError { - fieldState = selected ? .selectedError : .error - } else { - fieldState = selected ? .selected : .original - } - } - } - - //-------------------------------------------------- - // MARK: - Delegate - //-------------------------------------------------- - - /// Holds reference to delegateObject to inform molecular tableView of an update. - weak var delegateObject: MVMCoreUIDelegateObject? - - //-------------------------------------------------- - // MARK: - Lifecycle - //-------------------------------------------------- - - open override func layoutSubviews() { - super.layoutSubviews() - - refreshUI(bottomBarSize: showError ? 4 : 1) - } - - open override func updateView(_ size: CGFloat) { - super.updateView(size) - - refreshUI() - } - - /// This handles the top, left, and right border lines. - open override func draw(_ rect: CGRect) { - super.draw(rect) - - borderPath.removeAllPoints() - - if !disableAllBorders && !hideBorders { - // Brings the other half of the line inside the view to prevent cropping. - let origin = bounds.origin - let size = frame.size - let insetLean: CGFloat = 0.5 - borderPath.lineWidth = 1 - - borderPath.move(to: CGPoint(x: origin.x + insetLean, y: origin.y + size.height)) - borderPath.addLine(to: CGPoint(x: origin.x + insetLean, y: origin.y + insetLean)) - borderPath.addLine(to: CGPoint(x: origin.x + size.width - insetLean, y: origin.y + insetLean)) - borderPath.addLine(to: CGPoint(x: origin.x + size.width - insetLean, y: origin.y + size.height)) - - borderStrokeColor.setStroke() - borderPath.stroke() - } - } - - override open func setupView() { - super.setupView() - - isAccessibilityElement = false - isOpaque = false - - if let bottomBar = bottomBar { - layer.addSublayer(bottomBar) - } - } - - //-------------------------------------------------- - // MARK: - Draw States - //-------------------------------------------------- - - public enum FieldState { - case original - case error - case selectedError - case selected - case locked - case disabled - - public func setStateUI(for formField: EntryFieldContainer) { - - switch self { - case .original: - formField.originalUI() - - case .error: - formField.errorUI() - - case .selectedError: - formField.selectedErrorUI() - - case .selected: - formField.selectedUI() - - case .locked: - formField.lockedUI() - - case .disabled: - formField.disabledUI() - } - } - } - - open func originalUI() { - - isUserInteractionEnabled = true - hideBorders = false - borderStrokeColor = .mfSilver() - bottomBar?.backgroundColor = UIColor.black.cgColor - refreshUI(bottomBarSize: 1) - } - - open func errorUI() { - - isUserInteractionEnabled = true - hideBorders = false - borderStrokeColor = .mfPumpkin() - bottomBar?.backgroundColor = UIColor.mfPumpkin().cgColor - refreshUI(bottomBarSize: 4) - } - - open func selectedErrorUI() { - - isUserInteractionEnabled = true - hideBorders = false - borderStrokeColor = .black - bottomBar?.backgroundColor = UIColor.mfPumpkin().cgColor - refreshUI(bottomBarSize: 4) - } - - open func selectedUI() { - - isUserInteractionEnabled = true - hideBorders = false - borderStrokeColor = .black - bottomBar?.backgroundColor = UIColor.black.cgColor - refreshUI(bottomBarSize: 1) - } - - open func lockedUI() { - - isUserInteractionEnabled = false - hideBorders = true - borderStrokeColor = .clear - bottomBar?.backgroundColor = UIColor.clear.cgColor - refreshUI(bottomBarSize: 1) - } - - open func disabledUI() { - - isUserInteractionEnabled = false - hideBorders = false - borderStrokeColor = .mfSilver() - bottomBar?.backgroundColor = UIColor.mfSilver().cgColor - refreshUI(bottomBarSize: 1) - } - - open func refreshUI(bottomBarSize: CGFloat? = nil) { - - if !disableAllBorders { - let size: CGFloat = bottomBarSize ?? (showError ? 4 : 1) - bottomBar?.frame = CGRect(x: 0, y: bounds.height - size, width: bounds.width, height: size) - - delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self) - setNeedsDisplay() - layoutIfNeeded() - } - } -} - -// MARK:- MVMCoreUIMoleculeViewProtocol -extension EntryFieldContainer { - - override open func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - self.delegateObject = delegateObject - - guard let dictionary = json, !dictionary.isEmpty else { return } - } -} diff --git a/MVMCoreUI/Models/Molecules/FooterModel.swift.orig b/MVMCoreUI/Models/Molecules/FooterModel.swift.orig deleted file mode 100644 index 077c6b8c..00000000 --- a/MVMCoreUI/Models/Molecules/FooterModel.swift.orig +++ /dev/null @@ -1,37 +0,0 @@ -// -// FooterModel.swift -// MVMCoreUI -// -// Created by Suresh, Kamlesh on 11/27/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import Foundation - - -@objcMembers public class FooterModel: MoleculeContainerModel, MoleculeProtocol { - public static var identifier: String = "footer" - public var backgroundColor: Color? - - enum FooterCodingKeys: String, CodingKey { - case backgroundColor - } - - required public init(from decoder: Decoder) throws { -<<<<<<< HEAD - let typeContainer = try decoder.container(keyedBy: FooterCodingKeys.self) - backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) - try super.init(from: decoder) -======= - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - self.backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) - self.molecule = try typeContainer.decodeMolecule(codingKey: .molecule) ->>>>>>> 83b0a554049f764888ce9db27dbd7fa503fddf01 - } - - public override func encode(to encoder: Encoder) throws { - try super.encode(to: encoder) - var container = encoder.container(keyedBy: FooterCodingKeys.self) - try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) - } -} diff --git a/MVMCoreUI/Molecules/Items/StackItem.swift.orig b/MVMCoreUI/Molecules/Items/StackItem.swift.orig deleted file mode 100644 index 10288002..00000000 --- a/MVMCoreUI/Molecules/Items/StackItem.swift.orig +++ /dev/null @@ -1,100 +0,0 @@ -// -// StackItem.swift -// MVMCoreUI -// -// Created by Scott Pfeil on 12/13/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -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 - -<<<<<<< HEAD - 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) -======= - init(with view: StackItem) { - self.view = view - view.containerModel = self - } - - init(with view: StackItem, json: [AnyHashable: Any]?) { - self.view = view - view.containerModel = self - update(with: json) ->>>>>>> e36d487d326f710d7302c6d9bcb758d209ad329c - } - - 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 { - - -} diff --git a/MVMCoreUI/Molecules/Items/TableViewCell.swift b/MVMCoreUI/Molecules/Items/TableViewCell.swift index 9daec27d..cd8a3cdf 100644 --- a/MVMCoreUI/Molecules/Items/TableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/TableViewCell.swift @@ -137,6 +137,7 @@ import UIKit open func setupView() { selectionStyle = .none insetsLayoutMarginsFromSafeArea = false + preservesSuperviewLayoutMargins = false contentView.insetsLayoutMarginsFromSafeArea = false contentView.preservesSuperviewLayoutMargins = false } diff --git a/MVMCoreUI/Molecules/ModuleMolecule.swift.orig b/MVMCoreUI/Molecules/ModuleMolecule.swift.orig deleted file mode 100644 index d350171a..00000000 --- a/MVMCoreUI/Molecules/ModuleMolecule.swift.orig +++ /dev/null @@ -1,116 +0,0 @@ -// -// ModuleMolecule.swift -// MVMCoreUI -// -// Created by Scott Pfeil on 6/25/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import UIKit - -open class ModuleMoleculeModel: ContainerModelProtocol { - 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 { -<<<<<<< HEAD - var moduleMoleculeModel: ModuleMoleculeModel? { - get { return model as? ModuleMoleculeModel } -======= - public override func setupView() { - super.setupView() - containerModel = ModuleMoleculeModel() ->>>>>>> e36d487d326f710d7302c6d9bcb758d209ad329c - } - - open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { - #warning("need to change getter to get moduleModel instead to use.") - super.setWithModel(model, delegateObject, additionalData) - } - - // MARK: - MVMCoreUIMoleculeViewProtocol - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - - guard let moduleName = json?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { - // Critical error - return - } - - if view == nil { - if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: module, delegateObject: delegateObject, constrainIfNeeded: false) { - addAndContain(moleculeView) - } - } else { - (view as? MVMCoreUIMoleculeViewProtocol)?.setWithJSON(module, delegateObject: delegateObject, additionalData: additionalData) - } - } - - public class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - guard let moduleName = json?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { - // Critical error - return 0 - } - return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.estimatedHeight?(forRow: module, delegateObject: delegateObject) ?? 0 - } - - public class func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { - guard let moduleName = molecule?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { - // Critical error - return "moduleMolecule<>" - } - return "moduleMolecule<" + (MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.name?(forReuse: module, delegateObject: delegateObject) ?? module.stringForkey(KeyMoleculeName)) + ">" - } - - public class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { - let moduleName = json?.optionalStringForKey("moduleName") - if moduleName == nil || delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) == nil { - if let errorObject = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess), code: CoreUIErrorCode.ErrorCodeModuleMolecule.rawValue, domain: ErrorDomainNative, location: String(describing: self)) { - error?.pointee = errorObject - MVMCoreUILoggingHandler.shared()?.addError(toLog: errorObject) - } - } - if let moduleName = moduleName { - return [moduleName] - } - return nil - } -} diff --git a/MVMCoreUI/Molecules/StandardHeaderView.swift.orig b/MVMCoreUI/Molecules/StandardHeaderView.swift.orig deleted file mode 100644 index 1eee69b8..00000000 --- a/MVMCoreUI/Molecules/StandardHeaderView.swift.orig +++ /dev/null @@ -1,90 +0,0 @@ -// -// StandardHeaderView.swift -// MVMCoreUI -// -// Created by Scott Pfeil on 2/12/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import UIKit - -public class StandardHeaderView: MoleculeContainer { - var line: Line? - - // MARK: - MVMCoreViewProtocol - open override func updateView(_ size: CGFloat) { - super.updateView(size) - line?.updateView(size) - } - - public override func setupView() { - super.setupView() - topMarginPadding = PaddingDefaultVerticalSpacing - bottomMarginPadding = PaddingDefaultVerticalSpacing - - guard line == nil else { return } - let line = Line() - line.style = .heavy - addSubview(line) - NSLayoutConstraint.pinViewBottom(toSuperview: line, useMargins: false, constant: 0).isActive = true - NSLayoutConstraint.pinViewLeft(toSuperview: line, useMargins: true, constant: 0).isActive = true - NSLayoutConstraint.pinViewRight(toSuperview: line, useMargins: true, constant: 0).isActive = true - self.line = line - } - - // MARK: - MVMCoreUIMoleculeViewProtocol - open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - if let separatorJSON = json?.optionalDictionaryForKey("separator") { - line?.setWithJSON(separatorJSON, delegateObject: delegateObject, additionalData: additionalData) - } - } - -<<<<<<< HEAD - open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { - super.setWithModel(model, delegateObject, additionalData) - - guard let headerModel = model as? HeaderModel else { - return - } - - if let seperatorModel = headerModel.seperator as? LineModel { - line?.setWithJSON(seperatorModel.toJSON(), delegateObject: delegateObject, additionalData: additionalData) - } - } -======= -// open func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) { -// //TODO: Need to create setWithModel in ViewConstraining View -// -// #warning("This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView.") -// //TODO: This below call should be repaced with super.setWithModel once we get rid of ViewConstrainingView. -// setUpWithModel(model, delegateObject, additionalData) -// -// // This molecule will by default handle margins. -// (molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(false) -// (molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(false) -// -// guard let headerModel = model as? HeaderModel else { -// return -// } -// -// if let seperatorModel = headerModel.seperator as? LineModel { -// line?.setWithJSON(seperatorModel.toJSON(), delegateObject: delegateObject, additionalData: additionalData) -// } -// } ->>>>>>> e36d487d326f710d7302c6d9bcb758d209ad329c - - open override func reset() { - super.reset() - line?.style = .heavy - 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 121 - } -} diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadLineBodyCaretLinkImage.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadLineBodyCaretLinkImage.swift index 01325da9..fc19749a 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadLineBodyCaretLinkImage.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadLineBodyCaretLinkImage.swift @@ -7,13 +7,15 @@ // import Foundation -@objcMembers public class HeadLineBodyCaretLinkImage: View { - +@objcMembers public class HeadLineBodyCaretLinkImage: Container { let headlineBody = HeadlineBody(frame: .zero) let caretButton = CaretButton(frame: .zero) - let backgroundImageView = MFLoadImageView() + let backgroundImageView = MFLoadImageView(pinnedEdges: .all) var spaceBetweenConstant: CGFloat = 104.0 - let maxWidth : CGFloat = 350.0 + let maxWidth: CGFloat = 350.0 + static let heightConstant: CGFloat = 320.0 + var heightConstraint: NSLayoutConstraint? + // MARK: - MVMCoreViewProtocol open override func updateView(_ size: CGFloat) { super.updateView(size) @@ -29,25 +31,28 @@ import Foundation guard subviews.count == 0 else { return } - let view = MVMCoreUICommonViewsUtility.commonView() - addSubview(view) - NSLayoutConstraint.constraintPinSubview(toSuperview: view) - view.addSubview(headlineBody) - view.addSubview(caretButton) + heightConstraint = heightAnchor.constraint(equalToConstant: Self.heightConstant) + heightConstraint?.isActive = true + + let container = MVMCoreUICommonViewsUtility.commonView() + addAndContain(container) + + container.addSubview(headlineBody) + container.addSubview(caretButton) //Headline view - headlineBody.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true - headlineBody.topAnchor.constraint(equalTo: view.topAnchor, constant: PaddingDefault).isActive = true + headlineBody.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true + headlineBody.topAnchor.constraint(equalTo: container.topAnchor, constant: 0).isActive = true - let headLineBodyWidth = headlineBody.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.85) + let headLineBodyWidth = headlineBody.widthAnchor.constraint(equalTo: container.widthAnchor, multiplier: 0.85) headLineBodyWidth.priority = .defaultHigh headLineBodyWidth.isActive = true headlineBody.widthAnchor.constraint(lessThanOrEqualToConstant: maxWidth).isActive = true //Caret view caretButton.translatesAutoresizingMaskIntoConstraints = false - caretButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true - view.bottomAnchor.constraint(equalTo: caretButton.bottomAnchor, constant: PaddingDefault).isActive = true + caretButton.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true + container.bottomAnchor.constraint(equalTo: caretButton.bottomAnchor, constant: 0).isActive = true caretButton.topAnchor.constraint(greaterThanOrEqualTo: headlineBody.bottomAnchor, constant: spaceBetweenConstant).isActive = true @@ -56,9 +61,9 @@ import Foundation backgroundImageView.imageView.contentMode = .scaleAspectFill backgroundImageView.alignFillHorizontal() backgroundImageView.alignFillVertical() - view.addSubview(backgroundImageView) + addSubview(backgroundImageView) NSLayoutConstraint.constraintPinSubview(toSuperview: backgroundImageView) - view.sendSubviewToBack(backgroundImageView) + sendSubviewToBack(backgroundImageView) } // MARK: - MVMCoreUIMoleculeViewProtocol @@ -85,6 +90,7 @@ import Foundation guard let model = model as? HeadlineBodyCaretLinkImageModel else { return } headlineBody.setWithModel(model.headlineBody, delegateObject, additionalData) caretButton.setWithModel(model.caretLink, delegateObject, additionalData) + caretButton.isHidden = model.caretLink == nil backgroundImageView.setWithModel(model.image, delegateObject, additionalData) backgroundImageView.alignFillHorizontal() backgroundImageView.alignFillVertical() diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyCaretLinkImageModel.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyCaretLinkImageModel.swift index e57cb369..eb8d7c60 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyCaretLinkImageModel.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyCaretLinkImageModel.swift @@ -8,10 +8,64 @@ import UIKit -public class HeadlineBodyCaretLinkImageModel: MoleculeModelProtocol { +public class HeadlineBodyCaretLinkImageModel: ContainerModel, MoleculeModelProtocol { public static var identifier: String = "headlineBodyCaretLinkImage" public var backgroundColor: Color? public var caretLink: CaretLinkModel? public var headlineBody: HeadlineBodyModel public var image: ImageViewModel + + init(headlineBody: HeadlineBodyModel, image: ImageViewModel) { + self.headlineBody = headlineBody + self.image = image + super.init() + setDefaults() + } + + /// Defaults to set + func setDefaults() { + if useHorizontalMargins == nil { + useHorizontalMargins = true + } + if useVerticalMargins == nil { + useVerticalMargins = true + } + if topMarginPadding == nil { + topMarginPadding = PaddingDefault + } + if bottomMarginPadding == nil { + bottomMarginPadding = PaddingDefault + } + if image.height == nil { + image.height = HeadLineBodyCaretLinkImage.heightConstant + } + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case backgroundColor + case headlineBody + case image + case caretLink + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + headlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .headlineBody) + image = try typeContainer.decode(ImageViewModel.self, forKey: .image) + caretLink = try typeContainer.decodeIfPresent(CaretLinkModel.self, forKey: .caretLink) + 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(HeadlineBodyCaretLinkImageModel.identifier, forKey: .moleculeName) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + try container.encode(headlineBody, forKey: .headlineBody) + try container.encode(image, forKey: .image) + try container.encodeIfPresent(caretLink, forKey: .caretLink) + } } diff --git a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift index f7cf5c57..c53fccd2 100644 --- a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift +++ b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift @@ -44,6 +44,8 @@ import Foundation MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Line.self, viewModelClass: LineModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: GraphView.self, viewModelClass: CircleProgressModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Toggle.self, viewModelClass: ToggleModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Checkbox.self, viewModelClass: CheckboxModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: CheckboxWithLabelView.self, viewModelClass: CheckboxLabelModel.self) // Horizontal Combination Molecules MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: StringAndMoleculeView.self, viewModelClass: StringAndMoleculeModel.self) diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index 26310021..f362e595 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -54,7 +54,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } open override func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer) -> Bool { - let shouldFinish = super.shouldFinishProcessingLoad(loadObject, error: error) + guard super.shouldFinishProcessingLoad(loadObject, error: error) else { return false } // This template requires atleast one of the three layers. if templateModel?.header == nil, templateModel?.molecules?.count ?? 0 == 0, @@ -63,7 +63,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol error.pointee = errorObject return false } - return shouldFinish + return true } open override func newDataBuildScreen() { diff --git a/MVMCoreUI/Utility/NSLayoutConstraintAxis+Extension.swift b/MVMCoreUI/Utility/NSLayoutConstraintAxis+Extension.swift index f989e17b..9e82f9f9 100644 --- a/MVMCoreUI/Utility/NSLayoutConstraintAxis+Extension.swift +++ b/MVMCoreUI/Utility/NSLayoutConstraintAxis+Extension.swift @@ -60,28 +60,18 @@ extension NSLayoutConstraint.Axis: RawRepresentable { } } -@propertyWrapper -public struct Axis { - public var wrappedValue: NSLayoutConstraint.Axis - - public init(wrappedValue value: NSLayoutConstraint.Axis) { - self.wrappedValue = value - } -} - -extension Axis: Codable { +extension NSLayoutConstraint.Axis: Codable { public init(from decoder: Decoder) throws { let typeContainer = try decoder.singleValueContainer() let string = try typeContainer.decode(String.self) guard let axis = NSLayoutConstraint.Axis(rawValue: string) else { throw AxisError.notAnAxis } - wrappedValue = axis + self = axis } public func encode(to encoder: Encoder) throws { - let string = wrappedValue.rawValueString var container = encoder.singleValueContainer() - try container.encode(string) + try container.encode(rawValueString) } } diff --git a/MVMCoreUI/Utility/UIStackViewAlignment+Extension.swift b/MVMCoreUI/Utility/UIStackViewAlignment+Extension.swift index 18afca83..b2c4b82b 100644 --- a/MVMCoreUI/Utility/UIStackViewAlignment+Extension.swift +++ b/MVMCoreUI/Utility/UIStackViewAlignment+Extension.swift @@ -30,6 +30,11 @@ import Foundation try container.encode(alignment.rawValueString, forKey: .alignment) } */ + +enum AlignmentError: Error { + case notAnAlignment +} + extension UIStackView.Alignment: RawRepresentable { init?(rawValue: String) { @@ -70,3 +75,19 @@ extension UIStackView.Alignment: RawRepresentable { } } } + +extension UIStackView.Alignment: Codable { + public init(from decoder: Decoder) throws { + let typeContainer = try decoder.singleValueContainer() + let string = try typeContainer.decode(String.self) + guard let alignment = UIStackView.Alignment(rawValue: string) else { + throw AlignmentError.notAnAlignment + } + self = alignment + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(rawValueString) + } +}