Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions ui-kit/ios/conversations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@
"callbacks": {
"onItemClick": "(Conversation, IndexPath) -> Void",
"onItemLongClick": "(Conversation, IndexPath) -> Void",
"onBack": "() -> Void",

Check warning on line 35 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L35

Did you really mean 'onBack'?
"onSelection": "([Conversation]) -> Void",

Check warning on line 36 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L36

Did you really mean 'onSelection'?
"onError": "(CometChatException) -> Void",

Check warning on line 37 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L37

Did you really mean 'onError'?
"onEmpty": "() -> Void",

Check warning on line 38 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L38

Did you really mean 'onEmpty'?
"onLoad": "([Conversation]) -> Void"

Check warning on line 39 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L39

Did you really mean 'onLoad'?
},
"visibility": {
"hideSearch": { "type": "Bool", "default": false },
Expand All @@ -52,7 +52,7 @@
"customSoundForMessages": { "type": "URL?", "default": "nil" }
},
"selection": {
"selectionMode": { "type": "SelectionMode", "default": ".none" }

Check warning on line 55 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L55

Did you really mean 'selectionMode'?
},
"viewSlots": {
"listItemView": "(Conversation) -> UIView",
Expand Down Expand Up @@ -398,15 +398,67 @@

---

## Pinning Conversations

*Available since v5.1.22*

A pinned conversation sits at the top of the list with a pin indicator on the row, and holds that position as new messages arrive in other chats. A personal pin is **private to the logged-in user** — nobody else sees it — and syncs to that user's other devices.

<Warning>
**Two gates, both required.** Pin Conversation needs the `features.ux.conversations.pinned.enabled` app setting mapped for your app, *and* your own opt-in via `enablePinConversation`. With either missing the swipe action never appears. The kit reads the app setting through `CometChat.isPinConversationEnabled()`.
</Warning>

```swift lines
import CometChatUIKitSwift

let conversations = CometChatConversations()
conversations.enablePinConversation = true // off by default
```

Pinning applies immediately; **unpinning asks for confirmation first**. Hide the action on a single list with [`hidePinConversationOption`](#hidepinconversationoption) while it stays available elsewhere.

### Admin Pins

An app can also pin a conversation **for everyone**. A system pin sorts above every personal pin, and is not the user's to remove — the kit does not offer the unpin affordance on those rows at all.

Check warning on line 422 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L422

Did you really mean 'affordance'?

To reflect the same distinction in a view of your own, read the two properties the SDK exposes on `Conversation`:

```swift lines
import CometChatSDK

// `pinnedAt` uses a 0 sentinel, so presence — not `> 0` — is the pinned test.
let isPinned = conversation.pinnedAt != 0

// An admin/global pin. A user cannot unpin one, so hide or disable your unpin control.
let isSystemPinned = isPinned && conversation.pinnedBy == "app_system"
```

<Note>
The UI Kit has no public helper for this yet — unlike the React Native kit's `isSystemPinnedConversation()` — so the `"app_system"` sentinel has to be compared directly for now.
</Note>

### Errors

A failed pin surfaces as a toast. `PinConversationErrorCodes` names the codes the backend emits, so you can match them in your own handling:

| Code | Meaning |
|---|---|
| `ERR_PINNED_CONVERSATIONS_LIMIT_EXCEEDED` | The user is at the per-user pinned cap. The real cap rides in `errorParams` — never hard-code it. |
| `ERR_CONVERSATION_NOT_ACCESSIBLE` | No conversation row yet (never messaged), or deleted-for-me. |
| `ERR_PERMISSION_DENIED` | RBAC denial. |
| `ERR_BAD_REQUEST` | Invalid `pinnedBy` filter or malformed body. |

---

## Custom View Slots

| Slot | Signature | Replaces |
|------|-----------|----------|
| `listItemView` | `(Conversation) -> UIView` | Entire conversation row |
| `leadingView` | `(Conversation) -> UIView` | Avatar / left section |

Check warning on line 458 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L458

Did you really mean 'leadingView'?
| `titleView` | `(Conversation) -> UIView` | Name / title text |

Check warning on line 459 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L459

Did you really mean 'titleView'?
| `subtitleView` | `(Conversation) -> UIView` | Last message preview |

Check warning on line 460 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L460

Did you really mean 'subtitleView'?
| `trailView` | `(Conversation) -> UIView` | Right side (time, badge) |

Check warning on line 461 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L461

Did you really mean 'trailView'?
| `emptyStateView` | `UIView` | Empty state display — assign a view, not a closure |
| `errorStateView` | `UIView` | Error state display — assign a view, not a closure |
| `loadingView` | `UIView` | Loading state display — assign a view, not a closure |
Expand Down Expand Up @@ -740,7 +792,7 @@
| List item look | Style | `listItemBackground` | `UIColor(white: 0.95, alpha: 1.0)` |
| Unread badge | Style | `badgeStyle` | `BadgeStyle()` with custom colors |
| Avatar appearance | Style | `avatarStyle` | `AvatarStyle()` with custom radius |
| Hide search | Property | `hideSearch` | `conversations.hideSearch = true` |

Check warning on line 795 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L795

Did you really mean 'hideSearch'?
| Hide receipts | Property | `hideReceipts` | `conversations.hideReceipts = true` |
| Custom row | View Slot | `set(listItemView:)` | See Custom View Slots section |

Expand Down Expand Up @@ -938,7 +990,7 @@

#### set(textFormatters:)

Sets custom text formatters for processing and displaying message text in conversation subtitles.

Check warning on line 993 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L993

Did you really mean 'formatters'?

```swift lines
@discardableResult
Expand All @@ -947,7 +999,7 @@

| Parameter | Type | Description |
|-----------|------|-------------|
| `textFormatters` | `[CometChatTextFormatter]` | Array of text formatters to apply to message text |

Check warning on line 1002 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L1002

Did you really mean 'textFormatters'?

Check warning on line 1002 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L1002

Did you really mean 'formatters'?

```swift lines
import CometChatUIKitSwift
Expand All @@ -967,7 +1019,7 @@

All props are optional. Sorted alphabetically.

### avatarStyle

Check warning on line 1022 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L1022

Did you really mean 'avatarStyle'?

Customizes the appearance of avatars in conversation list items.

Expand All @@ -990,7 +1042,7 @@
conversations.avatarStyle = avatarStyle
```

### badgeStyle

Check warning on line 1045 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L1045

Did you really mean 'badgeStyle'?

Customizes the appearance of unread message count badges.

Expand Down Expand Up @@ -1022,7 +1074,7 @@
| Type | `ConversationRequest.ConversationRequestBuilder?` |
| Default | `nil` |

### dateStyle

Check warning on line 1077 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L1077

Did you really mean 'dateStyle'?

Customizes the appearance of date/time labels in conversation list items.

Expand Down Expand Up @@ -1083,7 +1135,7 @@
| Type | `Bool` |
| Default | `false` |

### disableTyping

Check warning on line 1138 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L1138

Did you really mean 'disableTyping'?

Disables typing indicators in the conversation list.

Expand All @@ -1099,6 +1151,24 @@
conversations.disableTyping = true
```

### enablePinConversation

*Available since v5.1.22*

Adds the **Pin / Unpin** swipe action to each row. Off by default — see [Pinning Conversations](#pinning-conversations) for the feature, including the app setting it also requires.

| | |
|---|---|
| Type | `Bool` |
| Default | `false` |

```swift lines
import CometChatUIKitSwift

let conversations = CometChatConversations()
conversations.enablePinConversation = true
```

### hideBackButton

Hides the back button in the navigation bar.
Expand Down Expand Up @@ -1135,7 +1205,25 @@
| Type | `Bool` |
| Default | `false` |

### hidePinConversationOption

*Available since v5.1.22*

Hides the Pin / Unpin swipe action on one list while the feature stays on elsewhere. ANDed with `enablePinConversation` and the app setting — see [Pinning Conversations](#pinning-conversations).

Check warning on line 1212 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L1212

Did you really mean 'ANDed'?

| | |
|---|---|
| Type | `Bool` |
| Default | `false` |

```swift lines
import CometChatUIKitSwift

let conversations = CometChatConversations()
conversations.hidePinConversationOption = true
```

### hideReceipts

Check warning on line 1226 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L1226

Did you really mean 'hideReceipts'?

Hides read/delivered receipt indicators.

Expand Down Expand Up @@ -1214,7 +1302,7 @@
conversations.protectedGroupIcon = UIImage(systemName: "lock.shield.fill")
```

### receiptStyle

Check warning on line 1305 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L1305

Did you really mean 'receiptStyle'?

Customizes the appearance of message receipt indicators (sent, delivered, read).

Expand Down Expand Up @@ -1269,7 +1357,7 @@

### textFormatters

Array of text formatters for customizing message text display.

Check warning on line 1360 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L1360

Did you really mean 'formatters'?

| | |
|---|---|
Expand Down Expand Up @@ -1362,7 +1450,7 @@
})
```

### Available Formatters

Check warning on line 1453 in ui-kit/ios/conversations.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/conversations.mdx#L1453

Did you really mean 'Formatters'?

| Formatter | Purpose | Default Format |
|-----------|---------|----------------|
Expand Down
65 changes: 36 additions & 29 deletions ui-kit/ios/core-features.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
{"name": "reactions", "description": "Let users react to messages with emojis", "component": "CometChatMessageList", "enabledByDefault": true},
{"name": "mentions", "description": "Tag users in messages with @mentions", "component": "CometChatMessageComposer", "enabledByDefault": true},
{"name": "threadedConversations", "description": "Reply to specific messages in threads", "component": "CometChatThreadedMessageHeader", "enabledByDefault": true},
{"name": "threadSubscription", "description": "Subscribe to or unsubscribe from a thread's replies", "component": "CometChatMessageList", "enabledByDefault": false},
{"name": "threadSubscription", "description": "Subscribe to or unsubscribe from a thread's replies — a bell in the thread screen's top bar, plus an option in the message action sheet", "component": "CometChatMessageHeader, CometChatMessageList", "enabledByDefault": true},
{"name": "groupChat", "description": "Create and manage group conversations", "component": "CometChatGroups", "enabledByDefault": true},
{"name": "search", "description": "Search across conversations and messages", "component": "CometChatSearch", "enabledByDefault": true}
],
Expand Down Expand Up @@ -106,7 +106,7 @@
}
```

Received messages render with per-type bubbles: a **media grid** for images and videos (with a fullscreen viewer — swipe, zoom, per-photo download, share), **playback rows** for audio files, and a **connected card stack** for documents. Messages from one send are grouped visually in the list. Per-message file count and per-file size limits come from your app's dashboard settings; violations surface directly in the tray.

Check warning on line 109 in ui-kit/ios/core-features.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/core-features.mdx#L109

Did you really mean 'fullscreen'?

See [Message Composer — Multiple Attachments](/ui-kit/ios/message-composer#multiple-attachments) for configuration and [Message Bubble Styling](/ui-kit/ios/message-bubble-styling) for the bubbles.

Expand Down Expand Up @@ -446,7 +446,7 @@
`enableRichTextFormatting` and `showRichTextFormattingOptions` are `true` by default. See the [CompactMessageComposer Rich Text Formatting](/ui-kit/ios/compact-message-composer#rich-text-formatting) section for full configuration details.

<Note>
Rich text formatting in message bubbles (rendering formatted text in the MessageList) is supported from UI Kit version 5.2.11 onwards. Earlier versions will display the raw markdown syntax instead of formatted text.

Check warning on line 449 in ui-kit/ios/core-features.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/core-features.mdx#L449

Did you really mean 'onwards'?
</Note>

| Component | Functionality |
Expand Down Expand Up @@ -561,12 +561,14 @@
**Component Used:**
- [ThreadedMessages](/ui-kit/ios/threaded-messages-header) - Displays thread replies

## Thread Subscription
### Thread Subscription

*Available since v5.1.22*

Let users subscribe to a thread to be notified about its replies, or unsubscribe to mute it. Users are subscribed automatically when they start a thread, reply in one, or are @-mentioned in one — subscribing explicitly is how they opt in to a thread they haven't participated in yet.

On by default — there is no dashboard flag for this feature, so `CometChatThreadSubscriptionConfig.setEnabled(false)` is the only way to remove it. See [Turning the Feature Off](/ui-kit/ios/guide-thread-subscription#turning-the-feature-off).

```swift lines
import UIKit
import CometChatUIKitSwift
Expand All @@ -579,10 +581,9 @@

let messageListView = CometChatMessageList()

// Off by default — opt in. Adds a "Subscribe to thread" /
// "Unsubscribe from thread" option to the message action sheet,
// on parent messages only.
messageListView.enableThreadSubscription = true
// The "Subscribe to thread" / "Unsubscribe from thread" option is
// added to the message action sheet on parent messages only. Hide it
// on one screen with hideThreadSubscriptionOption.
}

}
Expand All @@ -595,9 +596,6 @@
}
```

**Component Used:**
- [MessageList](/ui-kit/ios/message-list) - Hosts the subscribe/unsubscribe option

See the [Thread Subscription guide](/ui-kit/ios/guide-thread-subscription) for the full feature.

## Group Chat
Expand Down Expand Up @@ -712,72 +710,81 @@
}
```

## Pin Message
## Pin & Save Messages

*Available since v5.1.22*

Pin an important message so everyone in the conversation can find it. Pinning is restricted to group owners, admins and moderators; everyone else sees the pin indicator and the pinned list.
Keep important messages in reach. **Pinning** highlights a message for everyone in the conversation and is restricted to group owners, admins and moderatorseveryone else sees the pin indicator and the pinned list. **Saving** bookmarks a message privately for the acting user and spans every conversation, so saves are listed on a user-level screen rather than a per-conversation one.

```swift lines
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class PinMessageViewController: UIViewController {
class PinSaveMessagesViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

let messageListView = CometChatMessageList()

// Pin is off by default — opt in, and the feature must also be
// enabled for your app (CometChat.isPinMessageEnabled()).
// Both are off by default — opt in, and each feature must also be
// enabled for your app (CometChat.isPinMessageEnabled() and
// CometChat.isSaveMessageEnabled()).
messageListView.enablePinMessage = true
messageListView.enableSaveMessage = true

// Open the per-conversation pinned list
// Pinned messages are per-conversation.
let pinnedVC = CometChatPinnedMessages(group: group)
pinnedVC.set(onMessageClicked: { [weak self] message in
self?.navigationController?.popViewController(animated: true)
messageListView.goToMessage(withId: message.id)
})
navigationController?.pushViewController(pinnedVC, animated: true)

// Saved messages span every conversation, so open this from app chrome.
let savedVC = CometChatSavedMessages()
savedVC.hideNavigationBar = false
navigationController?.pushViewController(savedVC, animated: true)
}
}
```

See the [Pin & Save Messages guide](/ui-kit/ios/guide-pin-save-message) and [Pinned Messages](/ui-kit/ios/pinned-messages).
**Components Used:**
- [MessageList](/ui-kit/ios/message-list) - Adds Pin, Unpin, Save and Unsave to the message options, and shows the bubble indicators

Check warning on line 754 in ui-kit/ios/core-features.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/core-features.mdx#L754

Did you really mean 'Unsave'?
- [Pinned Messages](/ui-kit/ios/pinned-messages) - The messages pinned in one conversation
- [Saved Messages](/ui-kit/ios/saved-messages) - The current user's saved messages, across every conversation
- [Conversations](/ui-kit/ios/conversations) - Lets users pin a whole conversation to the top of their list

## Save Message
See the [Pin & Save Messages guide](/ui-kit/ios/guide-pin-save-message) for end-to-end wiring.

## Pin Conversations

*Available since v5.1.22*

Save a message privately for later. Saves are visible only to the user who made them and span every conversation, so they are listed on a user-level screen rather than a per-conversation one.
Keep the chats that matter at the top. Users pin a conversation from its swipe action; pinned conversations show an indicator and stay above the rest of the list. An admin can also pin a conversation for everyone — those rows are not the user's to unpin, so the affordance is not offered.

Check warning on line 765 in ui-kit/ios/core-features.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/core-features.mdx#L765

Did you really mean 'affordance'?

```swift lines
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class SaveMessageViewController: UIViewController {
class PinConversationsViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

let messageListView = CometChatMessageList()

// Save is off by default — opt in, and the feature must also be
// enabled for your app (CometChat.isSaveMessageEnabled()).
messageListView.enableSaveMessage = true
let conversationsView = CometChatConversations()

// Saved messages span every conversation, so open this from app chrome
let savedVC = CometChatSavedMessages()
savedVC.hideNavigationBar = false
navigationController?.pushViewController(savedVC, animated: true)
// Off by default — opt in, and the feature must also be enabled
// for your app.
conversationsView.enablePinConversation = true
}
}
```

See the [Pin & Save Messages guide](/ui-kit/ios/guide-pin-save-message) and [Saved Messages](/ui-kit/ios/saved-messages).
**Component Used:**
- [Conversations](/ui-kit/ios/conversations#pinning-conversations) - Provides the pin/unpin option, the row indicator, and pinned-first ordering

## Search

Expand Down Expand Up @@ -981,7 +988,7 @@
conversationsNav.tabBarItem = UITabBarItem(
title: "Chats",
image: UIImage(systemName: "message"),
selectedImage: UIImage(systemName: "message.fill")

Check warning on line 991 in ui-kit/ios/core-features.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/core-features.mdx#L991

Did you really mean 'selectedImage'?
)

// Users Tab
Expand Down
82 changes: 69 additions & 13 deletions ui-kit/ios/guide-thread-subscription.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,48 @@
- Threaded messages working in your app — see [Threaded Messages](/ui-kit/ios/guide-threaded-messages).
- CometChat UI Kit for iOS v5.1.22 or later, with Chat SDK v4.1.9 or later.

## Enable the Feature
## The Surfaces

Thread subscription is **off by default**. Opt in per [CometChatMessageList](/ui-kit/ios/message-list) instance. When the gate is off, the option never renders and no subscription request is ever made.
Thread subscription surfaces in two places: the message action sheet on [CometChatMessageList](/ui-kit/ios/message-list), and a bell in the thread screen's navigation bar, rendered by [CometChatMessageHeader](/ui-kit/ios/message-header). Each can be hidden per instance with `hideThreadSubscriptionOption` and `hideThreadSubscriptionButton` respectively.

```swift
let messageListView = CometChatMessageList()
messageListView.enableThreadSubscription = true // opt in — default is false
## Turning the Feature Off

Thread subscription is **on by default** — there is nothing to switch on. To remove it from your app entirely, close the gate:

```swift lines
import CometChatUIKitSwift

// On by default. Call this only to opt OUT.
CometChatThreadSubscriptionConfig.setEnabled(false)
```

Set it on **both** your main message list and the message list inside your thread screen, so the option is available in either place.
With the gate closed neither surface renders and no subscription request is ever made, whatever the per-instance `hideThreadSubscription*` flags say. The two are ANDed: the gate decides whether the feature exists in your app at all, and the per-instance flags remove a surface from one screen.

Check warning on line 37 in ui-kit/ios/guide-thread-subscription.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/guide-thread-subscription.mdx#L37

Did you really mean 'ANDed'?

`CometChatThreadSubscriptionConfig` is a plain process-wide switch, not an init-time setting — you can flip it at any point, before or after `CometChatUIKit.init`, and read it back with `isEnabled()`.

<Note>

This is the **only** control that will ever exist for the feature. Unlike pin and save, thread subscription has no dashboard flag and no app setting, so nothing on the server can switch it on or off. The other CometChat platforms work the same way: Android uses `CometChatThreadSubscriptionConfig.setEnabled(false)` and React Native `ThreadSubscriptionConfig.setEnabled(false)`.

</Note>

<Warning>

Closing the gate hides the controls but does **not** stop subscriptions. Users are still subscribed automatically by starting a thread, replying, or being @-mentioned, and still receive thread notifications — they simply have no way to change it in your app. Suppressing the notifications themselves is a notification-settings concern, not a UI Kit one.

</Warning>

## Surface 1: The Message Action Sheet Option

With the gate on, `CometChatMessageList` adds a **Subscribe to thread** / **Unsubscribe from thread** option to the long-press action sheet. The label and icon reflect the current state, read synchronously from the SDK when the sheet is built.
`CometChatMessageList` adds a **Subscribe to thread** / **Unsubscribe from thread** option to the long-press action sheet. The label and icon reflect the current state, read synchronously from the SDK when the sheet is built.

The option appears only on **parent messages** — never on a reply inside a thread:

```swift
// The kit's gate, for reference:
// enableThreadSubscription && parentMessageId == 0 && !hideThreadSubscriptionOption
// CometChatThreadSubscriptionConfig.isEnabled()
// && !hideThreadSubscriptionOption
// && parentMessageId == 0
```

<Note>
Expand All @@ -61,35 +83,69 @@

To replace the kit's behavior with your own, supply an `onItemClick` on a custom option with the id `MessageOptionConstants.threadSubscription` — the kit calls your handler instead of its own.

## Surface 2: The Bell in the Message Header
## Surface 2: The Bell in the Navigation Bar

[CometChatMessageHeader](/ui-kit/ios/message-header) renders a subscribe/unsubscribe bell in its trailing area. Set `parentMessage` to put the header in **thread mode** — the bell renders only then, so a conversation header is unaffected. As with the action-sheet option, it renders in one-on-one threads as well as groups.

[CometChatThreadedMessageHeader](/ui-kit/ios/threaded-messages-header) can render the same bell on its reply-count bar instead, for a screen with no header bar. Enable it on exactly one of the two — never both.
This is the bell to use. Every CometChat platform places the subscription bell in the thread screen's **top bar**, not in the reply-count row beneath it on iOS, putting `CometChatMessageHeader` in thread mode is how you get it there.

```swift
let messageHeaderView = CometChatMessageHeader()
messageHeaderView.set(parentMessage: parentMessage) // puts the header in thread mode
messageHeaderView.set(enableThreadSubscription: true) // off by default
```

Host it as the thread screen's navigation bar — pin it to the safe-area top and hide the system bar, exactly as a conversation screen does:

```swift lines
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(true, animated: animated)
}

func buildUI() {
view.addSubview(messageHeaderView)
view.addSubview(threadHeaderView) // reply-count bar, directly beneath
view.addSubview(messageListView)

NSLayoutConstraint.activate([
messageHeaderView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
messageHeaderView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
messageHeaderView.trailingAnchor.constraint(equalTo: view.trailingAnchor),

threadHeaderView.topAnchor.constraint(equalTo: messageHeaderView.bottomAnchor),
threadHeaderView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
threadHeaderView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
}
```

<Note>

[CometChatThreadedMessageHeader](/ui-kit/ios/threaded-messages-header) carries a **fallback** bell on its reply-count bar, so a thread screen with no top bar still has the control. A screen that renders both components should hide it, leaving the top-bar bell as the only one:

```swift
threadHeaderView.hideThreadSubscriptionButton = true
```

</Note>

The bell tracks state on its own: it reads the current subscription state from the SDK, flips optimistically on tap, reverts if the request fails, toasts in both directions, and emits `ccThreadSubscriptionChanged` on success. You do not wire any of that up.

If your screen already draws its own control and you would otherwise show two bells, suppress the kit's:
If your screen draws a subscription control of its own in the navigation bar, suppress the kit's:

```swift
messageHeaderView.set(hideThreadSubscriptionButton: true)
```

<Note>

The bell needs `parentMessage` and `enableThreadSubscription`, on a parent whose message has been sent. Setting the flag alone on a conversation header renders nothing — that is deliberate, so turning the feature on globally cannot put a thread control on a non-thread screen.
The bell needs `parentMessage`, on a parent whose message has been sent. Without it a conversation header renders nothing — that is deliberate, so a thread control can never appear on a non-thread screen.

</Note>

## Cross-Surface Sync

Both surfaces observe the UI Kit event bus, so toggling in one place updates the other without a refetch. After a successful toggle the kit emits:

Check warning on line 148 in ui-kit/ios/guide-thread-subscription.mdx

View check run for this annotation

Mintlify / Mintlify Validation (cometchat-22654f5b) - vale-spellcheck

ui-kit/ios/guide-thread-subscription.mdx#L148

Did you really mean 'refetch'?

```swift
CometChatThreadEvents.ccThreadSubscriptionChanged(parentMessageId: parentMessageId,
Expand Down
Loading