mirror of
https://github.com/WuKongIM/WuKongIMFlutterSDK
synced 2025-05-29 23:22:52 +00:00
fix:example Integrate business api
This commit is contained in:
parent
96814381ec
commit
e161253936
@ -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
280
example/lib/chatview.dart
Normal 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)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
@ -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";
|
||||
}
|
||||
}
|
@ -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, // 当前客户端的会话最大版本号(从保存的结果里取最大的version,如果本地没有数据则传0),
|
||||
"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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
// 监听同步最近会话
|
||||
|
@ -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]";
|
||||
}
|
||||
|
37
example/lib/order_message_content.dart
Normal file
37
example/lib/order_message_content.dart
Normal 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 "[订单消息]";
|
||||
}
|
||||
}
|
57
example/lib/popmenu_util.dart
Normal file
57
example/lib/popmenu_util.dart
Normal 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);
|
||||
}
|
||||
}
|
7
example/lib/popup_item.dart
Normal file
7
example/lib/popup_item.dart
Normal file
@ -0,0 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class PopupItem {
|
||||
final String text;
|
||||
final GestureTapCallback? onTap;
|
||||
PopupItem({this.text = '', this.onTap});
|
||||
}
|
@ -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}';
|
||||
}
|
||||
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)),
|
||||
),
|
||||
onPressed: () async {
|
||||
var v = await WKIM.shared.messageManager
|
||||
.getMaxExtraVersionWithChannel(channelID, channelType);
|
||||
print(v);
|
||||
// WKIM.shared.messageManager
|
||||
// .clearWithChannel(channelID, channelType);
|
||||
}),
|
||||
PopupMenuButton<String>(
|
||||
onSelected: (value) => {
|
||||
if (value == '清空聊天记录')
|
||||
{
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(5.0),
|
||||
),
|
||||
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');
|
||||
}
|
||||
}
|
@ -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,23 +359,57 @@ 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) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ChatPage(),
|
||||
settings: RouteSettings(
|
||||
arguments: ChatChannel(
|
||||
channelID,
|
||||
channelType,
|
||||
back: (channelID, channelType) async {
|
||||
bool isSuccess = await HttpUtils.createGroup(channelID);
|
||||
if (isSuccess) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ChatPage(),
|
||||
settings: RouteSettings(
|
||||
arguments: ChatChannel(
|
||||
channelID,
|
||||
channelType,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
@ -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,36 +51,37 @@ class _InputDialogState extends State<InputDialog> {
|
||||
},
|
||||
decoration: InputDecoration(hintText: hintText),
|
||||
autofocus: true),
|
||||
Row(
|
||||
children: [
|
||||
Radio<RadioValue>(
|
||||
value: RadioValue.personal,
|
||||
groupValue: _radioValue,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
hintText = '请输入对方uid';
|
||||
_radioValue = value!;
|
||||
});
|
||||
}),
|
||||
const Text(
|
||||
'单聊',
|
||||
style: TextStyle(fontSize: 18.0),
|
||||
),
|
||||
Radio<RadioValue>(
|
||||
value: RadioValue.group,
|
||||
groupValue: _radioValue,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
hintText = '请输入群Id';
|
||||
_radioValue = value!;
|
||||
});
|
||||
}),
|
||||
const Text(
|
||||
'群聊',
|
||||
style: TextStyle(fontSize: 18.0),
|
||||
),
|
||||
],
|
||||
)
|
||||
if (!widget.isOnlyText)
|
||||
Row(
|
||||
children: [
|
||||
Radio<RadioValue>(
|
||||
value: RadioValue.personal,
|
||||
groupValue: _radioValue,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
hintText = '请输入对方uid';
|
||||
_radioValue = value!;
|
||||
});
|
||||
}),
|
||||
const Text(
|
||||
'单聊',
|
||||
style: TextStyle(fontSize: 18.0),
|
||||
),
|
||||
Radio<RadioValue>(
|
||||
value: RadioValue.group,
|
||||
groupValue: _radioValue,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
hintText = '请输入群Id';
|
||||
_radioValue = value!;
|
||||
});
|
||||
}),
|
||||
const Text(
|
||||
'群聊',
|
||||
style: TextStyle(fontSize: 18.0),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
@ -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(
|
@ -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 {
|
||||
|
@ -1,16 +1,24 @@
|
||||
import 'package:wukongimfluttersdk/wkim.dart';
|
||||
|
||||
class Logs {
|
||||
static debug(Object msg) {
|
||||
// ignore: avoid_print
|
||||
print("debug:$msg");
|
||||
if (WKIM.shared.options.debug) {
|
||||
// ignore: avoid_print
|
||||
print("debug:$msg");
|
||||
}
|
||||
}
|
||||
|
||||
static info(Object msg) {
|
||||
// ignore: avoid_print
|
||||
print("info:$msg");
|
||||
if (WKIM.shared.options.debug) {
|
||||
// ignore: avoid_print
|
||||
print("info:$msg");
|
||||
}
|
||||
}
|
||||
|
||||
static error(Object msg) {
|
||||
// ignore: avoid_print
|
||||
print("error:$msg");
|
||||
if (WKIM.shared.options.debug) {
|
||||
// ignore: avoid_print
|
||||
print("error:$msg");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -741,6 +741,9 @@ class WKMessageManager {
|
||||
map['order_seq'] = orderSeq;
|
||||
MessageDB.shared.updateMsgWithField(map, clientSeq);
|
||||
setRefreshMsg(wkMsg);
|
||||
|
||||
// 更新最近会话
|
||||
WKIM.shared.conversationManager.saveWithLiMMsg(wkMsg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user