// ── Watch Timer Store ───────────────────────────────────────── // Reads timer data from App Group shared by the iOS app // Lightweight store for watchOS — read-only from shared data + local quick timers import Foundation import Combine import WatchKit @MainActor final class WatchTimerStore: ObservableObject { // MARK: - Published State @Published var timers: [TimerSnapshot] = [] @Published var now: Date = Date() // MARK: - Private private var tickTimer: Timer? private let sharedData = SharedTimerDataManager.shared // MARK: - Init init() { loadFromSharedData() startTicking() } deinit { tickTimer?.invalidate() } // MARK: - Data Loading func loadFromSharedData() { timers = sharedData.readActiveSnapshots() } // MARK: - Queries var nextFiringTimer: TimerSnapshot? { timers .filter { [.active, .warning].contains($0.state) } .sorted { $0.targetTime < $1.targetTime } .first } var activeTimers: [TimerSnapshot] { timers.filter { [.active, .warning, .snoozed, .firing].contains($0.state) } } // MARK: - Quick Timer Creation (writes to App Group) func createQuickTimer(minutes: Int, label: String) { let now = Date() let targetTime = now.addingTimeInterval(TimeInterval(minutes * 60)) let intervals = CascadePreset.minimal.defaultIntervals let snapshot = TimerSnapshot( id: UUID().uuidString, label: label, type: .countdown, urgency: .standard, state: .active, targetTime: targetTime, duration: TimeInterval(minutes * 60), startedAt: now, elapsedBeforePause: 0, snoozeCount: 0, category: nil, pomodoroCurrentRound: nil, pomodoroTotalRounds: nil, pomodoroIsBreak: nil, nextWarningTime: intervals.first.map { targetTime.addingTimeInterval(-Double($0) * 60) }, totalWarnings: intervals.count, firedWarnings: 0 ) // Add to local list and persist timers.append(snapshot) timers.sort { $0.targetTime < $1.targetTime } // Write back to shared data so iOS app picks it up sharedData.writeSnapshots(timers) // Haptic confirmation WKInterfaceDevice.current().play(.success) } // MARK: - Tick private func startTicking() { tickTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in Task { @MainActor in self?.tick() } } } private func tick() { now = Date() // Refresh from shared data every 30 seconds let interval = Int(now.timeIntervalSince1970) % 30 if interval == 0 { loadFromSharedData() } // Check for fired timers var changed = false for i in timers.indices { if timers[i].state == .active || timers[i].state == .warning { if now >= timers[i].targetTime { // Timer has fired — haptic alert WKInterfaceDevice.current().play(.notification) changed = true } } } if changed { loadFromSharedData() // Refresh to get updated states } } }