Files
multi-chrono-ios/MultiChrono/ContentView.swift
2026-01-27 02:05:41 +01:00

129 lines
3.8 KiB
Swift

//
// ContentView.swift
// MultiChrono
//
// Created by Beatrice Dellacà on 26/01/26.
//
import SwiftUI
import Combine
class ContentViewModel: ObservableObject {
@Published var stopwatches: [Stopwatch] = []
private let saveKey = "SavedStopwatches"
init() {
load()
}
func addStopwatch(name: String) {
let newStopwatch = Stopwatch(name: name)
stopwatches.append(newStopwatch)
save()
}
func deleteStopwatch(at index: Int) {
stopwatches[index].pause() // Ensure timer is stopped
stopwatches.remove(at: index)
save()
}
func deleteStopwatch(id: UUID) {
if let index = stopwatches.firstIndex(where: { $0.id == id }) {
deleteStopwatch(at: index)
}
}
func save() {
if let encoded = try? JSONEncoder().encode(stopwatches) {
UserDefaults.standard.set(encoded, forKey: saveKey)
}
}
func load() {
if let data = UserDefaults.standard.data(forKey: saveKey) {
if let decoded = try? JSONDecoder().decode([Stopwatch].self, from: data) {
stopwatches = decoded
}
}
}
}
struct ContentView: View {
@StateObject private var viewModel = ContentViewModel()
@State private var isShowingAddSheet = false
@State private var selectedStopwatch: Stopwatch?
@Environment(\.scenePhase) private var scenePhase
var body: some View {
NavigationStack {
List {
ForEach(viewModel.stopwatches) { stopwatch in
Button {
selectedStopwatch = stopwatch
} label: {
StopwatchRow(stopwatch: stopwatch, onDelete: {
viewModel.deleteStopwatch(id: stopwatch.id)
})
}
.buttonStyle(.plain) // Preserves the row layout and interactions
}
.onDelete { indexSet in
for index in indexSet {
viewModel.deleteStopwatch(at: index)
}
}
}
.listStyle(.plain)
.navigationTitle("MultiChrono")
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button(action: {
isShowingAddSheet = true
}) {
Image(systemName: "plus")
}
}
}
.sheet(isPresented: $isShowingAddSheet) {
AddStopwatchView { name in
viewModel.addStopwatch(name: name)
isShowingAddSheet = false
}
}
.sheet(item: $selectedStopwatch) { stopwatch in
StopwatchDetailView(
stopwatch: stopwatch,
onSave: { newName in
stopwatch.name = newName
viewModel.save()
selectedStopwatch = nil
},
onCancel: {
selectedStopwatch = nil
}
)
}
.overlay {
if viewModel.stopwatches.isEmpty {
ContentUnavailableView(
"No Stopwatches",
systemImage: "timer",
description: Text("Tap the + button to create a stopwatch.")
)
}
}
}
.onChange(of: scenePhase) { newPhase in
if newPhase == .background || newPhase == .inactive {
viewModel.save()
}
}
}
}
#Preview {
ContentView()
}