Skip to content

feat(messenger): route message links and land on the message - #1772

Merged
bmc08gt merged 7 commits into
code/cashfrom
feat/message-link-route
Oct 16, 2026
Merged

bmc08gt merged 7 commits into
code/cashfrom
feat/message-link-route

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator

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 to unrouted(). DeeplinkType.ChatMessage is checked first and needs exactly chat/{id}/m/{seq} with a numeric seq. It records the id form: a group link opens with isGroupLink = 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.Chat gains jumpToMessageId, which ChatViewModel turns 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.loadHistoryThrough pages 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).

@bmc08gt bmc08gt self-assigned this Oct 14, 2026
@github-actions github-actions Bot added type: feature New functionality area: scanner QR/Kikcode scanning, camera area: deeplinks Deep link handling, URL routing, and link parsing and removed type: feature New functionality labels Oct 14, 2026
@github-actions github-actions Bot added the type: feature New functionality label Oct 14, 2026
/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
bmc08gt force-pushed the feat/message-link-route branch from 6ffd2ce to b81c6a0 Compare October 16, 2026 21:09
@bmc08gt
bmc08gt added this pull request to stack #1798 October 16, 2026 21:15
@bmc08gt
bmc08gt merged commit df9e28b into code/cash Oct 16, 2026
3 checks passed
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: deeplinks Deep link handling, URL routing, and link parsing area: scanner QR/Kikcode scanning, camera type: feature New functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant