Repository navigation
RefWatch v0.3.1
RefWatch v0.3.1: HKWorkoutSession Match Mode and Session Persistence
74 commits spanning three major workstreams β runtime reliability, product focus, and watch-face usability.
1. Match Mode Runtime Overhaul
Problem: The watch app used WKExtendedRuntimeSession to stay alive during matches. This session type expires after ~10 minutes, and if the referee's wrist drops or the app backgrounds during a 90-minute match, the timer state could be lost. A crash or force-quit meant starting over.
What changed:
- HKWorkoutSession-backed runtime (
c5bd14c): Match Mode now starts an HKWorkoutSession when a match begins. watchOS treats workout sessions as first-class citizens β the system keeps the app resident, and if the process is killed, watchOS callshandleActiveWorkoutRecovery()on relaunch to hand the session back. - Proactive session chaining (
710197f): A renewal timer fires 30 seconds before the extended runtime session expires, seamlessly starting a new one. AStartTriggerenum (.begin,.proactiveRenewal,.invalidation) tracks why each session was created. - Full match snapshot & restore (
e309a34): A newActiveMatchSessionSnapshotcodable struct captures the entire match state β timer persistence, penalty shootout state, and display state β serialized to App Group UserDefaults. On relaunch,MatchLifecycleCoordinator.routeToResumedState()routes back to the correct screen (running, halftime, paused). - Always-On Display support (
50daa01): A newAlwaysOnTimerViewchecksisLuminanceReducedand swaps to a minimal wrist-down display β large time text, no colors, header label only. All three timer faces (Glance, ProStoppage, Standard) now support this. - workout-processing background mode (
c635d2a): Entitlements finalized toworkout-processing(required by HKWorkoutSession).
Why it matters: A referee can now start a match, lower their wrist, have the app background, even have watchOS kill the process β and when they raise their wrist or relaunch, the match resumes exactly where it was.
2. Workout Mode Removal (~3,095 lines deleted)
Problem: The app had two modes β Match Mode and Workout Mode β with a ModeSwitcherView at the root. Workout Mode was a general fitness timer that confused users and diluted the product's purpose.
What changed across 5 commits (b112e9b, c074711, 1c89291, 3c9b68d, 407c99e):
AppModeenum simplified from 2 cases to 1 (with a backward-compatible decoder migrating persisted.workoutto.match)- 14 files deleted:
WorkoutModeViewModel(986 lines),WorkoutSessionHostView(700 lines),WorkoutRootView,WorkoutHomeView,ModeSwitcherView,WorkoutCrownReturnGesture, and more AppRootViewnow directly hostsMatchRootViewβ no mode switching layer- 578 lines of workout tests removed
Why it matters: The app launches straight into match mode. No cognitive overhead. Every screen is purpose-built for officiating, and the removed code eliminates an entire class of mode-related bugs.
3. watchOS UI/UX Redesign (13 commits)
Problem: The watch face was cramped and hard to read at a glance β team names overlapped, scores lacked hierarchy, action buttons were too small, and number/action keys on the keypad looked identical.
Key changes:
- Timer face readability (
d6ed896,3cbc183): Scale factors increased (1.03β1.15x) for match time and remaining time. Minimum scale floor raised to 0.9β0.92 to prevent clipping on smaller watches. Font tiers upgraded β team names now usecardHeadlineinstead ofcardMeta. - Team name abbreviations (
efa3730): NewTeamNameAbbreviationTextcomponent shows 3-letter abbreviations with a long-press gesture to reveal the full name via toast. - Unified TeamScoreBox (
104939e): A new reusable component replaced duplicated score UI across kickoff and match screens, eliminating 41 lines of duplication. - Keypad distinction (
1e540b2): Action keys (Clear, OK) now render without background fill β only number buttons are filled. Instant visual distinction between data entry and control. - Event grid sizing (
d398c9d): Event icon max width 72β80pt, minimum 56β60pt. Labels promoted fromcaptiontocardMetaweight. - Kickoff redesign (
3b8c29e): Team selection uses the newTeamScoreBoxwith selectable outline styling. Confirm button enlarged to 56β64pt diameter. - Enlarged action buttons (
2cb5705,c6cfe68): Full-time buttons spaced out, keypad buttons resized for better tap targets.
Why it matters: On a 45mm watch screen, every pixel counts. The hierarchy is now clear at a glance: prominent match time β secondary score/team info β tertiary actions. Buttons are large enough to hit reliably during a match.
4. Supporting Changes
- SA 2026 Reference Catalog (
b0443de): New Supabase migration with Football SA 2026 competition and team data. iOS users can auto-populate their team library with official federation rosters. - Card metadata hardening (
49afb0f):CardDetailsgainedreasonCode,reasonTitle, andisSecondCautionDismissal.MisconductReasonnow includesminimumSuspensionMatchesandregulationReference. Match reports can now cite specific regulations. - iOS sheet UX (
3a89dfb): NewSheetDismissButtoncomponent standardized all sheet close buttons across the iOS companion app. - Documentation: Architecture docs updated for HKWorkoutSession adoption. Docs migrated to canonical folder structure.
- Tests: Expanded coverage for Match Mode lifecycle routing, runtime renewal races, fallback expiry, and deferred starts.
Full Changelog: v0.1.0...v0.3.1