mirror of
https://github.com/pointfreeco/swift-composable-architecture.git
synced 2025-12-14 20:35:56 +01:00
Meet The Composable Architecture tutorial various fixes and improvements (#3568)
* Fix tutorial documentation typo: sync ups to contacts * Update tutorial documentation: Use .foregroundStyle for icon color to replace deprecated .foregroundColor * Update tutorial documentation: Clarify that Reducer() is a macro * Update tutorial documentation: Modify test code to use `.modify` for enum mutation to fix issue reported in https://github.com/pointfreeco/swift-composable-architecture/discussions/3158 * Update tutorial documentation: Add @CasePathable to Alert enum and simplify test case syntax * Add @CasePathable to Alert enum in tutorial documentation to be consistent with previous part of the tutorial * Update tutorial documentation: Simplify StackAction with StackActionOf typealias * Update Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/04-NavigationStacks/02-04-NavigationStacks.tutorial --------- Co-authored-by: Stephen Celis <stephen.celis@gmail.com>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@
|
||||
/*.swiftinterface
|
||||
/*.xcodeproj
|
||||
xcuserdata/
|
||||
.docc-build/
|
||||
@@ -258,7 +258,7 @@
|
||||
|
||||
> Important: Delegate actions are the most general way of communicating from the child domain
|
||||
back to the parent, but there are other techniques. We could have also utilized the
|
||||
`@Shared` property wrapper for the collection of sync ups, which would allow the
|
||||
`@Shared` property wrapper for the collection of contacts, which would allow the
|
||||
`AddContactFeature` to insert a new contact directly into the parent collection without any
|
||||
further steps. This can be powerful, but we will use delegate actions for this tutorial. To
|
||||
read more about `@Shared` see the <doc:SharingState> article, and see the
|
||||
|
||||
@@ -12,7 +12,7 @@ struct ContactsView: View {
|
||||
store.send(.deleteButtonTapped(id: contact.id))
|
||||
} label: {
|
||||
Image(systemName: "trash")
|
||||
.foregroundColor(.red)
|
||||
.foregroundStyle(.red)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
@Step {
|
||||
Add a case for for the "Add contact" feature. Note that we are holding onto the actual
|
||||
`AddContactFeature` reducer in the case, not the state. The
|
||||
``ComposableArchitecture/Reducer()`` will fill in all the requirements for the reducer
|
||||
``ComposableArchitecture/Reducer()`` macro will fill in all the requirements for the reducer
|
||||
protocol for us automatically.
|
||||
|
||||
@Code(name: "ContactsFeatures.swift", file: 02-02-02-code-0001.swift)
|
||||
|
||||
@@ -22,7 +22,7 @@ struct ContactsFeatureTests {
|
||||
)
|
||||
}
|
||||
await store.send(\.destination.addContact.setName, "Blob Jr.") {
|
||||
$0.destination?.addContact?.contact.name = "Blob Jr."
|
||||
$0.destination?.modify(\.addContact) { $0.contact.name = "Blob Jr." }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ struct ContactsFeatureTests {
|
||||
)
|
||||
}
|
||||
await store.send(\.destination.addContact.setName, "Blob Jr.") {
|
||||
$0.destination?.addContact?.contact.name = "Blob Jr."
|
||||
$0.destination?.modify(\.addContact) { $0.contact.name = "Blob Jr." }
|
||||
}
|
||||
await store.send(\.destination.addContact.saveButtonTapped)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ struct ContactsFeatureTests {
|
||||
)
|
||||
}
|
||||
await store.send(\.destination.addContact.setName, "Blob Jr.") {
|
||||
$0.destination?.addContact?.contact.name = "Blob Jr."
|
||||
$0.destination?.modify(\.addContact) { $0.contact.name = "Blob Jr." }
|
||||
}
|
||||
await store.send(\.destination.addContact.saveButtonTapped)
|
||||
await store.receive(
|
||||
|
||||
@@ -22,7 +22,7 @@ struct ContactsFeatureTests {
|
||||
)
|
||||
}
|
||||
await store.send(\.destination.addContact.setName, "Blob Jr.") {
|
||||
$0.destination?.addContact?.contact.name = "Blob Jr."
|
||||
$0.destination?.modify(\.addContact) { $0.contact.name = "Blob Jr." }
|
||||
}
|
||||
await store.send(\.destination.addContact.saveButtonTapped)
|
||||
await store.receive(
|
||||
|
||||
@@ -22,7 +22,7 @@ struct ContactsFeatureTests {
|
||||
)
|
||||
}
|
||||
await store.send(\.destination.addContact.setName, "Blob Jr.") {
|
||||
$0.destination?.addContact?.contact.name = "Blob Jr."
|
||||
$0.destination?.modify(\.addContact) { $0.contact.name = "Blob Jr." }
|
||||
}
|
||||
await store.send(\.destination.addContact.saveButtonTapped)
|
||||
await store.receive(
|
||||
|
||||
@@ -22,7 +22,7 @@ struct ContactsFeatureTests {
|
||||
)
|
||||
}
|
||||
await store.send(\.destination.addContact.setName, "Blob Jr.") {
|
||||
$0.destination?.addContact?.contact.name = "Blob Jr."
|
||||
$0.destination?.modify(\.addContact) { $0.contact.name = "Blob Jr." }
|
||||
}
|
||||
await store.send(\.destination.addContact.saveButtonTapped)
|
||||
await store.receive(
|
||||
|
||||
@@ -9,6 +9,7 @@ struct ContactsFeature {
|
||||
case addButtonTapped
|
||||
case deleteButtonTapped(id: Contact.ID)
|
||||
case destination(PresentationAction<Destination.Action>)
|
||||
@CasePathable
|
||||
enum Alert: Equatable {
|
||||
case confirmDeletion(id: Contact.ID)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ struct ContactsFeatureTests {
|
||||
await store.send(.deleteButtonTapped(id: UUID(1))) {
|
||||
$0.destination = .alert(.deleteConfirmation(id: UUID(1)))
|
||||
}
|
||||
await store.send(.destination(.presented(.alert(.confirmDeletion(id: UUID(1)))))) {
|
||||
await store.send(\.destination.alert.confirmDeletion, UUID(1)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,10 @@ struct ContactsFeatureTests {
|
||||
await store.send(.deleteButtonTapped(id: UUID(1))) {
|
||||
$0.destination = .alert(.deleteConfirmation(id: UUID(1)))
|
||||
}
|
||||
await store.send(.destination(.presented(.alert(.confirmDeletion(id: UUID(1)))))) {
|
||||
$0.contacts.remove(id: UUID(1))
|
||||
await store.send(\.destination.alert.confirmDeletion, UUID(1)) {
|
||||
$0.contacts = [
|
||||
Contact(id: UUID(0), name: "Blob")
|
||||
]
|
||||
$0.destination = nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,9 +116,9 @@
|
||||
To do this we can chain into the `addContact` case name directly and mutate a part of its
|
||||
associated value.
|
||||
|
||||
> Tip: To chain into an enum and mutate an associated value, the enum must be annotated with
|
||||
> `@CasePathable` _and_ `@dynamicMemberLookup`. The `@Reducer` macro automatically applies
|
||||
> these annotations to enum-based `State`, but you must manually apply it to other enums.
|
||||
> Tip: To use the `modify` helper on an enum to mutate an associated value, the enum must
|
||||
> be annotated with `@CasePathable`. The `@Reducer` macro automatically applies
|
||||
> this annotation to enum-based `State`, but you must manually apply it to other enums.
|
||||
|
||||
@Code(name: "ContactsFeatureTests.swift", file: 02-03-01-code-0011.swift)
|
||||
}
|
||||
@@ -146,7 +146,7 @@
|
||||
}
|
||||
|
||||
@Step {
|
||||
To further assert that when the `saveContact` delegate action was received, you must
|
||||
To further assert that the `saveContact` delegate action was received, you must
|
||||
annotate `AddContactFeature.Action.Delegate` with the `@CasePathable` macro.
|
||||
|
||||
@Code(name: "ContactsFeature.swift", file: 02-03-01-code-0015.swift, previousFile: 02-03-01-code-0015-previous.swift)
|
||||
@@ -308,6 +308,9 @@
|
||||
@Step {
|
||||
Make use of the new `deleteConfirmation` static alert function in the `ContactsFeature`
|
||||
reducer, rather than building `AlertState` from scratch.
|
||||
|
||||
Also to further assert that the `confirmDeletion` action was received,
|
||||
annotate `ContactsFeature.Action.Alert` with the `@CasePathable` macro.
|
||||
|
||||
@Code(name: "ContactsFeature.swift", file: 02-03-03-code-0007.swift, previousFile: 02-03-03-code-0007-previous.swift)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ struct ContactsFeature {
|
||||
case addButtonTapped
|
||||
case deleteButtonTapped(id: Contact.ID)
|
||||
case destination(PresentationAction<Destination.Action>)
|
||||
@CasePathable
|
||||
enum Alert: Equatable {
|
||||
case confirmDeletion(id: Contact.ID)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ struct ContactsFeature {
|
||||
case addButtonTapped
|
||||
case deleteButtonTapped(id: Contact.ID)
|
||||
case destination(PresentationAction<Destination.Action>)
|
||||
@CasePathable
|
||||
enum Alert: Equatable {
|
||||
case confirmDeletion(id: Contact.ID)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ struct ContactsFeature {
|
||||
case addButtonTapped
|
||||
case deleteButtonTapped(id: Contact.ID)
|
||||
case destination(PresentationAction<Destination.Action>)
|
||||
case path(StackAction<ContactDetailFeature.State, ContactDetailFeature.Action>)
|
||||
case path(StackActionOf<ContactDetailFeature>)
|
||||
@CasePathable
|
||||
enum Alert: Equatable {
|
||||
case confirmDeletion(id: Contact.ID)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ struct ContactsFeature {
|
||||
case addButtonTapped
|
||||
case deleteButtonTapped(id: Contact.ID)
|
||||
case destination(PresentationAction<Destination.Action>)
|
||||
case path(StackAction<ContactDetailFeature.State, ContactDetailFeature.Action>)
|
||||
case path(StackActionOf<ContactDetailFeature>)
|
||||
@CasePathable
|
||||
enum Alert: Equatable {
|
||||
case confirmDeletion(id: Contact.ID)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ struct ContactsFeature {
|
||||
case addButtonTapped
|
||||
case deleteButtonTapped(id: Contact.ID)
|
||||
case destination(PresentationAction<Destination.Action>)
|
||||
case path(StackAction<ContactDetailFeature.State, ContactDetailFeature.Action>)
|
||||
case path(StackActionOf<ContactDetailFeature>)
|
||||
@CasePathable
|
||||
enum Alert: Equatable {
|
||||
case confirmDeletion(id: Contact.ID)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ struct ContactsFeature {
|
||||
case addButtonTapped
|
||||
case deleteButtonTapped(id: Contact.ID)
|
||||
case destination(PresentationAction<Destination.Action>)
|
||||
case path(StackAction<ContactDetailFeature.State, ContactDetailFeature.Action>)
|
||||
case path(StackActionOf<ContactDetailFeature>)
|
||||
@CasePathable
|
||||
enum Alert: Equatable {
|
||||
case confirmDeletion(id: Contact.ID)
|
||||
}
|
||||
|
||||
@@ -101,6 +101,9 @@
|
||||
This represents the actions that can happen inside the stack, such as pushing or popping
|
||||
an element off the stack, or an action happening inside a particular feature inside the
|
||||
stack.
|
||||
|
||||
> Tip: ``StackAction`` is generic over both state and action of the `Path` domain, and so
|
||||
> you can use the ``StackActionOf`` type alias to simplify the syntax a bit.
|
||||
|
||||
We will also handle the `.path` case in the reducer and return
|
||||
``ComposableArchitecture/Effect/none`` for now.
|
||||
|
||||
Reference in New Issue
Block a user