mirror of
https://github.com/WuKongIM/WuKongIMFlutterSDK
synced 2025-05-29 07:02:19 +00:00
Support message receipts
This commit is contained in:
parent
5f073e3b62
commit
a3343eb5e2
@ -12,3 +12,6 @@
|
||||
* Optimize processing of incorrect data
|
||||
### 1.0.6
|
||||
* Update sending messages without notification to refresh conversation messsage
|
||||
### 1.0.7
|
||||
* Support message receipts
|
||||
|
@ -9,7 +9,7 @@
|
||||
#### 安装
|
||||
```
|
||||
dependencies:
|
||||
wukongimfluttersdk: ^1.0.6
|
||||
wukongimfluttersdk: ^1.0.7
|
||||
```
|
||||
#### 引入
|
||||
```dart
|
||||
|
@ -1,11 +1,13 @@
|
||||
import 'package:example/const.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:wukongimfluttersdk/entity/channel.dart';
|
||||
import 'package:wukongimfluttersdk/entity/msg.dart';
|
||||
import 'package:wukongimfluttersdk/model/wk_card_content.dart';
|
||||
import 'package:wukongimfluttersdk/model/wk_image_content.dart';
|
||||
import 'package:wukongimfluttersdk/model/wk_text_content.dart';
|
||||
import 'package:wukongimfluttersdk/model/wk_video_content.dart';
|
||||
import 'package:wukongimfluttersdk/model/wk_voice_content.dart';
|
||||
import 'package:wukongimfluttersdk/proto/proto.dart';
|
||||
import 'package:wukongimfluttersdk/type/const.dart';
|
||||
import 'package:wukongimfluttersdk/wkim.dart';
|
||||
|
||||
@ -72,6 +74,10 @@ class ChatListDataState extends State<ChatList> {
|
||||
WKIM.shared.messageManager.addOnNewMsgListener('chat', (msgs) {
|
||||
setState(() {
|
||||
for (var i = 0; i < msgs.length; i++) {
|
||||
if (msgs[i].setting.receipt == 1) {
|
||||
// 消息需要回执
|
||||
testReceipt(msgs[i]);
|
||||
}
|
||||
msgList.add(UIMsg(msgs[i]));
|
||||
}
|
||||
});
|
||||
@ -85,6 +91,7 @@ class ChatListDataState extends State<ChatList> {
|
||||
msgList[i].wkMsg.messageID = wkMsg.messageID;
|
||||
msgList[i].wkMsg.messageSeq = wkMsg.messageSeq;
|
||||
msgList[i].wkMsg.status = wkMsg.status;
|
||||
msgList[i].wkMsg.wkMsgExtra = wkMsg.wkMsgExtra;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -92,6 +99,24 @@ class ChatListDataState extends State<ChatList> {
|
||||
});
|
||||
}
|
||||
|
||||
// 模拟同步消息扩展后保存到db
|
||||
testReceipt(WKMsg wkMsg) async {
|
||||
if (wkMsg.viewed == 0) {
|
||||
var maxVersion = await WKIM.shared.messageManager
|
||||
.getMaxExtraVersionWithChannel(channelID, channelType);
|
||||
var extra = WKMsgExtra();
|
||||
extra.messageID = wkMsg.messageID;
|
||||
extra.channelID = channelID;
|
||||
extra.channelType = channelType;
|
||||
extra.readed = 1;
|
||||
extra.readedCount = 1;
|
||||
extra.extraVersion = maxVersion + 1;
|
||||
List<WKMsgExtra> list = [];
|
||||
list.add(extra);
|
||||
WKIM.shared.messageManager.saveRemoteExtraMsg(list);
|
||||
}
|
||||
}
|
||||
|
||||
getMsgList() {
|
||||
WKIM.shared.messageManager.getOrSyncHistoryMessages(
|
||||
channelID, channelType, 0, true, 0, 100, 0, (list) {
|
||||
@ -274,10 +299,11 @@ class ChatListDataState extends State<ChatList> {
|
||||
onPressed: () {
|
||||
if (content != '') {
|
||||
_textEditingController.text = '';
|
||||
|
||||
Setting setting = Setting();
|
||||
setting.receipt = 1; //开启回执
|
||||
WKTextContent text = WKTextContent(content);
|
||||
WKIM.shared.messageManager
|
||||
.sendMessage(text, WKChannel(channelID, channelType));
|
||||
WKIM.shared.messageManager.sendMessageWithSetting(
|
||||
text, WKChannel(channelID, channelType), setting);
|
||||
// WKImageContent imageContent = WKImageContent(100, 200);
|
||||
// imageContent.localPath = 'addskds';
|
||||
// WKIM.shared.messageManager.sendMessage(
|
||||
|
@ -42,21 +42,21 @@ class IMUtils {
|
||||
WKImageContent imageContent = wkMsg.messageContent! as WKImageContent;
|
||||
imageContent.url = 'xxxxxx';
|
||||
wkMsg.messageContent = imageContent;
|
||||
back(wkMsg);
|
||||
back(true, wkMsg);
|
||||
}
|
||||
if (wkMsg.contentType == WkMessageContentType.voice) {
|
||||
// todo 上传语音
|
||||
WKVoiceContent voiceContent = wkMsg.messageContent! as WKVoiceContent;
|
||||
voiceContent.url = 'xxxxxx';
|
||||
wkMsg.messageContent = voiceContent;
|
||||
back(wkMsg);
|
||||
back(true, wkMsg);
|
||||
} else if (wkMsg.contentType == WkMessageContentType.video) {
|
||||
WKVideoContent videoContent = wkMsg.messageContent! as WKVideoContent;
|
||||
// todo 上传封面及视频
|
||||
videoContent.cover = 'xxxxxx';
|
||||
videoContent.url = 'ssssss';
|
||||
wkMsg.messageContent = videoContent;
|
||||
back(wkMsg);
|
||||
back(true, wkMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -11,7 +11,11 @@ class UIMsg {
|
||||
if (wkMsg.messageContent == null) {
|
||||
return '';
|
||||
}
|
||||
return wkMsg.messageContent!.displayText();
|
||||
var readCount = 0;
|
||||
if (wkMsg.wkMsgExtra != null) {
|
||||
readCount = wkMsg.wkMsgExtra!.readedCount;
|
||||
}
|
||||
return "${wkMsg.messageContent!.displayText()} [是否需要回执:${wkMsg.setting.receipt}],[已读数量:$readCount]";
|
||||
}
|
||||
|
||||
String getShowTime() {
|
||||
|
@ -499,7 +499,7 @@ packages:
|
||||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "1.0.6"
|
||||
version: "1.0.7"
|
||||
x25519:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -87,6 +87,30 @@ class MessaggeDB {
|
||||
return wkMsg;
|
||||
}
|
||||
|
||||
Future<List<WKMsg>> queryWithMessageIds(List<String> messageIds) async {
|
||||
StringBuffer sb = StringBuffer();
|
||||
for (int i = 0, size = messageIds.length; i < size; i++) {
|
||||
if (i != 0) {
|
||||
sb.write(",");
|
||||
}
|
||||
sb.write("'");
|
||||
sb.write(messageIds[i]);
|
||||
sb.write("'");
|
||||
}
|
||||
|
||||
String sql =
|
||||
"select $messageCols,$extraCols from ${WKDBConst.tableMessage} LEFT JOIN ${WKDBConst.tableMessageExtra} ON ${WKDBConst.tableMessage}.message_id=${WKDBConst.tableMessageExtra}.message_id WHERE ${WKDBConst.tableMessage}.message_id in (${sb.toString()})";
|
||||
List<WKMsg> list = [];
|
||||
List<Map<String, Object?>> results =
|
||||
await WKDBHelper.shared.getDB().rawQuery(sql);
|
||||
if (results.isNotEmpty) {
|
||||
for (Map<String, Object?> data in results) {
|
||||
list.add(WKDBConst.serializeWKMsg(data));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
Future<List<WKMsgReaction>> queryReactions(String messageID) async {
|
||||
String sql =
|
||||
"select * from ${WKDBConst.tableMessageReaction} where message_id='$messageID' and is_deleted=0 ORDER BY created_at desc";
|
||||
@ -536,7 +560,7 @@ class MessaggeDB {
|
||||
return msgs;
|
||||
}
|
||||
|
||||
insertOrUpdateMsgExtras(List<WKMsgExtra> list) async {
|
||||
Future<bool> insertOrUpdateMsgExtras(List<WKMsgExtra> list) async {
|
||||
List<String> msgIds = [];
|
||||
for (int i = 0, size = list.length; i < size; i++) {
|
||||
if (list[i].messageID != '') {
|
||||
@ -574,6 +598,21 @@ class MessaggeDB {
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<int> queryMaxExtraVersionWithChannel(
|
||||
String channelID, int channelType) async {
|
||||
int extraVersion = 0;
|
||||
String sql =
|
||||
"select max(extra_version) extra_version from ${WKDBConst.tableMessageExtra} where channel_id ='$channelID' and channel_type=$channelType";
|
||||
List<Map<String, Object?>> list =
|
||||
await WKDBHelper.shared.getDB().rawQuery(sql);
|
||||
if (list.isNotEmpty) {
|
||||
dynamic data = list[0];
|
||||
extraVersion = WKDBConst.readInt(data, 'extra_version');
|
||||
}
|
||||
return extraVersion;
|
||||
}
|
||||
|
||||
Future<List<WKMsgExtra>> queryMsgExtrasWithMsgIds(List<String> msgIds) async {
|
||||
@ -720,7 +759,6 @@ class MessaggeDB {
|
||||
map['is_mutual_deleted'] = extra.isMutualDeleted;
|
||||
map['content_edit'] = extra.contentEdit;
|
||||
map['edited_at'] = extra.editedAt;
|
||||
map['edited_at'] = extra.editedAt;
|
||||
map['need_upload'] = extra.needUpload;
|
||||
map['message_id'] = extra.messageID;
|
||||
return map;
|
||||
|
@ -343,10 +343,15 @@ class WKConnectionManager {
|
||||
|
||||
sendMessage(WKMsg wkMsg) {
|
||||
SendPacket packet = SendPacket();
|
||||
packet.setting = wkMsg.setting;
|
||||
packet.header.noPersist = wkMsg.header.noPersist;
|
||||
packet.header.showUnread = wkMsg.header.redDot;
|
||||
packet.header.syncOnce = wkMsg.header.syncOnce;
|
||||
packet.channelID = wkMsg.channelID;
|
||||
packet.channelType = wkMsg.channelType;
|
||||
packet.clientSeq = wkMsg.clientSeq;
|
||||
packet.clientMsgNO = wkMsg.clientMsgNO;
|
||||
packet.topic = wkMsg.topicID;
|
||||
packet.payload = wkMsg.content;
|
||||
_addSendingMsg(packet);
|
||||
_sendPacket(packet);
|
||||
@ -382,6 +387,7 @@ class WKConnectionManager {
|
||||
msg.header.redDot = recvMsg.header.showUnread;
|
||||
msg.header.noPersist = recvMsg.header.noPersist;
|
||||
msg.header.syncOnce = recvMsg.header.syncOnce;
|
||||
msg.setting = recvMsg.setting;
|
||||
msg.channelType = recvMsg.channelType;
|
||||
msg.channelID = recvMsg.channelID;
|
||||
msg.content = recvMsg.payload;
|
||||
@ -389,8 +395,6 @@ class WKConnectionManager {
|
||||
msg.messageSeq = recvMsg.messageSeq;
|
||||
msg.timestamp = recvMsg.messageTime;
|
||||
msg.fromUID = recvMsg.fromUID;
|
||||
msg.setting = recvMsg.setting;
|
||||
msg.clientMsgNO = recvMsg.clientMsgNO;
|
||||
msg.status = WKSendMsgResult.sendSuccess;
|
||||
msg.topicID = recvMsg.topic;
|
||||
msg.orderSeq = await WKIM.shared.messageManager
|
||||
|
@ -7,6 +7,7 @@ import 'package:wukongimfluttersdk/db/const.dart';
|
||||
import 'package:wukongimfluttersdk/db/message.dart';
|
||||
import 'package:wukongimfluttersdk/entity/msg.dart';
|
||||
import 'package:wukongimfluttersdk/model/wk_media_message_content.dart';
|
||||
import 'package:wukongimfluttersdk/proto/proto.dart';
|
||||
import 'package:wukongimfluttersdk/type/const.dart';
|
||||
|
||||
import '../entity/channel.dart';
|
||||
@ -23,7 +24,8 @@ class WKMessageManager {
|
||||
|
||||
final Map<int, WKMessageContent Function(dynamic data)> _msgContentList =
|
||||
HashMap<int, WKMessageContent Function(dynamic data)>();
|
||||
Function(WKMsg wkMsg, Function(WKMsg wkMsg))? _uploadAttachmentBack;
|
||||
Function(WKMsg wkMsg, Function(bool isSuccess, WKMsg wkMsg))?
|
||||
_uploadAttachmentBack;
|
||||
Function(WKMsg liMMsg)? _msgInsertedBack;
|
||||
HashMap<String, Function(List<WKMsg>)>? _newMsgBack;
|
||||
HashMap<String, Function(WKMsg)>? _refreshMsgBack;
|
||||
@ -105,6 +107,52 @@ class WKMessageManager {
|
||||
return messageSeq * wkOrderSeqFactor;
|
||||
}
|
||||
|
||||
Future<int> updateViewedAt(int viewedAt, String clientMsgNO) async {
|
||||
dynamic json = <String, Object>{};
|
||||
json['viewed'] = 1;
|
||||
json['viewed_at'] = viewedAt;
|
||||
return MessaggeDB.shared
|
||||
.updateMsgWithFieldAndClientMsgNo(json, clientMsgNO);
|
||||
}
|
||||
|
||||
Future<int> getMaxExtraVersionWithChannel(
|
||||
String channelID, int channelType) async {
|
||||
return MessaggeDB.shared
|
||||
.queryMaxExtraVersionWithChannel(channelID, channelType);
|
||||
}
|
||||
|
||||
saveRemoteExtraMsg(List<WKMsgExtra> list) async {
|
||||
MessaggeDB.shared.insertOrUpdateMsgExtras(list);
|
||||
List<String> msgIds = [];
|
||||
for (var extra in list) {
|
||||
msgIds.add(extra.messageID);
|
||||
}
|
||||
var msgList = await MessaggeDB.shared.queryWithMessageIds(msgIds);
|
||||
for (var msg in msgList) {
|
||||
for (var extra in list) {
|
||||
msg.wkMsgExtra ??= WKMsgExtra();
|
||||
if (msg.messageID == extra.messageID) {
|
||||
msg.wkMsgExtra!.readed = extra.readed;
|
||||
msg.wkMsgExtra!.readedCount = extra.readedCount;
|
||||
msg.wkMsgExtra!.unreadCount = extra.unreadCount;
|
||||
msg.wkMsgExtra!.revoke = extra.revoke;
|
||||
msg.wkMsgExtra!.revoker = extra.revoker;
|
||||
msg.wkMsgExtra!.isMutualDeleted = extra.isMutualDeleted;
|
||||
msg.wkMsgExtra!.editedAt = extra.editedAt;
|
||||
msg.wkMsgExtra!.contentEdit = extra.contentEdit;
|
||||
msg.wkMsgExtra!.extraVersion = extra.extraVersion;
|
||||
if (extra.contentEdit != '') {
|
||||
dynamic contentJson = jsonDecode(extra.contentEdit);
|
||||
msg.wkMsgExtra!.messageContent = WKIM.shared.messageManager
|
||||
.getMessageModel(WkMessageContentType.text, contentJson);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
setRefreshMsg(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void setSyncChannelMsgListener(
|
||||
String channelID,
|
||||
int channelType,
|
||||
@ -317,13 +365,30 @@ class WKMessageManager {
|
||||
_msgInsertedBack = insertListener;
|
||||
}
|
||||
|
||||
addOnUploadAttachmentListener(Function(WKMsg, Function(WKMsg)) back) {
|
||||
addOnUploadAttachmentListener(Function(WKMsg, Function(bool, WKMsg)) back) {
|
||||
_uploadAttachmentBack = back;
|
||||
}
|
||||
|
||||
sendMessage(WKMessageContent messageContent, WKChannel channel) async {
|
||||
var header = MessageHeader();
|
||||
header.redDot = true;
|
||||
sendMessageWithSettingAndHeader(messageContent, channel, Setting(), header);
|
||||
}
|
||||
|
||||
sendMessageWithSetting(
|
||||
WKMessageContent messageContent, WKChannel channel, Setting setting) {
|
||||
var header = MessageHeader();
|
||||
header.redDot = true;
|
||||
sendMessageWithSettingAndHeader(messageContent, channel, setting, header);
|
||||
}
|
||||
|
||||
sendMessageWithSettingAndHeader(WKMessageContent messageContent,
|
||||
WKChannel channel, Setting setting, MessageHeader header) async {
|
||||
WKMsg wkMsg = WKMsg();
|
||||
wkMsg.setting = setting;
|
||||
wkMsg.header = header;
|
||||
wkMsg.messageContent = messageContent;
|
||||
wkMsg.topicID = messageContent.topicId;
|
||||
wkMsg.channelID = channel.channelID;
|
||||
wkMsg.channelType = channel.channelType;
|
||||
wkMsg.fromUID = WKIM.shared.options.uid!;
|
||||
@ -347,7 +412,12 @@ class WKMessageManager {
|
||||
if (wkMsg.messageContent is WKMediaMessageContent) {
|
||||
// 附件消息
|
||||
if (_uploadAttachmentBack != null) {
|
||||
_uploadAttachmentBack!(wkMsg, (uploadedMsg) {
|
||||
_uploadAttachmentBack!(wkMsg, (isSuccess, uploadedMsg) {
|
||||
if (!isSuccess) {
|
||||
wkMsg.status = WKSendMsgResult.sendFail;
|
||||
updateMsgStatusFail(wkMsg.clientSeq);
|
||||
return;
|
||||
}
|
||||
// 重新编码消息正文
|
||||
Map<String, dynamic> json = uploadedMsg.messageContent!.encodeJson();
|
||||
json['type'] = uploadedMsg.contentType;
|
||||
|
@ -1,6 +1,7 @@
|
||||
class WKMessageContent {
|
||||
var contentType = 0;
|
||||
String content = "";
|
||||
String topicId = "";
|
||||
Map<String, dynamic> encodeJson() {
|
||||
return {};
|
||||
}
|
||||
|
@ -22,7 +22,8 @@ class WKVideoContent extends WKMediaMessageContent {
|
||||
'size': size,
|
||||
'width': width,
|
||||
'height': height,
|
||||
'second': second
|
||||
'second': second,
|
||||
'url': url
|
||||
};
|
||||
}
|
||||
|
||||
@ -35,6 +36,7 @@ class WKVideoContent extends WKMediaMessageContent {
|
||||
width = readInt(json, 'width');
|
||||
height = readInt(json, 'height');
|
||||
second = readInt(json, 'second');
|
||||
url = readString(json, 'url');
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ description: wukong IM flutter sdk
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 1.0.6
|
||||
version: 1.0.7
|
||||
homepage: https://github.com/WuKongIM/WuKongIMFlutterSDK
|
||||
|
||||
environment:
|
||||
|
Loading…
x
Reference in New Issue
Block a user