implement alerts, delete

This commit is contained in:
2026-01-28 23:43:50 +01:00
parent a607e33ce9
commit 93cf6f8483
3 changed files with 51 additions and 9 deletions

View File

@@ -62,6 +62,7 @@ struct ContentView: View {
@State private var isShowingSettings = false @State private var isShowingSettings = false
@State private var selectedStopwatch: Stopwatch? @State private var selectedStopwatch: Stopwatch?
@State private var draggingStopwatch: Stopwatch? @State private var draggingStopwatch: Stopwatch?
@State private var stopwatchToDelete: Stopwatch?
@Environment(\.scenePhase) private var scenePhase @Environment(\.scenePhase) private var scenePhase
var body: some View { var body: some View {
@@ -73,7 +74,8 @@ struct ContentView: View {
stopwatch: stopwatch, stopwatch: stopwatch,
viewModel: viewModel, viewModel: viewModel,
selectedStopwatch: $selectedStopwatch, selectedStopwatch: $selectedStopwatch,
draggingStopwatch: $draggingStopwatch draggingStopwatch: $draggingStopwatch,
stopwatchToDelete: $stopwatchToDelete
) )
} }
} }
@@ -119,9 +121,26 @@ struct ContentView: View {
stopwatch.reset() stopwatch.reset()
viewModel.save() viewModel.save()
selectedStopwatch = nil 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 { .overlay {
if viewModel.stopwatches.isEmpty { if viewModel.stopwatches.isEmpty {
ContentUnavailableView( ContentUnavailableView(
@@ -145,15 +164,14 @@ struct StopwatchListItem: View {
@ObservedObject var viewModel: ContentViewModel @ObservedObject var viewModel: ContentViewModel
@Binding var selectedStopwatch: Stopwatch? @Binding var selectedStopwatch: Stopwatch?
@Binding var draggingStopwatch: Stopwatch? @Binding var draggingStopwatch: Stopwatch?
@Binding var stopwatchToDelete: Stopwatch?
var body: some View { var body: some View {
Button { Button {
selectedStopwatch = stopwatch selectedStopwatch = stopwatch
} label: { } label: {
StopwatchRow(stopwatch: stopwatch, onDelete: { StopwatchRow(stopwatch: stopwatch, onDelete: {
withAnimation { stopwatchToDelete = stopwatch
viewModel.deleteStopwatch(id: stopwatch.id)
}
}) })
} }
.buttonStyle(.plain) .buttonStyle(.plain)
@@ -163,9 +181,7 @@ struct StopwatchListItem: View {
.contentShape(Rectangle()) .contentShape(Rectangle())
.contextMenu { .contextMenu {
Button(role: .destructive) { Button(role: .destructive) {
withAnimation { stopwatchToDelete = stopwatch
viewModel.deleteStopwatch(id: stopwatch.id)
}
} label: { } label: {
Label("Delete", systemImage: "trash") Label("Delete", systemImage: "trash")
} }

View File

@@ -12,9 +12,11 @@ struct StopwatchDetailView: View {
let onSave: (String) -> Void let onSave: (String) -> Void
let onCancel: () -> Void let onCancel: () -> Void
let onReset: () -> Void let onReset: () -> Void
let onDelete: () -> Void
@State private var draftName: String @State private var draftName: String
@State private var isShowingResetAlert = false @State private var isShowingResetAlert = false
@State private var isShowingDeleteAlert = false
private let dateFormatter: DateFormatter = { private let dateFormatter: DateFormatter = {
let formatter = DateFormatter() let formatter = DateFormatter()
@@ -22,11 +24,12 @@ struct StopwatchDetailView: View {
return formatter 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.stopwatch = stopwatch
self.onSave = onSave self.onSave = onSave
self.onCancel = onCancel self.onCancel = onCancel
self.onReset = onReset self.onReset = onReset
self.onDelete = onDelete
_draftName = State(initialValue: stopwatch.name) _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") .navigationTitle("Edit Stopwatch")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
@@ -121,6 +136,12 @@ struct StopwatchDetailView: View {
} }
Button("Cancel", role: .cancel) {} 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 { .toolbar {
ToolbarItem(placement: .cancellationAction) { ToolbarItem(placement: .cancellationAction) {
Button("Cancel") { Button("Cancel") {
@@ -143,6 +164,7 @@ struct StopwatchDetailView: View {
stopwatch: Stopwatch(name: "Test Timer"), stopwatch: Stopwatch(name: "Test Timer"),
onSave: { _ in }, onSave: { _ in },
onCancel: {}, onCancel: {},
onReset: {} onReset: {},
onDelete: {}
) )
} }

View File

@@ -20,6 +20,10 @@ struct StopwatchRow: View {
Text("\(stopwatch.formattedTime(format: settings.timeFormat))") Text("\(stopwatch.formattedTime(format: settings.timeFormat))")
.font(.largeTitle) .font(.largeTitle)
.monospacedDigit() .monospacedDigit()
Text("Laps: \(stopwatch.laps.count + (stopwatch.isRunning ? 1 : 0))")
.font(.caption)
.monospaced()
.foregroundStyle(.secondary)
} }
Spacer() Spacer()