Skip to content

Commit

Permalink
- Added global methods for navigation
Browse files Browse the repository at this point in the history
- Added `hidesBottomBarWhenPushed` configuration as Transitionable protocol option
- Added success and failure blocks on state restoration handling enum
- Fixed finding root view controller on app windows
  • Loading branch information
aronbalog committed Feb 24, 2018
1 parent cfe6b60 commit de3a263
Show file tree
Hide file tree
Showing 17 changed files with 167 additions and 108 deletions.
4 changes: 2 additions & 2 deletions CoreNavigation.podspec
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = 'CoreNavigation'
spec.ios.deployment_target = '8.0'
spec.version = '0.3.0'
spec.version = '0.4.0'
spec.license = 'MIT'
spec.summary = 'A Swift navigation framework'
spec.author = 'Aron Balog'
spec.homepage = 'https://github.com/aronbalog/CoreNavigation'
spec.source = { :git => 'https://github.com/aronbalog/CoreNavigation.git', :tag => '0.3.0' }
spec.source = { :git => 'https://github.com/aronbalog/CoreNavigation.git', :tag => spec.version }
spec.requires_arc = true
spec.xcconfig = { 'SWIFT_VERSION' => '4.0' }

Expand Down
18 changes: 18 additions & 0 deletions CoreNavigation.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@
3865B9901FEEA69B00C3182E /* ViewControllerEmbedding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E4584A1FAD0F5600134E74 /* ViewControllerEmbedding.swift */; };
3865B9911FEEA6A400C3182E /* NavigationConfiguration+Routing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383BE4E51FCBA91200C17AE3 /* NavigationConfiguration+Routing.swift */; };
3865B9921FEEA6A400C3182E /* Router+SharedInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 381C01141FCCCCC700CA7531 /* Router+SharedInstance.swift */; };
386EE1F8202924990005AFBB /* Route+ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386EE1F7202924990005AFBB /* Route+ViewController.swift */; };
386EE1F9202924990005AFBB /* Route+ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386EE1F7202924990005AFBB /* Route+ViewController.swift */; };
386EE1FB20292A140005AFBB /* Global.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386EE1FA20292A140005AFBB /* Global.swift */; };
386EE1FC20292A140005AFBB /* Global.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386EE1FA20292A140005AFBB /* Global.swift */; };
386EE1FE202938D80005AFBB /* Route+Registration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386EE1FD202938D80005AFBB /* Route+Registration.swift */; };
386EE1FF202938D80005AFBB /* Route+Registration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386EE1FD202938D80005AFBB /* Route+Registration.swift */; };
38814B02200EA3C900480711 /* ViewController_Purple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38814B01200EA3C900480711 /* ViewController_Purple.swift */; };
38814B04200EBA0A00480711 /* Auth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38814B03200EBA0A00480711 /* Auth.swift */; };
38C518B21FE5E2A600581709 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38C518B11FE5E2A600581709 /* AppDelegate.swift */; };
Expand Down Expand Up @@ -135,6 +141,9 @@
385718651FBDB33C0050810F /* UINavigationController+ViewControllerEmbedding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationController+ViewControllerEmbedding.swift"; sourceTree = "<group>"; };
385B9CCE1FEC5A06001306EC /* DataPassable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataPassable.swift; sourceTree = "<group>"; };
3865B9731FEE959700C3182E /* ResponseAware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseAware.swift; sourceTree = "<group>"; };
386EE1F7202924990005AFBB /* Route+ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Route+ViewController.swift"; sourceTree = "<group>"; };
386EE1FA20292A140005AFBB /* Global.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Global.swift; sourceTree = "<group>"; };
386EE1FD202938D80005AFBB /* Route+Registration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Route+Registration.swift"; sourceTree = "<group>"; };
38814B01200EA3C900480711 /* ViewController_Purple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController_Purple.swift; sourceTree = "<group>"; };
38814B03200EBA0A00480711 /* Auth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Auth.swift; sourceTree = "<group>"; };
38C518AF1FE5E2A500581709 /* CoreNavigationExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CoreNavigationExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -262,6 +271,8 @@
383BE4E51FCBA91200C17AE3 /* NavigationConfiguration+Routing.swift */,
381C01141FCCCCC700CA7531 /* Router+SharedInstance.swift */,
38D8232620228CD3003FA799 /* UIViewController+Routing.swift */,
386EE1F7202924990005AFBB /* Route+ViewController.swift */,
386EE1FD202938D80005AFBB /* Route+Registration.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -427,6 +438,7 @@
383BE4D21FCB4E7D00C17AE3 /* ObjectAssociation.swift */,
3808A415200C2D63006FD933 /* StateRestoration.swift */,
380E0C5520143358006E3F4B /* StateRestorationContext.swift */,
386EE1FA20292A140005AFBB /* Global.swift */,
);
path = Classes;
sourceTree = "<group>";
Expand Down Expand Up @@ -804,6 +816,7 @@
3865B97A1FEEA68B00C3182E /* NavigationAction.swift in Sources */,
38C518D21FE5E70400581709 /* ViewController_Orange.swift in Sources */,
3865B97C1FEEA68B00C3182E /* Navigator.swift in Sources */,
386EE1FC20292A140005AFBB /* Global.swift in Sources */,
38E890572002CD98006C1C67 /* ViewController_Green.swift in Sources */,
38C518B41FE5E2A600581709 /* ViewController.swift in Sources */,
38C518D01FE5E2E700581709 /* ViewController_Yellow.swift in Sources */,
Expand All @@ -815,6 +828,7 @@
3865B98A1FEEA69B00C3182E /* Protectable.swift in Sources */,
3865B98D1FEEA69B00C3182E /* Transitionable.swift in Sources */,
3865B98B1FEEA69B00C3182E /* Lifetime.swift in Sources */,
386EE1FF202938D80005AFBB /* Route+Registration.swift in Sources */,
3865B9821FEEA68B00C3182E /* ObjectAssociation.swift in Sources */,
3865B98E1FEEA69B00C3182E /* ViewControllerEventable.swift in Sources */,
38E890552002CAF3006C1C67 /* ProtectionSpace.swift in Sources */,
Expand All @@ -824,6 +838,7 @@
38C518D71FE5E74400581709 /* Route_Orange.swift in Sources */,
3865B97F1FEEA68B00C3182E /* Configuration.swift in Sources */,
3865B9811FEEA68B00C3182E /* ViewControllerEvents.swift in Sources */,
386EE1F9202924990005AFBB /* Route+ViewController.swift in Sources */,
380E0C5720143358006E3F4B /* StateRestorationContext.swift in Sources */,
38814B02200EA3C900480711 /* ViewController_Purple.swift in Sources */,
3865B9901FEEA69B00C3182E /* ViewControllerEmbedding.swift in Sources */,
Expand Down Expand Up @@ -872,9 +887,11 @@
38D8232720228CD3003FA799 /* UIViewController+Routing.swift in Sources */,
38F34B021FCB0D8C000F2696 /* UIViewController+VisibleViewController.swift in Sources */,
383BE4C71FCB4BB100C17AE3 /* Transitionable.swift in Sources */,
386EE1F8202924990005AFBB /* Route+ViewController.swift in Sources */,
38392DB01FBCF66D00040EA8 /* Navigator.swift in Sources */,
38CBD2E31FE71A9500D495CE /* Protectable.swift in Sources */,
3808A416200C2D63006FD933 /* StateRestoration.swift in Sources */,
386EE1FB20292A140005AFBB /* Global.swift in Sources */,
383BE4D71FCB579500C17AE3 /* UIApplication+RunOnce.swift in Sources */,
383BE4D11FCB4E6900C17AE3 /* UIViewController+Events.swift in Sources */,
38E4584B1FAD0F5600134E74 /* ViewControllerEmbedding.swift in Sources */,
Expand All @@ -892,6 +909,7 @@
383BE4CB1FCB4BE600C17AE3 /* Eventable.swift in Sources */,
383BE4D31FCB4E7D00C17AE3 /* ObjectAssociation.swift in Sources */,
383BE4E61FCBA91200C17AE3 /* NavigationConfiguration+Routing.swift in Sources */,
386EE1FE202938D80005AFBB /* Route+Registration.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
7 changes: 7 additions & 0 deletions CoreNavigation/Core/Classes/Action/NavigationAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,11 @@ public class NavigationAction<FromViewController: UIViewController, ToViewContro

return self
}

@discardableResult public func hidesBottomBarWhenPushed(_ hidesBottomBarWhenPushed: Bool) -> Self {
configuration.transition.hidesBottomBarWhenPushed = hidesBottomBarWhenPushed

return self
}

}
1 change: 1 addition & 0 deletions CoreNavigation/Core/Classes/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public struct Configuration {
var animated: Bool?
var completionBlocks: [(() -> Void)] = []
var viewControllerTransitioningDelegate: UIViewControllerTransitioningDelegate?
var hidesBottomBarWhenPushed: Bool?
}
class Result {
var successBlocks: [ResponseSuccessBlock<FromViewController, ToViewController, EmbeddingViewController>] = []
Expand Down
14 changes: 14 additions & 0 deletions CoreNavigation/Core/Classes/Global.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Foundation
import UIKit

public func present(_ configuration: @escaping (Configuration.Present) -> Void) {
Navigation.present(configuration)
}

public func push(_ configuration: @escaping (Configuration.Push) -> Void) {
Navigation.push(configuration)
}

public func response(_ configuration: (Configuration.Response) -> Void) -> Response<UIViewController, UIViewController, UIViewController>? {
return Navigation.response(configuration)
}
91 changes: 49 additions & 42 deletions CoreNavigation/Core/Classes/Navigator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class Navigator<FromViewController: UIViewController, ToViewController: UIViewCo
case .response:
return self.response()
}
}() else { return nil }
}() else { return nil }

configuration.result.successBlocks.forEach { (block) in
block(response)
Expand Down Expand Up @@ -93,7 +93,7 @@ class Navigator<FromViewController: UIViewController, ToViewController: UIViewCo
else {
return nil
}

var _response: NavigationResponse?

func action(destinationViewController: UIViewController) {
Expand Down Expand Up @@ -137,6 +137,10 @@ class Navigator<FromViewController: UIViewController, ToViewController: UIViewCo

fromViewController?.transitioningDelegate = transitioningDelegate

if let hidesBottomBarWhenPushed = configuration.transition.hidesBottomBarWhenPushed {
toViewController.hidesBottomBarWhenPushed = hidesBottomBarWhenPushed
}

switch configuration.stateRestoration.option {
case .automatically:
StateRestoration.prepare(toViewController, identifier: nil, parameters: response.parameters, protectionSpace: configuration.protection.protectionSpace)
Expand All @@ -151,7 +155,7 @@ class Navigator<FromViewController: UIViewController, ToViewController: UIViewCo
default:
()
}

if perform {
cache(viewController: toViewController)
bindEvents(to: toViewController)
Expand All @@ -170,7 +174,7 @@ class Navigator<FromViewController: UIViewController, ToViewController: UIViewCo
guard let toViewController = getToViewController({ (toViewController) in
if let toViewController = toViewController {
_response = self.response(fromViewController: nil, toViewController: toViewController, perform: true, releaseDestination: false, action: { _ in

}, completion: { _ in

})
Expand All @@ -184,16 +188,16 @@ class Navigator<FromViewController: UIViewController, ToViewController: UIViewCo
}

return self.response(fromViewController: nil, toViewController: toViewController, perform: true, releaseDestination: false, action: { destinationViewController in

}, completion: { _ in

})
}

private var fromViewController: UIViewController? {
return
(configuration.origin.fromViewController as? FromViewController) ??
UIViewController.currentViewController
UIViewController.currentViewController
}
private func getToViewController(_ toViewControllerBlock: @escaping (ToViewController?) -> Void) -> ToViewController? {
var cachedViewController: ToViewController? {
Expand All @@ -220,45 +224,47 @@ class Navigator<FromViewController: UIViewController, ToViewController: UIViewCo

#if ROUTING
func _route(to route: AbstractRoute, in router: Router) -> ToViewController? {
let request = Request<String, Any?>(route: route.routePath)

var _toViewController: ToViewController?

router.request(request)
.onSuccess({ (response) in
if let destination = response.destination as? ToViewController {
_toViewController = destination
} else if let destination = response.destination as? ToViewController.Type {
_toViewController = destination.init(nibName: nil, bundle: nil)
}

if let parameters = response.parameters {
self.configuration.data.value.merge(parameters, uniquingKeysWith: { (oldValue, newValue) -> Any in
newValue
})
}

if let parameters = (route as? ParametersAware)?.parameters {
self.configuration.data.value.merge(parameters, uniquingKeysWith: { (oldValue, newValue) -> Any in
newValue
})
}

toViewControllerBlock(_toViewController)
})
.execute()

return _toViewController
}

var _toViewController: ToViewController?

if let parameters = (route as? ParametersAware)?.parameters {
self.configuration.data.value.merge(parameters, uniquingKeysWith: { (oldValue, newValue) -> Any in
newValue
})
}

let request = Request<String, Any?>(route: route.routePath, parameters: self.configuration.data.value)

router.request(request)
.onSuccess({ (response) in
if let destination = response.destination as? ToViewController {
_toViewController = destination
} else if let destination = response.destination as? ToViewController.Type {
_toViewController = destination.init(nibName: nil, bundle: nil)
}

if let parameters = response.parameters {
self.configuration.data.value.merge(parameters, uniquingKeysWith: { (oldValue, newValue) -> Any in
newValue
})
}


toViewControllerBlock(_toViewController)
})
.execute()

return _toViewController
}
#endif

guard let viewController = cachedViewController ?? toViewController else {
#if ROUTING
if let (route, router) = target as? (AbstractRoute, Router) {
if let _toViewController = _route(to: route, in: router) {
return _toViewController
if let (route, router) = target as? (AbstractRoute, Router) {
if let _toViewController = _route(to: route, in: router) {
return _toViewController
}
}
}
#endif

return nil
Expand All @@ -278,7 +284,7 @@ class Navigator<FromViewController: UIViewController, ToViewController: UIViewCo

if let embeddingViewController = embeddingViewController {
passResponse(response, to: embeddingViewController)

switch configuration.stateRestoration.option {
case .automatically:
StateRestoration.prepare(embeddingViewController, identifier: nil, parameters: nil, protectionSpace: nil)
Expand Down Expand Up @@ -323,3 +329,4 @@ class Navigator<FromViewController: UIViewController, ToViewController: UIViewCo
}
}
}

4 changes: 3 additions & 1 deletion CoreNavigation/Core/Classes/StateRestoration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,18 @@ class StateRestoration: UIViewControllerRestoration {
viewController = action(storageItem: storageItem)

return viewController
case .protect(let protectionSpace):
case .protect(let protectionSpace, let onUnprotect, let onFailure):
if protectionSpace.shouldProtect(unprotect: {
viewController = action(storageItem: storageItem)

if let viewController = viewController {
context.unprotectSuccess?(viewController)
onUnprotect?(viewController)
}
}, failure: { (error) in
viewController = nil
context.unprotectFailure?(error)
onFailure?(error)
}) == false {
viewController = action(storageItem: storageItem)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,7 @@ extension UIViewController {

/// Returns the current application's top most view controller.
public class var currentViewController: UIViewController? {
var rootViewController: UIViewController?
let currentWindows = UIApplication.shared.windows

for window in currentWindows {
if let windowRootViewController = window.rootViewController {
rootViewController = windowRootViewController
break
}
}
let rootViewController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController

return self.currentViewController(of: rootViewController)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import UIKit
public enum StateRestorationBehavior {
case allow
case reject
case protect(protectionSpace: ProtectionSpace)
case protect(protectionSpace: ProtectionSpace, onUnprotect: StateRestorationContext.UnprotectSuccess?, onFailure: StateRestorationContext.UnprotectFailure?)
}

public protocol StateRestorationDelegate {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import UIKit
public protocol Transitionable {
func animated(_ animated: Bool) -> Self
func completion(_ completion: @escaping () -> Void) -> Self
func hidesBottomBarWhenPushed(_ hidesBottomBarWhenPushed: Bool) -> Self
}

public protocol TransitioningDelegatable {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Foundation
import CoreRoute

public extension Route {
public static func register(in router: Router = Navigation.router) {
router.register(routeType: self)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Foundation
import CoreRoute

public extension Route {
public var viewController: UIViewController? {
return UIViewController.from(route: self)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import UIKit
import CoreRoute

public extension UIViewController {
static func from<R: Route>(route: R) -> UIViewController? {
public static func from<R: AbstractRoute>(route: R) -> UIViewController? {
var response: Response<UIViewController, UIViewController, UIViewController>?

response = Navigation.response({ $0
Expand All @@ -14,6 +14,5 @@ public extension UIViewController {
return response?.toViewController
}
}

#endif

2 changes: 1 addition & 1 deletion CoreNavigationExample/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, StateRestorationDelegate
}

func application(_ application: UIApplication, stateRestorationBehaviorForContext context: StateRestorationContext) -> StateRestorationBehavior {
return .protect(protectionSpace: Auth(loggedIn: true))
return .protect(protectionSpace: Auth(loggedIn: true), onUnprotect: nil, onFailure: nil)
}

func application(_ application: UIApplication, viewControllerWithRestorationIdentifierPath identifierComponents: [Any], coder: NSCoder) -> UIViewController? {
Expand Down
Loading

0 comments on commit de3a263

Please sign in to comment.