Files
buzz/mobile/lib/features
Tom Brow 53ca047cd3 fix(mobile): keep mention rows still and cache directory searches (#8875)
Typing `@s` in a stream showed the matching channel members, then about
half a second later added people from outside the channel. The chooser
sits on the composer and grows upward, so each late row pushed every
shown row up and a tap could land on the wrong person. It happened every
time, even for a query typed moments earlier, because each new `@`
started its directory search from nothing.

### Changes

- **Search cache.** Finished directory searches are kept per community
and signer, in a small LRU keyed by query (`MentionSearchCache`). A
query searched before shows its people at once while a fresh search runs
in the background. A query not searched yet starts from the longest
searched query it extends (`@si` starts from `@s`), since a name-prefix
search for a longer query finds no one the shorter one missed (up to the
search's result limit). This replaces the per-opening "last search" that
reset on every new `@`.
- **Rows hold still.** While a query's directory search can still add
people or a retry row (`mentionSearchPendingProvider`), the chooser
reserves its full height with rows at the top, so late rows fill empty
space instead of moving shown rows. This includes the background refresh
of a cached query. The reservation lasts until the query or the opening
changes, so the panel never shrinks under the finger either.
- **Three rows, with progress.** The chooser has a fixed three-row
height (fewer rows at larger text sizes) before it scrolls, and never
taller than the space above the composer (so a short view, such as
landscape with the keyboard up, keeps its rows on screen). While the
search runs, a thin bar overlays its top edge without changing its
height.

The trade-off: while a query's search runs, the panel is full height
even when it ends with one or two rows.

### Demo

iPhone 18 Pro simulator, local relay. Sam and Sasha are channel members;
Saba, Sierra and Skyler come from the directory search.


https://github.com/user-attachments/assets/efae33ce-ee65-447b-9402-b0741c8dc2da

### Before merge

- [x] Kenny Lopez reviews the visible changes ([approved in Buzz
#buzz-mobile](buzz://message?channel=9f18f3c6-b5e5-453d-b36d-65487913be0b&id=c8b01eaa3760e44c3b6583f2e02bec576d78679adfb364e5fe718cc0926bdc2d)).

### Validation

- New tests: a cached query reopens with its people at once, stays
pending while it searches again, and clears when that search finishes; a
longer query starts from its prefix's people; an uncached query is
pending until its search finishes; and a compose bar journey step checks
that a late directory person leaves the shown row's position and the
panel height unchanged, both on a new query and on a cached query's
refresh. Other new tests cover the three-row cap, the progress bar, and
an 844×390 landscape view with the keyboard up, where the reserved
chooser previously pushed the only row above the screen. Disabling the
cache lookup fails the two cache tests, and disabling the reservation
fails the layout tests (the cached-refresh case moved a row 59pt).
- `just mobile-check` and `just mobile-test` pass.
- Exercised on the simulator against a local relay as shown above.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: Tom Brow <tomb@squareup.com>
Signed-off-by: Tom Brow <tomb@block.xyz>
Co-authored-by: Tom Brow <tomb@squareup.com>
Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@buzz.block.builderlab.xyz>
Co-authored-by: mbp <973be878edd6d4f79692a3827f20a6f7fe0ed0362f269ff6b6ba8867033d7d8e@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 13:55:46 -08:00
..