Conversations
A conversation is the message stream between two users (one-to-one) or within a group (group chat). This page shows how to use im.conversations to display the conversation list, unread counts and drafts; pin, mark as unread and delete conversations; and open a conversation or read its details. For the messages inside a conversation, see Messages; for mute settings, see Alerts, do not disturb and reports.
A typical flow: after sign-in, call im.conversations.list() and display it with LiveListBuilder. The list updates by itself on new messages, read changes and actions on the user's other devices. When the user taps a conversation, open its message list with its conversationKey.
The conversation list and unread counts are read from the local database first, so they show immediately on a cold start or while offline, and are then synced with the server.
| You want to | Use |
|---|---|
| Show a conversation list that updates itself | im.conversations.list() + LiveListBuilder; see Show the conversation list |
| Show unread counts and a bottom navigation badge | unreadCount, getUnreadTotal(); see Unread counts |
| Clear unread once the user has seen it | markRead(), markAllRead(); see Mark as read |
| Pin, mark as unread or delete a conversation | setPinned(), setMarkedUnread(), remove() |
| Keep unsent text from the input box | setDraft(); see Drafts |
| Show "typing…" | typing(), TypingChanged; see Typing indicator |
| Start a chat from contacts or a group | openSingle(), the group ID; see Open a conversation |
Show the conversation list
im.conversations.list() returns a live list (ConversationList, i.e. LiveList<ConversationView>). snapshot is the current snapshot; stream emits the current snapshot on subscribe and a new one on every change; call dispose() when you no longer show it. In Flutter UIs, rebuild from the snapshot with LiveListBuilder from deeprespond_im_flutter:
import 'package:deeprespond_im_flutter/render.dart';
import 'package:deeprespond_im_flutter/deeprespond_im_flutter.dart';
import 'package:flutter/material.dart';
class ConversationsPage extends StatefulWidget {
const ConversationsPage({super.key, required this.im});
final DRClient im;
@override
State<ConversationsPage> createState() => _ConversationsPageState();
}
class _ConversationsPageState extends State<ConversationsPage> {
late final ConversationList _list = widget.im.conversations.list();
@override
void dispose() {
_list.dispose(); // 页面销毁时释放
super.dispose();
}
String _preview(ConversationView c) {
final draft = c.draft;
if (draft != null) return '[草稿] ${draft.text}';
final last = c.lastMessage;
if (last == null) return '';
final me = widget.im.auth.currentUser?.username ?? '';
return summarize(last, nameOf: (u) => displayName(widget.im, u, groupId: c.groupId), self: me);
}
@override
Widget build(BuildContext context) => LiveListBuilder<ConversationView>(
list: _list,
builder: (context, snapshot) {
if (snapshot.items.isEmpty && snapshot.loading) return const Center(child: CircularProgressIndicator());
return ListView.builder(
itemCount: snapshot.items.length,
itemBuilder: (context, i) {
final c = snapshot.items[i];
final mentioned = c.state?.mentionSeq != null;
final dot = c.unreadCount == 0 && c.state?.markedUnread == true;
return ListTile(
key: ValueKey(c.conversationKey),
leading: c.state?.pinnedAt != null ? const Icon(Icons.push_pin) : null,
title: Text(conversationTitle(widget.im, c)),
subtitle: Text('${mentioned ? '[有人@我] ' : ''}${_preview(c)}', maxLines: 1, overflow: TextOverflow.ellipsis),
trailing: c.unreadCount > 0
? Badge(label: Text('${c.unreadCount}'), backgroundColor: c.muted != null ? Colors.grey : null)
: (dot ? const Badge() : null),
onTap: () {
// 用 c.conversationKey 打开消息列表,见“消息”一页
},
);
},
);
},
);
}- Snapshot.
itemsis a sorted list of ConversationView.hasMoremeans more conversations can be loaded,loadingmeans a load is in progress, anderrorisn'tnullif reading failed. - Stable objects. If nothing changed,
snapshotreturns the same object. When something changes you get a new snapshot in which unchanged conversations keep their old objects, so you can useidenticalto decide which rows to rebuild. Snapshots and their lists can't be modified. - Batched notifications. Several changes in the same event-loop turn produce one notification.
- Disposal. Whoever creates the list disposes it;
LiveListBuilderdoesn't do it for you. On sign-out or user switch, the SDK first replaces the snapshot with an empty list and notifies once, then disposes the list, so the UI never keeps showing the previous user's conversations. Calllist()again after signing in. Callinglist()while signed out throwsnot_signed_in. - Display names.
conversationTitle(),displayName()andsummarize()come frompackage:deeprespond_im_flutter/render.dart; see Messages. - Without
LiveListBuilder, you can subscribe tostreamwithStreamBuilder, or turn the list into aValueListenablewithtoValueListenable()forValueListenableBuilder; see Using it in Flutter UIs.
Sort order
- Pinned conversations come first, most recently pinned first.
- The rest are ordered by the time of the last message, newest first. Groups with no messages yet use the time you joined.
- One-to-one chats that don't have a server conversation yet (see Open a conversation) use the time of their newest queued message, or when the draft was first saved if they only have a draft.
- Typing a draft doesn't move an existing conversation.
- Deleted conversations (
state.hiddenistrue) are hidden and reappear when a new message arrives.
Load more
At first only the top conversations are loaded into memory (1000 by default; change it with the conversationWindow option when creating the client; see Initialization, sign-in and connection). When the user scrolls to the end and hasMore is true, call loadMore(). The SDK reads 100 more from local storage, and once that's exhausted fetches older conversations from the server.
final s = list.snapshot;
if (s.hasMore && !s.loading) await list.loadMore();On the first sign-in on a new device, local storage doesn't have every conversation yet. The SDK syncs recent conversations first and fetches older ones from the server on loadMore().
Unread counts
Each conversation's unreadCount is its number of unread messages. Group notices, call records, the user's own messages and messages sent with excludeFromUnread don't count.
- Marked as unread. When
unreadCountis 0 butstate.markedUnreadistrue, show an unread dot; see Mark as unread. - Mentions. When
state.mentionSeqisn'tnull, the conversation has an unread message that @-mentions the user or everyone, and you can show "[Mentioned]" before the preview. It goes back tonullonce the user reads that message. If that message is recalled, it falls back to the previous mention that's still valid. - Conversation being viewed. While the user is looking at a conversation (its message list is open, scrolled to the newest message, shown on screen, and the app is in the foreground; see Messages), new messages in it don't add to the local unread count. Mark them as read when the user sees them, or turn on
autoMarkReadwhen creating the client; otherwise the unread count comes back from the server on the next sync.
Unread total
im.conversations.getUnreadTotal() returns the unread total across all conversations synchronously, for a bottom navigation badge. ConversationsUnreadChanged is emitted when it changes:
void updateBadge() => setTabBadge(im.conversations.getUnreadTotal(excludeMuted: true));
final sub = im.on<ConversationsUnreadChanged>().listen((_) => updateBadge());
updateBadge();
// 页面销毁时
await sub.cancel();- The total covers every conversation, not just those loaded into memory. Deleted conversations don't count.
- A conversation that is only marked as unread, with no unread messages, counts as 1.
- With
excludeMuted: true, muted conversations don't count; see Alerts, do not disturb and reports. - On a new device whose local conversation list isn't complete yet, the SDK uses the server's unread total, and
excludeMutedhas no effect. The event'ssourceisserverin that case and becomeslocalonce the local list is complete. - App icon badge. When the app goes to the background, the SDK reports the unread total (excluding muted conversations) to the server, and pushes carry that badge count; the app doesn't need to set it. To use a different number, pass
badgeProviderwhen creating the client. When the app turns badges off (push_badge_enabledin the runtime configuration isfalse), nothing is reported. See Offline push.
Mark as read
When the user sees the latest messages in a conversation, call markRead() to move the read position to the newest message:
im.conversations.markRead(conversationId);
// 只标记到某一条(如用户只看到了第 120 条)
im.conversations.markRead(conversationId, seq: 120);markRead()doesn't wait or return anything. The SDK merges repeated calls for the same conversation and sends at most once per second. The local unread count updates before sending, and nothing is sent if the read position is already at the newest message.- Marking as read also clears "marked as unread" and mentions. In one-to-one chats with read receipts on, the other user sees "Read"; see Messages.
- Open message lists have their own
markRead()that does the same thing. Or setautoMarkRead: truewhen creating the client and let the SDK mark conversations the user is viewing.
To mark every conversation as read:
final (:count, :truncated) = await im.conversations.markAllRead();count is the number of conversations marked. The server only processes the groups the user is in plus the most recent 1000 one-to-one chats and left groups; truncated is true if older conversations still have unread messages. markAllRead() can be called at most twice per minute; beyond that it throws rate_limited (retryAfter is the wait in seconds).
Mark as unread
When the user wants to come back to a conversation later, they can mark it as unread:
await im.conversations.setMarkedUnread(conversationId, true);
// 取消
await im.conversations.setMarkedUnread(conversationId, false);Marking as unread doesn't change the read position, so the other user's "Read" status doesn't change either. It's cleared automatically when the conversation is marked as read, its history is cleared or it's deleted. The setting syncs across all of the user's devices.
Pin conversations
await im.conversations.setPinned(conversationId, true);
await im.conversations.setPinned(conversationId, false);Pinned conversations appear at the top of the list; state.pinnedAt is when it was pinned. Each user can pin up to 100 conversations; beyond that it throws limit_exceeded (reason is pinned_conversation_limit). Deleting a conversation unpins it.
Delete conversations and clear history
// 从会话列表中删除,消息仍然保留
await im.conversations.remove(conversationId);
// 删除并清空聊天记录
await im.conversations.remove(conversationId, clearMessages: true);
// 只清空聊天记录,会话仍在列表中
await im.conversations.clearMessages(conversationId);- Delete a conversation. It's removed from the user's list, its unread count is cleared, and it's unpinned and unmarked. It reappears when the other user or the group sends a new message, and earlier messages can still be scrolled back to.
- Clear history. The user can no longer see any earlier messages, and copies saved on this device are deleted too. The unread count is cleared. The other user and other group members aren't affected.
- Both affect only the user, and sync across all of their devices.
- Calling
remove()on a one-to-one chat without a server conversation yet (key starting withdraft:) only deletes its draft.
Drafts
When the user has typed text but not sent it, you can save it as the conversation's draft and restore it the next time the conversation opens:
// 离开会话时保存(正在引用第 42 条消息)
await im.conversations.setDraft(conversationKey, Draft(text: controller.text, replyToSeq: 42));
// 打开会话时恢复
final view = await im.conversations.get(conversationKey);
controller.text = view?.draft?.text ?? '';
final replyTo = view?.draft?.replyToSeq;
// 发出后清除
await im.conversations.setDraft(conversationKey, null);- Drafts are stored only on this device and don't sync to other devices.
- A draft can include
mentionUsernamesandmentionAll(people already @-mentioned in the input) andreplyToSeq(the message being quoted); they come back when you restore it. A draft with an emptytextand noreplyToSeqcounts as cleared. - The
draftfield in the conversation list updates too, so you can show "[Draft]" in the preview. Drafts don't change the order of existing conversations.
Showing muted conversations
When the user mutes a conversation, ConversationView.muted isn't null. muteMode is MuteMode.none (no alerts) or MuteMode.mentionOnly (alert only when the user is @-mentioned; groups only), and until is when it ends (null means indefinitely). In the list you can show a mute icon and a gray dot instead of the unread number.
Mute is set with im.push.mute(). When it expires the SDK restores it and updates the list automatically; see Alerts, do not disturb and reports.
Typing indicator
Call typing() while the user types, and the other user sees "typing…":
import 'dart:async';
import 'package:deeprespond_im_flutter/deeprespond_im_flutter.dart';
import 'package:flutter/material.dart';
class ChatTitle extends StatefulWidget {
const ChatTitle({super.key, required this.conversationKey, required this.title});
final String conversationKey;
final String title;
@override
State<ChatTitle> createState() => _ChatTitleState();
}
class _ChatTitleState extends State<ChatTitle> {
late List<String> _typing = im.conversations.getTyping(widget.conversationKey);
StreamSubscription<TypingChanged>? _sub;
@override
void initState() {
super.initState();
_sub = im.on<TypingChanged>().where((e) => e.conversationKey == widget.conversationKey).listen((e) => setState(() => _typing = e.usernames));
}
@override
void dispose() {
unawaited(_sub?.cancel());
super.dispose();
}
@override
Widget build(BuildContext context) => Text(_typing.isNotEmpty ? '对方正在输入…' : widget.title);
}
// 输入框:每次输入时报告
Widget input(String conversationKey) => TextField(onChanged: (_) => im.conversations.typing(conversationKey));- You can call
typing()on every keystroke; the SDK sends at most once every 3 seconds, and drops it when not connected. It works in one-to-one chats and groups of up to 100 members. - A received typing indicator disappears if nothing new arrives within 5 seconds.
im.conversations.getTyping(conversationKey)returns who is typing in a conversation synchronously; each item in the conversation list has the same value in itstypingfield.
Open a conversation
Every item in the conversation list has a conversationKey; use it to open the message list. When entering a chat from elsewhere (such as contacts or a group list):
One-to-one: use openSingle() to get the conversation by the other user's username:
final view = await im.conversations.openSingle('lisi');
final messages = im.messages.open(view.conversationKey);If the two users have chatted before, this returns the existing conversation. Otherwise it returns a local "draft conversation" whose conversationKey is draft:lisi and whose conversationId and state are null. When the first message is sent from it, the server creates the real conversation and the SDK swaps it in automatically:
- In the conversation list, the real conversation replaces the draft in the same position. The
ConversationsChangedevent includes both the removed draft key and the new conversation ID. - A message list opened with the draft key switches to the real conversation, and its
conversationKeybecomes the new conversation ID. - Methods called afterward with the old key, such as
typing(),setDraft(),getTyping()andim.messages.send(), are mapped to the new conversation ID automatically.
A draft conversation appears in the list only while it has a draft or queued messages; opening one without writing anything doesn't add it. If the other user messages first, or the user starts the chat on another device first, the draft conversation is merged into the real one in the same way.
Group: a group conversation's ID is the group ID, so open it with the group ID directly:
final messages = im.messages.open(groupId);Conversation details
im.conversations.get() reads one conversation from this device:
final view = await im.conversations.get(conversationId);
final state = view?.state;
if (view != null && state != null) {
if (view.conversationType == 'group' && state.membership != 'member') {
showToast('你已不在群中'); // left 已退出 / removed 已被移出 / dismissed 群已解散
}
if (view.conversationType == 'single' && view.peer == null) {
showToast('对方已注销');
}
print('对方已读到 ${state.peerReadSeq},可见范围 ${state.startSeq}~${state.maxSeq}');
}- Returns
nullif the conversation isn't stored on this device. The result is the same as the item in the conversation list. stateis the server's conversation state (ConversationState), such as the read position, the other user's read position and the user's membership in the group. Fields the server adds later can be read fromstate.raw.- Groups the user has left. After leaving, being removed, or the group being dissolved, the conversation stays in the list but
state.membershipis no longermember. The user can still scroll through earlier messages, mark as read, pin and delete the conversation, but can't send, recall, react or pin messages. - Deleted users. When the other user in a one-to-one chat is deleted,
peerisnull,conversationTitle()shows "Deleted user", and no more messages can be sent.
To fetch the latest state from the server right away (for example after a notification from your backend), call refresh():
final latest = await im.conversations.refresh(conversationId);You usually don't need it: the SDK updates conversation state in real time over the connection and syncs automatically after reconnecting or returning to the foreground.
Listen for conversation changes
The conversation list updates itself, so in most cases subscribing to the list is enough. To react to changes elsewhere (for example in another widget), listen for the event:
im.on<ConversationsChanged>().listen((e) {
// upserted:新增或有变化的会话键;removed:从本机移除的会话键(含并入正式会话的草稿键)
print('${e.upserted} ${e.removed}');
});The event fires after local data is updated and only says which conversations changed; read the latest content with get() or from a list snapshot. For all events, see Events and errors.
API reference
Methods of im.conversations. Apart from list(), markRead(), getUnreadTotal(), getTyping() and typing(), they all return a Future and throw DRException on failure: not_signed_in when signed out, and network_error or timeout for network errors. For error codes, see Events and errors and the server error codes.
In parameters, conversationId is the server's conversation ID. conversationKey is the key in the conversation list: the conversation ID for real conversations, or draft:{username} for a one-to-one chat with no server conversation yet.
im.conversations.list()
Gets the conversation list. Each call returns a new list object; call its dispose() when you're done with it.
Returns: ConversationList, i.e. LiveList<ConversationView>:
| Member | Description |
|---|---|
snapshot | The current snapshot LiveListSnapshot<ConversationView>: items, hasMore, loading, error |
stream | Stream<LiveListSnapshot<ConversationView>>: emits the current snapshot on subscribe and a new one on every change; closes when disposed |
loadMore() | Loads more conversations. Returns Future<void>; completes immediately when there are no more or a load is in progress |
dispose() | Disposes the list. Afterward loadMore() throws invalid_state (reason is disposed) |
Errors: throws not_signed_in synchronously when signed out.
im.conversations.get()
Reads one conversation from this device.
| Parameter | Type | Required | Description |
|---|---|---|---|
conversationId | String | Yes | Conversation ID. Can also be draft:{username} to get that draft conversation (null if it has no draft or queued messages) |
Returns: Future<ConversationView?>, null if not stored on this device.
Errors: not_signed_in, storage_error.
im.conversations.openSingle()
Gets the one-to-one conversation with a user. Returns it from this device if present; otherwise asks the server, and returns a draft conversation if the two users have no conversation yet.
| Parameter | Type | Required | Description |
|---|---|---|---|
username | String | Yes | The other user's username, case-insensitive |
Returns: Future<ConversationView>. A draft conversation has conversationKey draft:{username} (lowercase) and null conversationId and state. A draft conversation is also returned if the username doesn't exist, was deleted or is the user themself; sending will fail in that case.
Errors: local_validation (reason is required: empty username), network_error.
im.conversations.refresh()
Fetches the conversation state from the server again, merges it on this device and returns it.
| Parameter | Type | Required | Description |
|---|---|---|---|
conversationId | String | Yes | Conversation ID |
Returns: Future<ConversationView>.
Errors: not_found (the conversation doesn't exist or isn't visible to the user), local_validation (reason is not_found: the server returned the conversation but it wasn't saved on this device), network_error.
im.conversations.markRead()
Moves the read position to the newest message or a given one. Doesn't wait or return a result; the SDK batches requests and only logs failures.
| Parameter | Type | Required | Description |
|---|---|---|---|
conversationId | String | Yes | Conversation ID. Does nothing for draft conversations or when signed out |
seq | int? | No | Named. The sequence number read up to. Defaults to the newest message |
Returns: nothing (void).
im.conversations.markAllRead()
Marks every conversation as read. On success the SDK immediately syncs conversation state once.
Returns: Future<({int count, bool truncated})>. count is the number of conversations marked. When truncated is true, older conversations weren't processed, and unread counts on this device update after the next sync.
Errors: rate_limited (more than twice per minute; source is ErrorSource.local and retryAfter is the wait in seconds), network_error.
im.conversations.setMarkedUnread()
Marks a conversation as unread or clears the mark.
| Parameter | Type | Required | Description |
|---|---|---|---|
conversationId | String | Yes | Conversation ID |
marked | bool | Yes | true to mark as unread, false to clear |
Returns: Future<void>.
Errors: not_found, network_error.
im.conversations.setPinned()
Pins or unpins a conversation.
| Parameter | Type | Required | Description |
|---|---|---|---|
conversationId | String | Yes | Conversation ID |
pinned | bool | Yes | true to pin, false to unpin |
Returns: Future<void>.
Errors: limit_exceeded (reason is pinned_conversation_limit: 100 conversations already pinned), not_found, network_error.
im.conversations.remove()
Deletes a conversation, optionally clearing its history.
| Parameter | Type | Required | Description |
|---|---|---|---|
conversationId | String | Yes | Conversation ID. For draft:{username}, only the draft is deleted |
clearMessages | bool | No | Named. Also clear the history. Default false |
Returns: Future<void>.
Errors: not_found, network_error.
im.conversations.clearMessages()
Clears the user's history in a conversation. The conversation stays in the list.
| Parameter | Type | Required | Description |
|---|---|---|---|
conversationId | String | Yes | Conversation ID |
Returns: Future<void>.
Errors: not_found, network_error.
im.conversations.setDraft()
Saves or clears a conversation's draft (stored only on this device).
| Parameter | Type | Required | Description |
|---|---|---|---|
conversationKey | String | Yes | Conversation key; can be a draft conversation's draft:{username} |
draft | Draft? | Yes | The draft; see Draft. null clears it |
Returns: Future<void>.
Errors: not_signed_in, storage_error.
im.conversations.getUnreadTotal()
Returns the unread total synchronously. ConversationsUnreadChanged is emitted when it changes.
| Parameter | Type | Required | Description |
|---|---|---|---|
excludeMuted | bool | No | Named. Leave out muted conversations. Default false. Has no effect while the server's total is used |
Returns: int.
im.conversations.getTyping()
Returns who is typing in a conversation, synchronously. TypingChanged is emitted when it changes.
| Parameter | Type | Required | Description |
|---|---|---|---|
conversationKey | String | Yes | Conversation key |
Returns: List<String>, the usernames of people typing, or an empty list.
im.conversations.typing()
Tells the other side the user is typing. Sent at most once every 3 seconds, and dropped when not connected.
| Parameter | Type | Required | Description |
|---|---|---|---|
conversationKey | String | Yes | Conversation key; draft conversations work too |
Returns: nothing (void).
Events
| Event | Fields | Description |
|---|---|---|
ConversationsChanged | upserted, removed (List<String>) | Conversations in the list changed; keys are conversation IDs or draft:{username} |
ConversationsUnreadChanged | total (int), source (String) | The unread total changed; total follows getUnreadTotal()'s default rule (muted conversations included), and source is local or server |
TypingChanged | conversationKey (String), usernames (List<String>) | Who is typing changed |
Subscribe by type, such as im.on<ConversationsChanged>(), which returns a Stream; cancel the subscription when you no longer need it.
Types
Each type is a typed view of the server's JSON: common fields have camelCase getters, and the original JSON is in raw (read-only). Time fields are UTC DateTimes.
ConversationView
An item in the conversation list, combining the server's conversation state with data on this device.
| Field | Type | Description |
|---|---|---|
conversationKey | String | Conversation key: the conversation ID for real conversations, or draft:{username} for a one-to-one chat with no server conversation yet |
conversationId | String? | Conversation ID; null for draft conversations |
conversationType | String | single or group |
peer | String? | The other user's username in a one-to-one chat; null if that user was deleted, and for groups |
groupId | String? | The group ID for group chats; null for one-to-one |
state | ConversationState? | The server's conversation state; see ConversationState. null for draft conversations |
lastMessage | MessageView? | The last message, including ones still in the send queue; see Messages |
unreadCount | int | Unread messages (not counting "marked as unread") |
draft | Draft? | The draft on this device |
muted | MuteInfo? | Conversation mute; null if not set or expired. See MuteInfo |
typing | List<String> | People who are typing |
raw | Map<String, Object?> | Raw data |
ConversationState
The user's state in a conversation, the same as the server's user conversation object.
| Field | Type | Description |
|---|---|---|
conversationId | String | Conversation ID; for groups this is the group ID |
conversationType | String | single or group |
peer | String? | The other user's username in a one-to-one chat; null if that user was deleted |
groupId | String? | Group ID for group chats |
membership | String? | The user's membership in a group: member, left, removed, or dismissed (group dissolved). null for one-to-one |
startSeq | int | Sequence number of the first message the user can see (joining, clearing history and message expiry all raise it) |
maxSeq | int | Sequence number of the last message the user can see |
readSeq | int | The user's read position |
unreadCount | int | Unread count as computed by the server. In the UI use ConversationView.unreadCount, which includes messages just received on this device |
markedUnread | bool | Whether it's marked as unread |
peerReadSeq | int? | In one-to-one chats, the sequence number the other user has read up to; null if one-to-one read receipts are off. null for groups |
mentionSeq | int? | Sequence number of an unread message that @-mentions the user or everyone |
clearedSeq | int | Position where history was cleared; 0 if never cleared |
hiddenSeq | int | Position where the conversation was deleted; 0 if never deleted |
hidden | bool | Whether the conversation is currently deleted |
pinnedAt | DateTime? | When it was pinned |
joinedAt | DateTime? | For groups, when the user most recently joined |
leftAt | DateTime? | For groups, when the user left |
messageVersion | int | Version number for message changes in the conversation |
lastMessageAt | DateTime? | Time of the last message |
version | int | State version, used by the SDK for sync |
Draft
Create one with const Draft(text: '...').
| Field | Type | Description |
|---|---|---|
text | String | Required. Text in the input box |
mentionUsernames | List<String>? | People already @-mentioned |
mentionAll | bool | Whether everyone is already @-mentioned. Default false |
replyToSeq | int? | Sequence number of the message being quoted |
createdAt | DateTime? | When it was first saved. Set by the SDK; any value you pass is ignored |
updatedAt | DateTime? | When it was last saved. Set by the SDK |
MuteInfo
| Field | Type | Description |
|---|---|---|
mode | String | none: no alerts. mention_only: alert only when the user is @-mentioned (groups only) |
muteMode | MuteMode? | mode as an enum: MuteMode.none, MuteMode.mentionOnly; null for unknown values |
until | DateTime? | When it ends; null means indefinitely |
LiveListSnapshot
| Field | Type | Description |
|---|---|---|
items | List<T> | The items; can't be modified |
hasMore | bool | More can be loaded |
loading | bool | A load is in progress |
error | DRException? | The error from the most recent read |
