Explorar o código

Fix Temp Target and Override delete confirmation auto-dismissing

The delete confirmation for Temp Target and Override presets only appeared
for a moment before auto-dismissing, so presets could not be deleted by
swiping. It was attached to the ForEach inside the List and driven by two
state variables set at the same time, which made it dismiss itself.

Drive the dialog from a single optional via presenting:, attached once to
the view, matching the History screen. Applied to both Temp Targets and
Overrides.
Jonas Björkert hai 1 día
pai
achega
7764a422af

+ 6 - 1
Trio/Sources/Modules/Adjustments/View/AdjustmentsRootView.swift

@@ -16,7 +16,8 @@ extension Adjustments {
         @State var selectedTempTargetPresetID: String?
         @State var selectedOverride: OverrideStored?
         @State var selectedTempTarget: TempTargetStored?
-        @State var isConfirmDeletePresented = false
+        @State var overrideToDelete: OverrideStored?
+        @State var tempTargetToDelete: TempTargetStored?
         @State var isPromptPresented = false
         @State var isRemoveAlertPresented = false
         @State var removeAlert: Alert?
@@ -48,6 +49,10 @@ extension Adjustments {
         }
 
         var body: some View {
+            tempTargetDeleteConfirmation(overrideDeleteConfirmation(mainContent))
+        }
+
+        private var mainContent: some View {
             ZStack(alignment: .center, content: {
                 VStack {
                     Picker("Adjustment Tabs", selection: $state.selectedTab) {

+ 43 - 48
Trio/Sources/Modules/Adjustments/View/Overrides/AdjustmentsRootView+Overrides.swift

@@ -23,48 +23,10 @@ extension Adjustments.RootView {
                     actionButtonsForOverrides(for: preset)
                 }
                 .swipeActions(edge: .trailing, allowsFullSwipe: true) {
-                    actionButtonsForOverrides(for: preset)
+                    actionButtonsForOverrides(for: preset, deleteRole: nil)
                 }
             }
             .onMove(perform: state.reorderOverride)
-            .confirmationDialog(
-                "Delete the Override Preset \"\(selectedOverride?.name ?? "")\"?",
-                isPresented: $isConfirmDeletePresented,
-                titleVisibility: .visible
-            ) {
-                if let itemToDelete = selectedOverride {
-                    Button(
-                        state.currentActiveOverride == selectedOverride ? "Stop and Delete" : "Delete",
-                        role: .destructive
-                    ) {
-                        if state.currentActiveOverride == selectedOverride {
-                            Task {
-                                // Save cancelled Override in OverrideRunStored Entity
-                                // Cancel ALL active Override
-                                await state.disableAllActiveOverrides(createOverrideRunEntry: true)
-                            }
-                        }
-                        // Perform the delete action
-                        Task {
-                            await state.invokeOverridePresetDeletion(itemToDelete.objectID)
-                        }
-                        // Reset the selected item after deletion
-                        selectedOverride = nil
-                    }
-                }
-                Button("Cancel", role: .cancel) {
-                    // Dismiss the dialog without action
-                    selectedOverride = nil
-                }
-            } message: {
-                if state.currentActiveOverride == selectedOverride {
-                    Text(
-                        state
-                            .currentActiveOverride == selectedOverride ?
-                            "This override preset is currently running. Deleting will stop it." : ""
-                    )
-                }
-            }
             .listRowBackground(Color.chart)
         } header: {
             Text("Override Presets")
@@ -76,6 +38,37 @@ extension Adjustments.RootView {
         }
     }
 
+    func overrideDeleteConfirmation(_ content: some View) -> some View {
+        content.confirmationDialog(
+            "Delete the Override Preset \"\(overrideToDelete?.name ?? "")\"?",
+            isPresented: Binding(
+                get: { overrideToDelete != nil },
+                set: { if !$0 { overrideToDelete = nil } }
+            ),
+            titleVisibility: .visible,
+            presenting: overrideToDelete
+        ) { target in
+            Button(
+                state.currentActiveOverride == target ? "Stop and Delete" : "Delete",
+                role: .destructive
+            ) {
+                if state.currentActiveOverride == target {
+                    Task {
+                        await state.disableAllActiveOverrides(createOverrideRunEntry: true)
+                    }
+                }
+                Task {
+                    await state.invokeOverridePresetDeletion(target.objectID)
+                }
+            }
+            Button("Cancel", role: .cancel) {}
+        } message: { target in
+            if state.currentActiveOverride == target {
+                Text("This override preset is currently running. Deleting will stop it.")
+            }
+        }
+    }
+
     private func requestOverridePresetActivation(_ preset: OverrideStored) {
         let activation = PendingPresetActivation.override(
             objectID: preset.objectID,
@@ -86,23 +79,25 @@ extension Adjustments.RootView {
         requestPresetActivation(activation)
     }
 
-    func actionButtonsForOverrides(for preset: OverrideStored) -> some View {
+    func actionButtonsForOverrides(
+        for preset: OverrideStored,
+        deleteRole: ButtonRole? = .destructive
+    ) -> some View {
         Group {
-            Button(role: .destructive) {
-                selectedOverride = preset
-                isConfirmDeletePresented = true
+            Button(role: deleteRole) {
+                overrideToDelete = preset
             } label: {
                 Label("Delete", systemImage: "trash.fill")
-                    .tint(.red)
             }
-            Button(action: {
+            .tint(.red)
+            Button {
                 // Set the selected Override to the chosen Preset and pass it to the Edit Sheet
                 selectedOverride = preset
                 state.showOverrideEditSheet = true
-            }, label: {
+            } label: {
                 Label("Edit", systemImage: "pencil")
-                    .tint(.blue)
-            })
+            }
+            .tint(.blue)
         }
     }
 

+ 39 - 53
Trio/Sources/Modules/Adjustments/View/TempTargets/AdjustmentsRootView+TempTargets.swift

@@ -21,7 +21,7 @@ extension Adjustments.RootView {
             ForEach(state.scheduledTempTargets) { tempTarget in
                 tempTargetView(for: tempTarget)
                     .swipeActions(edge: .trailing, allowsFullSwipe: true) {
-                        actionButtonsForTempTargets(for: tempTarget)
+                        actionButtonsForTempTargets(for: tempTarget, deleteRole: nil)
                     }
             }
             .listRowBackground(Color.chart)
@@ -40,19 +40,10 @@ extension Adjustments.RootView {
                     actionButtonsForTempTargets(for: preset)
                 }
                 .swipeActions(edge: .trailing, allowsFullSwipe: true) {
-                    actionButtonsForTempTargets(for: preset)
+                    actionButtonsForTempTargets(for: preset, deleteRole: nil)
                 }
             }
             .onMove(perform: state.reorderTempTargets)
-            .confirmationDialog(
-                deleteConfirmationTitle,
-                isPresented: $isConfirmDeletePresented,
-                titleVisibility: .visible
-            ) {
-                deleteConfirmationButtons()
-            } message: {
-                deleteConfirmationMessage
-            }
             .listRowBackground(Color.chart)
         } header: {
             Text("Temporary Target Presets")
@@ -74,66 +65,61 @@ extension Adjustments.RootView {
         requestPresetActivation(activation)
     }
 
-    private func actionButtonsForTempTargets(for tempTarget: TempTargetStored) -> some View {
+    private func actionButtonsForTempTargets(
+        for tempTarget: TempTargetStored,
+        deleteRole: ButtonRole? = .destructive
+    ) -> some View {
         Group {
-            Button(role: .destructive) {
-                Task {
-                    selectedTempTarget = tempTarget
-                    isConfirmDeletePresented = true
-                }
+            Button(role: deleteRole) {
+                tempTargetToDelete = tempTarget
             } label: {
                 Label("Delete", systemImage: "trash.fill")
-                    .tint(.red)
             }
-            Button(action: {
+            .tint(.red)
+            Button {
                 selectedTempTarget = tempTarget
                 state.showTempTargetEditSheet = true
-            }, label: {
+            } label: {
                 Label("Edit", systemImage: "pencil")
-                    .tint(.blue)
-            })
+            }
+            .tint(.blue)
         }
     }
 
-    private var deleteConfirmationTitle: String {
-        let presetName = selectedTempTarget?.name ?? ""
-        return String(
-            localized: "Delete the Temp Target Preset \"\(presetName)\"?",
-            comment: "Delete confirmation title for temporary target presets"
-        )
-    }
-
-    private func deleteConfirmationButtons() -> some View {
-        Group {
-            if let itemToDelete = selectedTempTarget {
-                Button(
-                    state.currentActiveTempTarget == selectedTempTarget ? "Stop and Delete" : "Delete",
-                    role: .destructive
-                ) {
-                    if state.currentActiveTempTarget == selectedTempTarget {
-                        Task {
-                            await state.disableAllActiveTempTargets(createTempTargetRunEntry: true)
-                        }
-                    }
+    func tempTargetDeleteConfirmation(_ content: some View) -> some View {
+        content.confirmationDialog(
+            String(
+                localized: "Delete the Temp Target Preset \"\(tempTargetToDelete?.name ?? "")\"?",
+                comment: "Delete confirmation title for temporary target presets"
+            ),
+            isPresented: Binding(
+                get: { tempTargetToDelete != nil },
+                set: { if !$0 { tempTargetToDelete = nil } }
+            ),
+            titleVisibility: .visible,
+            presenting: tempTargetToDelete
+        ) { target in
+            Button(
+                state.currentActiveTempTarget == target ? "Stop and Delete" : "Delete",
+                role: .destructive
+            ) {
+                if state.currentActiveTempTarget == target {
                     Task {
-                        await state.invokeTempTargetPresetDeletion(itemToDelete.objectID)
+                        await state.disableAllActiveTempTargets(createTempTargetRunEntry: true)
                     }
-                    selectedTempTarget = nil
+                }
+                Task {
+                    await state.invokeTempTargetPresetDeletion(target.objectID)
                 }
             }
-            Button("Cancel", role: .cancel) {
-                selectedTempTarget = nil
+            Button("Cancel", role: .cancel) {}
+        } message: { target in
+            if state.currentActiveTempTarget == target {
+                Text("This Temp Target preset is currently running. Deleting will stop it.")
             }
         }
     }
 
-    private var deleteConfirmationMessage: Text? {
-        if state.currentActiveTempTarget == selectedTempTarget {
-            return Text("This Temp Target preset is currently running. Deleting will stop it.")
-        }
-        return nil
-    }
-
     var stickyStopTempTargetButton: some View {
         ZStack {
             Rectangle()