Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make enum reducer state equatable in tutorial. #2873

Merged
merged 1 commit into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extension ContactsFeature {
@Reducer
enum Destination {
case addContact(AddContactFeature)
case alert(AlertState<ContactsFeature.Action.Alert>)
}
}
Original file line number Diff line number Diff line change
@@ -1,57 +1,7 @@
@Reducer
struct ContactsFeature {
@ObservableState
struct State: Equatable {
var contacts: IdentifiedArrayOf<Contact> = []
@Presents var destination: Destination.State?
}
enum Action {
case addButtonTapped
case deleteButtonTapped(id: Contact.ID)
// case addContact(PresentationAction<AddContactFeature.Action>)
// case alert(PresentationAction<Alert>)
case destination(PresentationAction<Destination.Action>)
enum Alert: Equatable {
case confirmDeletion(id: Contact.ID)
}
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .addButtonTapped:
state.addContact = AddContactFeature.State(
contact: Contact(id: UUID(), name: "")
)
return .none

case let .addContact(.presented(.delegate(.saveContact(contact)))):
state.contacts.append(contact)
return .none

case .addContact:
return .none

case let .alert(.presented(.confirmDeletion(id: id))):
state.contacts.remove(id: id)
return .none

case .alert:
return .none

case let .deleteButtonTapped(id: id):
state.alert = AlertState {
TextState("Are you sure?")
} actions: {
ButtonState(role: .destructive, action: .confirmDeletion(id: id)) {
TextState("Delete")
}
}
return .none
}
}
.ifLet(\.$addContact, action: \.addContact) {
AddContactFeature()
}
.ifLet(\.$alert, action: \.alert)
extension ContactsFeature {
@Reducer(state: .equatable)
enum Destination {
case addContact(AddContactFeature)
case alert(AlertState<ContactsFeature.Action.Alert>)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
@Reducer
struct ContactsFeature {
@ObservableState
struct State: Equatable {
var contacts: IdentifiedArrayOf<Contact> = []
// @Presents var addContact: AddContactFeature.State?
// @Presents var alert: AlertState<Action.Alert>?
@Presents var destination: Destination.State?
}
enum Action {
case addButtonTapped
case addContact(PresentationAction<AddContactFeature.Action>)
case alert(PresentationAction<Alert>)
case deleteButtonTapped(id: Contact.ID)
enum Alert: Equatable {
case confirmDeletion(id: Contact.ID)
}
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .addButtonTapped:
state.addContact = AddContactFeature.State(
contact: Contact(id: UUID(), name: "")
)
return .none

case let .addContact(.presented(.delegate(.saveContact(contact)))):
state.contacts.append(contact)
return .none

case .addContact:
return .none

case let .alert(.presented(.confirmDeletion(id: id))):
state.contacts.remove(id: id)
return .none

case .alert:
return .none

case let .deleteButtonTapped(id: id):
state.alert = AlertState {
TextState("Are you sure?")
} actions: {
ButtonState(role: .destructive, action: .confirmDeletion(id: id)) {
TextState("Delete")
}
}
return .none
}
}
.ifLet(\.$addContact, action: \.addContact) {
AddContactFeature()
}
.ifLet(\.$alert, action: \.alert)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ struct ContactsFeature {
enum Action {
case addButtonTapped
case deleteButtonTapped(id: Contact.ID)
// case addContact(PresentationAction<AddContactFeature.Action>)
// case alert(PresentationAction<Alert>)
case destination(PresentationAction<Destination.Action>)
enum Alert: Equatable {
case confirmDeletion(id: Contact.ID)
Expand All @@ -17,10 +19,8 @@ struct ContactsFeature {
Reduce { state, action in
switch action {
case .addButtonTapped:
state.destination = .addContact(
AddContactFeature.State(
contact: Contact(id: UUID(), name: "")
)
state.addContact = AddContactFeature.State(
contact: Contact(id: UUID(), name: "")
)
return .none

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@ struct ContactsFeature {
)
return .none

case let .destination(.presented(.addContact(.delegate(.saveContact(contact))))):
case let .addContact(.presented(.delegate(.saveContact(contact)))):
state.contacts.append(contact)
return .none

case .addContact:
return .none

case let .alert(.presented(.confirmDeletion(id: id))):
state.contacts.remove(id: id)
return .none
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,13 @@ struct ContactsFeature {
state.contacts.append(contact)
return .none

case let .destination(.presented(.alert(.confirmDeletion(id: id)))):
case let .alert(.presented(.confirmDeletion(id: id))):
state.contacts.remove(id: id)
return .none

case .alert:
return .none

case let .deleteButtonTapped(id: id):
state.alert = AlertState {
TextState("Are you sure?")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ struct ContactsFeature {
state.contacts.remove(id: id)
return .none

case .destination:
return .none

case let .deleteButtonTapped(id: id):
state.alert = AlertState {
TextState("Are you sure?")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,13 @@ struct ContactsFeature {
return .none

case let .deleteButtonTapped(id: id):
state.destination = .alert(
AlertState {
TextState("Are you sure?")
} actions: {
ButtonState(role: .destructive, action: .confirmDeletion(id: id)) {
TextState("Delete")
}
state.alert = AlertState {
TextState("Are you sure?")
} actions: {
ButtonState(role: .destructive, action: .confirmDeletion(id: id)) {
TextState("Delete")
}
)
}
return .none
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ struct ContactsFeature {
return .none
}
}
.ifLet(\.$destination, action: \.destination)
.ifLet(\.$addContact, action: \.addContact) {
AddContactFeature()
}
.ifLet(\.$alert, action: \.alert)
}
}
Original file line number Diff line number Diff line change
@@ -1,40 +1,53 @@
struct ContactsView: View {
@Bindable var store: StoreOf<ContactsFeature>

var body: some View {
NavigationStack {
List {
ForEach(store.contacts) { contact in
HStack {
Text(contact.name)
Spacer()
Button {
store.send(.deleteButtonTapped(id: contact.id))
} label: {
Image(systemName: "trash")
.foregroundColor(.red)
@Reducer
struct ContactsFeature {
@ObservableState
struct State: Equatable {
var contacts: IdentifiedArrayOf<Contact> = []
@Presents var destination: Destination.State?
}
enum Action {
case addButtonTapped
case deleteButtonTapped(id: Contact.ID)
case destination(PresentationAction<Destination.Action>)
enum Alert: Equatable {
case confirmDeletion(id: Contact.ID)
}
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .addButtonTapped:
state.destination = .addContact(
AddContactFeature.State(
contact: Contact(id: UUID(), name: "")
)
)
return .none

case let .destination(.presented(.addContact(.delegate(.saveContact(contact))))):
state.contacts.append(contact)
return .none

case let .destination(.presented(.alert(.confirmDeletion(id: id)))):
state.contacts.remove(id: id)
return .none

case .destination:
return .none

case let .deleteButtonTapped(id: id):
state.destination = .alert(
AlertState {
TextState("Are you sure?")
} actions: {
ButtonState(role: .destructive, action: .confirmDeletion(id: id)) {
TextState("Delete")
}
}
}
}
.navigationTitle("Contacts")
.toolbar {
ToolbarItem {
Button {
store.send(.addButtonTapped)
} label: {
Image(systemName: "plus")
}
}
}
}
.sheet(
item: $store.scope(state: \.destination?.addContact, action: \.destination.addContact)
) { addContactStore in
NavigationStack {
AddContactView(store: addContactStore)
)
return .none
}
}
.alert($store.scope(state: \.alert, action: \.alert))
.ifLet(\.$destination, action: \.destination)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ struct ContactsView: View {
AddContactView(store: addContactStore)
}
}
.alert($store.scope(state: \.destination?.alert, action: \.destination.alert))
.alert($store.scope(state: \.alert, action: \.alert))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
struct ContactsView: View {
@Bindable var store: StoreOf<ContactsFeature>

var body: some View {
NavigationStack {
List {
ForEach(store.contacts) { contact in
HStack {
Text(contact.name)
Spacer()
Button {
store.send(.deleteButtonTapped(id: contact.id))
} label: {
Image(systemName: "trash")
.foregroundColor(.red)
}
}
}
}
.navigationTitle("Contacts")
.toolbar {
ToolbarItem {
Button {
store.send(.addButtonTapped)
} label: {
Image(systemName: "plus")
}
}
}
}
.sheet(
item: $store.scope(state: \.destination?.addContact, action: \.destination.addContact)
) { addContactStore in
NavigationStack {
AddContactView(store: addContactStore)
}
}
.alert($store.scope(state: \.destination?.alert, action: \.destination.alert))
}
}
Loading