Commit Graph
3 Commits
Author SHA1 Message Date
rzen e8b1cb800d Give the exercise run screen its own chrome, rolling digits, and a true resume
The run screen now hides the navigation bar in both orientations and draws
its own header — back chevron top-left, exercise name (plus library name
when renamed) in large type where the toolbar was, previewing the next
exercise during a between-exercise rest. Work and rest counters are pinned
to the exact vertical center of the timer half via equal flexible bands,
with the adjust pill moved to an overlay so complications can't shift them.
Counter digits are now state-driven and roll through numericText
transitions (work count-up, rest countdown, and the Done button count).

Reopening an in-progress exercise now resumes its timer from the durable
timestamps instead of restarting at zero: no sets done anchors the
stopwatch to startedAt; mid-rest lands back on the rest page with the
countdown still running off its true window; past the window the next
set's stopwatch counts from the rest's computed end. The resume page is
computed at init because the paged TabView must initialize on it — a
post-layout backward jump wedges the pager, which then ignores the next
animated programmatic advance.

Claude-Session: https://claude.ai/code/session_01H8VxUX4ckjU3vRF5M4L5FV
2026-07-14 20:56:18 -04:00
rzen df3eac9d5f Add a Live Activity for the running workout
A new iOS widget extension shows the active exercise, its phase, and the
work/rest countdown on the lock screen and in the Dynamic Island, driven
by the run flow's live frames so locking the phone mid-set keeps the
timer. The activity is seeded on open, refreshed on every page settle,
dismissed when the flow is left, and cleared on next launch if stranded.
Unifies the build-info stamping across all targets via a YAML anchor.

Claude-Session: https://claude.ai/code/session_01HJDQQDA9QdP8zByg43H5v3
2026-07-08 08:02:34 -04:00
rzen 8f69497b24 Make the live run two-way: drive from either device
The propped-up iPhone now runs the real ExerciseProgressView for a live
watch workout instead of a read-only mirror, and the live-run channel is
symmetric — either device can drive the flow and the other follows.

Each page transition is classified human / auto / remote: only human
transitions (swipe, Start, One More, swipe-back reset) are broadcast and
recorded by the actor; auto-advances (rest / timed-work countdown) record
locally but aren't sent, since both devices reach them independently off
the shared wall-clock anchors; an applied remote frame jumps the page
without re-recording or re-broadcasting. That rule is also what stops an
echo loop.

- PhoneConnectivityBridge gains sendLiveProgress/sendLiveEnded (the
  missing phone->watch direction); WatchConnectivityBridge receives
  frames into an observable liveIncoming via a new didReceiveMessage
  route. Both share one increasing per-run version sequence so the
  stale-frame guard works across the two devices' counters.
- Both ExerciseProgressViews gain an incomingFrame input + applyIncoming
  (syncing setCount for a remote One More); the iPhone one gains the
  liveSnapshot/broadcast machinery the watch already had.
- New LiveRunCoverView wraps the real driver for the cover (resolves the
  workout, persists via SyncEngine, wires the live channel + close);
  ContentView presents it; LiveProgressMirrorView is removed.

Claude-Session: https://claude.ai/code/session_01SCv7zvGFcKy47KSTnTLxRe
2026-06-20 22:11:05 -04:00