Slather logo

Coverage for "DispatchQueue+Action.swift" : 100.00%

(47 of 47 relevant lines covered)

RouteComposer/Classes/Extra/DispatchQueue+Action.swift

1
//
2
// RouteComposer
3
// DispatchQueue+Action.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
/// Extension that wraps actions into `DispatchQueue` and delays it for the provided time interval.
17
///
18
/// Can be used to test action implementation or the configuration issues.
19
public extension DispatchQueue {
20
21
    /// Wraps `Action` in to `DispatchQueue`
22
    ///
23
    /// Parameters:
24
    ///  - action: `Action` instance
25
    ///  - timeInterval: `DispatchTimeInterval` instance
26
    static func delay<A: Action>(_ action: A, for timeInterval: DispatchTimeInterval = .milliseconds(300)) -> DispatchQueueWrappedAction<A> {
1x
27
        DispatchQueueWrappedAction(action, timeInterval: timeInterval)
1x
28
    }
1x
29
30
    /// Wraps `ContainerAction` in to `DispatchQueue`
31
    ///
32
    /// Parameters:
33
    ///  - action: `ContainerAction` instance
34
    ///  - timeInterval: `DispatchTimeInterval` instance
35
    static func delay<A: ContainerAction>(_ action: A, for timeInterval: DispatchTimeInterval = .milliseconds(300)) -> DispatchQueueWrappedContainerAction<A> {
2x
36
        DispatchQueueWrappedContainerAction(action, timeInterval: timeInterval)
2x
37
    }
2x
38
39
}
40
41
/// `CATransaction` wrapper for `Action`
42
public struct DispatchQueueWrappedAction<A: Action>: Action {
43
44
    // MARK: Associated types
45
46
    /// Type of the `UIViewController` that `Action` can start from.
47
    public typealias ViewController = A.ViewController
48
49
    // MARK: Properties
50
51
    let action: A
52
53
    let timeInterval: DispatchTimeInterval
54
55
    // MARK: Methods
56
57
    init(_ action: A, timeInterval: DispatchTimeInterval) {
1x
58
        self.action = action
1x
59
        self.timeInterval = timeInterval
1x
60
    }
1x
61
62
    public func perform(with viewController: UIViewController, on existingController: A.ViewController, animated: Bool, completion: @escaping (RoutingResult) -> Void) {
3x
63
        guard animated else {
3x
64
            action.perform(with: viewController, on: existingController, animated: false, completion: completion)
1x
65
            return
1x
66
        }
2x
67
        action.perform(with: viewController, on: existingController, animated: true, completion: { result in
2x
68
            guard result.isSuccessful else {
2x
69
                completion(result)
1x
70
                return
1x
71
            }
1x
72
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + self.timeInterval) {
1x
73
                completion(result)
1x
74
            }
1x
75
        })
1x
76
    }
2x
77
78
}
79
80
/// `CATransaction` wrapper for `ContainerAction`
81
public struct DispatchQueueWrappedContainerAction<A: ContainerAction>: ContainerAction {
82
83
    // MARK: Associated types
84
85
    /// Type of the `UIViewController` that `Action` can start from.
86
    public typealias ViewController = A.ViewController
87
88
    // MARK: Properties
89
90
    let action: A
91
92
    let timeInterval: DispatchTimeInterval
93
94
    // MARK: Methods
95
96
    init(_ action: A, timeInterval: DispatchTimeInterval) {
2x
97
        self.action = action
2x
98
        self.timeInterval = timeInterval
2x
99
    }
2x
100
101
    public func perform(embedding viewController: UIViewController, in childViewControllers: inout [UIViewController]) throws {
1x
102
        try action.perform(embedding: viewController, in: &childViewControllers)
1x
103
    }
1x
104
105
    public func perform(with viewController: UIViewController, on existingController: A.ViewController, animated: Bool, completion: @escaping (RoutingResult) -> Void) {
3x
106
        guard animated else {
3x
107
            action.perform(with: viewController, on: existingController, animated: false, completion: completion)
1x
108
            return
1x
109
        }
2x
110
        action.perform(with: viewController, on: existingController, animated: true, completion: { result in
2x
111
            guard result.isSuccessful else {
2x
112
                completion(result)
1x
113
                return
1x
114
            }
1x
115
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + self.timeInterval) {
1x
116
                completion(result)
1x
117
            }
1x
118
        })
1x
119
    }
2x
120
121
}