test-repo/GlassTimer/Sources/TimerView.swift
Matt Bruce 105621b40e Add project standards and responsive design requirements to AGENTS.md
- Documented mobile-first responsive design as REQUIRED standard
- Added web development tech preferences (Next.js, Tailwind, etc.)
- Created memory/project-standards.md for coding guidelines
2026-02-18 09:42:05 -06:00

90 lines
2.6 KiB
Swift

import SwiftUI
import AlarmKit
import Observation
@Observable
@MainActor
final class TimerStore {
var timeRemaining: TimeInterval = 25 * 60 // 25 min Pomodoro
var isRunning = false
var session: Session?
private var timer: Task<Void, Never>?
private let service = TimerService()
}
struct TimerView: View {
@State private var store = TimerStore()
var body: some View {
NavigationStack {
VStack(spacing: 40) {
Text(timeString(from: store.timeRemaining))
.font(.system(size: 80, weight: .bold, design: .rounded))
.foregroundStyle(.primary)
VStack(spacing: 20) {
Button(store.isRunning ? "Pause" : "Start") {
toggleTimer()
}
.buttonStyle(.borderedProminent)
.controlSize(.large)
Button("Reset") {
resetTimer()
}
.buttonStyle(.bordered)
}
Spacer()
}
.padding()
.navigationTitle("Pomodoro Timer")
.sheet(isPresented: .constant(store.isRunning)) {
// Optional: Session summary sheet with AI
Text("Timer active!")
}
}
.glassEffect() // Liquid Glass for the nav stack
}
private func toggleTimer() {
if store.isRunning {
store.timer?.cancel()
store.timer = nil
store.isRunning = false
// Save session to SwiftData
store.session = Session(duration: store.timeRemaining, completed: true)
} else {
store.isRunning = true
store.timer = Task {
while store.timeRemaining > 0 && !Task.isCancelled {
try? await Task.sleep(for: .seconds(1))
store.timeRemaining -= 1
}
if !Task.isCancelled {
// Alarm via AlarmKit
await store.service.scheduleAlarm(for: store.timeRemaining)
store.isRunning = false
}
}
}
}
private func resetTimer() {
store.timer?.cancel()
store.timeRemaining = 25 * 60
store.isRunning = false
}
private func timeString(from timeInterval: TimeInterval) -> String {
let minutes = Int(timeInterval) / 60
let seconds = Int(timeInterval) % 60
return String(format: "%02d:%02d", minutes, seconds)
}
}
#Preview {
TimerView()
}