Skip to content

Commit 2a7bf42

Browse files
support showing raw screens
1 parent 95ff11b commit 2a7bf42

File tree

3 files changed

+223
-89
lines changed

3 files changed

+223
-89
lines changed

samples/containers/thingy/src/main/java/com/squareup/sample/thingy/BackStackWorkflow.kt

Lines changed: 72 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import kotlinx.coroutines.flow.StateFlow
1010
import kotlinx.coroutines.flow.flowOf
1111

1212
/**
13-
* Creates a [BackStackWorkflow].
13+
* Creates a [BackStackWorkflow]. See the docs on [BackStackWorkflow.runBackStack] for more
14+
* information about what [block] can do.
1415
*/
1516
public inline fun <PropsT, OutputT> backStackWorkflow(
1617
crossinline block: suspend BackStackScope<OutputT>.(props: StateFlow<PropsT>) -> Unit
@@ -25,62 +26,65 @@ public inline fun <PropsT, OutputT> backStackWorkflow(
2526
* Returns a [Workflow] that renders a [BackStackScreen] whose frames are controlled by the code
2627
* in [runBackStack].
2728
*
28-
* [runBackStack] can render child workflows by calling [BackStackScope.showWorkflow]. It can emit
29-
* outputs to its parent by calling [BackStackScope.emitOutput], and access its props via
30-
* the parameter passed to [runBackStack].
31-
*
32-
* # Examples
33-
*
34-
* The backstack is represented by _nesting_ `showWorkflow` calls. Consider this example:
35-
* ```
36-
* backStackWorkflow {
37-
* showWorkflow(child1) {
38-
* showWorkflow(child2) {
39-
* showWorkflow(child3) {
40-
* // goBack()
41-
* }
42-
* }
43-
* }
44-
* }
45-
* ```
46-
* This eventually represents a backstack of `[child1, child2, child3]`. `child2` will be pushed
47-
* onto the stack when `child1` emits an output, and `child3` pushed when `child2` emits. The
48-
* lambdas for `child2` and `child3` can call `goBack` to pop the stack and cancel the lambdas that
49-
* called their `showWorkflow`, until the next output is emitted.
50-
*
51-
* Contrast with calls in series:
52-
* ```
53-
* backStackWorkflow {
54-
* showWorkflow(child1) { finishWith(Unit) }
55-
* showWorkflow(child2) { finishWith(Unit) }
56-
* showWorkflow(child3) { }
57-
* }
58-
* ```
59-
* `child1` will be shown immediately, but when it emits an output, instead of pushing `child2` onto
60-
* the stack, `child1` will be removed from the stack and replaced with `child2`.
61-
*
62-
* These can be combined:
63-
* ```
64-
* backStackWorkflow {
65-
* showWorkflow(child1) {
66-
* showWorkflow(child2) {
67-
* // goBack(), or
68-
* finishWith(Unit)
69-
* }
70-
* showWorkflow(child3) {
71-
* // goBack()
72-
* }
73-
* }
74-
* }
75-
* ```
76-
* This code will show `child1` immediately, then when it emits an output show `child2`. When
77-
* `child2` emits an output, it can decide to call `goBack` to show `child1` again, or call
78-
* `finishWith` to replace itself with `child3`. `child3` can also call `goBack` to show `child`
79-
* again.
29+
* [runBackStack] can show renderings and render child workflows, as well as emit outputs to this
30+
* workflow's parent. See the docs on that method for more info.
8031
*/
8132
public abstract class BackStackWorkflow<PropsT, OutputT> :
8233
Workflow<PropsT, OutputT, BackStackScreen<Screen>> {
8334

35+
/**
36+
* Show renderings by calling [BackStackScope.showScreen]. Show child workflows by calling
37+
* [BackStackScope.showWorkflow]. Emit outputs by calling [BackStackScope.emitOutput].
38+
*
39+
* # Examples
40+
*
41+
* The backstack is represented by _nesting_ `showWorkflow` calls. Consider this example:
42+
* ```
43+
* backStackWorkflow {
44+
* showWorkflow(child1) {
45+
* showWorkflow(child2) {
46+
* showWorkflow(child3) {
47+
* // goBack()
48+
* }
49+
* }
50+
* }
51+
* }
52+
* ```
53+
* This eventually represents a backstack of `[child1, child2, child3]`. `child2` will be pushed
54+
* onto the stack when `child1` emits an output, and `child3` pushed when `child2` emits. The
55+
* lambdas for `child2` and `child3` can call `goBack` to pop the stack and cancel the lambdas that
56+
* called their `showWorkflow`, until the next output is emitted.
57+
*
58+
* Contrast with calls in series:
59+
* ```
60+
* backStackWorkflow {
61+
* showWorkflow(child1) { finishWith(Unit) }
62+
* showWorkflow(child2) { finishWith(Unit) }
63+
* showWorkflow(child3) { }
64+
* }
65+
* ```
66+
* `child1` will be shown immediately, but when it emits an output, instead of pushing `child2` onto
67+
* the stack, `child1` will be removed from the stack and replaced with `child2`.
68+
*
69+
* These can be combined:
70+
* ```
71+
* backStackWorkflow {
72+
* showWorkflow(child1) {
73+
* showWorkflow(child2) {
74+
* // goBack(), or
75+
* finishWith(Unit)
76+
* }
77+
* showWorkflow(child3) {
78+
* // goBack()
79+
* }
80+
* }
81+
* }
82+
* ```
83+
* This code will show `child1` immediately, then when it emits an output show `child2`. When
84+
* `child2` emits an output, it can decide to call `goBack` to show `child1` again, or call
85+
* `finishWith` to replace itself with `child3`. `child3` can also call `goBack` to show `child`
86+
* again.
87+
*/
8488
abstract suspend fun BackStackScope<OutputT>.runBackStack(props: StateFlow<PropsT>)
8589

8690
final override fun asStatefulWorkflow():
@@ -116,15 +120,25 @@ public sealed interface BackStackScope<OutputT> : CoroutineScope {
116120
* that is relevant within a backstack, and it's not possible to know whether the parent supports
117121
* back. What you probably want is to emit an output instead to tell the parent to go back.
118122
*
119-
* @param props The props passed to [workflow] when rendering it. This method will suspend until
120-
* the first value is emitted. Consider transforming the [BackStackWorkflow.runBackStack] props
121-
* [StateFlow] or using [flowOf].
123+
* @param props The props passed to [workflow] when rendering it. [showWorkflow] will suspend
124+
* until the first value is emitted. Consider transforming the [BackStackWorkflow.runBackStack]
125+
* props [StateFlow] or using [flowOf].
122126
*/
123127
suspend fun <ChildPropsT, ChildOutputT, R> showWorkflow(
124128
workflow: Workflow<ChildPropsT, ChildOutputT, Screen>,
129+
// TODO revert this back to a single value – can use the same trick to update props as for
130+
// emitting new screens.
125131
props: Flow<ChildPropsT>,
126132
onOutput: suspend BackStackNestedScope<OutputT, R>.(output: ChildOutputT) -> Unit
127133
): R
134+
135+
/**
136+
* Shows the screen produced by [screenFactory]. Suspends until [BackStackNestedScope.finishWith]
137+
* or [BackStackNestedScope.goBack] is called.
138+
*/
139+
suspend fun <R> showScreen(
140+
screenFactory: BackStackNestedScope<OutputT, R>.() -> Screen
141+
): R
128142
}
129143

130144
/**
@@ -140,14 +154,14 @@ public sealed interface BackStackNestedScope<OutputT, R> : BackStackScope<Output
140154
* [value] and cancels any output handlers still running for that workflow. The workflow is
141155
* removed from the stack and will no longer be rendered.
142156
*/
143-
fun finishWith(value: R): Nothing
157+
suspend fun finishWith(value: R): Nothing
144158

145159
/**
146160
* Removes all workflows started by the parent workflow's handler that invoked this [showWorkflow]
147161
* from the stack, and cancels that parent output handler coroutine (and thus all child workflow
148162
* coroutines as well).
149163
*/
150-
fun goBack(): Nothing
164+
suspend fun goBack(): Nothing
151165
}
152166

153167
public suspend inline fun <OutputT, ChildOutputT, R> BackStackScope<OutputT>.showWorkflow(

0 commit comments

Comments
 (0)