Skip to content

feat(tokens): replace Get with Buy In, swap Withdraw for Buy More - #1341

Merged
bmc08gt merged 2 commits into
code/cashfrom
feat/token-info-buy-in-labels
Aug 27, 2026
Merged

feat(tokens): replace Get with Buy In, swap Withdraw for Buy More#1341
bmc08gt merged 2 commits into
code/cashfrom
feat/token-info-buy-in-labels

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Token info led with "Get" for a token you don't hold and offered Give/Convert/Withdraw for one you do. Withdrawal isn't the action someone reaches for from a token's page, and there was no way to add to a position you already hold without backing out to the buy flow.

  • Unowned: the single tile reads "Buy In", same OnBuy(shortfall) dispatch as before.
  • Held: Give · Buy More · Convert. Withdraw drops, Convert takes its slot, and "Buy More" takes the middle with the same dispatch as the unowned tile.
  • Dollars: unchanged at Give · Convert · Withdraw. There is no buying more of the cash reserve, and cashing out is what people come to that screen for. CurrencyActionTiles branches on tokenMint == Mint.usdf.

action_get had a single call site and is replaced by action_buyIn; action_buyMore already existed.

Icons. The Buy In / Buy More tiles use ic_arrow_down, exported from Figma's IconArrowDown (node 9536:8434). The Withdraw tile has no design asset to pull: the file's only IconArrowUp is the 15.8px square-cap market-cap indicator, a different family from the 28px round-cap tile glyphs, and the tile row the design draws (node 9631:2168) has no Withdraw tile at all — it puts Withdraw in a full-width text button instead. So ic_arrow_up_large is ic_arrow_down reflected about y=14, which matches the family exactly. The _large suffix is there because ui/components already owns a 20dp ic_arrow_up for the chat send button; a second drawable by that name in a module on the same classpath would silently win the resource merge.

Worth a second opinion on two things: the mirrored asset, if a designer would rather add a real 28px IconArrowUp to the file; and the fact that withdrawal is no longer reachable from a non-Dollars token's page. AppRoute.Transfers.Withdrawal still exists and is reachable elsewhere, but I didn't audit every entry point — if this tile was the primary way in, that path is gone for tokens.

Buy flow titles

SwapEntryScreen and BuyReceiptScreen were both titled "Get", so tapping a tile opened a screen that named the action something else. Both now derive the title from state.isBuyingMore, and the payment-source row reads "Buy with". Held is the same test the tile row uses — an existing token account or a positive balance — so the tile and the screen it opens always agree; SwapViewModel picks the account up from AccountController.observeHasAccountFor, which outlives a balance that has gone to zero.

title_get and label_getWith are dropped. "You Get" on the receipt breakdown is left alone; it names a leg of the trade, not the flow.

Matches code-payments/code-ios-app#671, which makes the same change on iOS.

@bmc08gt bmc08gt self-assigned this Aug 27, 2026
@github-actions github-actions Bot added area: tokens Token accounts, balances, token info type: feature New functionality area: crypto Solana, keys, encryption, signing labels Aug 27, 2026
Token info led with "Get" for a token you don't hold and offered
Give/Convert/Withdraw for one you do. Withdrawal isn't the action someone
reaches for from a token's page, and there was no way to add to a position you
already hold without backing out to the buy flow.

- Unowned: the single tile reads "Buy In", same OnBuy(shortfall) dispatch.
- Held: Give / Buy More / Convert. Withdraw drops, Convert takes its slot, and
  "Buy More" takes the middle with the same dispatch as the unowned tile.
- Dollars is the exception and keeps Give / Convert / Withdraw. There is no
  buying more of the cash reserve, and cashing out is what people come here for.

action_get had one call site and becomes action_buyIn; action_buyMore already
existed. The tiles get the design's exported icons: ic_arrow_down is Figma's
IconArrowDown (node 9536:8434), and ic_arrow_up_large mirrors it vertically for
the Withdraw tile, which the design has no glyph for — its only IconArrowUp is
the 15.8px square-cap market-cap indicator, and the tile row it draws (node
9631:2168) has no Withdraw tile. The _large suffix avoids ui/components' 20dp
ic_arrow_up, used by chat send.
@bmc08gt
bmc08gt force-pushed the feat/token-info-buy-in-labels branch from 328fe8e to 34d2e16 Compare August 27, 2026 16:14
The amount and receipt screens were both titled "Get", so tapping "Buy In" or
"Buy More" on currency info opened a screen that named the action something
else. Both now derive their title from whether the target currency is already
held, and the payment-source row reads "Buy with".

Held is the same test the tile row uses — an existing token account or a
positive balance — so the tile and the screen it opens always agree. SwapViewModel
picks the account up from AccountController.observeHasAccountFor, which outlives
a balance that has gone to zero.

title_get and label_getWith are dropped; the titles reuse action_buyIn and
action_buyMore, and label_buyWith replaces the old label. "You Get" on the
receipt breakdown is left alone — it names a leg of the trade, not the flow.

Matches code-payments/code-ios-app#671.
@bmc08gt
bmc08gt merged commit 71644f7 into code/cash Aug 27, 2026
2 of 3 checks passed
@bmc08gt
bmc08gt deleted the feat/token-info-buy-in-labels branch August 27, 2026 16:25
bmc08gt added a commit that referenced this pull request Aug 27, 2026
#1341 added a required `accountController` parameter to `SwapViewModel` and
changed only `SwapViewModel.kt`, so `SwapViewModelErrorTest.createViewModel()`
still calls the old constructor. The module's unit tests have not compiled
since it merged, which fails every PR built against `code/cash`.

Add the mock in constructor order and stub `observeHasAccountFor` to return
false. Nothing in this file exercises the first-buy/top-up branch it feeds, and
an explicit answer is steadier than a relaxed mock's empty flow.

`SwapViewModelStateTest` never constructs the view model, so it needs nothing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: crypto Solana, keys, encryption, signing area: tokens Token accounts, balances, token info type: feature New functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant