Skip to content

Commit 62b9d86

Browse files
committed
Add Tutorial 3
1 parent e462bf8 commit 62b9d86

File tree

7 files changed

+190
-17
lines changed

7 files changed

+190
-17
lines changed

samples/tutorial/tutorial-base/src/main/java/workflow/tutorial/RootWorkflow.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ object RootWorkflow : StatefulWorkflow<Unit, State, Nothing, BackStackScreen<Scr
4343
when(renderState) {
4444
is Welcome -> {}
4545
is Todo -> {
46-
val todoScreen = context.renderChild(child = TodoListWorkflow, ListProps(username = renderState.username)) {
46+
val todoScreens = context.renderChild(child = TodoListWorkflow, ListProps(username = renderState.username)) {
4747
logout()
4848
}
49-
backStackScreens.add(todoScreen)
49+
backStackScreens.addAll(todoScreens)
5050
}
5151
}
5252

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package workflow.tutorial
2+
3+
import com.squareup.workflow1.ui.Screen
4+
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
5+
6+
@OptIn(WorkflowUiExperimentalApi::class)
7+
data class TodoEditScreen(
8+
val title: String,
9+
val note: String,
10+
val onTitleChanged: (String) -> Unit,
11+
val onNoteChanged: (String) -> Unit,
12+
13+
val discardChanges: () -> Unit,
14+
val saveChanges: () -> Unit
15+
): Screen
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package workflow.tutorial
2+
3+
import com.squareup.workflow1.ui.LayoutRunner
4+
import com.squareup.workflow1.ui.LayoutRunner.Companion.bind
5+
import com.squareup.workflow1.ui.ScreenViewFactory
6+
import com.squareup.workflow1.ui.ScreenViewFactory.Companion
7+
import com.squareup.workflow1.ui.ScreenViewRunner
8+
import com.squareup.workflow1.ui.ViewEnvironment
9+
import com.squareup.workflow1.ui.ViewFactory
10+
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
11+
import com.squareup.workflow1.ui.backPressedHandler
12+
import com.squareup.workflow1.ui.setTextChangedListener
13+
import com.squareup.workflow1.ui.updateText
14+
import workflow.tutorial.views.databinding.TodoEditViewBinding
15+
16+
@OptIn(WorkflowUiExperimentalApi::class)
17+
class TodoEditScreenViewRunner(
18+
private val binding: TodoEditViewBinding
19+
) : ScreenViewRunner<TodoEditScreen> {
20+
21+
override fun showRendering(
22+
rendering: TodoEditScreen,
23+
viewEnvironment: ViewEnvironment
24+
) {
25+
binding.root.backPressedHandler = rendering.discardChanges
26+
binding.save.setOnClickListener { rendering.saveChanges() }
27+
binding.todoTitle.updateText(rendering.title)
28+
binding.todoTitle.setTextChangedListener { rendering.onTitleChanged(it.toString()) }
29+
binding.todoNote.updateText(rendering.note)
30+
binding.todoNote.setTextChangedListener { rendering.onNoteChanged(it.toString()) }
31+
}
32+
33+
companion object : ScreenViewFactory<TodoEditScreen> by ScreenViewFactory.Companion.fromViewBinding(
34+
bindingInflater = TodoEditViewBinding::inflate,
35+
constructor = ::TodoEditScreenViewRunner
36+
)
37+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package workflow.tutorial
2+
3+
import android.icu.text.CaseMap.Title
4+
import com.squareup.workflow1.Snapshot
5+
import com.squareup.workflow1.StatefulWorkflow
6+
import com.squareup.workflow1.action
7+
import workflow.tutorial.TodoEditWorkflow.EditProps
8+
import workflow.tutorial.TodoEditWorkflow.Output
9+
import workflow.tutorial.TodoEditWorkflow.Output.Discard
10+
import workflow.tutorial.TodoEditWorkflow.Output.Save
11+
import workflow.tutorial.TodoEditWorkflow.State
12+
import workflow.tutorial.TodoListWorkflow.TodoModel
13+
14+
object TodoEditWorkflow : StatefulWorkflow<EditProps, State, Output, TodoEditScreen>() {
15+
16+
data class EditProps(
17+
val initialTodo: TodoModel
18+
)
19+
20+
data class State(
21+
val todo:TodoModel
22+
)
23+
24+
sealed class Output {
25+
object Discard: Output()
26+
data class Save(val todo: TodoModel): Output()
27+
}
28+
override fun initialState(
29+
props: EditProps,
30+
snapshot: Snapshot?
31+
): State = State(props.initialTodo)
32+
33+
override fun onPropsChanged(
34+
old: EditProps,
35+
new: EditProps,
36+
state: State
37+
): State {
38+
if (old.initialTodo != new.initialTodo) {
39+
return state.copy(todo = new.initialTodo)
40+
}
41+
return state
42+
}
43+
44+
override fun render(
45+
renderProps: EditProps,
46+
renderState: State,
47+
context: RenderContext
48+
): TodoEditScreen {
49+
return TodoEditScreen(
50+
title = renderState.todo.title,
51+
note = renderState.todo.note,
52+
onTitleChanged = { context.actionSink.send(onTitleChanged(it)) },
53+
onNoteChanged = { context.actionSink.send(onNoteChanged(it)) },
54+
saveChanges = { context.actionSink.send(onSave()) },
55+
discardChanges = { context.actionSink.send(onDiscard()) }
56+
)
57+
}
58+
59+
override fun snapshotState(state: State): Snapshot? = null
60+
61+
private fun onTitleChanged(title: String) = action { state = state.withTitle(title) }
62+
63+
private fun onNoteChanged(note: String) = action { state = state.withNote(note) }
64+
65+
private fun onDiscard() = action { setOutput(Discard) }
66+
67+
private fun onSave() = action { setOutput(Save(state.todo)) }
68+
69+
private fun State.withTitle(title: String) = copy(todo = todo.copy(title = title))
70+
private fun State.withNote(note: String) = copy(todo = todo.copy(note = note))
71+
}

samples/tutorial/tutorial-base/src/main/java/workflow/tutorial/TodoListScreenViewRunner.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
package workflow.tutorial
22

33
import androidx.recyclerview.widget.LinearLayoutManager
4-
import com.squareup.workflow1.ui.LayoutRunner
5-
import com.squareup.workflow1.ui.LayoutRunner.Companion.bind
64
import com.squareup.workflow1.ui.ScreenViewFactory
7-
import com.squareup.workflow1.ui.ScreenViewFactory.Companion
85
import com.squareup.workflow1.ui.ScreenViewRunner
96
import com.squareup.workflow1.ui.ViewEnvironment
10-
import com.squareup.workflow1.ui.ViewFactory
11-
import workflow.tutorial.views.databinding.TodoListViewBinding
127
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
138
import com.squareup.workflow1.ui.backPressedHandler
149
import workflow.tutorial.views.TodoListAdapter
10+
import workflow.tutorial.views.databinding.TodoListViewBinding
1511

1612
@OptIn(WorkflowUiExperimentalApi::class)
1713
class TodoListScreenViewRunner(
@@ -34,6 +30,7 @@ class TodoListScreenViewRunner(
3430
}
3531

3632
adapter.todoList = rendering.todoTitles
33+
adapter.onTodoSelected = rendering.onTodoSelected
3734
adapter.notifyDataSetChanged()
3835
}
3936

samples/tutorial/tutorial-base/src/main/java/workflow/tutorial/TodoListWorkflow.kt

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,18 @@ package workflow.tutorial
33
import com.squareup.workflow1.Snapshot
44
import com.squareup.workflow1.StatefulWorkflow
55
import com.squareup.workflow1.action
6+
import com.squareup.workflow1.ui.Screen
7+
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
8+
import workflow.tutorial.TodoEditWorkflow.EditProps
9+
import workflow.tutorial.TodoEditWorkflow.Output.Discard
10+
import workflow.tutorial.TodoEditWorkflow.Output.Save
611
import workflow.tutorial.TodoListWorkflow.Back
712
import workflow.tutorial.TodoListWorkflow.ListProps
813
import workflow.tutorial.TodoListWorkflow.State
14+
import workflow.tutorial.TodoListWorkflow.State.Step
915

10-
object TodoListWorkflow : StatefulWorkflow<ListProps, State, Back, TodoListScreen>() {
16+
@OptIn(WorkflowUiExperimentalApi::class)
17+
object TodoListWorkflow : StatefulWorkflow<ListProps, State, Back, List<Screen>>() {
1118

1219
object Back
1320
data class ListProps(val username: String)
@@ -16,39 +23,84 @@ object TodoListWorkflow : StatefulWorkflow<ListProps, State, Back, TodoListScree
1623
val note: String
1724
)
1825
data class State(
19-
val todos: List<TodoModel>
20-
)
26+
val todos: List<TodoModel>,
27+
val step: Step
28+
) {
29+
sealed class Step {
30+
object List: Step()
31+
32+
data class Edit(val index: Int) : Step()
33+
}
34+
}
2135

2236
override fun initialState(
2337
props: ListProps,
2438
snapshot: Snapshot?
2539
): State = State(
26-
listOf(
40+
todos = listOf(
2741
TodoModel(
2842
title = "Take the cat for a walk",
2943
note = "Cats really need their outside sunshine time. Don't forget to walk " +
30-
"Charlie. Hamilton is less excited about the prospect."
44+
"Charlie. Hamilton is less excited about the prospect.",
3145
)
32-
)
46+
),
47+
step = Step.List
3348
)
3449

3550
override fun render(
3651
renderProps: ListProps,
3752
renderState: State,
3853
context: RenderContext
39-
): TodoListScreen {
54+
): List<Screen> {
4055
val titles = renderState.todos.map { it.title }
41-
return TodoListScreen(
56+
val todoListScreen = TodoListScreen(
4257
username = renderProps.username,
4358
todoTitles = titles,
44-
onTodoSelected = {},
59+
onTodoSelected = {context.actionSink.send(selectTodo(it))},
4560
onBack = { context.actionSink.send(onBack()) }
4661
)
62+
63+
return when(val step = renderState.step) {
64+
Step.List -> listOf(todoListScreen)
65+
is Step.Edit -> {
66+
val todoEditScreen = context.renderChild(
67+
TodoEditWorkflow,
68+
props = EditProps(renderState.todos[step.index])
69+
) { output ->
70+
when(output) {
71+
Discard -> discardChanges()
72+
is Save -> saveChanges(output.todo, step.index)
73+
}
74+
}
75+
return listOf(todoListScreen, todoEditScreen)
76+
}
77+
}
78+
4779
}
4880

4981
private fun onBack() = action {
5082
setOutput(Back)
5183
}
5284

85+
private fun selectTodo(index: Int) = action {
86+
state = state.copy(step = Step.Edit(index))
87+
}
88+
89+
private fun discardChanges() = action {
90+
// When a discard action is received, return to the list.
91+
state = state.copy(step = Step.List)
92+
}
93+
94+
private fun saveChanges(
95+
todo: TodoModel,
96+
index: Int
97+
) = action {
98+
// When changes are saved, update the state of that todo item and return to the list.
99+
state = state.copy(
100+
todos = state.todos.toMutableList().also { it[index] = todo },
101+
step = Step.List
102+
)
103+
}
104+
53105
override fun snapshotState(state: State): Snapshot? = null
54106
}

samples/tutorial/tutorial-base/src/main/java/workflow/tutorial/TutorialActivity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ class TutorialActivity : AppCompatActivity() {
2525
// No need to add BackStackContainer. Its now by default built in ViewRegistry
2626
// com.squareup.workflow1.ui.backstack.BackStackContainer,
2727
WelcomeScreenViewRunner,
28-
TodoListScreenViewRunner
28+
TodoListScreenViewRunner,
29+
TodoEditScreenViewRunner
2930
)
3031

3132
override fun onCreate(savedInstanceState: Bundle?) {

0 commit comments

Comments
 (0)