// // NavigationController.swift // MVMCoreUI // // Created by Scott Pfeil on 10/24/19. // Copyright © 2019 Verizon Wireless. All rights reserved. // import UIKit @objcMembers open class NavigationController: UINavigationController, MVMCoreViewManagerViewControllerProtocol { public var separatorView: Line? public var manager: (UIViewController & MVMCoreViewManagerProtocol)? /// Getter for the main navigation controller public static func navigationController() -> Self? { return MVMCoreActionUtility.initializerClassCheck(MVMCoreUISession.sharedGlobal()?.navigationController, classToVerify: self) as? Self } /// Provides MVM styling to the navigation bar. Returns a reference to the line. public static func style(_ navigationBar: UINavigationBar) -> Line { navigationBar.backgroundColor = .white navigationBar.shadowImage = UIImage() navigationBar.isOpaque = true navigationBar.tintColor = .black navigationBar.titleTextAttributes = [NSAttributedString.Key.font: MFStyler.fontBoldBodySmall(false)]; return Line(pinTo: navigationBar, edge: .bottom, useMargin: false) } /// Sets up the application with a navigation controller public static func setupNavigationController() -> Self? { let navigationController = self.init() navigationController.separatorView = style(navigationController.navigationBar) MVMCoreUISession.sharedGlobal()?.navigationController = navigationController MVMCoreNavigationHandler.shared()?.viewControllerToPresentOn = navigationController MVMCoreNavigationHandler.shared()?.navigationController = navigationController MVMCoreNavigationHandler.shared()?.addDelegate(navigationController) return navigationController } /// Sets up the application with a navigation controller as the main container. public static func setupNavigationControllerAsMainController() -> Self? { guard let navigationController = setupNavigationController() else { return nil } MVMCoreUISession.sharedGlobal()?.setup(asStandardLoadViewDelegate: navigationController) return navigationController } /// Convenience function for setting the navigation item. public static func setNavigationItem(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol, viewController: UIViewController) { viewController.navigationItem.title = navigationItemModel.title viewController.navigationItem.accessibilityLabel = navigationItemModel.title viewController.navigationItem.hidesBackButton = navigationItemModel.hidesSystemBackButton viewController.navigationItem.leftItemsSupplementBackButton = !navigationItemModel.hidesSystemBackButton setNavigationButtons(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController) setNavigationTitleView(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController) } /// Convenience function for setting the navigation buttons. public static func setNavigationButtons(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol, viewController: UIViewController) { let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject var leftItems: [UIBarButtonItem] = [] if navigationItemModel.alwaysShowBackButton != false { if let backButtonModel = navigationItemModel.backButton, MVMCoreNavigationHandler.shared()?.getViewControllers(for: navigationController)?.count ?? 0 > 1 || navigationItemModel.alwaysShowBackButton ?? false { leftItems.append(backButtonModel.createNavigationItemButton(delegateObject: delegate, additionalData: nil)) } if let leftItemModels = navigationItemModel.additionalLeftButtons { for item in leftItemModels { leftItems.append(item.createNavigationItemButton(delegateObject: delegate, additionalData: nil)) } } } viewController.navigationItem.leftBarButtonItems = leftItems.count > 0 ? leftItems : nil var rightItems: [UIBarButtonItem] = [] if let rightItemModels = navigationItemModel.additionalRightButtons { for item in rightItemModels { rightItems.append(item.createNavigationItemButton(delegateObject: delegate, additionalData: nil)) } } viewController.navigationItem.rightBarButtonItems = rightItems.count > 0 ? rightItems : nil } /// Convenience function for setting the navigation bar ui, except for the buttons. public static func setNavigationBarUI(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol, viewController: UIViewController) { navigationController.setNavigationBarHidden(navigationItemModel.hidden, animated: true) navigationController.navigationBar.barTintColor = navigationItemModel.backgroundColor?.uiColor ?? .white let tint = navigationItemModel.tintColor.uiColor navigationController.navigationBar.tintColor = tint // Have the navigation title match the tint color navigationController.navigationBar.titleTextAttributes?.updateValue(tint, forKey: .foregroundColor) // Update line. if let navigationController = navigationController as? NavigationController { navigationController.separatorView?.isHidden = navigationItemModel.line?.type ?? .standard == .none } } /// Convenience function for setting the navigation titleView. public static func setNavigationTitleView(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol?, viewController: UIViewController) { let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject if let titleViewModel = navigationItemModel?.titleView, let molecule = ModelRegistry.createMolecule(titleViewModel, delegateObject: delegate, additionalData: nil) { viewController.navigationItem.titleView = molecule } } /// Convenience function to return the navigation model of the lowest controller traversing managers public static func getNavigationModel(from viewController: UIViewController) -> NavigationItemModelProtocol? { guard let controller = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController), let model = (controller as? PageProtocol)?.pageModel?.navigationBar else { return nil } return model } } extension NavigationController: MVMCoreViewManagerProtocol { // TODO: change this to optional public func getCurrentViewController() -> UIViewController? { return topViewController } public func containsPage(withPageType pageType: String?) -> Bool { for case let controller as MVMCoreViewControllerProtocol in viewControllers { if controller.pageType == pageType { return true } } return false } public func newDataReceived(in viewController: UIViewController) { if viewController == topViewController, let model = Self.getNavigationModel(from: viewController) { Self.setNavigationItem(navigationController: self, navigationItemModel: model, viewController: viewController) Self.setNavigationBarUI(navigationController: self, navigationItemModel: model, viewController: viewController) } manager?.newDataReceived?(in: viewController) } public func willDisplay(_ viewController: UIViewController) { guard let topViewController = topViewController else { return } if let model = Self.getNavigationModel(from: viewController) { Self.setNavigationItem(navigationController: self, navigationItemModel: model, viewController: topViewController) } manager?.willDisplay?(viewController) } public func displayedViewController(_ viewController: UIViewController) { guard let topViewController = topViewController else { return } if let model = Self.getNavigationModel(from: viewController) { Self.setNavigationBarUI(navigationController: self, navigationItemModel: model, viewController: topViewController) } manager?.displayedViewController?(viewController) } } extension NavigationController: MVMCorePresentationDelegateProtocol { public func navigationController(_ navigationController: UINavigationController, willDisplay viewController: UIViewController) { guard self == navigationController else { return } if let controller = viewController as? (UIViewController & MVMCoreViewManagerViewControllerProtocol) { MVMCoreViewManagerViewControllerProtocolHelper.helpSetManager(self, viewController: controller) controller.viewControllerReady?(inManager: self) } if let model = Self.getNavigationModel(from: viewController) { Self.setNavigationItem(navigationController: self, navigationItemModel: model, viewController: viewController) } manager?.willDisplay?(viewController) } public func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) { guard self == navigationController else { return } if let model = Self.getNavigationModel(from: viewController) { Self.setNavigationBarUI(navigationController: self, navigationItemModel: model, viewController: viewController) } manager?.displayedViewController?(viewController) } }