replaceMoleculeBehavior, cleaner child replacement helper, first working sample.

This commit is contained in:
Hedden, Kyle Matthew 2023-09-12 20:10:20 -04:00
parent 022319c186
commit 1f895ebdbd
9 changed files with 83 additions and 19 deletions

View File

@ -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
//-----------------------------------------------------

View File

@ -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)
}
//--------------------------------------------------

View File

@ -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

View File

@ -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<P: ParentMoleculeModelProtocol, T: MoleculeModelProtocol>(on target: P, keyPath: ReferenceWritableKeyPath<P, T?>, 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<T: MoleculeModelProtocol>(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<P: ParentMoleculeModelProtocol, T: MoleculeModelProtocol>(on target: P, keyPath: ReferenceWritableKeyPath<P, T>, replacementMolecule: MoleculeModelProtocol) -> Bool {
if target[keyPath: keyPath].id == replacementMolecule.id, let newHeadline = replacementMolecule as? T {
target[keyPath: keyPath] = newHeadline
func replace<T: MoleculeModelProtocol>(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<T>(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
}
}

View File

@ -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
}
}

View File

@ -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) {

View File

@ -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?)

View File

@ -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
}
}

View File

@ -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() {