mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-04-15 05:05:56 +00:00
9.8 KiB
9.8 KiB
Messaging Flow
Related spec: spec/api.md | spec/client/chat-view.md | spec/client/compose.md
Overview
Complete message lifecycle in SimpleX Chat iOS: composing, sending, receiving, editing, deleting, reacting to, replying to, and forwarding messages. All messages are end-to-end encrypted via the SMP protocol. The Haskell core handles encryption, routing, and persistence; the Swift UI layer drives composition and display.
Prerequisites
- User profile created and chat engine running (
startChat()completed) - At least one established contact or group conversation
ChatModel.sharedpopulated with chat list data
Step-by-Step Processes
1. Send Text Message
- User navigates to a conversation (direct or group) via
ChatListView->ChatView. - User types text into
ComposeView'sSendMessageViewtext editor. - Link previews are detected and fetched asynchronously (
ComposeLinkView). - User taps the send button.
ComposeViewbuilds aComposedMessage:ComposedMessage( fileSource: nil, quotedItemId: nil, msgContent: .text("Hello"), mentions: [:] )- Calls
apiSendMessages(type:id:scope:live:ttl:composedMessages:sendAsGroup:)(wheresendAsGroupdefaults tofalse; set totruewhen a channel owner sends as the channel identity). - Internally dispatches
ChatCommand.apiSendMessages(...)to the Haskell core. - Core encrypts, queues via SMP, and returns
ChatResponse1.newChatItems(user, aChatItems). processSendMessageCmdextracts[ChatItem]from response.- For direct chats, a background task tracks delivery via
chatModel.messageDelivery. ChatModelupdates, UI refreshes to show the new message.
2. Send Media (Image/Video/File)
- User taps the attachment button in
ComposeView. - Image: Picked via
PhotosPickeror camera. Compressed to <=255KB. Sent inline with.image(text, base64Image)content type. - Video: Picked from library. Thumbnail generated. Video file sent via XFTP for files >255KB. Content type:
.video(text, thumbnail, duration). - File: Picked via document picker. If <=255KB, sent inline. If >255KB, uploaded via XFTP (up to 1GB). Content type:
.file(text). ComposedMessageincludesfileSource: CryptoFile(filePath:).apiSendMessages(...)called with the composed message array.- Core handles XFTP upload for large files (chunked, encrypted upload to XFTP servers).
- Recipient receives file reference and can download.
3. Receive Message
ChatReceiver.sharedrunsreceiveMsgLoop()continuously callingchatRecvMsg().- Core delivers events via
APIResult<ChatEvent>. - On
ChatEvent.newChatItems(user, chatItems):processReceivedMsgis called.- For the active user,
ChatModelis updated with new items. - If the chat is currently open,
ItemsModelappends toreversedChatItems. NtfManagerposts a local notification if the app is in the background.
- Small files/images attached to incoming messages are auto-received if within size thresholds.
4. Edit Message
- User long-presses a sent message -> selects "Edit" from context menu.
ComposeViewenters edit mode with the original text pre-filled.- User modifies text and taps send.
- Calls
apiUpdateChatItem(type:id:scope:itemId:updatedMessage:live:). - Dispatches
ChatCommand.apiUpdateChatItem(...). - Core returns
ChatResponse1.chatItemUpdated(user, aChatItem)or.chatItemNotChanged(user, aChatItem). ChatModelupdates the item in place. Edit timestamp is shown in the UI.
5. Delete Message
- User long-presses a message -> selects "Delete".
- Presented with options:
- Delete for me (
CIDeleteMode.cidmInternal) -- removes locally only. - Delete for everyone (
CIDeleteMode.cidmBroadcast) -- sends deletion to recipient(s).
- Delete for me (
- Calls
apiDeleteChatItems(type:id:scope:itemIds:mode:). - Dispatches
ChatCommand.apiDeleteChatItem(type:id:scope:itemIds:mode:). - Core returns
ChatResponse1.chatItemsDeleted(user, items, _)containing[ChatItemDeletion]. - For group messages from other members, admin/owner can call
apiDeleteMemberChatItems(groupId:itemIds:). ChatModelremoves or replaces items with "deleted" placeholders.
6. React to Message
- User long-presses a message -> selects "React" -> picks an emoji.
- Calls
apiChatItemReaction(type:id:scope:itemId:add:reaction:). reactionisMsgReaction(e.g.,.emoji(.heart)).add: trueto add,add: falseto remove.- Core returns
ChatResponse1.chatItemReaction(user, _, reaction). - The reaction is displayed below the message bubble.
7. Reply to Message
- User long-presses a message -> selects "Reply".
ComposeViewenters reply mode, showing quoted message inContextItemView.- User types reply text and taps send.
ComposedMessageis created withquotedItemId: originalItem.id.apiSendMessages(...)sends with the quote reference.- Recipient sees the reply with the quoted context rendered above.
8. Forward Message
- User long-presses a message -> selects "Forward".
ChatItemForwardingViewis presented for destination chat selection.apiPlanForwardChatItems(type:id:scope:itemIds:)validates what can be forwarded, returns([Int64], ForwardConfirmation?).- User confirms and selects destination chat.
- Calls
apiForwardChatItems(toChatType:toChatId:toScope:fromChatType:fromChatId:fromScope:itemIds:ttl:sendAsGroup:)(wheresendAsGroupdefaults tofalse). - Core returns
ChatResponse1.newChatItems(...)with the forwarded items in the destination chat.
9. Voice Message
- User taps and holds the microphone button in
ComposeView. AudioRecPlaystarts recording to a temporary file.- On release, recording stops. Duration is calculated (max 5 minutes / 300 seconds).
ComposedMessagecreated with:fileSource: CryptoFilepointing to the audio filemsgContent: .voice(text: "", duration: seconds)
apiSendMessages(...)sends the voice message.- Voice messages <=510KB sent inline; larger via XFTP.
- Recipient sees
CIVoiceViewwith waveform and playback controls.
10. Delivery Tracking
- On send, message status starts as
CIStatus.sndNew. - After SMP delivery:
CIStatus.sndSent(sndProgress). - When delivered to recipient's agent: status updates to delivered.
- If delivery receipts are enabled by both parties, read status is reported.
- Failed delivery results in
CIStatus.sndError*orCIStatus.sndWarning*. - Status is displayed via
CIMetaView(checkmarks/indicators).
Data Structures
| Type | Location | Description |
|---|---|---|
ComposedMessage |
SimpleXChat/APITypes.swift |
Outgoing message: fileSource, quotedItemId, msgContent, mentions |
MsgContent |
SimpleXChat/ChatTypes.swift |
Enum: .text, .link, .image, .video, .voice, .file |
CIContent |
SimpleXChat/ChatTypes.swift |
Chat item content wrapper with sent/received variants |
CIStatus |
SimpleXChat/ChatTypes.swift |
Delivery status: sndNew, sndSent, sndError, rcvNew, rcvRead |
CIDirection |
SimpleXChat/ChatTypes.swift |
.directSnd, .directRcv, .groupSnd, .groupRcv(groupMember), .channelRcv |
ChatItem |
SimpleXChat/ChatTypes.swift |
Full message model: content, meta, status, direction, quotedItem |
ChatItemDeletion |
SimpleXChat/ChatTypes.swift |
Deleted item info with old/new item pairs |
CIDeleteMode |
SimpleXChat/ChatTypes.swift |
.cidmInternal (local) or .cidmBroadcast (for everyone) |
MsgReaction |
SimpleXChat/ChatTypes.swift |
Reaction type (emoji-based) |
UpdatedMessage |
SimpleXChat/APITypes.swift |
Edited message content for update API |
Error Cases
| Error | Cause | Handling |
|---|---|---|
ChatError.errorAgent(.SMP(_, .AUTH)) |
Recipient queue issue | Show "Connection error (AUTH)" alert |
ChatError.errorAgent(.BROKER(_, .TIMEOUT)) |
Server timeout | Retryable: show retry dialog via chatApiSendCmdWithRetry |
ChatError.errorAgent(.BROKER(_, .NETWORK)) |
Network failure | Retryable: show retry dialog |
| Send message error | Core processing failure | sendMessageErrorAlert shown to user |
chatItemNotChanged |
Edit with identical content | No error, item returned unchanged |
| File too large (>1GB) | XFTP limit exceeded | Prevented in UI file picker |
fileNotApproved |
Unknown XFTP relay servers | Show "Unknown servers!" alert with approve option |
Key Files
| File | Purpose |
|---|---|
Shared/Views/Chat/ComposeMessage/ComposeView.swift |
Message composition UI and send logic |
Shared/Views/Chat/ComposeMessage/SendMessageView.swift |
Text input and send button |
Shared/Views/Chat/ComposeMessage/ContextItemView.swift |
Reply/edit context display |
Shared/Views/Chat/ChatItemView.swift |
Per-message rendering dispatcher |
Shared/Views/Chat/ChatItem/MsgContentView.swift |
Text message content with markdown |
Shared/Views/Chat/ChatItem/CIMetaView.swift |
Delivery status indicators |
Shared/Views/Chat/ChatItemForwardingView.swift |
Forward destination picker |
Shared/Views/Chat/ChatItemInfoView.swift |
Message info (delivery details, timestamps) |
Shared/Model/SimpleXAPI.swift |
API functions: apiSendMessages, apiUpdateChatItem, apiDeleteChatItems, apiChatItemReaction, apiForwardChatItems |
SimpleXChat/APITypes.swift |
ComposedMessage, ChatCommand enum, response types |
SimpleXChat/ChatTypes.swift |
MsgContent, CIContent, CIStatus, CIDirection, ChatItem |
Shared/Model/AudioRecPlay.swift |
Voice message recording/playback engine |
Related Specifications
apps/ios/product/views/chat.md-- Chat view UI specificationapps/ios/product/README.md-- Product overview and capability map