Skip to content

Restore recognizable Android dashboard metric icons - #506

Open
kavemang wants to merge 3 commits into
ryanbr:mainfrom
kavemang:fix/dashboard-metric-icons-150
Open

kavemang wants to merge 3 commits into
ryanbr:mainfrom
kavemang:fix/dashboard-metric-icons-150

Conversation

@kavemang

@kavemang kavemang commented Jul 16, 2026 •

Copy link
Copy Markdown

Refs #150 and #151.

Uses distinct static metric glyphs instead of vessels in Android Today's Recovery Vitals and dashboard-card rows when Ring gauges on Today is off. HRV, resting HR and respiratory rate retain their metric palette tints and exact numeric labels.

The existing preference keeps its full scope: when enabled, the hero, Recovery Vitals rows and dashboard cards all render their existing rings. The Settings label, persisted values and default are preserved. The ring fraction helper and argument wiring are restored from current main, so users who chose rings keep the same displays; the new glyphs are the alternative when rings are disabled. No new colors, fonts or spacing are introduced by the review fix; the existing ring and glyph dimensions are retained.

This is an Android surface change; the existing Apple presentation and shared analytics are unchanged.

Validation: a private Kotlin harness passed 24 cases using the actual two row-selection blocks with framework stubs, covering both preference values and absent/out-of-range fractions. Source comparison verified all three preference readers and a byte-identical current-main fraction helper. Comment hygiene, diff-scoped i18n and whitespace passed. Guarded parity regeneration passed (289 known findings); all four expected checks passed at d55c40f8906a25efcd9c8716a8bee6fc0c9331ae: Android APK/full unit suite, Tools Python, hygiene and i18n. The complete roster and unchanged head were rechecked. The private harness does not compile Compose or establish on-device rendering.

@kavemang
kavemang force-pushed the fix/dashboard-metric-icons-150 branch from 8c43a62 to 4032152 Compare July 16, 2026 07:22
@kavemang
kavemang marked this pull request as ready for review July 16, 2026 07:46
@digitalerdude

Copy link
Copy Markdown

Same as I just noted on #508: this i18n coverage failure is the stale AppChangelog.kt literal from the 9.0.1 release, already fixed on main by #514. The check hasn't re-run since (base-branch changes don't retrigger pull_request workflows), so it should clear on a fresh push or a manual re-run — nothing in this PR's own diff is at fault.

#524 proposes a fix so this doesn't happen to unrelated PRs again.

digitalerdude added a commit to digitalerdude/noop that referenced this pull request Jul 17, 2026
…variant

ci_check() audited the whole merged tree unconditionally once the ryanbr#453
backlog closed, ignoring base_ref entirely. That means a transient
regression on main (the 9.0.1 release generating a raw AppChangelog.kt
literal, fixed by ryanbr#514) red-flagged every open PR whose diff never
touched the offending file — and those PRs stayed red, since a
pull_request-triggered workflow doesn't re-run just because main
changed. ryanbr#508 and ryanbr#506 are still showing that stale failure right now,
over 5 hours after ryanbr#514 fixed main.

Restores the base_ref diff (Android side already had the git_show/
literals_at_ref scaffolding for this, just unused) across every check:
hardcoded literals, missing-translation keys, and format-string
mismatches, on both platforms. A violation already present on base_ref
isn't this PR's fault and no longer fails it; existing debt is still
printed for visibility. Today that's zero everywhere, so the practical
behavior on a healthy main is unchanged — this only changes what
happens when main itself regresses.
digitalerdude added a commit to digitalerdude/noop that referenced this pull request Jul 17, 2026
…variant

ci_check() audited the whole merged tree unconditionally once the ryanbr#453
backlog closed, ignoring base_ref entirely. That means a transient
regression on main (the 9.0.1 release generating a raw AppChangelog.kt
literal, fixed by ryanbr#514) red-flagged every open PR whose diff never
touched the offending file — and those PRs stayed red, since a
pull_request-triggered workflow doesn't re-run just because main
changed. ryanbr#508 and ryanbr#506 are still showing that stale failure right now,
over 5 hours after ryanbr#514 fixed main.

Restores the base_ref diff (Android side already had the git_show/
literals_at_ref scaffolding for this, just unused) across every check:
hardcoded literals, missing-translation keys, and format-string
mismatches, on both platforms. A violation already present on base_ref
isn't this PR's fault and no longer fails it; existing debt is still
printed for visibility. Today that's zero everywhere, so the practical
behavior on a healthy main is unchanged — this only changes what
happens when main itself regresses.
digitalerdude added a commit to digitalerdude/noop that referenced this pull request Jul 19, 2026
…variant

ci_check() audited the whole merged tree unconditionally once the ryanbr#453
backlog closed, ignoring base_ref entirely. That means a transient
regression on main (the 9.0.1 release generating a raw AppChangelog.kt
literal, fixed by ryanbr#514) red-flagged every open PR whose diff never
touched the offending file — and those PRs stayed red, since a
pull_request-triggered workflow doesn't re-run just because main
changed. ryanbr#508 and ryanbr#506 are still showing that stale failure right now,
over 5 hours after ryanbr#514 fixed main.

Restores the base_ref diff (Android side already had the git_show/
literals_at_ref scaffolding for this, just unused) across every check:
hardcoded literals, missing-translation keys, and format-string
mismatches, on both platforms. A violation already present on base_ref
isn't this PR's fault and no longer fails it; existing debt is still
printed for visibility. Today that's zero everywhere, so the practical
behavior on a healthy main is unchanged — this only changes what
happens when main itself regresses.
digitalerdude added a commit to digitalerdude/noop that referenced this pull request Jul 25, 2026
…variant

ci_check() audited the whole merged tree unconditionally once the ryanbr#453
backlog closed, ignoring base_ref entirely. That means a transient
regression on main (the 9.0.1 release generating a raw AppChangelog.kt
literal, fixed by ryanbr#514) red-flagged every open PR whose diff never
touched the offending file — and those PRs stayed red, since a
pull_request-triggered workflow doesn't re-run just because main
changed. ryanbr#508 and ryanbr#506 are still showing that stale failure right now,
over 5 hours after ryanbr#514 fixed main.

Restores the base_ref diff (Android side already had the git_show/
literals_at_ref scaffolding for this, just unused) across every check:
hardcoded literals, missing-translation keys, and format-string
mismatches, on both platforms. A violation already present on base_ref
isn't this PR's fault and no longer fails it; existing debt is still
printed for visibility. Today that's zero everywhere, so the practical
behavior on a healthy main is unchanged — this only changes what
happens when main itself regresses.
digitalerdude added a commit to digitalerdude/noop that referenced this pull request Jul 27, 2026
…variant

ci_check() audited the whole merged tree unconditionally once the ryanbr#453
backlog closed, ignoring base_ref entirely. That means a transient
regression on main (the 9.0.1 release generating a raw AppChangelog.kt
literal, fixed by ryanbr#514) red-flagged every open PR whose diff never
touched the offending file — and those PRs stayed red, since a
pull_request-triggered workflow doesn't re-run just because main
changed. ryanbr#508 and ryanbr#506 are still showing that stale failure right now,
over 5 hours after ryanbr#514 fixed main.

Restores the base_ref diff (Android side already had the git_show/
literals_at_ref scaffolding for this, just unused) across every check:
hardcoded literals, missing-translation keys, and format-string
mismatches, on both platforms. A violation already present on base_ref
isn't this PR's fault and no longer fails it; existing debt is still
printed for visibility. Today that's zero everywhere, so the practical
behavior on a healthy main is unchanged — this only changes what
happens when main itself regresses.
ryanbr added a commit that referenced this pull request Aug 1, 2026
Effort was resolved independently in several places and only the hero ring
knew about the live in-progress value. The Key Metrics tile and the HR
chart's edge badge read DailyMetric.strain straight off the daily row, which
is rewritten only when the heavy daily pass runs. The reporter's morning
showed 2.3 on the ring and 0.5 in both of the others, with the HR trace
climbing from about 09:00 and the screenshot taken at 12:22 — the row
predated the whole morning. Recovery and Rest matched everywhere precisely
because neither has a live path.

Not a 9.3.0 regression: the live hero landed in v4.0.1 on 15 June and the
tile has read the stored column unchanged since 14 June. #963 made Effort
track an active morning more closely, which widened the gap enough to see.

StrainScorer.effectiveEffort(live:stored:) is now the one rule, Swift and
Kotlin, with the twin test suites pinning it. The MAX in it is not a
tie-break but the never-drop floor from #489/#506, where a sparse-HR live
under-read replaced a real 38.3 with 0 — worth naming, because it is the
part someone would 'simplify' into preferring live.

Android: resolved once in TodayScreen and threaded to MetricGrid and
HeartRateTrendCard, alongside the resolved values those already take
(caloriesForDay, importedStepsForDay). The near-zero Effort caption had a
fourth hand-rolled copy of the same expression; it now uses the shared one
and keeps returning null for past days so the caption stays today-only.

iOS already had effortStrain() as the single point, and its gauge and
near-zero note used it; effortMarker and the Effort StatTile reached past it
to the row. Both now resolve through it, and it delegates to the shared rule.
simoncad7 pushed a commit to simoncad7/noop that referenced this pull request Aug 17, 2026
…ryanbr#1006)

Effort was resolved independently in several places and only the hero ring
knew about the live in-progress value. The Key Metrics tile and the HR
chart's edge badge read DailyMetric.strain straight off the daily row, which
is rewritten only when the heavy daily pass runs. The reporter's morning
showed 2.3 on the ring and 0.5 in both of the others, with the HR trace
climbing from about 09:00 and the screenshot taken at 12:22 — the row
predated the whole morning. Recovery and Rest matched everywhere precisely
because neither has a live path.

Not a 9.3.0 regression: the live hero landed in v4.0.1 on 15 June and the
tile has read the stored column unchanged since 14 June. ryanbr#963 made Effort
track an active morning more closely, which widened the gap enough to see.

StrainScorer.effectiveEffort(live:stored:) is now the one rule, Swift and
Kotlin, with the twin test suites pinning it. The MAX in it is not a
tie-break but the never-drop floor from ryanbr#489/ryanbr#506, where a sparse-HR live
under-read replaced a real 38.3 with 0 — worth naming, because it is the
part someone would 'simplify' into preferring live.

Android: resolved once in TodayScreen and threaded to MetricGrid and
HeartRateTrendCard, alongside the resolved values those already take
(caloriesForDay, importedStepsForDay). The near-zero Effort caption had a
fourth hand-rolled copy of the same expression; it now uses the shared one
and keeps returning null for past days so the caption stays today-only.

iOS already had effortStrain() as the single point, and its gauge and
near-zero note used it; effortMarker and the Effort StatTile reached past it
to the row. Both now resolve through it, and it delegates to the shared rule.
@kavemang
kavemang force-pushed the fix/dashboard-metric-icons-150 branch from 53ae399 to f0fdc42 Compare September 25, 2026 08:50
@kavemang
kavemang force-pushed the fix/dashboard-metric-icons-150 branch from f0fdc42 to 51f7093 Compare September 28, 2026 20:28
@ryanbr

ryanbr commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Thanks @kavemang. The legibility argument holds up: the vessels share one silhouette, so HRV and Resting HR sat next to each other as two nearly identical shapes once the glass treatment desaturated their tints, which is exactly the complaint in #150. Distinct glyphs settle it, and the tints still come from Palette.metricCyan, metricRose and accent, and dropping the fraction denominators loses nothing real since HRV over 120, RHR over 100 and resp over 24 were arbitrary scales sitting beside the exact number anyway.

One thing the description does not mention, and it is user-visible.

"Ring gauges on Today" quietly covers a third of what it used to

On main, NoopPrefs.todayRingGauges has three readers in TodayScreen.kt: the hero at 3375, the Recovery Vitals row at 3847, and the per-card gauge at 4590. This patch removes the last two, leaving one.

The setting itself stays. SettingsScreen.kt still shows it at 1700 under l10n_settings_screen_ring_gauges_on_today_7a532de2, still labelled "Ring gauges on Today". So after this a wearer who turns it on or off finds it governs the hero and nothing else, while the label still promises Today as a whole. The description calls the per-card plumbing "obsolete", which reads like the intent, but a live preference losing two of its three surfaces is a product change rather than a cleanup, and it is not stated anywhere in the PR.

Three ways to settle it. The first keeps the choice everyone already made:

  • honour todayRingGauges in these rows as well: rings when it is on, the new glyphs when it is off. The legibility problem you are solving is the glass-desaturated vessel, so the fix only needs to be the default rather than the only option.
  • or narrow the label to name what it actually governs, so the control and its effect agree.
  • or retire the setting deliberately, which means the Settings row and its string go too, and is worth saying out loud rather than arriving as a side effect.

I have no objection to the glyphs becoming the default. It is the silent narrowing of a switch somebody may have deliberately turned on that I would rather not merge without it being a decision.

Refs #150, #151

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.

3 participants