Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1a5bdeb

Browse files
moar docs so i don't forget some cool usage patterns
1 parent702e06f commit1a5bdeb

File tree

1 file changed

+135
-4
lines changed

1 file changed

+135
-4
lines changed

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

Lines changed: 135 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import kotlinx.coroutines.CoroutineScope
88
importkotlinx.coroutines.flow.Flow
99
importkotlinx.coroutines.flow.StateFlow
1010
importkotlinx.coroutines.flow.flowOf
11+
importkotlinx.coroutines.launch
1112

1213
/**
1314
* Creates a [BackStackWorkflow]. See the docs on [BackStackWorkflow.runBackStack] for more
@@ -45,11 +46,58 @@ public abstract class BackStackWorkflow<PropsT, OutputT> :
4546
* Show renderings by calling [BackStackScope.showScreen]. Show child workflows by calling
4647
* [BackStackScope.showWorkflow]. Emit outputs by calling [emitOutput].
4748
*
48-
* # Examples
49+
* # Showing a screen
50+
*
51+
* ```
52+
* backStackWorkflow { _, _ ->
53+
* // Suspends until continueWith is called.
54+
* val result = showScreen {
55+
* MyScreenClass(
56+
* // Returns "finished" from showScreen.
57+
* onDoneClicked = { continueWith("finished") },
58+
* )
59+
* }
60+
* }
61+
* ```
62+
*
63+
* # Showing a workflow
64+
*
65+
* ```
66+
* backStackWorkflow { _, _ ->
67+
* // Suspends until an onOutput lambda returns a value.
68+
* val result = showWorkflow(
69+
* childWorkflow,
70+
* props = flowOf(childProps)
71+
* onOutput = { output ->
72+
* // Returns "finished: …" from showWorkflow.
73+
* return@showWorkflow "finished: $output"
74+
* }
75+
* )
76+
* }
77+
* ```
78+
*
79+
* # Emitting output
80+
*
81+
* The second parameter to the [runBackStack] function is an [emitOutput] function that will send
82+
* whatever you pass to it to this workflow's parent as an output.
83+
* ```
84+
* backStackWorkflow { _, emitOutput ->
85+
* showWorkflow(
86+
* childWorkflow,
87+
* props = flowOf(childProps)
88+
* onOutput = { output ->
89+
* // Forward the output to parent.
90+
* emitOutput(output)
91+
* }
92+
* )
93+
* }
94+
* ```
95+
*
96+
* # Nested vs serial calls
4997
*
5098
* The backstack is represented by _nesting_ `showWorkflow` calls. Consider this example:
5199
* ```
52-
* backStackWorkflow {
100+
* backStackWorkflow { _, _ ->
53101
* showWorkflow(child1) {
54102
* showWorkflow(child2) {
55103
* showWorkflow(child3) {
@@ -66,7 +114,7 @@ public abstract class BackStackWorkflow<PropsT, OutputT> :
66114
*
67115
* Contrast with calls in series:
68116
* ```
69-
* backStackWorkflow {
117+
* backStackWorkflow { _, _ ->
70118
* showWorkflow(child1) { finishWith(Unit) }
71119
* showWorkflow(child2) { finishWith(Unit) }
72120
* showWorkflow(child3) { }
@@ -77,7 +125,7 @@ public abstract class BackStackWorkflow<PropsT, OutputT> :
77125
*
78126
* These can be combined:
79127
* ```
80-
* backStackWorkflow {
128+
* backStackWorkflow { _, _ ->
81129
* showWorkflow(child1) {
82130
* showWorkflow(child2) {
83131
* // goBack(), or
@@ -93,6 +141,77 @@ public abstract class BackStackWorkflow<PropsT, OutputT> :
93141
* `child2` emits an output, it can decide to call `goBack` to show `child1` again, or call
94142
* `finishWith` to replace itself with `child3`. `child3` can also call `goBack` to show `child`
95143
* again.
144+
*
145+
* To push another screen on the backstack from a non-workflow screen, [launch] a coroutine:
146+
* ```
147+
* backStackScreen { _, _ ->
148+
* showScreen {
149+
* MyScreen(
150+
* onEvent = {
151+
* launch {
152+
* showWorkflow(…)
153+
* }
154+
* }
155+
* }
156+
* }
157+
* }
158+
* ```
159+
*
160+
* # Cancelling screens
161+
*
162+
* Calling [BackStackScope.showScreen] or [BackStackScope.showWorkflow] suspends the caller until
163+
* that workflow/screen produces a result. They handle coroutine cancellation too: if the calling
164+
* coroutine is cancelled while they're showing, they are removed from the backstack.
165+
*
166+
* This can be used to, for example, update a screen based on a flow:
167+
* ```
168+
* backStackWorkflow { props, _ ->
169+
* props.collectLatest { prop ->
170+
* showScreen {
171+
* MyScreen(message = prop)
172+
* }
173+
* }
174+
* }
175+
* ```
176+
* This example shows the props received from the parent to the user via `MyScreen`. Every time
177+
* the parent passes a new props, the `showScreen` call is cancelled and called again with the
178+
* new props, replacing the old instance of `MyScreen` in the backstack with a new one. Since
179+
* both instances of `MyScreen` are compatible, this is not a navigation event but just updates
180+
* the `MyScreen` view factory.
181+
*
182+
* # Factoring out code
183+
*
184+
* You don't have to keep all the logic for your backstack in a single function. You can pull out
185+
* functions, just make them extensions on [BackStackParentScope] to get access to `showScreen`
186+
* and `showRendering` calls.
187+
*
188+
* E.g. here's a helper that performs some suspending task and shows a retry screen if it fails:
189+
* ```
190+
* suspend fun <R> BackStackParentScope.userRetriable(
191+
* action: suspend () -> R
192+
* ): R {
193+
* var result = runCatching { action() }
194+
* // runCatching can catch CancellationException, so check.
195+
* ensureActive()
196+
*
197+
* while (result.isFailure) {
198+
* showScreen {
199+
* RetryScreen(
200+
* message = "Failed: ${result.exceptionOrNull()}",
201+
* onRetryClicked = { continueWith(Unit) },
202+
* onCancelClicked = { goBack() }
203+
* )
204+
* }
205+
*
206+
* // Try again.
207+
* result = runCatching { action() }
208+
* ensureActive()
209+
* }
210+
*
211+
* // We only leave the loop when action succeeded.
212+
* return result.getOrThrow()
213+
* }
214+
* ```
96215
*/
97216
abstractsuspendfun BackStackScope.runBackStack(
98217
props:StateFlow<PropsT>,
@@ -134,6 +253,12 @@ public sealed interface BackStackParentScope {
134253
* that is relevant within a backstack, and it's not possible to know whether the parent supports
135254
* back. What you probably want is to emit an output instead to tell the parent to go back.
136255
*
256+
* If the coroutine calling [showWorkflow] is cancelled, the workflow stops being rendered and its
257+
* rendering will be removed from the backstack.
258+
*
259+
* See [BackStackWorkflow.runBackStack] for high-level documentation about how to use this method
260+
* to implement a backstack workflow.
261+
*
137262
* @param props The props passed to [workflow] when rendering it. [showWorkflow] will suspend
138263
* until the first value is emitted. Consider transforming the [BackStackWorkflow.runBackStack]
139264
* props [StateFlow] or using [flowOf].
@@ -149,6 +274,12 @@ public sealed interface BackStackParentScope {
149274
/**
150275
* Shows the screen produced by [screenFactory]. Suspends untilBackStackNestedScope.goBack] is
151276
* called.
277+
*
278+
* If the coroutine calling [showScreen] is cancelled, the rendering will be removed from the
279+
* backstack.
280+
*
281+
* See [BackStackWorkflow.runBackStack] for high-level documentation about how to use this method
282+
* to implement a backstack workflow.
152283
*/
153284
suspendfun <R>showScreen(
154285
screenFactory:BackStackScreenScope<R>.()->Screen

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp