Skip to content

fix(today): draw the active ring's own battery in the Liquid header instead of nothing (#2208 second half) - #2374

Merged
ryanbr merged 1 commit into
ryanbr:mainfrom
pipiche38:fix/today-header-ring-battery
Sep 23, 2026
Merged

ryanbr merged 1 commit into
ryanbr:mainfrom
pipiche38:fix/today-header-ring-battery

Conversation

@pipiche38

Copy link
Copy Markdown

#2208 stopped the Liquid Today header drawing the STRAP's charge under an active ring, and the control has shown nothing under a ring since: StrapBatteryDisplay.resolve answered .notActiveDevice for every non-WHOOP active device because it could not tell whose number it held. The ring's own charge was already there — LiveState.ouraBatteryPct on iOS and SourceCoordinator.ouraBatteryPct on Android, both cleared with the link (#2075), both already resolved by LiveConsoleReadout.batteryPercent for the Live console and the Devices list. The header was the one surface still blind to it.

Change

  • iOS StrapBatteryDisplay.resolve takes ringPct + ringCharging (no defaults, for the same reason activeIsWhoop has none): a non-WHOOP active device with a ring charge reported this link is .charge(isRing: true); with none it stays .notActiveDevice, so a generic HR strap or a machine — which never write ouraBatteryPct — keep the control off the header exactly as before. Charging under a ring is the ring's charger state (OuraWearState.charging), never the strap's BATTERY_LEVEL bit.
  • .charge carries isRing so the VoiceOver label names the device the number belongs to: "Ring battery N percent(, charging)" — "Strap battery" over a ring's charge would be the [oura][ui] Today screen still draws the WHOOP's charge under an active Oura ring — #2076 covered the Live Console, Devices and the widget, not Today #2208 misattribution again, in the label instead of the number. Strings in every catalog locale.
  • Android: HeaderBatteryDisplay.resolve, a pure twin of the iOS resolver (minus the charging bit the Android ring never drew), replaces the strapIsActiveDevice gate + raw batteryPct pair on LiquidTodayHeader; LiquidBatteryRing takes isRing for its label (today_ring_battery_percent, every locale).

Design tokens only (the ring's stroke and hues are unchanged); no new colours, fonts or spacing.

Verification

Refs #2208, #2216, #2075.

…nstead of nothing (ryanbr#2208 second half)

ryanbr#2208 stopped the Liquid Today header drawing the STRAP's charge under an active ring, and the
control has shown nothing under a ring since: `StrapBatteryDisplay.resolve` answered
`.notActiveDevice` for every non-WHOOP active device because it could not tell whose number it
held. The ring's own charge was already there - `LiveState.ouraBatteryPct` on iOS and
`SourceCoordinator.ouraBatteryPct` on Android, both cleared with the link (ryanbr#2075), both already
resolved by `LiveConsoleReadout.batteryPercent` for the Live console and the Devices list. The
header was the one surface still blind to it.

- iOS `StrapBatteryDisplay.resolve` takes `ringPct` + `ringCharging` (no defaults, for the same
  reason `activeIsWhoop` has none): a non-WHOOP active device with a ring charge reported this
  link is `.charge(isRing: true)`; with none it stays `.notActiveDevice`, so a generic HR strap
  or a machine - which never write `ouraBatteryPct` - keep the control off the header exactly as
  before. Charging under a ring is the ring's charger state (`OuraWearState.charging`), never the
  strap's BATTERY_LEVEL bit.
- `.charge` carries `isRing` so the VoiceOver label names the device the number belongs to:
  "Ring battery N percent(, charging)" - "Strap battery" over a ring's charge would be the ryanbr#2208
  misattribution again, in the label instead of the number. Strings in every catalog locale.
- Android: `HeaderBatteryDisplay.resolve`, a pure twin of the iOS resolver (minus the charging bit
  the Android ring never drew), replaces the `strapIsActiveDevice` gate + raw `batteryPct` pair on
  `LiquidTodayHeader`; `LiquidBatteryRing` takes `isRing` for its label
  (`today_ring_battery_percent`, every locale).

Verification: `LiquidBatteryDisplayTests` 15/15 under `xcodebuild test` (Strand, macOS), four new
ring cases; `HeaderBatteryDisplayOracleTest` 4/4 - the 60-line expected literal is the verbatim
stdout of the Swift enum compiled standalone (`swiftc -O`) over the whole activeIsWhoop x
connected x strap-% x ring-% grid, plus the named ryanbr#2208/ryanbr#2216 cases; `Strand` (macOS) and
`NOOPiOS` build; `compileFullDebugKotlin` clean; `i18n_audit --ci` (both platforms) and
`doc_comment_lint` green. Display-only - the values come from the same fields the Live console
already shows on hardware.

Refs ryanbr#2208, ryanbr#2216, ryanbr#2075.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QrsZczdGcUyQSJVuYZuwUF
@ryanbr
ryanbr force-pushed the fix/today-header-ring-battery branch from 52d8478 to b4cedef Compare September 23, 2026 04:11
@ryanbr
ryanbr merged commit 971d0d9 into ryanbr:main Sep 23, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants