diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index e795475d..66fea82f 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -91,6 +91,7 @@ 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */; }; 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */; }; + 0A69F611241BDEA700F7231B /* RuleAnyRequiredModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */; }; 0A6BF4722360C56C0028F841 /* BaseDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */; }; 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; }; 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; }; @@ -122,6 +123,8 @@ 525019E72406853600EED91C /* ListFourColumnDataUsageDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525019E62406853600EED91C /* ListFourColumnDataUsageDivider.swift */; }; 52B201D224081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B201D024081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift */; }; 52B201D324081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B201D124081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift */; }; + 8D084AD02410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */; }; + 8D084AD22410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D084AD12410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift */; }; 8D24041123E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D24041023E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift */; }; 8D24041523E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D24041423E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift */; }; 8D448E5524050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D448E5424050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift */; }; @@ -450,6 +453,7 @@ 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.swift"; sourceTree = ""; }; 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = ""; }; 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesProtocol.swift; sourceTree = ""; }; + 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyRequiredModel.swift; sourceTree = ""; }; 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseDropdownEntryField.swift; sourceTree = ""; }; 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = ""; }; 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = ""; }; @@ -484,6 +488,8 @@ 525019E62406853600EED91C /* ListFourColumnDataUsageDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListFourColumnDataUsageDivider.swift; sourceTree = ""; }; 52B201D024081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonAndPaymentMethod.swift; sourceTree = ""; }; 52B201D124081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonAndPaymentMethodModel.swift; sourceTree = ""; }; + 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextBodyTextModel.swift; sourceTree = ""; }; + 8D084AD12410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextBodyText.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 = ""; }; 8D448E5424050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextAllTextAndLinksModel.swift; sourceTree = ""; }; @@ -789,6 +795,7 @@ 011D95A0240453D0000E3791 /* RuleEqualsModel.swift */, 011D95A2240453F8000E3791 /* RuleRegexModel.swift */, 011D95A4240455DC000E3791 /* FormGroupRule.swift */, + 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */, ); name = Rules; path = Rules/Rules; @@ -861,6 +868,8 @@ children = ( 8D448E5424050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift */, 52267A0623FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift */, + 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */, + 8D084AD12410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift */, ); path = OneColumn; sourceTree = ""; @@ -1768,6 +1777,7 @@ D28A838123CCB0D800DFE4FC /* AccordionListItemModel.swift in Sources */, DBC4391822442197001AB423 /* CaretView.swift in Sources */, C07065C42395677300FBF997 /* Link.swift in Sources */, + 0A69F611241BDEA700F7231B /* RuleAnyRequiredModel.swift in Sources */, D29770F221F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m in Sources */, D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */, D28A838923CCCFCB00DFE4FC /* LinkModel.swift in Sources */, @@ -1837,6 +1847,7 @@ 94C2D9AB23872EB50006CF46 /* LabelAttributeActionModel.swift in Sources */, 52B201D324081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift in Sources */, D2E2A99A23D8D6B4000B42E6 /* HeadlineBodyButtonModel.swift in Sources */, + 8D084AD22410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift in Sources */, 014AA73123C5059B006F3E93 /* ListPageTemplateModel.swift in Sources */, 017BEB4023620A230024EF95 /* TextFieldModel.swift in Sources */, D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */, @@ -1944,6 +1955,7 @@ D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */, D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */, 522679C223FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinksModel.swift in Sources */, + 8D084AD02410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift in Sources */, 0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */, 8D24041123E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift in Sources */, D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */, diff --git a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift index c8484829..251f5b45 100644 --- a/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift +++ b/MVMCoreUI/Atoms/Views/LabelWithInternalButton.swift @@ -81,7 +81,7 @@ public typealias CoreObjectActionLoadPresentDelegate = MVMCoreActionDelegateProt return NSRange(location: 0, length: frontText?.count ?? 0) } - private var actionRange: NSRange { + public var actionRange: NSRange { return NSRange(location: frontText?.count ?? 0, length: actionText?.count ?? 0) } diff --git a/MVMCoreUI/Atoms/Views/LeftRightLabelModel.swift b/MVMCoreUI/Atoms/Views/LeftRightLabelModel.swift index d7ee1553..44564c93 100644 --- a/MVMCoreUI/Atoms/Views/LeftRightLabelModel.swift +++ b/MVMCoreUI/Atoms/Views/LeftRightLabelModel.swift @@ -8,14 +8,22 @@ import UIKit -@objcMembers public class LeftRightLabelModel: MoleculeModelProtocol { +@objcMembers open class LeftRightLabelModel: MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "leftRightLabelView" public var moleculeName: String? = LeftRightLabelModel.identifier public var backgroundColor: Color? public var leftText: LabelModel public var rightText: LabelModel? - init(_ leftText: LabelModel) { + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + + public init(_ leftText: LabelModel) { self.leftText = leftText } } diff --git a/MVMCoreUI/BaseClasses/TableViewCell.swift b/MVMCoreUI/BaseClasses/TableViewCell.swift index 3154bbb9..ebf25a3c 100644 --- a/MVMCoreUI/BaseClasses/TableViewCell.swift +++ b/MVMCoreUI/BaseClasses/TableViewCell.swift @@ -120,7 +120,7 @@ import UIKit } // MARK: - MFViewProtocol - public func updateView(_ size: CGFloat) { + open func updateView(_ size: CGFloat) { containerHelper.updateViewMargins(self, model: listItemModel, size: size) if accessoryView != nil { @@ -151,7 +151,7 @@ import UIKit } //TODO: ModelProtocol, Change to model - public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { guard let model = model as? ListItemModelProtocol else { return } self.listItemModel = model @@ -176,6 +176,9 @@ import UIKit let backgroundColor = moleculeModel.backgroundColor { self.backgroundColor = backgroundColor.uiColor } + + // align if needed. + containerHelper.set(with: model, for: molecule as? MVMCoreUIViewConstrainingProtocol) } open func reset() { @@ -183,11 +186,11 @@ import UIKit backgroundColor = .white } - public class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { + open class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { return model.moleculeName } - public class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { return nil } diff --git a/MVMCoreUI/BaseControllers/MFViewController+Model.swift b/MVMCoreUI/BaseControllers/MFViewController+Model.swift index e70e68f6..05e506eb 100644 --- a/MVMCoreUI/BaseControllers/MFViewController+Model.swift +++ b/MVMCoreUI/BaseControllers/MFViewController+Model.swift @@ -31,9 +31,10 @@ extension MFViewController: MoleculeDelegateProtocol { return nil } - @objc public func moleculeLayoutUpdated(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) { } + // These are required because swift will call the extension function otherwise. + @objc public func moleculeLayoutUpdated(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) {} - @objc public func addMolecules(_ molecules: [[AnyHashable: Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { } - - @objc public func removeMolecules(_ molecules: [[AnyHashable: Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { } + @objc public func addMolecules(_ molecules: [[AnyHashable: Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) {} + @objc public func addMolecules(_ molecules: [[AnyHashable : Any]], indexPath: IndexPath, animation: UITableView.RowAnimation) {} + @objc public func removeMolecules(_ molecules: [[AnyHashable: Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) {} } diff --git a/MVMCoreUI/Containers/Views/Container/Container.swift b/MVMCoreUI/Containers/Views/Container/Container.swift index 96e6c3e8..a08cd651 100644 --- a/MVMCoreUI/Containers/Views/Container/Container.swift +++ b/MVMCoreUI/Containers/Views/Container/Container.swift @@ -23,15 +23,15 @@ open class Container: View, ContainerProtocol { } // MARK:- ContainerProtocol - public func alignHorizontal(_ alignment: UIStackView.Alignment) { + open func alignHorizontal(_ alignment: UIStackView.Alignment) { containerHelper.alignHorizontal(alignment) } - public func alignVertical(_ alignment: UIStackView.Alignment) { + open func alignVertical(_ alignment: UIStackView.Alignment) { containerHelper.alignVertical(alignment) } - public func constrainView(_ view: UIView) { + open func constrainView(_ view: UIView) { containerHelper.constrainView(view) } } diff --git a/MVMCoreUI/Containers/Views/Container/ContainerHelper.swift b/MVMCoreUI/Containers/Views/Container/ContainerHelper.swift index 77226341..223589fe 100644 --- a/MVMCoreUI/Containers/Views/Container/ContainerHelper.swift +++ b/MVMCoreUI/Containers/Views/Container/ContainerHelper.swift @@ -9,7 +9,7 @@ import Foundation -public class ContainerHelper: NSObject { +open class ContainerHelper: NSObject { var leftConstraint: NSLayoutConstraint? var topConstraint: NSLayoutConstraint? var bottomConstraint: NSLayoutConstraint? @@ -28,7 +28,7 @@ public class ContainerHelper: NSObject { var bottomLowConstraint: NSLayoutConstraint? var rightLowConstraint: NSLayoutConstraint? - func constrainView(_ view: UIView) { + open func constrainView(_ view: UIView) { guard let margins = view.superview?.layoutMarginsGuide else { return } leftConstraint = view.leftAnchor.constraint(equalTo: margins.leftAnchor) leftConstraint?.isActive = true @@ -69,7 +69,7 @@ public class ContainerHelper: NSObject { setAccessibility(view) } - func setAccessibility(_ view: UIView) { + open func setAccessibility(_ view: UIView) { guard let superView = view.superview else { return } superView.isAccessibilityElement = false if let elements = view.accessibilityElements { @@ -79,7 +79,7 @@ public class ContainerHelper: NSObject { } } - func alignHorizontal(_ alignment: UIStackView.Alignment) { + open func alignHorizontal(_ alignment: UIStackView.Alignment) { switch alignment { case .center: alignCenterHorizontalConstraint?.isActive = true @@ -109,7 +109,7 @@ public class ContainerHelper: NSObject { } } - func alignVertical(_ alignment: UIStackView.Alignment) { + open func alignVertical(_ alignment: UIStackView.Alignment) { switch alignment { case .center: alignCenterVerticalConstraint?.isActive = true @@ -139,7 +139,7 @@ public class ContainerHelper: NSObject { } } - static func getAlignment(for string: String) -> UIStackView.Alignment? { + public static func getAlignment(for string: String) -> UIStackView.Alignment? { switch string { case "leading": return .leading @@ -154,7 +154,7 @@ public class ContainerHelper: NSObject { } } - static func getAlignmentString(for alignment: UIStackView.Alignment?) -> String? { + public static func getAlignmentString(for alignment: UIStackView.Alignment?) -> String? { switch alignment { case .leading: return "leading" @@ -169,11 +169,11 @@ public class ContainerHelper: NSObject { } } - func updateViewMargins(_ view: UIView, model: ContainerModelProtocol?, size: CGFloat) { + open func updateViewMargins(_ view: UIView, model: ContainerModelProtocol?, size: CGFloat) { MFStyler.setMarginsFor(view, size: size, defaultHorizontal: model?.useHorizontalMargins ?? false, top: (model?.useVerticalMargins ?? false) ? (model?.topMarginPadding ?? 0) : 0, bottom: (model?.useVerticalMargins ?? false) ? (model?.bottomMarginPadding ?? 0) : 0) } - func set(with model: ContainerModelProtocol, for contained: MVMCoreUIViewConstrainingProtocol?) { + open func set(with model: ContainerModelProtocol, for contained: MVMCoreUIViewConstrainingProtocol?) { if let horizontalAlignment = model.horizontalAlignment ?? contained?.horizontalAlignment?() { alignHorizontal(horizontalAlignment) } @@ -182,7 +182,7 @@ public class ContainerHelper: NSObject { } } - func set(with JSON: [AnyHashable: Any]?, for contained: UIView) { + open 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?() { diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyRequiredModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyRequiredModel.swift new file mode 100644 index 00000000..0eab62a7 --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyRequiredModel.swift @@ -0,0 +1,23 @@ +// +// RuleAnyRequiredModel.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 3/13/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + + +public class RuleAnyRequiredModel: RulesProtocol { + + public static var identifier: String = "anyRequired" + public var type: String = RuleRequiredModel.identifier + public var fields: [String] + + public func isValid(_ formField: FormFieldProtocol) -> Bool { + guard let value = formField.formFieldValue() else { return false } + + return true + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextBodyText.swift b/MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextBodyText.swift new file mode 100644 index 00000000..99bc1a16 --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextBodyText.swift @@ -0,0 +1,35 @@ +// +// ListOneColumnFullWidthTextBodyText.swift +// MVMCoreUI +// +// Created by Kruthika KP on 05/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers open class ListOneColumnFullWidthTextBodyText: TableViewCell { + + //----------------------------------------------------- + // MARK: - Outlets + //----------------------------------------------------- + public var headlineBody = HeadlineBody(frame: .zero) + + //----------------------------------------------------- + // MARK: - View Lifecycle + //----------------------------------------------------- + override open func setupView() { + super.setupView() + addMolecule(headlineBody) + } + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?){ + super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListOneColumnFullWidthTextBodyTextModel else { return } + headlineBody.set(with: model.headlineBody, delegateObject, additionalData) + } + + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return 90 + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextBodyTextModel.swift b/MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextBodyTextModel.swift new file mode 100644 index 00000000..138cc69a --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextBodyTextModel.swift @@ -0,0 +1,43 @@ +// +// ListOneColumnFullWidthTextBodyTextModel.swift +// MVMCoreUI +// +// Created by Kruthika KP on 05/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class ListOneColumnFullWidthTextBodyTextModel: ListItemModel, MoleculeModelProtocol { + public static var identifier: String = "list1CFWBdy" + public var headlineBody: HeadlineBodyModel + + public init(headlineBody: HeadlineBodyModel) { + self.headlineBody = headlineBody + super.init() + } + + // Defaults to set + override public func setDefaults() { + super.setDefaults() + headlineBody.style = "item" + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case headlineBody + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + headlineBody = try typeContainer.decode(HeadlineBodyModel.self, forKey: .headlineBody) + try super.init(from: decoder) + } + + 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(headlineBody, forKey: .headlineBody) + } +} diff --git a/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBodyModel.swift b/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBodyModel.swift index 7f3d52dc..f34e7b94 100644 --- a/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBodyModel.swift +++ b/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBodyModel.swift @@ -14,4 +14,9 @@ public struct ImageHeadlineBodyModel: MoleculeModelProtocol { public var backgroundColor: Color? public var image: ImageViewModel public var headlineBody: HeadlineBodyModel + + public init(image: ImageViewModel, headlineBody: HeadlineBodyModel) { + self.image = image + self.headlineBody = headlineBody + } } diff --git a/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift b/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift index 50288c58..98160441 100644 --- a/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift +++ b/MVMCoreUI/Molecules/HorizontalCombinationViews/TwoButtonView.swift @@ -109,7 +109,9 @@ import UIKit public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) + guard let model = model as? TwoButtonViewModel else { return } + if let secondaryModel = model.secondaryButton { showSecondaryButton() secondaryButton.set(with: secondaryModel, delegateObject, additionalData) diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index f1d3794b..33229092 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -14,18 +14,18 @@ import UIKit // MARK: - MVMCoreUIMoleculeViewProtocol public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { - super.set(with: model, delegateObject, additionalData) - guard let model = model as? MoleculeListItemModel else { return } - - if molecule != nil { - (molecule as? ModelMoleculeViewProtocol)?.set(with: model.molecule, delegateObject, additionalData) - - } else if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(model.molecule, delegateObject, false) { - addMolecule(moleculeView) + guard let castModel = model as? MoleculeListItemModel else { + super.set(with: model, delegateObject, additionalData) + return } - containerHelper.set(with: model, for: molecule as? MVMCoreUIViewConstrainingProtocol) + if molecule != nil { + (molecule as? ModelMoleculeViewProtocol)?.set(with: castModel.molecule, delegateObject, additionalData) + } else if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(castModel.molecule, delegateObject, false) { + addMolecule(moleculeView) + } + super.set(with: model, delegateObject, additionalData) } public override class func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift index d7a08091..0ec98c65 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift @@ -8,7 +8,7 @@ import Foundation -@objcMembers public class HeadlineBodyModel: MoleculeModelProtocol { +@objcMembers open class HeadlineBodyModel: MoleculeModelProtocol { public static var identifier: String = "headlineBody" public var moleculeName: String? = HeadlineBodyModel.identifier public var headline: LabelModel? @@ -19,4 +19,8 @@ import Foundation public init(headline: LabelModel) { self.headline = headline } + + public init(body: LabelModel) { + self.body = body + } } diff --git a/MVMCoreUI/Organisms/Carousel.swift b/MVMCoreUI/Organisms/Carousel.swift index 9e2422e6..ba675adf 100644 --- a/MVMCoreUI/Organisms/Carousel.swift +++ b/MVMCoreUI/Organisms/Carousel.swift @@ -10,13 +10,13 @@ import UIKit open class Carousel: View { - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) + public let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) /// The current index of the collection view. Includes dummy cells when looping. - var currentIndex = 0 + public var currentIndex = 0 /// The index of the page, does not include dummy cells. - var pageIndex: Int { + public var pageIndex: Int { get { return loop ? currentIndex - 2 : currentIndex } @@ -26,7 +26,7 @@ open class Carousel: View { } /// The number of pages that there are. Used for the page control and for calculations. Should not include the looping dummy cells. Be sure to set this if subclassing and not using the molecules. - var numberOfPages = 0 + open var numberOfPages = 0 /// The json for the molecules. var molecules: [MoleculeModelProtocol]? @@ -35,20 +35,20 @@ open class Carousel: View { var itemAlignment = UICollectionView.ScrollPosition.left /// From 0-1. The item width as a percent of the carousel width. - var itemWidthPercent: Float = 1 + public var itemWidthPercent: Float = 1 /// The height of the carousel. Default is 300. - var collectionViewHeight: NSLayoutConstraint? + public var collectionViewHeight: NSLayoutConstraint? /// The view that we use for paging - var pagingView: (UIView & MVMCoreUIPagingProtocol)? + public var pagingView: (UIView & MVMCoreUIPagingProtocol)? /// If the carousel should loop after scrolling past the first and final cells. var loop = false private var dragging = false // For adding pager - private var bottomPin: NSLayoutConstraint? + public var bottomPin: NSLayoutConstraint? // MARK: - MVMCoreViewProtocol open override func setupView() { @@ -230,7 +230,7 @@ open class Carousel: View { } } - func setAccessiblity(_ cell: UICollectionViewCell?, index: Int) { + public func setAccessiblity(_ cell: UICollectionViewCell?, index: Int) { guard let cell = cell else { return } @@ -252,22 +252,22 @@ open class Carousel: View { } extension Carousel: UICollectionViewDelegateFlowLayout { - public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent) return CGSize(width: itemWidth, height: collectionView.bounds.height) } - public func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { + open func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { (cell as? MoleculeCollectionViewCell)?.setPeaking(false, animated: false) } } extension Carousel: UICollectionViewDataSource { - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return molecules?.count ?? 0 } - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let molecule = molecules?[indexPath.row], let moleculeInfo = getMoleculeInfo(with: molecule, delegateObject: nil) else { return UICollectionViewCell() @@ -336,7 +336,7 @@ extension Carousel: UIScrollViewDelegate { handleUserOnBufferCell() } - public func scrollViewDidScroll(_ scrollView: UIScrollView) { + open func scrollViewDidScroll(_ scrollView: UIScrollView) { // Check if the user is dragging the card even further past the next card. checkForDraggingOutOfBounds(scrollView) diff --git a/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift b/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift index d3a2fe80..eb175c3a 100644 --- a/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift +++ b/MVMCoreUI/OtherHandlers/ModelMoleculeDelegateProtocol.swift @@ -20,6 +20,8 @@ public protocol MoleculeDelegateProtocol { /// Asks the delegate to add or remove molecules. //optional func addMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) + func addMolecules(_ molecules: [[AnyHashable : Any]], indexPath: IndexPath, animation: UITableView.RowAnimation) + func removeMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) //optional @@ -36,6 +38,10 @@ extension MoleculeDelegateProtocol { // Do nothing } + public func addMolecules(_ molecules: [[AnyHashable : Any]], indexPath: IndexPath, animation: UITableView.RowAnimation) { + // Do nothing + } + public func removeMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { // Do nothing } diff --git a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift index d6163cec..640dbebe 100644 --- a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift +++ b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift @@ -106,6 +106,7 @@ import Foundation MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListLeftVariableRadioButtonAndPaymentMethod.self, viewModelClass: ListLeftVariableRadioButtonAndPaymentMethodModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListRVWheel.self, viewModelClass: ListRVWheelModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListOneColumnFullWidthTextAllTextAndLinks.self, viewModelClass: ListOneColumnFullWidthTextAllTextAndLinksModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListOneColumnFullWidthTextBodyText.self, viewModelClass: ListOneColumnFullWidthTextBodyTextModel.self) // Designed Section Dividers MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListFourColumnDataUsageDivider.self, viewModelClass: ListFourColumnDataUsageDividerModel.self) @@ -123,6 +124,7 @@ import Foundation // Helper models try? ModelRegistry.register(RuleRequiredModel.self) + try? ModelRegistry.register(RuleAnyRequiredModel.self) try? ModelRegistry.register(RuleAnyValueChangedModel.self) try? ModelRegistry.register(RuleAllValueChangedModel.self) try? ModelRegistry.register(RuleEqualsModel.self) diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index 1ea13b4c..c484fced 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -183,8 +183,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } } - public override func addMolecules(_ molecules: [[AnyHashable: Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { - + open override func addMolecules(_ molecules: [[AnyHashable : Any]], indexPath: IndexPath, animation: UITableView.RowAnimation) { var tmpMolecules = [ListItemModelProtocol & MoleculeModelProtocol]() molecules.forEach { molecule in @@ -194,7 +193,6 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } DispatchQueue.main.async { - guard let indexPath = self.tableView?.indexPath(for: sender) else { return } var indexPaths: [IndexPath] = [] for molecule in tmpMolecules { @@ -212,7 +210,17 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } } - public override func removeMolecules(_ molecules: [[AnyHashable: Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { + open override func addMolecules(_ molecules: [[AnyHashable: Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { + + DispatchQueue.main.async { [weak self] in + guard let indexPath = self?.tableView?.indexPath(for: sender) else { return } + DispatchQueue.global().async { + self?.addMolecules(molecules, indexPath: indexPath, animation: animation) + } + } + } + + open override func removeMolecules(_ molecules: [[AnyHashable: Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { var tmpMolecules = [ListItemModelProtocol & MoleculeModelProtocol]() @@ -240,7 +248,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol view.layoutIfNeeded() } - public func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { + open func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { // This dispatch is needed to fix a race condition that can occur if this function is called during the table setup. DispatchQueue.main.async { @@ -262,7 +270,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } } - public func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { + open func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], sender: UITableViewCell, animation: UITableView.RowAnimation) { var indexPaths: [IndexPath] = [] //TODO: cehck for molecule protocola eqality