Skip to content

General: Warn when a pod's listening time drops far below its rating - #692

Merged
d4rken merged 3 commits into
mainfrom
feat/battery-runtime-warning
Aug 25, 2026
Merged

General: Warn when a pod's listening time drops far below its rating#692
d4rken merged 3 commits into
mainfrom
feat/battery-runtime-warning

Conversation

@d4rken

@d4rken d4rken commented Aug 25, 2026

Copy link
Copy Markdown
Member

What changed

CAPod already estimated how much of its rated listening time each earbud still reaches, but that number sat in the device details sheet behind the info icon, where almost nobody would find it. Now, when one of your pods has dropped to half its rated listening time or less, a warning appears directly on that device's settings screen. Tapping it opens the details sheet with the per-pod figures.

The warning only appears once there is enough recent evidence behind it: at least eight listening sessions for that pod, with the most recent measurement under 60 days old. Until then nothing is shown, exactly as before, and turning off battery estimates for a device hides it entirely.

The wording also changed from "Battery Health" to estimated listening time. The figure compares measured drain against Apple's published listening rating, and a short runtime can come from loud volume, cold weather or a demanding codec just as easily as from a worn-out cell. Calling it "health" claimed more than the measurement supports.

Technical Context

  • The promotion gate reuses fields already persisted on DrainProfile.LearnedRate (updateCount, updatedAt), so there is no serialization change and no migration, and existing users qualify on data they already have. A richer per-session evidence store was considered and rejected: it would have changed the persisted shape, reset every user's figure, edited the estimator's most defect-prone code path, and centred on a route-verification signal that does not exist yet (see below).
  • The 50% threshold is mid-range rather than late. BatteryEstimator.plausibleForModel rejects any learned listening rate faster than 4x the rated drain (SPEC_BAND_MAX), so the derived figure can never fall below roughly 25%.
  • The banner triggers on the minimum across pods and names the affected one. The figure is deliberately per-pod, since a single failing earbud is exactly what a combined number would mask.
  • The detail sheet and its detailItems construction moved out of the device_info LazyColumn item up to screen scope. Left inside, the banner's tap would set the visibility flag while the only sheet renderer sat in a disposed lazy item, so nothing would open and the sheet would then appear unprompted when scrolling back to the header.
  • Known and deliberately not addressed here: the listening gate in BatteryEstimator uses device.isSystemConnected as a proxy for "audio is routed to these pods", but that flag derives from BluetoothProfile.HEADSET (HFP), not the active A2DP route. A worn-but-unrouted pod can have idle drain learned as listening drain, which biases the figure upward and therefore suppresses warnings rather than causing false ones. Separate change.
  • String keys were left unrenamed and only the English values changed, so the existing translated locale files keep their entries and Crowdin marks them for re-translation.
  • The banner has not been seen rendering on a device: its trigger needs roughly eight real listening sessions with genuine battery drain, so the gate arithmetic is covered by unit tests while the rendering is covered only by Compose previews.

d4rken added 3 commits August 25, 2026 20:31
The per-pod listening-time estimate was only visible behind the info icon on
the device settings header card. A pod that reaches half its rated listening
hours or less now raises a banner on the device settings screen, tapping it
opens the same detail sheet.

A displayed number needs less backing than one that raises a warning, so a
reading is only promoted into the banner when its slot has accumulated at
least 8 listening sessions across its qualifying rates and the newest of
those rates is at most 60 days old. The banner reads the already-gated state
field, so the per-profile battery estimate toggle suppresses it too.

The detail sheet's visibility moves out of DeviceInfoCard so both the info
icon and the banner can open it.
The figure compares observed listening drain against Apple's rated hours, so
it cannot separate a degraded cell from loud volume, cold weather or a hungry
codec. Runtime wording is true either way, "Battery Health" is not.

String keys are kept as they are so the translated locale files aren't
orphaned.
The detail sheet was composed inside the device-info lazy item, so tapping the
battery runtime warning banner after that item had scrolled out of composition
did nothing visible while still setting the visibility flag, which made the
sheet pop up unprompted on scrolling back up. Build the detail items and compose
the sheet at screen scope instead; the card now only reports the tap.

Fixes review finding F1
@d4rken d4rken added the enhancement Add a new feature of improve an existing feature label Aug 25, 2026
@d4rken
d4rken merged commit 865a609 into main Aug 25, 2026
11 checks passed
@d4rken
d4rken deleted the feat/battery-runtime-warning branch August 25, 2026 21:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Add a new feature of improve an existing feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant