Merge branch 'develop' into feature/accessibilityHandler

This commit is contained in:
Keerthy 2023-08-30 13:27:01 +05:30
commit bb1ac5895b
12 changed files with 211 additions and 144 deletions

View File

@ -51,30 +51,33 @@ public class AlertOperation: MVMCoreOperation {
// Observe for when it is removed. // Observe for when it is removed.
observeForCurrentAlertViewDismissal() observeForCurrentAlertViewDismissal()
// Adds the presentation to the animation queue. Task(priority: .high) {
let blockingOperation = MVMCoreOperation() guard let viewControllerToPresentOn = await NavigationHandler.shared().getViewControllerToPresentOn() else {
self.blockingOperation = blockingOperation markAsFinished()
Task { @MainActor in return
MVMCoreNavigationHandler.shared()?.present(alertController, animated: true, delegate: nil) { [weak self] in
guard let self = self else {
blockingOperation.markAsFinished()
return
}
Task {
// We finished but it was not displayed yet. It's possible that it was cancelled. Finish this task
if await !self.properties.getIsDisplayed() {
self.markAsFinished()
} else {
(CoreUIObject.sharedInstance()?.loggingDelegate as? MVMCoreUILoggingDelegateProtocol)?.logAlert(with: self.alertObject)
if self.isCancelled {
await self.dismissAlertView()
}
}
}
} }
// Block navigations until this alert is removed. // Presents the alert.
MVMCoreNavigationHandler.shared()?.addNavigationOperation(blockingOperation) let presentationOperation = await NavigationOperation(with: .present(viewController: alertController, onController: viewControllerToPresentOn), tryToReplace: false)
let blockingOperation = MVMCoreOperation()
blockingOperation.addDependency(presentationOperation)
self.blockingOperation = blockingOperation
// Block other navigation until this alert is removed.
NavigationHandler.shared().navigationQueue.addOperation(blockingOperation)
await NavigationHandler.shared().navigate(with: presentationOperation)
// We finished but it was not displayed yet. It's possible that it was cancelled. Finish this task
if await !self.properties.getIsDisplayed() {
self.markAsFinished()
} else {
(CoreUIObject.sharedInstance()?.loggingDelegate as? MVMCoreUILoggingDelegateProtocol)?.logAlert(with: self.alertObject)
if self.isCancelled {
await self.dismissAlertView()
}
}
} }
} }
@ -89,10 +92,13 @@ public class AlertOperation: MVMCoreOperation {
private func dismissAlertView() async { private func dismissAlertView() async {
guard await properties.getIsDisplayed() else { return } guard await properties.getIsDisplayed() else { return }
await withCheckedContinuation { continuation in await withCheckedContinuation { continuation in
Task { @MainActor in Task {
MVMCoreNavigationHandler.shared()?.dismiss(alertController, animated: true, delegate: nil) { let dismissOperation = await NavigationOperation(with: .dismiss(viewController: alertController))
continuation.resume() dismissOperation.queuePriority = .veryHigh
} let task = Task(priority: .high) { await NavigationHandler.shared().navigate(with: dismissOperation) }
blockingOperation?.markAsFinished()
_ = await task.result
continuation.resume()
} }
} }
} }

View File

@ -144,7 +144,9 @@ import MVMCore
picker.displayedPropertyKeys = ["phoneNumbers"] picker.displayedPropertyKeys = ["phoneNumbers"]
picker.predicateForEnablingContact = NSPredicate(format: "phoneNumbers.@count > 0") picker.predicateForEnablingContact = NSPredicate(format: "phoneNumbers.@count > 0")
picker.predicateForSelectionOfProperty = NSPredicate(format: "key == 'phoneNumbers'") picker.predicateForSelectionOfProperty = NSPredicate(format: "key == 'phoneNumbers'")
MVMCoreNavigationHandler.shared()?.present(picker, animated: true) Task(priority: .userInitiated) {
await NavigationHandler.shared().present(viewController: picker, animated: true)
}
} }
//-------------------------------------------------- //--------------------------------------------------

View File

@ -114,7 +114,7 @@ import MVMCore
open func performBlockOperation(with block: @escaping (MVMCoreBlockOperation) -> Void) { open func performBlockOperation(with block: @escaping (MVMCoreBlockOperation) -> Void) {
let operation = MVMCoreBlockOperation(block: block)! let operation = MVMCoreBlockOperation(block: block)!
MVMCoreNavigationHandler.shared()?.addNavigationOperation(operation) NavigationHandler.shared().navigationQueue.addOperation(operation)
} }
/// Collapses after a delay /// Collapses after a delay

View File

@ -7,9 +7,12 @@
// //
import UIKit import UIKit
import MVMCore
import Combine
@objcMembers open class NavigationController: UINavigationController, MVMCoreViewManagerViewControllerProtocol { @objcMembers open class NavigationController: UINavigationController, MVMCoreViewManagerViewControllerProtocol {
public weak var manager: (UIViewController & MVMCoreViewManagerProtocol)? public weak var manager: (UIViewController & MVMCoreViewManagerProtocol)?
private var cancellables: Set<AnyCancellable> = []
/// Getter for the main navigation controller /// Getter for the main navigation controller
public static func navigationController() -> Self? { public static func navigationController() -> Self? {
@ -20,9 +23,9 @@ import UIKit
public static func setupNavigationController() -> Self? { public static func setupNavigationController() -> Self? {
let navigationController = self.init() let navigationController = self.init()
MVMCoreUISession.sharedGlobal()?.navigationController = navigationController MVMCoreUISession.sharedGlobal()?.navigationController = navigationController
MVMCoreNavigationHandler.shared()?.viewControllerToPresentOn = navigationController NavigationHandler.shared().viewControllerToPresentOn = navigationController
MVMCoreNavigationHandler.shared()?.navigationController = navigationController NavigationHandler.shared().navigationController = navigationController
MVMCoreNavigationHandler.shared()?.addDelegate(navigationController) navigationController.subscribe()
navigationController.setNavigationBarUI(with: NavigationItemModel()) navigationController.setNavigationBarUI(with: NavigationItemModel())
return navigationController return navigationController
} }
@ -34,15 +37,45 @@ import UIKit
return navigationController return navigationController
} }
/// Convenience function to return the navigation model of the lowest controller traversing managers if applicable. /** Subscribes for events.
Updates the navigation item of the new view controller when one is pushed.
Based on ``NavigationItemModelProtocol`` of ``PageProtocol/pageModel``. Traverses the manager for the view controller if necessary.
*/
@MainActor
public func subscribe() {
NavigationHandler.shared().onNavigation.sink { [weak self] (event, operation) in
guard let self = self,
self == operation.navigationType.getNavigationController(),
let viewController = NavigationHandler.shared().getViewControllers(for: self).last,
let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController) else { return }
switch event {
case .willNavigate:
if let controller = viewController as? (UIViewController & MVMCoreViewManagerViewControllerProtocol) {
MVMCoreViewManagerViewControllerProtocolHelper.helpSetManager(self, viewController: controller)
}
if let model = getNavigationModel(from: newViewController) {
self.setNavigationItem(with: model, for: viewController)
self.setNavigationBarUI(with: model)
}
self.manager?.willDisplay?(newViewController)
case .didNavigate:
self.manager?.displayedViewController?(newViewController)
if let controller = viewController as? (UIViewController & MVMCoreViewManagerViewControllerProtocol) {
controller.viewControllerReady?(inManager: self)
}
@unknown default: break
}
}.store(in: &cancellables)
}
/// Convenience function to return the navigation model of the view controller.
public func getNavigationModel(from viewController: UIViewController) -> NavigationItemModelProtocol? { public func getNavigationModel(from viewController: UIViewController) -> NavigationItemModelProtocol? {
return (viewController as? PageProtocol)?.pageModel?.navigationBar return (viewController as? PageProtocol)?.pageModel?.navigationBar
} }
/// Verifies the controller is the currently displayed controller. /// Verifies the controller is the currently displayed controller.
public func isDisplayed(viewController: UIViewController) -> Bool { public func isDisplayed(viewController: UIViewController) -> Bool {
guard let topViewController = topViewController, guard viewController == getViewController() else {
viewController == MVMCoreUIUtility.getViewControllerTraversingManagers(topViewController) else {
return false return false
} }
return true return true
@ -84,8 +117,10 @@ extension NavigationController: MVMCoreViewManagerProtocol {
manager?.willDisplay?(viewController) manager?.willDisplay?(viewController)
} }
/// Updates the navigation item/bar of the current view controller based on the passed in model and view controller.
@MainActor
private func updateNavigationView(with model: NavigationItemModelProtocol, for viewController: UIViewController) { private func updateNavigationView(with model: NavigationItemModelProtocol, for viewController: UIViewController) {
guard let topViewController = topViewController else { return } guard let topViewController = NavigationHandler.shared().getViewControllers(for: self).last else { return }
setNavigationItem(with: model, for: topViewController, coordinatingWith: viewController as? PageBehaviorHandlerProtocol) setNavigationItem(with: model, for: topViewController, coordinatingWith: viewController as? PageBehaviorHandlerProtocol)
setNavigationBarUI(with: model) setNavigationBarUI(with: model)
@ -99,34 +134,6 @@ extension NavigationController: MVMCoreViewManagerProtocol {
} }
} }
extension NavigationController: MVMCorePresentationDelegateProtocol {
public func navigationController(_ navigationController: UINavigationController, prepareDisplayFor viewController: UIViewController) {
if let controller = viewController as? (UIViewController & MVMCoreViewManagerViewControllerProtocol) {
MVMCoreViewManagerViewControllerProtocolHelper.helpSetManager(self, viewController: controller)
}
guard self == navigationController,
let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController),
let model = getNavigationModel(from: newViewController) else { return }
setNavigationItem(with: model, for: viewController)
setNavigationBarUI(with: model)
}
public func navigationController(_ navigationController: UINavigationController, willDisplay viewController: UIViewController) {
guard self == navigationController,
let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController) else { return }
manager?.willDisplay?(newViewController)
}
public func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) {
guard self == navigationController,
let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController) else { return }
manager?.displayedViewController?(newViewController)
if let controller = viewController as? (UIViewController & MVMCoreViewManagerViewControllerProtocol) {
controller.viewControllerReady?(inManager: self)
}
}
}
extension UIColor { extension UIColor {
func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage { func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage {
return UIGraphicsImageRenderer(size: size).image { rendererContext in return UIGraphicsImageRenderer(size: size).image { rendererContext in

View File

@ -7,6 +7,7 @@
// //
import Foundation import Foundation
import MVMCore
public extension UINavigationController { public extension UINavigationController {
@ -38,7 +39,7 @@ public extension UINavigationController {
if model.hidesSystemBackButton, if model.hidesSystemBackButton,
model.alwaysShowBackButton != false { model.alwaysShowBackButton != false {
if let backButtonModel = model.backButton, if let backButtonModel = model.backButton,
MVMCoreNavigationHandler.shared()?.getViewControllers(for: self)?.count ?? 0 > 1 || model.alwaysShowBackButton ?? false { NavigationHandler.shared().getViewControllers(for: self).count > 1 || model.alwaysShowBackButton ?? false {
leftItems.append(backButtonModel.createNavigationItemButton(delegateObject: delegate, additionalData: nil)) leftItems.append(backButtonModel.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
} }
if let leftItemModels = model.additionalLeftButtons { if let leftItemModels = model.additionalLeftButtons {
@ -113,4 +114,11 @@ public extension UINavigationController {
setNavigationBarHidden(model.hidden, animated: true) setNavigationBarHidden(model.hidden, animated: true)
} }
@MainActor
func getViewController() -> UIViewController? {
guard let topViewController = getViewControllers().last,
let viewController = MVMCoreUIUtility.getViewControllerTraversingManagers(topViewController) else { return nil }
return viewController
}
} }

View File

@ -20,7 +20,8 @@ public protocol StatusBarUI {
// Navigation bar update functions // Navigation bar update functions
public extension MVMCoreUISplitViewController { public extension MVMCoreUISplitViewController {
/// Updates the state for various controls (navigation, tab, progress) for the controller. /// Updates the state for various controls (top navigation controller item, tab, progress) for the controller.
@MainActor
func updateState(with viewController: UIViewController) { func updateState(with viewController: UIViewController) {
guard let navigationController = navigationController, guard let navigationController = navigationController,
navigationController.isDisplayed(viewController: viewController) else { return } navigationController.isDisplayed(viewController: viewController) else { return }
@ -30,7 +31,9 @@ public extension MVMCoreUISplitViewController {
} }
// MARK: - Progress Bar // MARK: - Progress Bar
/// Updates the progress bar based on the page json for the view controller. /** Updates the progress bar based on the page json for the view controller.
Uses a string value between 0 and 100 from key progressPercent in the MVMCoreViewControllerProtocol.loadObject.pageJSON.
*/
func updateProgressBar(for viewController: UIViewController) { func updateProgressBar(for viewController: UIViewController) {
guard let viewController = viewController as? MVMCoreViewControllerProtocol else { return } guard let viewController = viewController as? MVMCoreViewControllerProtocol else { return }
var progress: Float = 0.0 var progress: Float = 0.0
@ -42,12 +45,16 @@ public extension MVMCoreUISplitViewController {
} }
// MARK: - Tab Bar // MARK: - Tab Bar
/// Updates the tab bar based on the page json for the view controller. /** Updates the tab bar based on the page json for the view controller.
For the index: checks the view controller's pageModel (``PageProtocol``) property ``TabPageModelProtocol/tabBarIndex``, else tabBarIndex in action map that led to this page, else the previous tab bar index of this page.
For hidden: checks the view controller's pageModel (``PageProtocol``) property ``TabPageModelProtocol/tabBarHidden``, else tabBarHidden in action map that led to this page, else it is visibile.
*/
@MainActor
func updateTabBar(for viewController: UIViewController) { func updateTabBar(for viewController: UIViewController) {
let mvmViewController = viewController as? MVMCoreViewControllerProtocol let mvmViewController = viewController as? MVMCoreViewControllerProtocol
tabBar?.delegateObject = mvmViewController?.delegateObject?() as? MVMCoreUIDelegateObject tabBar?.delegateObject = mvmViewController?.delegateObject?() as? MVMCoreUIDelegateObject
let navigationIndex = (MVMCoreNavigationHandler.shared()?.getViewControllers(for: navigationController)?.count ?? 1) - 1 let navigationIndex = (navigationController != nil ? NavigationHandler.shared().getViewControllers(for: navigationController!).count : 1) - 1
// Set the highlighted index. In terms of priority, Page > Action > Previous. // Set the highlighted index. In terms of priority, Page > Action > Previous.
if let index = ((viewController as? PageProtocol)?.pageModel as? TabPageModelProtocol)?.tabBarIndex { if let index = ((viewController as? PageProtocol)?.pageModel as? TabPageModelProtocol)?.tabBarIndex {
@ -80,10 +87,13 @@ public extension MVMCoreUISplitViewController {
} }
// MARK: - Navigation Bar // MARK: - Navigation Bar
/// Convenience function. Sets the navigation and split view properties for the view controller. Panel access is determined if view controller is a detail view protocol. /** Convenience function. Sets the navigation and split view properties for the view controller.
Panel access is determined if view controller is a ``MVMCoreUIDetailViewProtocol``
*/
@MainActor
func setNavigationBar(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) { func setNavigationBar(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) {
guard navigationController == self.navigationController, guard navigationController == self.navigationController,
viewController == getCurrentDetailViewController() else { self.navigationController?.isDisplayed(viewController: viewController) == true else {
/// Not the split view navigation controller, skip split functions. /// Not the split view navigation controller, skip split functions.
return return
} }
@ -97,9 +107,13 @@ public extension MVMCoreUISplitViewController {
setNavigationIconColor(navigationItemModel.tintColor.uiColor) setNavigationIconColor(navigationItemModel.tintColor.uiColor)
} }
/// Sets the left navigation items for the view controller based on model and splitview. /** Sets the left navigation items for the top view controller based on the model and viewController.
Panel access is determined if view controller is a ``MVMCoreUIDetailViewProtocol``
*/
@MainActor
func setLeftNavigationButtons(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol?, viewController: UIViewController) { func setLeftNavigationButtons(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol?, viewController: UIViewController) {
guard let topViewController = navigationController.topViewController else { return } let viewControllers = NavigationHandler.shared().getViewControllers(for: navigationController)
guard let topViewController = viewControllers.last else { return }
var leftItems: [UIBarButtonItem] = [] var leftItems: [UIBarButtonItem] = []
let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject
@ -110,7 +124,7 @@ public extension MVMCoreUISplitViewController {
if let forceBackButton = navigationItemModel?.alwaysShowBackButton { if let forceBackButton = navigationItemModel?.alwaysShowBackButton {
showBackButton = forceBackButton showBackButton = forceBackButton
} else { } else {
showBackButton = MVMCoreNavigationHandler.shared()?.getViewControllers(for: navigationController)?.count ?? 0 > 1 showBackButton = viewControllers.count > 1
} }
if showBackButton { if showBackButton {
if let backButtonModel = navigationItemModel?.backButton { if let backButtonModel = navigationItemModel?.backButton {
@ -144,9 +158,12 @@ public extension MVMCoreUISplitViewController {
topViewController.navigationItem.setLeftBarButtonItems(leftItems.count > 0 ? leftItems : nil, animated: !DisableAnimations.boolValue) topViewController.navigationItem.setLeftBarButtonItems(leftItems.count > 0 ? leftItems : nil, animated: !DisableAnimations.boolValue)
} }
/// Sets the right navigation items for the view controller based on model and splitview. /** Sets the right navigation items for the top view controller based on the model and viewController.
Panel access is determined if view controller is a ``MVMCoreUIDetailViewProtocol``
*/
@MainActor
func setRightNavigationButtons(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol?, viewController: UIViewController) { func setRightNavigationButtons(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol?, viewController: UIViewController) {
guard let topViewController = navigationController.topViewController else { return } guard let topViewController = NavigationHandler.shared().getViewControllers(for: navigationController).last else { return }
let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject
var rightItems: [UIBarButtonItem] = [] var rightItems: [UIBarButtonItem] = []
@ -173,6 +190,9 @@ public extension MVMCoreUISplitViewController {
topViewController.navigationItem.setRightBarButtonItems(rightItems.count > 0 ? rightItems : nil, animated: !DisableAnimations.boolValue) topViewController.navigationItem.setRightBarButtonItems(rightItems.count > 0 ? rightItems : nil, animated: !DisableAnimations.boolValue)
} }
/** If the current detail view controller has a navigation model.
``NavigationController/getNavigationModel(from:)`` from ``getCurrentDetailViewController()``
*/
@objc func navigationBarModelExists() -> Bool { @objc func navigationBarModelExists() -> Bool {
// Legacy Navigation // Legacy Navigation
guard let currentViewController = getCurrentDetailViewController(), guard let currentViewController = getCurrentDetailViewController(),
@ -180,8 +200,9 @@ public extension MVMCoreUISplitViewController {
return true return true
} }
/// Convenience function to update the navigation bar if the controller is the current lowest controller. /// Convenience function to update the navigation bar if the controller is the current detail controller.
@objc func updateNavigationBarFor(viewController: UIViewController) { @MainActor @objc
func updateNavigationBarFor(viewController: UIViewController) {
guard let navigationController = navigationController, guard let navigationController = navigationController,
navigationController.isDisplayed(viewController: viewController), navigationController.isDisplayed(viewController: viewController),
let model = navigationController.getNavigationModel(from: viewController) else { return } let model = navigationController.getNavigationModel(from: viewController) else { return }
@ -201,9 +222,13 @@ public extension MVMCoreUISplitViewController {
return .default return .default
} }
/// Updates the status bar background color and style. /** Updates the status bar background color and style for the passed view controller.
@objc func setStatusBarForCurrentViewController() { The background color is fetched from ``MVMCoreUIDetailViewProtocol/defaultStatusBarBackgroundColor()``, else the current navigation bar background, else the current status bar background color.
let viewController = getCurrentViewController() as? MVMCoreUIDetailViewProtocol The backgroundStytle is fetched from ``MVMCoreUIDetailViewProtocol/defaultStatusBarStyle()`` else ``getStatusBarStyle(for:)``
*/
@MainActor
func setStatusBar(for viewController: UIViewController?) {
let viewController = viewController as? MVMCoreUIDetailViewProtocol
let backgroundColor = viewController?.defaultStatusBarBackgroundColor?() ?? let backgroundColor = viewController?.defaultStatusBarBackgroundColor?() ??
navigationController?.navigationBar.standardAppearance.backgroundColor ?? navigationController?.navigationBar.standardAppearance.backgroundColor ??
statusBarView?.backgroundColor statusBarView?.backgroundColor
@ -213,6 +238,14 @@ public extension MVMCoreUISplitViewController {
setStatusBarBackgroundColor(backgroundColor, style: style) setStatusBarBackgroundColor(backgroundColor, style: style)
} }
/** Updates the status bar background color and style for the current view controller.
See ``setStatusBar(for:)``
*/
@MainActor
@objc func setStatusBarForCurrentViewController() {
setStatusBar(for: getCurrentViewController())
}
} }
extension MVMCoreUISplitViewController: MVMCoreViewManagerProtocol { extension MVMCoreUISplitViewController: MVMCoreViewManagerProtocol {
@ -235,6 +268,17 @@ extension MVMCoreUISplitViewController: MVMCoreViewManagerProtocol {
} }
@objc public extension MVMCoreUISplitViewController { @objc public extension MVMCoreUISplitViewController {
@objc func goBack() {
Task(priority: .userInitiated) { @MainActor in
if let viewController = getCurrentDetailViewController() as? MVMCoreUIDetailViewProtocol,
let backButtonPressed = viewController.backButtonPressed {
backButtonPressed()
} else {
await NavigationHandler.shared().popTopViewController()
}
}
}
/// Subscribes for notification events. /// Subscribes for notification events.
@objc func subscribeForNotifications() { @objc func subscribeForNotifications() {
guard cancellables == nil else { return } guard cancellables == nil else { return }

View File

@ -7,7 +7,6 @@
// //
#import "MVMCoreUISplitViewController.h" #import "MVMCoreUISplitViewController.h"
@import MVMCore.MVMCoreNavigationHandler;
@import MVMCore.MVMCoreDispatchUtility; @import MVMCore.MVMCoreDispatchUtility;
@import MVMCore.MVMCoreViewManagerProtocol; @import MVMCore.MVMCoreViewManagerProtocol;
@import MVMCore.MVMCoreActionUtility; @import MVMCore.MVMCoreActionUtility;
@ -192,14 +191,7 @@ CGFloat const PanelAnimationDuration = 0.2;
} }
- (IBAction)backButtonPressed:(id)sender { - (IBAction)backButtonPressed:(id)sender {
[MVMCoreDispatchUtility performBlockOnMainThread:^{ [self goBack];
UIViewController *detailViewController = [self getCurrentDetailViewController];
if ([detailViewController conformsToProtocol:@protocol(MVMCoreUIDetailViewProtocol)] && [detailViewController respondsToSelector:@selector(backButtonPressed)]) {
[((UIViewController <MVMCoreUIDetailViewProtocol> *)detailViewController) backButtonPressed];
} else {
[[MVMCoreNavigationHandler sharedNavigationHandler] popTopViewControllerAnimated:YES];
}
}];
} }
- (IBAction)rightPanelButtonPressed:(id)sender { - (IBAction)rightPanelButtonPressed:(id)sender {
@ -258,7 +250,7 @@ CGFloat const PanelAnimationDuration = 0.2;
- (void)setLeftNavigationItemForViewController:(UIViewController * _Nonnull)viewController accessible:(BOOL)accessible extended:(BOOL)extended { - (void)setLeftNavigationItemForViewController:(UIViewController * _Nonnull)viewController accessible:(BOOL)accessible extended:(BOOL)extended {
NSMutableArray *leftBarButtonItems = [NSMutableArray array]; NSMutableArray *leftBarButtonItems = [NSMutableArray array];
if (self.navigationController && [MVMCoreNavigationHandler.sharedNavigationHandler getViewControllersForNavigationController:self.navigationController].count > 1) { if (self.navigationController && [self.navigationController getViewControllers].count > 1) {
[leftBarButtonItems addObject:self.backButton]; [leftBarButtonItems addObject:self.backButton];
} }
if ((accessible && !extended) && self.leftPanelButton) { if ((accessible && !extended) && self.leftPanelButton) {
@ -1074,7 +1066,7 @@ CGFloat const PanelAnimationDuration = 0.2;
// Returns the desired view or falls back. Hot fix until we can get away from using these functions... // Returns the desired view or falls back. Hot fix until we can get away from using these functions...
+ (CGRect)getBounds:(UIView *)desiredView { + (CGRect)getBounds:(UIView *)desiredView {
UIView *view = desiredView ?: [MVMCoreNavigationHandler sharedNavigationHandler].navigationController.view ?: [MVMCoreGetterUtility getKeyWindow].rootViewController.view; UIView *view = desiredView ?: [self mainSplitViewController].navigationController.view ?: [MVMCoreGetterUtility getKeyWindow].rootViewController.view;
return view ? view.bounds : [UIScreen mainScreen].bounds; return view ? view.bounds : [UIScreen mainScreen].bounds;
} }
@ -1099,17 +1091,7 @@ CGFloat const PanelAnimationDuration = 0.2;
} }
- (UIViewController *)getCurrentVisibleController { - (UIViewController *)getCurrentVisibleController {
UIViewController *baseViewController = [MVMCoreNavigationHandler sharedNavigationHandler].viewControllerToPresentOn ?: [MVMCoreGetterUtility getKeyWindow].rootViewController; return [MVMCoreUIUtility getCurrentVisibleController];
UIViewController *viewController = nil;
while (baseViewController.presentedViewController && !baseViewController.presentedViewController.isBeingDismissed) {
viewController = baseViewController.presentedViewController;
baseViewController = viewController;
}
// if it is not presented viewcontroller, existing BAU logic will be working
if (!viewController) {
viewController = [MVMCoreUIUtility getViewControllerTraversingManagers:self.navigationController.topViewController];
}
return viewController;
} }
- (UIViewController *)getCurrentDetailViewController { - (UIViewController *)getCurrentDetailViewController {

View File

@ -205,7 +205,7 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
} }
} }
public func navigationController(_ navigationController: UINavigationController, interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { public func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
// Only percent interact if we've already loaded the view controller // Only percent interact if we've already loaded the view controller
guard let customInteractor = customInteractor, guard let customInteractor = customInteractor,
let index = index, let index = index,
@ -229,7 +229,7 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
hideNavigationBarLine(true) hideNavigationBarLine(true)
} }
public func navigationController(_ navigationController: UINavigationController, willDisplay viewController: UIViewController) { public func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
guard navigationController == subNavigationController else { return } guard navigationController == subNavigationController else { return }
if let viewController = viewController as? UIViewController & MVMCoreViewManagerViewControllerProtocol & MVMCoreViewControllerProtocol { if let viewController = viewController as? UIViewController & MVMCoreViewManagerViewControllerProtocol & MVMCoreViewControllerProtocol {
@ -247,7 +247,7 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
commitTo(controller: viewController) commitTo(controller: viewController)
} }
public func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) { public func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
guard navigationController == subNavigationController else { return } guard navigationController == subNavigationController else { return }
// Need to track swipe action. // Need to track swipe action.
if needToTrackTabSelect { if needToTrackTabSelect {
@ -272,7 +272,9 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
if let controller = viewControllers[indexPath.row] { if let controller = viewControllers[indexPath.row] {
// Load controller from the cache // Load controller from the cache
needToTrackTabSelect = true needToTrackTabSelect = true
MVMCoreNavigationHandler.shared()?.replaceTopViewController(with: controller, navigationController: subNavigationController, animated: true, delegate: self, replaceInStack: false, completionHandler: nil) Task(priority: .userInitiated) {
await NavigationHandler.shared().replace(viewController: controller, navigationController: subNavigationController, tryToReplace: false, animated: true)
}
} else if let tabsModel = tabs.tabsModel, } else if let tabsModel = tabs.tabsModel,
let action = tabsModel.tabs[indexPath.row].action { let action = tabsModel.tabs[indexPath.row].action {
// Perform the tab action // Perform the tab action

View File

@ -268,7 +268,7 @@ public class NotificationOperation: MVMCoreOperation {
} }
})! })!
transitionOperation.completionBlock = completionBlock transitionOperation.completionBlock = completionBlock
MVMCoreNavigationHandler.shared()?.addNavigationOperation(transitionOperation) NavigationHandler.shared().navigationQueue.addOperation(transitionOperation)
return transitionOperation return transitionOperation
} }
@ -314,6 +314,8 @@ open class NotificationHandler {
private var transitionDelegate: NotificationTransitionDelegateProtocol private var transitionDelegate: NotificationTransitionDelegateProtocol
private var cancellable: Cancellable?
// MARK: - Publishers // MARK: - Publishers
/// Publishes when a notification will show. /// Publishes when a notification will show.
@ -354,7 +356,27 @@ open class NotificationHandler {
/// Registers to know when pages change. /// Registers to know when pages change.
private func registerForPageChanges() { private func registerForPageChanges() {
MVMCoreNavigationHandler.shared()?.addDelegate(self) cancellable = NavigationHandler.shared().onNavigation
.filter({ $0.0 == .didNavigate })
.sink { [weak self] (event, operation) in
guard let self = self else { return }
Task {
// Update displayable for each top alert operation when page type changes, in top queue priority order.
guard self.queue.operations.count > 0,
let navigationController = await operation.navigationType.getNavigationController(),
await navigationController == MVMCoreUISplitViewController.main()?.navigationController,
let viewController = await navigationController.getViewController() else { return }
let pageType = (viewController as? MVMCoreViewControllerProtocol)?.pageType
self.queue.operations.compactMap {
$0 as? NotificationOperation
}.sorted {
$0.notificationModel.priority.rawValue > $1.notificationModel.priority.rawValue
}.forEach {
$0.updateDisplayable(by: pageType)
}
self.reevaluteQueue()
}
}
} }
/// Checks for new top alert json /// Checks for new top alert json
@ -534,26 +556,6 @@ open class NotificationHandler {
} }
} }
extension NotificationHandler: MVMCorePresentationDelegateProtocol {
// Update displayable for each top alert operation when page type changes, in top queue priority order.
public func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) {
guard queue.operations.count > 0 else { return }
let viewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController)
guard viewController == MVMCoreUISplitViewController.main()?.getCurrentViewController() else { return }
let pageType = (viewController as? MVMCoreViewControllerProtocol)?.pageType
Task {
queue.operations.compactMap {
$0 as? NotificationOperation
}.sorted {
$0.notificationModel.priority.rawValue > $1.notificationModel.priority.rawValue
}.forEach {
$0.updateDisplayable(by: pageType)
}
reevaluteQueue()
}
}
}
extension NotificationOperation { extension NotificationOperation {
/// Updates the operation and notification with the new model. /// Updates the operation and notification with the new model.
public func update(with model: NotificationModel, delegateObject: MVMCoreUIDelegateObject?) { public func update(with model: NotificationModel, delegateObject: MVMCoreUIDelegateObject?) {

View File

@ -57,6 +57,8 @@ import SafariServices
@MainActor @MainActor
open func openURL(inSafariWebView url: URL) { open func openURL(inSafariWebView url: URL) {
let safariViewController = SFSafariViewController(url: url) let safariViewController = SFSafariViewController(url: url)
MVMCoreNavigationHandler.shared()?.present(safariViewController, animated: true) Task(priority: .high) {
await NavigationHandler.shared().present(viewController: safariViewController)
}
} }
} }

View File

@ -7,7 +7,7 @@
// //
import UIKit import UIKit
import MVMCore
public extension MVMCoreUIUtility { public extension MVMCoreUIUtility {
@ -66,3 +66,25 @@ public extension MVMCoreUIUtility {
return nil return nil
} }
} }
@objc
public extension MVMCoreUIUtility {
@objc @MainActor
static func getVisibleViewController() -> UIViewController? {
var viewController = NavigationHandler.shared().getViewControllerToPresentOn()
while let presentedController = viewController?.presentedViewController,
!presentedController.isBeingDismissed {
viewController = presentedController
}
if let navigationController = viewController as? UINavigationController {
viewController = navigationController.topViewController
}
if let viewController = viewController {
return getViewControllerTraversingManagers(viewController)
} else if let viewController = MVMCoreUISession.sharedGlobal()?.navigationController?.topViewController {
return getViewControllerTraversingManagers(viewController)
} else {
return nil
}
}
}

View File

@ -11,7 +11,6 @@
#import "MVMCoreUISession.h" #import "MVMCoreUISession.h"
#import "MVMCoreUISplitViewController.h" #import "MVMCoreUISplitViewController.h"
#import <MVMCoreUI/MVMCoreUI-Swift.h> #import <MVMCoreUI/MVMCoreUI-Swift.h>
@import MVMCore.MVMCoreNavigationHandler;
@import MVMCore.MVMCoreGetterUtility; @import MVMCore.MVMCoreGetterUtility;
@implementation MVMCoreUIUtility @implementation MVMCoreUIUtility
@ -52,19 +51,10 @@
} }
+ (UIViewController *)getCurrentVisibleController { + (UIViewController *)getCurrentVisibleController {
UIViewController *baseViewController = [MVMCoreNavigationHandler sharedNavigationHandler].viewControllerToPresentOn ?: [MVMCoreGetterUtility getKeyWindow].rootViewController; __block UIViewController *viewController = nil;
UIViewController *viewController = nil; [MVMCoreDispatchUtility performSyncBlockOnMainThread:^{
while (baseViewController.presentedViewController && !baseViewController.presentedViewController.isBeingDismissed) { viewController = [self getVisibleViewController];
viewController = baseViewController.presentedViewController; }];
baseViewController = viewController;
}
if ([viewController isKindOfClass:[UINavigationController class]]) {
viewController = ((UINavigationController *)viewController).topViewController;
}
// if it is not presented viewcontroller, existing BAU logic will be working
if (!viewController) {
viewController = [self getViewControllerTraversingManagers:[MVMCoreUISession sharedGlobal].navigationController.topViewController];
}
return viewController; return viewController;
} }