// // BrowserNavigationController.swift // Gemini-iOS // // Created by Shadowfacts on 12/16/20. // import UIKit import BrowserCore import Combine class BrowserNavigationController: UINavigationController { let navigator: NavigationManager var poppedViewControllers = [UIViewController]() var skipResetPoppedOnNextPush = false private var interactivePushTransition: InteractivePushTransition! private var cancellables = [AnyCancellable]() init(navigator: NavigationManager) { self.navigator = navigator super.init(nibName: nil, bundle: nil) navigator.$currentURL .sink { [weak self] (newURL) in self?.pushViewController(BrowserWebViewController(navigator: navigator, url: newURL), animated: true) } .store(in: &cancellables) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() interactivePushTransition = InteractivePushTransition(navigationController: self) } override func popViewController(animated: Bool) -> UIViewController? { if let popped = super.popViewController(animated: animated) { poppedViewControllers.insert(popped, at: 0) return popped } else { return nil } } override func popToRootViewController(animated: Bool) -> [UIViewController]? { if let popped = super.popToRootViewController(animated: animated) { poppedViewControllers = popped return popped } else { return nil } } override func popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]? { if let popped = super.popToViewController(viewController, animated: animated) { poppedViewControllers.insert(contentsOf: popped, at: 0) return popped } else { return nil } } override func pushViewController(_ viewController: UIViewController, animated: Bool) { if skipResetPoppedOnNextPush { skipResetPoppedOnNextPush = false } else { self.poppedViewControllers = [] } super.pushViewController(viewController, animated: animated) } func onWillShow() { self.transitionCoordinator?.notifyWhenInteractionChanges({ (context) in if context.isCancelled { if self.interactivePushTransition.interactive { // when an interactive push gesture is cancelled, make sure to adding the VC that was being pushed back onto the popped stack so it doesn't disappear self.poppedViewControllers.insert(self.interactivePushTransition.pushingViewController!, at: 0) } else { // when an interactive pop gesture is cancelled (i.e. the user lifts their finger before it triggers), // the popViewController(animated:) method has already been called so the VC has already been added to the popped stack // so we make sure to remove it, otherwise there could be duplicate VCs on the navigation stasck self.poppedViewControllers.remove(at: 0) } } }) } }