Files
buzz/mobile/lib/features/home
Tom Brow 27f0fe7527 feat(mobile): add iOS Home Screen shortcuts for New chat, New DM and the Bestie (#9360)
Long-pressing the Buzz icon on iOS now offers three quick actions:

- **New chat** opens a new solo chat (the same draft as New › New chat).
- **New DM** opens the New DM picker.
- **Message <Bestie>** opens the DM with the current community's Bestie,
using the agent's display name (for example "Message astra"). It's
hidden when the community has no Bestie, and it updates when the Bestie,
its name or the community changes.

| Before | After |
| --- | --- |
| <img alt="before"
src="https://github.com/user-attachments/assets/393c3fb6-fe64-4505-a7a4-12714d8bf1df"
width="300"> | <img alt="after"
src="https://github.com/user-attachments/assets/1c57df92-6fed-4fee-9ce8-e9ea0ec70294"
width="300"> |

### How it works

Home publishes the items through a small native bridge
(`buzz/home_screen_shortcuts`), which sets
`UIApplication.shortcutItems`. A tap goes through the scene delegate.
The bridge keeps the latest one until Dart has handled it, the same
pattern push-notification taps use, so cold launches work too. Home runs
it only once the app is active and the destination is ready. When a tap
arrives, Home pops back to the first route once, so a shortcut never
opens beneath a Flutter sheet or a conversation that was already open. A
screen that refuses to close (for example a New chat whose first message
is still sending) stays, and the tap is dropped. The one exception is
the native iOS New channel form, which isn't a Flutter route: a shortcut
tapped with it open runs underneath it. If a screen is opened while a
tap is still waiting for its destination, the tap is dropped. A New DM
tap while the New DM picker is open replaces the picker. Opening the
Bestie DM now goes through one shared function, so the Home launcher
button and the shortcut run identical code. A second open while the DM
is still being looked up does nothing. Signing out clears the items. The
shortcut wiring lives in its own leaf widget, so Home doesn't rebuild
for it.

Behavior change for the existing Home Bestie launcher: if you open
another screen while it's still looking up the DM, the DM no longer
opens over that screen.

Behavior change for the native member picker (New DM, and Add members in
channels): a picker reopened while the previous one is still closing now
opens once the dismissal finishes, instead of failing with "Cannot open
the member picker".

### Validation

- Added tests: a Home journey covers the published titles (including the
Bestie's name), a cold tap that waits for the app to resume and for New
chat to be available, a Bestie tap made with another route open, a New
chat tap while a draft is open, a New DM tap replacing an open picker, a
waiting tap dropped once another screen opens, no Home rebuilds on
lifecycle changes, and clearing the items when Home goes away. A
launcher test covers a slow Bestie lookup, and a New chat test covers a
shortcut tapped while the first message is still sending. I also broke
the code that runs the shortcut and confirmed the journey fails.
- Full mobile suite and `flutter analyze` pass. CI doesn't compile Swift
on drafts, so `NativeAddMembersSheet.swift` was compiled with a local
`flutter build ios --simulator` build.
- iPhone 17 Pro simulator (iOS 27), signed in to a Builderlab community:
from a cold launch, New chat opened the new-chat draft. Then, with the
app warm, New DM opened the picker and Message <Bestie> replaced it with
the Bestie DM. The recording stays in Buzz because it shows real account
data.

buzz-review-completed

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

---------

Signed-off-by: Tom Brow <tomb@squareup.com>
Co-authored-by: Tom Brow <tomb@squareup.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 04:20:36 +00:00
..