Skip to content

Commit fca7a2b

Browse files
committed
[Router] Enable Setting Route Unanimated
Fixes #4
1 parent 95dfb84 commit fca7a2b

File tree

6 files changed

+139
-33
lines changed

6 files changed

+139
-33
lines changed

ReSwiftRouter/NavigationActions.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,25 @@ public let typeMap: [String: StandardActionConvertible.Type] =
1515
public struct SetRouteAction: StandardActionConvertible {
1616

1717
let route: Route
18+
let animated: Bool
1819
public static let type = "RE_SWIFT_ROUTER_SET_ROUTE"
1920

20-
public init (_ route: Route) {
21+
public init (_ route: Route, animated: Bool = true) {
2122
self.route = route
23+
self.animated = animated
2224
}
2325

2426
public init(_ action: StandardAction) {
2527
self.route = action.payload!["route"] as! Route
28+
self.animated = action.payload!["animated"] as! Bool
2629
}
2730

2831
public func toStandardAction() -> StandardAction {
29-
return StandardAction(type: SetRouteAction.type, payload: ["route": route], isTypedAction: true)
32+
return StandardAction(
33+
type: SetRouteAction.type,
34+
payload: ["route": route, "animated": animated],
35+
isTypedAction: true
36+
)
3037
}
3138

3239
}

ReSwiftRouter/NavigationReducer.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public struct NavigationReducer {
2121

2222
switch action {
2323
case let action as SetRouteAction:
24-
return setRoute(state, route: action.route)
24+
return setRoute(state, setRouteAction: action)
2525
case let action as SetRouteSpecificData:
2626
return setRouteSpecificData(state, route: action.route, data: action.data)
2727
default:
@@ -31,8 +31,9 @@ public struct NavigationReducer {
3131
return state
3232
}
3333

34-
static func setRoute(var state: NavigationState, route: Route) -> NavigationState {
35-
state.route = route
34+
static func setRoute(var state: NavigationState, setRouteAction: SetRouteAction) -> NavigationState {
35+
state.route = setRouteAction.route
36+
state.changeRouteAnimated = setRouteAction.animated
3637

3738
return state
3839
}

ReSwiftRouter/NavigationState.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public struct NavigationState {
3030

3131
public var route: Route = []
3232
public var routeSpecificState: [RouteHash: Any] = [:]
33+
var changeRouteAnimated: Bool = true
3334
}
3435

3536
extension NavigationState {

ReSwiftRouter/Routable.swift

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,46 @@ public typealias RoutingCompletionHandler = () -> Void
1010

1111
public protocol Routable {
1212

13-
func changeRouteSegment(from: RouteElementIdentifier,
14-
to: RouteElementIdentifier,
15-
completionHandler: RoutingCompletionHandler) -> Routable
16-
17-
func pushRouteSegment(routeElementIdentifier: RouteElementIdentifier,
13+
func pushRouteSegment(
14+
routeElementIdentifier: RouteElementIdentifier,
15+
animated: Bool,
1816
completionHandler: RoutingCompletionHandler) -> Routable
1917

20-
func popRouteSegment(routeElementIdentifier: RouteElementIdentifier,
18+
func popRouteSegment(
19+
routeElementIdentifier: RouteElementIdentifier,
20+
animated: Bool,
2121
completionHandler: RoutingCompletionHandler)
2222

23+
func changeRouteSegment(
24+
from: RouteElementIdentifier,
25+
to: RouteElementIdentifier,
26+
animated: Bool,
27+
completionHandler: RoutingCompletionHandler) -> Routable
28+
2329
}
2430

2531
extension Routable {
26-
public func changeRouteSegment(from: RouteElementIdentifier,
27-
to: RouteElementIdentifier, completionHandler: RoutingCompletionHandler) -> Routable {
32+
33+
public func pushRouteSegment(
34+
routeElementIdentifier: RouteElementIdentifier,
35+
animated: Bool,
36+
completionHandler: RoutingCompletionHandler) -> Routable {
2837
fatalError("This routable cannot change segments. You have not implemented it.")
2938
}
3039

31-
public func popRouteSegment(routeElementIdentifier: RouteElementIdentifier,
40+
public func popRouteSegment(
41+
routeElementIdentifier: RouteElementIdentifier,
42+
animated: Bool,
3243
completionHandler: RoutingCompletionHandler) {
3344
fatalError("This routable cannot change segments. You have not implemented it.")
3445
}
3546

36-
public func pushRouteSegment(routeElementIdentifier: RouteElementIdentifier,
47+
public func changeRouteSegment(
48+
from: RouteElementIdentifier,
49+
to: RouteElementIdentifier,
50+
animated: Bool,
3751
completionHandler: RoutingCompletionHandler) -> Routable {
3852
fatalError("This routable cannot change segments. You have not implemented it.")
3953
}
54+
4055
}

ReSwiftRouter/Router.swift

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ public class Router<State: StateType>: StoreSubscriber {
4444
case let .Pop(responsibleRoutableIndex, segmentToBePopped):
4545
dispatch_async(dispatch_get_main_queue()) {
4646
self.routables[responsibleRoutableIndex]
47-
.popRouteSegment(segmentToBePopped) {
48-
dispatch_semaphore_signal(semaphore)
47+
.popRouteSegment(
48+
segmentToBePopped,
49+
animated: state.changeRouteAnimated) {
50+
dispatch_semaphore_signal(semaphore)
4951
}
5052

5153
self.routables.removeAtIndex(responsibleRoutableIndex + 1)
@@ -55,8 +57,10 @@ public class Router<State: StateType>: StoreSubscriber {
5557
dispatch_async(dispatch_get_main_queue()) {
5658
self.routables[responsibleRoutableIndex + 1] =
5759
self.routables[responsibleRoutableIndex]
58-
.changeRouteSegment(segmentToBeReplaced,
59-
to: newSegment) {
60+
.changeRouteSegment(
61+
segmentToBeReplaced,
62+
to: newSegment,
63+
animated: state.changeRouteAnimated) {
6064
dispatch_semaphore_signal(semaphore)
6165
}
6266
}
@@ -65,8 +69,10 @@ public class Router<State: StateType>: StoreSubscriber {
6569
dispatch_async(dispatch_get_main_queue()) {
6670
self.routables.append(
6771
self.routables[responsibleRoutableIndex]
68-
.pushRouteSegment(segmentToBePushed) {
69-
dispatch_semaphore_signal(semaphore)
72+
.pushRouteSegment(
73+
segmentToBePushed,
74+
animated: state.changeRouteAnimated) {
75+
dispatch_semaphore_signal(semaphore)
7076
}
7177
)
7278
}

ReSwiftRouterTests/ReSwiftRouterIntegrationTests.swift

Lines changed: 88 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,47 @@ import Nimble
1111
import ReSwift
1212
@testable import ReSwiftRouter
1313

14-
class FakeRoutable: Routable {
14+
class MockRoutable: Routable {
1515

16+
var callsToPushRouteSegment: [(routeElement: RouteElementIdentifier, animated: Bool)] = []
17+
var callsToPopRouteSegment: [(routeElement: RouteElementIdentifier, animated: Bool)] = []
18+
var callsToChangeRouteSegment: [(
19+
from: RouteElementIdentifier,
20+
to: RouteElementIdentifier,
21+
animated: Bool
22+
)] = []
1623

17-
func pushRouteSegment(routeSegment: RouteElementIdentifier,
24+
func pushRouteSegment(
25+
routeElementIdentifier: RouteElementIdentifier,
26+
animated: Bool,
1827
completionHandler: RoutingCompletionHandler) -> Routable {
28+
callsToPushRouteSegment.append(
29+
(routeElement: routeElementIdentifier, animated: animated)
30+
)
1931
completionHandler()
20-
return FakeRoutable()
32+
return MockRoutable()
2133
}
2234

23-
func popRouteSegment(routeSegment: RouteElementIdentifier,
35+
func popRouteSegment(
36+
routeElementIdentifier: RouteElementIdentifier,
37+
animated: Bool,
2438
completionHandler: RoutingCompletionHandler) {
39+
callsToPopRouteSegment.append(
40+
(routeElement: routeElementIdentifier, animated: animated)
41+
)
2542
completionHandler()
2643
}
2744

28-
func changeRouteSegment(from: RouteElementIdentifier,
45+
func changeRouteSegment(
46+
from: RouteElementIdentifier,
2947
to: RouteElementIdentifier,
48+
animated: Bool,
3049
completionHandler: RoutingCompletionHandler) -> Routable {
3150
completionHandler()
32-
return FakeRoutable()
51+
52+
callsToChangeRouteSegment.append((from: from, to: to, animated: animated))
53+
54+
return MockRoutable()
3355
}
3456

3557
}
@@ -74,7 +96,7 @@ class SwiftFlowRouterIntegrationTests: QuickSpec {
7496
func pushRouteSegment(routeElementIdentifier: RouteElementIdentifier,
7597
completionHandler: RoutingCompletionHandler) -> Routable {
7698
called = true
77-
return FakeRoutable()
99+
return MockRoutable()
78100
}
79101
}
80102

@@ -100,12 +122,14 @@ class SwiftFlowRouterIntegrationTests: QuickSpec {
100122
self.calledWithIdentifier = calledWithIdentifier
101123
}
102124

103-
func pushRouteSegment(routeSegment: RouteElementIdentifier,
125+
func pushRouteSegment(
126+
routeSegment: RouteElementIdentifier,
127+
animated: Bool,
104128
completionHandler: RoutingCompletionHandler) -> Routable {
105129
calledWithIdentifier(routeSegment)
106130

107131
completionHandler()
108-
return FakeRoutable()
132+
return MockRoutable()
109133
}
110134

111135
}
@@ -137,12 +161,14 @@ class SwiftFlowRouterIntegrationTests: QuickSpec {
137161
self.calledWithIdentifier = calledWithIdentifier
138162
}
139163

140-
func pushRouteSegment(routeSegment: RouteElementIdentifier,
164+
func pushRouteSegment(
165+
routeSegment: RouteElementIdentifier,
166+
animated: Bool,
141167
completionHandler: RoutingCompletionHandler) -> Routable {
142168
calledWithIdentifier(routeSegment)
143169

144170
completionHandler()
145-
return FakeRoutable()
171+
return MockRoutable()
146172
}
147173
}
148174

@@ -160,7 +186,9 @@ class SwiftFlowRouterIntegrationTests: QuickSpec {
160186
self.injectedRoutable = injectedRoutable
161187
}
162188

163-
func pushRouteSegment(routeElementIdentifier: RouteElementIdentifier,
189+
func pushRouteSegment(
190+
routeElementIdentifier: RouteElementIdentifier,
191+
animated: Bool,
164192
completionHandler: RoutingCompletionHandler) -> Routable {
165193
completionHandler()
166194
return injectedRoutable
@@ -205,6 +233,54 @@ class SwiftFlowRouterIntegrationTests: QuickSpec {
205233

206234
}
207235

236+
describe("configuring animated/unanimated navigation") {
237+
238+
var store: Store<FakeAppState>!
239+
var mockRoutable: MockRoutable!
240+
var router: Router<FakeAppState>!
241+
242+
beforeEach {
243+
store = Store(reducer: AppReducer(), state: nil)
244+
mockRoutable = MockRoutable()
245+
router = Router(store: store, rootRoutable: mockRoutable) { state in
246+
state.navigationState
247+
}
248+
249+
// silence router not read warning, need to keep router alive via reference
250+
_ = router
251+
}
252+
253+
context("when dispatching an animated route change") {
254+
beforeEach {
255+
store.dispatch(SetRouteAction(["someRoute"], animated: true))
256+
}
257+
258+
it("calls routables asking for an animated presentation") {
259+
expect(mockRoutable.callsToPushRouteSegment.last?.animated).toEventually(beTrue())
260+
}
261+
}
262+
263+
context("when dispatching an unanimated route change") {
264+
beforeEach {
265+
store.dispatch(SetRouteAction(["someRoute"], animated: false))
266+
}
267+
268+
it("calls routables asking for an animated presentation") {
269+
expect(mockRoutable.callsToPushRouteSegment.last?.animated).toEventually(beFalse())
270+
}
271+
}
272+
273+
context("when dispatching a default route change") {
274+
beforeEach {
275+
store.dispatch(SetRouteAction(["someRoute"]))
276+
}
277+
278+
it("calls routables asking for an animated presentation") {
279+
expect(mockRoutable.callsToPushRouteSegment.last?.animated).toEventually(beTrue())
280+
}
281+
}
282+
}
283+
208284

209285
}
210286

0 commit comments

Comments
 (0)