Swift 2.0 .contextMenu Multiple Delete From Core Data

Viewed 385

First time post in here and new to coding... so I hope I am following proper protocol. I am putting together a view in Xcode 12.2 (SwiftUI 2) that outputs a list of data from Core Data and have a context menu to provide the user the option to edit, delete, and delete multiple. The context menu is working properly for edit and delete, however, I am facing a road block in how to implement the functionality to delete multiple list items. I am imagining the user would hard press one of the list items, the context menus pops open and if they press the "Delete Multiple" option, the view activates something similar to an edit mode that populates little circle on the left of each item which the user can select and delete more than one item at a time. I can see other article on how to do this, however, I cannot find guidance on how to implement this through Core Data. I have pasted my code below.

Please let me know if I am missing any other information that would make my question more clear.

I really appreciate the forums expertise and guidance.

Struct List : View    {
    
    @StateObject var appData = AppViewModel()
    @Environment(\.managedObjectContext) var context
       
    //Fetch Data...
    @FetchRequest(entity: EntryData.entity(), sortDescriptors: [NSSortDescriptor(key: "date", ascending: false)], animation: .spring()) var results : FetchedResults<EntryData>
    
    var body : some View {
        ZStack(alignment: Alignment(horizontal: .trailing, vertical: .bottom), content: {
            VStack{
                ScrollView(.vertical, showsIndicators: false, content: {
                    LazyVStack(alignment: .leading, spacing: 20){
                        ForEach(results){task in
                            VStack(alignment: .leading, spacing: 5, content: {
                                Text(task.category ?? "")
                                    .font(.title)
                                    .fontWeight(.bold)
                                Text(task.date ?? Date(), style:. date)
                                    .fontWeight(.bold)
                                Text("\(task.number.formattedCurrencyText)")
                                
                            })
                            .padding(.horizontal, 14)
                            .padding(.top, 10)
                            .foregroundColor(Color("ColorTextList"))
                            
                            .contextMenu{
                                Button(action: {appData.editItem(item: task)}, label: {
                                    Text("Edit")
                                })
                                Button(action: {
                                    context.delete(task)
                                    try! context.save()
                                }, label: {
                                    Text("Delete")
                                })
                                Button(action: {}, label: {
                                    Text("Delete Mutiple")
                                })
                            }
                        }
                        
                    }
                })
                
            }
            VStack(){
                VisualEffectView(effect: UIBlurEffect(style: .regular))
                    .frame(width: UIScreen.main.bounds.width, height: 50, alignment: .top)
                    .edgesIgnoringSafeArea(.all)
                    .background(Color.clear)
                Spacer()
            }
        })
        .background(Color.clear)
        .sheet(isPresented: $appData.isNewData, content: {
            AddDataView(appData: appData)
                .environment(\.managedObjectContext, self.context)
        })
        
    }
}

Adding the viewModel of the app. How do I tap into into this and delete each of the attributes in a multi-list selection?

import SwiftUI
import CoreData

class AppViewModel : ObservableObject, Identifiable{
    
    @Published var cateogry = ""
    @Published var date = Date()
    @Published var number : Double? = nil
    @Published var notes = ""
    @Published var id = UUID()
}

And adding the actual Core Data model screenshot.

enter image description here

1 Answers

You can implement a Selection Set for your List. This will contain all elements that are selected. Then you can dynamically show the contextMenu for delete or deleteAll based on the count of the set. Here is a full example with the implementation of deleteAll

struct SelectionDemo : View {
    @State var demoData = ["Dave", "Tom", "Phillip", "Steve"]
    @State var selected = Set<String>()

    var body: some View {

        HStack {
            List(demoData, id: \.self, selection: $selected){ name in
                Text(name)
                    .contextMenu {
                        Button(action: {
                            //Delete only one item
                        }){
                            Text("Delete")
                        }
                        if (selected.count > 1) {
                            Button(action: {
                                //Delete all
                                deleteAll()
                            })
                            {
                                Text("Delete all")
                            }
                        }
                    }
            }.frame(width: 500, height: 460)
        }
    }
    
    func deleteAll() {
        for element in selected {
            self.demoData.removeAll(where: {
                $0 == element
            })
        }
    }
}
Related