learning_ai_clock/ios/ChronoMindWatch/WatchTimerStore.swift

125 lines
3.5 KiB
Swift

// 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
}
}
}