Skip to content

feat(chat): add pin message contract scaffolding - #1165

Open
bmc08gt wants to merge 5 commits into
mainfrom
feat/chat-pins-contract
Open

bmc08gt wants to merge 5 commits into
mainfrom
feat/chat-pins-contract

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Data and API scaffolding for chat pinned messages (flipcash2 contract 0.24.0, upstream #164). No UI.

Pins flipcash2-client-protocol to 0.24.0 (published from code-payments/flipcash2-client-protocol#32), with Package.swift and Package.resolved moved together by bump-contract.sh.

  • FlipcashCore: ConversationPin, ConversationPinSummary, ConversationPinChange, ConversationPinsPage. Conversation.pinSummary, ConversationViewerState.canPin, and a .pinsChanged stream event.
  • ConversationStore applies pinsChanged and keeps only the greater version. setFeed and upsert keep a held summary when a feed row has none.
  • ChatService and FlipClient+Chat add pinMessage, unpinMessage, getPinnedMessages with ErrorPinMessage, ErrorUnpinMessage, ErrorGetPinnedMessages.
  • App target: EncryptedChatClient and ConversationController handle the new case in their exhaustive switches.
  • Schema 61 → 62: the conversation table gains pinCount, pinVersion and pinLatest (the serialized chat.v1.Pin), so the summary survives restarts and reads offline. writeConversation updates the pin columns only when the incoming summary's version is equal or higher, so a feed row without one never clears them. .pinsChanged persists through Database.applyPinSummary, which writes only a strictly newer version. getConversations() loads the summary back.
  • ConversationViewerState now encodes canInvite and canPin. Both were left out of CodingKeys and read back as false after a cold start, which is what viewerStateCanInviteRoundTrip on main was catching. Older rows decode both as false.
  • Tests: ConversationPinTests is new, and TransportClassificationTests gets the new RPCs. DatabaseConversationsTests covers the pin write rules, the cold-load round trip and canPin.

Not done yet: pinned messages in E2EE chats aren't opened. Pin and unpin results aren't applied to the store yet.

Wrap PinMessage, UnpinMessage and GetPinnedMessages with typed Error*
results, and map Pin, PinSummary, Metadata.pin_summary,
MetadataUpdate.pins_changed and ViewerState.Permissions.can_pin into the
domain models. The store keeps the greater pin-summary version and keeps a
held summary when a feed copy omits it. Built against the local
flipcash2-client-protocol override; the pin is unchanged.
@bmc08gt
bmc08gt marked this pull request as ready for review October 29, 2026 23:04
Store each conversation's pin count, version and latest pin (the
serialized chat.v1.Pin) on its row, so a cold start and an offline
launch carry the summary. A write with no summary or an older version
keeps the stored pins; PinsChanged applies only when strictly newer,
matching ConversationStore. Bumps Database.schemaVersion to 62.
The viewer state's CodingKeys left both permissions out, so they read back
as false after a cold start. Rows written by earlier schemas still decode,
with a missing key reading as false.
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