Merge branch 'develop' into feature/accessibilityHandler
This commit is contained in:
commit
48efbc73bf
@ -11,9 +11,19 @@ import Foundation
|
|||||||
open class ActionOpenPageHandler: MVMCoreJSONActionHandlerProtocol {
|
open class ActionOpenPageHandler: MVMCoreJSONActionHandlerProtocol {
|
||||||
required public init() {}
|
required public init() {}
|
||||||
|
|
||||||
|
func requestParamaters(for model: ActionOpenPageModel) -> MVMCoreRequestParameters {
|
||||||
|
let requestParameters = model.requestParameters.copy() as! MVMCoreRequestParameters
|
||||||
|
if let pageType = requestParameters.pageType {
|
||||||
|
// Re-evaluate required & optional modules as action models might have been generated prior to recent additions to the mapping.
|
||||||
|
requestParameters.modules = MVMCoreViewControllerMappingObject.shared()?.modulesRequired(forPageType: pageType) as? [String]
|
||||||
|
requestParameters.optionalModules = MVMCoreViewControllerMappingObject.shared()?.modulesOptional(forPageType: pageType) as? [String]
|
||||||
|
}
|
||||||
|
return requestParameters
|
||||||
|
}
|
||||||
|
|
||||||
open func performAction(with JSON: [AnyHashable : Any], model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
|
open func performAction(with JSON: [AnyHashable : Any], model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
|
||||||
guard let model = model as? ActionOpenPageModel else { return }
|
guard let model = model as? ActionOpenPageModel else { return }
|
||||||
let requestParameters: MVMCoreRequestParameters = model.requestParameters.copy() as! MVMCoreRequestParameters
|
let requestParameters = requestParamaters(for: model)
|
||||||
do {
|
do {
|
||||||
if let closure = delegateObject?.actionDelegate?.handleOpenPage {
|
if let closure = delegateObject?.actionDelegate?.handleOpenPage {
|
||||||
// Legacy code will use the old handler function and break the task chain here.
|
// Legacy code will use the old handler function and break the task chain here.
|
||||||
|
|||||||
@ -14,15 +14,7 @@ open class ActionShareHandler: MVMCoreActionHandlerProtocol {
|
|||||||
|
|
||||||
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) async throws {
|
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) async throws {
|
||||||
guard let model = model as? ActionShareModel else { return }
|
guard let model = model as? ActionShareModel else { return }
|
||||||
var shareData: [Any]
|
try await shareWith(activityItems: model.items.map { $0.value }, model: model)
|
||||||
switch model.sharedType {
|
|
||||||
case .text:
|
|
||||||
shareData = [model.sharedText]
|
|
||||||
case .url:
|
|
||||||
let url = try URL.createURL(with: model.sharedText)
|
|
||||||
shareData = [url]
|
|
||||||
}
|
|
||||||
try await shareWith(activityItems: shareData, model: model)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
@ -33,17 +25,7 @@ open class ActionShareHandler: MVMCoreActionHandlerProtocol {
|
|||||||
controller.completionWithItemsHandler = {(activityType: UIActivity.ActivityType?, completed: Bool, returnedItems: [Any]?, error: Error?) in
|
controller.completionWithItemsHandler = {(activityType: UIActivity.ActivityType?, completed: Bool, returnedItems: [Any]?, error: Error?) in
|
||||||
if completed {
|
if completed {
|
||||||
// Activity was completed, considered finished.
|
// Activity was completed, considered finished.
|
||||||
if activityType == .copyToPasteboard {
|
|
||||||
// Allow copy
|
|
||||||
MVMCoreSessionObject.sharedGlobal()?.copyString(toClipboard: model.sharedText)
|
|
||||||
}
|
|
||||||
continuation.resume()
|
continuation.resume()
|
||||||
} else if let _ = activityType {
|
|
||||||
// If a specific type of activity failed, the activity controller is still presented, cannot continue yet.
|
|
||||||
if let error = error,
|
|
||||||
let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: MVMCoreActionHandler.getErrorLocation(with: delegateObject?.actionDelegate, actionType: model.actionType)) {
|
|
||||||
MVMCoreLoggingHandler.addError(toLog: errorObject)
|
|
||||||
}
|
|
||||||
} else if let error = error {
|
} else if let error = error {
|
||||||
continuation.resume(throwing: error)
|
continuation.resume(throwing: error)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -6,14 +6,51 @@
|
|||||||
// Copyright © 2020 myverizon. All rights reserved.
|
// Copyright © 2020 myverizon. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
public struct ActionShareItemModel: Codable {
|
||||||
public struct ActionShareModel: ActionModelProtocol {
|
|
||||||
|
|
||||||
public enum SharedType: String, Codable {
|
public enum SharedType: String, Codable {
|
||||||
case text
|
case text
|
||||||
case url
|
case url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var type: SharedType
|
||||||
|
public var value: Any
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case type
|
||||||
|
case value
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(type: SharedType, value: Any) {
|
||||||
|
self.type = type
|
||||||
|
self.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(from decoder: Decoder) throws {
|
||||||
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
type = try typeContainer.decode(SharedType.self, forKey: .type)
|
||||||
|
switch type {
|
||||||
|
case .text:
|
||||||
|
value = try typeContainer.decode(String.self, forKey: .value)
|
||||||
|
case .url:
|
||||||
|
value = try typeContainer.decode(URL.self, forKey: .value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
try container.encode(type, forKey: .type)
|
||||||
|
switch type {
|
||||||
|
case .text:
|
||||||
|
try container.encode(value as! String, forKey: .value)
|
||||||
|
case .url:
|
||||||
|
try container.encode(value as! URL, forKey: .value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ActionShareModel: ActionModelProtocol {
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -21,8 +58,7 @@ public struct ActionShareModel: ActionModelProtocol {
|
|||||||
public static var identifier: String = "share"
|
public static var identifier: String = "share"
|
||||||
|
|
||||||
public var actionType: String = ActionShareModel.identifier
|
public var actionType: String = ActionShareModel.identifier
|
||||||
public var sharedType: SharedType
|
public var items: [ActionShareItemModel]
|
||||||
public var sharedText: String
|
|
||||||
public var extraParameters: JSONValueDictionary?
|
public var extraParameters: JSONValueDictionary?
|
||||||
public var analyticsData: JSONValueDictionary?
|
public var analyticsData: JSONValueDictionary?
|
||||||
|
|
||||||
@ -30,10 +66,54 @@ public struct ActionShareModel: ActionModelProtocol {
|
|||||||
// MARK: - Initializer
|
// MARK: - Initializer
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public init(sharedText: String, sharedType: SharedType, _ extraParameters: JSONValueDictionary? = nil, _ analyticsData: JSONValueDictionary? = nil) {
|
public init(items: [ActionShareItemModel], _ extraParameters: JSONValueDictionary? = nil, _ analyticsData: JSONValueDictionary? = nil) {
|
||||||
self.sharedType = sharedType
|
self.items = items
|
||||||
self.sharedText = sharedText
|
|
||||||
self.extraParameters = extraParameters
|
self.extraParameters = extraParameters
|
||||||
self.analyticsData = analyticsData
|
self.analyticsData = analyticsData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Codable
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case actionType
|
||||||
|
case items
|
||||||
|
case sharedType
|
||||||
|
case sharedText
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum DeprecatedCodingKeys: String, CodingKey {
|
||||||
|
case sharedType
|
||||||
|
case sharedText
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(from decoder: Decoder) throws {
|
||||||
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
if let items = try typeContainer.decodeIfPresent([ActionShareItemModel].self, forKey: .items) {
|
||||||
|
self.init(items: items)
|
||||||
|
} else {
|
||||||
|
// Legacy
|
||||||
|
try self.init(deprecatedFrom: decoder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private init(deprecatedFrom decoder: Decoder) throws {
|
||||||
|
let typeContainer = try decoder.container(keyedBy: DeprecatedCodingKeys.self)
|
||||||
|
let type = try typeContainer.decode(ActionShareItemModel.SharedType.self, forKey: .sharedType)
|
||||||
|
var value: Any
|
||||||
|
switch type {
|
||||||
|
case .url:
|
||||||
|
value = try typeContainer.decode(URL.self, forKey: .sharedText)
|
||||||
|
default:
|
||||||
|
value = try typeContainer.decode(String.self, forKey: .sharedText)
|
||||||
|
}
|
||||||
|
items = [ActionShareItemModel(type: type, value: value)]
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
try container.encode(actionType, forKey: .actionType)
|
||||||
|
try container.encode(items, forKey: .items)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -299,6 +299,9 @@
|
|||||||
if ([[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(getJSONForRequestParameters:)]) {
|
if ([[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(getJSONForRequestParameters:)]) {
|
||||||
NSDictionary *json = [[MVMCoreObject sharedInstance].globalLoadDelegate getJSONForRequestParameters:requestParameters];
|
NSDictionary *json = [[MVMCoreObject sharedInstance].globalLoadDelegate getJSONForRequestParameters:requestParameters];
|
||||||
if (json) {
|
if (json) {
|
||||||
|
#if HARD_CODED_RESPONSE_DELAY > 0
|
||||||
|
[NSThread sleepForTimeInterval:HARD_CODED_RESPONSE_DELAY];
|
||||||
|
#endif
|
||||||
completionHandler(json);
|
completionHandler(json);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -104,13 +104,17 @@
|
|||||||
timingOutIn: timeout) { (receivedParameter) in
|
timingOutIn: timeout) { (receivedParameter) in
|
||||||
// Queue the results for merge.
|
// Queue the results for merge.
|
||||||
parametersWorkQueue.async {
|
parametersWorkQueue.async {
|
||||||
if (returnedList[index] != nil) {
|
guard !complete else {
|
||||||
MVMCoreLoggingHandler.addError(toLog: MVMCoreErrorObject(title: nil, message: "Client parameter \(parameterType) has already executed. The completion handler should only be called once!", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: String(describing: ClientParameterHandler.self))!)
|
MVMCoreLoggingHandler.logDebugMessage(withDelegate: "Client \(parameterType) responded after task completion.")
|
||||||
} else {
|
return
|
||||||
MVMCoreLoggingHandler.shared()?.logCoreEvent(.clientParameterFetchComplete(name: parameterType, uuid: requestUUID[index], actionId: actionId))
|
|
||||||
returnedList[index] = receivedParameter
|
|
||||||
group.leave() // Leaving is only done after setup (barriered).
|
|
||||||
}
|
}
|
||||||
|
guard returnedList[index] == nil else {
|
||||||
|
MVMCoreLoggingHandler.addError(toLog: MVMCoreErrorObject(title: nil, message: "Client parameter \(parameterType) has already executed. The completion handler should only be called once!", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: String(describing: ClientParameterHandler.self))!)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
MVMCoreLoggingHandler.shared()?.logCoreEvent(.clientParameterFetchComplete(name: parameterType, uuid: requestUUID[index], actionId: actionId))
|
||||||
|
returnedList[index] = receivedParameter
|
||||||
|
group.leave() // Leaving is only done after setup (barriered).
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ public protocol ClientParameterProtocol: ModelHandlerProtocol {
|
|||||||
|
|
||||||
var clientParameterModel: ClientParameterModelProtocol { get set }
|
var clientParameterModel: ClientParameterModelProtocol { get set }
|
||||||
|
|
||||||
func fetchClientParameters(requestParameters: [String: Any], timingOutIn timeout: Double, completionHandler:@escaping ([String: AnyHashable]?) -> ())
|
func fetchClientParameters(requestParameters: [String: Any], timingOutIn timeout: TimeInterval, completionHandler:@escaping ([String: AnyHashable]?) -> ())
|
||||||
|
|
||||||
/// Default parameter for timeout scenarios. It will use the protocol extension method bydefault. Can override to send custom values.
|
/// Default parameter for timeout scenarios. It will use the protocol extension method bydefault. Can override to send custom values.
|
||||||
func valueOnTimeout() -> [String: AnyHashable]
|
func valueOnTimeout() -> [String: AnyHashable]
|
||||||
@ -28,10 +28,8 @@ public extension ClientParameterProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The handler should call this method to pass the parameter back to the caller.
|
/// The handler should call this method to pass the parameter back to the caller.
|
||||||
func returnParameters(_ isFlatMap: Bool, _ parameter: [String: AnyHashable]?, completionHandler: @escaping ([String: AnyHashable]?) -> ()) {
|
/// If using isFlatMap, you must provide at least 1 element in parameters or it will result in triggering a timeout.
|
||||||
guard let parameter = parameter else {
|
func returnParameters(_ isFlatMap: Bool, _ parameter: [String: AnyHashable], completionHandler: @escaping ([String: AnyHashable]?) -> ()) {
|
||||||
return completionHandler(nil)
|
|
||||||
}
|
|
||||||
if isFlatMap {
|
if isFlatMap {
|
||||||
completionHandler(parameter)
|
completionHandler(parameter)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -27,7 +27,7 @@ public extension MVMCoreActionUtility {
|
|||||||
- Parameter timemout: the time the operation has to finish before throwing a timeout error.
|
- Parameter timemout: the time the operation has to finish before throwing a timeout error.
|
||||||
- Parameter operation: the operation to perform.
|
- Parameter operation: the operation to perform.
|
||||||
*/
|
*/
|
||||||
static func perform<T>(with timeout: Int = 1, operation: @escaping @Sendable () async throws -> T) async throws -> T {
|
static func perform<T>(withTimeout timeout: TimeInterval, operation: @escaping @Sendable () async throws -> T) async throws -> T {
|
||||||
return try await withCheckedThrowingContinuation { continuation in
|
return try await withCheckedThrowingContinuation { continuation in
|
||||||
Task {
|
Task {
|
||||||
await withThrowingTaskGroup(of: T.self) { group in
|
await withThrowingTaskGroup(of: T.self) { group in
|
||||||
@ -40,7 +40,7 @@ public extension MVMCoreActionUtility {
|
|||||||
// Task for time out.
|
// Task for time out.
|
||||||
group.addTask {
|
group.addTask {
|
||||||
try Task.checkCancellation()
|
try Task.checkCancellation()
|
||||||
try await Task.sleep(nanoseconds: UInt64(timeout) * NSEC_PER_SEC)
|
try await Task.sleep(nanoseconds: UInt64(timeout * TimeInterval(NSEC_PER_SEC)))
|
||||||
throw MVMCoreActionUtilityError.timeOut
|
throw MVMCoreActionUtilityError.timeOut
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user