Drive through delegate up front. Remove some legacy delegate back and forth

This commit is contained in:
Scott Pfeil 2022-08-10 22:19:01 -04:00
parent d8bf3c9a08
commit 1f75221915
17 changed files with 118 additions and 81 deletions

View File

@ -100,6 +100,8 @@ import MVMCore
else { return }
let additionalDataWithSource = additionalData.dictionaryAdding(key: KeySourceModel, value: baseDropdownEntryFieldModel)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: actionModel, additionalData: additionalDataWithSource, delegateObject: delegateObject)
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: actionModel, additionalData: additionalDataWithSource, delegateObject: delegateObject)
}
}
}

View File

@ -389,9 +389,10 @@ import MVMCore
}
private func performCheckboxAction(with actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
var additionalDataToUpdate = additionalData ?? [:]
additionalDataToUpdate[KeySourceModel] = checkboxModel
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: actionModel, additionalData: additionalDataToUpdate, delegateObject: delegateObject)
let additionalDataToUpdate = (checkboxModel != nil) ? additionalData.dictionaryAdding(key: KeySourceModel, value: checkboxModel!) : additionalData
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: actionModel, additionalData: additionalDataToUpdate, delegateObject: delegateObject)
}
}
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {

View File

@ -396,11 +396,15 @@ public typealias ActionBlockConfirmation = () -> (Bool)
guard let self = self else { return }
if self.isOn {
if let action = model.action {
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: action, additionalData: additionalDataWithSource, delegateObject: delegateObject)
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: action, additionalData: additionalDataWithSource, delegateObject: delegateObject)
}
}
} else {
if let action = model.alternateAction ?? model.action {
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: action, additionalData: additionalDataWithSource, delegateObject: delegateObject)
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: action, additionalData: additionalDataWithSource, delegateObject: delegateObject)
}
}
}
}

View File

@ -387,7 +387,9 @@ public typealias ActionBlock = () -> ()
}
case let actionAtt as LabelAttributeActionModel:
addTappableLinkAttribute(range: NSRange(location: range.location, length: range.length)) {
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: actionAtt.action, additionalData: additionalData, delegateObject: delegateObject)
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: actionAtt.action, additionalData: additionalData, delegateObject: delegateObject)
}
}
addActionAttributes(range: range, string: attributedString)

View File

@ -259,7 +259,9 @@ extension Tabs: UICollectionViewDelegateFlowLayout {
if let delegate = delegate {
delegate.didSelectItem(indexPath, tabs: self)
} else if let action = tabsModel.tabs[selectedIndex].action {
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: action, additionalData: [KeySourceModel: tabsModel], delegateObject:delegateObject)
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: action, additionalData: [KeySourceModel: tabsModel], delegateObject: delegateObject)
}
}
if UIAccessibility.isVoiceOverRunning {
UIAccessibility.post(notification: .layoutChanged, argument: tabCell)

View File

@ -46,9 +46,13 @@ public class AccordionMoleculeTableViewCell: MoleculeTableViewCell {
model.selected = accordionButton.isSelected
if accordionButton.isSelected {
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: AddMoleculesActionModel(.automatic), additionalData: [KeySourceModel: model], delegateObject: delegateObject)
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: AddMoleculesActionModel(.automatic), additionalData: [KeySourceModel: model], delegateObject: delegateObject)
}
} else {
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: RemoveMoleculesActionModel(.automatic), additionalData: [KeySourceModel: model], delegateObject: delegateObject)
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: RemoveMoleculesActionModel(.automatic), additionalData: [KeySourceModel: model], delegateObject: delegateObject)
}
}
if (accordionListItemModel?.hideLineWhenExpanded ?? false) && (self.bottomSeparatorView?.shouldBeVisible() ?? false) {
@ -56,7 +60,9 @@ public class AccordionMoleculeTableViewCell: MoleculeTableViewCell {
}
if let actionModel = accordionButton.isSelected ? accordionListItemModel?.expandAction : accordionListItemModel?.collapseAction {
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: actionModel, additionalData: [KeySourceModel: model], delegateObject: delegateObject)
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: actionModel, additionalData: [KeySourceModel: model], delegateObject: delegateObject)
}
}
}

View File

@ -37,7 +37,9 @@ import UIKit
actions.append(AddMoleculesActionModel(.fade))
let actionsModel = ActionActionsModel(actions: actions)
actionsModel.concurrent = false
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: actionsModel, additionalData: additionData, delegateObject: self.delegateObject)
Task(priority: .userInitiated) {
try await (self.delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: actionsModel, additionalData: additionData, delegateObject: self.delegateObject)
}
}
}

View File

@ -57,7 +57,9 @@ extension TabsTableViewCell: TabsDelegate {
public func shouldSelectItem(_ indexPath: IndexPath, tabs: Tabs) -> Bool {
guard indexPath.row != tabs.selectedIndex else { return false }
if let model = tabsListItemModel {
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: RemoveMoleculesActionModel(indexPath.row < tabs.selectedIndex ? .right : .left), additionalData: [KeySourceModel: model], delegateObject: delegateObject)
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: RemoveMoleculesActionModel(indexPath.row < tabs.selectedIndex ? .right : .left), additionalData: [KeySourceModel: model], delegateObject: delegateObject)
}
}
previousTabIndex = tabs.selectedIndex
return true
@ -68,9 +70,13 @@ extension TabsTableViewCell: TabsDelegate {
guard let model = tabsListItemModel,
index < model.molecules.count else { return }
if let action = model.tabs.tabs[index].action {
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: action, additionalData: [KeySourceModel: model.tabs], delegateObject:delegateObject)
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: action, additionalData: [KeySourceModel: model.tabs], delegateObject: delegateObject)
}
}
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: AddMoleculesActionModel(index < previousTabIndex ? .left : .right), additionalData: [KeySourceModel: model], delegateObject: delegateObject)
}
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: AddMoleculesActionModel(index < previousTabIndex ? .left : .right), additionalData: [KeySourceModel: model], delegateObject: delegateObject)
}
}

View File

@ -11,8 +11,10 @@ import MVMCore
@objcMembers open class NotificationXButton: Button {
open func closeTopAlert() {
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: ActionDismissNotificationModel(), additionalData: nil, delegateObject: nil)
open func closeTopAlert(with delegateObject: MVMCoreUIDelegateObject?) {
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: ActionDismissNotificationModel(), additionalData: nil, delegateObject: delegateObject)
}
}
open override func setupView() {
@ -35,7 +37,7 @@ import MVMCore
// TODO: Temporary, consider action for dismissing top alert
if model.action.actionType == ActionNoopModel.identifier {
addActionBlock(event: .touchUpInside) { (button) in
(button as? NotificationXButton)?.closeTopAlert()
(button as? NotificationXButton)?.closeTopAlert(with: delegateObject)
}
}
}

View File

@ -7,7 +7,7 @@
//
import UIKit
import MVMCore
open class ModalMoleculeListTemplate: MoleculeListTemplate {
//--------------------------------------------------
@ -32,7 +32,9 @@ open class ModalMoleculeListTemplate: MoleculeListTemplate {
guard let self = self else { return }
let closeAction = (self.templateModel as? ModalListPageTemplateModel)?.closeAction ??
ActionBackModel()
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: closeAction, additionalData: nil, delegateObject: self.delegateObjectIVar)
Task(priority: .userInitiated) {
try await (self.delegateObject()?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: closeAction, additionalData: nil, delegateObject: self.delegateObject())
}
})
}

View File

@ -7,6 +7,7 @@
//
import UIKit
import MVMCore
open class ModalMoleculeStackTemplate: MoleculeStackTemplate {
//--------------------------------------------------
@ -28,7 +29,9 @@ open class ModalMoleculeStackTemplate: MoleculeStackTemplate {
guard let self = self else { return }
let closeAction = (self.templateModel as? ModalStackPageTemplateModel)?.closeAction ??
ActionBackModel()
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: closeAction, additionalData: nil, delegateObject: self.delegateObjectIVar)
Task(priority: .userInitiated) {
try await (self.delegateObject()?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: closeAction, additionalData: nil, delegateObject: self.delegateObject())
}
})
}
}

View File

@ -5,7 +5,7 @@
// Created by Scott Pfeil on 10/8/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import MVMCore
open class ModalSectionListTemplate: SectionListTemplate {
//--------------------------------------------------
@ -27,7 +27,9 @@ open class ModalSectionListTemplate: SectionListTemplate {
guard let self = self else { return }
let closeAction = (self.templateModel as? ModalSectionListTemplateModel)?.closeAction ??
ActionBackModel()
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: closeAction, additionalData: nil, delegateObject: self.delegateObjectIVar)
Task(priority: .userInitiated) {
try await (self.delegateObject()?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: closeAction, additionalData: nil, delegateObject: self.delegateObject())
}
})
}
}

View File

@ -92,7 +92,7 @@ public typealias ButtonAction = (Button) -> ()
if let sourceModel = sourceModel {
additionalData = additionalData.dictionaryAdding(key: KeySourceModel, value: sourceModel)
}
try await MVMCoreUIActionHandler.handleActionCheckingDelegate(with: model, additionalData: additionalData, delegateObject: delegateObject)
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: model, additionalData: additionalData, delegateObject: delegateObject)
}
// MARK:- MoleculeViewProtocol

View File

@ -9,7 +9,7 @@
import UIKit
import MVMCore
@objc open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMCoreViewManagerViewControllerProtocol, MoleculeDelegateProtocol, FormHolderProtocol, MVMCoreActionDelegateProtocol, ActionDelegateProtocol, ActionOpenPageDelegateProtocol, MVMCoreLoadDelegateProtocol, UITextFieldDelegate, UITextViewDelegate, ObservingTextFieldDelegate, MVMCoreUIDetailViewProtocol, PageProtocol, PageBehaviorHandlerProtocol {
@objc open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMCoreViewManagerViewControllerProtocol, MoleculeDelegateProtocol, FormHolderProtocol, MVMCoreActionDelegateProtocol, ActionDelegateProtocol, MVMCoreLoadDelegateProtocol, UITextFieldDelegate, UITextViewDelegate, ObservingTextFieldDelegate, MVMCoreUIDetailViewProtocol, PageProtocol, PageBehaviorHandlerProtocol {
//--------------------------------------------------
// MARK: - Properties
@ -439,40 +439,41 @@ import MVMCore
//--------------------------------------------------
// MARK: - MVMCoreActionDelegateProtocol
//--------------------------------------------------
open func getRequestParameters(for model: ActionOpenPageModel, delegateObject: DelegateObject? = nil, additionalData: [AnyHashable : Any]? = nil) throws -> (MVMCoreRequestParameters,[AnyHashable : Any]?) {
let json = try MVMCoreActionHandler.convertActionToJSON(model)
let requestParameters = MVMCoreRequestParameters(actionMap: json)!
addFormParams(requestParameters: requestParameters, model: model, additionalData: additionalData)
requestParameters.parentPageType = loadObject?.pageJSON?.optionalStringForKey("parentPageType")
var pageForwardedData = additionalData ?? [:]
executeBehaviors { (behavior: PageLocalDataShareBehavior) in
let dataMap = behavior.compileLocalPageDataForTransfer(delegateObjectIVar)
pageForwardedData.merge(dataMap) { current, _ in current }
}
return (requestParameters, pageForwardedData)
}
open func logAction(withActionInformation actionInformation: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) {
MVMCoreUILoggingHandler.shared()?.defaultLogAction(forController: self, actionInformation: actionInformation, additionalData: additionalData)
}
public func handlesUnknownAction(for model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws -> Bool {
var handled = false
executeBehaviors { (behavior: PageCustomActionHandlerBehavior) in
if !handled {
handled = behavior.handleAction(with: model, additionalData: additionalData)
open func performAction(with model: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) async throws {
var additionalData = additionalData
if let model = model as? ActionOpenPageModel {
addFormParams(requestParameters: model.requestParameters, model: model, additionalData: additionalData)
model.requestParameters.parentPageType = loadObject?.pageJSON?.optionalStringForKey("parentPageType")
var pageForwardedData = additionalData ?? [:]
executeBehaviors { (behavior: PageLocalDataShareBehavior) in
let dataMap = behavior.compileLocalPageDataForTransfer(delegateObjectIVar)
pageForwardedData.merge(dataMap) { current, _ in current }
}
additionalData = pageForwardedData
}
do {
if let behavior = behaviors?.compactMap({ $0 as? PageCustomActionHandlerBehavior }).first(where: { $0.canHandleAction(with: model, additionalData: additionalData) }) {
delegateObject?.actionDelegate?.logAction?(withActionInformation: model.toJSON(), additionalData: additionalData)
try await behavior.handleAction(with: model, additionalData: additionalData)
} else {
try await MVMCoreUIActionHandler.shared()?.handleAction(with: model, additionalData: additionalData, delegateObject: delegateObject)
}
} catch {
handleAction(error: error, model: model, additionalData: additionalData, delegateObject: delegateObject)
throw error
}
return handled
}
open func performAction(with model: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) async throws {
do {
try await MVMCoreUIActionHandler.shared()?.handleAction(with: model, additionalData: additionalData, delegateObject: delegateObject)
} catch {
MVMCoreUIActionHandler.shared()?.defaultHandle(error: error, model: model, additionalData: additionalData, delegateObject: delegateObject)
}
open func handleAction(error: Error, model: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) {
let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: MVMCoreActionHandler.getErrorLocation(with: delegateObject?.actionDelegate, actionType: model.actionType))!
MVMCoreUIActionHandler.shared()?.defaultHandleActionError(errorObject, additionalData: additionalData)
}
//--------------------------------------------------

View File

@ -7,6 +7,7 @@
//
import Foundation
import MVMCore
public enum AddMoleculesPosition {
case above
@ -85,28 +86,27 @@ public class AddRemoveMoleculesBehavior: PageCustomActionHandlerBehavior, PageMo
}
}
public func handleAction(with model: ActionModelProtocol, additionalData: [AnyHashable : Any]?) -> Bool {
if model.actionType == AddMoleculesActionModel.identifier {
guard let model = model as? AddMoleculesActionModel,
let list = delegate?.moleculeListDelegate,
let sourceModel = additionalData?[KeySourceModel] as? (ListItemModelProtocol & MoleculeModelProtocol & AddMolecules),
let moleculesToAdd = sourceModel.getRecursiveMoleculesToAdd(),
let indexPath = list.getAdjustedIndexPath(for: sourceModel, position: moleculesToAdd.1) else { return true }
DispatchQueue.main.async {
public func canHandleAction(with model: ActionModelProtocol, additionalData: [AnyHashable : Any]?) -> Bool {
return model.actionType == AddMoleculesActionModel.identifier || model.actionType == RemoveMoleculesActionModel.identifier
}
public func handleAction(with model: ActionModelProtocol, additionalData: [AnyHashable : Any]?) async throws {
if let model = model as? AddMoleculesActionModel,
let list = delegate?.moleculeListDelegate,
let sourceModel = additionalData?[KeySourceModel] as? (ListItemModelProtocol & MoleculeModelProtocol & AddMolecules),
let moleculesToAdd = sourceModel.getRecursiveMoleculesToAdd(),
let indexPath = list.getAdjustedIndexPath(for: sourceModel, position: moleculesToAdd.1) {
await MainActor.run {
list.addMolecules(moleculesToAdd.0, indexPath: indexPath, animation: model.animation)
}
return true
} else if model.actionType == RemoveMoleculesActionModel.identifier {
guard let model = model as? RemoveMoleculesActionModel,
} else if let model = model as? RemoveMoleculesActionModel,
let list = delegate?.moleculeListDelegate,
let sourceModel = additionalData?[KeySourceModel] as? (ListItemModelProtocol & MoleculeModelProtocol & RemoveMolecules),
let moleculesToRemove = sourceModel.getRecursiveMoleculesToRemove() else { return true }
DispatchQueue.main.async {
let moleculesToRemove = sourceModel.getRecursiveMoleculesToRemove() {
await MainActor.run {
list.removeMolecules(moleculesToRemove, animation: model.animation)
}
return true
}
return false
}
}

View File

@ -6,6 +6,8 @@
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import MVMCore
public protocol PageBehaviorProtocol: ModelHandlerProtocol {
@ -65,12 +67,14 @@ public protocol PageLocalDataShareBehavior: PageBehaviorProtocol {
}
public protocol PageCustomActionHandlerBehavior: PageBehaviorProtocol {
/// Returns if this behavior can handle the action.
func canHandleAction(with model: ActionModelProtocol, additionalData: [AnyHashable : Any]?) -> Bool
/// - Parameters:
/// - model: The action model.
/// - additionalData: Additional information of the
/// - Returns: Boolean determines if the action has been handled.
func handleAction(with model: ActionModelProtocol, additionalData: [AnyHashable : Any]?) -> Bool
func handleAction(with model: ActionModelProtocol, additionalData: [AnyHashable : Any]?) async throws
}
public extension MVMCoreUIDelegateObject {

View File

@ -170,19 +170,15 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
requestParameters.tabWasPressed = true
return requestParameters
}
open override func getRequestParameters(for model: ActionOpenPageModel, delegateObject: DelegateObject? = nil, additionalData: [AnyHashable : Any]? = nil) throws -> (MVMCoreRequestParameters, [AnyHashable : Any]?) {
let value = try super.getRequestParameters(for: model, delegateObject: delegateObject, additionalData: additionalData)
var requestParameters = value.0
let additionalData = value.1
guard let additionalData = additionalData,
additionalData.boolForKey("tabBarPressed") else {
// Pass to delegate
return try (viewController as? ActionOpenPageDelegateProtocol)?.getRequestParameters(for: model, delegateObject: delegateObject, additionalData: additionalData) ?? value
}
// Allow opportunity to modify parameters.
requestParameters = getRequestParametersForNewTabLoad(requestParameters: requestParameters, model: model, additionalData: additionalData)
return (requestParameters, additionalData)
open override func performAction(with model: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) async throws {
if let model = model as? ActionOpenPageModel,
let additionalData = additionalData,
additionalData.boolForKey("tabBarPressed") {
// Allow opportunity to modify parameters.
model.requestParameters = getRequestParametersForNewTabLoad(requestParameters: model.requestParameters, model: model, additionalData: additionalData)
}
try await super.performAction(with: model, additionalData: additionalData, delegateObject: delegateObject)
}
// MARK: - MVMCorePresentationDelegateProtocol
@ -277,7 +273,9 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
} else if let tabsModel = tabs.tabsModel,
let action = tabsModel.tabs[indexPath.row].action {
// Perform the tab action
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: action, additionalData: getAdditionalDataForNewTabLoad(indexPath: indexPath), delegateObject: delegateObjectIVar)
Task(priority: .userInitiated) {
try await (delegateObjectIVar.actionDelegate as? ActionDelegateProtocol)?.performAction(with: action, additionalData: getAdditionalDataForNewTabLoad(indexPath: indexPath), delegateObject: delegateObjectIVar)
}
}
return false
}