Modernization migrations and json passing

This commit is contained in:
Scott Pfeil 2022-07-21 12:39:43 -04:00
parent 90adc247d1
commit f123be046c
10 changed files with 101 additions and 34 deletions

View File

@ -13,13 +13,18 @@ open class ActionBackHandler: MVMCoreActionHandlerProtocol {
public func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionBackModel else { return }
let json = try MVMCoreActionHandler.convertActionToJSON(model)
// TODO: Make this actually async properly.
if delegateObject?.actionDelegate?.handleBackAction != nil {
delegateObject?.actionDelegate?.handleBackAction?(json, additionalData: additionalData)
if let closure = delegateObject?.actionDelegate?.handleBackAction {
// Legacy code will use the old handler function and break the task chain here.
try await MVMCoreActionHandler.getOriginalJSON(with: model, additionalData: additionalData) { json, additionalData in
closure(json, additionalData)
}
} else {
Task {
await MVMCoreNavigationHandler.shared()?.removeCurrentViewController()
await withCheckedContinuation { (continuation: CheckedContinuation<Void, Never>) in
Task {
await MVMCoreNavigationHandler.shared()?.removeCurrentViewController(true, completionHandler: {
continuation.resume()
})
}
}
}
}

View File

@ -12,6 +12,8 @@ open class ActionCancelHandler: MVMCoreActionHandlerProtocol {
required public init() {}
open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
delegateObject?.actionDelegate?.handleCancel?(model.toJSON(), additionalData: additionalData)
try await MVMCoreActionHandler.getOriginalJSON(with: model, additionalData: additionalData) { json, additionalData in
delegateObject?.actionDelegate?.handleCancel?(json, additionalData: additionalData)
}
}
}

View File

@ -8,37 +8,47 @@
import Foundation
// TODO: Modernize this.
open class ActionOpenPageHandler: MVMCoreActionHandlerProtocol {
required public init() {}
open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionOpenPageModel else { return }
var requestParameters: MVMCoreRequestParameters
var additionalData = additionalData
if let _ = (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.getRequestParameters {
let value = try (delegateObject!.actionDelegate! as! ActionDelegateProtocol).getRequestParameters(for: model, delegateObject: delegateObject, additionalData: additionalData)
requestParameters = value.0
additionalData = value.1
} else {
let json = try MVMCoreActionHandler.convertActionToJSON(model)
requestParameters = MVMCoreRequestParameters(actionMap: json)!
try await MVMCoreActionHandler.getOriginalJSON(with: model, additionalData: additionalData) { json, additionalData in
var additionalData = additionalData
// Allows the delegate a chance to create and modify request parameters.
var requestParameters: MVMCoreRequestParameters
if let _ = (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.getRequestParameters {
let value = try (delegateObject!.actionDelegate! as! ActionDelegateProtocol).getRequestParameters(for: model, delegateObject: delegateObject, additionalData: additionalData)
requestParameters = value.0
additionalData = value.1
} else {
requestParameters = MVMCoreRequestParameters(actionMap: json)!
}
if let closure = delegateObject?.actionDelegate?.handleOpenPage {
// Legacy code will use the old handler function and break the task chain here.
closure(requestParameters, json, additionalData)
} else {
try await performRequestAddingClientParameters(with: requestParameters, model: model, delegateObject: delegateObject, additionalData: additionalData)
}
}
try await performRequestAddingClientParameters(with: requestParameters, model: model, delegateObject: delegateObject, additionalData: additionalData)
}
/// Adds client parameters and makes calls performRequest()
open func performRequestAddingClientParameters(with requestParameters: MVMCoreRequestParameters, model: ActionOpenPageModel, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
// Adds any client parameters to the request parameters.
if let parametersToFetch = model.clientParameters,
let fetchedParameters = try await getClientParameters(with: parametersToFetch, requestParameters: requestParameters.parameters as? [String : Any] ?? [:], showLoadingOverlay: !requestParameters.backgroundRequest) {
let fetchedParameters = try await ClientParameterHandler().getClientParameters(with: parametersToFetch, requestParameters: requestParameters.parameters as? [String : Any] ?? [:], showLoadingOverlay: !requestParameters.backgroundRequest) {
requestParameters.add(fetchedParameters)
}
// Makes the request and waits for it.
try await MVMCoreLoadHandler.sharedGlobal()?.performRequest(with: requestParameters, delegateObject: delegateObject, additionalData: additionalData)
}
}
public extension ClientParameterHandler {
/// Iterates through the clientParameters list. Gets values from the individual handlers and attaches the parameters to extraParameters.
func getClientParameters(with model: ClientParameterModel, requestParameters: [String: Any], showLoadingOverlay: Bool) async throws -> [String: Any]? {
@ -49,8 +59,7 @@ open class ActionOpenPageHandler: MVMCoreActionHandlerProtocol {
do {
let parameters: [String: Any]? = try await withCheckedThrowingContinuation({ continuation in
do {
let handler = ClientParameterHandler()
try handler.getParameters(with: model, requestParameters: requestParameters) { parameters in
try getParameters(with: model, requestParameters: requestParameters) { parameters in
MVMCoreLoadingOverlayHandler.sharedLoadingOverlay()?.stopLoading(true)
continuation.resume(returning: parameters)
}

View File

@ -91,13 +91,13 @@ open class ActionOpenUrlHandler: MVMCoreActionHandlerProtocol {
} as Void
}
public func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
open func performAction(_ model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionOpenUrlModel else { return }
// Try loading the app url first, otherwise fall back to browser url.
if let appURL = model.appURL {
do {
try await ActionOpenUrlHandler.open(url: appURL)
try await openURL(model: model, additionalData: additionalData, delegateObject: delegateObject)
return
} catch {
// Log error and continue
@ -107,6 +107,10 @@ open class ActionOpenUrlHandler: MVMCoreActionHandlerProtocol {
}
}
}
try await openURL(model: model, additionalData: additionalData, delegateObject: delegateObject)
}
open func openURL(model: ActionOpenUrlModel, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) async throws {
try await ActionOpenUrlHandler.open(url: model.browserUrl)
}
}

View File

@ -28,6 +28,9 @@ extension MVMCoreActionHandlerProtocol {
@objc open class MVMCoreActionHandler: NSObject {
/// The key used to pass along the json for the legacy handlers in additionalData
public static let originalJSONKey: String = "ORIGINAL_JSON"
enum ActionError: MVMError {
case unknownAction(type: String)
@ -37,6 +40,10 @@ extension MVMCoreActionHandlerProtocol {
return "Couldn't perform action: \(type)"
}
}
public var errorCode: Int {
ErrorCode.unknownActionType.rawValue
}
}
/// Returns the action handler stored in the MVMCoreObject
@ -156,12 +163,27 @@ extension MVMCoreActionHandlerProtocol {
/// Subclass to log the action was fired.
open func logAction(with model: ActionModelProtocol, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
// Calls legacy log action function.
delegateObject?.actionDelegate?.logAction?(withActionInformation: model.toJSON(), additionalData: additionalData)
Task {
try await MVMCoreActionHandler.getOriginalJSON(with: model, additionalData: additionalData) { json, additionalData in
delegateObject?.actionDelegate?.logAction?(withActionInformation: json, additionalData: additionalData)
}
}
}
/// Subclass to handle and any actions where a handler was not registered. Checks with the delegate handlesUnknownAction function
open func handleUnregisteredAction(with model: ActionModelProtocol, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) async throws -> Bool {
return try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.handlesUnknownAction(for: model, delegateObject: delegateObject, additionalData: additionalData) ?? false
// Check if the delegate handles the action.
if try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.handlesUnknownAction(for: model, delegateObject: delegateObject, additionalData: additionalData) == true {
return true
} else if let closure = delegateObject?.actionDelegate?.handleUnknownActionType {
// Check if the legacy delegate handles the action.
try await MVMCoreActionHandler.getOriginalJSON(with: model, additionalData: additionalData) { json, additionalData in
closure(model.actionType, json, additionalData)
}
return true
} else {
return false
}
}
/// Logs the error.
@ -172,11 +194,20 @@ extension MVMCoreActionHandlerProtocol {
// MARK: - Legacy Holdovers
public static func getOriginalJSON(with model: ActionModelProtocol, additionalData: [AnyHashable: Any]?, closure: ([AnyHashable: Any], [AnyHashable: Any]?) async throws -> Void) async throws {
var additionalData = additionalData
let json = try additionalData?[MVMCoreActionHandler.originalJSONKey] as? [AnyHashable: Any] ?? MVMCoreActionHandler.convertActionToJSON(model)
additionalData?.removeValue(forKey: MVMCoreActionHandler.originalJSONKey)
try await closure(json, additionalData)
}
/// Legacy handle action with json.
@objc(handleActionWithDictionary:additionalData:delegateObject:)
open func handleAction(with json: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ActionHandler: json \(String(describing: json))")
Task(priority: .userInitiated) {
var additionalData = additionalData ?? [:]
additionalData[MVMCoreActionHandler.originalJSONKey] = json
do {
guard let json = json else {
throw ModelRegistry.Error.keyNotFound
@ -184,9 +215,21 @@ extension MVMCoreActionHandlerProtocol {
let model = try MVMCoreActionHandler.createModel(with: json, delegateObject: delegateObject)
_ = asyncHandleAction(with: model, additionalData: additionalData, delegateObject: delegateObject)
} catch {
MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ActionHandler: Error \(error)")
let errorObject = getActionErrorObject(for: error, actionType: json?.stringForkey(KeyActionType) ?? "noAction", delegateObject: delegateObject)
handle(errorObject: errorObject, delegateObject: delegateObject, additionalData: additionalData)
switch error {
case ModelRegistry.Error.decoderErrorModelNotMapped:
// If the model is not mapped, give the legacy classes a chance to handle it.
let actionType = json?.optionalStringForKey(KeyActionType)
if let closure = delegateObject?.actionDelegate?.handleUnknownActionType {
additionalData.removeValue(forKey: MVMCoreActionHandler.originalJSONKey)
closure(actionType, json, additionalData)
} else {
fallthrough
}
default:
MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ActionHandler: Error \(error)")
let errorObject = getActionErrorObject(for: error, actionType: json?.stringForkey(KeyActionType) ?? "noAction", delegateObject: delegateObject)
handle(errorObject: errorObject, delegateObject: delegateObject, additionalData: additionalData)
}
}
}
}

View File

@ -24,7 +24,6 @@
#import "MVMCoreHardcodedStringsConstants.h"
#import "MVMCoreErrorConstants.h"
#import "MVMCoreActionUtility.h"
#import <MVMCore/MVMCoreActionHandler.h>
#import "MVMCoreObject.h"
#import "MVMCoreConstants.h"
#import <MVMCore/MVMCore-Swift.h>

View File

@ -66,7 +66,6 @@ FOUNDATION_EXPORT const unsigned char MVMCoreVersionString[];
#import <MVMCore/MVMCoreAlertController.h>
// Action Handling
#import <MVMCore/MVMCoreActionHandler.h>
#import <MVMCore/MVMCoreActionDelegateProtocol.h>
#import <MVMCore/MVMCoreActionUtility.h>

View File

@ -37,6 +37,9 @@
// pops or dimisses as needed
- (void)removeCurrentViewController;
/// Dismisses or pops the current view controller.
- (void)removeCurrentViewController:(BOOL)animated completionHandler:(nullable void (^)(void))completionBlock;
#pragma mark - Delegate Handling
/// Adds a listener for navigation delegate functions

View File

@ -118,12 +118,16 @@
}
- (void)removeCurrentViewController {
[self removeCurrentViewController:YES completionHandler:NULL];
}
- (void)removeCurrentViewController:(BOOL)animated completionHandler:(nullable void (^)(void))completionBlock {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
// presentedViewController must be used on main thread
if (self.viewControllerToPresentOn.presentedViewController) {
[[MVMCoreNavigationHandler sharedNavigationHandler] dismissTopViewControllerAnimated:YES];
[[MVMCoreNavigationHandler sharedNavigationHandler] dismissTopViewControllerAnimated:animated delegate:nil completionHandler:completionBlock];
} else {
[[MVMCoreNavigationHandler sharedNavigationHandler] popTopViewControllerAnimated:YES];
[[MVMCoreNavigationHandler sharedNavigationHandler] popTopViewControllerAnimated:animated navigationController:nil delegate:nil completionHandler:completionBlock];
}
}];
}

View File

@ -10,7 +10,6 @@
#import <MVMCore/MVMCoreSessionObject.h>
#import <MVMCore/MVMCoreCache.h>
#import <MVMCore/MVMCoreViewControllerMappingObject.h>
#import <MVMCore/MVMCoreActionHandler.h>
#import <MVMCore/MVMCoreSessionTimeHandler.h>
#import <MVMCore/MVMCoreGlobalLoadProtocol.h>
#import <MVMCore/MVMCoreLoadingOverlayDelegateProtocol.h>