Skip to content

Commit 8bf017e

Browse files
committed
Add bridging to WorkflowHostingController
1 parent 3df7424 commit 8bf017e

File tree

1 file changed

+52
-20
lines changed

1 file changed

+52
-20
lines changed

WorkflowUI/Sources/Hosting/WorkflowHostingController.swift

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818

1919
import ReactiveSwift
2020
import UIKit
21+
import ViewEnvironmentUI
2122
import Workflow
2223

23-
/// Drives view controllers from a root Workflow.
2424
public final class WorkflowHostingController<ScreenType, Output>: UIViewController where ScreenType: Screen {
25+
public typealias CustomizeEnvironment = (inout ViewEnvironment) -> Void
26+
2527
/// Emits output events from the bound workflow.
2628
public var output: Signal<Output, Never> {
27-
return workflowHost.output
29+
workflowHost.output
2830
}
2931

3032
private(set) var rootViewController: UIViewController
@@ -33,28 +35,34 @@ public final class WorkflowHostingController<ScreenType, Output>: UIViewControll
3335

3436
private let (lifetime, token) = Lifetime.make()
3537

36-
public var rootViewEnvironment: ViewEnvironment {
38+
public var customizeEnvironment: CustomizeEnvironment {
3739
didSet {
38-
update(screen: workflowHost.rendering.value, environment: rootViewEnvironment)
40+
setNeedsEnvironmentUpdate()
3941
}
4042
}
4143

4244
public init<W: AnyWorkflowConvertible>(
4345
workflow: W,
44-
rootViewEnvironment: ViewEnvironment = .empty,
45-
observers: [WorkflowObserver] = []
46+
observers: [WorkflowObserver] = [],
47+
customizeEnvironment: @escaping CustomizeEnvironment = { _ in }
4648
) where W.Rendering == ScreenType, W.Output == Output {
4749
self.workflowHost = WorkflowHost(
4850
workflow: workflow.asAnyWorkflow(),
4951
observers: observers
5052
)
5153

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
5362
.rendering
5463
.value
55-
.buildViewController(in: rootViewEnvironment)
56-
57-
self.rootViewEnvironment = rootViewEnvironment
64+
.viewControllerDescription(environment: customizedEnvironment)
65+
.buildViewController()
5866

5967
super.init(nibName: nil, bundle: nil)
6068

@@ -66,9 +74,7 @@ public final class WorkflowHostingController<ScreenType, Output>: UIViewControll
6674
.signal
6775
.take(during: lifetime)
6876
.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)
7278
}
7379
}
7480

@@ -81,9 +87,19 @@ public final class WorkflowHostingController<ScreenType, Output>: UIViewControll
8187
fatalError("init(coder:) has not been implemented")
8288
}
8389

90+
private func update(screen: ScreenType) {
91+
update(screen: screen, environment: environment)
92+
}
93+
8494
private func update(screen: ScreenType, environment: ViewEnvironment) {
95+
let previousRoot = rootViewController
96+
8597
update(child: \.rootViewController, with: screen, in: environment)
8698

99+
if previousRoot !== rootViewController {
100+
setNeedsEnvironmentUpdate()
101+
}
102+
87103
updatePreferredContentSizeIfNeeded()
88104
}
89105

@@ -98,37 +114,43 @@ public final class WorkflowHostingController<ScreenType, Output>: UIViewControll
98114
updatePreferredContentSizeIfNeeded()
99115
}
100116

117+
override public func viewWillLayoutSubviews() {
118+
super.viewWillLayoutSubviews()
119+
120+
applyEnvironmentIfNeeded()
121+
}
122+
101123
override public func viewDidLayoutSubviews() {
102124
super.viewDidLayoutSubviews()
103125
rootViewController.view.frame = view.bounds
104126
}
105127

106128
override public var childForStatusBarStyle: UIViewController? {
107-
return rootViewController
129+
rootViewController
108130
}
109131

110132
override public var childForStatusBarHidden: UIViewController? {
111-
return rootViewController
133+
rootViewController
112134
}
113135

114136
override public var childForHomeIndicatorAutoHidden: UIViewController? {
115-
return rootViewController
137+
rootViewController
116138
}
117139

118140
override public var childForScreenEdgesDeferringSystemGestures: UIViewController? {
119-
return rootViewController
141+
rootViewController
120142
}
121143

122144
override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
123-
return rootViewController.supportedInterfaceOrientations
145+
rootViewController.supportedInterfaceOrientations
124146
}
125147

126148
override public var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
127-
return rootViewController.preferredStatusBarUpdateAnimation
149+
rootViewController.preferredStatusBarUpdateAnimation
128150
}
129151

130152
override public var childViewControllerForPointerLock: UIViewController? {
131-
return rootViewController
153+
rootViewController
132154
}
133155

134156
override public func preferredContentSizeDidChange(
@@ -150,4 +172,14 @@ public final class WorkflowHostingController<ScreenType, Output>: UIViewControll
150172
}
151173
}
152174

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+
153185
#endif

0 commit comments

Comments
 (0)