8f69497b24
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
55 lines
2.8 KiB
Markdown
55 lines
2.8 KiB
Markdown
# Workouts
|
|
|
|
A workout tracking app for iPhone and Apple Watch. Build workout splits, run
|
|
sessions, and track your progress — with your data stored as plain JSON files in
|
|
your own iCloud Drive.
|
|
|
|
## Key Features
|
|
|
|
- **Workout splits** — organize exercises into reusable routines with custom
|
|
colors and icons. Start with built-in starter splits (Upper Body / Core /
|
|
Lower Body) generated from a bundled exercise catalog.
|
|
- **Exercise library** — a bundled catalog of starter exercises (bodyweight and
|
|
machine-based) to populate your splits.
|
|
- **Run a workout** — start a session from a split, then tap an exercise to run it
|
|
as a paged flow: a **Ready?** lead-in, count-up work phases, count-down rests, and
|
|
a **Finish** page — mirroring the Apple Watch. Swipe a row to mark it complete, or
|
|
swipe to edit its plan (sets/reps/weight or duration) and notes.
|
|
- **Progress tracking** — weight-progression charts per exercise across past
|
|
sessions.
|
|
- **Apple Watch companion** — starting a workout on the iPhone launches the watch
|
|
app straight into it. The watch lists your in-progress workouts; pick one, pick an
|
|
exercise, and run it as a paged flow: a **Ready?** lead-in, count-up work phases,
|
|
count-down rests with final-three-second haptics and auto-advance, and a **Finish**
|
|
page with **One More** and a **Done** that auto-completes after a countdown. A
|
|
phase-dot row (purple work, teal rest) tracks progress. Rest time and the
|
|
auto-finish countdown are configurable; changes sync back to the phone.
|
|
- **Two-way live run** — prop your iPhone up during an Apple Watch workout and it runs
|
|
the same Ready → work/rest → Finish flow with live timers, in step with the watch. It's
|
|
bidirectional: drive from either device — swipe ahead, finish a set, add one — and the
|
|
other follows. Only *human* transitions are sent; automatic ones (a rest timer ending)
|
|
advance both devices independently off shared start times, so they never fight.
|
|
- **iCloud Drive sync** — your data lives as human-readable JSON in your iCloud
|
|
Drive, synced across devices and visible in the Files app. iCloud is required.
|
|
|
|
## Architecture
|
|
|
|
iCloud Drive JSON documents are the **sole source of truth**; a local SwiftData
|
|
store is a rebuildable read-through cache populated exclusively by an
|
|
`NSMetadataQuery` observer (one-way flow: files → observer → cache). The phone is
|
|
the only device that touches iCloud Drive; the Apple Watch is a thin remote that
|
|
round-trips workout changes through the phone via WatchConnectivity.
|
|
|
|
See `REQUIREMENTS.md` for the data model and `CLAUDE.md` for project guidance.
|
|
|
|
## Building
|
|
|
|
The Xcode project is generated with [XcodeGen](https://github.com/yonaskolb/XcodeGen):
|
|
|
|
```sh
|
|
xcodegen generate
|
|
open Workouts.xcodeproj
|
|
```
|
|
|
|
Requires Xcode 26 (iOS 26 / watchOS 26, Swift 6).
|