Skip to content

feat(messenger): send link previews built by the sender - #1788

Merged
bmc08gt merged 11 commits into
code/cashfrom
feat/link-preview-send
Oct 16, 2026
Merged

bmc08gt merged 11 commits into
code/cashfrom
feat/link-preview-send

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator

The sender now builds the link preview and sends it with the message. The recipient draws the card from the message alone. This is the Android side of code-payments/code-ios-app#1071, following the design in code-payments/flipcash-client-orchestrator#49 and flipcash2-client-protocol 0.19.0 (TextContent.link_previews).

Sending

  • The composer finds the first eligible web link in the draft, fetches the page with the existing WebLinkLookup, and uploads the page image through the chat photo path (sealed in encrypted chats).
  • A card above the field shows the preview while it loads and uploads. The × removes it only while that exact link stays in the draft; changing the link brings a preview back. A draft restored when the chat opens gets its preview too.
  • At send, the preview is attached only if it is ready, its url is still a whole link in the text, and its cleaned title is non-empty. Sending never waits for the fetch. If the image upload fails, the preview goes without an image.
  • A link whose scheme the keyboard capitalised (Https://) gets no card. The detector lowercases the scheme, so the url would fail the whole-link check at send and the card would be dropped.

Edit, retry and photos

  • Edit re-sends the stored preview only while its url is still a whole link in the new text, without fetching again.
  • Retry sends the preview stored on the pending message.
  • Photos with a ready preview go out without a caption, carrying the reply, and the text follows as its own message with the preview. The text is sent even if the photo send fails, as on iOS. Without a ready preview, the text stays the last photo's caption as before.

Receiving

  • The card comes only from the message. On read, a preview is dropped if its url isn't a whole link in the text or its title is empty; no fetch rules apply, so an http: link the sender previewed still draws.
  • The receive-side fetch, prefetch, web card cache, web image loader, tap-to-load and the web preview feature flag from feat(chat): web link previews #1732 are deleted, with no fallback. Token, group and person cards keep their stored answers in link_previews. Old web: rows fail to decode and are deleted on first read.

Storage
The preview is stored inside the message's existing JSON content column, and rows without one still load, so there is no database version bump. The two earlier changes to that column (#1770, #1576) didn't bump it either.

LinkPreviewVectorTest runs every case in the shared link_preview_send.json vectors.

… sending

Runs the shared link_preview_send.json vectors: 40 whole-link, 21 title and
11 description cases, with lengths counted in code points.
The send path lives in shared/chat, which cannot depend on the messenger
feature module, so the checks and their vector test move there.
Send attaches the ready preview after the whole-link check on the wire text and waits for its
image upload, sending without the image if the upload fails. The pending row keeps the preview so
a retry sends it again, and an edit keeps the stored preview only while its url is still a whole
link in the new text, without fetching the page again.
…age before send

The composer follows the draft's first web link, looks the page up with the existing WebLinkLookup, downloads its image through the guarded image client and stages it as a chat photo. The send takes the preview before the composer empties; a photo message drops it.
…e page

A text whose linkPreview matches its web card's link gets the card resolved from the preview, with the image as a chat photo through the app loader. It draws without the tap-to-load chip, since the reader contacts no site, and still draws nothing with previews off. The prefetcher skips it.
The card shows the host while the page loads and a spinner over the image
while it uploads; a failed upload drops the image. The x removes the
preview while that link stays in the draft, and changing the link brings
one back. Photos with a ready preview go out without a caption, followed
by the text as its own message carrying the preview.
Recipients draw a web card only from the preview its sender attached, so
the page prefetch, the web answers in the link card cache, the web image
store and the web preview flag go. The cache keeps group, token and
person answers; web rows already on disk fail to decode and are deleted
on load.
… animate it

The remove button sits inside the card's top-end corner at a photo chip's
remove-button size, on a haze blur of the card. The card no longer runs its
own expand and shrink: that stacked on the field's height easing and left the
field closing after the card had gone. The field now slides the card in and
out the way it does the photo chips. Host and description share a baseline.
…ry it

The detector lowercases a scheme the keyboard capitalised, so "Https://kotlinlang.org" showed a
composer card, but the server matches the preview url against the text byte for byte and the send
dropped it. The composer now applies the same whole-link check before fetching.
@bmc08gt bmc08gt self-assigned this Oct 16, 2026
@github-actions github-actions Bot added type: feature New functionality area: network gRPC, connectivity, API, exchange rates and removed type: feature New functionality labels 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
@github-actions github-actions Bot added the type: feature New functionality label Oct 16, 2026
@bmc08gt
bmc08gt merged commit a238c8b into code/cash Oct 16, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: network gRPC, connectivity, API, exchange rates type: feature New functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant