20 KiB
SimpleX Chat iOS -- Chat View Module
Technical specification for the message rendering, chat item types, and context menu actions in the conversation view.
Related specs: Compose Module | State Management | API Reference | README Related product: Chat View
Source: ChatView.swift | ChatInfoView.swift | GroupChatInfoView.swift
Table of Contents
- Overview
- ChatView
- ChatItemView -- Message Routing
- Message Renderers
- Media Views
- Metadata & Info
- Context Menu Actions
- Selection Mode
1. Overview
The chat view module renders individual conversations. It consists of:
- ChatView -- The main conversation screen with message list, compose bar, and navigation
- ChatItemView -- Router that dispatches each chat item to the appropriate renderer
- Specialized renderers -- FramedItemView (standard messages), EmojiItemView (emoji-only), CICallItemView (calls), event views, etc.
- Media views -- CIImageView, CIVideoView, CIVoiceView, CIFileView for attachments
ChatView
├── Message List (ScrollView / LazyVStack)
│ ├── ChatItemView (per message)
│ │ ├── FramedItemView (text/media bubbles)
│ │ │ ├── MsgContentView (text with markdown)
│ │ │ ├── CIImageView / CIVideoView / CIVoiceView
│ │ │ └── CIMetaView (timestamp, status)
│ │ ├── EmojiItemView (emoji-only messages)
│ │ ├── CICallItemView (call events)
│ │ ├── CIEventView (system events)
│ │ ├── CIGroupInvitationView (group invitations)
│ │ ├── DeletedItemView / MarkedDeletedItemView
│ │ └── CIInvalidJSONView (decode errors)
│ └── ... (more items)
├── ComposeView (message input)
└── Navigation bar (contact/group info)
2. ChatView
File: Shared/Views/Chat/ChatView.swift
The main conversation view. Key responsibilities:
State
- Uses
ItemsModel.shared.reversedChatItemsfor the primary message list ChatModel.shared.chatIdidentifies the active conversation- Manages compose state, scroll position, keyboard visibility
- Tracks selection mode for multi-message actions
Message List
- Renders messages in a
ScrollViewReaderwithLazyVStack - Items are in reverse chronological order (newest at bottom)
- Supports infinite scroll: preloads older messages when scrolling up via
ItemsModel.preloadState - Handles pagination splits (
chatState.splits) for non-contiguous loaded ranges
Navigation Bar
- Title: contact name / group name with connection status indicator
- Trailing button: navigates to
ChatInfoView(direct) orGroupChatInfoView(group) - Search button: toggles in-chat message search
Scroll Behavior
- Auto-scrolls to bottom on new sent/received messages (if already near bottom)
- "Scroll to bottom" floating button when scrolled up
openAroundItemIdsupport: scrolls to a specific message (e.g., from search or notification)
Key Functions
| Function | Line | Description |
|---|---|---|
body |
L74 | Main view body |
initChatView() |
L672 | Initializes chat view state on appear |
chatItemsList() |
L814 | Builds the scrollable message list |
scrollToItem(_:) |
L731 | Scrolls to a specific message by ID |
searchToolbar() |
L764 | In-chat search toolbar UI |
searchTextChanged(_:) |
L1087 | Handles search query changes |
loadChatItems(_:_:) |
L1519 | Loads chat items with pagination |
filtered(_:) |
L801 | Filters items by content type |
callButton(_:_:imageName:) |
L1264 | Audio/video call toolbar button |
searchButton() |
L1284 | Search toggle toolbar button |
addMembersButton() |
L1352 | Group add-members toolbar button |
forwardSelectedMessages() |
L1409 | Forwards batch-selected messages |
deletedSelectedMessages() |
L1401 | Deletes batch-selected messages |
onChatItemsUpdated() |
L1559 | Reacts to chat items model changes |
contentFilterMenu(withLabel:) |
L1292 | Content filter dropdown menu |
Supporting Types
| Type | Line | Description |
|---|---|---|
ChatItemWithMenu |
L1586 | Wraps each chat item with context menu |
FloatingButtonModel |
L2697 | Manages scroll-to-bottom button state |
ReactionContextMenu |
L2882 | Reaction picker context menu |
ToggleNtfsButton |
L2980 | Mute/unmute notifications button |
ContentFilter |
L3031 | Enum for message content filter types |
deleteMessages() |
L2779 | Deletes messages with confirmation |
archiveReports() |
L2826 | Archives report messages |
3. ChatItemView
File: Shared/Views/Chat/ChatItemView.swift
Routes each ChatItem to the appropriate renderer based on its CIContent type:
Content Types (CIContent enum)
| Content Type | Renderer | Line | Description |
|---|---|---|---|
sndMsgContent / rcvMsgContent |
FramedItemView |
L13 | Standard sent/received text+media message |
sndDeleted / rcvDeleted |
DeletedItemView |
L13 | Locally deleted message placeholder |
sndCall / rcvCall |
CICallItemView |
L13 | Call event (missed, ended, duration) |
rcvIntegrityError |
IntegrityErrorItemView |
L13 | Message integrity error |
rcvDecryptionError |
CIRcvDecryptionError |
L15 | Decryption failure |
sndGroupInvitation / rcvGroupInvitation |
CIGroupInvitationView |
L13 | Group invite |
sndGroupEvent / rcvGroupEvent |
CIEventView |
L13 | Group system event |
rcvConnEvent / sndConnEvent |
CIEventView |
L13 | Connection event |
rcvChatFeature / sndChatFeature |
CIChatFeatureView |
L13 | Feature toggle event |
rcvChatPreference / sndChatPreference |
CIFeaturePreferenceView |
L13 | Preference change |
invalidJSON |
CIInvalidJSONView |
L13 | Failed to decode |
Bubble Direction
- Sent messages: aligned right, sender-colored bubble
- Received messages: aligned left, receiver-colored bubble
- Events/system messages: centered, no bubble
Appearance Dependencies
Each ChatItemWithMenu may depend on the previous and next items for visual decisions:
- Whether to show the sender name (group messages, different sender than previous)
- Whether to show the tail on the bubble (last consecutive message from same sender)
- Date separator between messages on different days
ChatItemDummyModel.shared.sendUpdate() forces a re-render of all items when global appearance changes.
4. Message Renderers
FramedItemView
File: Shared/Views/Chat/ChatItem/FramedItemView.swift
The standard message bubble. Renders:
- Quote/reply preview (if replying to another message)
- Forwarded indicator
- Sender name (in groups)
- Message content (
MsgContentViewwith markdown) - Attached media (image, video, voice, file, link preview)
- Reaction summary bar
- Metadata line (
CIMetaView)
EmojiItemView
File: Shared/Views/Chat/ChatItem/EmojiItemView.swift
Renders emoji-only messages (messages containing only emoji characters) in a larger font without a bubble background.
MsgContentView
File: Shared/Views/Chat/ChatItem/MsgContentView.swift
Renders message text with SimpleX markdown formatting (bold, italic, code, links, mentions).
DeletedItemView / MarkedDeletedItemView
Files: Shared/Views/Chat/ChatItem/DeletedItemView.swift | Shared/Views/Chat/ChatItem/MarkedDeletedItemView.swift
DeletedItemView: Placeholder for locally deleted messagesMarkedDeletedItemView: Shows "message deleted" with optional moderation info (who deleted, when)
CIEventView
File: Shared/Views/Chat/ChatItem/CIEventView.swift
Centered system event text for group events (member joined, left, role changed) and connection events.
CIGroupInvitationView
File: Shared/Views/Chat/ChatItem/CIGroupInvitationView.swift
Renders group invitation with accept/reject buttons.
5. Media Views
CIImageView
File: Shared/Views/Chat/ChatItem/CIImageView.swift
Renders inline images. Tapping opens FullScreenMediaView for zooming/panning. Images are compressed to MAX_IMAGE_SIZE (255KB) before sending.
CIVideoView
File: Shared/Views/Chat/ChatItem/CIVideoView.swift
Renders video thumbnails with play button. Tapping opens video player. Videos above auto-receive threshold require manual download.
CIVoiceView / FramedCIVoiceView
Files: Shared/Views/Chat/ChatItem/CIVoiceView.swift | Shared/Views/Chat/ChatItem/FramedCIVoiceView.swift
Renders voice messages with waveform visualization, play/pause control, and duration. FramedCIVoiceView is the version inside a message bubble with additional context.
CIFileView
File: Shared/Views/Chat/ChatItem/CIFileView.swift
Renders file attachments with filename, size, and download/open actions. Shows transfer progress during upload/download.
CILinkView
File: Shared/Views/Chat/ChatItem/CILinkView.swift
Renders link preview cards with OpenGraph metadata (title, description, image).
AnimatedImageView
File: Shared/Views/Chat/ChatItem/AnimatedImageView.swift
Renders animated GIF images.
FullScreenMediaView
File: Shared/Views/Chat/ChatItem/FullScreenMediaView.swift
Full-screen media viewer with zoom, pan, and share actions. Supports images and videos.
6. Metadata & Info
CIMetaView
File: Shared/Views/Chat/ChatItem/CIMetaView.swift
Displays message metadata inline at the bottom of the bubble:
- Timestamp (sent time)
- Delivery status icon (sending, sent, delivered, read, error)
- Edit indicator (pencil icon if message was edited)
- Disappearing message timer (if timed message)
ChatItemInfoView
File: Shared/Views/Chat/ChatItemInfoView.swift
Detailed message information sheet (accessed via long-press menu "Info"):
- Full delivery history (per-member delivery status in groups)
- Edit history (all previous versions of edited messages)
- Forward chain info
- Message timestamps (created, updated, deleted)
7. Context Menu Actions
Long-pressing a message shows a context menu with actions based on message type and ownership:
| Action | Available For | API Command |
|---|---|---|
| Reply | All messages | Sets compose state to .replying |
| Forward | Sent/received content messages | apiForwardChatItems |
| Copy | Text messages | Copies to clipboard |
| Edit | Own sent messages (within edit window) | apiUpdateChatItem |
| Delete for me | All messages | apiDeleteChatItem(mode: .cidmInternal) |
| Delete for everyone | Own sent messages | apiDeleteChatItem(mode: .cidmBroadcast) |
| Moderate | Group admin/owner for others' messages | apiDeleteMemberChatItem |
| React | Content messages (if reactions enabled) | apiChatItemReaction |
| Select | All messages | Enters multi-select mode |
| Info | All messages | Opens ChatItemInfoView |
| Save | Media messages | Saves to photo library / files |
| Share | Content messages | iOS share sheet |
8. Selection Mode
Multi-selection mode allows batch operations on messages:
- Enter via long-press "Select" action
- Toggle individual messages with tap
- Toolbar appears with batch actions: Delete, Forward
- Exit via cancel button or completing batch action