ONEAPP-5208: Swiftify the navigation handler
This commit is contained in:
parent
6877763d07
commit
64535c6b21
@ -97,6 +97,7 @@
|
||||
AF60A7F4289212EB00919EEB /* MVMCoreError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F3289212EB00919EEB /* MVMCoreError.swift */; };
|
||||
AF686FDA2A8A876A008F666A /* NavigationOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF686FD92A8A876A008F666A /* NavigationOperation.swift */; };
|
||||
AF686FDC2A8A87EA008F666A /* KVOPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF686FDB2A8A87EA008F666A /* KVOPublisher.swift */; };
|
||||
AF686FDE2A8D29CD008F666A /* MVMCoreLoadRequestOperation+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF686FDD2A8D29CD008F666A /* MVMCoreLoadRequestOperation+Extension.swift */; };
|
||||
AF69D4E9286E54D500BC6862 /* ActionCallHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF69D4E8286E54D500BC6862 /* ActionCallHandler.swift */; };
|
||||
AF69D4EB286E586200BC6862 /* ActionRestartHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF69D4EA286E586200BC6862 /* ActionRestartHandler.swift */; };
|
||||
AF69D4ED286E5D8C00BC6862 /* ActionCancelHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF69D4EC286E5D8C00BC6862 /* ActionCancelHandler.swift */; };
|
||||
@ -252,6 +253,7 @@
|
||||
AF60A7F3289212EB00919EEB /* MVMCoreError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreError.swift; sourceTree = "<group>"; };
|
||||
AF686FD92A8A876A008F666A /* NavigationOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationOperation.swift; sourceTree = "<group>"; };
|
||||
AF686FDB2A8A87EA008F666A /* KVOPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KVOPublisher.swift; sourceTree = "<group>"; };
|
||||
AF686FDD2A8D29CD008F666A /* MVMCoreLoadRequestOperation+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreLoadRequestOperation+Extension.swift"; sourceTree = "<group>"; };
|
||||
AF69D4E8286E54D500BC6862 /* ActionCallHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionCallHandler.swift; sourceTree = "<group>"; };
|
||||
AF69D4EA286E586200BC6862 /* ActionRestartHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionRestartHandler.swift; sourceTree = "<group>"; };
|
||||
AF69D4EC286E5D8C00BC6862 /* ActionCancelHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionCancelHandler.swift; sourceTree = "<group>"; };
|
||||
@ -562,6 +564,7 @@
|
||||
AFBB964B1FBA3A560008D868 /* MVMCoreLoadHandler.m */,
|
||||
AFBB964A1FBA3A560008D868 /* MVMCoreLoadRequestOperation.h */,
|
||||
AFBB96521FBA3A570008D868 /* MVMCoreLoadRequestOperation.m */,
|
||||
AF686FDD2A8D29CD008F666A /* MVMCoreLoadRequestOperation+Extension.swift */,
|
||||
AFBB96471FBA3A560008D868 /* MVMCoreLoadObject.h */,
|
||||
AFBB96481FBA3A560008D868 /* MVMCoreLoadObject.m */,
|
||||
AFBB96491FBA3A560008D868 /* MVMCoreRequestParameters.h */,
|
||||
@ -935,6 +938,7 @@
|
||||
AF69D4F1286E9D8000BC6862 /* ActionNoopHandler.swift in Sources */,
|
||||
016FF6F2259A4FCC00F5E4AA /* ClientParameterModel.swift in Sources */,
|
||||
D2DEDCBB23C65BC300C44CC4 /* Percent.swift in Sources */,
|
||||
AF686FDE2A8D29CD008F666A /* MVMCoreLoadRequestOperation+Extension.swift in Sources */,
|
||||
60CBD0542A02397A00056CB0 /* MVMCoreSessionTimeHandler.swift in Sources */,
|
||||
AF686FDC2A8A87EA008F666A /* KVOPublisher.swift in Sources */,
|
||||
AFBB966A1FBA3A570008D868 /* MVMCoreLoadRequestOperation.m in Sources */,
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
open class ActionShareHandler: MVMCoreActionHandlerProtocol {
|
||||
|
||||
required public init() {}
|
||||
@ -28,7 +29,7 @@ open class ActionShareHandler: MVMCoreActionHandlerProtocol {
|
||||
open func shareWith(activityItems: [Any], model: ActionShareModel, delegateObject: DelegateObject? = nil) async throws {
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
|
||||
controller.popoverPresentationController?.sourceView = MVMCoreNavigationHandler.shared()?.viewControllerToPresentOn?.view
|
||||
controller.popoverPresentationController?.sourceView = NavigationHandler.shared().viewControllerToPresentOn?.view
|
||||
controller.completionWithItemsHandler = {(activityType: UIActivity.ActivityType?, completed: Bool, returnedItems: [Any]?, error: Error?) in
|
||||
if completed {
|
||||
// Activity was completed, considered finished.
|
||||
|
||||
@ -0,0 +1,91 @@
|
||||
//
|
||||
// MVMCoreLoadRequestOperation+Extension.swift
|
||||
// MVMCore
|
||||
//
|
||||
// Created by Scott Pfeil on 8/16/23.
|
||||
// Copyright © 2023 myverizon. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum PopBackError: MVMError, CustomStringConvertible {
|
||||
case noPageType
|
||||
case noNavigationHandler
|
||||
case noViewController
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .noPageType:
|
||||
return "Cannot pop with a pageType."
|
||||
case .noNavigationHandler:
|
||||
return "Cannot pop with a navigation controller."
|
||||
case .noViewController:
|
||||
return "No View Controller of popBackPageType in the hierarchy"
|
||||
}
|
||||
}
|
||||
|
||||
public var errorCode: Int {
|
||||
switch self {
|
||||
case .noPageType:
|
||||
return 55
|
||||
case .noNavigationHandler:
|
||||
return 56
|
||||
case .noViewController:
|
||||
return 57
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
public extension MVMCoreLoadRequestOperation {
|
||||
@objc
|
||||
func popBackToPage(for loadObject: MVMCoreLoadObject) {
|
||||
Task(priority: .high) {
|
||||
do {
|
||||
guard let popBackPageType = loadObject.pageJSON?.optionalStringForKey("popBackPageType") else {
|
||||
throw PopBackError.noPageType
|
||||
}
|
||||
try await NavigationHandler.shared().popToViewController(with: popBackPageType, navigationController: loadObject.requestParameters?.navigationController, delegateObject: loadObject.delegateObject, animated: !(loadObject.requestParameters?.shouldNotAnimatePush ?? false))
|
||||
MVMCoreLoadRequestOperation.loadFinished(loadObject, loadedViewController: nil, errorObject: nil)
|
||||
} catch {
|
||||
MVMCoreLoadRequestOperation.loadFinished(loadObject, loadedViewController: nil, errorObject: MVMCoreErrorObject.createErrorObject(for: error, location: MVMCoreLoadHandler.sharedGlobal()?.errorLocation(forRequest: loadObject)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
func display(viewController: UIViewController, loadObject: MVMCoreLoadObject?, completionHandler: @escaping () -> Void) {
|
||||
Task(priority: .high) {
|
||||
guard let navigationOperation = await NavigationHandler.shared().getNavigationOperation(with: viewController, loadObject: loadObject) else {
|
||||
completionHandler()
|
||||
return
|
||||
}
|
||||
// stop any loading animation we may have started if we are about to display
|
||||
cancellable = NavigationHandler.shared().onNavigationWillBegin.sink(receiveValue: { operation in
|
||||
if navigationOperation == operation,
|
||||
!self.backgroundLoad,
|
||||
!(loadObject?.requestParameters?.noloadingOverlay ?? false) {
|
||||
MVMCoreLoadingOverlayHandler.sharedLoadingOverlay()?.stopLoading(false)
|
||||
}
|
||||
})
|
||||
await NavigationHandler.shared().navigate(with: navigationOperation)
|
||||
cancellable = nil
|
||||
completionHandler()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension NavigationHandler {
|
||||
func popToViewController(with pageType: String, navigationController: UINavigationController? = nil, delegateObject: DelegateObject? = nil, animated: Bool = true) async throws {
|
||||
guard let navigationController = navigationController ?? NavigationHandler.shared().navigationController else {
|
||||
throw PopBackError.noNavigationHandler
|
||||
}
|
||||
guard let viewController = await navigationController.viewControllers.first(where: { viewController in
|
||||
(viewController as? MVMCoreViewManagerProtocol)?.containsPage(withPageType: pageType) == true ||
|
||||
(viewController as? MVMCoreViewControllerProtocol)?.pageType == pageType
|
||||
}) else {
|
||||
throw PopBackError.noViewController
|
||||
}
|
||||
await NavigationHandler.shared().navigate(with: .popTo(viewController: viewController, navigationController: navigationController, animated: animated), delegateObject: delegateObject)
|
||||
}
|
||||
}
|
||||
@ -31,6 +31,8 @@
|
||||
/// Legacy flag for if this operation will have an alert to show when finished.
|
||||
@property (nonatomic, readonly) BOOL alertToShow;
|
||||
|
||||
@property (nullable, strong, nonatomic) id cancellable;
|
||||
|
||||
// Initializes the operation with the request parameters object, data for page, and mvm view controller to handle the loading with.
|
||||
- (nullable instancetype)initWithRequestParameters:(nullable MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegateObject:(nullable DelegateObject *)delegateObject backgroundLoad:(BOOL)backgroundLoad;
|
||||
|
||||
|
||||
@ -482,9 +482,7 @@
|
||||
} else if ([ValuePresentationStylePopToPage isEqualToString:[loadObject.pageJSON string:KeyPresentationStyle]] && !loadObject.operation.backgroundLoad && !loadObject.requestParameters.noViewControllerToLoad) {
|
||||
|
||||
// We need to pop back to a page instead of loading a new page.
|
||||
[[MVMCoreNavigationHandler sharedNavigationHandler] popToViewControllerWithPageType:[loadObject.pageJSON string:@"popBackPageType"] navigationController:loadObject.requestParameters.navigationController animated:!loadObject.requestParameters.shouldNotAnimatePush delegate:loadObject.delegateObject.presentationDelegate completionHandler:^{
|
||||
[MVMCoreLoadRequestOperation loadFinished:loadObject loadedViewController:nil errorObject:error];
|
||||
}];
|
||||
[loadObject.operation popBackToPageFor:loadObject];
|
||||
|
||||
// Notify listeners of module/pages loaded.
|
||||
[MVMCoreLoadRequestOperation notifyListenersOfNewResponse:pages modules:modules systemParameters:systemParameters loadObject:loadObject];
|
||||
@ -776,7 +774,7 @@
|
||||
}
|
||||
|
||||
// Once displyed, we are finished.
|
||||
[MVMCoreActionUtility displayViewController:viewController forLoadObject:loadObject presentationDelegate:loadObject.delegateObject.presentationDelegate completionHandler:^{
|
||||
[loadObject.operation displayWithViewController:viewController loadObject:loadObject completionHandler:^{
|
||||
[MVMCoreLoadRequestOperation loadFinished:loadObject loadedViewController:viewController errorObject:error];
|
||||
}];
|
||||
}
|
||||
|
||||
@ -68,12 +68,56 @@ public class NavigationHandler {
|
||||
/** Publishes when the navigation will begin
|
||||
- Parameter NavigationType: The type of navigation being performed.
|
||||
*/
|
||||
public let onNavigationWillBegin = PassthroughSubject<(NavigationType), Never>()
|
||||
public let onNavigationWillBegin = PassthroughSubject<(NavigationOperation), Never>()
|
||||
|
||||
/** Publishes when the navigation did finish
|
||||
- Parameter NavigationType: The type of navigation being performed.
|
||||
*/
|
||||
public let onNavigationDidFinish = PassthroughSubject<(NavigationType), Never>()
|
||||
public let onNavigationDidFinish = PassthroughSubject<(NavigationOperation), Never>()
|
||||
|
||||
// MARK: - Getters
|
||||
|
||||
/**
|
||||
The base view controller for presentation when none are passed in.
|
||||
Either the convenience ``viewControllerToPresentOn`` or the rootViewController of the window ``MVMCoreGetterUtility/getKeyWindow()``
|
||||
- Returns: The base view controller for presentation.
|
||||
*/
|
||||
@MainActor
|
||||
public func getViewControllerToPresentOn() -> UIViewController? {
|
||||
return viewControllerToPresentOn ?? MVMCoreGetterUtility.getKeyWindow()?.rootViewController
|
||||
}
|
||||
|
||||
/**
|
||||
Get the top most presented view controller to present on.
|
||||
Loops through presentedViewController on ``getViewControllerToPresentOn()``
|
||||
- Returns: The top most view controller to present on.
|
||||
*/
|
||||
@MainActor
|
||||
public func getTopMostPresentedViewController() -> UIViewController? {
|
||||
var viewController = getViewControllerToPresentOn()?.presentedViewController
|
||||
while let presentedController = viewController?.presentedViewController {
|
||||
viewController = presentedController
|
||||
}
|
||||
return viewController
|
||||
}
|
||||
|
||||
/**
|
||||
Get the viewControllers of the navigation controller.
|
||||
Takes into account the current animation state ``NavigationOperation/toNavigationControllerViewControllers``
|
||||
- Parameter navigationController: The navigation controller to fetch the viewcontrollers for.
|
||||
- Returns: The viewControllers.
|
||||
*/
|
||||
@MainActor
|
||||
public func getViewControllers(for navigationController: UINavigationController) -> [UIViewController] {
|
||||
// Check if we are currently animating.
|
||||
guard let operation = NavigationHandler.shared().navigationQueue.operations.first(where: { operation in
|
||||
operation.isExecuting && (operation as? NavigationOperation) != nil
|
||||
}) as? NavigationOperation,
|
||||
navigationController == operation.navigationType.getNavigationController(),
|
||||
let futureViewControllers = operation.toNavigationControllerViewControllers
|
||||
else { return navigationController.viewControllers }
|
||||
return futureViewControllers
|
||||
}
|
||||
|
||||
// MARK: - Navigation Functions
|
||||
|
||||
@ -102,30 +146,6 @@ public class NavigationHandler {
|
||||
await navigate(with: operation)
|
||||
}
|
||||
|
||||
/**
|
||||
The base view controller for presentation when none are passed in.
|
||||
Either the convenience ``viewControllerToPresentOn`` or the rootViewController of the window ``MVMCoreGetterUtility/getKeyWindow()``
|
||||
- Returns: The base view controller for presentation.
|
||||
*/
|
||||
@MainActor
|
||||
public func getViewControllerToPresentOn() -> UIViewController? {
|
||||
return viewControllerToPresentOn ?? MVMCoreGetterUtility.getKeyWindow()?.rootViewController
|
||||
}
|
||||
|
||||
/**
|
||||
Get the top most presented view controller to present on.
|
||||
Loops through presentedViewController on ``getViewControllerToPresentOn()``
|
||||
- Returns: The top most view controller to present on.
|
||||
*/
|
||||
@MainActor
|
||||
public func getTopMostPresentedViewController() -> UIViewController? {
|
||||
var viewController = getViewControllerToPresentOn()?.presentedViewController
|
||||
while let presentedController = viewController?.presentedViewController {
|
||||
viewController = presentedController
|
||||
}
|
||||
return viewController
|
||||
}
|
||||
|
||||
public func push(viewController: UIViewController, navigationController: UINavigationController? = nil, delegateObject: DelegateObject? = nil, animated: Bool = true) async {
|
||||
guard let navigationController = navigationController ?? self.navigationController else { return }
|
||||
await NavigationHandler.shared().navigate(with: .push(viewController: viewController, navigationController: navigationController, animated: animated), delegateObject: delegateObject)
|
||||
@ -182,6 +202,15 @@ extension UINavigationController {
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
public extension UINavigationController {
|
||||
/// See ``NavigationHandler/getViewControllers(for:)``
|
||||
@objc @MainActor
|
||||
func getViewControllers() -> [UIViewController] {
|
||||
NavigationHandler.shared().getViewControllers(for: self)
|
||||
}
|
||||
}
|
||||
|
||||
extension UIViewController {
|
||||
/**
|
||||
Get the top most presented view controller to present on.
|
||||
@ -196,111 +225,3 @@ extension UIViewController {
|
||||
return controllerToPresentOn
|
||||
}
|
||||
}
|
||||
|
||||
/// Legacy objc ``NavigationHandler`` wrapper.
|
||||
@objc public class MVMCoreNavigationHandler: NSObject {
|
||||
|
||||
@objc(sharedNavigationHandler)
|
||||
public static func shared() -> MVMCoreNavigationHandler? {
|
||||
return MVMCoreNavigationHandler()
|
||||
}
|
||||
|
||||
@objc
|
||||
public weak var viewControllerToPresentOn: UIViewController? {
|
||||
get {
|
||||
return NavigationHandler.shared().viewControllerToPresentOn
|
||||
}
|
||||
set {
|
||||
NavigationHandler.shared().viewControllerToPresentOn = newValue
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
public func popTopViewControllerAnimated(_ animated: Bool) {
|
||||
Task(priority: .high) { @MainActor in
|
||||
await NavigationHandler.shared().popTopViewController()
|
||||
}
|
||||
}
|
||||
|
||||
@objc(presentViewController:animated:)
|
||||
public func present(_ viewController: UIViewController, animated: Bool) {
|
||||
Task(priority: .high) { @MainActor in
|
||||
await NavigationHandler.shared().present(viewController: viewController, animated: animated)
|
||||
}
|
||||
}
|
||||
|
||||
@objc(dismissTopViewControllerAnimated:)
|
||||
public func dismissTopViewController(animated: Bool) {
|
||||
Task(priority: .high) { @MainActor in
|
||||
await NavigationHandler.shared().dismissTopViewController(animated: animated)
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
public func popToViewControllerWithPageType(_ pageType: String, navigationController: UINavigationController?, animated: Bool = true, delegate: MVMCorePresentationDelegateProtocol?, completionHandler:(() -> Void)?) {
|
||||
Task(priority: .high) { @MainActor in
|
||||
guard let navigationController = navigationController ?? NavigationHandler.shared().navigationController,
|
||||
let viewController = navigationController.viewControllers.first(where: { viewController in
|
||||
(viewController as? MVMCoreViewControllerProtocol)?.pageType == pageType
|
||||
}) else {
|
||||
completionHandler?()
|
||||
return
|
||||
}
|
||||
await NavigationHandler.shared().navigate(with: .popTo(viewController: viewController, navigationController: navigationController, animated: animated))
|
||||
completionHandler?()
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
public func navigateWithLoadObject(_ loadObject: MVMCoreLoadObject?, viewController: UIViewController, delegate: MVMCorePresentationDelegateProtocol?, completionHandler:(() -> Void)?) {
|
||||
Task(priority: .high) {
|
||||
let delegateObject = DelegateObject()
|
||||
delegateObject.presentationDelegate = delegate
|
||||
guard let requestParameters = loadObject?.requestParameters else {
|
||||
// Push
|
||||
await NavigationHandler.shared().push(viewController:viewController, delegateObject:delegateObject, animated:true)
|
||||
completionHandler?()
|
||||
return
|
||||
}
|
||||
let shouldAnimate = !requestParameters.shouldNotAnimatePush
|
||||
let navigationController = requestParameters.navigationController ?? NavigationHandler.shared().navigationController
|
||||
switch requestParameters.loadStyle {
|
||||
case .replaceCurrent:
|
||||
await NavigationHandler.shared().replace(viewController: viewController, navigationController: navigationController, delegateObject: delegateObject, animated: shouldAnimate)
|
||||
completionHandler?()
|
||||
case .onTopOfRoot:
|
||||
guard let root = await navigationController?.viewControllers.first else { return }
|
||||
let viewControllers = [root, viewController]
|
||||
await NavigationHandler.shared().set(viewControllers: viewControllers, navigationController: navigationController, delegateObject: delegateObject, animated: shouldAnimate)
|
||||
completionHandler?()
|
||||
case .becomeRoot:
|
||||
await NavigationHandler.shared().set(viewControllers: [viewController], navigationController: navigationController, delegateObject: delegateObject, animated: shouldAnimate)
|
||||
completionHandler?()
|
||||
case .present:
|
||||
await NavigationHandler.shared().present(viewController: viewController, animated: shouldAnimate)
|
||||
completionHandler?()
|
||||
default:
|
||||
await NavigationHandler.shared().push(viewController: viewController, navigationController: navigationController, delegateObject: delegateObject, animated: shouldAnimate)
|
||||
completionHandler?()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Get the viewControllers of the navigation controller.
|
||||
Takes into account the current animation state ``NavigationOperation/toNavigationControllerViewControllers``
|
||||
- Parameter navigationController: The navigation controller to fetch the viewcontrollers for.
|
||||
- Returns: The viewControllers.
|
||||
*/
|
||||
@objc(getViewControllersForNavigationController:)
|
||||
public func getViewControllers(for navigationController: UINavigationController) -> [UIViewController] {
|
||||
// Check if we are currently animating.
|
||||
guard let operation = NavigationHandler.shared().navigationQueue.operations.first(where: { operation in
|
||||
operation.isExecuting && (operation as? NavigationOperation) != nil
|
||||
}) as? NavigationOperation,
|
||||
navigationController == operation.navigationType.getNavigationController(),
|
||||
let futureViewControllers = operation.toNavigationControllerViewControllers
|
||||
else { return navigationController.viewControllers }
|
||||
return futureViewControllers
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ open class NavigationOperation: MVMCoreOperation, UINavigationControllerDelegate
|
||||
}
|
||||
|
||||
open override func main() {
|
||||
checkAndHandleForCancellation()
|
||||
guard !checkAndHandleForCancellation() else { return }
|
||||
Task(priority: .high) { @MainActor in
|
||||
try Task.checkCancellation()
|
||||
|
||||
@ -116,7 +116,8 @@ open class NavigationOperation: MVMCoreOperation, UINavigationControllerDelegate
|
||||
}
|
||||
navigationController.delegate = self
|
||||
toNavigationControllerViewControllers = viewControllers
|
||||
NavigationHandler.shared().onNavigationWillBegin.send(navigationType)
|
||||
NavigationHandler.shared().onNavigationWillBegin.send(self)
|
||||
guard !checkAndHandleForCancellation() else { return }
|
||||
navigationController.setViewControllers(viewControllers, animated: animated)
|
||||
}
|
||||
|
||||
@ -174,9 +175,10 @@ open class NavigationOperation: MVMCoreOperation, UINavigationControllerDelegate
|
||||
*/
|
||||
@MainActor
|
||||
open func present(viewController: UIViewController, onController: UIViewController, animated: Bool = true) {
|
||||
NavigationHandler.shared().onNavigationWillBegin.send(navigationType)
|
||||
NavigationHandler.shared().onNavigationWillBegin.send(self)
|
||||
guard !checkAndHandleForCancellation() else { return }
|
||||
onController.getViewControllerToPresentOn().present(viewController, animated: animated) { [self] in
|
||||
NavigationHandler.shared().onNavigationDidFinish.send(navigationType)
|
||||
NavigationHandler.shared().onNavigationDidFinish.send(self)
|
||||
markAsFinished()
|
||||
}
|
||||
}
|
||||
@ -187,9 +189,10 @@ open class NavigationOperation: MVMCoreOperation, UINavigationControllerDelegate
|
||||
*/
|
||||
@MainActor
|
||||
open func dismiss(viewController: UIViewController, animated: Bool = true) {
|
||||
NavigationHandler.shared().onNavigationWillBegin.send(navigationType)
|
||||
NavigationHandler.shared().onNavigationWillBegin.send(self)
|
||||
guard !checkAndHandleForCancellation() else { return }
|
||||
viewController.dismiss(animated: animated) { [self] in
|
||||
NavigationHandler.shared().onNavigationDidFinish.send(navigationType)
|
||||
NavigationHandler.shared().onNavigationDidFinish.send(self)
|
||||
markAsFinished()
|
||||
}
|
||||
}
|
||||
@ -198,7 +201,7 @@ open class NavigationOperation: MVMCoreOperation, UINavigationControllerDelegate
|
||||
|
||||
open func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
|
||||
delegate?.navigationController?(navigationController, didShow: viewController, animated: animated)
|
||||
NavigationHandler.shared().onNavigationDidFinish.send(navigationType)
|
||||
NavigationHandler.shared().onNavigationDidFinish.send(self)
|
||||
markAsFinished()
|
||||
}
|
||||
|
||||
|
||||
@ -17,3 +17,79 @@ public extension MVMCoreActionUtility {
|
||||
return instance
|
||||
}
|
||||
}
|
||||
|
||||
@objc public extension MVMCoreActionUtility {
|
||||
/// Can call to display a view controller based on the load object in the same way the architecture does it. Will check the presentation style of the page, action, and request. Will check if needs a view manager.
|
||||
@objc(displayViewController:forLoadObject:completionHandler:)
|
||||
static func display(_ viewController: UIViewController & MVMCoreViewControllerProtocol, for loadObject: MVMCoreLoadObject?, completionHandler: (() -> Void)?) {
|
||||
Task(priority: .high) {
|
||||
guard let navigationOperation = await NavigationHandler.shared().getNavigationOperation(with: viewController, loadObject: loadObject) else {
|
||||
completionHandler?()
|
||||
return
|
||||
}
|
||||
await NavigationHandler.shared().navigate(with: navigationOperation)
|
||||
completionHandler?()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension NavigationHandler {
|
||||
|
||||
/// Gets the navigation operation based on the requestParameters.
|
||||
@MainActor
|
||||
func getNavigationOperation(with requestParameters: MVMCoreRequestParameters, viewController: UIViewController, delegateObject: DelegateObject?) -> NavigationOperation? {
|
||||
|
||||
// Lets the server determine the presentation style if not explicitely set by developer.
|
||||
if requestParameters.loadStyle == .default,
|
||||
let presentationStyle = requestParameters.actionMap?.optionalStringForKey(KeyPresentationStyle) {
|
||||
// Sets it based on the action map.
|
||||
requestParameters.setMFLoadStyleBasedOnPresentationStyle(presentationStyle)
|
||||
}
|
||||
|
||||
let shouldAnimate = !requestParameters.shouldNotAnimatePush
|
||||
switch requestParameters.loadStyle {
|
||||
case .replaceCurrent:
|
||||
guard let navigationController = requestParameters.navigationController ?? NavigationHandler.shared().navigationController else { return nil }
|
||||
return NavigationOperation(with: .replace(viewController: viewController, navigationController: navigationController, animated: shouldAnimate), tryToReplace: true, delegate: delegateObject?.presentationDelegate)
|
||||
case .onTopOfRoot:
|
||||
guard let navigationController = requestParameters.navigationController ?? NavigationHandler.shared().navigationController,
|
||||
let root = navigationController.viewControllers.first else { return nil }
|
||||
let viewControllers = [root, viewController]
|
||||
return NavigationOperation(with: .set(viewControllers: viewControllers, navigationController: navigationController, animated: shouldAnimate), tryToReplace: true, delegate: delegateObject?.presentationDelegate)
|
||||
case .becomeRoot:
|
||||
guard let navigationController = requestParameters.navigationController ?? NavigationHandler.shared().navigationController else { return nil }
|
||||
return NavigationOperation(with: .set(viewControllers: [viewController], navigationController: navigationController, animated: shouldAnimate), tryToReplace: true, delegate: delegateObject?.presentationDelegate)
|
||||
case .present:
|
||||
guard let viewControllerToPresentOn = getViewControllerToPresentOn() else { return nil }
|
||||
return NavigationOperation(with: .present(viewController: viewController, onController: viewControllerToPresentOn, animated: shouldAnimate), tryToReplace: true, delegate: delegateObject?.presentationDelegate)
|
||||
default:
|
||||
guard let navigationController = requestParameters.navigationController ?? NavigationHandler.shared().navigationController else { return nil }
|
||||
return NavigationOperation(with: .push(viewController: viewController, navigationController: navigationController, animated: shouldAnimate), tryToReplace: true, delegate: delegateObject?.presentationDelegate)
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the navigation operation based on the loadObject.
|
||||
@MainActor
|
||||
func getNavigationOperation(with viewController: UIViewController, loadObject: MVMCoreLoadObject?) -> NavigationOperation? {
|
||||
// Lets the server determine the presentation style if not explicitely set by developer.
|
||||
if loadObject?.requestParameters?.loadStyle == .default,
|
||||
let presentationStyle = loadObject?.pageJSON?.optionalStringForKey(KeyPresentationStyle) {
|
||||
// Let's the response override if needed.
|
||||
loadObject?.requestParameters?.setMFLoadStyleBasedOnPresentationStyle(presentationStyle)
|
||||
}
|
||||
|
||||
// Check if we need to load on another control
|
||||
var viewController = viewController
|
||||
if let coreViewController = viewController as? UIViewController & MVMCoreViewControllerProtocol,
|
||||
let viewControllerToLoad = MVMCoreObject.sharedInstance()?.globalLoadDelegate?.getViewManager?(with: coreViewController, loadObject: loadObject) {
|
||||
viewController = viewControllerToLoad
|
||||
}
|
||||
|
||||
guard let requestParameters = loadObject?.requestParameters else {
|
||||
// Push
|
||||
guard let navigationController = NavigationHandler.shared().navigationController else { return nil }
|
||||
return NavigationOperation(with: .push(viewController: viewController, navigationController: navigationController))
|
||||
}
|
||||
return NavigationHandler.shared().getNavigationOperation(with: requestParameters, viewController: viewController, delegateObject: loadObject?.delegateObject)
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <MVMCore/MVMCoreViewControllerProtocol.h>
|
||||
#import <MVMCore/MVMCoreLoadObject.h>
|
||||
#import <MVMCore/MVMCorePresentationDelegateProtocol.h>
|
||||
|
||||
@interface MVMCoreActionUtility : NSObject
|
||||
|
||||
@ -20,9 +19,6 @@
|
||||
// Links away to safari or another app. Returns if successful.
|
||||
+ (BOOL)linkAway:(nullable NSString *)safariURLString appURLString:(nullable NSString *)appURLString;
|
||||
|
||||
// Can call to display a view controller based on the load object in the same way the architecture does it. Will check the presentation style of the page, action, and request. Will check if needs a view manager.
|
||||
+ (void)displayViewController:(nonnull UIViewController <MVMCoreViewControllerProtocol> *)viewController forLoadObject:(nullable MVMCoreLoadObject *)loadObject presentationDelegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock;
|
||||
|
||||
// returns if the class is not the same or a subclass of the other class. Can pass throw an exception as well
|
||||
+ (BOOL)classIsInstanceTypeOfClass:(nonnull Class)theClass otherClass:(nonnull Class)otherClass throwException:(BOOL)throwException;
|
||||
|
||||
|
||||
@ -104,32 +104,6 @@
|
||||
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:completion];
|
||||
}
|
||||
|
||||
+ (void)displayViewController:(nonnull UIViewController <MVMCoreViewControllerProtocol> *)viewController forLoadObject:(nullable MVMCoreLoadObject *)loadObject presentationDelegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock {
|
||||
|
||||
// Lets the server determine the presentation style if not explicitely set by developer.
|
||||
if (loadObject.requestParameters.loadStyle == MFLoadStyleDefault) {
|
||||
|
||||
// Sets it first based on the action map.
|
||||
NSString *presentationStyle = [loadObject.requestParameters.actionMap stringForKey:KeyPresentationStyle];
|
||||
[loadObject.requestParameters setMFLoadStyleBasedOnPresentationStyle:presentationStyle];
|
||||
|
||||
// Let's the response override if needed.
|
||||
presentationStyle = [loadObject.pageJSON stringForKey:KeyPresentationStyle];
|
||||
[loadObject.requestParameters setMFLoadStyleBasedOnPresentationStyle:presentationStyle];
|
||||
}
|
||||
|
||||
// Check if we need to load on another control
|
||||
__block UIViewController *viewControllerToLoad = nil;
|
||||
if ([[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(getViewManagerWithViewController:loadObject:)]) {
|
||||
[MVMCoreDispatchUtility performSyncBlockOnMainThread:^{
|
||||
viewControllerToLoad = [[MVMCoreObject sharedInstance].globalLoadDelegate getViewManagerWithViewController:viewController loadObject:loadObject];
|
||||
}];
|
||||
}
|
||||
|
||||
// Navigates
|
||||
[[MVMCoreNavigationHandler sharedNavigationHandler] navigateWithLoadObject:loadObject viewController:(viewControllerToLoad ?: viewController) delegate:delegate completionHandler:completionBlock];
|
||||
}
|
||||
|
||||
+ (BOOL)classIsInstanceTypeOfClass:(Class)theClass otherClass:(Class)otherClass throwException:(BOOL)throwException {
|
||||
if (theClass != otherClass && ![theClass isSubclassOfClass:otherClass]) {
|
||||
if (throwException) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user