Update Tutorial 4
MODIFY
Samples/Tutorial/Frameworks/Tutorial4Complete/Sources/RootWorkflow.swift
Samples/Tutorial/Frameworks/Tutorial4Complete/Sources/RootWorkflow.swift
@@ -51,18 +51,19 @@ extension RootWorkflow {
enum Action: WorkflowAction {
typealias WorkflowType = RootWorkflow
- case login(name: String)
- case logout
+ case logIn(name: String)
+ case logOut
func apply(toState state: inout RootWorkflow.State) -> RootWorkflow.Output? {
switch self {
- case .login(name: let name):
+ case .logIn(name: let name):
// When the `login` action is received, change the state to `todo`.
state = .todo(name: name)
- case .logout:
+ case .logOut:
// Return to the welcome state on logout.
state = .welcome
}
+
return nil
}
}
@@ -90,17 +91,15 @@ extension RootWorkflow {
typealias Rendering = BackStackScreen<AnyScreen>
func render(state: RootWorkflow.State, context: RenderContext<RootWorkflow>) -> Rendering {
- // Delete the `let sink = context.makeSink(of: ...) as we no longer need a sink.
-
// Our list of back stack items. Will always include the "WelcomeScreen".
var backStackItems: [BackStackScreen<AnyScreen>.Item] = []
let welcomeScreen = WelcomeWorkflow()
.mapOutput { output -> Action in
switch output {
- // When `WelcomeWorkflow` emits `didLogin`, turn it into our `login` action.
- case .didLogin(name: let name):
- return .login(name: name)
+ // When `WelcomeWorkflow` emits `didLogIn`, turn it into our `logIn` action.
+ case .didLogIn(name: let name):
+ return .logIn(name: name)
}
}
.rendered(in: context)
@@ -116,25 +115,24 @@ extension RootWorkflow {
backStackItems.append(welcomeBackStackItem)
switch state {
- // When the state is `.welcome`, defer to the WelcomeWorkflow.
case .welcome:
// We always add the welcome screen to the backstack, so this is a no op.
break
- // When the state is `.todo`, defer to the TodoListWorkflow.
case .todo(name: let name):
+ // When the state is `.todo`, defer to the TodoListWorkflow.
- // was: let todoBackStackItems = TodoListWorkflow(name: name)
let todoBackStackItems = TodoWorkflow(name: name)
.mapOutput { output -> Action in
switch output {
case .back:
- // When receiving a `.back` output, treat it as a `.logout` action.
- return .logout
+ // When receiving a `.back` output, treat it as a `.logOut` action.
+ return .logOut
}
}
.rendered(in: context)
+ // Add the todoBackStackItems to our backStackItems
backStackItems.append(contentsOf: todoBackStackItems)
}

MODIFY
Samples/Tutorial/Frameworks/Tutorial4Complete/Sources/Todo/Edit/TodoEditWorkflow.swift
Samples/Tutorial/Frameworks/Tutorial4Complete/Sources/Todo/Edit/TodoEditWorkflow.swift
@@ -140,6 +140,7 @@ extension TodoEditWorkflow {
))
)
)
+
return backStackItem
}
}

MODIFY
Samples/Tutorial/Frameworks/Tutorial4Complete/Sources/Todo/List/TodoListWorkflow.swift
Samples/Tutorial/Frameworks/Tutorial4Complete/Sources/Todo/List/TodoListWorkflow.swift
@@ -25,6 +25,7 @@ import WorkflowUI
struct TodoListWorkflow: Workflow {
// The name is an input.
var name: String
+
// Use the list of todo items passed from our parent.
var todos: [TodoModel]
@@ -97,12 +98,11 @@ extension TodoListWorkflow {
typealias Rendering = BackStackScreen<AnyScreen>.Item
func render(state: TodoListWorkflow.State, context: RenderContext<TodoListWorkflow>) -> Rendering {
- // Define a sink to be able to send the .onBack action.
+ // Define a sink to be able to send actions.
let sink = context.makeSink(of: Action.self)
- let titles = todos.map { (todoModel) -> String in
- todoModel.title
- }
+ let titles = todos.map(\.title)
+
let todoListScreen = TodoListScreen(
todoTitles: titles,
onTodoSelected: { index in
@@ -115,7 +115,7 @@ extension TodoListWorkflow {
key: "list",
screen: todoListScreen.asAnyScreen(),
barContent: .init(
- title: "Welcome \(name)",
+ title: "Welcome, \(name)",
leftItem: .button(.back(handler: {
// When the left button is tapped, send the .onBack action.
sink.send(.onBack)

MODIFY
Samples/Tutorial/Frameworks/Tutorial4Complete/Sources/Todo/TodoWorkflow.swift
Samples/Tutorial/Frameworks/Tutorial4Complete/Sources/Todo/TodoWorkflow.swift
@@ -36,9 +36,11 @@ extension TodoWorkflow {
struct State {
var todos: [TodoModel]
var step: Step
+
enum Step {
// Showing the list of todo items.
case list
+
// Editing a single item. The state holds the index so it can be updated when a save action is received.
case edit(index: Int)
}
@@ -50,7 +52,7 @@ extension TodoWorkflow {
TodoModel(
title: "Take the cat for a walk",
note: "Cats really need their outside sunshine time. Don't forget to walk Charlie. Hamilton is less excited about the prospect."
- ),
+ )
],
step: .list
)
@@ -93,7 +95,7 @@ extension TodoWorkflow {
typealias WorkflowType = TodoWorkflow
case discardChanges
- case saveChanges(index: Int, todo: TodoModel)
+ case saveChanges(todo: TodoModel, index: Int)
func apply(toState state: inout TodoWorkflow.State) -> TodoWorkflow.Output? {
guard case .edit = state.step else {
@@ -102,13 +104,14 @@ extension TodoWorkflow {
switch self {
case .discardChanges:
+ // When a discard action is received, return to the list.
state.step = .list
- case .saveChanges(index: let index, todo: let updatedTodo):
- state.todos[index] = updatedTodo
- }
- // Return to the list view for either a discard or save action.
+ case .saveChanges(todo: let todo, index: let index):
+ // When changes are saved, update the state of that `todo` item and return to the list.
+ state.todos[index] = todo
state.step = .list
+ }
return nil
}
@@ -137,10 +140,7 @@ extension TodoWorkflow {
typealias Rendering = [BackStackScreen<AnyScreen>.Item]
func render(state: TodoWorkflow.State, context: RenderContext<TodoWorkflow>) -> Rendering {
- let todoListItem = TodoListWorkflow(
- name: name,
- todos: state.todos
- )
+ let todoListItem = TodoListWorkflow(name: name, todos: state.todos)
.mapOutput { output -> ListAction in
switch output {
case .back:
@@ -157,25 +157,25 @@ extension TodoWorkflow {
switch state.step {
case .list:
- // Return only the list item.
+ // On the "list" step, return just the list screen.
return [todoListItem]
case .edit(index: let index):
-
- let todoEditItem = TodoEditWorkflow(
- initialTodo: state.todos[index])
+ // On the "edit" step, return both the list and edit screens.
+ let todoEditItem = TodoEditWorkflow(initialTodo: state.todos[index])
.mapOutput { output -> EditAction in
switch output {
case .discard:
+ // Send the discardChanges actions when the discard output is received.
return .discardChanges
- case .save(let updatedTodo):
- return .saveChanges(index: index, todo: updatedTodo)
+ case .save(let todo):
+ // Send the saveChanges action when the save output is received.
+ return .saveChanges(todo: todo, index: index)
}
}
.rendered(in: context)
- // Return both the list item and edit.
return [todoListItem, todoEditItem]
}
}

MODIFY
Samples/Tutorial/Frameworks/Tutorial4Complete/Sources/Welcome/WelcomeWorkflow.swift
Samples/Tutorial/Frameworks/Tutorial4Complete/Sources/Welcome/WelcomeWorkflow.swift
@@ -23,7 +23,7 @@ import WorkflowUI
struct WelcomeWorkflow: Workflow {
enum Output {
- case didLogin(name: String)
+ case didLogIn(name: String)
}
}
@@ -48,7 +48,7 @@ extension WelcomeWorkflow {
typealias WorkflowType = WelcomeWorkflow
case nameChanged(name: String)
- case didLogin
+ case didLogIn
func apply(toState state: inout WelcomeWorkflow.State) -> WelcomeWorkflow.Output? {
switch self {
@@ -58,9 +58,9 @@ extension WelcomeWorkflow {
// Return `nil` for the output, we want to handle this action only at the level of this workflow.
return nil
- case .didLogin:
- // Return an output of `didLogin` with the name.
- return .didLogin(name: state.name)
+ case .didLogIn:
+ // Return an output of `didLogIn` with the name.
+ return .didLogIn(name: state.name)
}
}
}
@@ -97,8 +97,8 @@ extension WelcomeWorkflow {
sink.send(.nameChanged(name: name))
},
onLoginTapped: {
- // Whenever the login button is tapped, emit the `.didLogin` action.
- sink.send(.didLogin)
+ // Whenever the login button is tapped, emit the `.didLogIn` action.
+ sink.send(.didLogIn)
}
)
}

Update Tutorial 4