Repository navigation
feat(chat): open @handle mentions in message bubbles - #1609
Merged
Merged
Conversation
Ports code-ios-app#882. A `@handle` in a text or reply bubble is drawn as a rounded pill and opens whoever it names. Detection runs once per message in the mapper, beside the links, with iOS's pattern. A handle inside a link (`x.com/@jeff`) stays the link's. Mentions live on `ContentBubble.mentions`, outside card classification, and `splitAroundLinkCard` rebases each into its own row. A tap looks the handle up through `LinkCardResolver.lookUpUser`, which shares the person card's lookup and memory, so a handle already resolved opens without a round trip. Where it lands: - the viewer's own handle: the You tab, as a person card to yourself does - the open DM's counterpart: their profile as the title opens it, with Mute and without Message - anyone else: their profile with Message and Send Cash and no Mute (`ProfileOrigin.Mention`) - unclaimed: "No Such Account"; any other failure: "Couldn't Open Profile" The pill uses iOS's values: white at 14%, 6dp radius, 6dp padding and a 3dp gap, drawn per line when the handle wraps. The room either side comes from inline placeholders, since Compose has no per-character kerning.
A Compose Text that wraps reports the full width it was offered, so a wrapped message stretched its bubble to the maximum width. A mention pill wrapping onto its own line left most of the bubble empty. The body now measures itself once at the offered width and takes the width of its widest line, as SwiftUI text does on iOS. A clickable span with no style is drawn as a web link, so mentions came out purple and underlined over their pills. They now take the body's colour with no underline.
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.
Android had no mention support. This ports code-payments/code-ios-app#882, which iOS now ships to everyone, with no flag here either.
Detection
detectMentionsinchat-uiuses iOS's pattern,(?:^|[^A-Za-z0-9_.@])(@([A-Za-z0-9_]{2,15}))(?![A-Za-z0-9_@]), over UTF-16 offsets. Handles are lowercased. Email addresses,@@name, and handles outside 2–15 characters or running into more handle characters are not mentions. A handle that overlaps a detected link is left to the link.ChatViewModel's mapper detects once per message, besidedetectUrls, and stores the result onContentBubble.mentions. Mentions take no part in link-card classification.splitAroundLinkCardrebases each one into the row it falls in, and the card row gets none.MentionDetectionTestportsMentionDetectorTestscase for case.SplitAroundLinkCardTestcovers iOS'smentionRebasedIntoTrailingRowand a leading-row counterpart.Tap
ChatAction.OpenMention(username)carries only the handle.ChatViewModellooks it up withLinkCardResolver.lookUpUser, which uses the same lookup and memory as aflipcash.com/<handle>person card, so a handle a card already resolved opens without a round trip.mentionDestinationpicks where it lands:ProfileOrigin.Mention)ChatStep.Profilegained anorigin(defaultChat), andprofileShowsMuteandprofileShortcutRecipientread it.MentionDestinationTestportsMentionDestinationTests.Pill
White at 14%, 6dp radius, 6dp padding and a 3dp gap to the neighbouring words, drawn behind each line when the handle wraps. These are iOS's
MentionPillvalues. I found no Figma node for the pill in either repo, so the colour hasn't been checked against the design. Compose has no per-character kerning, so the room either side of the handle is an inline placeholder with a no-break space stand-in, which keeps the pill's padding on the same line as the@and the handle. The tap covers the whole pill. A mention's letters keep the body's colour with no underline; a clickable span with no style of its own draws as a web link.Bubble width
Every text bubble now narrows to its widest line (
widestLineinWidestLine.kt). A ComposeTextthat wraps reports the whole width it was offered, so any wrapped message stretched its bubble to the maximum. Mentions made it obvious: a pill wrapping onto its own line left most of the bubble empty. The body is measured once at the offered width and then given exactly its widest line. SwiftUI text sizes this way, so this matches iOS.The transcript has no tap-to-dismiss-keyboard handler, so a first tap with the keyboard up goes to the link. iOS's first-tap bug doesn't carry over.