Centralize SoureModel

This commit is contained in:
Scott Pfeil 2022-08-12 16:17:05 -04:00
parent 31169e318e
commit 78034bb8d0
20 changed files with 58 additions and 84 deletions

View File

@ -23,10 +23,8 @@ open class ActionPopupHandler: MVMCoreActionHandlerProtocol {
return
}
(delegateObject?.actionDelegate as? MVMCoreUIActionDelegateProtocol)?.willShowPopup(with: alertObject, alertJson: json!)
Task {
_ = await MainActor.run {
MVMCoreAlertHandler.shared()?.showAlert(with: alertObject)
}
Task { @MainActor in
MVMCoreAlertHandler.shared()?.showAlert(with: alertObject)
continuation.resume()
}
})

View File

@ -12,8 +12,6 @@ import MVMCore
open class MVMCoreUIActionOpenPageHandler: ActionOpenPageHandler {
open override func performAction(with JSON: [AnyHashable : Any], model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
// Cleanup the source model data to prevent it from being accidentally auto-forwarded in openPage network requests by blind additionalData insertions. (https://onejira.verizon.com/browse/CXTDT-135642, https://onejira.verizon.com/browse/CXTDT-136001).
var additionalData = additionalData
additionalData?.removeValue(forKey: KeySourceModel)
try await super.performAction(with: JSON, model: model, delegateObject: delegateObject, additionalData: additionalData)
try await super.performAction(with: JSON, model: model, delegateObject: delegateObject, additionalData: MVMCoreUIActionHandler.removeSourceModel(from: additionalData))
}
}

View File

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

View File

@ -389,10 +389,7 @@ import MVMCore
}
private func performCheckboxAction(with actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
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)
}
MVMCoreUIActionHandler.performActionUnstructured(with: actionModel, sourceModel: checkboxModel, additionalData: additionalData, delegateObject: delegateObject)
}
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {

View File

@ -390,21 +390,16 @@ public typealias ActionBlockConfirmation = () -> (Bool)
accessibilityLabel = accessibileString
}
let additionalDataWithSource = additionalData.dictionaryAdding(key: KeySourceModel, value: model)
if model.action != nil || model.alternateAction != nil {
didToggleAction = { [weak self] in
guard let self = self else { return }
if self.isOn {
if let action = model.action {
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: action, additionalData: additionalDataWithSource, delegateObject: delegateObject)
}
MVMCoreUIActionHandler.performActionUnstructured(with: action, sourceModel: model, additionalData: additionalData, delegateObject: delegateObject)
}
} else {
if let action = model.alternateAction ?? model.action {
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: action, additionalData: additionalDataWithSource, delegateObject: delegateObject)
}
MVMCoreUIActionHandler.performActionUnstructured(with: action, sourceModel: model, additionalData: additionalData, delegateObject: delegateObject)
}
}
}

View File

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

View File

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

View File

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

View File

@ -28,7 +28,6 @@ import UIKit
let self = self,
let model = self.listItemModel as? DropDownListItemModel else { return }
let additionData = [KeySourceModel: model]
var actions: [ActionModelProtocol] = []
if let oldValue = oldValue,
oldValue.count > 0 {
@ -37,9 +36,7 @@ import UIKit
actions.append(AddMoleculesActionModel(.fade))
let actionsModel = ActionActionsModel(actions: actions)
actionsModel.concurrent = false
Task(priority: .userInitiated) {
try await (self.delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: actionsModel, additionalData: additionData, delegateObject: self.delegateObject)
}
MVMCoreUIActionHandler.performActionUnstructured(with: actionsModel, sourceModel: model, additionalData: nil, delegateObject: self.delegateObject)
}
}

View File

@ -57,9 +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 {
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: RemoveMoleculesActionModel(indexPath.row < tabs.selectedIndex ? .right : .left), additionalData: [KeySourceModel: model], delegateObject: delegateObject)
}
MVMCoreUIActionHandler.performActionUnstructured(with: RemoveMoleculesActionModel(indexPath.row < tabs.selectedIndex ? .right : .left), sourceModel: model, additionalData: nil, delegateObject: delegateObject)
}
previousTabIndex = tabs.selectedIndex
return true
@ -70,13 +68,9 @@ extension TabsTableViewCell: TabsDelegate {
guard let model = tabsListItemModel,
index < model.molecules.count else { return }
if let action = model.tabs.tabs[index].action {
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.performActionUnstructured(with: action, sourceModel: model.tabs, additionalData: nil, delegateObject: delegateObject)
}
MVMCoreUIActionHandler.performActionUnstructured(with: AddMoleculesActionModel(index < previousTabIndex ? .left : .right), sourceModel: model, additionalData: nil, delegateObject: delegateObject)
}
}

View File

@ -12,9 +12,7 @@ import MVMCore
@objcMembers open class NotificationXButton: Button {
open func closeTopAlert(with delegateObject: MVMCoreUIDelegateObject?) {
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: ActionDismissNotificationModel(), additionalData: nil, delegateObject: delegateObject)
}
MVMCoreUIActionHandler.performActionUnstructured(with: ActionDismissNotificationModel(), sourceModel: model, additionalData: nil, delegateObject: delegateObject)
}
open override func setupView() {

View File

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

View File

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

View File

@ -27,9 +27,7 @@ open class ModalSectionListTemplate: SectionListTemplate {
guard let self = self else { return }
let closeAction = (self.templateModel as? ModalSectionListTemplateModel)?.closeAction ??
ActionBackModel()
Task(priority: .userInitiated) {
try await (self.delegateObject()?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: closeAction, additionalData: nil, delegateObject: self.delegateObject())
}
MVMCoreUIActionHandler.performActionUnstructured(with: closeAction, additionalData: nil, delegateObject: self.delegateObject())
})
}
}

View File

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

View File

@ -88,11 +88,7 @@ public typealias ButtonAction = (Button) -> ()
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 (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: model, additionalData: additionalData, delegateObject: delegateObject)
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: model, additionalData: MVMCoreUIActionHandler.add(sourceModel: sourceModel, to: additionalData), delegateObject: delegateObject)
}
// MARK:- MoleculeViewProtocol

View File

@ -419,7 +419,7 @@ import MVMCore
/// Override this method to avoid adding form params.
open func addFormParams(requestParameters: MVMCoreRequestParameters, model: ActionOpenPageModel, additionalData: [AnyHashable: Any]?) {
formValidator?.addFormParams(requestParameters: requestParameters, model: additionalData?[KeySourceModel] as? MoleculeModelProtocol & FormItemProtocol)
formValidator?.addFormParams(requestParameters: requestParameters, model: MVMCoreUIActionHandler.getSourceModel(from: additionalData) as? MoleculeModelProtocol & FormItemProtocol)
}
public func handleFieldErrors(_ fieldErrors: [Any]?, loadObject: MVMCoreLoadObject) {

View File

@ -93,7 +93,7 @@ public class AddRemoveMoleculesBehavior: PageCustomActionHandlerBehavior, PageMo
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 sourceModel = MVMCoreUIActionHandler.getSourceModel(from: additionalData) as? (ListItemModelProtocol & MoleculeModelProtocol & AddMolecules),
let moleculesToAdd = sourceModel.getRecursiveMoleculesToAdd(),
let indexPath = list.getAdjustedIndexPath(for: sourceModel, position: moleculesToAdd.1) {
await MainActor.run {
@ -101,7 +101,7 @@ public class AddRemoveMoleculesBehavior: PageCustomActionHandlerBehavior, PageMo
}
} else if let model = model as? RemoveMoleculesActionModel,
let list = delegate?.moleculeListDelegate,
let sourceModel = additionalData?[KeySourceModel] as? (ListItemModelProtocol & MoleculeModelProtocol & RemoveMolecules),
let sourceModel = MVMCoreUIActionHandler.getSourceModel(from: additionalData) as? (ListItemModelProtocol & MoleculeModelProtocol & RemoveMolecules),
let moleculesToRemove = sourceModel.getRecursiveMoleculesToRemove() {
await MainActor.run {
list.removeMolecules(moleculesToRemove, animation: model.animation)

View File

@ -145,7 +145,9 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
open func shouldContinue(toErrorPage loadObject: MVMCoreLoadObject, error: MVMCoreErrorObject?) -> Bool {
// Push error screens so they do not replace the tab page.
loadObject.requestParameters?.navigationController = navigationController
MVMCoreDispatchUtility.performSyncBlock(onMainThread: {
loadObject.requestParameters?.navigationController = self.navigationController
})
loadObject.requestParameters?.loadStyle = .push
return true
}
@ -160,7 +162,7 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
/// Allow override of additioonal data for tab press action
open func getAdditionalDataForNewTabLoad(indexPath: IndexPath) -> [AnyHashable: Any]? {
return ["tabBarPressed": true, KeySourceModel: tabsModel]
return MVMCoreUIActionHandler.add(sourceModel: tabsModel, to: ["tabBarPressed": true])
}
/// Allows modification of requestParameters object for openPage request
@ -273,9 +275,7 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
} else if let tabsModel = tabs.tabsModel,
let action = tabsModel.tabs[indexPath.row].action {
// Perform the tab action
Task(priority: .userInitiated) {
try await (delegateObjectIVar.actionDelegate as? ActionDelegateProtocol)?.performAction(with: action, additionalData: getAdditionalDataForNewTabLoad(indexPath: indexPath), delegateObject: delegateObjectIVar)
}
MVMCoreUIActionHandler.performActionUnstructured(with: action, sourceModel: tabsModel, additionalData: getAdditionalDataForNewTabLoad(indexPath: indexPath), delegateObject: delegateObject())
}
return false
}

View File

@ -12,16 +12,38 @@ import SafariServices
@objc open class MVMCoreUIActionHandler: MVMCoreActionHandler {
/// Adds the source model to the additionalData
public static func add(sourceModel: MoleculeModelProtocol?, to additionalData: [AnyHashable: Any]?) -> [AnyHashable: Any]? {
guard let sourceModel = sourceModel else { return additionalData }
return additionalData.dictionaryAdding(key: KeySourceModel, value: sourceModel)
}
/// Gets the source model from the additionalData
public static func getSourceModel(from additionalData: [AnyHashable: Any]?) -> MoleculeModelProtocol? {
return additionalData?[KeySourceModel] as? MoleculeModelProtocol
}
/// Removes the source model to the additionalData
public static func removeSourceModel(from additionalData: [AnyHashable: Any]?) -> [AnyHashable: Any]? {
guard var additionalData = additionalData else { return nil }
additionalData.removeValue(forKey: KeySourceModel)
return additionalData
}
/// Starts the action in a task, adding the source model.
public static func performActionUnstructured(with model: ActionModelProtocol, sourceModel: MoleculeModelProtocol? = nil, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: model, additionalData: MVMCoreUIActionHandler.add(sourceModel: sourceModel, to: additionalData), delegateObject: delegateObject)
}
}
/// Logs the error and shows a popup if the error is not silent.
open override func defaultHandleActionError(_ error: MVMCoreErrorObject, additionalData: [AnyHashable : Any]?) {
super.defaultHandleActionError(error, additionalData: additionalData)
guard !error.silentError else { return }
Task(priority: .userInitiated) {
await MainActor.run {
// Show alert
let alertObject = MVMCoreAlertObject.init(popupAlertWithError: error, isGreedy: false)!
MVMCoreAlertHandler.shared()?.showAlert(with: alertObject)
}
Task(priority: .userInitiated) { @MainActor in
let alertObject = MVMCoreAlertObject.init(popupAlertWithError: error, isGreedy: false)!
MVMCoreAlertHandler.shared()?.showAlert(with: alertObject)
}
}