import SwiftUI
struct MemoListView: View {
let folder : FolderModel
@State private var showActionSheet : Bool = false
@EnvironmentObject var vm : FolderListViewModel
var body: some View {
ZStack {
if folder.memo.count == 0 {
NoMemoView()
} else {
List {
ForEach(folder.memo) { memo in
MemoRowView(memo: memo, folder: self.folder)
.onLongPressGesture {
self.showActionSheet.toggle()
}
.confirmationDialog(Text("Option"), isPresented: $showActionSheet) {
Button(role : .destructive, action: {
vm.deleteMemo(folder: folder, memo: memo)
}, label: {
Text("Delete")
.foregroundColor(.red)
})
}
}
.listRowSeparator(.hidden)
}
.listStyle(.plain)
}
}
.navigationTitle("Memos in '\(folder.folderName)'")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
HStack {
NavigationLink(destination: {
NewMemoView(folder: self.folder)
}, label: {
Image(systemName: "plus")
})
NavigationLink(destination: {
}, label: {
Image(systemName: "gear")
})
}
}
}
}
}
Hi! Please check my code above. I want to apply actionSheet(confirmationDialog) to each of row in list but I think the list can't recognize which row is selected.
If I tried to delete row3, it just delete only row1
I don't know how I can handle this situation.
Thanks!
CodePudding user response:
As per your comments to the original post, .confirmationDialog
only has an isPresented
binding available, rather than an object-based one as with sheet
, fullScreenCover
, etc.
One workaround I've used quite successfully is to move the confirmationDialog, and the boolean state flag that drives it, into a child view. This could be MemoRowView
itself, or you could keep that view as the presentation component only and wrap it in an interactive view that called MemoRowView
and added the interactive elements, e.g.
// MemoListView
List {
ForEach(folder.memo) { memo in
MemoListItem(memo: memo, folder: self.folder)
}
.listStyle(.plain)
This does mean injecting quite a lot of domain knowledge into the list item, so it'd need its own @EnvironmentObject reference, etc., but that could be lived with.
Alternatively, you could keep the code that deletes the object in the parent view, and just keep the confirmation in the child view:
struct MemoListItem: View {
var memo: MemoModel
var folder: FolderModel
var onDelete: () -> Void
@State private var showDeleteConfirmation: Bool = false
init(memo: MemoModel, folder: FolderModel, onDelete: @escaping () -> Void) {
self.memo = memo
self.folder = folder
self.onDelete = onDelete
}
var body: some View {
// rest of row setup omitted for brevity
.confirmationDialog(Text("Option"), isPresented: $showDeleteConfirmation) {
Button("Delete", role: .destructive, action: onDelete)
}
}
}
// MemoListView
List {
ForEach(folder.memo) { memo in
MemoListItem(memo: memo, folder: self.folder, onDelete: {
vm.deleteMemo(folder: folder, memo: memo)
})
}
}
CodePudding user response:
An explanation of what I wrote in my comment :
struct MemoListView: View {
@EnvironmentObject var vm : FolderListViewModel
// Updated folder so as it seems it is extracted from your
// view model
var folder : FolderModel {
vm.folder
}
@State private var showActionSheet : Bool = false
// This is the way to know which memo to delete
@State var memoToDelete: Memo?
var body: some View {
ZStack {
if folder.memo.count == 0 {
NoMemoView()
} else {
List {
ForEach(folder.memo) { memo in
MemoRowView(memo: memo, folder: self.folder)
.onLongPressGesture {
// Save the memo on the current row
memoToDelete = memo
self.showActionSheet.toggle()
}
.confirmationDialog(Text("Option"), isPresented: $showActionSheet) {
Button(role : .destructive, action: {
// Delete the saved memo
if let memo = memoToDelete {
vm.deleteMemo(folder: folder, memo: memo)
}
}, label: {
// Here to show the memo id before delete
if let memo = memoToDelete {
Text("Delete \(memo.id)")
.foregroundColor(.red)
}
})
}
}
.listRowSeparator(.hidden)
}
.listStyle(.plain)
}
}
.navigationTitle("Memos in '\(folder.folderName)'")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
HStack {
NavigationLink(destination: {
NewMemoView(folder: self.folder)
}, label: {
Image(systemName: "plus")
})
NavigationLink(destination: {
}, label: {
Image(systemName: "gear")
})
}
}
}
}
}
Note : I changed from the comment and kept the dialog on each row. It is not the best way to do it.