Slather logo

Coverage for "GlobalInterceptorRouter.swift" : 78.38%

(29 of 37 relevant lines covered)

RouteComposer/Classes/Extra/GlobalInterceptorRouter.swift

1
//
2
// RouteComposer
3
// GlobalInterceptorRouter.swift
4
// https://github.com/ekazaev/route-composer
5
//
6
// Created by Eugene Kazaev in 2018-2022.
7
// Distributed under the MIT license.
8
//
9
// Become a sponsor:
10
// https://github.com/sponsors/ekazaev
11
//
12
13
import Foundation
14
import UIKit
15
16
/// The `DefaultRouter` searches for the view controller as a starting point before it starts to run interceptors.
17
/// Sometimes if interceptor can change the entire stack of view controllers it is handy to run a global interceptor
18
/// any starting point is found. `GlobalInterceptorRouter` proxy allows to add such a global interceptor that will be
19
/// executed before any work that `DefaultRouter` will do.
20
public struct GlobalInterceptorRouter<R>: Router where R: Router {
21
22
    // MARK: Properties
23
24
    var router: R
25
26
    private var interceptors: [AnyRoutingInterceptor] = []
13x
27
28
    // MARK: Methods
29
30
    /// Constructor
31
    ///
32
    /// - Parameters:
33
    ///   - router: `Router` instance to proxy.
34
    public init(router: R) {
13x
35
        self.router = router
13x
36
    }
13x
37
38
    public func navigate<Context>(to step: DestinationStep<some UIViewController, Context>,
39
                                  with context: Context,
40
                                  animated: Bool,
41
                                  completion: ((RoutingResult) -> Void)?) throws {
100x
42
        do {
100x
43
            let interceptorRunner = try DefaultRouter.InterceptorRunner(interceptors: interceptors, with: AnyContextBox(context))
100x
44
            interceptorRunner.perform(completion: { result in
100x
45
                do {
100x
46
                    switch result {
100x
47
                    case .success:
100x
48
                        try router.navigate(to: step, with: context, animated: animated, completion: { result in
100x
49
                            completion?(result)
97x
50
                        })
97x
51
                    case let .failure(error):
100x
52
                        throw error
!
53
                    }
100x
54
                } catch {
100x
55
                    completion?(.failure(error))
3x
56
                }
100x
57
            })
100x
58
        } catch {
100x
59
            throw error
!
60
        }
100x
61
    }
100x
62
63
    /// Adds `RoutingInterceptor` instance to the `GlobalInterceptorRouter`
64
    ///
65
    /// - Parameter interceptor: The `RoutingInterceptor` instance to be executed by `Router` before routing to this step.
66
    public mutating func addGlobal<RI: RoutingInterceptor>(_ interceptor: RI) where RI.Context == Any? {
26x
67
        interceptors.append(RoutingInterceptorBox(interceptor))
26x
68
    }
26x
69
70
}
71
72
extension GlobalInterceptorRouter: InterceptableRouter where R: InterceptableRouter {
73
74
    public mutating func add<RI: RoutingInterceptor>(_ interceptor: RI) where RI.Context == Any? {
13x
75
        router.add(interceptor)
13x
76
    }
13x
77
78
    public mutating func add<CT: ContextTask>(_ contextTask: CT) where CT.ViewController == UIViewController, CT.Context == Any? {
!
79
        router.add(contextTask)
!
80
    }
!
81
82
    public mutating func add<PT: PostRoutingTask>(_ postTask: PT) where PT.Context == Any? {
!
83
        router.add(postTask)
!
84
    }
!
85
86
}