From f204557bc4117229e624a03b594527c28fa6401b Mon Sep 17 00:00:00 2001 From: Kirill Budevich Date: Thu, 17 Aug 2017 23:04:13 +0300 Subject: [PATCH 1/4] Added simple 2 methods, which help close the current module or stack of modules. --- LightRoute/LightRoute.swift | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/LightRoute/LightRoute.swift b/LightRoute/LightRoute.swift index 307779f..d552357 100644 --- a/LightRoute/LightRoute.swift +++ b/LightRoute/LightRoute.swift @@ -92,7 +92,6 @@ public final class StoryboardFactory: StoryboardFactoryProtocol { self.storyboard = UIStoryboard(name: name, bundle: bundle) self.restorationId = restorationId } - } @@ -131,6 +130,9 @@ public protocol TransitionHandler: class { /// func forSegue(identifier: String, to type: T.Type, completion: @escaping TransitionSetupBlock) + func closeModule(animated: Bool) + + func closeModulesInStack(animated: Bool) } @@ -440,7 +442,22 @@ public extension TransitionHandler where Self: UIViewController { } } - + func closeModule(animated: Bool) { + if let navigationVC = self.navigationController { + navigationVC.popViewController(animated: animated) + } else { + self.dismiss(animated: animated, completion: nil) + } + } + + func closeModulesInStack(animated: Bool) { + if let navigationVC = self.navigationController { + navigationVC.popToRootViewController(animated: animated) + } else { + print("[LightRoute]: The navigationController's stack doesn't exist, dissmiss only the top view controller") + self.dismiss(animated: animated, completion: nil) + } + } } /// From 3fbffbcfc5d673702ba9ec2206699651bbd7529d Mon Sep 17 00:00:00 2001 From: Kirill Budevich Date: Thu, 17 Aug 2017 23:09:56 +0300 Subject: [PATCH 2/4] Added documentation of funcs --- LightRoute/LightRoute.swift | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/LightRoute/LightRoute.swift b/LightRoute/LightRoute.swift index d552357..9a2c1d3 100644 --- a/LightRoute/LightRoute.swift +++ b/LightRoute/LightRoute.swift @@ -129,9 +129,21 @@ public protocol TransitionHandler: class { /// - parameter completion: transition setup block with custon type. /// func forSegue(identifier: String, to type: T.Type, completion: @escaping TransitionSetupBlock) - + + + /// + /// Methods close current module. + /// + /// - parameter animated: Transition animate state. + /// func closeModule(animated: Bool) + + /// + /// Methods close all modules in Navigation Controller stack. + /// + /// - parameter animated: Transition animate state. + /// func closeModulesInStack(animated: Bool) } From ed879552910d4985c070d378cada5c145c59577d Mon Sep 17 00:00:00 2001 From: Kirill Budevich Date: Thu, 28 Sep 2017 22:56:59 +0300 Subject: [PATCH 3/4] Upgraded close modules funcs to LightRoute style --- LightRoute/LightRoute.swift | 167 ++++++++++++++++++++++++++++++------ 1 file changed, 140 insertions(+), 27 deletions(-) diff --git a/LightRoute/LightRoute.swift b/LightRoute/LightRoute.swift index 9a2c1d3..be265c3 100644 --- a/LightRoute/LightRoute.swift +++ b/LightRoute/LightRoute.swift @@ -132,19 +132,11 @@ public protocol TransitionHandler: class { /// - /// Methods close current module. + /// Methods close current module(s). /// - /// - parameter animated: Transition animate state. + /// - no parameter. /// - func closeModule(animated: Bool) - - - /// - /// Methods close all modules in Navigation Controller stack. - /// - /// - parameter animated: Transition animate state. - /// - func closeModulesInStack(animated: Bool) + func close() -> CloseTransitionPromise } @@ -217,6 +209,9 @@ public enum TransitionNavigationStyle { /// This case performs that current transition must be present. case present + + /// This case performs that current transition must be pop to root. + case popToRoot } @@ -332,16 +327,18 @@ public final class TransitionPromise { print("[LightRoute]: Transition error, navigation controller was nil.") return } - + switch navCase { case .pop: navController.popToViewController(destination, animated: animated) + case .popToRoot: + navController.popToRootViewController(animated: animated) case .present: navController.present(destination, animated: animated, completion: nil) case .push: navController.pushViewController(destination, animated: animated) } - + case .default: root.present(destination, animated: animated, completion: nil) } @@ -402,6 +399,123 @@ public final class TransitionPromise { } +/// The main class that describes the closing transition. +public final class CloseTransitionPromise { + + // MARK: - + // MARK: Properties + + + // MARK: Public + + /// Shows animated this transition or not. + public var isAnimated: Bool { + return animated + } + + /// Check transition protected or not. + public var isProtected: Bool { + return protected + } + + + // MARK: Private + + // Wait transition post action. + private var postLinkAction: TransitionPostLinkAction? + + // Set and get current transition animate state. + internal var animated: Bool = true + + // Set and get current transition flow state. + internal var protected: Bool = false + + // Main transition data. + private unowned var root: UIViewController + + // Save current transition case. + private var transitionCase: TransitionStyle? + + + // MARK: - + // MARK: Initialize + + /// + /// Initialize transition promise for current transition. + /// - parameter distination: The view controller at which the jump occurs. + /// - parameter type: The argument which checks the specified type and controller type for compatibility, and returns this type in case of success. + /// + init(root: UIViewController) { + self.root = root + } + + /// This method makes a current transition. + public func pop() { + self.postLinkAction?() + } + + /// + /// Instantiate transition case and waits, when should be active. + /// - note: This method must be called once for the current transition. + /// You can call it many times, but he still fire only the last called function. + /// + /// - parameter case: Case for transition promise. + /// - returns: Configured transition promise. + /// + public func to(preferred style: TransitionStyle) -> CloseTransitionPromise { + if self.isProtected { + print("[LightRoute]: Can't add transition case, as was current transition is protected.") + + return self + } + // Remove old link action then we can setup new transition action. + self.postLinkAction = nil + + // Setup new transition action from transition case. + self.postLintAction { [weak self] in + guard let root = self?.root, let animated = self?.isAnimated else { fatalError("[LightRoute]: Root view controller was nil") } + + switch style { + case .navigationController(preferredStyle: let navCase): + + guard let navController = root.navigationController else { + print("[LightRoute]: Transition error, navigation controller was nil.") + return + } + + switch navCase { + case .popToRoot: + navController.popToRootViewController(animated: animated) + default: + fatalError("[LightRoute]: Use only popToRoot in this case") + } + + case .default: + if let navController = root.navigationController { + navController.popViewController(animated: animated) + } else { + root.dismiss(animated: animated, completion: nil) + } + } + } + + return self + } + + // MARK: - + // MARK: Private methods + + /// + /// This method waits to be able to fire. + /// - parameter completion: Whait push action from `TransitionPromise` class. + /// + func postLintAction( _ completion: @escaping TransitionPostLinkAction) { + self.postLinkAction = completion + } + +} + + // MARK: - // MARK: Extension UIViewController @@ -453,22 +567,21 @@ public extension TransitionHandler where Self: UIViewController { } } } - - func closeModule(animated: Bool) { - if let navigationVC = self.navigationController { - navigationVC.popViewController(animated: animated) - } else { - self.dismiss(animated: animated, completion: nil) - } - } - func closeModulesInStack(animated: Bool) { - if let navigationVC = self.navigationController { - navigationVC.popToRootViewController(animated: animated) - } else { - print("[LightRoute]: The navigationController's stack doesn't exist, dissmiss only the top view controller") - self.dismiss(animated: animated, completion: nil) + + func close() -> CloseTransitionPromise { + let promise = CloseTransitionPromise(root: self) + + // Default close transition action. + promise.postLintAction { + if let navController = self.navigationController { + navController.popViewController(animated: true) + } else { + self.dismiss(animated: true, completion: nil) + } } + + return promise } } From 239fc1fb4bbe122459d4abc8d1949446993fc4c5 Mon Sep 17 00:00:00 2001 From: Kirill Budevich Date: Fri, 29 Sep 2017 00:11:25 +0300 Subject: [PATCH 4/4] Fixed error(crash), when the NavController tries to find destinationController on it's stack. --- LightRoute/LightRoute.swift | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/LightRoute/LightRoute.swift b/LightRoute/LightRoute.swift index 307779f..8b78e0f 100644 --- a/LightRoute/LightRoute.swift +++ b/LightRoute/LightRoute.swift @@ -307,6 +307,8 @@ public final class TransitionPromise { } // Remove old link action then we can setup new transition action. self.postLinkAction = nil + + self.checkForPop(in: style) // Setup new transition action from transition case. self.postLintAction { [weak self] in @@ -384,7 +386,40 @@ public final class TransitionPromise { func postLintAction( _ completion: @escaping TransitionPostLinkAction) { self.postLinkAction = completion } - + + /// + /// This method check style for 'pop', if so then change destination view controller to correct from navigation stack. + /// - parameter style: Style from `TransitionStyle` class. + /// + private func checkForPop(in style: TransitionStyle) { + switch style { + case .navigationController(preferredStyle: let navStyle): + switch navStyle { + case .pop: + guard let dest = self.getDestinationFromNavigationStack() else { fatalError("[LightRoute]: Destination view controller was nil (not exist in navigation stack)") } + destination = dest + default: + break + } + + default: + break + } + } + + /// + /// This method found correct view controller from navigation stack. + /// - no parameter. + /// + private func getDestinationFromNavigationStack() -> UIViewController? { + guard let navController = root.navigationController else { + print("[LightRoute]: Transition error, navigation controller was nil.") + return nil + } + let destinationId = destination?.restorationIdentifier + + return navController.viewControllers.filter({ $0.restorationIdentifier == destinationId}).first + } }