From 93cf6f848337498d4426d4a6aa794c5b94f999b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beatrice=20Dellac=C3=A0?= Date: Wed, 28 Jan 2026 23:43:50 +0100 Subject: [PATCH] implement alerts, delete --- MultiChrono/ContentView.swift | 30 ++++++++++++++++++++------- MultiChrono/StopwatchDetailView.swift | 26 +++++++++++++++++++++-- MultiChrono/StopwatchRow.swift | 4 ++++ 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/MultiChrono/ContentView.swift b/MultiChrono/ContentView.swift index 3df14cb..29ea9dd 100644 --- a/MultiChrono/ContentView.swift +++ b/MultiChrono/ContentView.swift @@ -62,6 +62,7 @@ struct ContentView: View { @State private var isShowingSettings = false @State private var selectedStopwatch: Stopwatch? @State private var draggingStopwatch: Stopwatch? + @State private var stopwatchToDelete: Stopwatch? @Environment(\.scenePhase) private var scenePhase var body: some View { @@ -73,7 +74,8 @@ struct ContentView: View { stopwatch: stopwatch, viewModel: viewModel, selectedStopwatch: $selectedStopwatch, - draggingStopwatch: $draggingStopwatch + draggingStopwatch: $draggingStopwatch, + stopwatchToDelete: $stopwatchToDelete ) } } @@ -119,9 +121,26 @@ struct ContentView: View { stopwatch.reset() viewModel.save() selectedStopwatch = nil + }, + onDelete: { + viewModel.deleteStopwatch(id: stopwatch.id) + selectedStopwatch = nil } ) } + .alert("Are you sure you want to delete the Stopwatch \(stopwatchToDelete?.name ?? "")?", isPresented: Binding( + get: { stopwatchToDelete != nil }, + set: { if !$0 { stopwatchToDelete = nil } } + )) { + if let stopwatch = stopwatchToDelete { + Button("Delete", role: .destructive) { + withAnimation { + viewModel.deleteStopwatch(id: stopwatch.id) + } + } + } + Button("Cancel", role: .cancel) {} + } .overlay { if viewModel.stopwatches.isEmpty { ContentUnavailableView( @@ -145,15 +164,14 @@ struct StopwatchListItem: View { @ObservedObject var viewModel: ContentViewModel @Binding var selectedStopwatch: Stopwatch? @Binding var draggingStopwatch: Stopwatch? + @Binding var stopwatchToDelete: Stopwatch? var body: some View { Button { selectedStopwatch = stopwatch } label: { StopwatchRow(stopwatch: stopwatch, onDelete: { - withAnimation { - viewModel.deleteStopwatch(id: stopwatch.id) - } + stopwatchToDelete = stopwatch }) } .buttonStyle(.plain) @@ -163,9 +181,7 @@ struct StopwatchListItem: View { .contentShape(Rectangle()) .contextMenu { Button(role: .destructive) { - withAnimation { - viewModel.deleteStopwatch(id: stopwatch.id) - } + stopwatchToDelete = stopwatch } label: { Label("Delete", systemImage: "trash") } diff --git a/MultiChrono/StopwatchDetailView.swift b/MultiChrono/StopwatchDetailView.swift index b61499f..2ecdc14 100644 --- a/MultiChrono/StopwatchDetailView.swift +++ b/MultiChrono/StopwatchDetailView.swift @@ -12,9 +12,11 @@ struct StopwatchDetailView: View { let onSave: (String) -> Void let onCancel: () -> Void let onReset: () -> Void + let onDelete: () -> Void @State private var draftName: String @State private var isShowingResetAlert = false + @State private var isShowingDeleteAlert = false private let dateFormatter: DateFormatter = { let formatter = DateFormatter() @@ -22,11 +24,12 @@ struct StopwatchDetailView: View { return formatter }() - init(stopwatch: Stopwatch, onSave: @escaping (String) -> Void, onCancel: @escaping () -> Void, onReset: @escaping () -> Void) { + init(stopwatch: Stopwatch, onSave: @escaping (String) -> Void, onCancel: @escaping () -> Void, onReset: @escaping () -> Void, onDelete: @escaping () -> Void) { self.stopwatch = stopwatch self.onSave = onSave self.onCancel = onCancel self.onReset = onReset + self.onDelete = onDelete _draftName = State(initialValue: stopwatch.name) } @@ -112,6 +115,18 @@ struct StopwatchDetailView: View { } } } + + Section { + Button(role: .destructive) { + isShowingDeleteAlert = true + } label: { + HStack { + Spacer() + Text("Delete Stopwatch") + Spacer() + } + } + } } .navigationTitle("Edit Stopwatch") .navigationBarTitleDisplayMode(.inline) @@ -121,6 +136,12 @@ struct StopwatchDetailView: View { } Button("Cancel", role: .cancel) {} } + .alert("Are you sure you want to delete the Stopwatch \(stopwatch.name)?", isPresented: $isShowingDeleteAlert) { + Button("Delete", role: .destructive) { + onDelete() + } + Button("Cancel", role: .cancel) {} + } .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Cancel") { @@ -143,6 +164,7 @@ struct StopwatchDetailView: View { stopwatch: Stopwatch(name: "Test Timer"), onSave: { _ in }, onCancel: {}, - onReset: {} + onReset: {}, + onDelete: {} ) } diff --git a/MultiChrono/StopwatchRow.swift b/MultiChrono/StopwatchRow.swift index 23783e5..49fb4f1 100644 --- a/MultiChrono/StopwatchRow.swift +++ b/MultiChrono/StopwatchRow.swift @@ -20,6 +20,10 @@ struct StopwatchRow: View { Text("\(stopwatch.formattedTime(format: settings.timeFormat))") .font(.largeTitle) .monospacedDigit() + Text("Laps: \(stopwatch.laps.count + (stopwatch.isRunning ? 1 : 0))") + .font(.caption) + .monospaced() + .foregroundStyle(.secondary) } Spacer()