Is the following the best way to get a List to work properly with .swipeActions? It appears to work (at least until Apple comes up with a better way to handle this) but I'm not sure that it's a sound idea.
So, I'm using a List that refers to a struct in my model and I wanted to be able to use swipeActions to delete a client (swipe left) with a confirmationDialog and to also use swipeActions to edit a client (swipe right) using a .sheet. The only way that I could get this to work so that it would delete or edit the correct "row" in the list was to use a temporary variable to store the "row" and to also have a separate view that contains my NavigationLink, .swipeActions, .sheet, etc. For reference, I used a combination of ideas from @Esera and @ScottM from post SwiftUI `swipeActions` and `confirmationDialog` delete the wrong item
I have more testing to do but this seems to work for iPhone. If anyone has a better way to do this, I would definitely be interested in hearing about it... Also, if you see any issues with the way I'm handling this or find any bugs, please let me know.
Here is the relevant code... I took out some formatting stuff for the sake of simplicity so it's not going to match the video clip exactly.
ClientList structure ->
struct ClientList: Codable, Identifiable {
@DocumentID var id: String?
var firstName: String
var lastName: String
var notes: String
var owner: String
var clientDocPath: String
}
Main ClientListView ->
struct ClientListView: View {
@ObservedObject var model: MovieModel
@State var isPresentedTrailing = false
@State var isPresentedLeading = false
@State var isPresentedAbout = false
@State var oldFavorite = false
var body: some View {
ZStack {
Color("maroon")
VStack {
Text("Client List")
Text("Swipe right to edit item... Swipe left to delete an item... ")
List($model.myClientList) { $client in
//..separate view to get swipeActions to work right
ClientNavView(model: model, client: $client)
}
}
.listStyle(.plain)
.sheet(isPresented: $isPresentedTrailing, onDismiss: {
//
}, content: {
AddClient(model: model, count: model.myClientList.count)
})
.sheet(isPresented: $isPresentedAbout, onDismiss: {
//
}, content: {
SupportView()
})
}
.accentColor(.black)
.navigationBarTitle(Text("Clients"), displayMode: .inline)
.navigationBarItems(
leading: AboutLogoutOptions(model: model, isPresentedLeading: $isPresentedLeading, isPresentedAbout: $isPresentedAbout),
trailing: Button(action: { self.isPresentedTrailing.toggle() }) {
Text("Add")
}
.buttonStyle(.bordered)
.tint(Color("ocean"))
)
.onAppear {
model.fetchClients()
}
.navigationViewStyle(.stack)
}
Separate ClientNavView (referenced inside of List in ClientListView) ->
struct ClientNavView: View {
@ObservedObject var model: MovieModel
@Binding var client: ClientList
@State var oldFavorite = false
@State var editToggle = false
@State var deleteToggle = false
@State var tempClientToDelete: ClientList? = nil
@State var tempClientToEdit: ClientList? = nil
var body: some View {
NavigationLink {
ContentView2(model: model, clientDocPath: client.clientDocPath, clientFirstName: client.firstName, clientLastName: client.lastName)
} label: {
ClientListRowView(model: model, client: $client)
}
.swipeActions(edge: .trailing) {
Button {
print("client to delete = \(client.firstName)\(client.lastName)")
tempClientToDelete = client
deleteToggle = true
} label: {
Image(systemName: "trash.fill")
}.tint(.red)
}
.confirmationDialog("Delete???", isPresented: $deleteToggle){
Button("Delete", role: .destructive){
if let deleteClient = tempClientToDelete {
print("Actually deleting: \(deleteClient)")
deleteToggle = false
tempClientToDelete = nil
model.deleteClient(clientDocPath: deleteClient.clientDocPath, clientToDelete: deleteClient)
}
}
Button("Cancel", role: .cancel){}
}message: {
Text("""
Are you sure you want to delete this client? Deleting this client will delete ALL other data including Contacts and Items. This action CANNOT be undone.
"""
)
}
.swipeActions(edge: .leading) {
Button {
print("client to edit = \(client.firstName)\(client.lastName)")
tempClientToEdit = client
editToggle = true
} label: {
Image(systemName: "pencil")
}.tint(.cyan)
}
.sheet(isPresented: $editToggle, onDismiss: {
editToggle = false
tempClientToEdit = nil
}, content: {
if let editClient = tempClientToEdit {
EditClient(model: model, client: editClient)
}
})
.onAppear{
tempClientToEdit = client
}
}
"Row" - ClientListRowView (referenced in ClientNavView) ->
struct ClientListRowView: View {
@ObservedObject var model: MovieModel
@State var editToggle = false
@Binding var client: ClientList
var body: some View {
VStack(alignment: .leading, spacing: 10){
HStack {
Text("\(client.firstName )")
Text("\(client.lastName)")
Spacer()
}
Text("\(client.notes)")
.italic()
.font(Font.system(.body))
.foregroundColor(.gray)
.padding(.top, 2)
.padding(.leading, 80)
Spacer()
}
.padding(.leading, 2)
.foregroundColor(.indigo)
.font(Font.custom("ChalkboardSE-Bold", size: 18))
}
}