Skip to content

feat(chat): forward a message through the share sheet - #1076

Merged
bmc08gt merged 24 commits into
mainfrom
feat/message-link-share
Oct 16, 2026
Merged

bmc08gt merged 24 commits into
mainfrom
feat/message-link-share

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator

The long-press menu gains Forward, which opens the share-to-chats sheet that profiles and groups already use, with a new message subject titled "Share Message". Android's version is code-payments/code-android-app#1784.

The link is app.flipcash.com/chat/{chatId}/m/{seq}: a group's UUID, or a DM's base64url id, the same form the router reads back. DeepLinkControllerTests round-trips both forms.

In the sheet:

  • Copy Link copies the message link. There's no separate menu row for it.
  • Share hands the system sheet the bare URL. Reusing GroupInviteShareItem titled the preview "Invite to Join Group".
  • The source chat stays in the list.

Forward shows on any confirmed participant message, and not on system notices, tombstones, or encrypted messages. A reader outside a group keeps it, as with Report. The menu order is Copy, Reply, Forward, Edit, Delete, Report.

Stacked on #1057.

`/chat/{id}/m/{seq}` parsed as `.chat(id)` and dropped the message, so a
message link opened the chat at the bottom. It now parses to
`.chatMessage(id, seq)` and routes through `routeChat` to a sibling
destination that carries the message.

The transcript lands with the reply jump's scroll-and-flash. When the
message isn't stored locally, `MessageLoader.revealPaging` pages older
history back from the oldest stored message until it is, capped at 20
pages, so the window stays contiguous. A link to the open chat jumps in
place instead of remounting it.

A link tapped in another chat shows a back chip under the bar that
returns there. It hides when the user drags the transcript or sends.

A malformed `/m/` segment falls back to `.chat(id)`. A private group the
viewer isn't in still opens its profile. The scan allowlist and the
link-card classifier accept the new route; the classifier keeps the
group card until the message card lands.
A link to a message older than the first page landed with the target as
the window's first row, half under the top edge, because `reveal`
anchored the window on the target itself. It now anchors 12 messages
earlier where history allows, and `revealPaging` fetches one more page
when the page it stopped on begins at the target.

`MessageLinkSmokeTests` opens `/chat/{id}/m/100` in the XCTests tip DM,
whose first page holds 251-300, and waits for the highlighted row to be
on screen. The row a jump lands on carries the `chat-attention-target`
accessibility identifier while the flash runs, so the test can find it.
* commit '16a24ad1eb3eeac2097eac72d32150ba2c368f18':
  fix(ui): draw UIKit caption in Avenir Medium like SwiftUI (#1064)
  fix(members): host chip and member count label to match Android (#1058)
  chore(chat): log the attach lifecycle the same way in both hosts (#1062)
  refactor(chat): decide attach close events in one place (#1061)
  refactor(chat): measure the attach card's frame once (#1060)
  refactor(chat): read the attach menu rows live over the keyboard (#1059)
  refactor(chat): build the attach actions once for both hosts (#1056)
  fix(chat): render system messages in the transcript (#1054)

# Conflicts:
#	Flipcash/Core/Screens/Conversation/ChatScreenRepresentable.swift
It used a flat 12% white fill. On iOS 26 it now takes the same interactive
glass as the composer; older iOS keeps the fill and hairline border.
…chat closes

Dragging the transcript or sending a message no longer hides the chip,
matching Android. The drag and own-message hooks existed only for the chip,
so they go with it.
A message link tapped in a chat replaced the whole chat stack, so the back
chip reopened the source chat fresh at the bottom. The landed chat is now
pushed over the source when that chat is the visible screen, and the chip
pops back to it. A link that can't go on top (another tab or a sheet is up)
still navigates, and the chip still reopens the chat.
@bmc08gt bmc08gt self-assigned this Oct 16, 2026
A /chat/{id}/m/{seq} link now classifies to a message card instead of the group card. The resolver reads public groups under fullOrRedacted so the server applies the listener rules, decrypts member reads through the existing chat client, and falls back to the chat preview or its kind for non-members. Redacted text never enters the model.
A known chat with a deleted or missing message now draws the chat header over "This message was deleted." instead of the URL-only face. Resolved, gated and cash faces show the chat kind, redacted and cash faces carry the byline, and cash adds the settled footer.
The card filled the bubble. All eight states now take the cash card's
width, (available - rowInset*2) * 0.64, on the sender's side, per the
updated node 11396:118.
Main added system notices as message content. They aren't link targets,
so a link to one falls back to the URL-only face, like encrypted and
widget content.
The card read only the source chat's roster display name, so a sender with
no display name, or one the roster leaves out, came back as "Someone" even
when the chat itself named them. It now falls back to the username handle,
then to KnownAuthorDirectory (saved names, then a profile fetch), the same
order ConversationLoadCoordinator attributes rows in.
The header, byline and footer were 12 pt and the deleted/locked line 15 pt.
Android's MessageLinkCard draws them with textSmall (14) and textMedium (16).
They used textSecondary (123 gray), which read dark on the card. They now use
white at 0.6, the same as the web link card's host line, and the kind label
moves from 0.55 to match.
A photo message's card shows a thumbnail beside its caption or "Photo".
A reader below the chat's rules gets the photo's BlurHash only: the
redacted card carries no blob, so nothing on it can fetch the bytes.

A text that is only a cash link now draws as the cash face, with the
link's amount and claim state, instead of the raw send.flipcash.com URL.
The card's header loaded no picture, so every chat showed a monogram. It
now reads the chat's avatar from the shared avatar store, the same one
the Chats tab uses: the chat picture for a group, the other person's
picture for a DM. The avatar goes from 20 to 24 pt.

A photo with no caption shows the photo alone, without a "Photo" label.
The long-press menu gains "Forward", which opens the share-to-chats sheet
that profiles and groups use, with a new message subject titled "Share
Message". The link is app.flipcash.com/chat/{chatId}/m/{seq}, with the
group's UUID or a DM's base64url id, the same form the router reads back.
The sheet's Copy Link tile copies it; its Share tile hands the system sheet
the bare URL, since GroupInviteShareItem titled the preview "Invite to Join
Group".

Forward appears on any confirmed participant message, and not on system
notices, tombstones, or encrypted messages. A reader outside a group keeps
it, as with Report.
@bmc08gt
bmc08gt force-pushed the feat/message-link-card branch from 7cc9e3c to e3c5708 Compare October 16, 2026 18:44
@bmc08gt
bmc08gt force-pushed the feat/message-link-share branch from ef43e73 to 082d830 Compare October 16, 2026 18:44
* origin/main: (23 commits)
  feat(chat): open message links on the linked message (#1055)
  fix(chat): load the link preview for a draft restored on opening a chat
  fix(chat): bring a removed link preview back once its link is edited out of the draft
  fix(chat): animate the composer link card in and out on the chip spring
  fix(chat): draw the composer link preview as a compact card with its remove button on the corner
  fix(chat): enlarge the composer link image and pin its remove button to it
  feat(chat): send a link preview alongside staged photos
  feat(chat): show the link preview's page in the composer before its image uploads
  feat(chat): draw a web card from the sender's preview and drop the receive-side fetch
  feat(chat): build a link preview in the composer and send it with the text
  feat(chat): carry a text message's link preview on the wire and in the store
  feat(chat): add the sender-side link preview checks and their shared vectors
  fix(chat): match Android's update-app bubble border and subtitle
  fix(chat): stand the jump button outside the bar clip so the reply strip no longer leaks (#1074)
  build: update release manifest
  fix(home): draw unselected tab glyphs and labels white on every iOS version (#1073)
  feat(settings): version card for TestFlight builds, kept current by the release manifest (#1072)
  feat(settings): add the update dot and version card (#1070)
  feat(update): tell users when a newer App Store version is out (#1069)
  feat(chat): jump-to-bottom button with unread badge (#1068)
  ...

# Conflicts:
#	Flipcash/Core/Screens/Conversation/LinkCardClassifier.swift
#	Flipcash/Core/Screens/Conversation/LinkCardFeed.swift
#	Flipcash/Core/Screens/Conversation/LinkCardResolver.swift
#	Flipcash/Core/Session/SessionAuthenticator.swift
#	FlipcashCore/Sources/FlipcashCore/Models/Chat/LinkCard.swift
#	FlipcashTests/Chat/LinkCardResolverTests.swift
#	FlipcashUI/Sources/FlipcashUI/Chat/ChatShareProfileCell.swift
#	FlipcashUI/Sources/FlipcashUI/Chat/LinkCardSource.swift
#	FlipcashUI/Sources/FlipcashUI/Chat/LinkCardView.swift
…t/message-link-share

* origin/feat/message-link-card: (23 commits)
  feat(chat): open message links on the linked message (#1055)
  fix(chat): load the link preview for a draft restored on opening a chat
  fix(chat): bring a removed link preview back once its link is edited out of the draft
  fix(chat): animate the composer link card in and out on the chip spring
  fix(chat): draw the composer link preview as a compact card with its remove button on the corner
  fix(chat): enlarge the composer link image and pin its remove button to it
  feat(chat): send a link preview alongside staged photos
  feat(chat): show the link preview's page in the composer before its image uploads
  feat(chat): draw a web card from the sender's preview and drop the receive-side fetch
  feat(chat): build a link preview in the composer and send it with the text
  feat(chat): carry a text message's link preview on the wire and in the store
  feat(chat): add the sender-side link preview checks and their shared vectors
  fix(chat): match Android's update-app bubble border and subtitle
  fix(chat): stand the jump button outside the bar clip so the reply strip no longer leaks (#1074)
  build: update release manifest
  fix(home): draw unselected tab glyphs and labels white on every iOS version (#1073)
  feat(settings): version card for TestFlight builds, kept current by the release manifest (#1072)
  feat(settings): add the update dot and version card (#1070)
  feat(update): tell users when a newer App Store version is out (#1069)
  feat(chat): jump-to-bottom button with unread badge (#1068)
  ...
@bmc08gt
bmc08gt changed the base branch from feat/message-link-card to main October 16, 2026 21:09
* origin/main:
  feat(chat): draw message links as a message card (#1057)
@bmc08gt
bmc08gt merged commit 3f230fe into main Oct 16, 2026
2 of 3 checks passed
bmc08gt added a commit that referenced this pull request Oct 19, 2026
* origin/main:
  feat(chat): pick a new group's currency from a full-width row (#1084)
  fix(core): round Decimal.doubleValue correctly (#1082)
  feat(flipcash): adopt ocp 0.8.0 and flipcash2 0.20.0 contracts (#1078)
  chore: bump version to 2026.10.4 (#1086)
  chore: record 2026.10.3 as the production release (#1089)
  ci(release-manifest): record every TestFlight build when it processes (#1088)
  build: update release manifest
  test: stop four retry-only tests failing on a loaded runner (#1087)
  fix: clear the 2026.10.3 release test gate (#1085)
  build: update release manifest
  fix(chat): cap the attach card's corner radius at 40pt on iOS 26 (#1081)
  feat(update): check for an update every time the app returns from the background (#1080)
  build: update release manifest
  chore(chat): log where the inline photo picker flow stops (#1079)
  build: update release manifest
  fix(chat): open the author's profile from the avatar beside a photo (#1077)
  feat(chat): forward a message through the share sheet (#1076)
  feat(chat): draw message links as a message card (#1057)

# Conflicts:
#	FlipcashCoreVectors/Tests/FlipcashCoreVectorsTests/MultiPaymentIntentVectorTests.swift
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant