Skip to content

Mobile redesign: one-scroll dashboard, a header that fits, five real tabs - #225

Merged
henriqueaklein merged 9 commits into
developfrom
redesign/navigation-260806
Aug 7, 2026
Merged

Mobile redesign: one-scroll dashboard, a header that fits, five real tabs#225
henriqueaklein merged 9 commits into
developfrom
redesign/navigation-260806

Conversation

@SirYakoob

Copy link
Copy Markdown

What you hit on a phone today

The dashboard was four panels that each scrolled on their own, so the page
itself could not be scrolled and you saw four small windows instead of a
screen. Every section is now capped and the page scrolls.

The header spent 224px of 342 on one control, because the wallet pill absorbed
whatever the brand left over. It is a 44px icon beside a 44px menu button now,
a fixed 100px cluster, so nothing in the bar competes for width any more.

The bottom bar said More, which is not a place. It now reads Home, Assets,
Swap, Activity, News, and the menu moved to the header.

Assets had no page - View all on a five-row preview led nowhere useful. It
has a screen with search and sort.

A transaction row printed its action inside a 44.5px chip, too narrow for six
of the eight words it could hold, so it clipped the one word it existed to
show. The action leads the subtitle now.

Mock holdings emptied themselves a few seconds after you added them.

Verification

Every gate below was run on this branch, not assumed.

Gate Result
dart format lib test 392 files, 10 changed, committed
flutter analyze No issues found, repo-wide
flutter test 1175 passing, 3 skipped, 0 failing
check_brace_style.sh pass
check_raw_colors.sh pass
check_onboarding_seed_safety.sh pass
check_no_new_key_logging.sh --scan-tree pass
check_agent_rules_sync.sh FAILS - see below

check_agent_rules_sync.sh fails, and it is not this branch. AGENTS.md and
.github/copilot-instructions.md are byte-identical to origin/develop here
(git diff --quiet origin/develop -- on both returns clean), so the drift
shipped with the gate itself in #223. Fixing it means editing the agent rules,
which has nothing to do with this branch, so it is reported rather than folded
in.

develop was merged into this branch today. Two conflicts, both in the
transaction row, and both resolved by combining the two designs rather than
picking one: develop's phone-width shrink is preserved inside the rebuilt
subtitle. A third break had no conflict at all - develop added a third
_body call site while this branch added two required parameters to it, on
different lines - and only the analyzer caught it.

Seven filter-bar assertions changed from 40/183 to 52/243. That is not drift:
develop gave the phone page's filter bar its own row and raised its chips from
32 to the 44pt touch minimum. The old numbers defended title-row headroom that
this surface no longer has to share, and the comment now says the pin protects
the touch target, so a return to 183 reads as the accessibility regression it
would be.

Deliberately not here

  • The header cannot tell two ETH wallets apart. AccountAvatar draws a
    currency icon, and with the wallet name removed nothing else identifies the
    account; the 16px network badge resolves to the same eth.png for ETH on
    Ethereum. The semantic label still names wallet and chain, so this is a
    sighted-user gap rather than a total one. The fix - a two-character monogram
    in the same circle - lives in account_drawer.dart, outside this change.
    Filed as a todo.
  • The mobile bar overflows vertically at about 1.23x Dynamic Type. The
    slot's stack measures 56.85 against 60.00. Pre-existing and pinned by an
    assertion; no label ever truncates horizontally. Not fixed inside a
    navigation change. Filed.
  • The transaction amount column already clips ordinary amounts on a phone -
    real amounts run 86.5 to 136px against 113. Taking width from it was measured
    as strictly worse, so it was left alone. Filed.
  • A pending mint still renders Minte…, a measured 7.7px short. Removing
    the job hash did not touch it, because mint's context is a qualifier and mint
    never printed a hash.
  • The wallet name field still accepts an address. The old header printed
    such a string twice; this header prints no name at all, so the defect no
    longer surfaces there. It is not fixed - import_security_screen.dart still
    stores unvalidated free text. Filed.
  • The Menu is still today's derived sheet. Its redesign is planned, not
    built, and the plan is committed with a superseded-in-part header: it was
    written for a full-screen route, and the menu is staying a bottom sheet
    because the wallet control beside it opens one, and two controls that look
    alike should not behave differently.
  • Bad state: Cannot emit new states after calling close appears in logs.
    Pre-existing and unrelated to anything here.

Reviewing on a device

--dart-define=GW_DEV_TOOLS=true for mock data. Dark mode, phone width. The
two things worth a second look are the transaction subtitle - lead, context
and status must read as ONE line at ONE size, since that line is where the two
branches met - and the day labels on /transactions, where two spacing rules
collided and the structural one was given precedence.

…page

The dashboard used to hold four independently scrolling panels, so a phone
gave you four small windows into four lists and no way to see the page. Every
section is now capped and the PAGE scrolls, which is the only scroll a phone
should have.

Assets gets its own screen behind View all, with search and sort, because a
five-row preview is a summary and not somewhere you can find a token.

GNUS is pinned first everywhere it is listed. That rule existed and phase 25
had quietly demoted it to a tie-break, so a funded wallet could bury its own
native token under whatever happened to be worth more that morning. It now
lives in one comparator that both the panel and the page call, so the two
cannot disagree.

The Assets panel header goes back to the shared section-title component: it
was the one panel drawing its own, and on a phone that read as a different
kind of thing sitting among Compute, Markets and Transactions.

Panel rhythm is symmetric - the gap above a section title now equals the gap
below it. The component's own doc claimed it already did this; it did not, and
the claim is corrected rather than left to mislead the next reader.
The wallet control used to take 224px of a 342px header - more than half the
bar for one control - because it absorbed whatever the brand lockup left. It
is now a 44px icon beside a 44px menu button: a fixed 100px cluster, so the
header stops being a tug of war and the brand keeps its size at every text
scale.

Neither control carries a border. In this palette a fill cannot identify a
control at all - surfaceMenu on the bar measures 1.11:1 - so the glyphs do the
identifying, at 7.54:1 and 19.29:1, which is better than the 3.30:1 edge they
replace.

The bottom bar becomes Home, Assets, Swap, Activity, News. More leaves it, and
the menu button ships in the SAME change rather than after it: removing More
first would have stranded Markets, Web, Feedback and Settings with no way back
on a phone.

Assets is reachable from the bar as well as from the dashboard link, and both
entrances now behave the same way rather than one stacking a page.

Known and deliberate: with the wallet name gone, the avatar draws a currency
icon, so two ETH wallets render the same header. The semantic label still
names the wallet and the chain, so this is a sighted-user gap rather than a
total one. Filed as a todo with the monogram that fixes it.
A transaction row used to print its action in a chip beside the token. On a
phone that chip was 44.5px, too narrow for six of the eight words it could
hold, so it clipped the one thing it existed to show. The action now leads the
subtitle, where the line is long enough for it.

Lead and context are separated by COLOUR rather than by weight or a
separator - textPrimary against textSecondary, 19.4:1 against 6.01:1. That
was the only separation available for zero width, and width is the entire
constraint on that line. One weight step at 13px was tried on device and read
as a single run of text.

The job hash is gone from the subtitle. It identified nothing anyone could act
on and it was eating the room the wording needed. Counterparty addresses stay
on send and receive rows, where they do identify something.

Status moves to a capped tail on the narrow row, and only there: the wide page
already states it in a pill, and printing it twice is worse than either.

Merged with develop's phone-width work rather than over it - the smaller
title, subtitle and gaps it introduced are all preserved here, and the filter
bar keeps the 44pt touch targets that change gave it.
A drawer footer added the phone's full home-indicator inset on top of its own
padding, so on an iPhone the button sat 54pt off the bottom of the sheet with
nothing in the gap. It now caps that inset, which lands it at 40 and leaves
the safe area genuinely clear rather than doubly cleared.

The cap moves to a shared constant, because the splash screen was solving the
same problem with its own copy of the number.
Populating mock data appeared to work and then emptied itself. Two emits were
unguarded. `getCoins` checked the dev flag BEFORE its await and emitted after
it, so a slow fetch - one RPC timing out and CoinGecko rate limiting made it
28 seconds - landed on top of the mocks whenever it finally returned. And
`loadInitial` reset the list with no guard at all, which one accidental
pull-to-refresh was enough to trigger. Worse, the flag stayed set afterwards,
so the other guard then blocked the refetch and the panel just sat empty.

Both guards lead with the `kDebugMode && kShowDevTools` const pair, so release
builds fold them away and the real data path is byte-identical.
…s 171-185

The walk record is the load-bearing file: it separates what Jakub approved
outright from what he decided with reasoning from what was accepted only by
omission, because treating the last group as approval is how a design walk
quietly invents decisions nobody made.

Sketches 171 to 185 with their READMEs, phases 24 and 25, and the quick tasks
behind each change in this branch.

Two plans are written and NOT executed: the Menu page and the bottom-nav
follow-ups. The Menu one is superseded in part - it is built around a
full-screen route, and the menu is staying a bottom sheet, decided after that
plan was written. It is kept for the findings it carries and its frontmatter
says which parts no longer apply.
…ific row

CI's quality job runs on Linux, where `/web` does not exist -
`nav_destinations.dart:67` declares it `visible: !Platform.isLinux`. The test
typed out `Web` as a literal, so it passed on a Mac and failed on the runner
for a reason that was about the runner rather than the code.

The labels now come from `moreDestinations` itself. A platform guard would
have worked too, and its sibling in `mobile_nav_destinations_test.dart` uses
one, but that spreads a single platform rule across two files. Deriving keeps
the rule where it is declared, and the assertion follows any future
conditional destination with no edit.

Settings keeps its own explicit assertion on top of the derived loop. It is
the destination whose loss would be worst and the one the hamburger exists to
keep reachable, so it should not depend on the derivation also being correct.
…dow-wide flag

Jakub on device: the Transactions section on the HOME page renders smaller
than designed since the merge, and his call is to keep our sizes there.

Root cause recorded rather than fixed, because the obvious fix is wrong.
Develop's density pass is gated on `!useDesktopLayout(context)`, which reads
the WINDOW, so on a phone it is true for the dashboard panel as well as for
the page it was written for. Deleting it would fix the panel and undo real
work on the page, including 44pt filter-bar touch targets.

Neither `compact` nor `wide` can separate the two surfaces: the panel is
~376px and the narrow page ~390px. The recommendation is to pass density from
the call site, which already knows.
Jakub, 2026-08-07: everything that goes into the repo has to be English,
always. The team is not Polish-only - Brian owns Android and other people read
this code - and the Polish was almost always the quote explaining WHY a
decision was made, which is exactly the part a reader most needs.

Provenance survives, only the language changes. A Polish quotation becomes an
English rendering that still says who decided it and when, and it is NOT put
in quotation marks, because those were not his words in English.

Left alone on purpose: generated wallet names, network names and filenames
that happen to be Polish, because they are identifiers and measured data
rather than prose. Sketches from July are also untouched at his request; they
are not part of this branch and pulling them in would bloat the diff with
unrelated files.

One correction to how this was done. The first sweep worked from a keyword
list with no diacritics, so it missed eight files - including three under
`lib` and `test` whose quotes were spelled with full Polish characters, and
one sketch whose README was translated while its HTML was not, leaving the
pair half and half. The scope is now checked with two independent patterns,
diacritics and an ASCII vocabulary, over every file this branch touches.
@braianxde
braianxde marked this pull request as ready for review August 7, 2026 19:15
@henriqueaklein
henriqueaklein merged commit 241ad41 into develop Aug 7, 2026
8 checks passed
@henriqueaklein
henriqueaklein deleted the redesign/navigation-260806 branch August 7, 2026 21:26
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