Button -> Delegate -> ActionHandler.

Components will go through delegate. Delegate will choose how to handle it.
This commit is contained in:
Scott Pfeil 2022-08-08 17:45:28 -04:00
parent 126c464a92
commit d8bf3c9a08
32 changed files with 77 additions and 49 deletions

View File

@ -24,7 +24,7 @@ open class ActionAlertHandler: MVMCoreJSONActionHandlerProtocol {
}
}
open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
let json = try MVMCoreActionHandler.convertActionToJSON(model)
try await performAction(with: json, model: model, delegateObject: delegateObject, additionalData: additionalData)
}

View File

@ -13,7 +13,7 @@ import MVMCore
open class ActionCollapseNotificationHandler: MVMCoreActionHandlerProtocol {
required public init() {}
open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
CoreUIObject.sharedInstance()?.globalTopAlertDelegate?.getTopAlertView?().collapseNotification?()
}
}

View File

@ -13,7 +13,7 @@ import MVMCore
open class ActionDismissNotificationHandler: MVMCoreActionHandlerProtocol {
required public init() {}
open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
await withCheckedContinuation { continuation in
CoreUIObject.sharedInstance()?.globalTopAlertDelegate?.getTopAlertView?().hideAlertView?(true, completionHandler: { finished in
continuation.resume()

View File

@ -25,7 +25,7 @@ open class ActionOpenPanelHandler: MVMCoreJSONActionHandlerProtocol {
}
}
open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionOpenPanelModel else { return }
let json = try MVMCoreActionHandler.convertActionToJSON(model)
try await performAction(with: json, model: model, delegateObject: delegateObject, additionalData: additionalData)

View File

@ -13,7 +13,7 @@ import MVMCore
open class ActionPopupHandler: MVMCoreActionHandlerProtocol {
required public init() {}
open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionPopupModel else { return }
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
MVMCoreCache.shared()?.fetchJSON(forPageType: model.pageType, queue: nil, waitUntilFinished: true, completionHandler: { json in

View File

@ -13,7 +13,7 @@ import MVMCore
open class ActionTopAlertHandler: MVMCoreActionHandlerProtocol {
required public init() {}
open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionTopAlertModel else { return }
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
MVMCoreCache.shared()?.fetchJSON(forPageType: model.pageType, queue: nil, waitUntilFinished: true, completionHandler: { json in

View File

@ -13,7 +13,7 @@ import MVMCore
open class ActionTopNotificationHandler: MVMCoreActionHandlerProtocol {
required public init() {}
open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionTopNotificationModel else { return }
await MVMCoreUITopAlertView.sharedGlobal()?.showTopAlert(with: model.topNotification)
}

View File

@ -100,6 +100,8 @@ extension Tags: UICollectionViewDelegate {
open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let tagModel = tags?[indexPath.row],
let tagAction = tagModel.action else { return }
Button.performButtonAction(with: tagAction, button: self, delegateObject: delegateObject, additionalData: nil)
Task(priority: .userInitiated) {
try await Button.performButtonAction(with: tagAction, button: self, delegateObject: delegateObject, additionalData: nil)
}
}
}

View File

@ -100,6 +100,6 @@ import MVMCore
else { return }
let additionalDataWithSource = additionalData.dictionaryAdding(key: KeySourceModel, value: baseDropdownEntryFieldModel)
MVMCoreActionHandler.shared()?.asyncHandleAction(with: actionModel, additionalData: additionalDataWithSource, delegateObject: delegateObject)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: actionModel, additionalData: additionalDataWithSource, delegateObject: delegateObject)
}
}

View File

@ -391,7 +391,7 @@ import MVMCore
private func performCheckboxAction(with actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
var additionalDataToUpdate = additionalData ?? [:]
additionalDataToUpdate[KeySourceModel] = checkboxModel
MVMCoreActionHandler.shared()?.asyncHandleAction(with: actionModel, additionalData: additionalDataToUpdate, delegateObject: delegateObject)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: actionModel, additionalData: additionalDataToUpdate, delegateObject: delegateObject)
}
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {

View File

@ -106,7 +106,9 @@ import UIKit
guard isEnabled else { return }
isSelected = !isSelected
if let heartModel = heartModel {
Button.performButtonAction(with: heartModel.action, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: heartModel)
Task(priority: .userInitiated) {
try await Button.performButtonAction(with: heartModel.action, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: heartModel)
}
}
setNeedsDisplay()
}

View File

@ -142,7 +142,9 @@ open class RadioBox: Control, MFButtonProtocol {
isSelected = true
radioBoxModel?.selected = isSelected
if let radioBoxModel = radioBoxModel, let actionModel = radioBoxModel.action {
Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: radioBoxModel)
Task(priority: .userInitiated) {
try await Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: radioBoxModel)
}
}
layer.setNeedsDisplay()
}

View File

@ -104,7 +104,9 @@ import VDSFormControlsTokens
}
if let radioModel = radioModel, let actionModel = radioModel.action, isSelected, !wasPreviouslySelected {
Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: radioModel)
Task(priority: .userInitiated) {
try await Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: radioModel)
}
}
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)

View File

@ -124,7 +124,9 @@ open class RadioSwatch: Control, MFButtonProtocol {
isSelected = true
radioSwatchModel?.selected = isSelected
if let radioSwatchModel = radioSwatchModel, let actionModel = radioSwatchModel.action {
Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: radioSwatchModel)
Task(priority: .userInitiated) {
try await Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: radioSwatchModel)
}
}
layer.setNeedsDisplay()
}

View File

@ -396,11 +396,11 @@ public typealias ActionBlockConfirmation = () -> (Bool)
guard let self = self else { return }
if self.isOn {
if let action = model.action {
MVMCoreActionHandler.shared()?.asyncHandleAction(with: action, additionalData: additionalDataWithSource, delegateObject: delegateObject)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: action, additionalData: additionalDataWithSource, delegateObject: delegateObject)
}
} else {
if let action = model.alternateAction ?? model.action {
MVMCoreActionHandler.shared()?.asyncHandleAction(with: action, additionalData: additionalDataWithSource, delegateObject: delegateObject)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: action, additionalData: additionalDataWithSource, delegateObject: delegateObject)
}
}
}

View File

@ -387,7 +387,7 @@ public typealias ActionBlock = () -> ()
}
case let actionAtt as LabelAttributeActionModel:
addTappableLinkAttribute(range: NSRange(location: range.location, length: range.length)) {
MVMCoreActionHandler.shared()?.asyncHandleAction(with: actionAtt.action, additionalData: additionalData, delegateObject: delegateObject)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: actionAtt.action, additionalData: additionalData, delegateObject: delegateObject)
}
addActionAttributes(range: range, string: attributedString)

View File

@ -69,7 +69,10 @@ import VDSColorTokens
// MARK: - UITabBarDelegate
public func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
model.selectedTab = item.tag
Button.performButtonAction(with: model.tabs[item.tag].action, button: item, delegateObject: delegateObject, additionalData: nil)
let action = model.tabs[item.tag].action
Task(priority: .userInitiated) {
try await Button.performButtonAction(with: action, button: item, delegateObject: delegateObject, additionalData: nil)
}
}
// MARK: - TabBarProtocol

View File

@ -259,7 +259,7 @@ extension Tabs: UICollectionViewDelegateFlowLayout {
if let delegate = delegate {
delegate.didSelectItem(indexPath, tabs: self)
} else if let action = tabsModel.tabs[selectedIndex].action {
MVMCoreActionHandler.shared()?.asyncHandleAction(with: action, additionalData: [KeySourceModel: tabsModel], delegateObject:delegateObject)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: action, additionalData: [KeySourceModel: tabsModel], delegateObject:delegateObject)
}
if UIAccessibility.isVoiceOverRunning {
UIAccessibility.post(notification: .layoutChanged, argument: tabCell)

View File

@ -6,8 +6,8 @@
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
@objcMembers public class AccordionMoleculeTableViewCell: MoleculeTableViewCell {
import MVMCore
public class AccordionMoleculeTableViewCell: MoleculeTableViewCell {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -46,9 +46,9 @@
model.selected = accordionButton.isSelected
if accordionButton.isSelected {
MVMCoreActionHandler.shared()?.asyncHandleAction(with: AddMoleculesActionModel(.automatic), additionalData: [KeySourceModel: model], delegateObject: delegateObject)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: AddMoleculesActionModel(.automatic), additionalData: [KeySourceModel: model], delegateObject: delegateObject)
} else {
MVMCoreActionHandler.shared()?.asyncHandleAction(with: RemoveMoleculesActionModel(.automatic), additionalData: [KeySourceModel: model], delegateObject: delegateObject)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: RemoveMoleculesActionModel(.automatic), additionalData: [KeySourceModel: model], delegateObject: delegateObject)
}
if (accordionListItemModel?.hideLineWhenExpanded ?? false) && (self.bottomSeparatorView?.shouldBeVisible() ?? false) {
@ -56,7 +56,7 @@
}
if let actionModel = accordionButton.isSelected ? accordionListItemModel?.expandAction : accordionListItemModel?.collapseAction {
MVMCoreActionHandler.shared()?.asyncHandleAction(with: actionModel, additionalData: [KeySourceModel: model], delegateObject: delegateObject)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: actionModel, additionalData: [KeySourceModel: model], delegateObject: delegateObject)
}
}

View File

@ -37,7 +37,7 @@ import UIKit
actions.append(AddMoleculesActionModel(.fade))
let actionsModel = ActionActionsModel(actions: actions)
actionsModel.concurrent = false
MVMCoreActionHandler.shared()?.asyncHandleAction(with: actionsModel, additionalData: additionData, delegateObject: self.delegateObject)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: actionsModel, additionalData: additionData, delegateObject: self.delegateObject)
}
}

View File

@ -57,7 +57,7 @@ extension TabsTableViewCell: TabsDelegate {
public func shouldSelectItem(_ indexPath: IndexPath, tabs: Tabs) -> Bool {
guard indexPath.row != tabs.selectedIndex else { return false }
if let model = tabsListItemModel {
MVMCoreActionHandler.shared()?.asyncHandleAction(with: RemoveMoleculesActionModel(indexPath.row < tabs.selectedIndex ? .right : .left), additionalData: [KeySourceModel: model], delegateObject: delegateObject)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: RemoveMoleculesActionModel(indexPath.row < tabs.selectedIndex ? .right : .left), additionalData: [KeySourceModel: model], delegateObject: delegateObject)
}
previousTabIndex = tabs.selectedIndex
return true
@ -68,9 +68,9 @@ extension TabsTableViewCell: TabsDelegate {
guard let model = tabsListItemModel,
index < model.molecules.count else { return }
if let action = model.tabs.tabs[index].action {
MVMCoreActionHandler.shared()?.asyncHandleAction(with: action, additionalData: [KeySourceModel: model.tabs], delegateObject:delegateObject)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: action, additionalData: [KeySourceModel: model.tabs], delegateObject:delegateObject)
}
MVMCoreActionHandler.shared()?.asyncHandleAction(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

@ -60,7 +60,9 @@ import Foundation
if let topAction = model.topAction,
topAction.actionType == ActionNoopModel.identifier {
topView.button.addActionBlock(event: .touchUpInside) { [weak self] (button) in
Button.performButtonAction(with: topAction, button: button, delegateObject: delegateObject, additionalData: additionalData)
Task(priority: .userInitiated) {
try await Button.performButtonAction(with: topAction, button: button, delegateObject: delegateObject, additionalData: additionalData)
}
self?.expand(topViewShowing: model.alwaysShowTopLabel)
}
}

View File

@ -12,7 +12,7 @@ import MVMCore
@objcMembers open class NotificationXButton: Button {
open func closeTopAlert() {
MVMCoreUIActionHandler.shared()?.asyncHandleAction(with: ActionDismissNotificationModel(), additionalData: nil, delegateObject: nil)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: ActionDismissNotificationModel(), additionalData: nil, delegateObject: nil)
}
open override func setupView() {

View File

@ -32,7 +32,7 @@ open class ModalMoleculeListTemplate: MoleculeListTemplate {
guard let self = self else { return }
let closeAction = (self.templateModel as? ModalListPageTemplateModel)?.closeAction ??
ActionBackModel()
MVMCoreActionHandler.shared()?.asyncHandleAction(with: closeAction, additionalData: nil, delegateObject: self.delegateObjectIVar)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: closeAction, additionalData: nil, delegateObject: self.delegateObjectIVar)
})
}

View File

@ -28,7 +28,7 @@ open class ModalMoleculeStackTemplate: MoleculeStackTemplate {
guard let self = self else { return }
let closeAction = (self.templateModel as? ModalStackPageTemplateModel)?.closeAction ??
ActionBackModel()
MVMCoreActionHandler.shared()?.asyncHandleAction(with: closeAction, additionalData: nil, delegateObject: self.delegateObjectIVar)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: closeAction, additionalData: nil, delegateObject: self.delegateObjectIVar)
})
}
}

View File

@ -27,7 +27,7 @@ open class ModalSectionListTemplate: SectionListTemplate {
guard let self = self else { return }
let closeAction = (self.templateModel as? ModalSectionListTemplateModel)?.closeAction ??
ActionBackModel()
MVMCoreActionHandler.shared()?.asyncHandleAction(with: closeAction, additionalData: nil, delegateObject: self.delegateObjectIVar)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: closeAction, additionalData: nil, delegateObject: self.delegateObjectIVar)
})
}
}

View File

@ -33,7 +33,9 @@ public typealias BarButtonAction = (BarButtonItem) -> ()
buttonDelegate = delegateObject?.buttonDelegate
actionDelegate?.buttonAction = { sender in
let additionalDataWithSource = additionalData.dictionaryAdding(key: KeySourceModel, value: model)
Button.performButtonAction(with: model.action, button: sender, delegateObject: delegateObject, additionalData: additionalDataWithSource)
Task(priority: .userInitiated) {
try await Button.performButtonAction(with: model.action, button: sender, delegateObject: delegateObject, additionalData: additionalDataWithSource)
}
}
}
}

View File

@ -6,8 +6,9 @@
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
public typealias ButtonAction = (Button) -> ()
import MVMCore
public typealias ButtonAction = (Button) -> ()
@objcMembers open class Button: UIButton, MFButtonProtocol, MoleculeViewProtocol {
//--------------------------------------------------
@ -79,21 +80,19 @@ public typealias ButtonAction = (Button) -> ()
addActionBlock(event: .touchUpInside) { [weak self] sender in
guard let self = self, let actionModel = actionModel else { return }
Self.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: self.model)
Task(priority: .userInitiated) {
try await Self.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: self.model)
}
}
}
open class func performButtonAction(with model: ActionModelProtocol, button: MFButtonProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, sourceModel: MoleculeModelProtocol? = nil) {
if let data = try? model.encode(using: JSONEncoder()),
let actionMap = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.init()) as? [AnyHashable: Any],
delegateObject?.buttonDelegate?.button?(button, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true {
if let sourceModel = sourceModel {
let additionalDataWithSource = additionalData.dictionaryAdding(key: KeySourceModel, value: sourceModel)
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalDataWithSource, delegateObject: delegateObject)
} else {
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
}
open class func performButtonAction(with model: ActionModelProtocol, button: MFButtonProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, sourceModel: MoleculeModelProtocol? = nil) async throws {
guard delegateObject?.buttonDelegate?.button?(button, shouldPerformActionWithMap: model.toJSON(), additionalData: additionalData) ?? true else { return }
var additionalData = additionalData
if let sourceModel = sourceModel {
additionalData = additionalData.dictionaryAdding(key: KeySourceModel, value: sourceModel)
}
try await MVMCoreUIActionHandler.handleActionCheckingDelegate(with: model, additionalData: additionalData, delegateObject: delegateObject)
}
// MARK:- MoleculeViewProtocol

View File

@ -118,7 +118,9 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo
open func shouldSelect(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Bool {
if let action = model?.action {
Button.performButtonAction(with: action, button: self, delegateObject: delegateObject, additionalData: additionalData)
Task(priority: .userInitiated) {
try await Button.performButtonAction(with: action, button: self, delegateObject: delegateObject, additionalData: additionalData)
}
}
return false
}

View File

@ -256,7 +256,9 @@ import UIKit
open func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
guard let action = listItemModel?.action else { return }
Button.performButtonAction(with: action, button: self, delegateObject: delegateObject, additionalData: additionalData)
Task(priority: .userInitiated) {
try await Button.performButtonAction(with: action, button: self, delegateObject: delegateObject, additionalData: additionalData)
}
}
open func didDeselectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { }

View File

@ -467,6 +467,14 @@ import MVMCore
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)
}
}
//--------------------------------------------------
// MARK: - MoleculeDelegateProtocol
//--------------------------------------------------

View File

@ -277,7 +277,7 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
} else if let tabsModel = tabs.tabsModel,
let action = tabsModel.tabs[indexPath.row].action {
// Perform the tab action
MVMCoreActionHandler.shared()?.asyncHandleAction(with: action, additionalData: getAdditionalDataForNewTabLoad(indexPath: indexPath), delegateObject: delegateObjectIVar)
MVMCoreUIActionHandler.asyncHandleActionCheckingDelegate(with: action, additionalData: getAdditionalDataForNewTabLoad(indexPath: indexPath), delegateObject: delegateObjectIVar)
}
return false
}