Dashboard: Show current charge stats near the top while plugged in - #21
Merged
Conversation
The battery-statistics card sat permanently at the tail of the dashboard, so a live charge was several scrolls below the fold. It now claims the second slot whenever external power is reported, and returns to the tail when unplugged. Promotion is plug-driven only: a device held at its limit reports BATTERY_STATUS_NOT_CHARGING while still connected, so charge status must not gate it. It is also independent of the card's content state — promo, loading and unavailable are promoted too, so the slot can't shift under the user while the stats DB answers. The promoted slot sits below the interrupted-session warning and the access setup guide, which are rarer and actionable. The single "on the charger" rule moves to BatteryReadout.onCharger, shared with the card's presentation mapping. The card keeps one lexical construction site; only its placement is conditional. Every dashboard item gains a stable LazyColumn key: index-keyed items would renumber when the stats card moves and lose their remembered state — plugging in mid-drag would have snapped the alarm slider back. Statistics also lose their settings entry: the dashboard card is now the only way in, so the capture switch lives next to the data it produces. While a session is live the card's own tap deep-links into that session, so the live state carries an explicit "History" action for the past-sessions list; it must not bubble to the card's navigation, which is asserted. With one entry point left, the stats screen's back paths (top-bar and system) both return to the dashboard, so statsOrigin is gone. AmplyNavigationCard's KDoc claimed it must hold no interactive controls, which its own tested "Retry" button already contradicted; it now describes the real contract (surface tap plus at most one small non-bubbling text action). Ordering assertions run at a tall Robolectric qualifier so every compared card is composed — otherwise a failure would mean "scrolled out", not "wrong order" — while above-the-fold assertions stay at the real screen height. A live plug/unplug transition test covers the move itself.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Technical Context
Placement is plug-driven, not content-driven.
statsPromotedreads only the raw battery readout via the newBatteryReadout.onCharger(plugged != 0, null → false), the same ruleStatsCardPresentation.fromuses — deliberately notstatus, because a device holding at its limit reportsBATTERY_STATUS_NOT_CHARGINGwhile still connected. It is also independent of the card's own state, soPromo/Loading/Unavailableare promoted too and the slot cannot shift under the user as the stats DB answers. This partially reverses the fixed-slot decision from #17; the single construction site stays (one lexicalStatsDashboardCard(...), so the supported and unsupported branches cannot drift), only the placement is conditional.Every dashboard item gained a stable
LazyColumnkey. Without keys a lazy list identifies items by index, so the stats card changing slot renumbers everything after it and discards their remembered state — plugging in mid-drag would have snapped the charge-alarm slider back to its persisted value. Keys are unique per render; the pairs that appear in both branches (full charge, reconnect, Shizuku banner) are mutually exclusive.Navigation. With the settings row gone there is one entry point, so
statsOriginis deleted and both back paths — the top-bar action and theBackHandlerbranch — return to the dashboard.detailOriginstays: the session detail is still reached from the dashboard card (live deep-link) and from the list.Card contract.
AmplyNavigationCard's KDoc claimed it must contain no interactive controls, which its own tested "Retry" button already contradicted. It now states the real contract: the surface owns the primary tap plus at most one small trailing text action that must not bubble — asserted for both History and Retry.Review guidance for the tests. Bounds-ordering assertions run under
@Config(qualifiers = "+h2400dp")so every compared card is composed; on the default screen aLazyColumnmay not have composed the far card and a failure would mean "scrolled out", not "wrong order". Above-the-fold assertions deliberately stay at the real screen height, where the fold means something. A plug → unplug transition test drives the move through one live composition and asserts exactly one stats card after each step.Not covered by automated tests: system-back from the statistics screen and its session detail (needs instrumentation) — on the manual list below. Play Store screenshots need no regeneration; their fixtures leave the battery readout unset, so those shots keep the tail placement.
Manual verification
Not yet run on hardware — planned pass: promoted placement plus tap-through to the live session; History → list; unplug → back to the tail; both back paths out of the statistics screen;
adb shell dumpsys battery set ac 1thenset status 4to confirm the plugged-but-not-charging case.