Skip to content

feat(messenger): send an invitation with the group invite link - #1500

Merged
bmc08gt merged 3 commits into
code/cashfrom
feat/group-invite-share
Sep 18, 2026
Merged

bmc08gt merged 3 commits into
code/cashfrom
feat/group-invite-share

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

"Send Invite Link" put the bare URL in the share sheet, so the recipient got a link with no
indication of what it opens. iOS' GroupInviteShareItem now sends a sentence ahead of it; this
matches the wording exactly.

Join <group> on Flipcash and let's chat

https://app.flipcash.com/chat/<uuid>

The same sentence fills EXTRA_TITLE/EXTRA_SUBJECT, the way shareToken uses title_shareToken
in both slots. A group with no name shares the bare link rather than an invitation with a hole in
it — an untitled group reaches the controller as "", so the check is isNotBlank, matching iOS'
trim-and-check. The copy action is untouched: ChatViewModel still copies the URL verbatim, which
is what you want when it is pasted into a URL bar.

subtitle_shareGroupInvite ("Join me on Flipcash") was drafted for this slot and never wired. It is
replaced by message_groupInvite rather than left alongside it.

Two smaller parity fixes ride along:

  • The group profile's invite row drew ic_group_3, which names a group rather than the act of adding
    to one. iOS uses person.badge.plus on the same row, so it is now Icons.Outlined.PersonAdd. The
    @ glyph stays where it belongs — the row inside the sheet this opens, where it stands for the
    username the link is sent to (node 10127:118328).
  • The share sheet's preview thumbnail is now the group's picture. Android draws that thumbnail from
    the intent's ClipData, not from any extra, so SharePreviewImage caches the rendition through the
    FileProvider path the tip-card preview already uses and passes a content:// URI. Best-effort: no
    picture, a slow fetch or an expired URL each share exactly what they shared before. API 29+ only,
    and Android-only — iOS sets no image on its LPLinkMetadata.

The picture URL is resolved in GroupInviteSheet rather than in the share controller. The stored
download URL expires, and re-minting it needs BlobAccessContext.ChatProfile, which
:apps:flipcash:shared:shareable cannot see: it depends on :libs:messaging, not :services:flipcash.
Only a String? URL and a cache key cross that boundary.

One thing this cannot match: iOS returns the bare URL to AirDrop and Slack, both of which render a
link preview themselves. ACTION_SEND carries one EXTRA_TEXT to every target and
EXTRA_EXCLUDE_COMPONENTS can only drop a target entirely, so on Android those two receive the
sentence as well.

:apps:flipcash:shared:shareable had no test source set. This adds one, with three cases over the
built intent: titled, blank-titled and untitled.

The group invite share put the bare URL in EXTRA_TEXT, so the recipient got a
link and nothing saying what it was. iOS' GroupInviteSheet now names the group
ahead of the link, and this matches it: "Join <title> on Flipcash and let's
chat", a blank line, then the URL. The blank line is what keeps the URL
unfurling on its own rather than running into the sentence.

A group with no title has nothing to name, so it keeps sharing the bare link.
EXTRA_TITLE/EXTRA_SUBJECT carry the same sentence, the way shareToken uses
title_shareToken in both slots.

message_groupInvite replaces subtitle_shareGroupInvite, which was drafted for
this slot and never referenced.

The copy action is untouched — ChatViewModel still copies the URL verbatim,
since a sentence pasted into a URL bar is worse than the gap being closed.

Adds the module's first test source set; both cases are asserted through the
chooser's EXTRA_INTENT under Robolectric.
Three things about the group invite.

The profile row's icon was ic_group_3, a three-person glyph naming a group
rather than the act of adding to one. iOS' same row draws person.badge.plus, so
this draws Icons.Outlined.PersonAdd — the Material glyph closest to it, and the
same kind of vector the Leave row beside it already uses.

The Sharesheet now carries the group's picture as its preview thumbnail, so what
is being invited to is recognisable before it is sent. The image goes out as
ClipData, which needs a content:// URI another process can open, so
SharePreviewImage loads the rendition through the app's shared Coil loader —
keyed on the durable blob id, so it hits what the screen already downloaded —
and writes it into the share_previews cache the tip-code previews use. Best
effort throughout: no picture, a slow fetch or an expired download URL all share
what they shared before. The URL is resolved in the sheet rather than in the
share controller, because re-minting an expired one needs the chat's profile to
authorize it and the shareable module sees nothing of :services:flipcash.

An untitled group reached the controller as "" rather than null —
ChatSubject.Group.title is groupTitle.orEmpty() — so the invitation would have
named a group with a hole where the name goes. Blank now falls back to the bare
link the way null does, which is what iOS' GroupInviteShareItem does with the
same value.
@bmc08gt bmc08gt self-assigned this Sep 18, 2026
@github-actions github-actions Bot added the type: feature New functionality label Sep 18, 2026
EXTRA_TITLE carried the invitation sentence, so the Sharesheet drew it as
the headline directly above the same sentence as the first line of the
body — and truncated it there, the headline being a single line. The
group's name is what that slot is for.

EXTRA_SUBJECT keeps the sentence. It is an email's subject line rather
than a headline sitting above a body, so there is nothing to repeat.
@bmc08gt
bmc08gt merged commit 3de15ea into code/cash Sep 18, 2026
3 checks passed
@bmc08gt
bmc08gt deleted the feat/group-invite-share branch September 23, 2026 16:46
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