import UIKit import Theme public protocol Presenting { func present(_ target: UIViewController..., from parent: UIViewController) func dismiss(from parent: UIViewController) } public extension Presenting { func dismiss(from parent: UIViewController) { parent.dismiss(animated: true) } } public struct PushPresenter: Presenting { public init() {} public func present(_ target: UIViewController..., from parent: UIViewController) { parent.navigationController?.pushViewController(target.first!, animated: true) } } public struct ModalPresenter: Presenting { public init() {} public func present(_ target: UIViewController..., from parent: UIViewController) { let statusBarVC = StatusBarViewController(target.first!) statusBarVC.modalPresentationStyle = .fullScreen parent.present(statusBarVC, animated: true) } } public struct ReplacePresenter: Presenting { public enum Mode { case replaceAll case replaceLast case replaceBackwards(AnyObject.Type) } var mode: Mode public init(mode: Mode = .replaceAll) { self.mode = mode } public func present(_ target: UIViewController..., from parent: UIViewController) { guard let navigationController = parent.navigationController else { return } switch mode { case .replaceAll: navigationController.setViewControllers(target, animated: true) case .replaceBackwards(let OlderInStack): if let oldScreen = navigationController.viewControllers.filter({ $0.isKind(of: OlderInStack.self) }).first, let index = navigationController.viewControllers.firstIndex(of: oldScreen) { let viewControllersBefore = navigationController.viewControllers.dropLast( navigationController.viewControllers.count - index ) if let coordinator = navigationController.transitionCoordinator { coordinator.animate(alongsideTransition: nil) { _ in navigationController.setViewControllers(viewControllersBefore + target , animated: true) } } else { navigationController.setViewControllers(viewControllersBefore + target , animated: true) } } else { navigationController.pushViewController(target.first!, animated: true) } case .replaceLast: let viewControllersBefore = navigationController.viewControllers.dropLast() func replace() { navigationController.setViewControllers(viewControllersBefore + target , animated: true) } if let coordinator = navigationController.transitionCoordinator { coordinator.animate(alongsideTransition: nil) { _ in replace() } } else { replace() } } } } public struct PopReplacePresenter: Presenting { public init() {} public func present(_ target: UIViewController..., from parent: UIViewController) { if let lastViewController = parent.navigationController?.viewControllers.last { parent.navigationController?.setViewControllers([target.first!, lastViewController], animated: false) parent.navigationController?.setViewControllers([target.first!], animated: true) } } }