會話
會話是兩個使用者之間(單聊)或一個群中(群聊)的訊息流。本頁介紹用 im.conversations 顯示會話列表、未讀數和草稿,置頂、標記為未讀、刪除會話,以及開啟一個會話、檢視會話詳情。會話中的訊息見訊息,免打擾的設定見提醒、免打擾與舉報。
典型用法:登入後呼叫 im.conversations.list() 取得會話列表,用 LiveListBuilder 顯示,列表隨新訊息、已讀、其他裝置上的操作自動更新;使用者點選一個會話時,用它的 conversationKey 開啟訊息列表。
會話列表和未讀數都先從本機的資料庫讀取,App 冷啟動、離線時也能立即顯示,隨後與服務端同步。
| 要做什麼 | 用什麼 |
|---|---|
| 顯示會話列表並自動更新 | im.conversations.list() + LiveListBuilder,見顯示會話列表 |
| 顯示未讀數、底部導航欄角標 | unreadCount、getUnreadTotal(),見未讀數 |
| 使用者看過後清除未讀 | markRead()、markAllRead(),見標記已讀 |
| 置頂、標記為未讀、刪除會話 | setPinned()、setMarkedUnread()、remove() |
| 儲存輸入框中沒發出的文字 | setDraft(),見草稿 |
| 顯示“對方正在輸入…” | typing()、TypingChanged,見正在輸入 |
| 從聯絡人或群進入聊天 | openSingle()、群 ID,見開啟會話 |
顯示會話列表
im.conversations.list() 返回一個會持續更新的列表(ConversationList,即 LiveList<ConversationView>)。snapshot 是當前的快照,stream 在訂閱時先發出當前快照、之後每次變化發出新快照,不再顯示時呼叫 dispose() 釋放。在 Flutter 介面中用 deeprespond_im_flutter 的 LiveListBuilder 按快照重建:
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 打开消息列表,见“消息”一页
},
);
},
);
},
);
}- 快照:
items是排好序的 ConversationView 列表;hasMore表示還有更多會話可以載入;loading表示正在載入;讀取出錯時error不為null。 - 物件不變:沒有變化時
snapshot返回同一個物件;有變化時換成新的快照,其中沒有變化的會話沿用原來的物件,可以用identical判斷哪些行需要重建。快照和其中的列表都不能修改。 - 合併通知:同一輪事件迴圈中的多次變化合併為一次通知。
- 釋放:列表由建立它的一方釋放,
LiveListBuilder不會替你釋放。退出登入、切換使用者時 SDK 先把快照換成空列表並通知一次,然後釋放列表,介面不會繼續顯示上一個使用者的會話;重新登入後要再呼叫list()。未登入時呼叫list()丟擲not_signed_in。 - 顯示名稱:
conversationTitle()、displayName()、summarize()來自package:deeprespond_im_flutter/render.dart,見訊息。 - 不用
LiveListBuilder時,可以直接用StreamBuilder訂閱stream,或者用toValueListenable()轉為ValueListenable交給ValueListenableBuilder,見在 Flutter 介面中使用。
排序
- 置頂的會話在前,按置頂時間倒序;
- 其餘的按最後一條訊息的時間倒序,還沒有訊息的群按入群時間;
- 還沒有服務端會話的單聊(見開啟會話)按其中最新一條待發訊息的時間,只有草稿的按草稿第一次儲存的時間;
- 輸入框中的草稿不改變已有會話的位置;
- 刪除了的會話(
state.hidden為true)不顯示,收到新訊息時重新出現。
載入更多
第一次只把排在前面的會話讀入記憶體(預設 1000 個,可以用建立客戶端時的 conversationWindow 選項調整,見初始化、登入與連線)。使用者翻到末尾時,如果 hasMore 為 true,呼叫 loadMore():SDK 先從本地再讀 100 個,本地讀完後再向服務端取更早的會話。
final s = list.snapshot;
if (s.hasMore && !s.loading) await list.loadMore();在新裝置上第一次登入時,本地還沒有全部會話,SDK 先同步最近的會話,更早的在 loadMore() 時從服務端獲取。
未讀數
每個會話的 unreadCount 是這個會話的未讀訊息數。群提示、通話記錄、本人發的訊息和傳送時設定了 excludeFromUnread 的訊息不計入。
- 標記為未讀:
unreadCount為 0 而state.markedUnread為true時,顯示一個未讀圓點,見標記為未讀。 - 有人 @ 我:
state.mentionSeq不為null時,會話中有 @ 本人或 @ 全體成員、本人還沒有讀到的訊息,可以在摘要前顯示“[有人@我]”。讀到這條訊息後它變回null;這條訊息被撤回時,提醒退回到之前一條仍然有效的 @。 - 正在看的會話:使用者正在看某個會話時(訊息列表開啟、停在最新處、在介面上顯示,並且 App 在前臺,見訊息),這個會話的新訊息不計入本地的未讀數。請在使用者看到新訊息時標記已讀,或者在建立客戶端時開啟
autoMarkRead,否則下一次同步後未讀數會以服務端為準重新出現。
未讀總數
im.conversations.getUnreadTotal() 同步返回全部會話的未讀總數,用於底部導航欄的角標。總數變化時發出 ConversationsUnreadChanged 事件:
void updateBadge() => setTabBadge(im.conversations.getUnreadTotal(excludeMuted: true));
final sub = im.on<ConversationsUnreadChanged>().listen((_) => updateBadge());
updateBadge();
// 页面销毁时
await sub.cancel();- 總數覆蓋全部會話,不只是已讀入記憶體的那些;刪除了的會話不計入。
- 只是標記為未讀、沒有未讀訊息的會話算 1。
excludeMuted: true時不計入設定了免打擾的會話,見提醒、免打擾與舉報。- 在新裝置上本地的會話列表還不完整時,SDK 用服務端統計的未讀總數,這時
excludeMuted不起作用。事件的source為server時就是這種情況,本地的會話列表完整之後變為local。 - App 圖示的角標:App 切到後臺時,SDK 自動把未讀總數(不計免打擾的會話)上報給服務端,推送帶上這個角標數,App 不需要自己設定。要用別的數字時,在建立客戶端時提供
badgeProvider;應用關閉了角標(執行配置的push_badge_enabled為false)時不上報。見離線推送。
標記已讀
使用者看到一個會話的最新訊息時,呼叫 markRead() 把已讀位置推進到最新一條:
im.conversations.markRead(conversationId);
// 只标记到某一条(如用户只看到了第 120 条)
im.conversations.markRead(conversationId, seq: 120);markRead()不等待、不返回結果。SDK 把同一會話的多次呼叫合併,至少間隔 1 秒傳送一次;傳送前先更新本地的未讀數,已讀位置已經是最新的不再傳送。- 標記已讀同時取消“標記為未讀”和“有人 @ 我”。單聊開啟了已讀回執時,對方隨之看到“已讀”,見訊息。
- 已開啟的訊息列表也有
markRead(),作用相同。也可以在建立客戶端時設定autoMarkRead: true,由 SDK 在會話正在被看時自動標記。
把全部會話標記為已讀:
final (:count, :truncated) = await im.conversations.markAllRead();count 為標記的會話數。服務端只處理當前所在的群和最近的 1000 個單聊和已離開的群,更早的會話還有未讀時 truncated 為 true。markAllRead() 每分鐘最多呼叫 2 次,超出時丟擲 rate_limited(retryAfter 為需要等待的秒數)。
標記為未讀
使用者想稍後再處理一個會話時,可以把它標記為未讀:
await im.conversations.setMarkedUnread(conversationId, true);
// 取消
await im.conversations.setMarkedUnread(conversationId, false);標記為未讀不改變已讀位置,對方看到的“已讀”也不變。標記已讀、清空聊天記錄、刪除會話時自動取消。設定在本人的全部裝置間同步。
置頂會話
await im.conversations.setPinned(conversationId, true);
await im.conversations.setPinned(conversationId, false);置頂的會話排在列表最前面,state.pinnedAt 為置頂的時間。每個使用者最多置頂 100 個會話,超出時丟擲 limit_exceeded(reason 為 pinned_conversation_limit)。刪除會話時自動取消置頂。
刪除會話與清空聊天記錄
// 从会话列表中删除,消息仍然保留
await im.conversations.remove(conversationId);
// 删除并清空聊天记录
await im.conversations.remove(conversationId, clearMessages: true);
// 只清空聊天记录,会话仍在列表中
await im.conversations.clearMessages(conversationId);- 刪除會話:會話從本人的會話列表中移除,未讀數清零,同時取消置頂和標記為未讀。對方或群裡有新訊息時會話重新出現,刪除前的訊息仍可以翻看。
- 清空聊天記錄:本人看不到此前的全部訊息,本機儲存的也一併刪除;未讀數清零。對方和其他群成員不受影響。
- 都隻影響本人,在本人的全部裝置間同步。
- 對還沒有服務端會話的單聊(鍵以
draft:開頭)呼叫remove(),只刪除它的草稿。
草稿
使用者在輸入框中輸入了文字但沒有發出時,可以儲存為這個會話的草稿,下次開啟會話時恢復:
// 离开会话时保存(正在引用第 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);- 草稿只儲存在本機,不同步到其他裝置。
- 草稿可以帶
mentionUsernames、mentionAll(輸入框中已 @ 的人)和replyToSeq(正在引用的訊息),恢復時一起取回。text為空字串且沒有replyToSeq的視為清除。 - 會話列表中的
draft欄位隨之更新,可以在摘要處顯示“[草稿]”。草稿不改變已有會話的排序。
免打擾的顯示
使用者對一個會話設定了免打擾後,ConversationView.muted 不為 null:muteMode 為 MuteMode.none 表示不提醒,MuteMode.mentionOnly 表示只在有人 @ 本人時提醒(只用於群),until 為到期時間(null 表示一直有效)。會話列表中可以顯示一個免打擾圖示,未讀數顯示為灰色圓點而不是數字。
免打擾由 im.push.mute() 設定,到期後 SDK 自動恢復並更新會話列表,見提醒、免打擾與舉報。
正在輸入
使用者在輸入框中輸入時呼叫 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));typing()可以在每次輸入時呼叫,SDK 每 3 秒最多傳送一次;長連線沒有連上時直接丟棄。單聊和 100 人以內的群可用。- 收到的“正在輸入”5 秒內沒有再收到就自動消失。
im.conversations.getTyping(conversationKey)同步返回這個會話中正在輸入的人,會話列表中每一項的typing欄位相同。
開啟會話
會話列表中的每一項都有 conversationKey,用它開啟訊息列表。從其他地方(如聯絡人、群列表)進入聊天時:
單聊:用 openSingle() 按對方的使用者名稱取得會話:
final view = await im.conversations.openSingle('lisi');
final messages = im.messages.open(view.conversationKey);兩人之間已經聊過時返回已有的會話;還沒有會話時返回一個本地的“草稿會話”,conversationKey 為 draft:lisi,conversationId 和 state 為 null。在草稿會話中發出第一條訊息後,服務端建立正式的會話,SDK 自動把草稿會話換成正式會話:
- 會話列表中草稿會話被正式會話替換,位置不變,
ConversationsChanged事件同時帶上被移除的草稿鍵和新的會話 ID; - 用草稿鍵開啟的訊息列表自動切換到正式會話,它的
conversationKey變為新的會話 ID; - 之後用舊鍵呼叫
typing()、setDraft()、getTyping()、im.messages.send()等方法時,SDK 自動換成新的會話 ID。
草稿會話只在有草稿或待發訊息時出現在會話列表中;只是開啟、什麼也沒寫的不出現。對方先發來訊息,或本人在其他裝置上先和他聊了的,草稿會話同樣併入正式會話。
群聊:群會話的 ID 就是群 ID,直接用群 ID 開啟:
final messages = im.messages.open(groupId);會話詳情
im.conversations.get() 從本機讀取一個會話:
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}');
}- 本機沒有這個會話時返回
null。會話列表中的每一項與它相同。 state是服務端的會話狀態(ConversationState),如已讀位置、對方已讀到的位置、在群裡的身份。服務端新增的欄位可以從state.raw讀取。- 已離開的群:退出、被移出或群解散後,會話仍在列表中,
state.membership不再是member。可以翻看離開前的訊息、標記已讀、置頂和刪除會話,但不能再傳送訊息、撤回、表情回應和置頂訊息。 - 對方已刪除:單聊的對方被刪除後
peer為null,用conversationTitle()顯示為“已刪除的使用者”,不能再傳送。
需要立即從服務端取最新狀態時(如收到你的業務服務端的通知),呼叫 refresh():
final latest = await im.conversations.refresh(conversationId);通常不需要呼叫:SDK 透過長連線實時更新會話狀態,斷線重連、回到前臺後自動同步。
監聽會話的變化
會話列表會自動更新,大多數情況下只需訂閱列表。要在其他地方響應會話的變化(如更新另一個元件),可以監聽事件:
im.on<ConversationsChanged>().listen((e) {
// upserted:新增或有变化的会话键;removed:从本机移除的会话键(含并入正式会话的草稿键)
print('${e.upserted} ${e.removed}');
});事件在本地資料更新之後發出,只說明哪些會話變了,最新的內容用 get() 或列表的快照讀取。全部事件見事件與錯誤處理。
介面參考
im.conversations 的方法。除 list()、markRead()、getUnreadTotal()、getTyping()、typing() 之外都返回 Future,失敗時丟擲 DRException;沒有登入時為 not_signed_in,網路錯誤為 network_error、timeout。錯誤碼見事件與錯誤處理和服務端的錯誤碼。
引數中的 conversationId 是服務端的會話 ID;conversationKey 是會話列表中的鍵,正式會話就是會話 ID,還沒有服務端會話的單聊為 draft:{username}。
im.conversations.list()
取得會話列表。每次呼叫返回一個新的列表物件,不再使用時呼叫它的 dispose()。
返回值:ConversationList,即 LiveList<ConversationView>:
| 成員 | 說明 |
|---|---|
snapshot | 當前的快照 LiveListSnapshot<ConversationView>:items、hasMore、loading、error |
stream | Stream<LiveListSnapshot<ConversationView>>:訂閱時先發出當前快照,之後每次變化發出新快照;釋放後結束 |
loadMore() | 載入更多會話,返回 Future<void>;沒有更多或正在載入時立即返回 |
dispose() | 釋放列表。釋放後 loadMore() 丟擲 invalid_state(reason 為 disposed) |
可能的錯誤:未登入時同步丟擲 not_signed_in。
im.conversations.get()
從本機讀取一個會話。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
conversationId | String | 是 | 會話 ID;也可以是 draft:{username},返回這個草稿會話(沒有草稿和待發訊息時為 null) |
返回值:Future<ConversationView?>,本機沒有時為 null。
可能的錯誤:not_signed_in、storage_error。
im.conversations.openSingle()
按對方的使用者名稱取得單聊會話:本機有的直接返回;沒有的向服務端查詢,兩人之間還沒有會話時返回草稿會話。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
username | String | 是 | 對方的使用者名稱,不區分大小寫 |
返回值:Future<ConversationView>。草稿會話的 conversationKey 為 draft:{username}(小寫),conversationId、state 為 null。使用者名稱不存在、已刪除或就是本人時同樣返回草稿會話,傳送時才會失敗。
可能的錯誤:local_validation(reason 為 required,使用者名稱為空)、network_error。
im.conversations.refresh()
從服務端重新獲取會話狀態,合併到本機後返回。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
conversationId | String | 是 | 會話 ID |
返回值:Future<ConversationView>。
可能的錯誤:not_found(會話不存在或本人不可見)、local_validation(reason 為 not_found,服務端返回了會話但本機沒有儲存)、network_error。
im.conversations.markRead()
把已讀位置推進到最新一條或指定的一條。不等待、不返回結果,SDK 合併傳送,失敗時只記日誌。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
conversationId | String | 是 | 會話 ID。草稿會話和未登入時什麼也不做 |
seq | int? | 否 | 命名引數,已讀到的序號,預設為最新一條 |
返回值:無(void)。
im.conversations.markAllRead()
把全部會話標記為已讀。成功後 SDK 立即同步一次會話狀態。
返回值:Future<({int count, bool truncated})>。count 為標記的會話數;truncated 為 true 時還有更早的會話沒有處理,本機的未讀數等同步後再更新。
可能的錯誤:rate_limited(每分鐘超過 2 次,source 為 ErrorSource.local,retryAfter 為需要等待的秒數)、network_error。
im.conversations.setMarkedUnread()
標記為未讀或取消標記。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
conversationId | String | 是 | 會話 ID |
marked | bool | 是 | true 標記為未讀,false 取消 |
返回值:Future<void>。
可能的錯誤:not_found、network_error。
im.conversations.setPinned()
置頂或取消置頂會話。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
conversationId | String | 是 | 會話 ID |
pinned | bool | 是 | true 置頂,false 取消 |
返回值:Future<void>。
可能的錯誤:limit_exceeded(reason 為 pinned_conversation_limit,已置頂 100 個)、not_found、network_error。
im.conversations.remove()
刪除會話,可以同時清空聊天記錄。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
conversationId | String | 是 | 會話 ID;為 draft:{username} 時只刪除草稿 |
clearMessages | bool | 否 | 命名引數,同時清空聊天記錄,預設 false |
返回值:Future<void>。
可能的錯誤:not_found、network_error。
im.conversations.clearMessages()
清空本人在這個會話中的聊天記錄,會話仍在列表中。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
conversationId | String | 是 | 會話 ID |
返回值:Future<void>。
可能的錯誤:not_found、network_error。
im.conversations.setDraft()
儲存或清除會話的草稿(只儲存在本機)。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
conversationKey | String | 是 | 會話鍵,可以是草稿會話的 draft:{username} |
draft | Draft? | 是 | 草稿,見 Draft;null 清除 |
返回值:Future<void>。
可能的錯誤:not_signed_in、storage_error。
im.conversations.getUnreadTotal()
同步返回未讀總數。變化時發出 ConversationsUnreadChanged。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
excludeMuted | bool | 否 | 命名引數,不計入免打擾的會話,預設 false。用服務端的總數時不起作用 |
返回值:int。
im.conversations.getTyping()
同步返回一個會話中正在輸入的人。變化時發出 TypingChanged。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
conversationKey | String | 是 | 會話鍵 |
返回值:List<String>,正在輸入的人的使用者名稱,沒有時為空列表。
im.conversations.typing()
告訴對方本人正在輸入。每 3 秒最多傳送一次,長連線沒有連上時直接丟棄。
| 引數 | 型別 | 必填 | 說明 |
|---|---|---|---|
conversationKey | String | 是 | 會話鍵;草稿會話同樣可用 |
返回值:無(void)。
事件
| 事件 | 欄位 | 說明 |
|---|---|---|
ConversationsChanged | upserted、removed(List<String>) | 會話列表中的會話變化,鍵為會話 ID 或 draft:{username} |
ConversationsUnreadChanged | total(int)、source(String) | 未讀總數變化;total 按 getUnreadTotal() 的預設規則(計入免打擾的會話),source 為 local 或 server |
TypingChanged | conversationKey(String)、usernames(List<String>) | 正在輸入的人變化 |
用 im.on<ConversationsChanged>() 這樣按型別訂閱,返回 Stream,不再需要時取消訂閱。
資料結構
各型別都是服務端 JSON 的型別化檢視:常用欄位有 camelCase 的 getter,原始的 JSON 在 raw 中(不可修改)。時間欄位為 UTC 的 DateTime。
ConversationView
會話列表中的一項,由服務端的會話狀態和本機的資料組合而成。
| 欄位 | 型別 | 說明 |
|---|---|---|
conversationKey | String | 會話鍵:正式會話為會話 ID;還沒有服務端會話的單聊為 draft:{username} |
conversationId | String? | 會話 ID,草稿會話為 null |
conversationType | String | single 或 group |
peer | String? | 單聊的對方使用者名稱,對方已刪除時為 null;群聊為 null |
groupId | String? | 群聊的群 ID;單聊為 null |
state | ConversationState? | 服務端的會話狀態,見 ConversationState;草稿會話為 null |
lastMessage | MessageView? | 最後一條訊息,包括髮送佇列中還沒發出的;見訊息 |
unreadCount | int | 未讀訊息數(不含“標記為未讀”) |
draft | Draft? | 本機的草稿 |
muted | MuteInfo? | 會話免打擾,沒有設定或已到期為 null,見 MuteInfo |
typing | List<String> | 正在輸入的人 |
raw | Map<String, Object?> | 原始資料 |
ConversationState
本人在一個會話中的狀態,與服務端的使用者會話物件相同。
| 欄位 | 型別 | 說明 |
|---|---|---|
conversationId | String | 會話 ID;群會話的 ID 就是群 ID |
conversationType | String | single 或 group |
peer | String? | 單聊的對方使用者名稱,對方已刪除時為 null |
groupId | String? | 群聊的群 ID |
membership | String? | 群聊中本人的身份:member(成員)、left(已退出)、removed(已被移出)、dismissed(群已解散)。單聊為 null |
startSeq | int | 本人能看到的第一條訊息的序號(入群、清空聊天記錄、訊息過期都會讓它變大) |
maxSeq | int | 本人能看到的最後一條訊息的序號 |
readSeq | int | 本人的已讀位置 |
unreadCount | int | 服務端統計的未讀數。介面請用 ConversationView.unreadCount,它包含了本機剛收到的訊息 |
markedUnread | bool | 是否標記為未讀 |
peerReadSeq | int? | 單聊中對方已讀到的序號;應用沒有開啟單聊已讀回執時為 null。群聊為 null |
mentionSeq | int? | 本人還沒讀到的、@ 了本人或全體成員的訊息的序號 |
clearedSeq | int | 清空聊天記錄的位置,0 表示沒有清空過 |
hiddenSeq | int | 刪除會話時的位置,0 表示沒有刪除過 |
hidden | bool | 會話是否處於刪除狀態 |
pinnedAt | DateTime? | 置頂的時間 |
joinedAt | DateTime? | 群聊中本次入群的時間 |
leftAt | DateTime? | 群聊中離開的時間 |
messageVersion | int | 會話中訊息的變更版本號 |
lastMessageAt | DateTime? | 最後一條訊息的時間 |
version | int | 狀態的版本號,SDK 同步用 |
Draft
用 const Draft(text: '...') 建立。
| 欄位 | 型別 | 說明 |
|---|---|---|
text | String | 必填,輸入框中的文字 |
mentionUsernames | List<String>? | 已 @ 的人 |
mentionAll | bool | 是否已 @ 全體成員,預設 false |
replyToSeq | int? | 正在引用的訊息的序號 |
createdAt | DateTime? | 第一次儲存的時刻,由 SDK 填寫,傳入的忽略 |
updatedAt | DateTime? | 最近一次儲存的時刻,由 SDK 填寫 |
MuteInfo
| 欄位 | 型別 | 說明 |
|---|---|---|
mode | String | none 不提醒;mention_only 只在 @ 本人時提醒(只用於群) |
muteMode | MuteMode? | mode 的列舉形式:MuteMode.none、MuteMode.mentionOnly;不認識的取值為 null |
until | DateTime? | 到期時間,null 表示一直有效 |
LiveListSnapshot
| 欄位 | 型別 | 說明 |
|---|---|---|
items | List<T> | 條目,不可修改 |
hasMore | bool | 還有更多可以載入 |
loading | bool | 正在載入 |
error | DRException? | 最近一次讀取的錯誤 |
