feat(wallet): Apple-Wallet card expand + v2 "You" tab - #1252
Merged
Conversation
Ports the iOS currency-info revamp (code-ios-app#585) to Android's new UI (gated on FeatureFlag.NewUi; legacy screen untouched). Hero card, action tiles (Give/Convert/Withdraw, single Get when not held, USDF = Convert/Withdraw), per-token Recent, Market Cap + chart, About, created footer, and a scroll-revealed title pill. The app bar is an overlay (chat-style): content fills behind it as the haze source, inset by the measured bar height, with a bg->transparent scrim; back/pill/share are frosted liquid glass (via the optional hazeState on the app-bar chrome). Adds a bounded per-token recent-activity query (MessageDao/MessageDataSource/ActivityFeedCoordinator) surfaced as TokenInfoViewModel.State.transactions. All sizing via grid/type/shape/color tokens.
Replaces the onSizeChanged/measured overlay with a SubcomposeLayout (OverlayTopBarScaffold) that measures the app bar BEFORE the content in the same layout pass, so the hero card gets the correct top inset on the very first frame instead of settling on frame 2. Mirrors the chat screen's ChatInputScaffold (top-bar only). The scrim height is kept off the content inset so it can't shift the content on a later frame.
…pp bar The scrim spanned the full app-bar height, washing content out across the whole bar. Scope it to the status-bar strip plus half the app-bar row, so the hero card dims as it scrolls up behind the frosted chrome (matching iOS) and stays vibrant below the bar's midline. The app bar is measured on its own (status bar excluded) so scrim = statusBar + appBar/2. The scrim never grows the content inset (the scaffold measures the full bar), so there's no jump.
…h over it Port the iOS #587 card-expand to Android: tapping a wallet card flies it to the currency-info hero while the deck reorganises behind it, driven by one progress scalar (:apps:flipcash:card-expand). Deck reorg mirrors iOS TokenCardStack: every non-hero card interpolates linearly from its own current top to a cleared spot and fades out — cards above converge onto the opened card's slot, cards below run off the bottom. Reading each card's own bounds makes it correct at any scroll offset, which fixes hidden cards revealing themselves mid-transition when the deck was scrolled/pinned. Host the expanded detail INSIDE the wallet nav entry (CardExpandHost), matching iOS's WalletScreen structure, so a pushed action screen covers it with the right z-order. The controller stays app-root so its fly-state survives the entry's composition being torn down on push; the hero's fly target is seeded from (and falls back to) the controller's surviving heroBounds, otherwise the card came back invisible after popping from a pushed action. Wire the currency-info action tiles: Give and Withdraw push real screens, Convert opens the buy flow. Give pushes rather than presenting a sheet on v2. Also: - flying hero ramps to full opacity by HeroPhase — opaque before the detail background covers its deck backing (no open dim), while still crossfading on close so the hand-off to the natural-z deck card dissolves instead of snapping - token discovery opens token-info as an ordinary push (asPush) with a back arrow - Convert tile uses the Figma IconArrowBottomTop glyph
The give/chat amount-entry screens pass a fillMaxWidth() token pill as the app bar title but left titleAlignment at its Start default. That used to look centred only by accident: the phantom leading slot was measured unconditionally, so leftIconWidth was never 0 and a Start title got pushed right by roughly a back button's width. Reserving that phantom width is now conditional on the title actually being centred, so with no leading control leftIconWidth is 0 and the title snaps flush to the inset — on the give screen the pill sat 64px left of centre (content centred at 476 against a 540 screen centre). Declare the centring instead of leaning on the leading slot's width. The pill now centres at exactly 540 with or without a back arrow.
The v2 "You" tab is now the menu surface: the viewer's own tip card (tappable to
present full screen) plus "Share as a Link" above the settings list, with the
version footer scrolling in the footer slot. v1 keeps the Settings sheet — title,
close, Add Money / Withdraw tiles and a pinned footer.
Collect the NewUi flag reactively instead of snapshotting it. observe() is a
StateFlow seeded with the flag's DEFAULT (NewUi defaults to true) until DataStore
emits the stored value, so `remember { observe(flag).value }` captured that
default on first composition and froze it — a v1 build rendered the v2 "You"
screen (no close, no money tiles) because the read never saw the stored false.
The app root already collected it properly, which is why only these screens
disagreed with the rest of the app. Same fix applied to the tip card, tips and
token-info screens, which shared the pattern.
The tip card is now owned by the You tab, so the v2 TipCard step is just the
post-profile-setup landing (full-bleed, no settings hamburger) and the "You" tab
routes to the menu. Tip-code preview rendering moves to :shared:bills so the menu
can warm the share preview without depending on the tipping feature.
Also drops the GiveUsdf flag — USDF is giveable via the v2 currency-info tiles,
and the legacy reserve layout offers Withdraw + Deposit only.
…bling v2 The v2 tab bar is a hoisted overlay drawn above the nav content, so the You tab's list needs its height as bottom content padding — otherwise the settings rows and version footer scroll under the bar with no way to clear it. Reserve it via LocalTabBarPadding, which the tab-bar inset decorator only makes non-zero for tab homes. No navigationBarsPadding on the v2 footer: the bar measures itself with that padding already in, so applying it again would double-count. Give the footer its own top spacing too — in the footer slot it scrolls with the list and was sitting flush against the last row's divider. Enabling New UI also used to leave the app on whatever the v1 stack was — the settings sheet the toggle lives in — so v2 rendered the menu as a floating sheet instead of its "You" tab. Re-home onto the target shell's landing screen (You tab for v2, scanner for v1) when the flag is toggled. Order matters: reset the stack BEFORE flipping the flag. Resetting after races the shell swap, and an animated sheet dismiss can't survive it at all — the host driving the dismiss is disposed mid-animation, stranding the sheet on screen. Resetting first means the new shell composes against a stack that already makes sense in it. The reset also has to target the real app-root navigator. Inside a sheet, LocalCodeNavigator is the sheet's own navigator, and that one is built without a parent — so rootNavigator resolves back to itself and the reset only cleared the sheet's inner stack (dropping Lab back to Menu, still in the sheet). The sheet scene publishes its host as LocalSheetNavigator; use that when present.
…ng a bill v2 reaches the give screen as a push from currency-info, not as a sheet, so hide() — which only pops when a Sheet is on the stack — left it up once a bill was presented. Pop instead so the bill presents over the currency-info beneath it. v1 still opens give as a sheet and keeps hide(). The pop is untransitioned. The bill overlay and its scrim are drawn PER nav entry, so an animated pop slides the outgoing give entry's copy of them away while the incoming currency-info entry composes its own — which reads as a flash behind the bill. Swapping in a single frame keeps the scrim continuously up.
bmc08gt
force-pushed
the
feat/wallet-card-expand
branch
from
August 19, 2026 21:41
7a63631 to
b8979de
Compare
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.
Ports the iOS #587 Apple-Wallet card-expand to Android, makes the menu the v2 "You" tab, and fixes a handful of v1/v2 issues found while testing.
Card expand
Tapping a wallet card flies it to the currency-info hero while the deck reorganises behind it, driven by a single progress scalar (
:apps:flipcash:card-expand).The deck reorg mirrors iOS
TokenCardStack: every non-hero card interpolates linearly from its own current top to a cleared spot and fades — cards above converge onto the opened card's slot, cards below run off the bottom. Reading each card's own bounds makes it correct at any scroll offset, which fixes hidden cards revealing themselves mid-transition when the deck was scrolled.The expanded detail is hosted inside the wallet nav entry (matching iOS's
WalletScreenstructure) so a pushed action screen covers it with the right z-order. The controller stays app-root so its fly state survives the entry being torn down on push. The hero's fly target is seeded from — and falls back to — the controller's survivingheroBounds; without that the card came back invisible after popping from a pushed action, since the target was a composition-localrememberthat reset to null.Currency-info action tiles are wired up: Give and Withdraw push real screens, Convert opens the buy flow. Give pushes rather than presenting a sheet on v2.
Also: the flying hero ramps to full opacity by
HeroPhase(opaque before the detail background covers its deck backing, but still crossfading on close so the hand-off to the natural-z deck card dissolves instead of snapping); token discovery opens token-info as an ordinary push with a back arrow; Convert uses the FigmaIconArrowBottomTopglyph.v2 "You" tab
The menu is now the v2 "You" tab — the viewer's tip card plus "Share as a Link" above the settings list, with the version footer scrolling in the footer slot. v1 keeps the Settings sheet (title, close, Add Money / Withdraw tiles, pinned footer). Tip-code preview rendering moves to
:shared:billsso the menu can warm the share preview without depending on the tipping feature. The v2 TipCard step becomes just the post-profile-setup landing.The list reserves the hoisted tab bar's height as bottom content padding so it scrolls clear of the bar, and enabling New UI now re-homes onto the target shell's landing screen instead of leaving the app on the v1 settings sheet (which v2 rendered as a floating sheet).
Drops the
GiveUsdfflag — USDF is giveable via the v2 currency-info tiles.Bug fixes
NewUi leaked into v1.
observe()returns aStateFlowseeded with the flag's default (NewUidefaults to true) until DataStore emits the stored value, soremember { observe(flag).value }captured that default on first composition and froze it — a v1 build rendered the v2 "You" screen with no close button and no money tiles. The app root already collected it properly, which is why only these screens disagreed with the rest of the app. Fixed on the menu, tip card, tips and both token-info screens, which all shared the pattern.Amount-entry title off-centre. The give/chat amount-entry screens pass a
fillMaxWidth()pill as the app bar title but lefttitleAlignmentat itsStartdefault. That only looked centred by accident — the phantom leading slot used to be measured unconditionally, so a Start title got pushed right by roughly a back button's width. Now that reserving it is conditional on the title actually being centred, the pill snapped flush to the inset and sat 64px left of centre. Declaring the centring puts it back at exactly centre with or without a back arrow.Testing
Unit suite green. Card expand, give flow, the v1/v2 menu split, the app-bar centring and both UI-switch directions were verified on an emulator; the centring and tab-bar inset were checked against measured view bounds rather than by eye.