// // WorkoutCoordinator.swift // Keging // // 엔진 ↔ 진동·Live Activity·백그라운드 오디오·화면 꺼짐 방지 배선 (iOS) // import UIKit @MainActor final class WorkoutCoordinator { static let shared = WorkoutCoordinator() private var wired = false private init() {} func wire() { guard !wired else { return } wired = true LiveActivityManager.shared.cleanupStaleActivities() let engine = KegelEngine.shared engine.onPhaseChange = { [weak engine] phase, rep, phaseEnd in guard let engine else { return } let config = engine.config switch phase { case .prepare: break // 준비는 무진동 — 첫 수축 진동이 시작 신호 case .contract: Haptics.play(config.contractPattern) case .relax: Haptics.play(config.relaxPattern) } LiveActivityManager.shared.sync(phase: phase, rep: rep, totalReps: config.reps, phaseEnd: phaseEnd) } engine.onSessionEnd = { completed, record in LiveActivityManager.shared.end() BackgroundAudioKeeper.shared.stop() UIApplication.shared.isIdleTimerDisabled = false if completed, let record { let config = SettingsStore.shared.config HealthRecorder.shared.save( record: record, effortScore: config.effortScore, workoutType: config.healthWorkoutType ) } } } func startWorkout() { guard !KegelEngine.shared.isRunning else { return } HealthRecorder.shared.requestAuthorizationIfNeeded() BackgroundAudioKeeper.shared.start() UIApplication.shared.isIdleTimerDisabled = true KegelEngine.shared.start(config: SettingsStore.shared.config) } }