@@ -8,18 +8,23 @@ import kotlinx.coroutines.CoroutineScope
88import kotlinx.coroutines.flow.Flow
99import kotlinx.coroutines.flow.StateFlow
1010import kotlinx.coroutines.flow.flowOf
11- import kotlin.experimental.ExperimentalTypeInference
1211
1312/* *
1413 * Creates a [BackStackWorkflow]. See the docs on [BackStackWorkflow.runBackStack] for more
1514 * information about what [block] can do.
1615 */
1716public inline fun <PropsT , OutputT > backStackWorkflow (
18- crossinline block : suspend BackStackScope <OutputT >.(props: StateFlow <PropsT >) -> Unit
17+ crossinline block : suspend BackStackScope .(
18+ props: StateFlow <PropsT >,
19+ emitOutput: (OutputT ) -> Unit
20+ ) -> Unit
1921): Workflow <PropsT , OutputT , BackStackScreen <Screen >> =
2022 object : BackStackWorkflow <PropsT , OutputT >() {
21- override suspend fun BackStackScope<OutputT>.runBackStack (props : StateFlow <PropsT >) {
22- block(props)
23+ override suspend fun BackStackScope.runBackStack (
24+ props : StateFlow <PropsT >,
25+ emitOutput : (OutputT ) -> Unit
26+ ) {
27+ block(props, emitOutput)
2328 }
2429 }
2530
@@ -35,7 +40,7 @@ public abstract class BackStackWorkflow<PropsT, OutputT> :
3540
3641 /* *
3742 * Show renderings by calling [BackStackScope.showScreen]. Show child workflows by calling
38- * [BackStackScope.showWorkflow]. Emit outputs by calling [BackStackScope. emitOutput].
43+ * [BackStackScope.showWorkflow]. Emit outputs by calling [emitOutput].
3944 *
4045 * # Examples
4146 *
@@ -86,7 +91,10 @@ public abstract class BackStackWorkflow<PropsT, OutputT> :
8691 * `finishWith` to replace itself with `child3`. `child3` can also call `goBack` to show `child`
8792 * again.
8893 */
89- abstract suspend fun BackStackScope<OutputT>.runBackStack (props : StateFlow <PropsT >)
94+ abstract suspend fun BackStackScope.runBackStack (
95+ props : StateFlow <PropsT >,
96+ emitOutput : (OutputT ) -> Unit
97+ )
9098
9199 final override fun asStatefulWorkflow ():
92100 StatefulWorkflow <PropsT , * , OutputT , BackStackScreen <Screen >> =
@@ -97,23 +105,19 @@ public abstract class BackStackWorkflow<PropsT, OutputT> :
97105annotation class BackStackWorkflowDsl
98106
99107@BackStackWorkflowDsl
100- public sealed interface BackStackScope <OutputT > : CoroutineScope {
101-
102- /* *
103- * Emits an output to the [backStackWorkflow]'s parent.
104- */
105- fun emitOutput (output : OutputT )
108+ public sealed interface BackStackParentScope {
106109
107110 /* *
108111 * Starts rendering [workflow] and pushes its rendering onto the top of the backstack.
109112 *
110113 * Whenever [workflow] emits an output, [onOutput] is launched into a new coroutine. If one call
111114 * doesn't finish before another output is emitted, multiple callbacks can run concurrently.
112115 *
113- * When [onOutput] calls [BackStackNestedScope.finishWith], this workflow stops rendering, its
114- * rendering is removed from the backstack, and any running output handlers are cancelled.
116+ * When [onOutput] returns a value, this workflow stops rendering, its rendering is removed from
117+ * the backstack, and any running output handlers are cancelled. The calling coroutine is resumed
118+ * with the value.
115119 *
116- * When [onOutput] calls [BackStackNestedScope .goBack], if this [showWorkflow] call is nested in
120+ * When [onOutput] calls [BackStackWorkflowScope .goBack], if this [showWorkflow] call is nested in
117121 * another, then this workflow will stop rendering, any of its still-running output handlers will
118122 * be cancelled, and the output handler that called this [showWorkflow] will be cancelled.
119123 * If this is a top-level workflow in the [BackStackWorkflow], the whole
@@ -130,32 +134,27 @@ public sealed interface BackStackScope<OutputT> : CoroutineScope {
130134 // TODO revert this back to a single value – can use the same trick to update props as for
131135 // emitting new screens.
132136 props : Flow <ChildPropsT >,
133- onOutput : suspend BackStackNestedScope < OutputT , R > .(output: ChildOutputT ) -> Unit
137+ onOutput : suspend BackStackWorkflowScope .(output: ChildOutputT ) -> R
134138 ): R
135139
136140 /* *
137- * Shows the screen produced by [screenFactory]. Suspends until [BackStackNestedScope.finishWith]
138- * or [BackStackNestedScope.goBack] is called.
141+ * Shows the screen produced by [screenFactory]. Suspends untilBackStackNestedScope.goBack] is
142+ * called.
139143 */
140144 suspend fun <R > showScreen (
141- screenFactory : BackStackNestedScope < OutputT , R >.() -> Screen
145+ screenFactory : BackStackScreenScope < R >.() -> Screen
142146 ): R
143147}
144148
149+ @BackStackWorkflowDsl
150+ public sealed interface BackStackScope : BackStackParentScope , CoroutineScope
151+
145152/* *
146153 * Scope receiver used for all [showWorkflow] calls. This has all the capabilities of
147- * [BackStackScope] with the additional ability to [finish][finishWith] a nested workflow or
148- * [go back][goBack] to its outer workflow.
154+ * [BackStackScope] with the additional ability to [go back][goBack] to its outer workflow.
149155 */
150156@BackStackWorkflowDsl
151- public sealed interface BackStackNestedScope <OutputT , R > : BackStackScope <OutputT > {
152-
153- /* *
154- * Causes the [showWorkflow] call that ran the output handler that was passed this scope to return
155- * [value] and cancels any output handlers still running for that workflow. The workflow is
156- * removed from the stack and will no longer be rendered.
157- */
158- suspend fun finishWith (value : R ): Nothing
157+ public sealed interface BackStackWorkflowScope : BackStackScope {
159158
160159 /* *
161160 * Removes all workflows started by the parent workflow's handler that invoked this [showWorkflow]
@@ -165,22 +164,22 @@ public sealed interface BackStackNestedScope<OutputT, R> : BackStackScope<Output
165164 suspend fun goBack (): Nothing
166165}
167166
168- @OptIn(ExperimentalTypeInference ::class )
169- public suspend inline fun <OutputT , ChildOutputT , R > BackStackScope<OutputT>.showWorkflow (
167+ @BackStackWorkflowDsl
168+ public sealed interface BackStackScreenScope <R > : BackStackScope {
169+ fun continueWith (value : R )
170+ fun goBack ()
171+ }
172+
173+ public suspend inline fun <ChildOutputT , R > BackStackParentScope.showWorkflow (
170174 workflow : Workflow <Unit , ChildOutputT , Screen >,
171- @BuilderInference noinline onOutput : suspend BackStackNestedScope < OutputT , R > .(output: ChildOutputT ) -> Unit
175+ noinline onOutput : suspend BackStackWorkflowScope .(output: ChildOutputT ) -> R
172176): R = showWorkflow(workflow, props = flowOf(Unit ), onOutput)
173177
174- // public suspend inline fun <OutputT, ChildOutputT> BackStackScope<OutputT>.showWorkflow(
175- // workflow: Workflow<Unit, ChildOutputT, Screen>,
176- // noinline onOutput: suspend BackStackNestedScope<OutputT, Unit>.(output: ChildOutputT) -> Unit
177- // ): Unit = showWorkflow(workflow, props = flowOf(Unit), onOutput)
178-
179- public suspend inline fun <ChildPropsT > BackStackScope <* >.showWorkflow (
178+ public suspend inline fun <ChildPropsT > BackStackParentScope.showWorkflow (
180179 workflow : Workflow <ChildPropsT , Nothing , Screen >,
181180 props : Flow <ChildPropsT >,
182181): Nothing = showWorkflow(workflow, props = props) { error(" Cannot call" ) }
183182
184- public suspend inline fun BackStackScope < * > .showWorkflow (
183+ public suspend inline fun BackStackParentScope .showWorkflow (
185184 workflow : Workflow <Unit , Nothing , Screen >,
186185): Nothing = showWorkflow(workflow, props = flowOf(Unit )) { error(" Cannot call" ) }
0 commit comments