From 57403b4b3685912b988a265e213b811e72655d12 Mon Sep 17 00:00:00 2001 From: ambientlight Date: Tue, 11 Jul 2017 00:08:33 +0800 Subject: [PATCH] updated to ReduxRouter.NavigationController for back button handling --- .../Actions/PopRouteAction.swift | 19 ++++ .../Base.lproj/Main.storyboard | 44 +++---- SwiftFlowGitHubBrowser/Routes/Routes.swift | 4 +- .../BookmarkViewController.swift | 6 - .../NavigationController.swift | 107 ++++++++++++++++++ .../RepositoryDetailViewController.swift | 10 -- .../RootNavigationController.swift | 18 +++ 7 files changed, 170 insertions(+), 38 deletions(-) create mode 100644 SwiftFlowGitHubBrowser/Actions/PopRouteAction.swift create mode 100644 SwiftFlowGitHubBrowser/ViewControllers/NavigationController.swift create mode 100644 SwiftFlowGitHubBrowser/ViewControllers/RootNavigationController.swift diff --git a/SwiftFlowGitHubBrowser/Actions/PopRouteAction.swift b/SwiftFlowGitHubBrowser/Actions/PopRouteAction.swift new file mode 100644 index 0000000..195a0d1 --- /dev/null +++ b/SwiftFlowGitHubBrowser/Actions/PopRouteAction.swift @@ -0,0 +1,19 @@ +// +// PopRouteAction.swift +// SwiftFlowGitHubBrowser +// +// Created by Taras Vozniuk on 11/07/2017. +// Copyright © 2017 Benji Encz. All rights reserved. +// + +import Foundation +import ReSwiftRouter + +func popRouteAction() -> SetRouteAction? { + let currentRoute = store.state.navigationState.route + guard currentRoute.startIndex != currentRoute.endIndex else { + return nil + } + + return SetRouteAction([RouteElementIdentifier](currentRoute[currentRoute.startIndex ..< currentRoute.endIndex.advanced(by: -1)])) +} diff --git a/SwiftFlowGitHubBrowser/Base.lproj/Main.storyboard b/SwiftFlowGitHubBrowser/Base.lproj/Main.storyboard index b351c25..d51569a 100644 --- a/SwiftFlowGitHubBrowser/Base.lproj/Main.storyboard +++ b/SwiftFlowGitHubBrowser/Base.lproj/Main.storyboard @@ -1,9 +1,13 @@ - - + + + + + - + + @@ -15,15 +19,15 @@ - + - - + + - + @@ -65,15 +69,15 @@ - + - - + + - + @@ -112,15 +116,15 @@ - + - - + + - + @@ -165,18 +169,18 @@ - + - + @@ -187,10 +191,10 @@ - + - + diff --git a/SwiftFlowGitHubBrowser/Routes/Routes.swift b/SwiftFlowGitHubBrowser/Routes/Routes.swift index 4ca17c5..c25384f 100644 --- a/SwiftFlowGitHubBrowser/Routes/Routes.swift +++ b/SwiftFlowGitHubBrowser/Routes/Routes.swift @@ -195,8 +195,8 @@ class MainViewRoutable: Routable { _ routeElementIdentifier: RouteElementIdentifier, animated: Bool, completionHandler: @escaping RoutingCompletionHandler) { - // no-op, since this is called when VC is already popped. - completionHandler() + + (self.viewController as? UINavigationController)?.popViewController(true, completion: completionHandler) } } diff --git a/SwiftFlowGitHubBrowser/ViewControllers/BookmarkViewController.swift b/SwiftFlowGitHubBrowser/ViewControllers/BookmarkViewController.swift index 29447ea..d17969e 100644 --- a/SwiftFlowGitHubBrowser/ViewControllers/BookmarkViewController.swift +++ b/SwiftFlowGitHubBrowser/ViewControllers/BookmarkViewController.swift @@ -35,12 +35,6 @@ class BookmarkViewController: UIViewController, StoreSubscriber { super.viewWillDisappear(animated) store.unsubscribe(self) - - // Required to update the route, when this VC was dismissed through back button from - // NavigationController, since we can't intercept the back button - if store.state.navigationState.route == [mainViewRoute, bookmarkRoute] { - store.dispatch(SetRouteAction([mainViewRoute])) - } } func newState(state: [Bookmark]) { diff --git a/SwiftFlowGitHubBrowser/ViewControllers/NavigationController.swift b/SwiftFlowGitHubBrowser/ViewControllers/NavigationController.swift new file mode 100644 index 0000000..b0e61cd --- /dev/null +++ b/SwiftFlowGitHubBrowser/ViewControllers/NavigationController.swift @@ -0,0 +1,107 @@ +// +// NavigationController.swift +// SwiftFlowGitHubBrowser +// +// Created by Taras Vozniuk on 10/07/2017. +// Copyright © 2017 Benji Encz. All rights reserved. +// + +import UIKit +import ReSwiftRouter + +// dummy view controller returned when popViewController is canceled +public final class PopWasIgnored: UIViewController {} + +open class NavigationController: UINavigationController { + + fileprivate var isSwipping: Bool = false + + // indicates that backButton was pressed when set to false + fileprivate var isPerformingPop: Bool = false + + override open func viewDidLoad() { + super.viewDidLoad() + self.interactivePopGestureRecognizer?.addTarget(self, action: #selector(NavigationController.handlePopSwipe)) + self.delegate = self + } + + override open func popViewController(animated: Bool) -> UIViewController? { + + // when swipping we are discarding all subsequent popViewController calls + guard !self.isSwipping else { + return PopWasIgnored() + } + + self.isPerformingPop = true + return super.popViewController(animated: animated) + } + + // will be called after popViewController call + func handlePopSwipe(){ + self.isSwipping = true + } + + /// should be overriden + /// normally you should dispatch SetRouteAction here + open func popRoute(){ + print("WARNING: \(#function) should to be overriden") + } +} + +extension NavigationController: UINavigationControllerDelegate { + + public func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { + self.isSwipping = false + } +} + +extension NavigationController: UINavigationBarDelegate { + + // if overriden navigationController popViewController won't be called before this method + // on back button press + // isPerformingPop will be false here in this case + public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool { + defer { isPerformingPop = false } + + // changeRoute is performed: + // 1. back button was pressed + // 2. pop swipe was triggerred + if !isPerformingPop || self.isSwipping { + self.popRoute() + } + + // don't remove the navigationItem if navigationController + // is not going to be popped + return isPerformingPop + } +} + +/* +extension UINavigationController { + + open func pushViewController(_ viewController: UIViewController, animated: Bool, completion: @escaping () -> Void) { + + self.pushViewController(viewController, animated: animated) + + guard animated, let coordinator = self.transitionCoordinator else { + completion() + return + } + + coordinator.animate(alongsideTransition: nil) { _ in completion() } + } + + open func popViewController(animated: Bool, completion: @escaping () -> Void) -> UIViewController? { + + let popped = self.popViewController(animated: animated) + + guard animated, let coordinator = self.transitionCoordinator else { + completion() + return popped + } + + coordinator.animate(alongsideTransition: nil) { _ in completion() } + return popped + } +} +*/ diff --git a/SwiftFlowGitHubBrowser/ViewControllers/RepositoryDetailViewController.swift b/SwiftFlowGitHubBrowser/ViewControllers/RepositoryDetailViewController.swift index 09d580d..7361b12 100644 --- a/SwiftFlowGitHubBrowser/ViewControllers/RepositoryDetailViewController.swift +++ b/SwiftFlowGitHubBrowser/ViewControllers/RepositoryDetailViewController.swift @@ -47,16 +47,6 @@ class RepositoryDetailViewController: UIViewController, StoreSubscriber { store.unsubscribe(self) } - override func didMove(toParentViewController parent: UIViewController?) { - if parent == nil { - // Required to update the route, when this VC was dismissed through back button from - // NavigationController, since we can't intercept the back button - if store.state.navigationState.route == [mainViewRoute, repositoryDetailRoute] { - store.dispatch(SetRouteAction([mainViewRoute])) - } - } - } - // MARK: State Updates func newState(state: (selectedRepository: Repository?, isBookmarked: Bool)) { diff --git a/SwiftFlowGitHubBrowser/ViewControllers/RootNavigationController.swift b/SwiftFlowGitHubBrowser/ViewControllers/RootNavigationController.swift new file mode 100644 index 0000000..2a68c73 --- /dev/null +++ b/SwiftFlowGitHubBrowser/ViewControllers/RootNavigationController.swift @@ -0,0 +1,18 @@ +// +// RootNavigationController.swift +// SwiftFlowGitHubBrowser +// +// Created by Taras Vozniuk on 10/07/2017. +// Copyright © 2017 Benji Encz. All rights reserved. +// + +import UIKit +import ReSwiftRouter + +class RootNavigationController: NavigationController { + override func popRoute() { + if let popRouteAction = popRouteAction(){ + store.dispatch(popRouteAction) + } + } +}