Repository navigation
mobile: long-press a message link for open, copy and share - #9135
Conversation
|
@codex review |
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Didn't find any major issues. More of your lovely PRs please. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
| child: Column( | ||
| mainAxisSize: MainAxisSize.min, | ||
| crossAxisAlignment: CrossAxisAlignment.stretch, | ||
| children: [ |
There was a problem hiding this comment.
🤖 P2 · Lower link actions become unreachable with large text
In a short landscape viewport with enlarged system text, a URL occupying three lines plus the three action rows can exceed the sheet’s available height. BuzzTitledSheetLayout constrains this body with Flexible, but this Column does not scroll. isScrollControlled changes the route’s height constraint; it does not add scrolling.
User/system effect: Lower actions, including Share link, can overflow outside the reachable sheet with no way to scroll to them.
Test: Open a long HTTP link’s menu in landscape with large system text and check that every action remains reachable. This finding is based on source inspection, without an independent Flutter reproduction.
There was a problem hiding this comment.
🤖 Agreed. Addressed in e350e70 by making the sheet body scrollable, like the image actions sheet. The link journey test now opens the sheet in a 640x260 viewport and checks Share link is reachable; without the fix it fails with a RenderFlex overflow.
e350e70 to
36722c7
Compare
| leading: const Icon(BuzzIcons.copy), | ||
| title: const Text('Copy link'), | ||
| onTap: () { | ||
| Navigator.of(sheetContext).pop(); |
There was a problem hiding this comment.
🤖 Withdrawn · Navigator cancels the second pointer
The proposed two-pointer failure is not established. Flutter's Navigator.pop calls _afterNavigation, which cancels active pointers. cancelPointer queues cancellation before the next pointer event. This contradicts my original callback-interleaving claim and supports the author's reported two-order widget reproduction. I missed this framework behavior; no selection guard is requested for this finding. Independently verified from Flutter source, without running the author's test.
There was a problem hiding this comment.
🤖 I couldn't reproduce this. Flutter's Navigator cancels every other active pointer after any navigation (NavigatorState._cancelActivePointers, called from _afterNavigation), so once the first row pops the sheet, the second finger's tap is cancelled before it is released. I checked this with a widget test that pushes the conversation onto a route, opens the Link sheet, puts pointers on Copy link and Open link, and releases them in both orders, with no selection guard. Only one tap callback ran each time, Open never ran, and the conversation stayed open. So I left the sheet as is.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 36722c7707
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| final canOpen = scheme == 'buzz' || scheme == 'http' || scheme == 'https'; | ||
| return _LinkLongPress( | ||
| url: url, | ||
| onOpen: canOpen ? () => unawaited(openLink()) : null, |
There was a problem hiding this comment.
🤖 P2 · Entity links still have no Copy or Share action
Valid buzz://repo, buzz://pr, and buzz://issue links return through the EntityDeepLink branch before this wrapper. Holding one therefore still opens the message menu rather than the Link sheet. This leaves the requested Buzz-link sharing unavailable for these rendered chips, which also hide their original URL behind a label. Keeping their taps inert is compatible with offering Copy and Share on hold.
User/system effect: a repository, PR or issue destination cannot be copied or shared through the new link menu.
Test: extend the existing entity-link table with a hold on each chip and verify Copy/Share use its exact URL while Open remains absent.
There was a problem hiding this comment.
🤖 Fixed in a137b4d: repo, PR and issue chips now open the Link sheet on hold with Copy and Share for the exact URL; taps stay inert and Open stays hidden. The entity-chip table test now holds each chip and checks this.
Holding a link in a message now opens a Link sheet (open, copy, share) instead of the whole-message actions menu. The link's recognizer shares the message row's hold deadline, so it wins the gesture arena the same way reaction pills do; taps and holds elsewhere in the message are unchanged. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Tom Brow <[email protected]>
A long URL with large text in landscape could push Share link out of the sheet. Make the body scrollable like the image actions sheet. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Tom Brow <[email protected]>
A finger on a link now tints it like the message row's press highlight, and Share link appears for every link, including buzz:// ones (non-web links share as text). Adds swipe-to-reply coverage for drags starting on and beside a link. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Tom Brow <[email protected]>
openLink only handles buzz and http(s) destinations, so a mailto or relative link's Open action just closed the sheet. The sheet now offers only Copy and Share for those. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Tom Brow <[email protected]>
Entity chips (buzz://repo, pr, issue) were wrapped in IgnorePointer, so a hold fell through to the message menu. They now open the Link sheet with Copy and Share; taps stay inert and Open stays hidden since mobile has no destination for them. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Tom Brow <[email protected]>
5b8ef2e to
a137b4d
Compare
|
@codex review |
|
Codex Review: Didn't find any major issues. Bravo. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
johnmatthewtennant
left a comment
There was a problem hiding this comment.
🤖 Reviewed exact head a137b4d4332543b818a41d0fb4e416dff9615239 with the full review collection. No important correctness blockers found. Source review only; no independent app or device run.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a137b4d433
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| // openLink handles only these schemes; the sheet hides Open for others. | ||
| final scheme = Uri.tryParse(url)?.scheme; | ||
| final canOpen = scheme == 'buzz' || scheme == 'http' || scheme == 'https'; |
There was a problem hiding this comment.
Gate Open on the parsed Buzz destination
The earlier mailto: case is fixed, but fresh evidence remains: this scheme-only predicate marks every buzz: URI as openable. For example, an authored [agent](buzz://agent/new?card=av_123) parses as an AgentCreationDeepLink, while openLink dispatches only channel, message, and invite links before returning; agent-creation, add-community, Nostr-bind, malformed, and unknown Buzz links therefore show an enabled Open link action that merely closes the sheet. Derive onOpen from the parsed types actually handled, or route every supported parsed deep link through the pending-link dispatcher.
Useful? React with 👍 / 👎.
…ived-solo-read * origin/main: fix(relay): say "channel owner or admin" in the call_webhook save refusal (#9169) feat(mobile): consolidate Solo chat settings in one sheet (#9255) fix(cli): preserve attachments across successive edits (#9226) fix(mobile): swipe left to reply so swipe-back keeps rightward drags (#9127) mobile: long-press a message link for open, copy and share (#9135) feat(mobile): long-press a Solo chat to open its details sheet (#9163) fix(mobile): shimmer loading photos in the iOS carousel (#9167)
Links render as widgets again so a hold can open the link sheet and tint the link; gpt_markdown text spans support neither. Each ordinary link is keyed message-link:<url>, and link tests find links by that key instead of as LinkTextSpans, restoring upstream assertions where they existed. A Buzz URL of an unknown shape stays plain text instead of becoming a link whose tap and Open action do nothing, as it was before the migration. Signed-off-by: Samin Yeasar Sohag <[email protected]>
…ction-p * origin/main: (111 commits) feat(mobile): tag the reacted-to message author on reactions (#9141) fix(mobile): steady New DM picker rows and animate picks (#9249) perf(mobile): keep remote images on disk and show small ones as thumbnails (#9158) fix(relay): deliver slow cross-node events late instead of closing their recipients (#9235) fix(mobile): read only shown events from filtered Activity rows (#9215) fix(mobile): show the channel name as the notification subtitle (#9173) fix(mobile): keep Home's header clean under sheets (#9152) fix(mobile): show already-loaded custom emoji in the iOS reactions sheet (#9150) mobile: add follow and remind actions to inbox row menu (#9142) fix(mobile): start no threads in Solo chats (#9123) mobile: persist user profiles so names and avatars render on launch (#9116) fix(mobile): keep a sent thread reply above the composer (#9026) [buzz] Recover database pool capacity after stalled connections (#9267) feat: send a User-Agent on relay WebSocket upgrades (#9246) Record why relay connections close and quiet close warnings (#9245) fix(relay): say "channel owner or admin" in the call_webhook save refusal (#9169) feat(mobile): consolidate Solo chat settings in one sheet (#9255) fix(cli): preserve attachments across successive edits (#9226) fix(mobile): swipe left to reply so swipe-back keeps rightward drags (#9127) mobile: long-press a message link for open, copy and share (#9135) ... Signed-off-by: Matthew Boston <[email protected]>
Holding a link in a message used to open the whole-message actions sheet, so there was no way to copy or share just the link. Now a hold on a link opens a small Link sheet showing the URL with Open link, Copy link and Share link. Web links share as URLs so the share sheet can preview them; other links (such as
buzz://) share as text. Open link appears only for destinations the app can open (web andbuzz://links), so amailto:link offers Copy and Share. Repo, PR and issue chips, which have no mobile destination, also offer Copy and Share on hold. While a finger is down, the link gets a light tint behind it, the same kind of press highlight the message row paints. A hold anywhere else in the message still opens the message actions, and a tap on a link still opens it directly.The link gets its own long-press recognizer with the same hold deadline as the message row. Pointer events reach the deeper recognizer first, so at equal deadlines the link wins the arena before the message row, the same mechanism reaction pills already use to claim their own hold. Rendering is otherwise unchanged: the link widget tree only gains a
RawGestureDetector, aSemanticswrapper and aDecoratedBoxfor the tint, press state lives in the link widget so only the link rebuilds, and the sheet is built only when opened. Open reuses the existing tap path (external browser, authenticated relay-media download, or Buzz deep link).Validation
Added tests: a journey in
message_content_test.dart, run with both iOS (200 ms) and Android (default) hold timing, that holds surrounding text (message menu opens, link sheet doesn't), holds the link (link sheet, not the message menu), copies it (clipboard gets the URL), opens it from the sheet and by a plain tap, and checks the press tint appears on touch and clears when the finger moves away. Removing the link recognizer or the tint makes it fail. Another test holds amailto:link and checks the sheet offers Copy and Share but not Open. Swipe-to-reply tests inswipe_reply_tests.dartdrag a message starting on its link and beside it, with both hold timings, and both open the reply.Full
just mobile-check mobile-testpasses (after rebasing onto main, twohosted_backup_service_test.darttests failed once under load and pass on rerun; this PR doesn't touch that code).Automated app run on an iPhone 17 Pro simulator (iOS 27) signed in to a Builderlab community, in a private QA channel: held message text (message actions sheet, dismissed and composer focus restored as before), held a link (Link sheet), Copy link (toast, simulator pasteboard holds the URL), held again and Share link (system share sheet with the page preview). The simulator's share sheet then stopped responding to dismissal, a known simulator share-extension quirk unrelated to this change. After adding the tint, a second simulator run held the link and captured the pressed state (below). Not covered: Android device run, VoiceOver.
link-long-press.mp4
🤖 Generated with Claude Code