fix:example Integrate business api

This commit is contained in:
SL 2024-11-11 19:28:44 +08:00
parent 96814381ec
commit e161253936
23 changed files with 1072 additions and 358 deletions

View File

@ -110,3 +110,7 @@
* fix: Update sync channel message
### 1.5.5
* fix: After successfully modifying the synchronization channel message, no problem was returned
### 1.5.6
* fix: Optimize reconnection and resend messages
### 1.5.7
* fix: Optimize channel fields in cmd messages

280
example/lib/chatview.dart Normal file
View File

@ -0,0 +1,280 @@
import 'package:example/const.dart';
import 'package:example/http.dart';
import 'package:example/msg.dart';
import 'package:example/order_message_content.dart';
import 'package:flutter/material.dart';
import 'package:wukongimfluttersdk/type/const.dart';
import 'package:wukongimfluttersdk/wkim.dart';
import 'popmenu_util.dart';
import 'popup_item.dart';
getChannelAvatarURL(UIMsg uiMsg) {
var fromChannel = uiMsg.wkMsg.getFrom();
if (fromChannel != null && fromChannel.avatar != '') {
return HttpUtils.getAvatarUrl(fromChannel.channelID);
}
WKIM.shared.channelManager
.fetchChannelInfo(uiMsg.wkMsg.fromUID, WKChannelType.personal);
return '';
}
Widget chatAvatar(UIMsg uiMsg) {
return Image.network(
getChannelAvatarURL(uiMsg),
height: 40,
width: 40,
fit: BoxFit.cover,
errorBuilder:
(BuildContext context, Object exception, StackTrace? stackTrace) {
return Image.asset(
'assets/ic_default_avatar.png',
width: 40,
height: 40,
);
},
);
}
longClick(
UIMsg uiMsg, BuildContext context, LongPressStartDetails details) async {
List<PopupItem> items = [];
items.add(PopupItem(
text: '删除',
onTap: () {
HttpUtils.deleteMsg(
uiMsg.wkMsg.clientMsgNO,
uiMsg.wkMsg.channelID,
uiMsg.wkMsg.channelType,
uiMsg.wkMsg.messageSeq,
uiMsg.wkMsg.messageID);
},
));
if (uiMsg.wkMsg.fromUID == UserInfo.uid &&
uiMsg.wkMsg.status == WKSendMsgResult.sendSuccess) {
items.add(PopupItem(
text: '撤回',
onTap: () {
HttpUtils.revokeMsg(
uiMsg.wkMsg.clientMsgNO,
uiMsg.wkMsg.channelID,
uiMsg.wkMsg.channelType,
uiMsg.wkMsg.messageSeq,
uiMsg.wkMsg.messageID);
},
));
}
await PopmenuUtil.showPopupMenu(context, details, items);
}
Widget orderView(UIMsg uiMsg, BuildContext context) {
var leftMargin = 60.0;
var rightMargin = 5.0;
if (uiMsg.wkMsg.fromUID != UserInfo.uid) {
leftMargin = 10.0;
rightMargin = 60.0;
}
var orderContent = uiMsg.wkMsg.messageContent as OrderMsg;
return Expanded(
child: GestureDetector(
onLongPressStart: (details) {
longClick(uiMsg, context, details);
},
child: Container(
padding: const EdgeInsets.only(left: 5, top: 5, right: 5, bottom: 5),
margin: EdgeInsets.only(
left: leftMargin, top: 0, right: rightMargin, bottom: 0),
decoration: const BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(Radius.circular(12)),
color: Color.fromARGB(255, 250, 250, 250)),
alignment: Alignment.centerLeft,
child: Column(
children: [
Container(
margin:
const EdgeInsets.only(left: 5, top: 5, right: 5, bottom: 5),
alignment: Alignment.centerLeft,
child: Text(
'订单号:${orderContent.orderNo}',
style: const TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold),
),
),
Container(
margin:
const EdgeInsets.only(left: 5, top: 5, right: 5, bottom: 5),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Image.network(
orderContent.imgUrl,
height: 80,
width: 80,
fit: BoxFit.contain,
errorBuilder: (BuildContext context, Object exception,
StackTrace? stackTrace) {
return Image.asset('assets/ic_default_avatar.png');
},
),
Expanded(
child: Container(
margin: const EdgeInsets.only(
left: 10, top: 5, right: 0, bottom: 5),
child: Column(
children: [
Text(
'商品名称:${orderContent.title}',
softWrap: true,
style: const TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.bold),
),
Row(
children: [
Text("\$${orderContent.price}",
style: const TextStyle(
color: Colors.red,
fontSize: 14,
fontWeight: FontWeight.bold)),
const SizedBox(width: 100.0),
Text('${orderContent.num}',
style: const TextStyle(
color: Colors.red,
fontSize: 14,
fontWeight: FontWeight.bold)),
],
)
],
),
))
],
),
),
],
),
),
),
);
}
Widget getRevokedView(UIMsg uiMsg, BuildContext context) {
return Container(
alignment: Alignment.center,
margin: const EdgeInsets.only(left: 60, top: 10, right: 60, bottom: 10),
child: const Text('消息被撤回',
style: TextStyle(
color: Colors.black, fontSize: 14, fontWeight: FontWeight.bold)),
);
}
Widget getSendView(UIMsg uiMsg, BuildContext context) {
if (uiMsg.wkMsg.contentType == 56) {
return orderView(uiMsg, context);
} else {
return sendTextView(uiMsg, context);
}
}
Widget getRecvView(UIMsg uiMsg, BuildContext context) {
if (uiMsg.wkMsg.contentType == 56) {
return orderView(uiMsg, context);
} else {
return recvTextView(uiMsg, context);
}
}
Widget recvTextView(UIMsg uiMsg, BuildContext context) {
return Expanded(
child: GestureDetector(
onLongPressStart: (details) {
longClick(uiMsg, context, details);
},
child: Container(
alignment: Alignment.centerLeft,
margin: const EdgeInsets.only(left: 10, top: 0, right: 60, bottom: 0),
child: Container(
padding:
const EdgeInsets.only(left: 10, top: 5, right: 10, bottom: 5),
decoration: const BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(Radius.circular(12)),
color: Color.fromARGB(255, 163, 33, 243)),
child: Column(
children: [
Container(
alignment: Alignment.topLeft,
child: Text(
uiMsg.getShowContent(),
style: const TextStyle(color: Colors.white, fontSize: 16),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
uiMsg.getShowTime(),
style: const TextStyle(
color: Color.fromARGB(255, 226, 215, 215),
fontSize: 12),
)
],
)
],
),
),
),
),
);
}
Widget sendTextView(UIMsg uiMsg, BuildContext context) {
var alignment = Alignment.bottomRight;
if (uiMsg.wkMsg.fromUID != UserInfo.uid) {
alignment = Alignment.centerLeft;
}
return Expanded(
child: GestureDetector(
onLongPressStart: (details) {
longClick(uiMsg, context, details);
},
child: Container(
padding: const EdgeInsets.only(left: 5, top: 3, right: 5, bottom: 3),
margin: const EdgeInsets.only(left: 60, top: 0, right: 5, bottom: 0),
decoration: const BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(Radius.circular(12)),
color: Color.fromARGB(255, 9, 75, 243)),
alignment: alignment,
child: Column(
children: [
Container(
alignment: Alignment.centerLeft,
child: Text(
uiMsg.getShowContent(),
style: const TextStyle(color: Colors.white, fontSize: 16),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
uiMsg.getShowTime(),
style: const TextStyle(
color: Color.fromARGB(255, 226, 215, 215), fontSize: 12),
),
Image(
image: AssetImage(uiMsg.getStatusIV()),
width: 30,
height: 30)
],
),
],
),
),
),
);
}

View File

@ -1,23 +0,0 @@
import 'package:wukongimfluttersdk/model/wk_message_content.dart';
class CustomMsg extends WKMessageContent {
var name = "";
CustomMsg(this.name) {
contentType = 12;
}
@override
Map<String, dynamic> encodeJson() {
return {"name": name};
}
@override
WKMessageContent decodeJson(Map<String, dynamic> json) {
name = json["name"];
return this;
}
@override
String displayText() {
return "我是自定义消息:$name";
}
}

View File

@ -1,15 +1,25 @@
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:example/const.dart';
import 'package:wukongimfluttersdk/entity/channel.dart';
import 'package:wukongimfluttersdk/entity/conversation.dart';
import 'package:wukongimfluttersdk/entity/msg.dart';
import 'package:wukongimfluttersdk/type/const.dart';
import 'package:wukongimfluttersdk/wkim.dart';
class HttpUtils {
// static String apiURL = "https://api.githubim.com";
static String apiURL = "http://175.27.245.108:15001";
static String apiURL = "http://62.234.8.38:7090/v1";
// static String apiURL = "http://175.27.245.108:15001";
static getAvatarUrl(String uid) {
return "$apiURL/users/$uid/avatar";
}
static getGroupAvatarUrl(String gid) {
return "$apiURL/groups/$gid/avatar";
}
static Future<int> login(String uid, String token) async {
final httpClient = HttpClient();
@ -23,7 +33,7 @@ class HttpUtils {
..onHttpClientCreate = (client) {
return httpClient;
};
final response = await dio.post("$apiURL/user/token", data: {
final response = await dio.post("$apiURL/user/login", data: {
'uid': uid,
'token': token,
'device_flag': 0,
@ -32,7 +42,7 @@ class HttpUtils {
return response.statusCode!;
}
static Future<String> getIP() async {
static Future<String> getIP(String uid) async {
final httpClient = HttpClient();
httpClient.badCertificateCallback =
(X509Certificate cert, String host, int port) {
@ -45,7 +55,7 @@ class HttpUtils {
return httpClient;
};
String ip = '';
final response = await dio.get('$apiURL/route');
final response = await dio.get('$apiURL/users/$uid/route');
if (response.statusCode == HttpStatus.ok) {
ip = response.data['tcp_addr'];
}
@ -65,26 +75,29 @@ class HttpUtils {
..onHttpClientCreate = (client) {
return httpClient;
};
final response = await dio.post('$apiURL/conversation/sync', data: {
"uid": UserInfo.uid, // uid
"login_uid": UserInfo.uid, // uid
"version": version, // (version0)
"last_msg_seqs":
lastSsgSeqs, // channelID:channelType:last_msg_seq|channelID:channelType:last_msg_seq
"msg_count": 10 // app点进去第一屏的数据
"msg_count": 10, // app点进去第一屏的数据
"device_uuid": UserInfo.uid,
});
// print(response.data);
WKSyncConversation conversation = WKSyncConversation();
conversation.conversations = [];
if (response.statusCode == HttpStatus.ok) {
try {
var list = response.data;
var list = response.data['conversations'];
// var list = jsonDecode(response.data);
for (int i = 0; i < list.length; i++) {
var json = list[i];
WKSyncConvMsg convMsg = WKSyncConvMsg();
convMsg.channelID = json['channel_id'];
convMsg.channelType = json['channel_type'];
convMsg.unread = json['unread'];
convMsg.unread = json['unread'] ?? 0;
convMsg.timestamp = json['timestamp'];
convMsg.lastMsgSeq = json['last_msg_seq'];
convMsg.lastClientMsgNO = json['last_client_msg_no'];
@ -127,7 +140,7 @@ class HttpUtils {
..onHttpClientCreate = (client) {
return httpClient;
};
final response = await dio.post('$apiURL/channel/messagesync', data: {
final response = await dio.post('$apiURL/message/channel/sync', data: {
"login_uid": UserInfo.uid, // uid
"channel_id": channelID, // ID
"channel_type": channelType, //
@ -163,14 +176,303 @@ class HttpUtils {
msg.clientMsgNO = json['client_msg_no'];
msg.messageSeq = json['message_seq'];
msg.fromUID = json['from_uid'];
msg.isDeleted = json['is_deleted'];
msg.timestamp = json['timestamp'];
// msg.payload = json['payload'];
String payload = json['payload'];
// String payload = json['payload'];
try {
msg.payload = jsonDecode(utf8.decode(base64Decode(payload)));
msg.payload = json['payload'];
// msg.payload = jsonDecode(utf8.decode(base64Decode(payload)));
} catch (e) {
// print('异常了');
}
//
var extraJson = json['message_extra'];
if (extraJson != null) {
var extra = getMsgExtra(extraJson);
msg.messageExtra = extra;
}
return msg;
}
static WKSyncExtraMsg getMsgExtra(dynamic extraJson) {
var extra = WKSyncExtraMsg();
extra.messageID = extraJson['message_id'];
extra.messageIdStr = extraJson['message_id_str'];
extra.revoke = extraJson['revoke'] ?? 0;
extra.revoker = extraJson['revoker'] ?? '';
extra.readed = extraJson['readed'] ?? 0;
extra.readedCount = extraJson['readed_count'] ?? 0;
extra.isMutualDeleted = extraJson['is_mutual_deleted'] ?? 0;
return extra;
}
static getGroupInfo(String groupId) async {
final httpClient = HttpClient();
httpClient.badCertificateCallback =
(X509Certificate cert, String host, int port) {
//
return true;
};
final dio = Dio();
dio.httpClientAdapter = DefaultHttpClientAdapter()
..onHttpClientCreate = (client) {
return httpClient;
};
final response = await dio.get('$apiURL/groups/$groupId');
if (response.statusCode == HttpStatus.ok) {
var json = response.data;
var channel = WKChannel(groupId, WKChannelType.group);
channel.channelName = json['name'];
channel.avatar = json['avatar'];
WKIM.shared.channelManager.addOrUpdateChannel(channel);
} else {
print('获取群信息失败');
}
}
static getUserInfo(String uid) async {
final httpClient = HttpClient();
httpClient.badCertificateCallback =
(X509Certificate cert, String host, int port) {
//
return true;
};
final dio = Dio();
dio.httpClientAdapter = DefaultHttpClientAdapter()
..onHttpClientCreate = (client) {
return httpClient;
};
try {
final response = await dio.get('$apiURL/users/$uid');
if (response.statusCode == HttpStatus.ok) {
var json = response.data;
var channel = WKChannel(uid, WKChannelType.personal);
channel.channelName = json['name'];
channel.avatar = json['avatar'];
WKIM.shared.channelManager.addOrUpdateChannel(channel);
}
} catch (e) {
print('获取用户信息失败$e');
}
}
static revokeMsg(String clientMsgNo, String channelId, int channelType,
int msgSeq, String msgId) async {
final httpClient = HttpClient();
httpClient.badCertificateCallback =
(X509Certificate cert, String host, int port) {
//
return true;
};
final dio = Dio();
dio.httpClientAdapter = DefaultHttpClientAdapter()
..onHttpClientCreate = (client) {
return httpClient;
};
try {
final response = await dio.post('$apiURL/message/revoke', data: {
'login_uid': UserInfo.uid,
'channel_id': channelId,
'channel_type': channelType,
'client_msg_no': clientMsgNo,
'message_id': msgId,
});
if (response.statusCode == HttpStatus.ok) {
print('撤回消息成功');
}
} catch (e) {
print('获取用户信息失败$e');
}
}
static deleteMsg(String clientMsgNo, String channelId, int channelType,
int msgSeq, String msgId) async {
final httpClient = HttpClient();
httpClient.badCertificateCallback =
(X509Certificate cert, String host, int port) {
//
return true;
};
final dio = Dio();
dio.httpClientAdapter = DefaultHttpClientAdapter()
..onHttpClientCreate = (client) {
return httpClient;
};
try {
final response = await dio.delete('$apiURL/message', data: {
'login_uid': UserInfo.uid,
'channel_id': channelId,
'channel_type': channelType,
'message_seq': msgSeq,
'message_id': msgId,
});
if (response.statusCode == HttpStatus.ok) {
WKIM.shared.messageManager.deleteWithClientMsgNo(clientMsgNo);
}
} catch (e) {
print('删除消息失败$e');
}
}
static syncMsgExtra(String channelId, int channelType, int version) async {
final httpClient = HttpClient();
httpClient.badCertificateCallback =
(X509Certificate cert, String host, int port) {
//
return true;
};
final dio = Dio();
dio.httpClientAdapter = DefaultHttpClientAdapter()
..onHttpClientCreate = (client) {
return httpClient;
};
try {
final response = await dio.post('$apiURL/message/extra/sync', data: {
'login_uid': UserInfo.uid,
'channel_id': channelId,
'channel_type': channelType,
'source': UserInfo.uid,
'limit': 100,
'extra_version': version,
});
if (response.statusCode == HttpStatus.ok) {
var arrJson = response.data;
if (arrJson != null && arrJson.length > 0) {
List<WKMsgExtra> list = [];
for (int i = 0; i < arrJson.length; i++) {
var extraJson = arrJson[i];
WKMsgExtra extra = WKMsgExtra();
extra.messageID = extraJson['message_id_str'];
extra.revoke = extraJson['revoke'] ?? 0;
extra.revoker = extraJson['revoker'] ?? '';
extra.readed = extraJson['readed'] ?? 0;
extra.readedCount = extraJson['readed_count'] ?? 0;
extra.isMutualDeleted = extraJson['is_mutual_deleted'] ?? 0;
list.add(extra);
}
WKIM.shared.messageManager.saveRemoteExtraMsg(list);
}
}
} catch (e) {
print('同步消息扩展失败$e');
}
}
//
static clearUnread(String channelId, int channelType) async {
final httpClient = HttpClient();
httpClient.badCertificateCallback =
(X509Certificate cert, String host, int port) {
//
return true;
};
final dio = Dio();
dio.httpClientAdapter = DefaultHttpClientAdapter()
..onHttpClientCreate = (client) {
return httpClient;
};
try {
final response = await dio.put('$apiURL/conversation/clearUnread', data: {
'login_uid': UserInfo.uid,
'channel_id': channelId,
'channel_type': channelType,
'unread': 0,
});
if (response.statusCode == HttpStatus.ok) {
print('清空红点成功');
}
} catch (e) {
print('清空红点失败$e');
}
}
//
static clearChannelMsg(String channelId, int channelType) async {
final httpClient = HttpClient();
httpClient.badCertificateCallback =
(X509Certificate cert, String host, int port) {
//
return true;
};
final dio = Dio();
dio.httpClientAdapter = DefaultHttpClientAdapter()
..onHttpClientCreate = (client) {
return httpClient;
};
try {
int maxSeq = await WKIM.shared.messageManager
.getMaxMessageSeq(channelId, channelType);
final response = await dio.post('$apiURL/message/offset', data: {
'login_uid': UserInfo.uid,
'channel_id': channelId,
'channel_type': channelType,
'message_seq': maxSeq
});
if (response.statusCode == HttpStatus.ok) {
WKIM.shared.messageManager.clearWithChannel(channelId, channelType);
}
} catch (e) {
print('清除频道消息失败$e');
}
}
//
static Future<bool> createGroup(String groupNo) async {
final httpClient = HttpClient();
httpClient.badCertificateCallback =
(X509Certificate cert, String host, int port) {
//
return true;
};
final dio = Dio();
dio.httpClientAdapter = DefaultHttpClientAdapter()
..onHttpClientCreate = (client) {
return httpClient;
};
try {
final response = await dio.post('$apiURL/group/create', data: {
'login_uid': UserInfo.uid,
'group_no': groupNo,
});
if (response.statusCode == HttpStatus.ok) {
return true;
} else {
return false;
}
} catch (e) {
print('创建群失败$e');
return false;
}
}
//
static Future<bool> updateGroupName(String groupNo, String groupName) async {
final httpClient = HttpClient();
httpClient.badCertificateCallback =
(X509Certificate cert, String host, int port) {
//
return true;
};
final dio = Dio();
dio.httpClientAdapter = DefaultHttpClientAdapter()
..onHttpClientCreate = (client) {
return httpClient;
};
try {
final response = await dio.put('$apiURL/groups/$groupNo', data: {
'login_uid': UserInfo.uid,
'name': groupName,
});
if (response.statusCode == HttpStatus.ok) {
return true;
} else {
return false;
}
} catch (e) {
print('修改群名称失败$e');
return false;
}
}
}

View File

@ -1,13 +1,12 @@
import 'package:example/const.dart';
import 'package:wukongimfluttersdk/common/options.dart';
import 'package:wukongimfluttersdk/entity/channel.dart';
import 'package:wukongimfluttersdk/model/wk_image_content.dart';
import 'package:wukongimfluttersdk/model/wk_video_content.dart';
import 'package:wukongimfluttersdk/model/wk_voice_content.dart';
import 'package:wukongimfluttersdk/type/const.dart';
import 'package:wukongimfluttersdk/wkim.dart';
import 'custom_message.dart';
import 'order_message_content.dart';
import 'http.dart';
class IMUtils {
@ -15,7 +14,7 @@ class IMUtils {
bool result = await WKIM.shared
.setup(Options.newDefault(UserInfo.uid, UserInfo.token));
WKIM.shared.options.getAddr = (Function(String address) complete) async {
String ip = await HttpUtils.getIP();
String ip = await HttpUtils.getIP(UserInfo.uid);
complete(ip);
};
if (result) {
@ -24,57 +23,64 @@ class IMUtils {
}
//
WKIM.shared.messageManager
.registerMsgContent(12, (data) => CustomMsg("").decodeJson(data));
.registerMsgContent(56, (data) => OrderMsg().decodeJson(data));
return result;
}
// sdk事件
//
static initListener() {
var imgs = [
"https://lmg.jj20.com/up/allimg/tx29/06052048151752929.png",
"https://pic.imeitou.com/uploads/allimg/2021061715/aqg1wx3nsds.jpg",
"https://lmg.jj20.com/up/allimg/tx30/10121138219844229.jpg",
"https://lmg.jj20.com/up/allimg/tx30/10121138219844229.jpg",
"https://lmg.jj20.com/up/allimg/tx28/430423183653303.jpg",
"https://lmg.jj20.com/up/allimg/tx23/520420024834916.jpg",
"https://himg.bdimg.com/sys/portraitn/item/public.1.a535a65d.tJe8MgWmP8zJ456B73Kzfg",
"https://img2.baidu.com/it/u=3324164588,1070151830&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500",
"https://img1.baidu.com/it/u=3916753633,2634890492&fm=253&fmt=auto&app=138&f=JPEG?w=400&h=400",
"https://img0.baidu.com/it/u=4210586523,443489101&fm=253&fmt=auto&app=138&f=JPEG?w=304&h=304",
"https://img2.baidu.com/it/u=2559320899,1546883787&fm=253&fmt=auto&app=138&f=JPEG?w=441&h=499",
"https://img0.baidu.com/it/u=2952429745,3806929819&fm=253&fmt=auto&app=138&f=JPEG?w=380&h=380",
"https://img2.baidu.com/it/u=3783923022,668713258&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
];
//
WKIM.shared.cmdManager.addOnCmdListener('sys_im', (wkcmd) async {
if (wkcmd.cmd == 'messageRevoke') {
var channelID = wkcmd.param['channel_id'];
var channelType = wkcmd.param['channel_type'];
if (channelID != '') {
//
var maxVersion = await WKIM.shared.messageManager
.getMaxExtraVersionWithChannel(channelID, channelType);
HttpUtils.syncMsgExtra(channelID, channelType, maxVersion);
}
} else if (wkcmd.cmd == 'channelUpdate') {
var channelID = wkcmd.param['channel_id'];
var channelType = wkcmd.param['channel_type'];
if (channelID != '') {
if (channelType == WKChannelType.personal) {
//
HttpUtils.getUserInfo(channelID);
} else if (channelType == WKChannelType.group) {
//
HttpUtils.getGroupInfo(channelID);
}
}
} else if (wkcmd.cmd == 'unreadClear') {
print('清空红点的cmd');
//
var channelID = wkcmd.param['channel_id'];
var channelType = wkcmd.param['channel_type'];
var unread = wkcmd.param['unread'];
if (channelID != '') {
WKIM.shared.conversationManager
.updateRedDot(channelID, channelType, unread);
}
}
});
//
WKIM.shared.messageManager.addOnSyncChannelMsgListener((channelID,
channelType, startMessageSeq, endMessageSeq, limit, pullMode, back) {
//
HttpUtils.syncChannelMsg(channelID, channelType, startMessageSeq,
endMessageSeq, limit, pullMode, (p0) => back(p0));
});
// channel资料
// channel资料/
WKIM.shared.channelManager
.addOnGetChannelListener((channelId, channelType, back) {
print('获取频道资料');
if (channelType == WKChannelType.personal) {
//
//
// todo API请求后返回
var channel = WKChannel(channelId, channelType);
channel.channelName = "【单聊】${channel.channelID}";
var index = channel.channelID.hashCode % imgs.length;
channel.avatar = imgs[index];
channel.remoteExtraMap = {'status': 1, 'notice': 'xx'};
channel.localExtra = {'localStatus': 1, 'localNotice': 'nxx'};
back(channel);
print('获取个人资料$channelId');
HttpUtils.getUserInfo(channelId);
} else if (channelType == WKChannelType.group) {
//
var channel = WKChannel(channelId, channelType);
channel.channelName = "【群聊】${channel.channelID}";
var index = channel.channelID.hashCode % imgs.length;
channel.avatar = imgs[index];
channel.remoteExtraMap = {'status': 2, 'notice': 'ss'};
channel.localExtra = {'localStatus': 2, 'localNotice': 'nss'};
back(channel);
HttpUtils.getGroupInfo(channelId);
}
});
//

View File

@ -1,6 +1,5 @@
import 'package:wukongimfluttersdk/entity/msg.dart';
import 'package:wukongimfluttersdk/type/const.dart';
import 'package:wukongimfluttersdk/wkim.dart';
import 'const.dart';
@ -12,10 +11,6 @@ class UIMsg {
if (wkMsg.messageContent == null) {
return '';
}
var readCount = 0;
if (wkMsg.wkMsgExtra != null) {
readCount = wkMsg.wkMsgExtra!.readedCount;
}
return wkMsg.messageContent!.displayText();
// return "${wkMsg.messageContent!.displayText()} [是否需要回执:${wkMsg.setting.receipt}][已读数量:$readCount]";
}

View File

@ -0,0 +1,37 @@
import 'package:wukongimfluttersdk/model/wk_message_content.dart';
class OrderMsg extends WKMessageContent {
var orderNo = "";
var title = '';
var imgUrl = '';
var num = 0;
var price = 0;
OrderMsg() {
contentType = 56;
}
@override
Map<String, dynamic> encodeJson() {
return {
"orderNo": orderNo,
'title': title,
'imgUrl': imgUrl,
'num': num,
'price': price
};
}
@override
WKMessageContent decodeJson(Map<String, dynamic> json) {
title = json["title"];
orderNo = json["orderNo"];
imgUrl = json["imgUrl"];
num = json["num"];
price = json["price"];
return this;
}
@override
String displayText() {
return "[订单消息]";
}
}

View File

@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'popup_item.dart';
class PopmenuUtil {
static Future showPopupMenu(BuildContext context,
LongPressStartDetails details, List<PopupItem> items) {
final List<PopupMenuItem> popupMenuItems = [];
for (PopupItem item in items) {
PopupMenuItem popupMenuItem = PopupMenuItem(
// PopupMenuItem 8
padding: const EdgeInsets.all(0),
onTap: item.onTap,
child: Builder(builder: (context0) {
// 使 context
// context
return GestureDetector(
behavior: HitTestBehavior.opaque,
child: Container(
padding: const EdgeInsets.all(8.0),
child: Text(
item.text,
style: const TextStyle(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.bold),
),
),
);
}),
);
popupMenuItems.add(popupMenuItem);
}
RenderBox? renderBox =
Overlay.of(context).context.findRenderObject() as RenderBox;
//
final RelativeRect position = RelativeRect.fromRect(
Rect.fromLTRB(
details.globalPosition.dx,
details.globalPosition.dy,
details.globalPosition.dx + 110, // X轴坐标
details.globalPosition.dy - 40, // Y轴坐标
),
Offset.zero & renderBox.size,
);
return showMenu(
color: Colors.white,
context: context,
position: position,
items: popupMenuItems,
useRootNavigator: true);
}
}

View File

@ -0,0 +1,7 @@
import 'package:flutter/material.dart';
class PopupItem {
final String text;
final GestureTapCallback? onTap;
PopupItem({this.text = '', this.onTap});
}

View File

@ -1,4 +1,6 @@
import 'package:example/const.dart';
import 'package:example/http.dart';
import 'package:example/order_message_content.dart';
import 'package:flutter/material.dart';
import 'package:wukongimfluttersdk/entity/channel.dart';
import 'package:wukongimfluttersdk/entity/msg.dart';
@ -7,7 +9,9 @@ import 'package:wukongimfluttersdk/proto/proto.dart';
import 'package:wukongimfluttersdk/type/const.dart';
import 'package:wukongimfluttersdk/wkim.dart';
import 'chatview.dart';
import 'msg.dart';
import 'ui_input_dialog.dart';
class ChatPage extends StatelessWidget {
const ChatPage({super.key});
@ -45,14 +49,8 @@ class ChatListDataState extends State<ChatList> {
WKIM.shared.channelManager
.getChannel(channelID, channelType)
.then((channel) {
print(channel?.localExtra);
print(channel?.remoteExtraMap);
WKIM.shared.channelManager.fetchChannelInfo(channelID, channelType);
if (channelType == WKChannelType.group) {
title = '${channel?.channelName}';
} else {
title = '${channel?.channelName}';
}
});
}
List<UIMsg> msgList = [];
@ -66,6 +64,20 @@ class ChatListDataState extends State<ChatList> {
}
initListener() {
//
WKIM.shared.channelManager.addOnRefreshListener('chat', (channel) {
if (channelID == channel.channelID) {
title = channel.channelName;
}
for (var i = 0; i < msgList.length; i++) {
if (msgList[i].wkMsg.fromUID == channel.channelID) {
msgList[i].wkMsg.setFrom(channel);
}
}
setState(() {});
});
//
WKIM.shared.messageManager.addOnMsgInsertedListener((wkMsg) {
setState(() {
msgList.add(UIMsg(wkMsg));
@ -74,6 +86,8 @@ class ChatListDataState extends State<ChatList> {
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
});
});
//
WKIM.shared.messageManager.addOnNewMsgListener('chat', (msgs) {
setState(() {
for (var i = 0; i < msgs.length; i++) {
@ -90,6 +104,8 @@ class ChatListDataState extends State<ChatList> {
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
});
});
//
WKIM.shared.messageManager.addOnRefreshMsgListener('chat', (wkMsg) {
for (var i = 0; i < msgList.length; i++) {
if (msgList[i].wkMsg.clientMsgNO == wkMsg.clientMsgNO) {
@ -102,6 +118,19 @@ class ChatListDataState extends State<ChatList> {
}
setState(() {});
});
//
WKIM.shared.messageManager.addOnDeleteMsgListener('chat', (clientMsgNo) {
for (var i = 0; i < msgList.length; i++) {
if (msgList[i].wkMsg.clientMsgNO == clientMsgNo) {
setState(() {
msgList.removeAt(i);
});
break;
}
}
});
//
WKIM.shared.messageManager.addOnClearChannelMsgListener("chat",
(channelId, channelType) {
@ -178,67 +207,16 @@ class ChatListDataState extends State<ChatList> {
}
Widget _buildRow(UIMsg uiMsg) {
if (uiMsg.wkMsg.wkMsgExtra?.revoke == 1) {
return getRevokedView(uiMsg, context);
}
if (uiMsg.wkMsg.fromUID == UserInfo.uid) {
return Container(
padding: const EdgeInsets.only(left: 0, top: 5, right: 0, bottom: 5),
child: Row(
children: [
Expanded(
child: Container(
padding:
const EdgeInsets.only(left: 5, top: 3, right: 5, bottom: 3),
margin: const EdgeInsets.only(
left: 60, top: 0, right: 5, bottom: 0),
decoration: const BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(Radius.circular(12)),
color: Colors.blue),
alignment: Alignment.bottomRight,
child: Column(
children: [
Container(
alignment: Alignment.centerRight,
child: Text(
uiMsg.getShowContent(),
style:
const TextStyle(color: Colors.white, fontSize: 16),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
uiMsg.getShowTime(),
style:
const TextStyle(color: Colors.grey, fontSize: 12),
),
Image(
image: AssetImage(uiMsg.getStatusIV()),
width: 30,
height: 30)
],
),
],
),
),
),
Container(
decoration: const BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(Radius.circular(20)),
color: Color.fromARGB(255, 243, 33, 131)),
width: 50,
alignment: Alignment.center,
height: 50,
margin: const EdgeInsets.fromLTRB(0, 0, 10, 0),
child: Text(
CommonUtils.getAvatar(uiMsg.wkMsg.fromUID),
style: const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold),
),
),
getSendView(uiMsg, context),
chatAvatar(uiMsg),
],
),
);
@ -246,62 +224,7 @@ class ChatListDataState extends State<ChatList> {
return Container(
padding: const EdgeInsets.only(left: 0, top: 5, right: 0, bottom: 5),
child: Row(
children: [
Container(
decoration: const BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(Radius.circular(20)),
color: Color.fromARGB(255, 215, 80, 1)),
width: 50,
alignment: Alignment.center,
height: 50,
margin: const EdgeInsets.fromLTRB(0, 0, 10, 0),
child: Text(
CommonUtils.getAvatar(uiMsg.wkMsg.fromUID),
style: const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold),
),
),
Expanded(
child: Container(
alignment: Alignment.centerLeft,
margin: const EdgeInsets.only(
left: 0, top: 0, right: 60, bottom: 0),
child: Container(
padding: const EdgeInsets.only(
left: 10, top: 3, right: 10, bottom: 3),
decoration: const BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(Radius.circular(12)),
color: Color.fromARGB(255, 163, 33, 243)),
child: Column(
children: [
Container(
alignment: Alignment.topLeft,
child: Text(
uiMsg.getShowContent(),
style: const TextStyle(
color: Colors.white, fontSize: 16),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
uiMsg.getShowTime(),
style: const TextStyle(
color: Colors.grey, fontSize: 12),
)
],
)
],
),
),
),
)
],
children: [chatAvatar(uiMsg), getRecvView(uiMsg, context)],
),
);
}
@ -315,23 +238,90 @@ class ChatListDataState extends State<ChatList> {
appBar: AppBar(
title: Text(title),
actions: [
MaterialButton(
child: const Text(
'清空记录',
style: TextStyle(color: Color.fromARGB(255, 4, 80, 194)),
PopupMenuButton<String>(
onSelected: (value) => {
if (value == '清空聊天记录')
{
showDialog(
context: context,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
),
onPressed: () async {
var v = await WKIM.shared.messageManager
.getMaxExtraVersionWithChannel(channelID, channelType);
print(v);
// WKIM.shared.messageManager
// .clearWithChannel(channelID, channelType);
}),
backgroundColor: Colors.white,
title: const Text('确认清空聊天记录?'),
content: const Text('清空后将无法恢复,确定要清空吗?'),
actions: <Widget>[
GestureDetector(
child: const Text(
'取消',
style: TextStyle(
color: Color.fromARGB(255, 113, 112, 112),
fontSize: 16,
fontWeight: FontWeight.bold),
),
onTap: () {
Navigator.of(context).pop();
},
),
GestureDetector(
child: Container(
margin: const EdgeInsets.only(left: 20),
child: const Text('确认',
style: TextStyle(
color: Colors.red,
fontSize: 16,
fontWeight: FontWeight.bold)),
),
onTap: () {
Navigator.of(context).pop();
HttpUtils.clearChannelMsg(
channelID, channelType);
},
),
],
);
})
}
else if (value == '修改群名称')
{showUpdateChannelNameDialog(context)}
},
itemBuilder: (context) {
return getPopuMenuItems();
},
)
],
),
floatingActionButton: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
heroTag: 'previous',
onPressed: () {
getPrevious();
},
tooltip: '上一页',
backgroundColor: Colors.transparent,
child: const Icon(Icons.vertical_align_top),
),
const SizedBox(height: 10.0),
FloatingActionButton(
heroTag: 'next',
onPressed: () {
getLast();
},
backgroundColor: Colors.transparent,
tooltip: '下一页',
child: const Icon(Icons.vertical_align_bottom),
),
const SizedBox(height: 20.0),
]),
body: Container(
padding:
const EdgeInsets.only(left: 10, top: 10, right: 10, bottom: 10),
color: const Color.fromARGB(255, 221, 221, 221),
child: Column(
children: [
Expanded(
@ -356,36 +346,22 @@ class ChatListDataState extends State<ChatList> {
),
MaterialButton(
onPressed: () {
getPrevious();
DateTime now = DateTime.now();
var orderMsg = OrderMsg();
orderMsg.title = "问界M9纯电版 旗舰SUV 2024款 3.0L 自动 豪华版";
orderMsg.num = 300;
orderMsg.price = 20;
orderMsg.orderNo = '${now.millisecondsSinceEpoch}';
orderMsg.imgUrl =
"https://img0.baidu.com/it/u=4245434814,3643211003&fm=253&fmt=auto&app=120&f=JPEG?w=674&h=500";
WKIM.shared.messageManager.sendMessage(
orderMsg, WKChannel(channelID, channelType));
},
color: Colors.brown,
child:
const Text("上一页", style: TextStyle(color: Colors.white)),
),
MaterialButton(
onPressed: () {
WKMsgExtra extra = WKMsgExtra();
extra.messageID = "112";
extra.channelID = channelID;
extra.channelType = channelType;
extra.readed = 1;
extra.extraVersion = 100871;
List<WKMsgExtra> list = [];
list.add(extra);
WKMsgExtra extra1 = WKMsgExtra();
extra1.messageID = "1122";
extra1.channelID = channelID;
extra1.channelType = channelType;
extra1.readed = 1;
extra1.extraVersion = 100872;
list.add(extra1);
WKIM.shared.messageManager.saveRemoteExtraMsg(list);
// getLast();
},
color: Colors.brown,
child:
const Text("下一页", style: TextStyle(color: Colors.white)),
child: const Text("自定义消息",
style: TextStyle(color: Colors.white)),
),
const SizedBox(width: 10.0),
MaterialButton(
onPressed: () {
if (content != '') {
@ -458,10 +434,42 @@ class ChatListDataState extends State<ChatList> {
);
}
getPopuMenuItems() {
var list = <PopupMenuItem<String>>[];
list.add(const PopupMenuItem<String>(
value: '清空聊天记录',
child: Text('清空聊天记录'),
));
if (channelType == WKChannelType.group) {
list.add(const PopupMenuItem<String>(
value: '修改群名称',
child: Text('修改群名称'),
));
}
return list;
}
showUpdateChannelNameDialog(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext context) => InputDialog(
title: const Text("请输入群名称"),
isOnlyText: true,
hintText: '请输入群名称',
back: (name, channelType) {
HttpUtils.updateGroupName(channelID, name);
},
),
);
}
@override
void dispose() {
super.dispose();
//
WKIM.shared.messageManager.removeNewMsgListener('chat');
WKIM.shared.messageManager.removeOnRefreshMsgListener('chat');
WKIM.shared.messageManager.removeDeleteMsgListener('chat');
WKIM.shared.channelManager.removeOnRefreshListener('chat');
}
}

View File

@ -1,14 +1,16 @@
import 'package:example/const.dart';
import 'package:example/http.dart';
import 'package:flutter/material.dart';
import 'package:wukongimfluttersdk/common/logs.dart';
import 'package:wukongimfluttersdk/entity/conversation.dart';
import 'package:wukongimfluttersdk/entity/reminder.dart';
import 'package:wukongimfluttersdk/type/const.dart';
import 'package:wukongimfluttersdk/wkim.dart';
import 'chat.dart';
import 'contestation.dart';
import 'input_dialog.dart';
import 'popmenu_util.dart';
import 'popup_item.dart';
import 'ui_chat.dart';
import 'conversation_msg.dart';
import 'ui_input_dialog.dart';
class HomePage extends StatelessWidget {
const HomePage({super.key});
@ -112,7 +114,7 @@ class ListViewShowDataState extends State<ListViewShowData> {
if (msgList[i].msg.channelID == channel.channelID &&
msgList[i].msg.channelType == channel.channelType) {
msgList[i].msg.setWkChannel(channel);
msgList[i].channelAvatar = channel.avatar;
msgList[i].channelAvatar = "${HttpUtils.apiURL}/${channel.avatar}";
msgList[i].channelName = channel.channelName;
setState(() {});
break;
@ -173,7 +175,8 @@ class ListViewShowDataState extends State<ListViewShowData> {
if (uiConversation.channelAvatar == '') {
uiConversation.msg.getWkChannel().then((channel) {
if (channel != null) {
uiConversation.channelAvatar = channel.avatar;
uiConversation.channelAvatar =
"${HttpUtils.apiURL}/${channel.avatar}";
}
});
}
@ -189,6 +192,10 @@ class ListViewShowDataState extends State<ListViewShowData> {
} else {
uiConversation.channelName = channel.channelRemark;
}
if (uiConversation.channelName == '') {
WKIM.shared.channelManager.fetchChannelInfo(
uiConversation.msg.channelID, uiConversation.msg.channelType);
}
} else {
WKIM.shared.channelManager.fetchChannelInfo(
uiConversation.msg.channelID, uiConversation.msg.channelType);
@ -200,7 +207,8 @@ class ListViewShowDataState extends State<ListViewShowData> {
Widget _buildRow(UIConversation uiMsg) {
return Container(
margin: const EdgeInsets.all(10),
color: Colors.white,
padding: const EdgeInsets.all(10),
child: Row(
children: [
Container(
@ -282,7 +290,9 @@ class ListViewShowDataState extends State<ListViewShowData> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color.fromARGB(255, 221, 221, 221),
appBar: AppBar(
backgroundColor: const Color.fromARGB(255, 251, 246, 246),
title: Text(_connectionStatusStr),
),
body: ListView.builder(
@ -290,6 +300,9 @@ class ListViewShowDataState extends State<ListViewShowData> {
itemCount: msgList.length,
itemBuilder: (context, pos) {
return GestureDetector(
onLongPressStart: (details) {
longClick(msgList[pos], context, details);
},
onTap: () {
Navigator.push(
context,
@ -315,46 +328,6 @@ class ListViewShowDataState extends State<ListViewShowData> {
child: const Icon(Icons.add),
),
persistentFooterButtons: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color.fromARGB(255, 240, 117, 2),
),
onPressed: () {
WKIM.shared.conversationManager.clearAllRedDot();
},
child: const Text(
'清除未读',
style: TextStyle(color: Colors.white),
),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color.fromARGB(255, 240, 2, 133),
),
onPressed: () {
if (msgList.isEmpty) {
return;
}
List<WKReminder> list = [];
WKReminder reminder = WKReminder();
reminder.needUpload = 0;
reminder.type = WKMentionType.wkReminderTypeMentionMe;
reminder.data = '[有人@你]';
reminder.done = 0;
reminder.reminderID = 11;
reminder.version = 1;
reminder.publisher = "uid_1";
reminder.channelID = msgList[0].msg.channelID;
reminder.channelType = msgList[0].msg.channelType;
list.add(reminder);
WKIM.shared.reminderManager.saveOrUpdateReminders(list);
},
child: const Text(
'提醒项',
style: TextStyle(color: Colors.white),
),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
@ -386,9 +359,11 @@ class ListViewShowDataState extends State<ListViewShowData> {
_showDialog(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext context) => InputDialog(
builder: (BuildContext _context) => InputDialog(
title: const Text("创建新的聊天"),
back: (channelID, channelType) {
back: (channelID, channelType) async {
bool isSuccess = await HttpUtils.createGroup(channelID);
if (isSuccess) {
Navigator.push(
context,
MaterialPageRoute(
@ -401,8 +376,40 @@ class ListViewShowDataState extends State<ListViewShowData> {
),
),
);
}
},
),
);
}
longClick(UIConversation uiMsg, BuildContext context,
LongPressStartDetails details) {
List<PopupItem> items = [];
if (uiMsg.msg.unreadCount > 0) {
items.add(PopupItem(
text: '设置已读',
onTap: () {
HttpUtils.clearUnread(uiMsg.msg.channelID, uiMsg.msg.channelType);
},
));
}
items.add(PopupItem(
text: '测试提醒项',
onTap: () {
List<WKReminder> list = [];
WKReminder reminder = WKReminder();
reminder.needUpload = 0;
reminder.type = WKMentionType.wkReminderTypeMentionMe;
reminder.data = '[有人@你]';
reminder.done = 0;
reminder.reminderID = 11;
reminder.version = 1;
reminder.publisher = "uid_1";
reminder.channelID = uiMsg.msg.channelID;
reminder.channelType = uiMsg.msg.channelType;
list.add(reminder);
WKIM.shared.reminderManager.saveOrUpdateReminders(list);
}));
PopmenuUtil.showPopupMenu(context, details, items);
}
}

View File

@ -3,12 +3,16 @@ import 'package:wukongimfluttersdk/type/const.dart';
class InputDialog extends StatefulWidget {
const InputDialog(
{Key? key, this.hintText = "请输入对方uid...", this.title, this.back})
{Key? key,
this.isOnlyText = false,
this.hintText = "请输入对方uid...",
this.title,
this.back})
: super(key: key);
final Function(String channelID, int channelType)? back;
final Widget? title; // Text('New nickname'.tr)
final String? hintText;
final bool isOnlyText;
@override
State<InputDialog> createState() => _InputDialogState(
title: this.title, hintText: this.hintText, back: this.back);
@ -31,6 +35,10 @@ class _InputDialogState extends State<InputDialog> {
Widget build(BuildContext context) {
return AlertDialog(
title: title,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
),
backgroundColor: Colors.white,
content: SizedBox(
height: 125,
child: Column(
@ -43,6 +51,7 @@ class _InputDialogState extends State<InputDialog> {
},
decoration: InputDecoration(hintText: hintText),
autofocus: true),
if (!widget.isOnlyText)
Row(
children: [
Radio<RadioValue>(

View File

@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:wukongimfluttersdk/wkim.dart';
import 'home.dart';
import 'ui_conversation.dart';
void main() {
runApp(const MyApp());
@ -74,7 +74,7 @@ class LoginDemoState extends State<LoginDemo> {
TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
Text(
'悟空IM演示程序。当前SDK版本V1.0.1',
'悟空IM演示程序。当前SDK版本V1.5.6',
textAlign: TextAlign.center,
style:
TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
@ -92,7 +92,7 @@ class LoginDemoState extends State<LoginDemo> {
},
decoration: const InputDecoration(
labelText: 'API基地址',
hintText: 'API基地址 默认【https://api.githubim.com'),
hintText: 'API基地址 默认【http://62.234.8.38:7090/v1'),
),
),
Padding(

View File

@ -8,7 +8,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:example/main.dart';
import 'package:example/ui_main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {

View File

@ -1,16 +1,24 @@
import 'package:wukongimfluttersdk/wkim.dart';
class Logs {
static debug(Object msg) {
if (WKIM.shared.options.debug) {
// ignore: avoid_print
print("debug:$msg");
}
}
static info(Object msg) {
if (WKIM.shared.options.debug) {
// ignore: avoid_print
print("info:$msg");
}
}
static error(Object msg) {
if (WKIM.shared.options.debug) {
// ignore: avoid_print
print("error:$msg");
}
}
}

View File

@ -4,6 +4,8 @@ class Options {
String? uid, token;
String? addr; // connect address IP:PORT
int protoVersion = 0x04; // protocol version
int deviceFlag = 0;
bool debug = true;
Function(Function(String addr) complete)?
getAddr; // async get connect address
Proto proto = Proto();

View File

@ -50,7 +50,7 @@ class WKMsg {
_channelInfo = wkChannel;
}
getChannelInfo() {
WKChannel? getChannelInfo() {
return _channelInfo;
}
@ -58,7 +58,7 @@ class WKMsg {
_memberOfFrom = wkChannelMember;
}
getMemberOfFrom() {
WKChannelMember? getMemberOfFrom() {
return _memberOfFrom;
}
@ -66,7 +66,7 @@ class WKMsg {
_from = channel;
}
getFrom() {
WKChannel? getFrom() {
return _from;
}
}

View File

@ -13,6 +13,12 @@ class WKCMDManager {
handleCMD(dynamic json) {
String cmd = WKDBConst.readString(json, 'cmd');
dynamic param = json['param'];
if (param != null && param is Map) {
if (!param.containsKey('channel_id')) {
param['channel_id'] = json['channel_id'];
param['channel_type'] = json['channel_type'];
}
}
WKCMD wkcmd = WKCMD();
wkcmd.cmd = cmd;
wkcmd.param = param;

View File

@ -36,17 +36,18 @@ class _WKSocket {
_isListening = false;
_instance = null;
try {
_socket?.destroy();
_socket?.close();
// _socket?.destroy();
} finally {
_socket = null; // _socket null
}
}
void send(Uint8List data) {
send(Uint8List data) {
try {
if (_socket?.remotePort != null) {
_socket?.add(data); // 使
_socket?.flush();
return _socket?.flush();
}
} catch (e) {
Logs.debug('发送消息错误$e');
@ -78,7 +79,7 @@ class WKConnectionManager {
Timer? checkNetworkTimer;
final heartIntervalSecond = const Duration(seconds: 60);
final checkNetworkSecond = const Duration(seconds: 1);
final HashMap<int, SendingMsg> _sendingMsgMap = HashMap();
final LinkedHashMap<int, SendingMsg> _sendingMsgMap = LinkedHashMap();
HashMap<String, Function(int, int?, ConnectionInfo?)>? _connectionListenerMap;
_WKSocket? _socket;
addOnConnectionStatus(String key, Function(int, int?, ConnectionInfo?) back) {
@ -270,15 +271,18 @@ class WKConnectionManager {
setConnectionStatus(WKConnectStatus.success,
reasoncode: connackPacket.reasonCode,
info: ConnectionInfo(connackPacket.nodeId));
// Future.delayed(Duration(seconds: 1), () {
// });
try {
WKIM.shared.conversationManager.setSyncConversation(() {
setConnectionStatus(WKConnectStatus.syncCompleted);
_resendMsg();
});
} catch (e) {
Logs.error(e.toString());
}
_resendMsg();
_startHeartTimer();
_startCheckNetworkTimer();
} else {
@ -287,6 +291,7 @@ class WKConnectionManager {
Logs.debug('连接失败!错误->${connackPacket.reasonCode}');
}
} else if (packet.header.packetType == PacketType.recv) {
Logs.debug('收到消息');
var recvPacket = packet as RecvPacket;
_verifyRecvMsg(recvPacket);
if (!recvPacket.header.noPersist) {
@ -334,6 +339,7 @@ class WKConnectionManager {
}
_sendConnectPacket() async {
CryptoUtils.init();
var deviceID = await _getDeviceID();
var connectPacket = ConnectPacket(
uid: WKIM.shared.options.uid!,
@ -346,10 +352,10 @@ class WKConnectionManager {
_sendPacket(connectPacket);
}
_sendPacket(Packet packet) {
_sendPacket(Packet packet) async {
var data = WKIM.shared.options.proto.encode(packet);
if (!isReconnection) {
_socket?.send(data);
await _socket?.send(data);
}
}
@ -366,8 +372,8 @@ class WKConnectionManager {
setConnectionStatus(WKConnectStatus.noNetwork);
} else {
if (isReconnection) {
connect();
isReconnection = false;
connect();
}
}
});
@ -519,13 +525,13 @@ class WKConnectionManager {
return isDelete;
}
_resendMsg() {
_resendMsg() async {
_removeSendingMsg();
if (_sendingMsgMap.isNotEmpty) {
final it = _sendingMsgMap.entries.iterator;
while (it.moveNext()) {
if (it.current.value.isCanResend) {
_sendPacket(it.current.value.sendPacket);
for (var entry in _sendingMsgMap.entries) {
if (entry.value.isCanResend) {
Logs.debug("重发消息:${entry.value.sendPacket.clientSeq}");
await _sendPacket(entry.value.sendPacket);
}
}
}

View File

@ -741,6 +741,9 @@ class WKMessageManager {
map['order_seq'] = orderSeq;
MessageDB.shared.updateMsgWithField(map, clientSeq);
setRefreshMsg(wkMsg);
//
WKIM.shared.conversationManager.saveWithLiMMsg(wkMsg, 0);
}
}

View File

@ -1,4 +1,3 @@
import 'package:wukongimfluttersdk/common/crypto_utils.dart';
import 'package:wukongimfluttersdk/common/mode.dart';
import 'package:wukongimfluttersdk/db/wk_db_helper.dart';
import 'package:wukongimfluttersdk/manager/channel_manager.dart';
@ -28,7 +27,7 @@ class WKIM {
Future<bool> setup(Options opts) async {
options = opts;
CryptoUtils.init();
deviceFlagApp = opts.deviceFlag;
_initNormalMsgContent();
if (isApp()) {
bool result = await WKDBHelper.shared.init();
@ -68,6 +67,7 @@ class WKIM {
});
}
@Deprecated('Use Options deviceFlag')
void setDeviceFlag(int deviceFlag) {
deviceFlagApp = deviceFlag;
}

View File

@ -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.5.5
version: 1.5.7
homepage: https://github.com/WuKongIM/WuKongIMFlutterSDK
environment: