Skip to content

RefWatch v0.3.1

Choose a tag to compare

@Saidiibrahim Saidiibrahim released this 22 Mar 10:29
· 79 commits to main since this release

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 calls handleActiveWorkoutRecovery() 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. A StartTrigger enum (.begin, .proactiveRenewal, .invalidation) tracks why each session was created.
  • Full match snapshot & restore (e309a34): A new ActiveMatchSessionSnapshot codable 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 new AlwaysOnTimerView checks isLuminanceReduced and 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 to workout-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):

  • AppMode enum simplified from 2 cases to 1 (with a backward-compatible decoder migrating persisted .workout to .match)
  • 14 files deleted: WorkoutModeViewModel (986 lines), WorkoutSessionHostView (700 lines), WorkoutRootView, WorkoutHomeView, ModeSwitcherView, WorkoutCrownReturnGesture, and more
  • AppRootView now directly hosts MatchRootView β€” 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 use cardHeadline instead of cardMeta.
  • Team name abbreviations (efa3730): New TeamNameAbbreviationText component 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 from caption to cardMeta weight.
  • Kickoff redesign (3b8c29e): Team selection uses the new TeamScoreBox with 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): CardDetails gained reasonCode, reasonTitle, and isSecondCautionDismissal. MisconductReason now includes minimumSuspensionMatches and regulationReference. Match reports can now cite specific regulations.
  • iOS sheet UX (3a89dfb): New SheetDismissButton component 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