mvm_core_ui/MVMCoreUI/Containers/NavigationController.swift
Pfeil, Scott Robert db106c2fb5 weak managers
2021-07-23 15:33:57 -04:00

188 lines
10 KiB
Swift

//
// 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 weak 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 if applicable.
public func getNavigationModel(from viewController: UIViewController) -> NavigationItemModelProtocol? {
guard let topViewController = topViewController,
viewController == MVMCoreUIUtility.getViewControllerTraversingManagers(topViewController),
let model = (viewController as? PageProtocol)?.pageModel?.navigationBar else { return nil }
return model
}
}
extension NavigationController: MVMCoreViewManagerProtocol {
public func getCurrentViewController() -> UIViewController? {
guard let topViewController = topViewController else { return nil }
return MVMCoreUIUtility.getViewControllerTraversingManagers(topViewController)
}
public func containsPage(withPageType pageType: String?) -> Bool {
for controller in viewControllers {
if let manager = controller as? MVMCoreViewManagerProtocol,
manager.containsPage(withPageType: pageType) {
return true
} else if let controller = controller as? MVMCoreViewControllerProtocol,
controller.pageType == pageType {
return true
}
}
return false
}
public func newDataReceived(in viewController: UIViewController) {
if let topViewController = topViewController,
let model = getNavigationModel(from: viewController) {
Self.setNavigationItem(navigationController: self, navigationItemModel: model, viewController: topViewController)
Self.setNavigationBarUI(navigationController: self, navigationItemModel: model, viewController: topViewController)
}
manager?.newDataReceived?(in: viewController)
}
public func willDisplay(_ viewController: UIViewController) {
if let topViewController = topViewController,
let model = getNavigationModel(from: viewController) {
Self.setNavigationItem(navigationController: self, navigationItemModel: model, viewController: topViewController)
}
manager?.willDisplay?(viewController)
}
public func displayedViewController(_ viewController: UIViewController) {
if let topViewController = topViewController,
let model = 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)
}
guard let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController) else { return }
if let model = getNavigationModel(from: newViewController) {
Self.setNavigationItem(navigationController: self, navigationItemModel: model, viewController: viewController)
}
manager?.willDisplay?(newViewController)
}
public func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) {
guard self == navigationController,
let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController) else { return }
if let model = getNavigationModel(from: newViewController) {
Self.setNavigationBarUI(navigationController: self, navigationItemModel: model, viewController: viewController)
}
manager?.displayedViewController?(newViewController)
if let controller = viewController as? (UIViewController & MVMCoreViewManagerViewControllerProtocol) {
controller.viewControllerReady?(inManager: self)
}
}
}