feat: redesign Dynamic Island with phase-driven UI and animations
This commit is contained in:
@@ -57,6 +57,8 @@ final class MusicPlayerViewModel: ObservableObject {
|
||||
|
||||
func play() {
|
||||
guard audio.isMusicEnabled, player != nil else { return }
|
||||
// Reactivate the audio session in case the system deactivated it while backgrounded
|
||||
try? AVAudioSession.sharedInstance().setActive(true)
|
||||
player?.volume = audio.musicVolume
|
||||
player?.play()
|
||||
}
|
||||
|
||||
@@ -58,6 +58,8 @@ final class PlayerViewModel: ObservableObject {
|
||||
private var warmupIndex: Int = 0
|
||||
// Cooldown phase index
|
||||
private var cooldownIndex: Int = 0
|
||||
// Throttle rapid toggle from widget
|
||||
private var lastToggleTimestamp: Date = .distantPast
|
||||
|
||||
private var currentBlock: TabataBlock? {
|
||||
guard currentBlockIndex < program.blocks.count else { return nil }
|
||||
@@ -91,6 +93,14 @@ final class PlayerViewModel: ObservableObject {
|
||||
// ─── Controls ─────────────────────────────────────────────────
|
||||
|
||||
func togglePlayPause() {
|
||||
let now = Date()
|
||||
guard now.timeIntervalSince(lastToggleTimestamp) > 0.6 else {
|
||||
print("[PlayerVM] TogglePlayPause throttled (last tap was < 0.6s ago)")
|
||||
return
|
||||
}
|
||||
lastToggleTimestamp = now
|
||||
print("[PlayerVM] TogglePlayPause — isPaused=\(isPaused), isRunning=\(isRunning)")
|
||||
|
||||
if !isRunning {
|
||||
startWorkout()
|
||||
} else if isPaused {
|
||||
@@ -384,7 +394,11 @@ final class PlayerViewModel: ObservableObject {
|
||||
trackTitle: currentTrackTitle,
|
||||
trackArtist: currentTrackArtist,
|
||||
isPlaying: isPlayingMusic,
|
||||
isPaused: isPaused
|
||||
isPaused: isPaused,
|
||||
blockIndex: currentBlockIndex + 1,
|
||||
blockCount: program.blocks.count,
|
||||
exerciseShortName: String(currentExercise?.nameEn.prefix(8) ?? ""),
|
||||
phaseElapsedSeconds: max(0, Double(totalPhaseTime) - Double(timeRemaining))
|
||||
)
|
||||
|
||||
if let existing = workoutActivity, existing.activityState != .active {
|
||||
@@ -452,7 +466,11 @@ final class PlayerViewModel: ObservableObject {
|
||||
trackTitle: safeActivity.content.state.trackTitle,
|
||||
trackArtist: safeActivity.content.state.trackArtist,
|
||||
isPlaying: false,
|
||||
isPaused: false
|
||||
isPaused: false,
|
||||
blockIndex: safeActivity.content.state.blockIndex,
|
||||
blockCount: safeActivity.content.state.blockCount,
|
||||
exerciseShortName: safeActivity.content.state.exerciseShortName,
|
||||
phaseElapsedSeconds: safeActivity.content.state.phaseElapsedSeconds
|
||||
)
|
||||
await safeActivity.end(ActivityContent(state: finalState, staleDate: nil), dismissalPolicy: .immediate)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user