Skip to content

feat(messenger): draw message links as a card of the linked message - #1774

Merged
bmc08gt merged 9 commits into
feat/message-link-routefrom
feat/message-link-card
Oct 16, 2026
Merged

bmc08gt merged 9 commits into
feat/message-link-routefrom
feat/message-link-card

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #1772; retarget to code/cash once that merges.

A message link in a chat drew the group invite card, or a plain URL for a DM. It now gets its own card showing the linked message, sized to what the viewer is allowed to see. Task B of the message-links design; share entry points wait until this ships on both platforms.

What the card shows (MessageLinkLookup, beside GroupLinkLookup):

  • In the chat: the message, read through the chat's own path (ChatCoordinator.readMessage: stored copy first, else fetch and open), so a private group's message is decrypted on device. Shows the reaction count, never paid totals.
  • Public group, not a member: GetMessage with FULL_OR_REDACTED. A redacted body is blurred, excluded from accessibility, and offers Buy.
  • Private group, not a member: the group's record and Request.
  • DM, not a member: locked, the chat kind only.
  • Deleted or missing message, or NOT_FOUND: Unresolved.

Unknown membership counts as not a member, so the card never shows more than the server would give a stranger. Results are held per visit, like cash cards, since membership can change between visits.

Classifier. The message route wins over the invite; the invite card still needs the bare /chat/{uuid}.

Taps go through the transcript's URI handler, which #1772 already routes in-app (jump in place, or open with the back chip).

Redaction below Android 12. Modifier.blur draws nothing before API 31 and minSdk is 29, so on Android 10 and 11 the redacted body is covered with a solid block instead.

States follow node 11396:118, values node 11493:201. A Robolectric test renders every state to build/screenshots/message_link_card.png for comparison.

@bmc08gt bmc08gt self-assigned this Oct 14, 2026
@github-actions github-actions Bot added the type: feature New functionality label Oct 14, 2026
@bmc08gt
bmc08gt force-pushed the feat/message-link-card branch from 94841ee to 1b01e76 Compare October 14, 2026 18:52
@bmc08gt
bmc08gt force-pushed the feat/message-link-card branch 3 times, most recently from a3ddf6c to fa7ac1b Compare October 16, 2026 14:11
A link to /chat/{id}/m/{seq} now gets its own card instead of the
group invite card. What the card shows depends on the viewer:

- in the chat: the message, opened through the chat's own path so a
  private group's message is decrypted on device, and its reaction count
- a public group they aren't in: GetMessage in FULL_OR_REDACTED; a
  redacted body is drawn blurred and offers Buy
- a private group they aren't in: the group's record and Request
- a DM they aren't in: that it is one

A deleted or missing message, or a chat the server doesn't have, is
Unresolved. Unknown membership is read as not a member, so the card
never shows more than the server would hand a stranger.

Card states follow Figma node 11396:118, values node 11493:201.
Modifier.blur draws nothing below Android 12 and minSdk is 29, so on
Android 10 and 11 the redacted excerpt would show in plain text. Cover it
with a solid block there instead.

Adds a Robolectric test that renders every card state to
build/screenshots/message_link_card.png for comparison with the design.
The card filled the transcript bubble width, so it ran wider than a cash
card and changed width against nothing. It now takes the cash card's
fraction of the row in every state, on the sender's side.
- Byline, footer and the "Public group" kind draw in white 60%; the header
  avatar grows to 24dp.
- The author falls back from the roster to a profile the app already has, then
  a profile fetch, then "Someone".
- A photo message draws a 56dp thumbnail beside its caption and no "Photo"
  label without one. A reader outside the chat's rules gets no blob, so the
  thumbnail draws its BlurHash only.
…card

When the linked message is only a send.flipcash.com link, the card reads
"<author> sent a cash link", shows the amount in the cash card's large
type and its claim state in the footer, matching iOS #1057. A cash link
with other text around it, or a redacted message, stays an excerpt.
The card now leads with one identity row: a 32dp avatar beside the chat
name over "Author · time", with a chevron in place of the "Open" text when
the card opens. The excerpt is 15sp medium at 88% white, up to four lines,
with line breaks folded to spaces. A photo sits to the right of its
caption, or alone at the start when it has none.

The byline time follows iOS: now, 45m, 2h, Yesterday, Oct 9, then
Oct 9, 2025 for earlier years.

A link to a deleted message now names its chat and says "This message
was deleted." instead of resting on the skeleton.
A message GetMessage reports NotFound in a chat it does have drew the
loading skeleton forever. iOS draws the deleted card for a nil message
(MessageLinkLookup.swift), so the lookup now does the same, and a message
carrying any Deleted content counts, not only a lone one.
… metadata

A photo rendition can arrive with its blob id but no blob metadata, as on the
Test B DM photo in XCTests. Every rendition picker skips those, so the card had
no photo and no BlurHash and drew an empty square. Fall back to the first
rendition, as the transcript bubble does; the loader fetches it by id.
…nt on its card

code/cash added MessageContent.Unsupported (#1770), which left the card's body
mapping non-exhaustive. The card has no way to draw it, so it falls back to the
attachment line, like a widget or system message.
@bmc08gt
bmc08gt force-pushed the feat/message-link-card branch from b1bfb6b to 1d99776 Compare October 16, 2026 21:09
@bmc08gt
bmc08gt added this pull request to stack #1798 October 16, 2026 21:15
@bmc08gt
bmc08gt merged commit 778680e 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

type: feature New functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant