Home > Blockchain >  SwiftUI: EditButton says "Done" after swipe to delete action
SwiftUI: EditButton says "Done" after swipe to delete action

Time:04-29

Why does the EditButton says "Done" (instead of "Edit") after I delete one scrum using "swipe to delete"?

I tried changing editMode to .inactive inside onDelete, but even this didn't work.

Why is this not working, and can I fix it somehow? Is it some new bug?

struct ScrumsView: View {
    @Binding var scrums: [DailyScrum]
    @Environment(\.scenePhase) private var scenePhase
    @State private var isPresentingNewScrumView = false
    @State private var newScrumData = DailyScrum.Data()
    let saveAction: ()->Void
    
    var body: some View {
        List {
            ForEach($scrums) { $scrum in
                NavigationLink(destination: DetailView(scrum: $scrum)) {
                    CardView(scrum: scrum)
                }
                .listRowBackground(scrum.theme.mainColor)
            }
            .onDelete { indexSet in
                scrums.remove(atOffsets: indexSet)
            }
        }
        .navigationTitle("Daily Scrums")
        .toolbar {
            ToolbarItemGroup(placement: .navigationBarLeading) {
                EditButton()
            }
            ToolbarItemGroup(placement: .navigationBarTrailing) {
                Button {
                    isPresentingNewScrumView = true
                } label: {
                    Image(systemName: "plus")
                }
                .accessibilityLabel("New scrum")
            }
        }
        .sheet(isPresented: $isPresentingNewScrumView) {
            NavigationView {
                DetailEditView(data: $newScrumData)
                    //.navigationTitle(Text("New Scrum"))
                    .toolbar {
                        ToolbarItemGroup(placement: .cancellationAction) {
                            Button("Dismiss") {
                                isPresentingNewScrumView = false
                                newScrumData = DailyScrum.Data()
                            }
                        }
                        ToolbarItemGroup(placement: .confirmationAction) {
                            Button("Add") {
                                let newScrum = DailyScrum(data: newScrumData)
                                scrums.append(newScrum)
                                isPresentingNewScrumView = false
                                newScrumData = DailyScrum.Data()
                            }
                        }
                    }
            }
        }
        .onChange(of: scenePhase) { phase in
            if phase == .inactive { saveAction() }
        }
    }
}

CodePudding user response:

It seems EditButton is incompatible with this new way of using @StateObject to declare the store object. I had the idea to try reverting to the old way of creating the store object and surprisingly it fixed the issue. Change the ScrumStore to this

class ScrumStore: ObservableObject {
    @Published var scrums: [DailyScrum] = []
    
    static var shared = ScrumStore()

And change the ScrumdingerApp to this:

struct ScrumdingerApp: App {
    private var store = ScrumStore.shared
    
    var body: some Scene {
        WindowGroup {
            NavigationView {
                ScrumsView(store: store) {

And ScrumsView to this:

struct ScrumsView: View {
    //@Binding var scrums: [DailyScrum]
    @ObservedObject var store: ScrumStore

...

var body: some View {
    List {
        ForEach($store.scrums) { $scrum in

And change the other scrums to store.scrums too.

This makes the edit button work properly for swipe to delete

I would also improve the code by making the store object be an Environment object, e.g.

struct ScrumdingerApp: App {
    private var store = ScrumStore.shared
    
    var body: some Scene {
        WindowGroup {
            ContentView()
            .environmentObject(store)
        }
}

struct ContentView: View {
    @EnvironmentObject var store: ScrumStore
   
...

I would also improve how the model structs are loaded and saved, e.g. I would load it in the object's init and have a function to save it. The function could be called on a scene phase or after the model is mutated. Before doing too much loading and saving you might want to try FileDocument which does all that for you and gives you iCloud drive support for free. I recommend the document app WWDC videos to learn that, there is a new one every year.

  • Related