Skip to content

Commit 510a776

Browse files
authored
Apply Equatable in tutorial step. (#3700)
1 parent 49f0323 commit 510a776

18 files changed

+269
-244
lines changed

Sources/ComposableArchitecture/Documentation.docc/Articles/TreeBasedNavigation.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,12 @@ struct InventoryFeature {
194194
> expands it into a fully composed feature that operates on enum state with a case for each
195195
> feature's state. You can expand the macro code in Xcode to see everything that is written for you.
196196
197+
> Tip: Since the ``Reducer()`` macro generates the `State` and `Action` types for you, if you need
198+
> to apply any protocols to those types you can do so in an extension:
199+
> ```swift
200+
> extension InventoryFeature.Destination.State: Equatable, Sendable {}
201+
> ```
202+
197203
With that done we can now hold onto a _single_ piece of optional state in our feature, using the
198204
``Presents()`` macro, and we hold onto the destination actions using the
199205
``PresentationAction`` type:
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,9 @@
1-
@Reducer
2-
struct ContactsFeature {
3-
@ObservableState
4-
struct State: Equatable {
5-
var contacts: IdentifiedArrayOf<Contact> = []
6-
// @Presents var addContact: AddContactFeature.State?
7-
// @Presents var alert: AlertState<Action.Alert>?
8-
@Presents var destination: Destination.State?
9-
}
10-
enum Action {
11-
case addButtonTapped
12-
case addContact(PresentationAction<AddContactFeature.Action>)
13-
case alert(PresentationAction<Alert>)
14-
case deleteButtonTapped(id: Contact.ID)
15-
enum Alert: Equatable {
16-
case confirmDeletion(id: Contact.ID)
17-
}
18-
}
19-
var body: some ReducerOf<Self> {
20-
Reduce { state, action in
21-
switch action {
22-
case .addButtonTapped:
23-
state.addContact = AddContactFeature.State(
24-
contact: Contact(id: UUID(), name: "")
25-
)
26-
return .none
27-
28-
case let .addContact(.presented(.delegate(.saveContact(contact)))):
29-
state.contacts.append(contact)
30-
return .none
31-
32-
case .addContact:
33-
return .none
34-
35-
case let .alert(.presented(.confirmDeletion(id: id))):
36-
state.contacts.remove(id: id)
37-
return .none
38-
39-
case .alert:
40-
return .none
41-
42-
case let .deleteButtonTapped(id: id):
43-
state.alert = AlertState {
44-
TextState("Are you sure?")
45-
} actions: {
46-
ButtonState(role: .destructive, action: .confirmDeletion(id: id)) {
47-
TextState("Delete")
48-
}
49-
}
50-
return .none
51-
}
52-
}
53-
.ifLet(\.$addContact, action: \.addContact) {
54-
AddContactFeature()
55-
}
56-
.ifLet(\.$alert, action: \.alert)
1+
extension ContactsFeature {
2+
@Reducer
3+
enum Destination {
4+
case addContact(AddContactFeature)
5+
case alert(AlertState<ContactsFeature.Action.Alert>)
576
}
587
}
8+
9+
extension ContactFeature.Destination.State: Equatable {}
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,57 @@
1-
extension ContactsFeature {
2-
@Reducer
3-
enum Destination {
4-
case addContact(AddContactFeature)
5-
case alert(AlertState<ContactsFeature.Action.Alert>)
1+
@Reducer
2+
struct ContactsFeature {
3+
@ObservableState
4+
struct State: Equatable {
5+
@Presents var addContact: AddContactFeature.State?
6+
@Presents var alert: AlertState<Action.Alert>?
7+
var contacts: IdentifiedArrayOf<Contact> = []
8+
}
9+
enum Action {
10+
case addButtonTapped
11+
case addContact(PresentationAction<AddContactFeature.Action>)
12+
case alert(PresentationAction<Alert>)
13+
case deleteButtonTapped(id: Contact.ID)
14+
enum Alert: Equatable {
15+
case confirmDeletion(id: Contact.ID)
16+
}
17+
}
18+
var body: some ReducerOf<Self> {
19+
Reduce { state, action in
20+
switch action {
21+
case .addButtonTapped:
22+
state.addContact = AddContactFeature.State(
23+
contact: Contact(id: UUID(), name: "")
24+
)
25+
return .none
26+
27+
case let .addContact(.presented(.delegate(.saveContact(contact)))):
28+
state.contacts.append(contact)
29+
return .none
30+
31+
case .addContact:
32+
return .none
33+
34+
case let .alert(.presented(.confirmDeletion(id: id))):
35+
state.contacts.remove(id: id)
36+
return .none
37+
38+
case .alert:
39+
return .none
40+
41+
case let .deleteButtonTapped(id: id):
42+
state.alert = AlertState {
43+
TextState("Are you sure?")
44+
} actions: {
45+
ButtonState(role: .destructive, action: .confirmDeletion(id: id)) {
46+
TextState("Delete")
47+
}
48+
}
49+
return .none
50+
}
51+
}
52+
.ifLet(\.$addContact, action: \.addContact) {
53+
AddContactFeature()
54+
}
55+
.ifLet(\.$alert, action: \.alert)
656
}
757
}

Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/02-MultipleDestinations/02-02-02-code-0004.swift

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,58 @@
1-
extension ContactsFeature {
2-
@Reducer
3-
enum Destination {
4-
case addContact(AddContactFeature)
5-
case alert(AlertState<ContactsFeature.Action.Alert>)
1+
@Reducer
2+
struct ContactsFeature {
3+
@ObservableState
4+
struct State: Equatable {
5+
var contacts: IdentifiedArrayOf<Contact> = []
6+
// @Presents var addContact: AddContactFeature.State?
7+
// @Presents var alert: AlertState<Action.Alert>?
8+
@Presents var destination: Destination.State?
9+
}
10+
enum Action {
11+
case addButtonTapped
12+
case addContact(PresentationAction<AddContactFeature.Action>)
13+
case alert(PresentationAction<Alert>)
14+
case deleteButtonTapped(id: Contact.ID)
15+
enum Alert: Equatable {
16+
case confirmDeletion(id: Contact.ID)
17+
}
18+
}
19+
var body: some ReducerOf<Self> {
20+
Reduce { state, action in
21+
switch action {
22+
case .addButtonTapped:
23+
state.addContact = AddContactFeature.State(
24+
contact: Contact(id: UUID(), name: "")
25+
)
26+
return .none
27+
28+
case let .addContact(.presented(.delegate(.saveContact(contact)))):
29+
state.contacts.append(contact)
30+
return .none
31+
32+
case .addContact:
33+
return .none
34+
35+
case let .alert(.presented(.confirmDeletion(id: id))):
36+
state.contacts.remove(id: id)
37+
return .none
38+
39+
case .alert:
40+
return .none
41+
42+
case let .deleteButtonTapped(id: id):
43+
state.alert = AlertState {
44+
TextState("Are you sure?")
45+
} actions: {
46+
ButtonState(role: .destructive, action: .confirmDeletion(id: id)) {
47+
TextState("Delete")
48+
}
49+
}
50+
return .none
51+
}
52+
}
53+
.ifLet(\.$addContact, action: \.addContact) {
54+
AddContactFeature()
55+
}
56+
.ifLet(\.$alert, action: \.alert)
657
}
758
}
8-
extension ContactsFeature.Destination.State: Equatable {}
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,7 @@
1-
@Reducer
2-
struct ContactsFeature {
3-
@ObservableState
4-
struct State: Equatable {
5-
var contacts: IdentifiedArrayOf<Contact> = []
6-
// @Presents var addContact: AddContactFeature.State?
7-
// @Presents var alert: AlertState<Action.Alert>?
8-
@Presents var destination: Destination.State?
9-
}
10-
enum Action {
11-
case addButtonTapped
12-
case addContact(PresentationAction<AddContactFeature.Action>)
13-
case alert(PresentationAction<Alert>)
14-
case deleteButtonTapped(id: Contact.ID)
15-
enum Alert: Equatable {
16-
case confirmDeletion(id: Contact.ID)
17-
}
18-
}
19-
var body: some ReducerOf<Self> {
20-
Reduce { state, action in
21-
switch action {
22-
case .addButtonTapped:
23-
state.addContact = AddContactFeature.State(
24-
contact: Contact(id: UUID(), name: "")
25-
)
26-
return .none
27-
28-
case let .addContact(.presented(.delegate(.saveContact(contact)))):
29-
state.contacts.append(contact)
30-
return .none
31-
32-
case .addContact:
33-
return .none
34-
35-
case let .alert(.presented(.confirmDeletion(id: id))):
36-
state.contacts.remove(id: id)
37-
return .none
38-
39-
case .alert:
40-
return .none
41-
42-
case let .deleteButtonTapped(id: id):
43-
state.alert = AlertState {
44-
TextState("Are you sure?")
45-
} actions: {
46-
ButtonState(role: .destructive, action: .confirmDeletion(id: id)) {
47-
TextState("Delete")
48-
}
49-
}
50-
return .none
51-
}
52-
}
53-
.ifLet(\.$addContact, action: \.addContact) {
54-
AddContactFeature()
55-
}
56-
.ifLet(\.$alert, action: \.alert)
1+
extension ContactsFeature {
2+
@Reducer
3+
enum Destination {
4+
case addContact(AddContactFeature)
5+
case alert(AlertState<ContactsFeature.Action.Alert>)
576
}
587
}
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,8 @@
1-
@Reducer
2-
struct ContactsFeature {
3-
@ObservableState
4-
struct State: Equatable {
5-
var contacts: IdentifiedArrayOf<Contact> = []
6-
@Presents var destination: Destination.State?
7-
}
8-
enum Action {
9-
case addButtonTapped
10-
case deleteButtonTapped(id: Contact.ID)
11-
// case addContact(PresentationAction<AddContactFeature.Action>)
12-
// case alert(PresentationAction<Alert>)
13-
case destination(PresentationAction<Destination.Action>)
14-
enum Alert: Equatable {
15-
case confirmDeletion(id: Contact.ID)
16-
}
17-
}
18-
var body: some ReducerOf<Self> {
19-
Reduce { state, action in
20-
switch action {
21-
case .addButtonTapped:
22-
state.addContact = AddContactFeature.State(
23-
contact: Contact(id: UUID(), name: "")
24-
)
25-
return .none
26-
27-
case let .addContact(.presented(.delegate(.saveContact(contact)))):
28-
state.contacts.append(contact)
29-
return .none
30-
31-
case .addContact:
32-
return .none
33-
34-
case let .alert(.presented(.confirmDeletion(id: id))):
35-
state.contacts.remove(id: id)
36-
return .none
37-
38-
case .alert:
39-
return .none
40-
41-
case let .deleteButtonTapped(id: id):
42-
state.alert = AlertState {
43-
TextState("Are you sure?")
44-
} actions: {
45-
ButtonState(role: .destructive, action: .confirmDeletion(id: id)) {
46-
TextState("Delete")
47-
}
48-
}
49-
return .none
50-
}
51-
}
52-
.ifLet(\.$addContact, action: \.addContact) {
53-
AddContactFeature()
54-
}
55-
.ifLet(\.$alert, action: \.alert)
1+
extension ContactsFeature {
2+
@Reducer
3+
enum Destination {
4+
case addContact(AddContactFeature)
5+
case alert(AlertState<ContactsFeature.Action.Alert>)
566
}
577
}
8+
extension ContactsFeature.Destination.State: Equatable {}
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
struct ContactsFeature {
33
@ObservableState
44
struct State: Equatable {
5-
@Presents var addContact: AddContactFeature.State?
6-
@Presents var alert: AlertState<Action.Alert>?
75
var contacts: IdentifiedArrayOf<Contact> = []
6+
// @Presents var addContact: AddContactFeature.State?
7+
// @Presents var alert: AlertState<Action.Alert>?
8+
@Presents var destination: Destination.State?
89
}
910
enum Action {
1011
case addButtonTapped

Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/02-MultipleDestinations/02-02-02-code-0006.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ struct ContactsFeature {
88
enum Action {
99
case addButtonTapped
1010
case deleteButtonTapped(id: Contact.ID)
11+
// case addContact(PresentationAction<AddContactFeature.Action>)
12+
// case alert(PresentationAction<Alert>)
1113
case destination(PresentationAction<Destination.Action>)
1214
enum Alert: Equatable {
1315
case confirmDeletion(id: Contact.ID)
@@ -17,10 +19,8 @@ struct ContactsFeature {
1719
Reduce { state, action in
1820
switch action {
1921
case .addButtonTapped:
20-
state.destination = .addContact(
21-
AddContactFeature.State(
22-
contact: Contact(id: UUID(), name: "")
23-
)
22+
state.addContact = AddContactFeature.State(
23+
contact: Contact(id: UUID(), name: "")
2424
)
2525
return .none
2626

Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/02-MultipleDestinations/02-02-02-code-0007.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,13 @@ struct ContactsFeature {
2424
)
2525
return .none
2626

27-
case let .destination(.presented(.addContact(.delegate(.saveContact(contact))))):
27+
case let .addContact(.presented(.delegate(.saveContact(contact)))):
2828
state.contacts.append(contact)
2929
return .none
3030

31+
case .addContact:
32+
return .none
33+
3134
case let .alert(.presented(.confirmDeletion(id: id))):
3235
state.contacts.remove(id: id)
3336
return .none

Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/02-MultipleDestinations/02-02-02-code-0008.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,13 @@ struct ContactsFeature {
2828
state.contacts.append(contact)
2929
return .none
3030

31-
case let .destination(.presented(.alert(.confirmDeletion(id: id)))):
31+
case let .alert(.presented(.confirmDeletion(id: id))):
3232
state.contacts.remove(id: id)
3333
return .none
3434

35+
case .alert:
36+
return .none
37+
3538
case let .deleteButtonTapped(id: id):
3639
state.alert = AlertState {
3740
TextState("Are you sure?")

0 commit comments

Comments
 (0)