d5915a9552
- Redesign the watch app into an active-workout runner: a root gate shows the in-progress workout's exercises or prompts to start one on iPhone, and each exercise runs as a horizontally-paged HIIT cycle (count-up work, count-down rest with final-three-second haptics + auto-advance, One More / Done on the last set). Replaces the old history list. - Add a configurable rest-between-sets duration in iPhone Settings (default 45s), synced to the watch over WatchConnectivity. - Launch the watch app into the session when a workout starts on the phone via HealthKit (startWatchApp); the watch runs an HKWorkoutSession for foreground runtime and ends it when the workout finishes. Adds the HealthKit entitlement + Health usage strings on both targets and WKBackgroundModes on the watch. Claude-Session: https://claude.ai/code/session_018gg69MaUetDNzWzBXisfMV
38 lines
1.2 KiB
Swift
38 lines
1.2 KiB
Swift
import Foundation
|
|
import Observation
|
|
import SwiftData
|
|
|
|
/// Composition root for the iOS app. Owns the SwiftData cache container and the
|
|
/// iCloud sync engine, and drives the one-shot launch sequence. Injected into the
|
|
/// view tree via `.environment(...)`.
|
|
@Observable
|
|
@MainActor
|
|
final class AppServices {
|
|
let container: ModelContainer
|
|
let syncEngine: SyncEngine
|
|
let watchBridge: PhoneConnectivityBridge
|
|
let workoutLauncher = WorkoutLauncher()
|
|
|
|
private var bootstrapTask: Task<Void, Never>?
|
|
|
|
init() {
|
|
let container = WorkoutsModelContainer.make()
|
|
self.container = container
|
|
self.syncEngine = SyncEngine(container: container)
|
|
self.watchBridge = PhoneConnectivityBridge(container: container, syncEngine: syncEngine)
|
|
}
|
|
|
|
/// Launch step: resolve iCloud and reconcile the cache. Idempotent — repeated
|
|
/// callers await the same one-shot task.
|
|
func bootstrap() async {
|
|
if let bootstrapTask { await bootstrapTask.value; return }
|
|
let task = Task { @MainActor [weak self] in
|
|
guard let self else { return }
|
|
await self.syncEngine.connect()
|
|
self.watchBridge.activate()
|
|
}
|
|
bootstrapTask = task
|
|
await task.value
|
|
}
|
|
}
|