Repository navigation
feat(messenger): route message links and land on the message - #1772
Merged
Merged
Conversation
/chat/{chatId}/m/{seq} matched the group invite check, which ignores
everything after the id, so a group's message link opened as the bare
group, and a DM id (base64url, not UUID-shaped) fell to unrouted.
ChatMessage is checked before the invite and claims exactly four
segments with a numeric seq. It records which id form the link used:
a group link keeps the invite's gated preview and dead-link close, a DM
link opens the way a DM does. /chat/{uuid} and a malformed tail still
reach the invite.
A message link opens the chat scrolled to that message and flashes it,
reusing the reply jump. When the message is older than anything stored,
the chat pages back from its oldest stored message until the target is
stored, so the transcript stays contiguous down to it.
A message link tapped inside a chat jumps in place when it points at the
same chat. Otherwise it opens the linked chat with a Back to {chat} chip
that pops to the chat it was tapped in. The chip hides on scroll-away or
send; links opened from outside the app get no chip.
…ttles The landing paged history as soon as the chat id was known, before the open had resolved membership or access. A link into a group the viewer cannot read fetched and stored the transcript the blur is there to withhold. The landing now waits on State.messageLinkLanding: a member, an eligible non-member of a group with listener rules, or a DM pages to the message; a withheld group or a missing chat fetches nothing and drops the open-at-message hold. A viewer who buys in from the gate is still walked to the message.
…solves A link with a group id could open with the chat marked a tip DM before the group loaded, so the landing read as Readable and paged a withheld group's history. A group hydrated by id also has a null membership, which left the landing waiting forever. Carry linkedAsGroup from the route and read a null membership as outside, as the gate does.
While pages load, peek returns placeholders for rows on screen, so the landed message read as off screen and the chip was dismissed before it was seen. Wait for a drag before checking.
Over a light row such as a cash card, the flat white 12% fill left the label unreadable. Use the Join Requests anchor's ultra-thin haze and divider hairline instead.
Scrolling away from the landed message or sending hid the chip, so a reader who scrolled to read around the linked message lost the way back. The chip now stays for the life of the screen.
bmc08gt
force-pushed
the
feat/message-link-route
branch
from
October 16, 2026 21:09
6ffd2ce to
b81c6a0
Compare
bmc08gt
added this pull request to stack #1798
October 16, 2026 21:15
bmc08gt
added a commit
that referenced
this pull request
Oct 16, 2026
…w-send * origin/code/cash: build(deps): bump grpc from 1.84.0 to 1.84.3 (#1792) build(deps): bump io.grpc:grpc-android from 1.84.0 to 1.84.3 (#1790) build(deps): bump com.bugsnag:bugsnag-android from 6.27.1 to 6.28.0 (#1791) build(deps): bump com.composables:composeunstyled-bottom-sheet (#1793) build(deps): bump androidx.paging:paging-compose from 3.5.1 to 3.5.3 (#1794) build(deps): bump androidx-paging from 3.5.1 to 3.5.3 (#1796) build(deps): bump kotlin from 2.4.20 to 2.4.21 (#1789) build(deps): bump gradle-wrapper from 9.8.0 to 9.8.1 (#1797) fix(theme): use iOS's Avenir Next Demi file (#1800) feat(messenger): share and copy a link to a message (#1784) feat(messenger): show the linked message when a link lands in a gated group (#1777) feat(messenger): draw message links as a card of the linked message (#1774) feat(messenger): route message links and land on the message (#1772) # Conflicts: # apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/ChatViewModel.kt # apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/link/LinkCardModule.kt # apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/link/LinkCardResolver.kt # apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/link/MessageLinkPrefetcher.kt # apps/flipcash/shared/chat/src/main/kotlin/com/flipcash/shared/chat/internal/delegates/MessagingDelegate.kt
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.
A message link (
https://app.flipcash.com/chat/{chatId}/m/{seq}) opened as the bare group for a group, and did nothing for a DM. This routes it and lands on the message. Task A of the message-links design; the card (B) stacks on this, and share entry points wait until B ships on both platforms.Route.
isGroupChatInvite()ignored everything after the id, so it claimed group message links; a DM id is base64url, not UUID-shaped, so DM links fell tounrouted().DeeplinkType.ChatMessageis checked first and needs exactlychat/{id}/m/{seq}with a numeric seq. It records the id form: a group link opens withisGroupLink = true(gated preview for a non-member, closes on a dead link), a DM link opens the way a DM does./chat/{uuid}and a malformed tail still reach the invite.Land.
AppRoute.Messaging.ChatgainsjumpToMessageId, whichChatViewModelturns into the existing reply jump once the chat id is known. The unread-divider positioning stands down until that jump lands. When the message is older than anything stored,MessagingDelegate.loadHistoryThroughpages back from the oldest stored id with the mediator's own fetch until the target is stored. It doesn't fetch the lone message: the mediator appends from the last stored item, so a lone message would leave a gap above the loaded window that is never filled.Walk budget. The jump's walk was budgeted in messages but counts list rows (date separators, unread divider, one bubble per part). A link to message 3 of Moony (~1,180 messages) stopped about 30 rows short and stayed at the bottom. The budget is now two rows per message, capped as before; this also applies to reply jumps and the unread-divider walk.
Back chip. A message link tapped inside a chat jumps in place for the same chat; for another chat it opens that chat with a "Back to {chat}" chip that pops to where it was tapped. The chip hides on scroll-away or send, and links from outside the app get none. Style follows the Join Requests anchor (concepts, node 11478:144).