diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift index f1fd5fed..a5657dd4 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Checkbox.swift @@ -124,7 +124,7 @@ import MVMCore didSet { if !updateSelectionOnly { layoutIfNeeded() - (model as? CheckboxModel)?.checked = isSelected + (model as? CheckboxModel)?.selected = isSelected shapeLayer?.removeAllAnimations() updateCheckboxUI(isSelected: isSelected, isAnimated: isAnimated) _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) @@ -419,8 +419,8 @@ import MVMCore isAnimated = model.animated isRound = model.round - if model.checked { - checkAndBypassAnimations(selected: model.checked) + if model.selected { + checkAndBypassAnimations(selected: model.selected) } isEnabled = model.enabled diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift index c2d9f14e..c4f69f27 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift @@ -6,10 +6,14 @@ // Copyright © 2020 Verizon Wireless. All rights reserved. // -import Foundation +/// Protocol to apply to any model of a UI Control with a binary on/off nature. +/// +/// Example classes: Checkbox or Toggle. +@objc public protocol SelectableMoleculeModelProtocol { + var selected: Bool { get set } +} - -@objcMembers public class CheckboxModel: MoleculeModelProtocol, FormFieldProtocol { +@objcMembers public class CheckboxModel: MoleculeModelProtocol, SelectableMoleculeModelProtocol, FormFieldProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -17,7 +21,7 @@ import Foundation public static var identifier: String = "checkbox" public var backgroundColor: Color? public var accessibilityIdentifier: String? - public var checked: Bool = false + public var selected: Bool = false public var enabled: Bool = true public var animated: Bool = true public var inverted: Bool = false @@ -66,19 +70,19 @@ import Foundation case groupName case offAction } - + //-------------------------------------------------- - // MARK: - Methods + // MARK: - Form Validation //-------------------------------------------------- - public func formFieldValue() -> AnyHashable? { checked } + public func formFieldValue() -> AnyHashable? { selected } //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- public init(isChecked: Bool = false) { - self.checked = isChecked + self.selected = isChecked baseValue = isChecked } @@ -132,10 +136,10 @@ import Foundation } if let checked = try typeContainer.decodeIfPresent(Bool.self, forKey: .checked) { - self.checked = checked + self.selected = checked } - baseValue = checked + baseValue = selected if let animated = try typeContainer.decodeIfPresent(Bool.self, forKey: .animated) { self.animated = animated @@ -169,7 +173,7 @@ import Foundation try container.encodeIfPresent(fieldKey, forKey: .fieldKey) try container.encodeIfPresent(borderColor, forKey: .borderColor) try container.encode(borderWidth, forKey: .borderWidth) - try container.encode(checked, forKey: .checked) + try container.encode(selected, forKey: .checked) try container.encode(inverted, forKey: .inverted) try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier) try container.encodeIfPresent(checkColor, forKey: .checkColor) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift index 304b23c4..3513a03b 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Toggle.swift @@ -98,7 +98,7 @@ public typealias ActionBlockConfirmation = () -> (Bool) self.constrainKnob() } - toggleModel?.state = isOn + toggleModel?.selected = isOn _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) accessibilityValue = isOn ? MVMCoreUIUtility.hardcodedString(withKey: "AccOn") : MVMCoreUIUtility.hardcodedString(withKey: "AccOff") setNeedsLayout() @@ -381,7 +381,7 @@ public typealias ActionBlockConfirmation = () -> (Bool) containerTintColor.off = model.offTintColor.uiColor knobTintColor.on = model.onKnobTintColor.uiColor knobTintColor.off = model.offKnobTintColor.uiColor - isOn = model.state + isOn = model.selected changeStateNoAnimation(isOn) isAnimated = model.animated isEnabled = model.enabled diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift index 4990df73..5be014fb 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/ToggleModel.swift @@ -15,7 +15,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo public static var identifier: String = "toggle" public var accessibilityIdentifier: String? public var backgroundColor: Color? - public var state: Bool = false + public var selected: Bool = false public var animated: Bool = true public var enabled: Bool = true public var action: ActionModelProtocol? @@ -53,17 +53,17 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo } //-------------------------------------------------- - // MARK: - Methods + // MARK: - Form Valdiation //-------------------------------------------------- - public func formFieldValue() -> AnyHashable? { state } + public func formFieldValue() -> AnyHashable? { selected } //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- public init(_ state: Bool) { - self.state = state + self.selected = state baseValue = state } @@ -75,7 +75,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo let typeContainer = try decoder.container(keyedBy: CodingKeys.self) if let state = try typeContainer.decodeIfPresent(Bool.self, forKey: .state) { - self.state = state + self.selected = state } if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { @@ -109,7 +109,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText) - baseValue = state + baseValue = selected fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey) if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) { self.groupName = groupName @@ -123,7 +123,7 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol, EnableableMo try container.encodeModelIfPresent(action, forKey: .action) try container.encodeModelIfPresent(alternateAction, forKey: .alternateAction) try container.encode(moleculeName, forKey: .moleculeName) - try container.encode(state, forKey: .state) + try container.encode(selected, forKey: .state) try container.encode(animated, forKey: .animated) try container.encode(enabled, forKey: .enabled) try container.encode(onTintColor, forKey: .onTintColor) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift index 5cc07fed..2eec132f 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift @@ -81,7 +81,7 @@ numberOfLines = try typeContainer.decodeIfPresent(Int.self, forKey: .numberOfLines) } - public func encode(to encoder: Encoder) throws { + open func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encodeIfPresent(moleculeName, forKey: .moleculeName) try container.encode(text, forKey: .text) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift index 5076eb9e..633989d5 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableIconWithRightCaretBodyTextModel.swift @@ -7,7 +7,7 @@ // -public class ListLeftVariableIconWithRightCaretBodyTextModel: ListItemModel, MoleculeModelProtocol { +public class ListLeftVariableIconWithRightCaretBodyTextModel: ListItemModel, ParentMoleculeModelProtocol { //----------------------------------------------------- // MARK: - Properties //----------------------------------------------------- @@ -17,6 +17,10 @@ public class ListLeftVariableIconWithRightCaretBodyTextModel: ListItemModel, Mol public var headlineBody: HeadlineBodyModel public var rightLabel: LabelModel + public var children: [MoleculeModelProtocol] { + [image, headlineBody, rightLabel] + } + //----------------------------------------------------- // MARK: - Methods //----------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableRightCaretAlltextAndLinksModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableRightCaretAlltextAndLinksModel.swift index f16daf2b..e2bc1691 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableRightCaretAlltextAndLinksModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableRightCaretAlltextAndLinksModel.swift @@ -7,7 +7,7 @@ // -public class ListRightVariableRightCaretAllTextAndLinksModel: ListItemModel, MoleculeModelProtocol { +public class ListRightVariableRightCaretAllTextAndLinksModel: ListItemModel, ParentMoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -16,6 +16,10 @@ public class ListRightVariableRightCaretAllTextAndLinksModel: ListItemModel, Mol public var rightLabel: LabelModel public var eyebrowHeadlineBodyLink: EyebrowHeadlineBodyLinkModel + public var children: [MoleculeModelProtocol] { + [rightLabel, eyebrowHeadlineBodyLink] + } + //----------------------------------------------------- // MARK: - Methods //----------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabelsModel.swift b/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabelsModel.swift index 76a56178..5c910298 100644 --- a/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabelsModel.swift +++ b/MVMCoreUI/Atomic/Molecules/LeftRightViews/CornerLabelsModel.swift @@ -8,7 +8,7 @@ import UIKit -public class CornerLabelsModel: MoleculeModelProtocol { +public class CornerLabelsModel: ParentMoleculeModelProtocol { public static var identifier: String = "cornerLabels" public var backgroundColor: Color? public var topLeftLabel: LabelModel? @@ -16,7 +16,10 @@ public class CornerLabelsModel: MoleculeModelProtocol { public var bottomLeftLabel: LabelModel? public var bottomRightLabel: LabelModel? public var molecule: MoleculeModelProtocol? - + public var children: [MoleculeModelProtocol] { + [molecule, topLeftLabel, topRightLabel, bottomLeftLabel, bottomRightLabel].compactMap { $0 } + } + init(with molecule: MoleculeModelProtocol?) { self.molecule = molecule } @@ -35,20 +38,20 @@ public class CornerLabelsModel: MoleculeModelProtocol { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) molecule = try typeContainer.decodeModelIfPresent(codingKey: .molecule) - topLeftLabel = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .topLeftLabel) - topRightLabel = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .topRightLabel) - bottomLeftLabel = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .bottomLeftLabel) - bottomRightLabel = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .bottomRightLabel) + topLeftLabel = try typeContainer.decodeMoleculeIfPresent(codingKey: .topLeftLabel) + topRightLabel = try typeContainer.decodeMoleculeIfPresent(codingKey: .topRightLabel) + bottomLeftLabel = try typeContainer.decodeMoleculeIfPresent(codingKey: .bottomLeftLabel) + bottomRightLabel = try typeContainer.decodeMoleculeIfPresent(codingKey: .bottomRightLabel) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeModelIfPresent(molecule, forKey: .molecule) - try container.encodeIfPresent(topLeftLabel, forKey: .topLeftLabel) - try container.encodeIfPresent(topRightLabel, forKey: .topRightLabel) - try container.encodeIfPresent(bottomLeftLabel, forKey: .bottomLeftLabel) - try container.encodeIfPresent(bottomRightLabel, forKey: .bottomRightLabel) + try container.encodeModelIfPresent(topLeftLabel, forKey: .topLeftLabel) + try container.encodeModelIfPresent(topRightLabel, forKey: .topRightLabel) + try container.encodeModelIfPresent(bottomLeftLabel, forKey: .bottomLeftLabel) + try container.encodeModelIfPresent(bottomRightLabel, forKey: .bottomRightLabel) try container.encode(moleculeName, forKey: .moleculeName) } } diff --git a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/ImageBarButtonItem.swift b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/ImageBarButtonItem.swift index 33ed39b8..50676cbc 100644 --- a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/ImageBarButtonItem.swift +++ b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/ImageBarButtonItem.swift @@ -20,16 +20,9 @@ } /// Creates the item with the passed in action. - public static func create(with image: UIImage?, actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Self { + public static func create(with image: UIImage?, model: MoleculeModelProtocol & NavigationButtonModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Self { let button = create(with: image) - button.set(with: actionModel, delegateObject: delegateObject, additionalData: additionalData) - return button - } - - /// Creates the item with the passed in action map. - public static func create(with image: UIImage?, actionMap: [AnyHashable: Any], delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Self { - let button = create(with: image) - button.set(with: actionMap, delegateObject: delegateObject, additionalData: additionalData) + button.set(with: model, delegateObject: delegateObject, additionalData: additionalData) return button } diff --git a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/LabelBarButtonItem.swift b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/LabelBarButtonItem.swift index 5175defe..1eb4c8a1 100644 --- a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/LabelBarButtonItem.swift +++ b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/LabelBarButtonItem.swift @@ -21,16 +21,9 @@ } /// Creates the item with the passed in action. - public static func create(with title: String?, actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Self { + public static func create(with title: String?, model: NavigationLabelButtonModel, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Self { let button = create(with: title) - button.set(with: actionModel, delegateObject: delegateObject, additionalData: additionalData) - return button - } - - /// Creates the item with the passed in action map. - public static func create(with title: String?, actionMap: [AnyHashable : Any], delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Self { - let button = create(with: title) - button.set(with: actionMap, delegateObject: delegateObject, additionalData: additionalData) + button.set(with: model, delegateObject: delegateObject, additionalData: additionalData) return button } diff --git a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationImageButtonModel.swift b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationImageButtonModel.swift index f18c9fa1..8ba75d1a 100644 --- a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationImageButtonModel.swift +++ b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationImageButtonModel.swift @@ -67,7 +67,7 @@ public class NavigationImageButtonModel: NavigationButtonModelProtocol, Molecule /// Convenience function that creates a BarButtonItem for the model. public func createNavigationItemButton(delegateObject: MVMCoreUIDelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) -> UIBarButtonItem { let uiImage = MVMCoreCache.shared()?.getImageFromRegisteredBundles(image) - let buttonItem = ImageBarButtonItem.create(with: uiImage, actionModel: action, delegateObject: delegateObject, additionalData: additionalData) + let buttonItem = ImageBarButtonItem.create(with: uiImage, model: self, delegateObject: delegateObject, additionalData: additionalData) buttonItem.accessibilityIdentifier = accessibilityIdentifier ?? image if let accessibilityString = accessibilityText { buttonItem.accessibilityLabel = accessibilityString diff --git a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationLabelButtonModel.swift b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationLabelButtonModel.swift index e52ea0d5..d72c6ae0 100644 --- a/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationLabelButtonModel.swift +++ b/MVMCoreUI/Atomic/Molecules/NavigationBar/Buttons/NavigationLabelButtonModel.swift @@ -7,16 +7,16 @@ // -public class NavigationLabelButtonModel: NavigationButtonModelProtocol, MoleculeModelProtocol { +open class NavigationLabelButtonModel: NavigationButtonModelProtocol, MoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - public var backgroundColor: Color? - public static var identifier: String = "navigationLabelButton" - public var accessibilityIdentifier: String? - public var title: String - public var action: ActionModelProtocol + open var backgroundColor: Color? + open class var identifier: String { "navigationLabelButton" } + open var accessibilityIdentifier: String? + open var title: String + open var action: ActionModelProtocol //-------------------------------------------------- // MARK: - Initializer @@ -62,7 +62,7 @@ public class NavigationLabelButtonModel: NavigationButtonModelProtocol, Molecule //-------------------------------------------------- /// Convenience function that creates a BarButtonItem for the model. - public func createNavigationItemButton(delegateObject: MVMCoreUIDelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) -> UIBarButtonItem { - return LabelBarButtonItem.create(with: title, actionModel: action, delegateObject: delegateObject, additionalData: additionalData) + open func createNavigationItemButton(delegateObject: MVMCoreUIDelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) -> UIBarButtonItem { + return LabelBarButtonItem.create(with: title, model: self, delegateObject: delegateObject, additionalData: additionalData) } } diff --git a/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift b/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift index 5fab61f9..6a75718b 100644 --- a/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift @@ -91,3 +91,16 @@ open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtoc try container.encodeModelIfPresent(titleView, forKey: .titleView) } } + +extension NavigationItemModel: ParentMoleculeModelProtocol { + public var children: [MoleculeModelProtocol] { + var children: [MoleculeModelProtocol] = [line, titleView, backButton].compactMap { $0 } + if let leftButtons = additionalLeftButtons { + children.append(contentsOf: leftButtons) + } + if let rightButtons = additionalRightButtons { + children.append(contentsOf: rightButtons) + } + return children + } +} diff --git a/MVMCoreUI/Atomic/Protocols/MoleculeDelegateProtocol.swift b/MVMCoreUI/Atomic/Protocols/MoleculeDelegateProtocol.swift index e61ea662..0435cf66 100644 --- a/MVMCoreUI/Atomic/Protocols/MoleculeDelegateProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/MoleculeDelegateProtocol.swift @@ -6,30 +6,34 @@ // Copyright © 2019 Verizon Wireless. All rights reserved. // -import Foundation public protocol MoleculeDelegateProtocol: AnyObject { - + func getRootMolecules() -> [MoleculeModelProtocol] /// returns a module for the corresponding module name. - func getModuleWithName(_ name: String?) -> [AnyHashable : Any]? + func getModuleWithName(_ name: String?) -> [AnyHashable: Any]? + func getModuleWithName(_ moleculeName: String) -> MoleculeModelProtocol? - + /// Notifies the delegate that the molecule layout update. Should be called when the layout may change due to an async method. Mainly used for list or collections. func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) //optional - + /// Asks the delegate to add or remove molecules. Mainly used for list or collections. func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? + func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) + func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) } extension MoleculeDelegateProtocol { - public func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) {} + public func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) { } - public func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? { return nil } - public func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) {} - public func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) {} + public func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? { nil } + + public func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) { } + + public func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) { } } diff --git a/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift b/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift index 4e7efabb..abe4cdd7 100644 --- a/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift @@ -50,5 +50,4 @@ extension MoleculeTreeTraversalProtocol { return accumulator } } - } diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift index 34f81bc4..baab7479 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift @@ -183,10 +183,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol //-------------------------------------------------- open override func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) { - guard let tableView = tableView else { return } - - let point = molecule.convert(molecule.bounds.origin, to: tableView) - if let indexPath = tableView.indexPathForRow(at: point), tableView.indexPathsForVisibleRows?.contains(indexPath) ?? false { + guard let tableView = tableView else { return } + if let indexPath = tableView.indexPathForRow(at: molecule.center), tableView.indexPathsForVisibleRows?.contains(indexPath) ?? false { performTableViewUpdates() } } @@ -222,6 +220,36 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } } + open func newData(for molecule: MoleculeModelProtocol) { + //TODO: expand for header, navigation, etc + let json = molecule.toJSON() + guard let index = moleculesInfo?.firstIndex(where: { (moleculeInfo) -> Bool in + //TODO: check for molecule protocol eqaulity + if json == moleculeInfo.molecule.toJSON() { + return true + } else if let parent = moleculeInfo.molecule as? ParentMoleculeModelProtocol { + // Get all molecules of the same type for faster check. + let molecules: [MoleculeModelProtocol] = parent.reduceDepthFirstTraverse(options: .childFirst, depth: 0, initialResult: []) { (accumulator, currentMolecule, depth) in + if currentMolecule.moleculeName == molecule.moleculeName { + return accumulator + [currentMolecule] + } + return accumulator + } + for molecule in molecules { + if json == molecule.toJSON() { + return true + } + } + } + return false + }) else { return } + + // Refresh the cell. + let indexPath = IndexPath(row: index, section: 0) + _ = tableView(tableView, cellForRowAt: indexPath) + performTableViewUpdates() + } + open override func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) { var indexPaths: [IndexPath] = [] //TODO: check for molecule protocol equality diff --git a/MVMCoreUI/Atomic/Templates/StackPageTemplateModel.swift b/MVMCoreUI/Atomic/Templates/StackPageTemplateModel.swift index 27769b20..1ed663c2 100644 --- a/MVMCoreUI/Atomic/Templates/StackPageTemplateModel.swift +++ b/MVMCoreUI/Atomic/Templates/StackPageTemplateModel.swift @@ -16,7 +16,7 @@ public var moleculeStack: StackModel public override var rootMolecules: [MoleculeModelProtocol] { - return [header, moleculeStack, footer].compactMap { $0 } + [navigationBar, header, moleculeStack, footer].compactMap { $0 } } //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift b/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift index 6a1bb244..06d813ef 100644 --- a/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift +++ b/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift @@ -18,7 +18,7 @@ public var footer: MoleculeModelProtocol? public override var rootMolecules: [MoleculeModelProtocol] { - return [header, footer].compactMap { $0 } + [navigationBar, header, footer].compactMap { $0 } } //-------------------------------------------------- diff --git a/MVMCoreUI/BaseClasses/BarButtonItem.swift b/MVMCoreUI/BaseClasses/BarButtonItem.swift index d41fd57f..b46647f2 100644 --- a/MVMCoreUI/BaseClasses/BarButtonItem.swift +++ b/MVMCoreUI/BaseClasses/BarButtonItem.swift @@ -20,7 +20,7 @@ public typealias BarButtonAction = (BarButtonItem) -> () //-------------------------------------------------- // MARK: - Delegate //-------------------------------------------------- - + open var model: (MoleculeModelProtocol & NavigationButtonModelProtocol)? open weak var buttonDelegate: ButtonDelegateProtocol? var actionDelegate: ActionDelegate? @@ -28,18 +28,12 @@ public typealias BarButtonAction = (BarButtonItem) -> () // MARK: - Methods //-------------------------------------------------- - open func set(with actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + open func set(with model: MoleculeModelProtocol & NavigationButtonModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + self.model = model buttonDelegate = delegateObject?.buttonDelegate actionDelegate?.buttonAction = { sender in - Button.performButtonAction(with: actionModel, button: sender, delegateObject: delegateObject, additionalData: additionalData) - } - } - - open func set(with actionMap: [AnyHashable : Any], delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - buttonDelegate = delegateObject?.buttonDelegate - actionDelegate?.buttonAction = { sender in - guard delegateObject?.buttonDelegate?.button?(sender, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true else { return } - MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) + let additionalDataWithSource = additionalData.dictionaryAdding(key: KeySourceModel, value: model) + Button.performButtonAction(with: model.action, button: sender, delegateObject: delegateObject, additionalData: additionalDataWithSource) } } } diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index f86061e5..5cd811de 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -450,10 +450,12 @@ import UIKit addFormParams(requestParameters: requestParameters, actionInformation: actionInformation, additionalData: additionalData) requestParameters.parentPageType = loadObject?.pageJSON?.optionalStringForKey("parentPageType") var pageForwardedData = additionalData ?? [:] + executeBehaviors { (behavior: PageLocalDataShareBehavior) in let dataMap = behavior.compileLocalPageDataForTransfer(delegateObjectIVar) - pageForwardedData.merge(dataMap) { (current, _) in current } + pageForwardedData.merge(dataMap) { current, _ in current } } + MVMCoreActionHandler.defaultHandleOpenPage(for: requestParameters, actionInformation: actionInformation, additionalData: pageForwardedData, delegateObject: delegateObject()) } @@ -461,14 +463,16 @@ import UIKit MVMCoreUILoggingHandler.shared()?.defaultLogAction(forController: self, actionInformation: actionInformation, additionalData: additionalData) } - open func handleUnknownActionType(_ actionType: String?, actionInformation: [AnyHashable : Any]?, additionalData: [AnyHashable : Any]?) { + open func handleUnknownActionType(_ actionType: String?, actionInformation: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) { var handled = false + executeBehaviors { (behavior: PageCustomActionHandlerBehavior) in - if (!handled) { + if !handled { handled = behavior.handleAction(type: actionType, information: actionInformation, additionalData: additionalData) } } - if (!handled) { + + if !handled { MVMCoreUIActionHandler.defaultHandleUnknownActionType(actionType, actionInformation: actionInformation, additionalData: additionalData, delegateObject: delegateObjectIVar) } } @@ -478,7 +482,7 @@ import UIKit //-------------------------------------------------- open func getRootMolecules() -> [MoleculeModelProtocol] { - return model?.rootMolecules ?? [] + model?.rootMolecules ?? [] } open func getModuleWithName(_ name: String?) -> [AnyHashable: Any]? { diff --git a/MVMCoreUI/Behaviors/GetContactBehavior.swift b/MVMCoreUI/Behaviors/GetContactBehavior.swift index c69bdbce..77c0d7f4 100644 --- a/MVMCoreUI/Behaviors/GetContactBehavior.swift +++ b/MVMCoreUI/Behaviors/GetContactBehavior.swift @@ -9,6 +9,7 @@ import Foundation import Contacts + public protocol PageGetContactBehaviorConsumerProtocol { func getMatchParameters() -> (NSPredicate, [CNKeyDescriptor])? func consume(contacts: [CNContact]) @@ -18,7 +19,7 @@ public class PageGetContactBehaviorModel: PageBehaviorModelProtocol { public class var identifier: String { "pageGetContactBehavior" } public var shouldAllowMultipleInstances: Bool { false } - public init() {} + public init() { } } public class PageGetContactBehavior: PageVisibilityBehavior { diff --git a/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift b/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift index e7db54bc..3f14f3cc 100644 --- a/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift +++ b/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift @@ -41,6 +41,11 @@ public protocol PageLocalDataShareBehavior: PageBehaviorProtocol { public protocol PageCustomActionHandlerBehavior: PageBehaviorProtocol { + /// - Parameters: + /// - actionType: The action type of the passed action model. + /// - information: information of the passed action model. + /// - additionalData: Additional information of the + /// - Returns: Boolean determines if the action has been handled. func handleAction(type actionType: String?, information: [AnyHashable : Any]?, additionalData: [AnyHashable : Any]?) -> Bool } diff --git a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift index d4eb516e..1edea27b 100644 --- a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift +++ b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift @@ -127,7 +127,7 @@ open class CoreUIModelMapping: ModelMapping { ModelRegistry.register(NavigationItemModel.self) ModelRegistry.register(NavigationImageButtonModel.self) ModelRegistry.register(NavigationLabelButtonModel.self) - + // MARK:- Other Organisms ModelRegistry.register(handler: Carousel.self, for: CarouselModel.self) ModelRegistry.register(handler: BarsIndicatorView.self, for: BarsCarouselIndicatorModel.self)