Skip to content

ADR-0084: Report selection outlives its tooltip; Home keeps one hero

Context

Three W05 review findings shared one cause: transient feedback was carrying persistent meaning. On Reports the selected category lived in the same state as the four-second tooltip, so the timeout also removed View transactions. On Home a missing FX rate made the shared budget summary incomplete, and the hero's "budget unavailable" line appeared even when no budget was configured. The review strip also used an attention-container fill and a filled tertiary button in a different vertical position per breakpoint, so it competed with the monthly hero and moved between wide and narrow layouts.

Decision

Reports selection is persistent until the user or the period changes it. The donut keeps two separate states: the selected slice index and whether the tap tooltip is visible. The tooltip still dismisses after four seconds so it never covers the chart indefinitely; the selected legend row, its Role.Checkbox state and the slice's View transactions action remain. A second tap on the selected row toggles it off, a changed slice set or month clears it, and the existing callback reports exactly those transitions. The drill-down keeps the viewed month and resolves the scope once: a normal slice uses its category id, an uncategorised slice uses UNCATEGORISED_CATEGORY_ID (0), and the merged Other bucket stays month-only (categoryId = null). The drill-down button carries a unique accessible name including the slice label, because the insight card shows the same visible label.

The Home budget marker means a configured budget is unavailable. The shared BudgetSummaryCalculator remains the only owner of limits, spend, percent and availability. Home additionally records whether any positive limit was configured; only then may an incomplete summary render the hero's budget unavailable line. No limit, a zero cleared-limit sentinel, or an unrelated missing FX rate hides the budget line entirely. Spending FX gaps keep their own footnote, exact configured-limit percentages stay exact, and an unconvertible configured limit remains honestly unavailable.

Home has one primary hero and quiet supporting surfaces. The review strip uses AppSurface.grouping with the paired AppSurface.primaryText / AppSurface.supportingText roles and a tonal action, matching the existing manual-capture guidance; it does not introduce a palette or a second strong fill. The revoked-listener warning keeps errorContainer / onErrorContainer because it is a repair error, not ordinary support. Both breakpoints show capture status, then the single review strip, then the hero (and any availability footnote), so the supporting order never changes with width. The hero remains the only AppSurface.hero surface. The Home month control keeps fillMaxWidth only to give its label a bounded width at narrow or large-text sizes; the visible control stays intrinsic between two 48 dp arrows and paints no pill.

Consequences

A selected report category and its drill-down no longer disappear while the user reads the figures, and the timeout has one meaning. A no-budget month can never imply a budget error, while configured-limit failures stay visible. Home's supporting notices remain readable and actionable without competing with the monthly total in light, dark or dynamic colour. The strip's tonal action container is a deliberately low-contrast step against the grouping surface (about 1.2:1); its label clears 4.5:1 and its target is at least 48 dp, which is the affordance M3 tonal buttons rely on rather than a second strong fill. No schema, route, money or dependency contract changes.