From a729f27f4ccefd162c5d110d25c68b4d235aea25 Mon Sep 17 00:00:00 2001 From: Tyler Heck Date: Sat, 26 Jul 2025 12:29:47 -0600 Subject: [PATCH 1/8] Update welcome image link path in tutorial 1 readme file --- samples/tutorial/Tutorial1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/tutorial/Tutorial1.md b/samples/tutorial/Tutorial1.md index 6bf0e2f45e..075bdf6918 100644 --- a/samples/tutorial/Tutorial1.md +++ b/samples/tutorial/Tutorial1.md @@ -10,7 +10,7 @@ The `tutorial-base` module will be our starting place to build from. Go ahead and launch `TutorialActivity`. You should see this welcome screen: -![Welcome](im "An Android phone app with title text _Welcome!_, an EditText with prompt _Please enter your name_, and a Log In button") +![Welcome](images/welcome.png "An Android phone app with title text _Welcome!_, an EditText with prompt _Please enter your name_, and a Log In button") You can enter a name, but the login button won't do anything. From f3e91e719b6bddd639a0f189813e2d488f3cf92d Mon Sep 17 00:00:00 2001 From: Tyler Heck Date: Sat, 26 Jul 2025 12:30:46 -0600 Subject: [PATCH 2/8] Add newline between markdown alert type and content in tutorial readme files --- samples/tutorial/Tutorial1.md | 3 ++- samples/tutorial/Tutorial2.md | 6 ++++-- samples/tutorial/Tutorial5.md | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/samples/tutorial/Tutorial1.md b/samples/tutorial/Tutorial1.md index 075bdf6918..5220ae1a40 100644 --- a/samples/tutorial/Tutorial1.md +++ b/samples/tutorial/Tutorial1.md @@ -196,7 +196,8 @@ object WelcomeWorkflow : StatefulWorkflow() } ``` -> [!TIP] This tutorial doesn't cover persistence support. +> [!TIP] +> This tutorial doesn't cover persistence support. > If you feel the need for it, > the easiest way to get there is by using the [`@Parcelize` annotation](https://developer.android.com/kotlin/parcelize) on your state types. > They will be saved and restored via the `savedStateHandler` of the JetPack `ViewModel` diff --git a/samples/tutorial/Tutorial2.md b/samples/tutorial/Tutorial2.md index fb1b6276f3..d10640f81a 100644 --- a/samples/tutorial/Tutorial2.md +++ b/samples/tutorial/Tutorial2.md @@ -591,7 +591,8 @@ Update `render()` to create an `eventHandler` function to post the new output ev At the same time, use workflow's handy `View.setBackHandler` function to respond to Android back press events. -> [!NOTE] `View.setBackHandler` is implemented via +> [!NOTE] +> `View.setBackHandler` is implemented via > [OnBackPressedCallback](https://developer.android.com/reference/androidx/activity/OnBackPressedCallback) > and so plays nicely with the > [OnBackPressedDispatcher](https://developer.android.com/reference/androidx/activity/OnBackPressedDispatcher), Compose's [BackHandler](https://foso.github.io/Jetpack-Compose-Playground/activity/backhandler/) @@ -653,7 +654,8 @@ navigate TodoListScreen(username=David, todoTitles=[Take the cat for a walk], o navigate WelcomeScreen(promptText=, onLogInTapped=Function1) ``` -> [!TIP] Note the logging above remains useful +> [!TIP] +> Note the logging above remains useful > even though we are now wrapping our leaf screens in a `BackStackScreen`. > The default `onNavigate` function used by `Flow<*>.reportNavigation()` > can drill through the stock `Unwrappable` interface implemented by `BackStackScreen` diff --git a/samples/tutorial/Tutorial5.md b/samples/tutorial/Tutorial5.md index 07272742cb..c1313b879c 100644 --- a/samples/tutorial/Tutorial5.md +++ b/samples/tutorial/Tutorial5.md @@ -241,7 +241,8 @@ The child's rendering _must_ be specified when declaring an expected workflow since the parent's call to `renderChild` _must_ return a value of the appropriate rendering type, and the workflow library can't know how to create those instances of your own types. -> [!NOTE] Under `testRender` all children are mocked +> [!NOTE] +> Under `testRender` all children are mocked > > We consider tests built around `testRender` to be unit tests (as opposed to integration tests) > because they do not actually run any child workflows or workers. From 8c902575cd4cc183a1d3cb490ce8cca2eacc1a51 Mon Sep 17 00:00:00 2001 From: Tyler Heck Date: Sat, 26 Jul 2025 12:32:41 -0600 Subject: [PATCH 3/8] Update code link syntax in tutorial 2 readme file --- samples/tutorial/Tutorial2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/tutorial/Tutorial2.md b/samples/tutorial/Tutorial2.md index d10640f81a..45d0a23cbf 100644 --- a/samples/tutorial/Tutorial2.md +++ b/samples/tutorial/Tutorial2.md @@ -711,6 +711,6 @@ We'll show you how in the next tutorial, when we add our Todo Editing screen. > - The `Overlay` marker interface, implemented by renderings that model things like Android `Dialog` windows > - `ScreenOverlay` for modeling an `Overlay` whose content comes from a `Screen` > - `BodyAndOverlaysScreen`, a class that arranges `Overlay` instances in layers over a body `Screen`. -> - And `the [AndroidOverlay](https://github.com/square/workflow-kotlin/blob/main/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/navigation/AndroidOverlay.kt)` interface that simplifies implementing `ScreenOverlay` with Android's `AppCompatDialog` class. +> - And the [`AndroidOverlay`](https://github.com/square/workflow-kotlin/blob/main/workflow-ui/core-android/src/main/java/com/squareup/workflow1/ui/navigation/AndroidOverlay.kt) interface that simplifies implementing `ScreenOverlay` with Android's `AppCompatDialog` class. [Tutorial 3](Tutorial3.md) From 8370242a9487aa31a73019efb23ee478f6cd7bf4 Mon Sep 17 00:00:00 2001 From: Tyler Heck Date: Sat, 26 Jul 2025 12:34:07 -0600 Subject: [PATCH 4/8] Update typographical errors in tutorial readme files --- samples/tutorial/Tutorial1.md | 2 +- samples/tutorial/Tutorial5.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/tutorial/Tutorial1.md b/samples/tutorial/Tutorial1.md index 5220ae1a40..12004a5a40 100644 --- a/samples/tutorial/Tutorial1.md +++ b/samples/tutorial/Tutorial1.md @@ -373,7 +373,7 @@ You could also write: } ``` -And let's make an `onLogInTapped` event handler that enques one of those `updateName` actions. +And let's make an `onLogInTapped` event handler that enqueues one of those `updateName` actions. ```kotlin object WelcomeWorkflow : StatefulWorkflow() { diff --git a/samples/tutorial/Tutorial5.md b/samples/tutorial/Tutorial5.md index c1313b879c..f09bd089c4 100644 --- a/samples/tutorial/Tutorial5.md +++ b/samples/tutorial/Tutorial5.md @@ -464,7 +464,7 @@ class TodoNavigationWorkflowTest { The `RenderTester` allows easy "mocking" of child workflows and workers. However, this means that we are not exercising the full infrastructure (even though we could get a fairly high confidence from the tests). -ometimes, it may be worth putting together integration tests that test a full tree of Workflows. +Sometimes, it may be worth putting together integration tests that test a full tree of Workflows. This lets us test integration with the non-workflow world as well, such as external reactive data sources that your workflows might be observing via Workers. @@ -482,12 +482,12 @@ the same runtime that `renderWorkflowIn` uses. When you create an Android app using Workflow, you will probably use `renderWorkflowIn`, which starts a runtime to host your workflows in an androidx ViewModel. -Under the hood,this method is an overload of lower-level `renderWorkflowIn` function +Under the hood, this method is an overload of lower-level `renderWorkflowIn` function that runs the workflow runtime in a coroutine and exposes a `StateFlow` of renderings. When writing integration tests for workflows, you can use this core function directly (maybe with a library like [Turbine](https://github.com/cashapp/turbine)), or you can use `workflow-testing`'s `WorkflowTester`. -The `WorkflowTester` starts a workflow and lets you request renderingsand outputs manually +The `WorkflowTester` starts a workflow and lets you request renderings and outputs manually so you can write tests that interact with the runtime from the outside. This will be a properly opaque test, From 3c5f98f9f8b66de7ff2c9a4f0ddc3284913097cc Mon Sep 17 00:00:00 2001 From: Tyler Heck Date: Sat, 26 Jul 2025 12:35:06 -0600 Subject: [PATCH 5/8] Add tutorial 5 readme file link to tutorial 4 readme file --- samples/tutorial/Tutorial4.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/tutorial/Tutorial4.md b/samples/tutorial/Tutorial4.md index 5e5b00491f..d46d73c2d7 100644 --- a/samples/tutorial/Tutorial4.md +++ b/samples/tutorial/Tutorial4.md @@ -441,3 +441,5 @@ Additionally, now the `TodoList` and `TodoEdit` workflows are completely decoupl there is no longer a requirement that the `TodoEdit` workflow is displayed after the list. For instance, we could change the list to have "viewing" or "editing" modes, where tapping on an item might only allow it to be viewed, but another mode would allow editing. + +[Tutorial 5](Tutorial5.md) From 357fbfd5879e7a91c5d65fc115316b0726309b08 Mon Sep 17 00:00:00 2001 From: Tyler Heck Date: Sat, 26 Jul 2025 12:37:22 -0600 Subject: [PATCH 6/8] Update reference errors in tutorial readme files --- samples/tutorial/Tutorial1.md | 2 +- samples/tutorial/Tutorial2.md | 8 ++++---- samples/tutorial/Tutorial4.md | 6 +++--- samples/tutorial/Tutorial5.md | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/samples/tutorial/Tutorial1.md b/samples/tutorial/Tutorial1.md index 12004a5a40..711fa7e89c 100644 --- a/samples/tutorial/Tutorial1.md +++ b/samples/tutorial/Tutorial1.md @@ -142,7 +142,7 @@ private fun welcomeScreenRunner( viewBinding: WelcomeViewBinding ) = ScreenViewRunner { screen: WelcomeScreen, _ -> viewBinding.prompt.text = screen.promptText - viewBinding.login.setOnClickListener { + viewBinding.logIn.setOnClickListener { screen.onLogInTapped(viewBinding.username.text.toString()) } } diff --git a/samples/tutorial/Tutorial2.md b/samples/tutorial/Tutorial2.md index 45d0a23cbf..cce96adb8b 100644 --- a/samples/tutorial/Tutorial2.md +++ b/samples/tutorial/Tutorial2.md @@ -138,7 +138,7 @@ private fun todoListScreenRunner( todoListBinding.todoList.adapter = adapter return ScreenViewRunner { screen: TodoListScreen, _ -> - adapter.todoList = rendering.todoTitles + adapter.todoList = screen.todoTitles adapter.notifyDataSetChanged() } } @@ -396,7 +396,7 @@ object RootNavigationWorkflow : StatefulWorkflow() // infrastructure will create a child workflow with state if one is not already running. val welcomeScreen = context.renderChild(WelcomeWorkflow) { output -> // When WelcomeWorkflow emits LoggedIn, turn it into our login action. - login(output.username) + logIn(output.username) } return welcomeScreen } @@ -571,8 +571,8 @@ object RootNavigationWorkflow : StatefulWorkflow { val todoBackStack = context.renderChild( - child = TodoNavigationWorkflow, - props = TodoProps(renderState.username), + child = TodoListWorkflow, + props = ListProps(renderState.username), handler = { // When TodoNavigationWorkflow emits Back, enqueue our log out action. logOut diff --git a/samples/tutorial/Tutorial4.md b/samples/tutorial/Tutorial4.md index d46d73c2d7..4aa326590c 100644 --- a/samples/tutorial/Tutorial4.md +++ b/samples/tutorial/Tutorial4.md @@ -213,7 +213,7 @@ object TodoNavigationWorkflow : StatefulWorkflow @@ -294,7 +294,7 @@ object TodoNavigationWorkflow : StatefulWorkflow @@ -403,7 +403,7 @@ object TodoNavigationWorkflow : StatefulWorkflow diff --git a/samples/tutorial/Tutorial5.md b/samples/tutorial/Tutorial5.md index f09bd089c4..0a5462d819 100644 --- a/samples/tutorial/Tutorial5.md +++ b/samples/tutorial/Tutorial5.md @@ -343,7 +343,7 @@ class TodoNavigationWorkflowTest { TodoNavigationWorkflow .testRender( - props = TodoProps(name = "Ada"), + props = TodoProps(username = "Ada"), // Start from the list step to validate selecting a todo. initialState = State( todos = todos, @@ -385,7 +385,7 @@ class TodoNavigationWorkflowTest { TodoNavigationWorkflow .testRender( - props = TodoProps(name = "Ada"), + props = TodoProps(username = "Ada"), // Start from the edit step so we can simulate saving. initialState = State( todos = todos, From d54c1f7855eaf84404c11a78159aeb25c9b2e696 Mon Sep 17 00:00:00 2001 From: Tyler Heck Date: Sat, 26 Jul 2025 12:37:46 -0600 Subject: [PATCH 7/8] Update type errors in tutorial readme files --- samples/tutorial/Tutorial2.md | 6 +++--- samples/tutorial/Tutorial4.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/tutorial/Tutorial2.md b/samples/tutorial/Tutorial2.md index cce96adb8b..53f5e73d1a 100644 --- a/samples/tutorial/Tutorial2.md +++ b/samples/tutorial/Tutorial2.md @@ -208,7 +208,7 @@ object RootNavigationWorkflow : StatefulWorkflow() return welcomeScreen } - override fun snapshotState(state: State): Snapshot? = null + override fun snapshotState(state: Unit): Snapshot? = null } ``` @@ -349,9 +349,9 @@ Finally, map the output event from `WelcomeWorkflow` in `RootNavigationWorkflow` ```kotlin override fun render( renderProps: Unit, - renderState: Unit, + renderState: State, context: RenderContext - ): Screen { + ): WelcomeScreen { // Render a child workflow of type WelcomeWorkflow. When renderChild is called, the // infrastructure will start a child workflow session if one is not already running. val welcomeScreen = context.renderChild(WelcomeWorkflow) { output -> diff --git a/samples/tutorial/Tutorial4.md b/samples/tutorial/Tutorial4.md index 4aa326590c..0e749bd94d 100644 --- a/samples/tutorial/Tutorial4.md +++ b/samples/tutorial/Tutorial4.md @@ -109,7 +109,7 @@ object TodoListWorkflow : StatefulWorkflow Date: Sat, 26 Jul 2025 12:38:17 -0600 Subject: [PATCH 8/8] Update code errors in tutorial 2 readme file --- samples/tutorial/Tutorial2.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/samples/tutorial/Tutorial2.md b/samples/tutorial/Tutorial2.md index 53f5e73d1a..cb3cfdd4af 100644 --- a/samples/tutorial/Tutorial2.md +++ b/samples/tutorial/Tutorial2.md @@ -254,10 +254,10 @@ At the same time, add a `reportNavigation()` call when creating the `renderings` workflow = RootNavigationWorkflow, scope = viewModelScope, savedStateHandle = savedState - ) - }.reportNavigation { - Log.i("navigate", it.toString()) -} + ).reportNavigation { + Log.i("navigate", it.toString()) + } + } ``` Now when you run the app we'll see the welcome screen again. @@ -486,8 +486,12 @@ object TodoListWorkflow : StatefulWorkflow