Skip to content

Share a deck or a profile as a QR code - #331

Merged
jvsena42 merged 5 commits into
mainfrom
feat/share-qr-sheet
Sep 20, 2026
Merged

jvsena42 merged 5 commits into
mainfrom
feat/share-qr-sheet

Conversation

@jvsena42

Copy link
Copy Markdown
Owner

Every share button — deck detail, own profile, someone else's profile — used to open the system
chooser directly. That only helps someone who already has the recipient in a messaging app; the
person sitting across the table had no way to take the link off the screen.

They now raise an in-app sheet carrying the link as a QR code, with Copy link and Share…
underneath. Share attaches the same code as a PNG beside the named line, so what leaves the app is
a picture anyone can point a camera at. Both platforms, all three buttons.

What is in it

  • ShareLinkSheet on Android (ModalBottomSheet) and iOS (.sheet), driven by the existing
    ShareProfile/Share effects — no ViewModel changed, so the shared tests are untouched.
  • The link is elided in the middle when it does not fit: a pubky URI's two ends are what
    identify it, and eliding the tail leaves 60 characters of key saying nothing.
  • Copy confirms on the button itself ("Link copied", two seconds) rather than in a toast — Android
    13 raises its own clipboard chip, and a toast landed on top of it.
  • Android writes the PNG to cacheDir/share/ behind a new FileProvider, as one overwritten file,
    and passes it as ClipData as well as EXTRA_STREAM: the read grant rides on the clip, and
    without it the chooser draws no thumbnail.
  • iOS renders the code through UIImage, never CGContext.draw — the renderer's context is
    y-flipped, and a mirrored QR is one no scanner reads — and measures itself for a .height
    detent, since iOS has no fit-the-content detent.
  • Five new strings in all eleven languages on both platforms, plus share_deck_body /
    share_profile_body on iOS, where the English line was hardcoded in three views.

Verified on device

Journey 12 re-run and updated; journeys/RESULTS.md has the table. Android phone (dark, guest) and
Pixel_Tablet in both rotations (light, signed in), iPhone 17 simulator. The attached PNG was pulled
off the device and decoded with zxing — it carries exactly the deck URI, right way up.

Also fixes an unrelated compile error on main: DiscoverScreen.swift passed onRetryBrowse after
onGridColumnsChanged, so iosApp did not build at all.

🤖 Generated with Claude Code

jvsena42 and others added 5 commits September 20, 2026 14:10
`onRetryBrowse` was passed after `onGridColumnsChanged`, which `DiscoverView`
declares before it, so `iosApp` did not compile on `main`. Argument order only.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Five new keys (hint, copy, copied, share, QR content description) on both
platforms, plus `share_deck_body`/`share_profile_body` on iOS, which had the
English line hardcoded in the two profile screens and the deck screen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every share button — deck detail, own profile, someone else's profile — now
raises a sheet holding the link as a QR code, with Copy link and Share…
underneath, instead of going straight to the system chooser. The chooser only
helps someone who already has the recipient in a messaging app; a code needs no
channel at all, and Share attaches the same picture as a PNG.

Three things worth knowing. The grant rides on the intent's `ClipData`, not on
`EXTRA_STREAM` alone — without it the chooser draws no thumbnail and a receiver
that resolves the uri itself is refused. The PNG goes to `cacheDir/share/`, the
one path the new `FileProvider` exposes, as a single overwritten file. And the
copy confirmation is the button's own label rather than a toast: Android 13
raises its own clipboard chip, and the toast landed on top of it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`ShareLinkSheet` mirrors the Android sheet: title, code, middle-elided link,
Copy link and Share…, the last presenting `UIActivityViewController` with the
code as a `UIImage` ahead of the named line.

Two details. `QrCodeView.shareImage` draws through `UIImage`, never
`CGContext.draw`, because the renderer's context is y-flipped and a mirrored QR
is one no scanner reads. And the sheet measures itself for a `.height` detent —
iOS has no fit-the-content detent, and `.large` left the code stranded at the
top of a full-height sheet.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Journey 12's share steps described the old straight-to-chooser behaviour.
Re-run on both emulators and the iPhone 17 simulator; the attached PNG was
pulled off the device and decoded to confirm it carries the deck URI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jvsena42
jvsena42 enabled auto-merge September 20, 2026 17:12
@jvsena42
jvsena42 merged commit 104ac4a into main Sep 20, 2026
8 checks passed
@jvsena42
jvsena42 deleted the feat/share-qr-sheet branch September 20, 2026 17:22
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