18
18
19
19
import ReactiveSwift
20
20
import UIKit
21
+ import ViewEnvironmentUI
21
22
import Workflow
22
23
23
- /// Drives view controllers from a root Workflow.
24
24
public final class WorkflowHostingController < ScreenType, Output> : UIViewController where ScreenType: Screen {
25
+ public typealias CustomizeEnvironment = ( inout ViewEnvironment ) -> Void
26
+
25
27
/// Emits output events from the bound workflow.
26
28
public var output : Signal < Output , Never > {
27
- return workflowHost. output
29
+ workflowHost. output
28
30
}
29
31
30
32
private( set) var rootViewController : UIViewController
@@ -33,28 +35,34 @@ public final class WorkflowHostingController<ScreenType, Output>: UIViewControll
33
35
34
36
private let ( lifetime, token) = Lifetime . make ( )
35
37
36
- public var rootViewEnvironment : ViewEnvironment {
38
+ public var customizeEnvironment : CustomizeEnvironment {
37
39
didSet {
38
- update ( screen : workflowHost . rendering . value , environment : rootViewEnvironment )
40
+ setNeedsEnvironmentUpdate ( )
39
41
}
40
42
}
41
43
42
44
public init < W: AnyWorkflowConvertible > (
43
45
workflow: W ,
44
- rootViewEnvironment : ViewEnvironment = . empty ,
45
- observers : [ WorkflowObserver ] = [ ]
46
+ observers : [ WorkflowObserver ] = [ ] ,
47
+ customizeEnvironment : @escaping CustomizeEnvironment = { _ in }
46
48
) where W. Rendering == ScreenType , W. Output == Output {
47
49
self . workflowHost = WorkflowHost (
48
50
workflow: workflow. asAnyWorkflow ( ) ,
49
51
observers: observers
50
52
)
51
53
52
- self . rootViewController = workflowHost
54
+ self . customizeEnvironment = customizeEnvironment
55
+
56
+ // Customize the default environment for the first render so that we can perform updates and query view
57
+ // controller containment methods before the view has been added to the hierarchy.
58
+ var customizedEnvironment : ViewEnvironment = . empty
59
+ customizeEnvironment ( & customizedEnvironment)
60
+
61
+ rootViewController = workflowHost
53
62
. rendering
54
63
. value
55
- . buildViewController ( in: rootViewEnvironment)
56
-
57
- self . rootViewEnvironment = rootViewEnvironment
64
+ . viewControllerDescription ( environment: customizedEnvironment)
65
+ . buildViewController ( )
58
66
59
67
super. init ( nibName: nil , bundle: nil )
60
68
@@ -66,9 +74,7 @@ public final class WorkflowHostingController<ScreenType, Output>: UIViewControll
66
74
. signal
67
75
. take ( during: lifetime)
68
76
. observeValues { [ weak self] screen in
69
- guard let self = self else { return }
70
-
71
- self . update ( screen: screen, environment: self . rootViewEnvironment)
77
+ self ? . update ( screen: screen)
72
78
}
73
79
}
74
80
@@ -81,9 +87,19 @@ public final class WorkflowHostingController<ScreenType, Output>: UIViewControll
81
87
fatalError ( " init(coder:) has not been implemented " )
82
88
}
83
89
90
+ private func update( screen: ScreenType ) {
91
+ update ( screen: screen, environment: environment)
92
+ }
93
+
84
94
private func update( screen: ScreenType , environment: ViewEnvironment ) {
95
+ let previousRoot = rootViewController
96
+
85
97
update ( child: \. rootViewController, with: screen, in: environment)
86
98
99
+ if previousRoot !== rootViewController {
100
+ setNeedsEnvironmentUpdate ( )
101
+ }
102
+
87
103
updatePreferredContentSizeIfNeeded ( )
88
104
}
89
105
@@ -98,37 +114,43 @@ public final class WorkflowHostingController<ScreenType, Output>: UIViewControll
98
114
updatePreferredContentSizeIfNeeded ( )
99
115
}
100
116
117
+ override public func viewWillLayoutSubviews( ) {
118
+ super. viewWillLayoutSubviews ( )
119
+
120
+ applyEnvironmentIfNeeded ( )
121
+ }
122
+
101
123
override public func viewDidLayoutSubviews( ) {
102
124
super. viewDidLayoutSubviews ( )
103
125
rootViewController. view. frame = view. bounds
104
126
}
105
127
106
128
override public var childForStatusBarStyle : UIViewController ? {
107
- return rootViewController
129
+ rootViewController
108
130
}
109
131
110
132
override public var childForStatusBarHidden : UIViewController ? {
111
- return rootViewController
133
+ rootViewController
112
134
}
113
135
114
136
override public var childForHomeIndicatorAutoHidden : UIViewController ? {
115
- return rootViewController
137
+ rootViewController
116
138
}
117
139
118
140
override public var childForScreenEdgesDeferringSystemGestures : UIViewController ? {
119
- return rootViewController
141
+ rootViewController
120
142
}
121
143
122
144
override public var supportedInterfaceOrientations : UIInterfaceOrientationMask {
123
- return rootViewController. supportedInterfaceOrientations
145
+ rootViewController. supportedInterfaceOrientations
124
146
}
125
147
126
148
override public var preferredStatusBarUpdateAnimation : UIStatusBarAnimation {
127
- return rootViewController. preferredStatusBarUpdateAnimation
149
+ rootViewController. preferredStatusBarUpdateAnimation
128
150
}
129
151
130
152
override public var childViewControllerForPointerLock : UIViewController ? {
131
- return rootViewController
153
+ rootViewController
132
154
}
133
155
134
156
override public func preferredContentSizeDidChange(
@@ -150,4 +172,14 @@ public final class WorkflowHostingController<ScreenType, Output>: UIViewControll
150
172
}
151
173
}
152
174
175
+ extension WorkflowHostingController : ViewEnvironmentCustomizing , ViewEnvironmentObserving {
176
+ public func apply( environment: ViewEnvironment ) {
177
+ update ( screen: workflowHost. rendering. value, environment: environment)
178
+ }
179
+
180
+ public func customize( environment: inout ViewEnvironment ) {
181
+ customizeEnvironment ( & environment)
182
+ }
183
+ }
184
+
153
185
#endif
0 commit comments