Skip to content

feat(chat): send, store and open photo messages - #1681

Open
bmc08gt wants to merge 2 commits into
code/cashfrom
feat/chat-media-transport
Open

bmc08gt wants to merge 2 commits into
code/cashfrom
feat/chat-media-transport

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator

The transport and storage half of chat photos, ported from
code-ios-app#959. Nothing in the app calls it yet; the UI follows in a
stacked PR.

  • Encoding: photos are downscaled and encoded as JPEG down a quality
    ladder of 0.9, 0.8, 0.7, 0.6 until they fit the blob policy, with EXIF
    orientation baked in and a BlurHash for the placeholder. The
    chat_media.json vectors are the iOS file, byte for byte.
  • Encrypted chats: the blob is sealed with the shared-core ChatCipher,
    uploaded with the chat field, and sent as EncryptedContent. A photo
    that can't be opened loads as ChatPhotoUnavailable.
  • Sending: one message per photo, each retried on its own. Finalization
    polls GetBlobs every 2s, at most 30 times, counted only while the app
    is in the foreground.
  • Storage: pending uploads live in Room (schema 42) with the JPEG in
    filesDir, so a send resumes after the app is killed.
  • Loading: a Coil fetcher keyed chat-media-<blobId>, registered in
    FlipcashApp.
  • Fixes found on the way: captions were never sent, because caption
    inside the builder's apply resolved to the builder's own field; and
    a sent message disappeared when the stream delivered its stored copy
    before the send returned, because clearing the pending row deleted by
    its client id.

First of three stacked PRs for chat photos (port of code-payments/code-ios-app#959). Next: the composer layout, then the photo UI.

The transport and storage half of chat photos, ported from
code-ios-app#959. Nothing in the app calls it yet; the UI follows in a
stacked PR.

- Encoding: photos are downscaled and encoded as JPEG down a quality
  ladder of 0.9, 0.8, 0.7, 0.6 until they fit the blob policy, with EXIF
  orientation baked in and a BlurHash for the placeholder. The
  chat_media.json vectors are the iOS file, byte for byte.
- Encrypted chats: the blob is sealed with the shared-core ChatCipher,
  uploaded with the `chat` field, and sent as EncryptedContent. A photo
  that can't be opened loads as ChatPhotoUnavailable.
- Sending: one message per photo, each retried on its own. Finalization
  polls GetBlobs every 2s, at most 30 times, counted only while the app
  is in the foreground.
- Storage: pending uploads live in Room (schema 43) with the JPEG in
  filesDir, so a send resumes after the app is killed.
- Loading: a Coil fetcher keyed `chat-media-<blobId>`, registered in
  FlipcashApp.
- Fixes found on the way: captions were never sent, because `caption`
  inside the builder's `apply` resolved to the builder's own field; and
  a sent message disappeared when the stream delivered its stored copy
  before the send returned, because clearing the pending row deleted by
  its client id.
@bmc08gt
bmc08gt force-pushed the feat/chat-media-transport branch from 37fc323 to cca6d0b Compare October 6, 2026 00:58
@github-actions github-actions Bot added the type: feature New functionality label Oct 6, 2026
A photo that finished uploading while it sat in the composer confirms
within about 100 ms of the tap. Room hasn't drawn the pending row by
then, so the bubble's first frame already reads Sent and the bar never
shows. On the Seeker the new bubble landed as Delivered with no bar in
any frame.

The Sent stage now waits until 800 ms after the row was inserted. The
message is still confirmed in the database at once; only the bar's
phase waits, and a later post in the same batch isn't held up.
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