diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyTextModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyTextModel.swift index 6d8881e4..b4ef3495 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyTextModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonBodyTextModel.swift @@ -7,7 +7,7 @@ // -open class ListLeftVariableRadioButtonBodyTextModel: ListItemModel, MoleculeModelProtocol { +open class ListLeftVariableRadioButtonBodyTextModel: ListItemModel, ParentMoleculeModelProtocol { //----------------------------------------------------- // MARK: - Properties //----------------------------------------------------- @@ -15,7 +15,16 @@ open class ListLeftVariableRadioButtonBodyTextModel: ListItemModel, MoleculeMode public static var identifier: String = "listLVRBBdy" public var radioButton: RadioButtonModel public var headlineBody: HeadlineBodyModel - + + public var children: [MoleculeModelProtocol] { + [radioButton, headlineBody] + } + + public func replaceChildMolecule(with replacementMolecule: MoleculeModelProtocol) -> Bool { + return replace(childMolecule: &radioButton, with: replacementMolecule) + || replace(childMolecule: &headlineBody, with: replacementMolecule) + } + //----------------------------------------------------- // MARK: - Initializer //----------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift index a3eaf918..4371fe34 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift @@ -25,12 +25,8 @@ } public func replaceChildMolecule(with replacementMolecule: MoleculeModelProtocol) -> Bool { - return [ - \HeadlineBodyModel.headline, - \HeadlineBodyModel.body, - ].contains { - replaceChildMolecule(on: self, keyPath: $0, replacementMolecule: replacementMolecule) - } + return replace(childMolecule:&headline, with: replacementMolecule) + || replace(childMolecule:&body, with: replacementMolecule) } //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Organisms/StackModel.swift b/MVMCoreUI/Atomic/Organisms/StackModel.swift index da6c067e..cb8740ac 100644 --- a/MVMCoreUI/Atomic/Organisms/StackModel.swift +++ b/MVMCoreUI/Atomic/Organisms/StackModel.swift @@ -26,6 +26,9 @@ } public func replaceChildMolecule(with replacementMolecule: MoleculeModelProtocol) -> Bool { + // IDEALLY: + //return replace(inChildMolecules: &molecules, with: replacementMolecule) + guard let replacementMolecule = replacementMolecule as? StackItemModelProtocol & MoleculeModelProtocol else { return false } guard let matchingIndex = molecules.firstIndex(where: { molecule in molecule.id == replacementMolecule.id diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/ParentMoleculeModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/ParentMoleculeModelProtocol.swift index 78377a25..19a3a711 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/ParentMoleculeModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/ParentMoleculeModelProtocol.swift @@ -60,20 +60,29 @@ public extension ParentMoleculeModelProtocol { /// Top level test to replace child molecules. Each parent molecule should attempt to replace. func replaceChildMolecule(with molecule: MoleculeModelProtocol) -> Bool { return false } - /// Helper function for replacing molecules on a path. - func replaceChildMolecule(on target: P, keyPath: ReferenceWritableKeyPath, replacementMolecule: MoleculeModelProtocol) -> Bool { - if let currentMolecule = target[keyPath: keyPath], currentMolecule.id == replacementMolecule.id, let newHeadline = replacementMolecule as? T { - target[keyPath: keyPath] = newHeadline + /// Helper function for replacing molecules. + func replace(childMolecule: inout T?, with replacementMolecule: MoleculeModelProtocol) -> Bool { + if childMolecule != nil, childMolecule?.id == replacementMolecule.id, let newHeadline = replacementMolecule as? T { + childMolecule = newHeadline return true } return false } - func replaceChildMolecule(on target: P, keyPath: ReferenceWritableKeyPath, replacementMolecule: MoleculeModelProtocol) -> Bool { - if target[keyPath: keyPath].id == replacementMolecule.id, let newHeadline = replacementMolecule as? T { - target[keyPath: keyPath] = newHeadline + func replace(childMolecule: inout T, with replacementMolecule: MoleculeModelProtocol) -> Bool { + if childMolecule.id == replacementMolecule.id, let newHeadline = replacementMolecule as? T { + childMolecule = newHeadline return true } return false } + + func replace(inChildMolecules molecules: inout [T], with replacementMolecule: MoleculeModelProtocol) -> Bool where T: MoleculeModelProtocol { + guard let replacementMolecule = replacementMolecule as? T else { return false } + guard let matchingIndex = molecules.firstIndex(where: { molecule in + molecule.id == replacementMolecule.id + }) else { return false } + molecules[matchingIndex] = replacementMolecule + return true + } } diff --git a/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift b/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift index a2da7cf4..48f5166b 100644 --- a/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift @@ -51,10 +51,13 @@ public extension MoleculeTreeTraversalProtocol { } } - func replaceMolecule(with replacementMolecule: MoleculeModelProtocol) { + func replaceMolecule(with replacementMolecule: MoleculeModelProtocol) -> Bool { + var didReplaceMolecule = false depthFirstTraverse(options: .parentFirst, depth: 0) { depth, molecule, stop in guard let parentMolecule = molecule as? ParentMoleculeModelProtocol else { return } - stop = parentMolecule.replaceChildMolecule(with: replacementMolecule) + didReplaceMolecule = parentMolecule.replaceChildMolecule(with: replacementMolecule) + stop = didReplaceMolecule } + return didReplaceMolecule } } diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index d91e776e..16c1500f 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -74,7 +74,9 @@ import MVMCore } open func modulesToListenFor() -> [String]? { - loadObject?.requestParameters?.allModules() + let requestModules = loadObject?.requestParameters?.allModules() ?? [] + let behaviorModules = behaviors?.flatMap { $0.modulesToListenFor() } ?? [] + return requestModules + behaviorModules } @objc open func responseJSONUpdated(notification: Notification) { diff --git a/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift b/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift index 543ee60c..c6292783 100644 --- a/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift +++ b/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift @@ -14,12 +14,15 @@ public protocol PageBehaviorProtocol: ModelHandlerProtocol { /// Should the behavior persist regardless of page behavior model updates. var transcendsPageUpdates: Bool { get } + func modulesToListenFor() -> [String] + /// Initializes the behavior with the model init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) } public extension PageBehaviorProtocol { var transcendsPageUpdates: Bool { return false } + func modulesToListenFor() -> [String] { return [] } } /** @@ -46,7 +49,6 @@ public extension PageMoleculeTransformationBehavior { } public protocol PageVisibilityBehavior: PageBehaviorProtocol { - func willShowPage(_ delegateObject: MVMCoreUIDelegateObject?) func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?) func willHidePage(_ delegateObject: MVMCoreUIDelegateObject?) diff --git a/MVMCoreUI/Behaviors/ReplacementMoleculeBehavior.swift b/MVMCoreUI/Behaviors/ReplacementMoleculeBehavior.swift new file mode 100644 index 00000000..89a34f4a --- /dev/null +++ b/MVMCoreUI/Behaviors/ReplacementMoleculeBehavior.swift @@ -0,0 +1,39 @@ +// +// ReplacementMoleculeBehavior.swift +// MVMCoreUI +// +// Created by Kyle Hedden on 9/12/23. +// Copyright © 2023 Verizon Wireless. All rights reserved. +// + +import Foundation +import MVMCore + +public class ReplacableMoleculeBehaviorModel: PageBehaviorModelProtocol { + public class var identifier: String { "replaceMoleculeBehavior" } + public var shouldAllowMultipleInstances: Bool { true } + public var moleculeIds: [String] +} + +public class ReplacableMoleculeBehavior: PageMoleculeTransformationBehavior { + var moleculeIds: [String] + + public required init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { + moleculeIds = (model as! ReplacableMoleculeBehaviorModel).moleculeIds + } + + public func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?) { + var shouldRefreshUI = false + for moleculeId in moleculeIds { + guard let replacementModel = delegateObject?.moleculeDelegate?.getModuleWithName(moleculeId) else { continue } + let didReplace = rootMolecules.contains(where: { model in + return model.replaceMolecule(with: replacementModel) + }) + shouldRefreshUI = shouldRefreshUI || didReplace + } + } + + public func modulesToListenFor() -> [String] { + moleculeIds + } +} diff --git a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift index af356d93..91042b47 100644 --- a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift +++ b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift @@ -227,6 +227,7 @@ open class CoreUIModelMapping: ModelMapping { ModelRegistry.register(handler: PageGetContactBehavior.self, for: PageGetContactBehaviorModel.self) ModelRegistry.register(handler: AddRemoveMoleculesBehavior.self, for: AddRemoveMoleculesBehaviorModel.self) ModelRegistry.register(handler: GetNotificationAuthStatusBehavior.self, for: GetNotificationAuthStatusBehaviorModel.self) + ModelRegistry.register(handler: ReplacableMoleculeBehavior.self, for: ReplacableMoleculeBehaviorModel.self) } open override class func registerActions() {