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
5 changes: 5 additions & 0 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -2263,6 +2263,8 @@
"ui-kit/flutter/message-list",
"ui-kit/flutter/message-composer",
"ui-kit/flutter/threaded-messages-header",
"ui-kit/flutter/pinned-messages",
"ui-kit/flutter/saved-messages",
"ui-kit/flutter/incoming-call",
"ui-kit/flutter/outgoing-call",
"ui-kit/flutter/call-buttons",
Expand Down Expand Up @@ -4589,7 +4591,10 @@
"sdk/flutter/edit-message",
"sdk/flutter/flag-message",
"sdk/flutter/delete-message",
"sdk/flutter/pin-messages",
"sdk/flutter/save-messages",
"sdk/flutter/delete-conversation",
"sdk/flutter/pin-conversations",
"sdk/flutter/typing-indicators",
"sdk/flutter/transient-messages",
"sdk/flutter/delivery-read-receipts",
Expand Down
8 changes: 4 additions & 4 deletions notifications/preferences.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ CometChatNotifications.fetchPreferences(

MessagesOptions? messagesPreference = groupPreferences?.messages;
RepliesOptions? repliesPreference = groupPreferences?.replies;
RepliesOptions? quotedRepliesPreference = groupPreferences?.quotedReplies;
QuotedRepliesOptions? quotedRepliesPreference = groupPreferences?.quotedReplies;
ReactionsOptions? reactionsPreference = groupPreferences?.reactions;
MemberActionsOptions? memberAddedPreference = groupPreferences?.memberAdded;
MemberActionsOptions? memberJoinedPreference = groupPreferences?.memberJoined;
Expand Down Expand Up @@ -323,7 +323,7 @@ NotificationPreferences updatedPreferences = NotificationPreferences();
GroupPreferences groupPreferences = GroupPreferences(
messages: MessagesOptions.SUBSCRIBE_TO_MENTIONS,
replies: RepliesOptions.SUBSCRIBE_TO_ALL,
quotedReplies: RepliesOptions.SUBSCRIBE_TO_ALL,
quotedReplies: QuotedRepliesOptions.SUBSCRIBE_TO_ALL,
reactions: ReactionsOptions.SUBSCRIBE_TO_REACTIONS_ON_ALL_MESSAGES,
memberAdded: MemberActionsOptions.SUBSCRIBE,
memberJoined: MemberActionsOptions.SUBSCRIBE,
Expand Down Expand Up @@ -444,7 +444,7 @@ CometChatNotifications.fetchPreferences(

MessagesOptions? oneOnOneMessagesPreference = oneOnOnePreferences?.messages;
RepliesOptions? oneOnOneRepliesPreference = oneOnOnePreferences?.replies;
RepliesOptions? oneOnOneQuotedRepliesPreference = oneOnOnePreferences?.quotedReplies;
QuotedRepliesOptions? oneOnOneQuotedRepliesPreference = oneOnOnePreferences?.quotedReplies;
ReactionsOptions? oneOnOneReactionsPreference = oneOnOnePreferences?.reactions;
},
onError: (e) {
Expand Down Expand Up @@ -567,7 +567,7 @@ NotificationPreferences updatedPreferences = NotificationPreferences();
OneOnOnePreferences oneOnOnePreferences = OneOnOnePreferences(
messages: MessagesOptions.SUBSCRIBE_TO_ALL,
replies: RepliesOptions.SUBSCRIBE_TO_MENTIONS,
quotedReplies: RepliesOptions.SUBSCRIBE_TO_MENTIONS,
quotedReplies: QuotedRepliesOptions.SUBSCRIBE_TO_MENTIONS,
reactions: ReactionsOptions.SUBSCRIBE_TO_REACTIONS_ON_ALL_MESSAGES);

// Load the updates in the NotificationPreferences instance.
Expand Down
6 changes: 6 additions & 0 deletions notifications/push-overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,9 @@ UI Kit implementation
</Card>

</CardGroup>

<Note>

There is no separate guide for Flutter web builds yet. A Flutter app running on the web registers its FCM token with `PushPlatforms.FCM_WEB` (wire value `fcm_web`) instead of `FCM_FLUTTER_ANDROID` or the APNs providers, passing the token as the `fcmToken` argument to `CometChatNotifications.registerPushToken()`. Everything else — enabling push and adding an FCM provider in the dashboard — matches the Flutter (Android) guide.

</Note>
106 changes: 106 additions & 0 deletions sdk/flutter/pin-conversations.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
title: "Pin Conversations"
description: "Pin CometChat conversations to the top of the list in Flutter apps and keep every device in sync through real-time pin events."
---



Pinning a conversation surfaces it at the top of the logged-in user's conversation list. Conversation pins are **per-user** — pinning a conversation does not affect how the other participants see their lists. A pinned conversation carries a `pinnedAt` timestamp and the `pinnedBy` uid.

A conversation can also be pinned for the user by an admin surface, in which case `pinnedBy` carries the `app_system` sentinel. System pins rank above the user's own pins and cannot be removed from the client.

## Pin a Conversation

In order to pin a conversation, you can use the `pinConversation()` method. This method takes the uid/guid of the conversation counterpart and the conversation type (`user`/`group`). On success it returns the full updated `Conversation` with `pinnedAt` and `pinnedBy` stamped.

<Tabs>
<Tab title="Dart">
```dart
String conversationWith = "cometchat-uid-1";
String conversationType = CometChatConversationType.user;

CometChat.pinConversation(conversationWith, conversationType,
onSuccess: (Conversation conversation) {
debugPrint("Conversation pinned at: ${conversation.pinnedAt}");
}, onError: (CometChatException e) {
debugPrint("Conversation pinning failed with exception: ${e.message}");
});
```

</Tab>
</Tabs>

The call is idempotent — pinning an already-pinned conversation succeeds and returns the current state.

## Unpin a Conversation

In order to unpin a conversation, you can use the `unpinConversation()` method. Only a pin placed by the logged-in user can be removed — an `app_system` pin is rejected server-side. The returned `Conversation` carries the pin fields cleared to `null`.

<Tabs>
<Tab title="Dart">
```dart
String conversationWith = "cometchat-uid-1";
String conversationType = CometChatConversationType.user;

CometChat.unpinConversation(conversationWith, conversationType,
onSuccess: (Conversation conversation) {
debugPrint("Conversation unpinned");
}, onError: (CometChatException e) {
debugPrint("Conversation unpinning failed with exception: ${e.message}");
});
```

</Tab>
</Tabs>

## Real-Time Pin Events

Pin and unpin events are delivered to the logged-in user's devices through the `ConversationListener` class — the acting device receives the callback on success, and the user's other devices receive it over the socket, so lists stay in sync everywhere. Admin (`app_system`) pins applied server-side arrive through the same callbacks.

To receive them, register a listener using the `addConversationListener()` method and override the `onConversationPinned()` and `onConversationUnpinned()` callbacks. Remove the listener with `removeConversationListener()` when it is no longer needed.

<Tabs>
<Tab title="Dart">
```dart
class Class_Name with ConversationListener {

//CometChat.addConversationListener("listenerId", this);

@override
void onConversationPinned(Conversation conversation) {
debugPrint("Conversation pinned: ${conversation.conversationId}");
}

@override
void onConversationUnpinned(Conversation conversation) {
debugPrint("Conversation unpinned: ${conversation.conversationId}");
}
}
```

</Tab>
</Tabs>

When applying these events to a conversation list, keep the ordering contract: system pins (`pinnedBy == "app_system"`) stay above user pins, and user pins stay above the activity-ordered rest of the list.

## Fetching and Ordering

Pinned conversations are returned by the regular `ConversationsRequest` described in [Retrieve Conversations](/sdk/flutter/retrieve-conversations), ordered pinned-first — system pins, then the user's pins, then the remaining conversations by latest activity. Inspect `conversation.pinnedAt` / `conversation.pinnedBy` on the fetched objects to render the pinned state.

## Feature Availability and Limits

Whether the Pin Conversation feature is enabled for the logged-in user is served on the user's login payload. You can check it at any time using the synchronous `isPinConversationEnabled()` method — it never throws, and returns `true` when the backend did not serve the flag.

The maximum number of conversations a user can pin is available through `getPinnedConversationsLimit()`, which returns `null` when the backend did not serve a limit. When a pin call exceeds the cap, it fails with a limit-exceeded error whose `errorParams` map carries the authoritative limit as `{"limit": n}`.

<Tabs>
<Tab title="Dart">
```dart
if (CometChat.isPinConversationEnabled()) {
int? limit = CometChat.getPinnedConversationsLimit();
debugPrint("Conversation pinning enabled, limit: ${limit ?? "server default"}");
}
```

</Tab>
</Tabs>
146 changes: 146 additions & 0 deletions sdk/flutter/pin-messages.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
---
title: "Pin Messages"
description: "Pin and unpin CometChat messages in Flutter apps, listen to pin events in real time, and fetch the pinned messages of a conversation."
---



Pinning highlights an important message for **everyone in the conversation**. A pinned message carries a `pinnedAt` timestamp and the `pinnedBy` uid of the member who pinned it, and every participant can fetch the conversation's pinned list.

Pinning is permissioned in groups — only participants with the admin, moderator or owner scope can pin or unpin. In one-to-one conversations both participants can.

## Pin a Message

*In other words, as a member of a conversation, how do I pin a message for everyone?*

In order to pin a message, you can use the `pinMessage()` method. This method takes the id of the message to be pinned. On success it returns the **full updated message** with `pinnedAt` and `pinnedBy` stamped.

<Tabs>
<Tab title="Dart">
```dart
int messageId = 103;

CometChat.pinMessage(messageId, onSuccess: (BaseMessage message) {
debugPrint("Message pinned successfully: ${message.pinnedAt}");
}, onError: (CometChatException e) {
debugPrint("Message pinning failed with exception: ${e.message}");
});
```

</Tab>
</Tabs>

The call is idempotent — pinning an already-pinned message succeeds and returns the current state.

## Unpin a Message

In order to unpin a message, you can use the `unpinMessage()` method. The returned message carries the pin fields cleared to `null`. The same permission model applies.

<Tabs>
<Tab title="Dart">
```dart
int messageId = 103;

CometChat.unpinMessage(messageId, onSuccess: (BaseMessage message) {
debugPrint("Message unpinned successfully");
}, onError: (CometChatException e) {
debugPrint("Message unpinning failed with exception: ${e.message}");
});
```

</Tab>
</Tabs>

## Real-Time Pin Events

Pin and unpin actions are delivered to all participants through the `MessageListener` class. To receive them, register a listener using the `addMessageListener()` method and override the `onMessagePinned()` and `onMessageUnpinned()` callbacks. Both receive the full updated message object.

<Tabs>
<Tab title="Dart">
```dart
class Class_Name with MessageListener {

//CometChat.addMessageListener("listenerId", this);

@override
void onMessagePinned(BaseMessage message) {
debugPrint("Message pinned: ${message.id} by ${message.pinnedBy}");
}

@override
void onMessageUnpinned(BaseMessage message) {
debugPrint("Message unpinned: ${message.id}");
}
}
```

</Tab>
</Tabs>

The device that performed the action also receives these callbacks on success, so a single code path can update your UI for your own pins and for pins made by other members or your other devices.

## Fetch Pinned Messages

You can fetch all the pinned messages of a conversation by using the `MessagesRequest` class with the `pinned` parameter of the `MessagesRequestBuilder` set to `true`. A pinned list belongs to one conversation, so pair it with the `uid` (for a user conversation) or `guid` (for a group).

<Tabs>
<Tab title="Dart">
```dart
String UID = "cometchat-uid-1";

MessagesRequest messageRequest = (MessagesRequestBuilder()
..uid = UID
..pinned = true
..limit = 50).build();

messageRequest.fetchPrevious(onSuccess: (List<BaseMessage> list) {
debugPrint("Pinned messages fetched: ${list.length}");
}, onError: (CometChatException e) {
debugPrint("Pinned message fetching failed with exception: ${e.message}");
});
```

</Tab>
</Tabs>

## Feature Availability and Limits

Whether the Pin Message feature is enabled for the logged-in user is served on the user's login payload. You can check it at any time using the synchronous `isPinMessageEnabled()` method — it never throws, and returns `true` when the backend did not serve the flag so the feature is not disabled on older backends.

The maximum number of messages that can be pinned per conversation is also served on the login payload and is available through `getPinnedMessagesLimit()`. It returns `null` when the backend did not serve a limit.

<Tabs>
<Tab title="Dart">
```dart
if (CometChat.isPinMessageEnabled()) {
int? limit = CometChat.getPinnedMessagesLimit();
debugPrint("Pinning enabled, limit: ${limit ?? "server default"}");
}
```

</Tab>
</Tabs>

When a pin call exceeds the cap, it fails with the `ERR_PINNED_MESSAGES_LIMIT_EXCEEDED` error code. The exception's `errorParams` map carries the authoritative limit as `{"limit": n}`, which you can interpolate into your error copy.

<Tabs>
<Tab title="Dart">
```dart
CometChat.pinMessage(messageId, onSuccess: (BaseMessage message) {
debugPrint("Message pinned");
}, onError: (CometChatException e) {
if (e.code == 'ERR_PINNED_MESSAGES_LIMIT_EXCEEDED') {
final limit = e.errorParams?['limit'];
debugPrint("You can only pin $limit messages. Unpin one to pin another.");
}
});
```

</Tab>
</Tabs>

<Note>

Pins placed from an admin surface carry the `app_system` sentinel in `pinnedBy`. Save is the private, per-user counterpart of pinning — see [Save Messages](/sdk/flutter/save-messages).

</Note>
Loading