expand out behaviors into page data sharing, molecule updates before rendering and custom action handling. continue expanding molecular traversal reach and custom model overrides.

This commit is contained in:
Kyle Matthew Hedden 2021-04-01 17:33:50 -04:00
parent 8da5c9d32b
commit b89c1e66f5
9 changed files with 105 additions and 18 deletions

View File

@ -7,12 +7,13 @@
// //
@objcMembers public class ImageViewModel: MoleculeModelProtocol { @objcMembers open class ImageViewModel: MoleculeModelProtocol {
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Properties // MARK: - Properties
//-------------------------------------------------- //--------------------------------------------------
public static var identifier: String = "image" open class var identifier: String { "image" }
public var backgroundColor: Color? public var backgroundColor: Color?
public var moleculeName: String = ImageViewModel.identifier public var moleculeName: String = ImageViewModel.identifier
public var image: String public var image: String

View File

@ -7,7 +7,7 @@
// //
public class ListLeftVariableIconWithRightCaretModel: ListItemModel, MoleculeModelProtocol { public class ListLeftVariableIconWithRightCaretModel: ListItemModel, ParentMoleculeModelProtocol {
//----------------------------------------------------- //-----------------------------------------------------
// MARK: - Properties // MARK: - Properties
//----------------------------------------------------- //-----------------------------------------------------
@ -17,6 +17,10 @@ public class ListLeftVariableIconWithRightCaretModel: ListItemModel, MoleculeMod
public var leftLabel: LabelModel public var leftLabel: LabelModel
public var rightLabel: LabelModel public var rightLabel: LabelModel
public var children: [MoleculeModelProtocol] {
return [image, leftLabel, rightLabel]
}
//----------------------------------------------------- //-----------------------------------------------------
// MARK: - Methods // MARK: - Methods
//----------------------------------------------------- //-----------------------------------------------------
@ -57,9 +61,9 @@ public class ListLeftVariableIconWithRightCaretModel: ListItemModel, MoleculeMod
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
leftLabel = try typeContainer.decode(LabelModel.self, forKey: .leftLabel) leftLabel = try typeContainer.decodeMoleculeIfPresent(codingKey: .leftLabel)!
rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel) rightLabel = try typeContainer.decodeMoleculeIfPresent(codingKey: .rightLabel)!
image = try typeContainer.decode(ImageViewModel.self, forKey: .image) image = try typeContainer.decodeMoleculeIfPresent(codingKey: .image)!
try super.init(from: decoder) try super.init(from: decoder)
} }

View File

@ -50,11 +50,11 @@ public class TwoButtonViewModel: ParentMoleculeModelProtocol {
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
primaryButton = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .primaryButton) primaryButton = try typeContainer.decodeMoleculeIfPresent(codingKey: .primaryButton)
if primaryButton?.style == nil { if primaryButton?.style == nil {
primaryButton?.style = .primary primaryButton?.style = .primary
} }
secondaryButton = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .secondaryButton) secondaryButton = try typeContainer.decodeMoleculeIfPresent(codingKey: .secondaryButton)
if secondaryButton?.style == nil { if secondaryButton?.style == nil {
secondaryButton?.style = .secondary secondaryButton?.style = .secondary
} }

View File

@ -48,4 +48,32 @@ import Foundation
public init(body: LabelModel) { public init(body: LabelModel) {
self.body = body self.body = body
} }
//-----------------------------------------------------
// MARK: - Codec
//-----------------------------------------------------
private enum CodingKeys: String, CodingKey {
case moleculeName
case headline
case body
case style
case backgroundColor
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
headline = try typeContainer.decodeMoleculeIfPresent(codingKey: .headline)
body = try typeContainer.decodeMoleculeIfPresent(codingKey: .body)
style = try typeContainer.decodeIfPresent(Style.self, forKey: .style)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(headline, forKey: .headline)
try container.encodeIfPresent(style, forKey: .style)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
}
} }

View File

@ -10,6 +10,8 @@ import Foundation
public protocol MoleculeDelegateProtocol: AnyObject { public protocol MoleculeDelegateProtocol: AnyObject {
func getRootMolecules() -> [MoleculeModelProtocol]
/// returns a module for the corresponding module name. /// 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? func getModuleWithName(_ moleculeName: String) -> MoleculeModelProtocol?

View File

@ -143,7 +143,6 @@ import UIKit
// Parse the model for the page. // Parse the model for the page.
do { do {
try parsePageJSON() try parsePageJSON()
return true
} catch let parsingError { } catch let parsingError {
// Log all parsing errors and fail load. // Log all parsing errors and fail load.
handleLoggingFor(parsingError: parsingError) handleLoggingFor(parsingError: parsingError)
@ -153,6 +152,14 @@ import UIKit
} }
return false return false
} }
if let pageData = loadObject.dataForPage {
executeBehaviors { (behavior: PageLocalDataShareBehavior) in
behavior.receiveLocalPageData(pageData, delegateObjectIVar)
}
}
return true
} }
func handleLoggingFor(parsingError: Error) { func handleLoggingFor(parsingError: Error) {
@ -230,6 +237,10 @@ import UIKit
/// Processes any new data. Called after the page is loaded the first time and on response updates for this page, /// Processes any new data. Called after the page is loaded the first time and on response updates for this page,
open func handleNewData() { open func handleNewData() {
executeBehaviors { (behavior: PageMoleculeTransformationBehavior) in
behavior.onPageNew(rootMolecules: getRootMolecules(), delegateObjectIVar)
}
if formValidator == nil { if formValidator == nil {
let rules = model?.formRules let rules = model?.formRules
formValidator = FormValidator(rules) formValidator = FormValidator(rules)
@ -373,6 +384,10 @@ import UIKit
// Track. // Track.
MVMCoreUISession.sharedGlobal()?.currentPageType = pageType MVMCoreUISession.sharedGlobal()?.currentPageType = pageType
MVMCoreUILoggingHandler.shared()?.defaultLogPageState(forController: self) MVMCoreUILoggingHandler.shared()?.defaultLogPageState(forController: self)
executeBehaviors { [weak self] (behavior: PageVisibilityBehavior) in
behavior.onPageShown(self?.delegateObjectIVar)
}
} }
open override func viewDidAppear(_ animated: Bool) { open override func viewDidAppear(_ animated: Bool) {
@ -381,10 +396,6 @@ import UIKit
if manager == nil { if manager == nil {
pageShown() pageShown()
} }
executeBehaviors { [weak self] (behavior: PageVisibilityBehavior) in
behavior.onPageShown(self?.delegateObjectIVar)
}
} }
open override func viewDidDisappear(_ animated: Bool) { open override func viewDidDisappear(_ animated: Bool) {
@ -463,17 +474,38 @@ import UIKit
open func handleOpenPage(for requestParameters: MVMCoreRequestParameters, actionInformation: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) { open func handleOpenPage(for requestParameters: MVMCoreRequestParameters, actionInformation: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) {
addFormParams(requestParameters) addFormParams(requestParameters)
requestParameters.parentPageType = loadObject?.pageJSON?.optionalStringForKey("parentPageType") requestParameters.parentPageType = loadObject?.pageJSON?.optionalStringForKey("parentPageType")
MVMCoreActionHandler.defaultHandleOpenPage(for: requestParameters, actionInformation: actionInformation, additionalData: additionalData, delegateObject: delegateObject()) var pageForwardedData = additionalData ?? [:]
executeBehaviors { (behavior: PageLocalDataShareBehavior) in
let dataMap = behavior.compileLocalPageDataForTransfer(delegateObjectIVar)
pageForwardedData.merge(dataMap) { (current, _) in current }
}
MVMCoreActionHandler.defaultHandleOpenPage(for: requestParameters, actionInformation: actionInformation, additionalData: pageForwardedData, delegateObject: delegateObject())
} }
open func logAction(withActionInformation actionInformation: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) { open func logAction(withActionInformation actionInformation: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) {
MVMCoreUILoggingHandler.shared()?.defaultLogAction(forController: self, actionInformation: actionInformation, additionalData: additionalData) MVMCoreUILoggingHandler.shared()?.defaultLogAction(forController: self, actionInformation: actionInformation, additionalData: additionalData)
} }
open func handleUnknownActionType(_ actionType: String?, actionInformation: [AnyHashable : Any]?, additionalData: [AnyHashable : Any]?) {
var handled = false
executeBehaviors { (behavior: PageCustomActionHandlerBehavior) in
if (!handled) {
handled = behavior.handleAction(type: actionType, information: actionInformation, additionalData: additionalData)
}
}
if (!handled) {
MVMCoreUIActionHandler.defaultHandleUnknownActionType(actionType, actionInformation: actionInformation, additionalData: additionalData, delegateObject: delegateObjectIVar)
}
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - MoleculeDelegateProtocol // MARK: - MoleculeDelegateProtocol
//-------------------------------------------------- //--------------------------------------------------
open func getRootMolecules() -> [MoleculeModelProtocol] {
return model?.rootMolecules ?? []
}
open func getModuleWithName(_ name: String?) -> [AnyHashable: Any]? { open func getModuleWithName(_ name: String?) -> [AnyHashable: Any]? {
guard let name = name else { return nil } guard let name = name else { return nil }
return loadObject?.modulesJSON?.optionalDictionaryForKey(name) return loadObject?.modulesJSON?.optionalDictionaryForKey(name)

View File

@ -33,11 +33,10 @@ public class PageGetContactBehavior: PageVisibilityBehavior {
CNContactStore().requestAccess(for: .contacts) { [weak self] (access, error) in CNContactStore().requestAccess(for: .contacts) { [weak self] (access, error) in
guard access, guard access,
error == nil, error == nil,
// TODO: Clean up this interface let rootMolecules = self?.delegate?.moleculeDelegate?.getRootMolecules() else { return }
let model = (self?.delegate?.moleculeDelegate as? PageProtocol)?.pageModel as? TemplateModelProtocol else { return }
// Iterate models and provide contact // Iterate models and provide contact
let store = CNContactStore() let store = CNContactStore()
let consumers: [PageGetContactBehaviorConsumerProtocol] = model.allMoleculesOfType() let consumers: [PageGetContactBehaviorConsumerProtocol] = rootMolecules.allMoleculesOfType()
for consumer in consumers { for consumer in consumers {
guard let parameters = consumer.getMatchParameters(), guard let parameters = consumer.getMatchParameters(),
let contacts = try? store.unifiedContacts(matching: parameters.0, keysToFetch: parameters.1) else { return } let contacts = try? store.unifiedContacts(matching: parameters.0, keysToFetch: parameters.1) else { return }

View File

@ -14,6 +14,15 @@ public protocol PageBehaviorProtocol: ModelHandlerProtocol {
init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?)
} }
/**
Behavior conforming protocols. Behaviors will conform to one or more of these protocols to receive page lifecycle events that pertain to them.
*/
public protocol PageMoleculeTransformationBehavior {
func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject)
}
public protocol PageVisibilityBehavior: PageBehaviorProtocol { public protocol PageVisibilityBehavior: PageBehaviorProtocol {
func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?) func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?)
@ -22,7 +31,18 @@ public protocol PageVisibilityBehavior: PageBehaviorProtocol {
public protocol PageScrolledBehavior: PageBehaviorProtocol { public protocol PageScrolledBehavior: PageBehaviorProtocol {
func pageScrolled(scrollView: UIScrollView,_ delegateObject: MVMCoreUIDelegateObject?) func pageScrolled(scrollView: UIScrollView, _ delegateObject: MVMCoreUIDelegateObject?)
}
public protocol PageLocalDataShareBehavior: PageBehaviorProtocol {
func compileLocalPageDataForTransfer(_ delegateObject: MVMCoreUIDelegateObject) -> [AnyHashable: Any]
func receiveLocalPageData(_ data:[AnyHashable: Any], _ delegateObject: MVMCoreUIDelegateObject)
}
public protocol PageCustomActionHandlerBehavior: PageBehaviorProtocol {
func handleAction(type actionType: String?, information: [AnyHashable : Any]?, additionalData: [AnyHashable : Any]?) -> Bool
} }
public extension MVMCoreUIDelegateObject { public extension MVMCoreUIDelegateObject {

View File

@ -6,6 +6,7 @@
// Copyright © 2021 Verizon Wireless. All rights reserved. // Copyright © 2021 Verizon Wireless. All rights reserved.
// //
/// Protocol for molecules to implicity require behaviors.
public protocol PageBehaviorProtocolRequirer { public protocol PageBehaviorProtocolRequirer {
func getRequiredBehaviors() -> [PageBehaviorModelProtocol] func getRequiredBehaviors() -> [PageBehaviorModelProtocol]
} }