Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions .planning/handoffs/session-2026-08-10-summaries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Session summary - 2026-08-10 (Crypto News feed + Transactions filter)

Window: 2026-08-09 evening to 2026-08-10 early. Branch
`redesign/news-digest-tx-filters-260810`, stacked on `redesign/assets-boxed-panels-260808`.
Draft PR #231. Standup note in the team's flat-bullet chat format below; paste as plain text.

```
Shipped to draft PR #231 (github.com/GeniusVentures/GeniusWallet/pull/231):

Crypto News, phone:
• The grid is gone. On a phone it resolved to two 181px columns, which gave a 16px
headline 147px of line against a 62-character median headline, so nearly every card
was truncated and 30 articles spent 4,248px of grid. It now leads with the hero story
and follows with one digest panel - the same DashboardScrollContainer every other list
page uses - holding the search field, a story count and each remaining article as a
72px-thumbnail row. "Next up" is gone as a band; its three stories are the first three
rows. Wide layout is byte-identical.
• The refresh button renders on desktop only. It exists because pull-to-refresh is
unreachable with a mouse, and that only holds where there is a mouse; on a phone
RefreshIndicator is already over the same feed. Its 40px tap target, not the 32px
title, set the header height, so the header goes 56 to 48.
• The "Updated Xm ago" stamp moved down 1px. GWPageHeader centres a trailing by line
box, and Inter's proportional leading puts the title's ink at 7.93..30.61 and the
stamp's at 11.49..25.03, so it read a pixel high.

Transactions, phone:
• The filter left the list. It was the dashboard panel's bar: four icon-only chips,
five more filters behind an overflow menu, no labels anywhere, names only in a
Tooltip a finger cannot open, and a menu pick left no mark on the page at all - the
list read as unfiltered while showing part of itself.
• It is now a funnel in GWPageHeader.trailing, costing the page zero vertical space,
opening our own ResponsiveDrawer with a GWSelectRow per filter carrying the same
badge mark the rows use plus a live count. All nine filters and All are one gesture
away and every one is named. A live filter tints the trigger and adds a dismissible
chip row with the filter's name and "3 of 10" - the count Assets prints and this page
never had.
• Icons.filter_alt_outlined, not Icons.tune: tune is already Swap's settings glyph, and
the funnel is already this screen's own filtered-empty mark.
• The page filter moved from TransactionsSlimView's State up to TransactionsScreen,
because the trigger sits two widgets above the list. Both pass-throughs take it as an
optional parameter, so the dashboard panel keeps its own filter and its call sites are
unchanged.
• Three corrections found on device: the page title sat 8px lower than every other page
title (a 48x48 IconButton sets the header row's height against the 32px title line -
the trigger is 48x32 now and the page measures 48/0/48, identical to Assets); the
phone background dropped GWMeshBackground for the flat surfaceBase Assets and News
paint (#0B0D12 dark, #DCE0E6 light); "No more transactions" is gone.

Verification:
• dart format 399 files 0 changed, flutter analyze clean, flutter test +1203 ~3 all
passed, check_brace_style / check_raw_colors / check_onboarding_seed_safety /
check_no_new_key_logging all 0.
• check_agent_rules_sync is RED and was red before this branch: AGENTS.md and
.github/copilot-instructions.md have drifted in the lazy-developer-ladder prose.
Neither file is touched here. Someone owns that sync; it should not ride a UI PR.
• Test count 1207 to 1203, accounted for exactly: a 14-test group on the old filter bar
became a 9-test group on the new control, the drawer-padding census gained one, three
end-of-list tests folded to two cap tests, one header-geometry test added. One
assertion has no successor and was deleted rather than faked - it measured the font
size of the terminus label, which no longer exists.

Known and deliberately not fixed:
• The filter drawer will be full-screen height on a phone, ~180px empty below the last
row. EVERY mobile ResponsiveDrawer does this whatever it holds -
_ResponsiveDrawerScaffold returns a Scaffold, which takes constraints.biggest.
Measured: a drawer whose whole body is Text('one line') reports Size(390, 844).
Fixing it means a maxHeight on the component and ~19 call sites to re-check. Worth
its own ticket; it affects every sheet in the app, not just this one.
• _TransactionFilterBar and _FilterChip are now dead code, ~200 lines. Deleting the
narrow page's filter row removed their only LIVE call site: _panel only runs when
page == false, so its "page ? bar : GWViewAllLink" ternary has taken the link arm
since the 2026-08-07 merge. Kept for now because removing them is a separate call.
• The trigger's tap target is 48x32, down from 48x48. 32 clears WCAG 2.2 SC 2.5.8's
24x24 floor and 48dp Android horizontally, but is under Apple's 44pt vertically. That
is the price of the title landing level with the other pages. The alternative is
teaching GWPageHeader to absorb a tall trailing into its own bottom gap, which
touches a component shared with Buy GNUS and Swap.
• Filters still mixes two orthogonal axes - seven types and two statuses in one enum
with single-value selection - so picking Pending un-picks Sent and "my failed sends"
cannot be asked. Measured in sketch 191: Failed alone returns 2 rows, Sent + Failed
returns 1. Sketch 191-F7 is the design. Model change, not a filter treatment.
• Mint is the only filter whose mark is not a Material icon but a stroked SVG asset at
stroke-width 3.2, so it reads heavier than everything beside it at any size. True in
the shipped app. Recorded in sketch 193, not fixed silently.
• The "Updated" stamp can lie: _load stamps on whenComplete while the API returns its
cache untouched for two minutes, so a refresh in that window says "Updated now"
having fetched nothing. Sketch 194 finding 3.

Design record:
• Sketches 189 to 195 committed. 189 news feed (scheme C shipped), 190 Transactions in
the Assets language (C chosen), 191 and 192 two rounds of filter treatments, 193 the
corrections round, 194 the news freshness stamp (A shipped), 195 the filter design
that shipped.
• Three corrections recorded there rather than quietly fixed: 188/190/191/192 drew
hand-made filter glyphs instead of the shared badgeSpec table, so their marks were
stroked where the app's are filled and vertical where the app's are diagonal;
188/190 drew a count on each filter chip that the code has never rendered; 191/192
invented a bottom sheet instead of using ResponsiveDrawer. Layout findings stand, but
any impression they invited about how the control felt was formed against wrong marks.

Base branch note:
• #231 is stacked on #230 (assets-boxed-panels), which is on #227 (row-rhythm).
Targeting develop directly would drag ~50 commits already in review into the diff.
Retarget once the parents land.
```
103 changes: 103 additions & 0 deletions .planning/sketches/189-news-mobile-feed/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
---
sketch: 189
name: news-mobile-feed
question: "What is the Crypto News feed on a phone, once the desktop magazine's grid stops working there?"
winner: "C"
tags: [mobile, ios, news, feed, magazine, grid, density, cards, search, topics, keyword-classifier, rss, code-grounded, follows-100, follows-101, follows-102, follows-031]
---

# Sketch 189 - Crypto News on a phone

http://localhost:8899/189-news-mobile-feed/

Jakub, 2026-08-09: *look at Crypto News, see how it looks and what functions we have in the code, then
design me an adjustment for how the mobile app looks - I think there should be some changes there.
Three or four designs, based on our base components.*

**Decided the same day: scheme C.** Jakub, on seeing the set: *definitely design C. I would just like
the header title to be the same as in Assets - unless you have actually already unified it everywhere.
Keep the components we have, so that we do not introduce anything new unless it is essential.*

## Real content, not placeholder

The 30 items CoinTelegraph's RSS returned on 9 Aug 2026 - real headlines, real deks, real photo URLs,
real timestamps - pulled at build time and inlined. Ages are computed against a fixed `NOW`
(2026-08-09T12:30Z) by `shortTimeAgo`, ported verbatim from `news_article.dart:10-25`, so the sketch is
deterministic across reloads.

## What the phone gets today, measured

`crypto_news_screen.dart` is 695 lines and every line of it is a good desktop page. Three things break
in the translation to 390pt:

| Piece | Phone geometry | Source |
| --- | --- | --- |
| Frame | gutter 6, title gap 24 -> content **378px** | `breakpoints.dart:32-41` |
| Hero | photo 16:9 = 213px, + text ~= **362px** | `:481` `AspectRatio(16/9)` |
| Next up | title + 3 numbered rows ~= **290px** | `:494-522` |
| Grid | `(378/360).ceil()` = **2 cols**, tile **181 x 312** | `:396-404` |
| Tile text width | 181 - 2 borders - 32 padding = **147px** | `:609` `EdgeInsets.all(space8)` |
| Grid block alone | 13 rows x 312 + 12 x 16 = **4,248px** | fixed heights, exactly computable |

1. **The headline does not fit its own tile.** `titleMd` is 16px with 147px of line - roughly 30
characters in two lines. The median headline in the live feed is **62 characters**, the longest 76.
Nearly every tile ellipsises, and a truncated headline is the one thing a news card exists to
deliver.
2. **One object, three card languages.** `_HeroCard`, `_NextUpRow` and `_NewsGridCard` draw one model
with five fields three ways. Side by side on a desktop that reads as editorial hierarchy; stacked on
a phone it reads as three different lists.
3. **The page is roughly six viewports long** against a 628px scroll area, and the cost is **164px of
page per article** (two per 328px grid row) for a headline the tile then truncates.

Smaller, and separate: the header's refresh `IconButton` (`_UpdatedStamp`, `:248`) exists, by its own
comment, because "pull-to-refresh alone is unreachable with a mouse". On a phone there is no mouse and
`RefreshIndicator` is mounted at `:174`. The **stamp** beside it keeps its job either way. Left as a
toggle (`MOBILE HEADER`) rather than decided - it is not part of C.

## The data ceiling, stated once

`NewsArticle` has exactly five fields: `title`, `link`, `description` (-> `dek`), `pubDate`,
`imageUrl`. The RSS carries **no category, no author, no source, no read state**. Any design offering
topics has to derive them locally. Scheme D does, and pays for it in the open.

## Variants

- **Today** - the control, not a candidate: `crypto_news_screen.dart` rendered at phone width.
- **A: Digest** - no photos at all. One panel, 30 headline rows, the app's own row rhythm. Shortest
page, fewest components, and the tab becomes indistinguishable in language from Assets and Activity.
Rejected on what it costs: a news product without pictures reads like a log.
- **B: Thumb list** - one card language, photos kept at a 72px square. The headline gets 264px of line
instead of 147. Rejected as a whole page for one reason only: thirty identical rows have **no first
item**, and an editorial feed wants one.
- **C: Lead + digest** ★ **CHOSEN** - the hero survives (it is the one piece of today's design that
works at 390pt), everything behind it becomes B's rows in one panel. Search moves inside the panel,
below the hero, so the first screen is a story rather than a search field.
- **D: C + topics** - C plus a keyword-derived topic track and a "new since you last looked" divider.
Not taken now. The divider is cheap and exact (one `lastOpenedAt` string in the Hive box the news
cache already uses); the topics are a `RegExp` classifier that is wrong sometimes and deserves its
own decision against a week of real feed, not one day of it.

## Why C won, in one line

It is the only scheme that keeps a first impression **and** fixes all three defects, and it deletes two
of the three card components rather than all three.

## What to look for

- **Today** first, with **RULER** on: read the second column of tiles and count the ellipses.
- The **measured page height** under each phone. It is `scrollHeight`, read from the live DOM after
render - not a number typed into the notes. Every photo slot has a CSS-fixed height or aspect-ratio,
so the figure is final before a single image loads and does not move as the network fills them in.
- **NO PHOTOS** on B and C: the live feed does ship articles with a null `imageUrl`, and this is how
each scheme degrades.
- Search states: **Search hit** keeps the hero frozen and reports in the panel; **No match** shows the
inline line, never a blanked page. That is today's shipped rule (`:176-184`), preserved.

## Provenance

Colours verbatim from `gw_colors.dart` dark(); spacing from `genius_wallet_consts.dart`; row rhythm
from `gw_row_rhythm.dart` (wall 8, icon 38, icon-to-text 8, separator 12/1/12); page frame from
`GeniusBreakpoints.pageGutter` / `pageTitleGap`; title inset from `gwPageHeaderContentInset`
(1 + `space3` + `space4` = 15 at phone). Inter inlined from the shipping TTFs. `node --check` clean;
div balance 0; rendered in jsdom with **zero script errors** across all five schemes with every control
exercised (46 clicks).
1,056 changes: 1,056 additions & 0 deletions .planning/sketches/189-news-mobile-feed/index.html

Large diffs are not rendered by default.

Loading