Open the Dictionary, Saved, Settings or the coffee tree from a tab, and the bar across the top is Flutter's stock one: a solid strip with a back arrow and a small title in it, sitting above the page and never changing.
The design's is a different thing. The page carries its own large title, the way a tab root does since #441. The bar over it is invisible while the page is at the top — just a back arrow floating there — and as you scroll it fades in: the page blurred and tinted behind it, a hairline along the bottom, and a small copy of the title sliding up on the left to replace the large one that has gone under it.
Fifteen screens wear the stock bar today (grep -l 'AppBar(' lib/).
Why this is its own ticket
#245 put both halves of this in Out of Scope as one effort: "Pushed pages keep their own AppBar for now; unifying them into the design's SubHeader shape is the same effort as the collapse styling." #441 built the tab half and ruled that this half is split out. The reason, recorded here so it does not go quiet the way the first half did:
- The tab half moved the header out of the shell's layout and over the tab, which pushed the status-bar inset into all four tab roots and gave each one a large title. One seam, four screens.
- This half is a different seam and fifteen screens, and it brings a problem the tab half does not have: a page that swaps its content inside the same scroller — a dictionary category you drill into, a term that links to another term — jumps back to the top while the bar still thinks it is scrolled, leaving a small title stacked on top of an un-scrolled large one. The design solves it with a
resetKey that clears the scroll offset and the flag together.
- Landing both at once would have put two unrelated things at risk in one review.
What #441 leaves for this to use
HeaderChrome (lib/app/header_chrome.dart) is the bar itself — invisible at rest, then tinted, blurred and hairlined, with the short fade below it — and it takes its height from whoever mounts it. HeaderCompactTitle is the small title that slides in. So this composes what is already there instead of writing a second copy, which is what #245 meant by "one effort".
What the design has that the app has not
Its SubScreenHeader is that same bar at height 96, carrying a back or close control, the small title, and optional controls on the right.
The room it leaves under itself is per page, not one number. 108 where the page opens on a large title; 84 on the coffee tree and the streak, and 100 on the grove, which open on a drawing instead. The scroll threshold varies too: 40 everywhere except the Saved shelf, which the design gives 72.
It has two variants. The circled back control — so both ends of the bar carry the same weight — belongs here: the design rings it on the term page, which is the one bar with a control at each end. The pinned mode, which stays filled and titled for a page with no large title to collapse, does not: its only host in the design is the Roasty dress-up screen, which this app has not built. The two pages here that open on a hero — the streak and the grove — are not that case either; the design passes them the ordinary scrolled flag. So it is not ported, and sub_header.dart says why.
Acceptance criteria
Resolution
Shipped in PR #526.
Two things the ticket had wrong, both found by reviewing against the design rather than against the ticket. The scroll pad and the threshold are per page, not the single pair this ticket quoted — the tree and the streak open at 84 and the grove at 100, and the Saved shelf waits until 72 where everything else waits until 40. The pinned variant has no host here and is not ported; the reason is above and in sub_header.dart.
Three things came with it because the change made them cheap or made them wrong to leave: HeaderChrome and HeaderCompactTitle moved into lib/core/widgets/ (a feature screen may not import the app layer), ScrollFlagScope took over the scroll hook FloatTopbar had its own copy of, and the compact title stopped drawing an empty eyebrow line — which the design never draws and no caller had needed until now.
The six full-screen flows that still draw an AppBar are #525.
Open the Dictionary, Saved, Settings or the coffee tree from a tab, and the bar across the top is Flutter's stock one: a solid strip with a back arrow and a small title in it, sitting above the page and never changing.
The design's is a different thing. The page carries its own large title, the way a tab root does since #441. The bar over it is invisible while the page is at the top — just a back arrow floating there — and as you scroll it fades in: the page blurred and tinted behind it, a hairline along the bottom, and a small copy of the title sliding up on the left to replace the large one that has gone under it.
Fifteen screens wear the stock bar today (
grep -l 'AppBar(' lib/).Why this is its own ticket
#245 put both halves of this in Out of Scope as one effort: "Pushed pages keep their own
AppBarfor now; unifying them into the design'sSubHeadershape is the same effort as the collapse styling." #441 built the tab half and ruled that this half is split out. The reason, recorded here so it does not go quiet the way the first half did:resetKeythat clears the scroll offset and the flag together.What #441 leaves for this to use
HeaderChrome(lib/app/header_chrome.dart) is the bar itself — invisible at rest, then tinted, blurred and hairlined, with the short fade below it — and it takes its height from whoever mounts it.HeaderCompactTitleis the small title that slides in. So this composes what is already there instead of writing a second copy, which is what #245 meant by "one effort".What the design has that the app has not
Its
SubScreenHeaderis that same bar at height 96, carrying a back or close control, the small title, and optional controls on the right.The room it leaves under itself is per page, not one number. 108 where the page opens on a large title; 84 on the coffee tree and the streak, and 100 on the grove, which open on a drawing instead. The scroll threshold varies too: 40 everywhere except the Saved shelf, which the design gives 72.
It has two variants. The circled back control — so both ends of the bar carry the same weight — belongs here: the design rings it on the term page, which is the one bar with a control at each end. The pinned mode, which stays filled and titled for a page with no large title to collapse, does not: its only host in the design is the Roasty dress-up screen, which this app has not built. The two pages here that open on a hero — the streak and the grove — are not that case either; the design passes them the ordinary scrolled flag. So it is not ported, and
sub_header.dartsays why.Acceptance criteria
HeaderChrome, not a second copy of it. Nine screens through oneSubScreenScaffold; asserted intest/widget/core/widgets/sub_screen_scaffold_test.dart, andtest/unit/pushed_pages_wear_the_design_bar_test.dartstops a tenth hand-rolling its ownScrollFlagScope.resetKeyclears the flag and keys the body, so both halves go together; covered inscroll_flag_scope_test.dartand through the scaffolddart format,flutter analyze, the metrics gate and the full suite (2578) clean, with a changelog bulletResolution
Shipped in PR #526.
Two things the ticket had wrong, both found by reviewing against the design rather than against the ticket. The scroll pad and the threshold are per page, not the single pair this ticket quoted — the tree and the streak open at 84 and the grove at 100, and the Saved shelf waits until 72 where everything else waits until 40. The pinned variant has no host here and is not ported; the reason is above and in
sub_header.dart.Three things came with it because the change made them cheap or made them wrong to leave:
HeaderChromeandHeaderCompactTitlemoved intolib/core/widgets/(a feature screen may not import the app layer),ScrollFlagScopetook over the scroll hookFloatTopbarhad its own copy of, and the compact title stopped drawing an empty eyebrow line — which the design never draws and no caller had needed until now.The six full-screen flows that still draw an
AppBarare #525.