0

SwiftUI .confirmationDialog on List/ListRow is working fine on iOS 15. I am using code like this example code:

struct ContentView: View {
    @StateObject var viewModel = ViewModel()

    var body: some View {
        
        NavigationView {
            List(viewModel.messages) { message in
                ListRow(message: message) { message in
                    withAnimation {
                        viewModel.delete(message)
                    }
                }
            }
            .navigationTitle("Messages")
            .onAppear { viewModel.fetch() }
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
}

struct ListRow: View {
    @State private var showConfirmation: Bool = false
    var message: Message
    var delete: (Message) -> Void
        
    var body: some View {
        
        Text(message.text)
        
            .swipeActions {
                Button( role: .destructive, action: { showConfirmation = true },
                        label: { Label("Delete", systemImage: "trash") })
            }
        
            .confirmationDialog(
                "Are you sure?",
                isPresented: $showConfirmation,
                titleVisibility: .visible,
                actions: { Button("Delete", role: .destructive) { withAnimation { delete(message) }}},
                message: { Text("You cannot undo deleting message \"\(message.text)\"") }
            )
    }
}

class ViewModel: ObservableObject {
    @Published var messages: [Message] = []
    
    func fetch() {
        messages = [Message(text: "Hello"),
                    Message(text: "How are you?"),
                    Message(text: "Do you have any plans?"),
                    Message(text: "Sailing?"),
                    Message(text: "Or Fishing?")]
    }
    
    func delete(_ message: Message?) {
        guard let message = message else { print("ERROR: no message to delete!"); return }
        messages.removeAll { $0.id == message.id }
    }
}

struct Message: Identifiable, Hashable {
    var text: String
    var id = UUID()
}

iOS 15 confDialog working as expected (animated gif):

iOS 15 confDialog OK

The same code on iOS 16 is delivering unexpected results, e.g. only triggering delete on the second try, etc. See below (animated gif):

iOS 16 confDialog issue

What should be done differently on iOS 16 to make the .configurationDialog modifier work as expected/as in iOS 15?

KlausM
  • 193
  • 12

1 Answers1

1

.destructive automatically removes the row and that is probably clearing the showConfirmation state. You could prevent the row disappearing by changing the role to .none like this:

        .swipeActions {
            Button(role: .none, action: { showConfirmation = true },
                    label: { Label("Delete", systemImage: "trash") })
            .tint(Color.red)
        }
malhal
  • 26,330
  • 7
  • 115
  • 133
  • 1
    Wow, that is surprising! But you are right, a Button role .none fixes the problem! This feels like a bug, as .role should only be used by the OS to determine placement and colouring on different apple platforms, shouldn't it? In this case one could argue that the swipeAction button is not destructive but only the confimationDialog button is destructive. In that sense it is correct. But still a weird and unexpected side effect! – KlausM Nov 11 '22 at 12:26