-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRouter.swift
118 lines (101 loc) · 3.4 KB
/
Router.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//
// Router.swift
//
// Created by Guilherme Silva Lisboa on 2016-08-10.
// Copyright © 2016 GLDev. All rights reserved.
//
import UIKit
enum NavigationPath: Int {
case home, none
}
class Router {
// MARK: - Properties
var childRouter: Router? // Has to be optional since the router might not have children.
weak var parent: Router? // Has to be optional since the base router wont have a parent.
var controller: UIViewController = UIViewController()
var possiblePaths: [NavigationPath] {
return []
}
var routerPath: NavigationPath {
return .none
}
init(parent: Router) {
self.parent = parent
parent.childRouter = self
}
// MARK: - Lifecycle
/**
Root router initializer. Should only be used for the root router.
*/
init() {
}
// MARK: - Router Methods
/**
Navigate to new destination from current controller
- parameter destination: Navigation destination
- parameter data: optional data to be transmitted between routers.
- returns: if the path is possible or not.
*/
@discardableResult final func navigateTo(destination: NavigationPath, data: Any? = nil) -> Bool {
guard routerPath != destination else {
guard let childRouter = self.childRouter else { return false }
childRouter.dismissController(router: self, data: data)
return true
}
// check if it's to be intercepted, otherwise take the default destination router
let destinationRouter: Router? = destinationRouterForPath(path: destination, data: data)
guard let router = destinationRouter else {
guard let parent = self.parent else { return false }
return parent.navigateTo(destination: destination, data: data)
}
displayRouter(router: router, path: destination)
childRouter = router
return true
}
// TODO: Check this too. probably dismissController isn't needed. Check to remove.
/**
Dismiss this router from the navigation
- parameter destination: new destination to be handled by the parent if necessary
*/
private func dismissController(router: Router, data: Any? = nil) {
parent?.childWillReturnNavigation(data: data)
guard let navigationController = router.controller.navigationController else {
self.controller.dismiss(animated: true, completion: nil)
return
}
if let navController = router.controller as? UINavigationController {
navController.popToRootViewController(animated: true)
} else {
navigationController.popToViewController(router.controller, animated: true)
}
}
// MARK: Abstract Methods
/**
Called when the router navigate back the flow to its parent.
- parameter data: any data that might be passed to the previous router in the flow.
*/
func childWillReturnNavigation(data: Any? = nil) {
// To be overrited.
}
/**
router to be displayed for this path
- parameter path: navigation path
- parameter data: optional data to be transmitted between routers.
- returns: router to be displayed.
*/
func destinationRouterForPath(path: NavigationPath, data: Any?) -> Router? {
return nil
}
/**
Display a router in a specific way based on the navigation
- parameter router: router to be displayed
- parameter path: navigation path.
*/
func displayRouter(router: Router, path: NavigationPath) {
if let navigationController = controller.navigationController {
navigationController.pushViewController(router.controller, animated: true)
} else {
controller.present(router.controller, animated: true, completion: nil)
}
}
}