diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index f02ca813..e661e013 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -382,7 +382,7 @@ D23A8FEE26122F7D007E14CE /* VisibleBehaviorForVideo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D23A8FED26122F7D007E14CE /* VisibleBehaviorForVideo.swift */; }; D23A8FF82612308D007E14CE /* PageBehaviorProtocolRequirer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D23A8FF72612308D007E14CE /* PageBehaviorProtocolRequirer.swift */; }; D23A8FFB26123189007E14CE /* PageBehaviorModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D23A8FFA26123189007E14CE /* PageBehaviorModelProtocol.swift */; }; - D23A90002612347A007E14CE /* PageBehaviorHandlerModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D23A8FFF2612347A007E14CE /* PageBehaviorHandlerModelProtocol.swift */; }; + D23A90002612347A007E14CE /* PageBehaviorConatinerModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D23A8FFF2612347A007E14CE /* PageBehaviorConatinerModelProtocol.swift */; }; D23A9004261234CE007E14CE /* PageBehaviorHandlerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D23A9003261234CE007E14CE /* PageBehaviorHandlerProtocol.swift */; }; D23A900926125FFB007E14CE /* GetContactBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = D23A900826125FFB007E14CE /* GetContactBehavior.swift */; }; D23A90682614B0B4007E14CE /* CoreUIModelMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = D23A90672614B0B4007E14CE /* CoreUIModelMapping.swift */; }; @@ -969,7 +969,7 @@ D23A8FED26122F7D007E14CE /* VisibleBehaviorForVideo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleBehaviorForVideo.swift; sourceTree = ""; }; D23A8FF72612308D007E14CE /* PageBehaviorProtocolRequirer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageBehaviorProtocolRequirer.swift; sourceTree = ""; }; D23A8FFA26123189007E14CE /* PageBehaviorModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageBehaviorModelProtocol.swift; sourceTree = ""; }; - D23A8FFF2612347A007E14CE /* PageBehaviorHandlerModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageBehaviorHandlerModelProtocol.swift; sourceTree = ""; }; + D23A8FFF2612347A007E14CE /* PageBehaviorConatinerModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageBehaviorConatinerModelProtocol.swift; sourceTree = ""; }; D23A9003261234CE007E14CE /* PageBehaviorHandlerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageBehaviorHandlerProtocol.swift; sourceTree = ""; }; D23A900826125FFB007E14CE /* GetContactBehavior.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetContactBehavior.swift; sourceTree = ""; }; D23A90672614B0B4007E14CE /* CoreUIModelMapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreUIModelMapping.swift; sourceTree = ""; }; @@ -1202,10 +1202,10 @@ D2E2A9A023E095AB000B42E6 /* ButtonModelProtocol.swift */, 014AA72323C501E2006F3E93 /* ContainerModelProtocol.swift */, D23EA7FA2475F09800D60C34 /* CarouselItemProtocol.swift */, + 01EB3683236097C0006832FA /* MoleculeModelProtocol.swift */, 012A88C3238D86E600FE3DA1 /* CarouselItemModelProtocol.swift */, 012A88B0238C880100FE3DA1 /* CarouselPagingModelProtocol.swift */, EA05EFAA278DE53600828819 /* ClearableModelProtocol.swift */, - 01EB3683236097C0006832FA /* MoleculeModelProtocol.swift */, 012A889B23889E8400FE3DA1 /* TemplateModelProtocol.swift */, D28A837823C7D5BC00DFE4FC /* PageModelProtocol.swift */, 011B58EF23A2AA980085F53C /* ListItemModelProtocol.swift */, @@ -1321,7 +1321,7 @@ children = ( D23A8FF72612308D007E14CE /* PageBehaviorProtocolRequirer.swift */, D23A8FFA26123189007E14CE /* PageBehaviorModelProtocol.swift */, - D23A8FFF2612347A007E14CE /* PageBehaviorHandlerModelProtocol.swift */, + D23A8FFF2612347A007E14CE /* PageBehaviorConatinerModelProtocol.swift */, D23A9003261234CE007E14CE /* PageBehaviorHandlerProtocol.swift */, 27F973522466074500CAB5C5 /* PageBehaviorProtocol.swift */, ); @@ -2720,7 +2720,7 @@ 01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */, D2A92884241ACB25004E01C6 /* ProgrammaticScrollViewController.swift in Sources */, EA985C3E2970938F00F2FF2E /* Tilelet.swift in Sources */, - D23A90002612347A007E14CE /* PageBehaviorHandlerModelProtocol.swift in Sources */, + D23A90002612347A007E14CE /* PageBehaviorConatinerModelProtocol.swift in Sources */, EAA78020290081320057DFDF /* VDSMoleculeViewProtocol.swift in Sources */, 0A21DB7F235DECC500C160A2 /* EntryField.swift in Sources */, D2E2A99F23E07F8A000B42E6 /* PillButton.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Molecules/OtherContainers/MoleculeContainerProtocol.swift b/MVMCoreUI/Atomic/Molecules/OtherContainers/MoleculeContainerProtocol.swift index 29017c96..44b040aa 100644 --- a/MVMCoreUI/Atomic/Molecules/OtherContainers/MoleculeContainerProtocol.swift +++ b/MVMCoreUI/Atomic/Molecules/OtherContainers/MoleculeContainerProtocol.swift @@ -12,13 +12,15 @@ public protocol MoleculeContainerModelProtocol: ContainerModelProtocol, ParentMo } public extension MoleculeContainerModelProtocol { - + var children: [MoleculeModelProtocol] { return [molecule] } +} + +public extension MoleculeContainerModelProtocol where Self: AnyObject { - func replaceMolecule(with replacementMolecule: MoleculeModelProtocol) throws -> Bool { + mutating func replaceMolecule(with replacementMolecule: MoleculeModelProtocol) throws -> Bool { return try replaceChildMolecule(at: &molecule, with: replacementMolecule) } - } diff --git a/MVMCoreUI/Atomic/Organisms/StackModelProtocol.swift b/MVMCoreUI/Atomic/Organisms/StackModelProtocol.swift index 3d57fe72..1456f6e5 100644 --- a/MVMCoreUI/Atomic/Organisms/StackModelProtocol.swift +++ b/MVMCoreUI/Atomic/Organisms/StackModelProtocol.swift @@ -16,11 +16,12 @@ public protocol StackModelProtocol: ParentMoleculeModelProtocol { } extension StackModelProtocol { - public var children: [MoleculeModelProtocol] { return molecules } +} + +extension StackModelProtocol where Self: AnyObject { - public func replaceChildMolecule(with molecule: MoleculeModelProtocol) throws -> Bool { + public mutating func replaceChildMolecule(with molecule: MoleculeModelProtocol) throws -> Bool { return try replaceChildMolecule(in: &molecules, with: molecule) } - } diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift index 31adc6ef..0fcab2d0 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift @@ -68,8 +68,13 @@ public extension Array where Element == MoleculeModelProtocol { } func depthFirstTraverse(options: TreeTraversalOptions, depth: Int, onVisit: (Int, MoleculeModelProtocol, inout Bool) -> Void) { - forEach { (molecule) in - molecule.depthFirstTraverse(options: options, depth: depth, onVisit: onVisit) + var shouldStop = false + for molecule in self { + molecule.depthFirstTraverse(options: options, depth: depth) { depth, molecule, stop in + onVisit(depth, molecule, &shouldStop) + stop = shouldStop + } + if shouldStop { break } } } } diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/ParentMoleculeModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/ParentMoleculeModelProtocol.swift index c970bc39..a9f4f8ac 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/ParentMoleculeModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/ParentMoleculeModelProtocol.swift @@ -8,15 +8,15 @@ import Foundation -public protocol ParentModelProtocol: MoleculeTreeTraversalProtocol, AnyObject { +public protocol ParentModelProtocol: MoleculeTreeTraversalProtocol { var children: [MoleculeModelProtocol] { get } /// Method for replacing surface level children. (Does not recurse.) - func replaceChildMolecule(with molecule: MoleculeModelProtocol) throws -> Bool + mutating func replaceChildMolecule(with molecule: MoleculeModelProtocol) throws -> Bool } -public extension ParentModelProtocol { +public extension ParentModelProtocol where Self: AnyObject { /// Top level test to replace child molecules. Each parent molecule should attempt to replace. func replaceChildMolecule(with molecule: MoleculeModelProtocol) throws -> Bool { return false } diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift index f884e4aa..296f73f5 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift @@ -37,9 +37,12 @@ public extension TemplateModelProtocol { func depthFirstTraverse(options: TreeTraversalOptions, depth: Int, onVisit: (Int, MoleculeModelProtocol, inout Bool) -> Void) { return rootMolecules.depthFirstTraverse(options: options, depth: depth, onVisit: onVisit) } +} + +extension TemplateModelProtocol { /// Recursively finds and replaces the first child matching the replacement molecule id property. - func replaceMolecule(with replacementMolecule: MoleculeModelProtocol) throws -> Bool { + mutating func replaceMolecule(with replacementMolecule: MoleculeModelProtocol) throws -> Bool { // Attempt root level replacement on the template model first. if try replaceChildMolecule(with: replacementMolecule) { return true @@ -49,7 +52,7 @@ public extension TemplateModelProtocol { var possibleError: Error? // Dive into each root thereafter. depthFirstTraverse(options: .parentFirst, depth: 0) { depth, molecule, stop in - guard let parentMolecule = molecule as? ParentMoleculeModelProtocol else { return } + guard var parentMolecule = molecule as? ParentMoleculeModelProtocol else { return } do { didReplaceMolecule = try parentMolecule.replaceChildMolecule(with: replacementMolecule) } catch { diff --git a/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift b/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift index 144001bc..80fa29a0 100644 --- a/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift @@ -8,7 +8,7 @@ import Foundation -public protocol TemplateProtocol: AnyObject, PageProtocol { +public protocol TemplateProtocol: AnyObject, PageProtocol{ associatedtype TemplateModel: TemplateModelProtocol var templateModel: TemplateModel? { get set } @@ -28,25 +28,26 @@ public extension TemplateProtocol { } } + func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> TemplateModel { + try decoder.decode(TemplateModel.self, from: data) + } +} + +public extension TemplateProtocol where Self: PageBehaviorHandlerProtocol, Self: MVMCoreViewControllerProtocol { + /// Helper function to do common parsing logic. func parseTemplate(json: [AnyHashable: Any]?) throws { guard let pageJSON = json else { return } - let delegateObject = (self as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject + let delegateObject = delegateObject?() as? MVMCoreUIDelegateObject let data = try JSONSerialization.data(withJSONObject: pageJSON) let decoder = JSONDecoder.create(with: delegateObject) templateModel = try decodeTemplate(using: decoder, from: data) // Add additional required behaviors if applicable. - guard var behaviorHandlerModel = templateModel as? TemplateModelProtocol & PageBehaviorHandlerModelProtocol, - var behaviorHandler = self as? PageBehaviorHandlerProtocol else { return } - behaviorHandlerModel.traverseAndAddRequiredBehaviors() - behaviorHandler.createBehaviors(for: behaviorHandlerModel, delegateObject: delegateObject) - if let viewController = self as? UIViewController { - MVMCoreUISession.sharedGlobal()?.applyGlobalBehaviors(to: viewController) - } - } - - func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> TemplateModel { - try decoder.decode(TemplateModel.self, from: data) + guard var pageBehaviorsModel = templateModel as? TemplateModelProtocol & PageBehaviorConatinerModelProtocol else { return } + + pageBehaviorsModel.traverseAndAddRequiredBehaviors() + var behaviorHandler = self + behaviorHandler.applyBehaviors(pageBehaviorModel: pageBehaviorsModel, delegateObject: delegateObject) } } diff --git a/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift index b84792a6..e4e50d89 100644 --- a/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift @@ -80,12 +80,12 @@ } - open override func handleNewData() { + open override func updateUI() { topViewOutsideOfScrollArea = templateModel?.anchorHeader ?? false bottomViewOutsideOfScrollArea = templateModel?.anchorFooter ?? false setup() registerCells() - super.handleNewData() + super.updateUI() } //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Templates/ModalSectionListTemplate.swift b/MVMCoreUI/Atomic/Templates/ModalSectionListTemplate.swift index baf8d78a..071b78c2 100644 --- a/MVMCoreUI/Atomic/Templates/ModalSectionListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/ModalSectionListTemplate.swift @@ -21,8 +21,8 @@ open class ModalSectionListTemplate: SectionListTemplate { // MARK: - Lifecycle //-------------------------------------------------- - override open func handleNewData() { - super.handleNewData() + override open func updateUI() { + super.updateUI() _ = MVMCoreUICommonViewsUtility.addCloseButton(to: view, action: { [weak self] _ in guard let self = self else { return } let closeAction = (self.templateModel as? ModalSectionListTemplateModel)?.closeAction ?? diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift index 950b6785..0605e4e6 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift @@ -81,12 +81,12 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol return molecule } - open override func handleNewData() { + open override func updateUI() { topViewOutsideOfScrollArea = templateModel?.anchorHeader ?? false bottomViewOutsideOfScrollArea = templateModel?.anchorFooter ?? false setup() registerWithTable() - super.handleNewData() + super.updateUI() } open override func viewDidAppear(_ animated: Bool) { @@ -300,7 +300,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } extension MoleculeListTemplate: MoleculeListProtocol { - open func removeMolecules(at indexPaths: [IndexPath], animation: UITableView.RowAnimation?) { + public func removeMolecules(at indexPaths: [IndexPath], animation: UITableView.RowAnimation?) { for (index, indexPath) in indexPaths.sorted().enumerated() { let removeIndex = indexPath.row - index moleculesInfo?.remove(at: removeIndex) @@ -313,7 +313,7 @@ extension MoleculeListTemplate: MoleculeListProtocol { view.layoutIfNeeded() } - open func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation?) { + public func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation?) { var indexPaths: [IndexPath] = [] for molecule in molecules { @@ -332,7 +332,7 @@ extension MoleculeListTemplate: MoleculeListProtocol { self.view.layoutIfNeeded() } - open func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? { + public func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? { guard let index = moleculesInfo?.firstIndex(where: { (moleculeInfo) -> Bool in return equal(moleculeA: molecule, moleculeB: moleculeInfo.molecule) }) else { return nil } diff --git a/MVMCoreUI/Atomic/Templates/ThreeLayerFillMiddleTemplate.swift b/MVMCoreUI/Atomic/Templates/ThreeLayerFillMiddleTemplate.swift index eb8a674f..bb6c5bdb 100644 --- a/MVMCoreUI/Atomic/Templates/ThreeLayerFillMiddleTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/ThreeLayerFillMiddleTemplate.swift @@ -26,8 +26,8 @@ } } - open override func handleNewData() { - super.handleNewData() + open override func updateUI() { + super.updateUI() heightConstraint?.isActive = true } } diff --git a/MVMCoreUI/Atomic/Templates/ThreeLayerTemplate.swift b/MVMCoreUI/Atomic/Templates/ThreeLayerTemplate.swift index 933d6043..d0203e70 100644 --- a/MVMCoreUI/Atomic/Templates/ThreeLayerTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/ThreeLayerTemplate.swift @@ -19,10 +19,10 @@ import UIKit try super.parsePageJSON() } - open override func handleNewData() { + open override func updateUI() { topViewOutsideOfScroll = templateModel?.anchorHeader ?? false bottomViewOutsideOfScroll = templateModel?.anchorFooter ?? false - super.handleNewData() + super.updateUI() } open override func viewForTop() -> UIView? { diff --git a/MVMCoreUI/BaseControllers/MVMControllerModelProtocol.swift b/MVMCoreUI/BaseControllers/MVMControllerModelProtocol.swift index 78f6f604..b4aabd55 100644 --- a/MVMCoreUI/BaseControllers/MVMControllerModelProtocol.swift +++ b/MVMCoreUI/BaseControllers/MVMControllerModelProtocol.swift @@ -9,6 +9,6 @@ import Foundation -public protocol MVMControllerModelProtocol: TemplateModelProtocol, FormHolderModelProtocol, PageBehaviorHandlerModelProtocol { +public protocol MVMControllerModelProtocol: TemplateModelProtocol, FormHolderModelProtocol, PageBehaviorConatinerModelProtocol { } diff --git a/MVMCoreUI/BaseControllers/ScrollingViewController.swift b/MVMCoreUI/BaseControllers/ScrollingViewController.swift index 4fd23be2..e7698d49 100644 --- a/MVMCoreUI/BaseControllers/ScrollingViewController.swift +++ b/MVMCoreUI/BaseControllers/ScrollingViewController.swift @@ -63,8 +63,8 @@ open class ScrollingViewController: ViewController { registerForKeyboardNotifications() } - open override func handleNewData() { - super.handleNewData() + open override func updateUI() { + super.updateUI() // will change scrollView indicatorStyle automatically on the basis of backgroundColor var greyScale: CGFloat = 0 if view.backgroundColor?.getWhite(&greyScale, alpha: nil) ?? false { diff --git a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift index 4011f4f8..13b62f2b 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift @@ -108,8 +108,8 @@ import Foundation } } - open override func handleNewData() { - super.handleNewData() + open override func updateUI() { + super.updateUI() topView?.removeFromSuperview() bottomView?.removeFromSuperview() topView = viewForTop() diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index 4faff136..f452fa96 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -50,8 +50,8 @@ open class ThreeLayerTableViewController: ProgrammaticTableViewController { tableView.reloadData() } - open override func handleNewData() { - super.handleNewData() + open override func updateUI() { + super.updateUI() createViewForTableHeader() createViewForTableFooter() tableView?.reloadData() diff --git a/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift index ec8aaaa3..0ec3cac9 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerViewController.swift @@ -49,8 +49,8 @@ open class ThreeLayerViewController: ProgrammaticScrollViewController { } } - open override func handleNewData() { - super.handleNewData() + open override func updateUI() { + super.updateUI() // Removes the views topView?.removeFromSuperview() diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index afd91ec0..1b4e5728 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -111,9 +111,12 @@ import MVMCore guard newData else { return } do { + // TODO: Parse parsePageJSON modifies the page model on a different thread than + // the UI update which could cause discrepancies. Parse should return the resulting + // object and assignment should be synchronized on handleNewData(model: ). try parsePageJSON() MVMCoreDispatchUtility.performBlock(onMainThread: { - self.handleNewDataAndUpdateUI() + self.handleNewData() }) } catch { if let coreError = MVMCoreErrorObject.createErrorObject(for: error, location: "updateJSON for pageType: \(String(describing: pageType))") { @@ -160,7 +163,7 @@ import MVMCore } return false } - + return true } @@ -229,9 +232,12 @@ import MVMCore return true } - /// Calls processNewData and then sets the ui to update with updateView - open func handleNewDataAndUpdateUI() { - handleNewData() + @MainActor + open func updateUI() { + if let backgroundColor = model?.backgroundColor { + view.backgroundColor = backgroundColor.uiColor + } + needsUpdateUI = true view.setNeedsLayout() } @@ -244,6 +250,7 @@ import MVMCore } /// Processes any new data. Called after the page is loaded the first time and on response updates for this page, + @MainActor open func handleNewData() { if model?.navigationBar == nil { let navigationItem = createDefaultLegacyNavigationModel() @@ -259,12 +266,10 @@ import MVMCore formValidator = FormValidator(rules) } - if let backgroundColor = model?.backgroundColor { - view.backgroundColor = backgroundColor.uiColor - } - // Notify the manager of new data manager?.newDataReceived?(in: self) + + updateUI() } public func generateMoleculeView(from model: MoleculeModelProtocol) -> MoleculeViewProtocol? { @@ -333,7 +338,7 @@ import MVMCore initialLoad() } - handleNewDataAndUpdateUI() + handleNewData() } open override func viewDidLayoutSubviews() { diff --git a/MVMCoreUI/Behaviors/GetContactBehavior.swift b/MVMCoreUI/Behaviors/GetContactBehavior.swift index 77c0d7f4..6f9a3cd4 100644 --- a/MVMCoreUI/Behaviors/GetContactBehavior.swift +++ b/MVMCoreUI/Behaviors/GetContactBehavior.swift @@ -43,7 +43,7 @@ public class PageGetContactBehavior: PageVisibilityBehavior { MVMCoreDispatchUtility.performBlock(onMainThread: { // TODO: move to protocol function instead guard let controller = self?.delegate?.moleculeDelegate as? ViewController else { return } - controller.handleNewDataAndUpdateUI() + controller.handleNewData() }) } } diff --git a/MVMCoreUI/Behaviors/GetNotificationAuthStatusBehavior.swift b/MVMCoreUI/Behaviors/GetNotificationAuthStatusBehavior.swift index 78bb1129..980f0dbf 100644 --- a/MVMCoreUI/Behaviors/GetNotificationAuthStatusBehavior.swift +++ b/MVMCoreUI/Behaviors/GetNotificationAuthStatusBehavior.swift @@ -45,11 +45,12 @@ public class GetNotificationAuthStatusBehavior: PageVisibilityBehavior { for consumer in consumers { consumer.consume(notificationStatus: settings.authorizationStatus) } - // Tell template to update - MVMCoreDispatchUtility.performBlock(onMainThread: { + + Task { + // Tell template to update guard let controller = self.delegate?.moleculeDelegate as? ViewController else { return } - controller.handleNewDataAndUpdateUI() - }) + await controller.handleNewData() + } } } diff --git a/MVMCoreUI/Behaviors/Protocols/PageBehaviorHandlerModelProtocol.swift b/MVMCoreUI/Behaviors/Protocols/PageBehaviorConatinerModelProtocol.swift similarity index 79% rename from MVMCoreUI/Behaviors/Protocols/PageBehaviorHandlerModelProtocol.swift rename to MVMCoreUI/Behaviors/Protocols/PageBehaviorConatinerModelProtocol.swift index bb752694..ddc1e646 100644 --- a/MVMCoreUI/Behaviors/Protocols/PageBehaviorHandlerModelProtocol.swift +++ b/MVMCoreUI/Behaviors/Protocols/PageBehaviorConatinerModelProtocol.swift @@ -1,16 +1,17 @@ // -// PageBehaviorHandlerModelProtocol.swift +// PageBehaviorConatinerModelProtocol.swift // MVMCoreUI // // Created by Scott Pfeil on 3/29/21. // Copyright © 2021 Verizon Wireless. All rights reserved. // -public protocol PageBehaviorHandlerModelProtocol { +/// Protocol applied to a model that contains a list of behavior models. +public protocol PageBehaviorConatinerModelProtocol { var behaviors: [PageBehaviorModelProtocol]? { get set } } -public extension PageBehaviorHandlerModelProtocol { +public extension PageBehaviorConatinerModelProtocol { /// Adds the behavior model to the behaviors if possible. mutating func add(behavior: PageBehaviorModelProtocol) { @@ -24,7 +25,7 @@ public extension PageBehaviorHandlerModelProtocol { } } -public extension PageBehaviorHandlerModelProtocol where Self: MoleculeTreeTraversalProtocol { +public extension PageBehaviorConatinerModelProtocol where Self: MoleculeTreeTraversalProtocol { /// Traverses all models and adds any required behavior models. mutating func traverseAndAddRequiredBehaviors() { diff --git a/MVMCoreUI/Behaviors/Protocols/PageBehaviorHandlerProtocol.swift b/MVMCoreUI/Behaviors/Protocols/PageBehaviorHandlerProtocol.swift index 9e5c6a6d..7607f5e2 100644 --- a/MVMCoreUI/Behaviors/Protocols/PageBehaviorHandlerProtocol.swift +++ b/MVMCoreUI/Behaviors/Protocols/PageBehaviorHandlerProtocol.swift @@ -12,20 +12,10 @@ public protocol PageBehaviorHandlerProtocol { } public extension PageBehaviorHandlerProtocol { + /// Creates the behaviors and sets the variable. - mutating func createBehaviors(for model: PageBehaviorHandlerModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { - - behaviors = behaviors?.filter { $0.transcendsPageUpdates } - if behaviors?.isEmpty ?? false { - behaviors = nil - } - - guard let behaviorModels = model.behaviors else { - return - } - - var behaviors: [PageBehaviorProtocol] = behaviors ?? [] - + func createBehaviors(for behaviorModels: [PageBehaviorModelProtocol], delegateObject: MVMCoreUIDelegateObject?) -> [PageBehaviorProtocol] { + var behaviors = [PageBehaviorProtocol]() for behaviorModel in behaviorModels { do { let handlerType = try ModelRegistry.getHandler(behaviorModel) as! PageBehaviorProtocol.Type @@ -37,7 +27,23 @@ public extension PageBehaviorHandlerProtocol { } } } + return behaviors + } + + mutating func applyBehaviors(pageBehaviorModel: PageBehaviorConatinerModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { + // Pull the existing behaviors. + var behaviors = (behaviors ?? []).filter { $0.transcendsPageUpdates } + // Create and append any new behaviors based on the incoming models. + let newBehaviors = createBehaviors(for: pageBehaviorModel.behaviors ?? [], delegateObject: delegateObject) + behaviors.append(contentsOf: newBehaviors) + + // Apply them to the page. self.behaviors = behaviors.count > 0 ? behaviors : nil + + // Ask the session to apply any more. (Curently inverted contol due to Swift <--> Obj-C conflict. + if let viewController = self as? UIViewController { + MVMCoreUISession.sharedGlobal()?.applyGlobalBehaviors(to: viewController) + } } /// Executes all behaviors of type. @@ -49,3 +55,11 @@ public extension PageBehaviorHandlerProtocol { return try behaviors?.compactMap({$0 as? T}).allSatisfy({ return try behaviourBlock($0) }) ?? true } } + +public extension PageBehaviorHandlerProtocol where Self: MVMCoreViewControllerProtocol { + + mutating func applyBehaviors(pageBehaviorModel: PageBehaviorConatinerModelProtocol) { + applyBehaviors(pageBehaviorModel: pageBehaviorModel, delegateObject: delegateObject?() as? MVMCoreUIDelegateObject) + } + +} diff --git a/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift b/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift index c6292783..6d6fda04 100644 --- a/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift +++ b/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift @@ -86,8 +86,8 @@ public protocol PageCustomActionHandlerBehavior: PageBehaviorProtocol { } public extension MVMCoreUIDelegateObject { - var behaviorModelDelegate: PageBehaviorHandlerModelProtocol? { - (moleculeDelegate as? PageProtocol)?.pageModel as? PageBehaviorHandlerModelProtocol + var behaviorModelDelegate: PageBehaviorConatinerModelProtocol? { + (moleculeDelegate as? PageProtocol)?.pageModel as? PageBehaviorConatinerModelProtocol } weak var behaviorTemplateDelegate: (PageBehaviorHandlerProtocol & NSObjectProtocol)? { diff --git a/MVMCoreUI/Behaviors/ReplacementMoleculeBehavior.swift b/MVMCoreUI/Behaviors/ReplacementMoleculeBehavior.swift index 8daf3c8f..3773e717 100644 --- a/MVMCoreUI/Behaviors/ReplacementMoleculeBehavior.swift +++ b/MVMCoreUI/Behaviors/ReplacementMoleculeBehavior.swift @@ -24,7 +24,7 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior { public func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?) { - guard let templateModel = delegateObject?.moleculeDelegate?.getTemplateModel() else { return } + guard var templateModel = delegateObject?.moleculeDelegate?.getTemplateModel() else { return } templateModel.printMolecules()