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
//--------------------------------------------------
public static var identifier: String = "image"
open class var identifier: String { "image" }
public var backgroundColor: Color?
public var moleculeName: String = ImageViewModel.identifier
public var image: String

View File

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

View File

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

View File

@ -48,4 +48,32 @@ import Foundation
public init(body: LabelModel) {
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 {
func getRootMolecules() -> [MoleculeModelProtocol]
/// returns a module for the corresponding module name.
func getModuleWithName(_ name: String?) -> [AnyHashable : Any]?
func getModuleWithName(_ moleculeName: String) -> MoleculeModelProtocol?

View File

@ -143,7 +143,6 @@ import UIKit
// Parse the model for the page.
do {
try parsePageJSON()
return true
} catch let parsingError {
// Log all parsing errors and fail load.
handleLoggingFor(parsingError: parsingError)
@ -153,6 +152,14 @@ import UIKit
}
return false
}
if let pageData = loadObject.dataForPage {
executeBehaviors { (behavior: PageLocalDataShareBehavior) in
behavior.receiveLocalPageData(pageData, delegateObjectIVar)
}
}
return true
}
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,
open func handleNewData() {
executeBehaviors { (behavior: PageMoleculeTransformationBehavior) in
behavior.onPageNew(rootMolecules: getRootMolecules(), delegateObjectIVar)
}
if formValidator == nil {
let rules = model?.formRules
formValidator = FormValidator(rules)
@ -373,6 +384,10 @@ import UIKit
// Track.
MVMCoreUISession.sharedGlobal()?.currentPageType = pageType
MVMCoreUILoggingHandler.shared()?.defaultLogPageState(forController: self)
executeBehaviors { [weak self] (behavior: PageVisibilityBehavior) in
behavior.onPageShown(self?.delegateObjectIVar)
}
}
open override func viewDidAppear(_ animated: Bool) {
@ -381,10 +396,6 @@ import UIKit
if manager == nil {
pageShown()
}
executeBehaviors { [weak self] (behavior: PageVisibilityBehavior) in
behavior.onPageShown(self?.delegateObjectIVar)
}
}
open override func viewDidDisappear(_ animated: Bool) {
@ -463,17 +474,38 @@ import UIKit
open func handleOpenPage(for requestParameters: MVMCoreRequestParameters, actionInformation: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) {
addFormParams(requestParameters)
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]?) {
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
//--------------------------------------------------
open func getRootMolecules() -> [MoleculeModelProtocol] {
return model?.rootMolecules ?? []
}
open func getModuleWithName(_ name: String?) -> [AnyHashable: Any]? {
guard let name = name else { return nil }
return loadObject?.modulesJSON?.optionalDictionaryForKey(name)

View File

@ -33,11 +33,10 @@ public class PageGetContactBehavior: PageVisibilityBehavior {
CNContactStore().requestAccess(for: .contacts) { [weak self] (access, error) in
guard access,
error == nil,
// TODO: Clean up this interface
let model = (self?.delegate?.moleculeDelegate as? PageProtocol)?.pageModel as? TemplateModelProtocol else { return }
let rootMolecules = self?.delegate?.moleculeDelegate?.getRootMolecules() else { return }
// Iterate models and provide contact
let store = CNContactStore()
let consumers: [PageGetContactBehaviorConsumerProtocol] = model.allMoleculesOfType()
let consumers: [PageGetContactBehaviorConsumerProtocol] = rootMolecules.allMoleculesOfType()
for consumer in consumers {
guard let parameters = consumer.getMatchParameters(),
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?)
}
/**
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 {
func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?)
@ -22,7 +31,18 @@ public protocol PageVisibilityBehavior: 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 {

View File

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