Redesign workout live activity with circular timer ring, phase icons, and smoother updates
Some checks failed
CI / TypeScript (pull_request) Failing after 19s
CI / ESLint (pull_request) Failing after 4s
CI / Tests (pull_request) Failing after 7s
CI / Build Check (pull_request) Has been skipped
CI / Admin Web Tests (pull_request) Successful in 2m9s
CI / Deploy Edge Functions (pull_request) Has been skipped
Some checks failed
CI / TypeScript (pull_request) Failing after 19s
CI / ESLint (pull_request) Failing after 4s
CI / Tests (pull_request) Failing after 7s
CI / Build Check (pull_request) Has been skipped
CI / Admin Web Tests (pull_request) Successful in 2m9s
CI / Deploy Edge Functions (pull_request) Has been skipped
- Add CountdownRing with real-time arc progress on lock screen - Replace generic dots with phase-specific SF Symbols (flame, snowflake, etc.) - Remove horizontal progress bar in favor of round counter text - Increase Dynamic Island expanded font sizes for better visibility - Increase live activity sync frequency from 5s to 1s for smoother arc updates - Add pause/resume button via TogglePauseIntent AppIntent - Remove AlertConfiguration to silence notification sounds on updates
This commit is contained in:
@@ -365,7 +365,7 @@ final class PlayerViewModel: ObservableObject {
|
||||
|
||||
// ─── Dynamic Island / Live Activity ─────────────────────────────
|
||||
|
||||
func syncActivity() {
|
||||
func syncActivity(shouldAlert: Bool = false) {
|
||||
guard ActivityAuthorizationInfo().areActivitiesEnabled else { return }
|
||||
guard isRunning else { return }
|
||||
|
||||
@@ -377,6 +377,7 @@ final class PlayerViewModel: ObservableObject {
|
||||
exerciseName: currentExercise?.nameEn ?? "",
|
||||
phase: workoutPhase,
|
||||
phaseEndDate: phaseEnd,
|
||||
phaseDuration: Double(totalPhaseTime),
|
||||
roundCurrent: currentRound,
|
||||
roundTotal: totalRoundsInBlock,
|
||||
heartRate: heartRate,
|
||||
@@ -393,7 +394,7 @@ final class PlayerViewModel: ObservableObject {
|
||||
if let existing = workoutActivity {
|
||||
nonisolated(unsafe) let safeExisting = existing
|
||||
let staleDate = Date().addingTimeInterval(isPaused ? 3600 : 120)
|
||||
let alert = alertForPhase(workoutPhase)
|
||||
let alert = shouldAlert ? alertForPhase(workoutPhase) : nil
|
||||
Task { @MainActor in
|
||||
if let alert {
|
||||
await safeExisting.update(ActivityContent(state: state, staleDate: staleDate), alertConfiguration: alert)
|
||||
@@ -444,6 +445,7 @@ final class PlayerViewModel: ObservableObject {
|
||||
exerciseName: safeActivity.content.state.exerciseName,
|
||||
phase: .complete,
|
||||
phaseEndDate: safeActivity.content.state.phaseEndDate,
|
||||
phaseDuration: safeActivity.content.state.phaseDuration,
|
||||
roundCurrent: safeActivity.content.state.roundCurrent,
|
||||
roundTotal: safeActivity.content.state.roundTotal,
|
||||
heartRate: safeActivity.content.state.heartRate,
|
||||
@@ -457,7 +459,7 @@ final class PlayerViewModel: ObservableObject {
|
||||
|
||||
private func startActivitySyncTimer() {
|
||||
stopActivitySyncTimer()
|
||||
activitySyncTimer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { [weak self] _ in
|
||||
activitySyncTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
|
||||
Task { @MainActor [weak self] in
|
||||
self?.syncActivity()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user