Skip to content

feat(chat): encrypt and cache photos, and keep sends alive in the background - #963

Merged
bmc08gt merged 2 commits into
feat/chat-media-sendfrom
feat/chat-media-offline
Oct 5, 2026
Merged

bmc08gt merged 2 commits into
feat/chat-media-sendfrom
feat/chat-media-offline

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Third of four stacked PRs for chat photos, on top of #962. Encrypts photos in encrypted DMs, caches them on disk, and keeps a send alive through backgrounding and relaunch.

  • In an encrypted DM a photo is sealed with the shared-core chat cipher and sent as EncryptedContent. Incoming ones are decrypted before they are drawn; one that can't be opened shows as unavailable.
  • Downloaded photos are cached on disk by blob id, so they no longer fall back to the blur hash after five minutes.
  • The READY poll retries through a dropped stream, its deadline counts only time the app is awake, and the send holds a background task assertion.
  • Pending photos are written to disk at send. After a relaunch, one whose bytes were stored resumes, and one that never reached the server comes back failed with retry.
  • Outgoing bubbles show upload progress, then a sliding segment while the server processes the blob, which reports no progress.

Design notes: .claude/plans/2026-10-03-pending-photo-persistence.md.

Stack: #961 → #962 → this → #964.

Downloaded photos go to a dedicated Kingfisher disk cache keyed by blob
id, so they no longer fall back to the blur hash after five minutes.

In an encrypted DM a photo is sealed with the shared-core chat cipher,
stored with endToEndEncryptedFor set to the chat, and sent as
EncryptedContent. Incoming encrypted photos are decrypted before they
are drawn, and one that can't be opened shows as unavailable.

Blob rejections now log the server's reason code instead of "unknown".
Outgoing photo bubbles show a thin progress bar in the corner: the
upload's byte fraction, then a sliding segment while the server
processes the blob, which has no progress signal.

A send no longer fails when the app is backgrounded mid-send. The
READY poll retries through a dropped stream, its deadline only counts
time the app is awake, and the send holds a background task assertion.
A retry after the bytes are stored polls again instead of uploading
again.

Pending photos are written to disk at send, so a relaunch restores them:
one whose bytes were stored resumes, one that never reached the server
comes back failed with retry, and one that already sent is dropped.
@bmc08gt
bmc08gt force-pushed the feat/chat-media-offline branch from 6688e2d to f26ae2d Compare October 5, 2026 22:23
@bmc08gt
bmc08gt merged commit ed4aba3 into main Oct 5, 2026
2 of 3 checks passed
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