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:
parent
8da5c9d32b
commit
b89c1e66f5
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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?
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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 }
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user