2025-07-21 15:46:30 +08:00
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:get/get.dart';
|
|
|
|
|
import 'package:logger/logger.dart';
|
2025-08-21 10:50:38 +08:00
|
|
|
|
import 'package:loopin/IM/controller/chat_controller.dart';
|
|
|
|
|
import 'package:loopin/IM/controller/im_user_info_controller.dart';
|
2025-07-21 15:46:30 +08:00
|
|
|
|
import 'package:loopin/IM/controller/tab_bar_controller.dart';
|
|
|
|
|
import 'package:loopin/IM/global_badge.dart';
|
|
|
|
|
import 'package:loopin/IM/im_core.dart';
|
|
|
|
|
import 'package:loopin/IM/im_friend_listeners.dart';
|
|
|
|
|
import 'package:loopin/IM/im_message_listeners.dart';
|
|
|
|
|
import 'package:loopin/IM/im_result.dart';
|
2025-08-21 10:50:38 +08:00
|
|
|
|
import 'package:loopin/IM/push_service.dart';
|
2025-07-21 15:46:30 +08:00
|
|
|
|
import 'package:loopin/models/conversation_view_model.dart';
|
2025-08-21 10:50:38 +08:00
|
|
|
|
import 'package:loopin/utils/wxsdk.dart';
|
|
|
|
|
import 'package:tencent_cloud_chat_sdk/enum/friend_application_type_enum.dart';
|
|
|
|
|
import 'package:tencent_cloud_chat_sdk/enum/friend_response_type_enum.dart';
|
|
|
|
|
import 'package:tencent_cloud_chat_sdk/enum/friend_type_enum.dart';
|
2025-07-21 15:46:30 +08:00
|
|
|
|
import 'package:tencent_cloud_chat_sdk/enum/history_msg_get_type_enum.dart';
|
2025-08-21 10:50:38 +08:00
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_callback.dart';
|
2025-07-21 15:46:30 +08:00
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart';
|
2025-08-21 10:50:38 +08:00
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation_filter.dart';
|
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation_operation_result.dart';
|
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation_result.dart';
|
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_follow_info.dart';
|
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_follow_operation_result.dart';
|
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_follow_type_check_result.dart';
|
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_friend_info.dart';
|
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_friend_info_result.dart';
|
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_friend_operation_result.dart';
|
2025-07-21 15:46:30 +08:00
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart';
|
2025-08-21 10:50:38 +08:00
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message_change_info.dart';
|
2025-08-26 17:38:59 +08:00
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message_search_param.dart';
|
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message_search_result.dart';
|
2025-07-21 15:46:30 +08:00
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_user_full_info.dart';
|
2025-08-21 10:50:38 +08:00
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_user_info_result.dart';
|
2025-07-21 15:46:30 +08:00
|
|
|
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_value_callback.dart';
|
|
|
|
|
import 'package:tencent_cloud_chat_sdk/native_im/adapter/tim_conversation_manager.dart';
|
2025-08-21 10:50:38 +08:00
|
|
|
|
import 'package:tencent_cloud_chat_sdk/native_im/adapter/tim_friendship_manager.dart';
|
|
|
|
|
import 'package:tencent_cloud_chat_sdk/native_im/adapter/tim_message_manager.dart';
|
2025-07-21 15:46:30 +08:00
|
|
|
|
import 'package:tencent_cloud_chat_sdk/tencent_im_sdk_plugin.dart';
|
|
|
|
|
|
|
|
|
|
final logger = Logger();
|
|
|
|
|
|
|
|
|
|
/// IM 服务封装类
|
|
|
|
|
class ImService {
|
|
|
|
|
ImService._();
|
|
|
|
|
static final instance = ImService._();
|
|
|
|
|
|
|
|
|
|
/// 登录
|
|
|
|
|
Future<ImResult> login({
|
|
|
|
|
required String userID,
|
|
|
|
|
required String userSig,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TencentImSDKPlugin.v2TIMManager.login(
|
|
|
|
|
userID: userID,
|
|
|
|
|
userSig: userSig,
|
|
|
|
|
);
|
|
|
|
|
final result = ImResult(
|
|
|
|
|
success: res.code == 0,
|
|
|
|
|
code: res.code,
|
|
|
|
|
desc: res.desc,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (result.success) {
|
|
|
|
|
logger.i("IM 登录成功:$userID");
|
2025-08-26 21:21:59 +08:00
|
|
|
|
|
|
|
|
|
// 初始化会话数据
|
|
|
|
|
final ctl = Get.find<ChatController>();
|
|
|
|
|
await ctl.getConversationList();
|
|
|
|
|
|
|
|
|
|
/// 初始化微信 SDK
|
2025-08-21 10:50:38 +08:00
|
|
|
|
await Wxsdk.init();
|
|
|
|
|
|
|
|
|
|
// 注册用户信息(基本信息+自定义信息)
|
2025-08-26 17:38:59 +08:00
|
|
|
|
if (!Get.isRegistered<ImUserInfoController>()) {
|
2025-08-26 21:21:59 +08:00
|
|
|
|
final imInfo = Get.put(ImUserInfoController(), permanent: true);
|
|
|
|
|
await imInfo.refreshUserInfo();
|
2025-08-26 17:38:59 +08:00
|
|
|
|
} else {
|
2025-08-26 21:21:59 +08:00
|
|
|
|
await Get.find<ImUserInfoController>().refreshUserInfo();
|
2025-08-26 17:38:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-07-21 15:46:30 +08:00
|
|
|
|
// 登录成功后注册高级消息监听器
|
|
|
|
|
final messageService = ImMessageListenerService();
|
|
|
|
|
Get.put<ImMessageListenerService>(messageService, permanent: true);
|
|
|
|
|
|
|
|
|
|
await messageService.init();
|
|
|
|
|
|
|
|
|
|
// 注册关系链监听器
|
|
|
|
|
final friendListener = ImFriendListeners();
|
|
|
|
|
Get.put<ImFriendListeners>(friendListener, permanent: true);
|
|
|
|
|
friendListener.register();
|
|
|
|
|
|
|
|
|
|
/// 注册消息未读数监听器
|
|
|
|
|
Get.put(GlobalBadge(), permanent: true);
|
2025-08-26 21:21:59 +08:00
|
|
|
|
|
|
|
|
|
// 初始化push服务
|
|
|
|
|
PushService().initPush(
|
|
|
|
|
sdkAppId: 1600080789,
|
|
|
|
|
appKey: 'vkFpe55aYqfV7Sk5uGaoxhEstJ3tcI9dquk7JwG1GloDSLD2HeMWeQweWWXgNlhC',
|
|
|
|
|
);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
} else {
|
|
|
|
|
logger.i("IM 登录失败:${result.code} - ${result.desc}");
|
|
|
|
|
Get.snackbar(
|
|
|
|
|
'登录失败',
|
|
|
|
|
'${result.code} - ${result.desc}',
|
|
|
|
|
backgroundColor: Colors.red.withAlpha(230),
|
|
|
|
|
colorText: Colors.white,
|
|
|
|
|
icon: const Icon(Icons.error_outline, color: Colors.white),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 登出
|
|
|
|
|
Future<ImResult> logout() async {
|
|
|
|
|
final res = await TencentImSDKPlugin.v2TIMManager.logout();
|
|
|
|
|
if (res.code == 0) {
|
|
|
|
|
/// 移出消息监听器
|
2025-08-26 17:38:59 +08:00
|
|
|
|
await Get.delete<ImMessageListenerService>(force: true);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
|
|
|
|
|
/// 移出关系链监听器
|
|
|
|
|
Get.find<ImFriendListeners>().unregister();
|
2025-08-26 17:38:59 +08:00
|
|
|
|
await Get.delete<ImFriendListeners>(force: true);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
|
|
|
|
|
/// 清理tabbar
|
|
|
|
|
Get.find<TabBarController>().badgeMap.clear();
|
|
|
|
|
|
2025-08-21 10:50:38 +08:00
|
|
|
|
/// 清理会话列表数据
|
|
|
|
|
Get.find<ChatController>().initChatData();
|
|
|
|
|
|
2025-07-21 15:46:30 +08:00
|
|
|
|
/// 移出未读消息监听器
|
|
|
|
|
Get.find<GlobalBadge>().onClose();
|
2025-08-26 17:38:59 +08:00
|
|
|
|
await Get.delete<GlobalBadge>(force: true);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
|
2025-08-21 10:50:38 +08:00
|
|
|
|
/// 移除推送服务
|
2025-08-26 17:38:59 +08:00
|
|
|
|
await PushService.unInitPush();
|
2025-08-21 10:50:38 +08:00
|
|
|
|
|
2025-07-21 15:46:30 +08:00
|
|
|
|
/// 反初始化
|
2025-08-26 17:38:59 +08:00
|
|
|
|
await ImCore.unInit();
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
2025-08-21 10:50:38 +08:00
|
|
|
|
return ImResult.wrapNoData(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 设置会话自定义属性
|
|
|
|
|
Future<ImResult<List<V2TimConversationOperationResult>>> setConversationCustomData({
|
|
|
|
|
required String customData,
|
|
|
|
|
required List<String> conversationIDList,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMConversationManager.instance.setConversationCustomData(customData: customData, conversationIDList: conversationIDList);
|
|
|
|
|
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 获取符合过滤条件的未读消息总数
|
|
|
|
|
Future<ImResult<int>> getUnreadMessageCountByFilter({
|
|
|
|
|
required V2TimConversationFilter filter,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMConversationManager.instance.getUnreadMessageCountByFilter(
|
|
|
|
|
filter: filter,
|
|
|
|
|
);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 删除会话
|
|
|
|
|
Future<ImResult<void>> deleteConversation({
|
|
|
|
|
required String conversationID,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMConversationManager.instance.deleteConversation(conversationID: conversationID);
|
|
|
|
|
|
|
|
|
|
return ImResult.wrapNoData(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 创建会话分组
|
|
|
|
|
Future<ImResult<List<V2TimConversationOperationResult>>> createConversationGroup({
|
|
|
|
|
required String groupName,
|
|
|
|
|
required List<String> conversationIDList,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMConversationManager.instance.createConversationGroup(
|
|
|
|
|
groupName: groupName,
|
|
|
|
|
conversationIDList: conversationIDList,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 获取会话分组列表
|
|
|
|
|
Future<ImResult<List<String>>> getConversationGroupList() async {
|
|
|
|
|
final res = await TIMConversationManager.instance.getConversationGroupList();
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 将会话添加到分组
|
|
|
|
|
Future<ImResult<List<V2TimConversationOperationResult>>> addConversationsToGroup({
|
|
|
|
|
required String groupName,
|
|
|
|
|
required List<String> conversationIDList,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMConversationManager.instance.addConversationsToGroup(
|
|
|
|
|
groupName: groupName,
|
|
|
|
|
conversationIDList: conversationIDList,
|
2025-07-21 15:46:30 +08:00
|
|
|
|
);
|
2025-08-21 10:50:38 +08:00
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///将会话移除分组
|
|
|
|
|
Future<ImResult<List<V2TimConversationOperationResult>>> deleteConversationsFromGroup({
|
|
|
|
|
required String groupName,
|
|
|
|
|
required List<String> conversationIDList,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMConversationManager.instance.deleteConversationsFromGroup(
|
|
|
|
|
groupName: groupName,
|
|
|
|
|
conversationIDList: conversationIDList,
|
|
|
|
|
);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 高级查询会话列表
|
|
|
|
|
Future<ImResult<V2TimConversationResult>> getConversationListByFilter({
|
|
|
|
|
required V2TimConversationFilter filter,
|
|
|
|
|
required int nextSeq,
|
|
|
|
|
int count = 20,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMConversationManager.instance.getConversationListByFilter(
|
|
|
|
|
filter: filter,
|
|
|
|
|
nextSeq: nextSeq,
|
|
|
|
|
count: count,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return ImResult.wrap(res);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 查询会话记录
|
|
|
|
|
Future<ImResult> getConversationList(String nextSeq, int count) async {
|
2025-08-21 10:50:38 +08:00
|
|
|
|
// final res = await TencentImSDKPlugin.v2TIMManager.getConversationManager().getConversationList(nextSeq: nextSeq, count: count);
|
|
|
|
|
final res = await getConvData(nextSeq, count);
|
|
|
|
|
if (res.success == false) {
|
2025-07-21 15:46:30 +08:00
|
|
|
|
return ImResult(
|
|
|
|
|
success: false,
|
|
|
|
|
code: res.code,
|
|
|
|
|
desc: res.desc,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final convList = res.data?.conversationList ?? [];
|
2025-08-26 17:38:59 +08:00
|
|
|
|
|
2025-07-21 15:46:30 +08:00
|
|
|
|
final userIDList = <String>[];
|
|
|
|
|
final groupIDList = <String>[];
|
|
|
|
|
|
|
|
|
|
// 提前收集所有需要批量查询的 userID 和 groupID
|
|
|
|
|
for (var conv in convList) {
|
2025-08-27 23:26:29 +08:00
|
|
|
|
logger.e('未过滤前到会话数据:${conv.toLogString()}');
|
2025-08-26 17:38:59 +08:00
|
|
|
|
if (conv.userID != null) {
|
|
|
|
|
userIDList.add(conv.userID!);
|
|
|
|
|
} else if (conv.groupID != null) {
|
|
|
|
|
groupIDList.add(conv.groupID!);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-27 23:26:29 +08:00
|
|
|
|
logger.e('用户ID:$userIDList');
|
2025-07-21 15:46:30 +08:00
|
|
|
|
|
|
|
|
|
Map<String, String?> userFaceUrlMap = {};
|
|
|
|
|
Map<String, String?> groupFaceUrlMap = {};
|
2025-08-26 17:38:59 +08:00
|
|
|
|
Map<String, String> isCustomAdmin = {};
|
2025-07-21 15:46:30 +08:00
|
|
|
|
if (userIDList.isNotEmpty) {
|
|
|
|
|
final userRes = await TencentImSDKPlugin.v2TIMManager.getUsersInfo(userIDList: userIDList);
|
2025-08-26 17:38:59 +08:00
|
|
|
|
|
2025-07-21 15:46:30 +08:00
|
|
|
|
if (userRes.code == 0) {
|
|
|
|
|
for (var user in userRes.data!) {
|
|
|
|
|
final userId = user.userID ?? '';
|
|
|
|
|
userFaceUrlMap[userId] = user.faceUrl;
|
|
|
|
|
|
|
|
|
|
// 读取管理员标识
|
|
|
|
|
final customInfo = user.customInfo;
|
2025-08-27 23:26:29 +08:00
|
|
|
|
logger.w('自定义信息:${user.toJson()}');
|
2025-07-21 15:46:30 +08:00
|
|
|
|
if (customInfo != null) {
|
2025-08-26 17:38:59 +08:00
|
|
|
|
isCustomAdmin[userId] = customInfo['admin'] ?? '0';
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (groupIDList.isNotEmpty) {
|
|
|
|
|
final groupRes = await TencentImSDKPlugin.v2TIMManager.getGroupManager().getGroupsInfo(groupIDList: groupIDList);
|
|
|
|
|
if (groupRes.code == 0) {
|
|
|
|
|
for (var groupResult in groupRes.data!) {
|
|
|
|
|
final info = groupResult.groupInfo;
|
|
|
|
|
if (info != null) {
|
|
|
|
|
groupFaceUrlMap[info.groupID] = info.faceUrl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final viewList = convList.map((conv) {
|
|
|
|
|
String? faceUrl = conv.faceUrl;
|
|
|
|
|
|
|
|
|
|
if (faceUrl == null || faceUrl.isEmpty) {
|
|
|
|
|
if (conv.userID != null) {
|
|
|
|
|
faceUrl = userFaceUrlMap[conv.userID!];
|
|
|
|
|
} else if (conv.groupID != null) {
|
|
|
|
|
faceUrl = groupFaceUrlMap[conv.groupID!];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-26 17:38:59 +08:00
|
|
|
|
return ConversationViewModel(
|
|
|
|
|
conversation: conv,
|
|
|
|
|
faceUrl: faceUrl,
|
|
|
|
|
isCustomAdmin: isCustomAdmin[conv.userID],
|
|
|
|
|
);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}).toList();
|
|
|
|
|
|
2025-08-21 10:50:38 +08:00
|
|
|
|
// 筛选数据,过滤掉陌生人消息
|
|
|
|
|
viewList.removeWhere((conv) {
|
|
|
|
|
final special = conv.conversation.conversationGroupList ?? [];
|
|
|
|
|
return special.contains('noFriend');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
ChatController chatcontroller = Get.find<ChatController>();
|
|
|
|
|
logger.e('新的分页内容:${res.data!.toLogString()},控制器中的:${chatcontroller.nextSeq.value}');
|
|
|
|
|
String newNextSeq = res.data?.nextSeq ?? '0';
|
|
|
|
|
bool isEnd = res.data?.isFinished ?? true;
|
|
|
|
|
|
|
|
|
|
if (isEnd) {
|
|
|
|
|
//没数据了,关闭拉取;
|
|
|
|
|
chatcontroller.isFinished.value = isEnd;
|
|
|
|
|
} else {
|
|
|
|
|
// 没拉完,记录游标
|
|
|
|
|
chatcontroller.nextSeq.value = newNextSeq;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新分页
|
|
|
|
|
chatcontroller.nextSeq.value = res.data!.nextSeq!;
|
|
|
|
|
if (res.data!.isFinished == false) {
|
|
|
|
|
if (viewList.length < 20) {
|
|
|
|
|
// 递归补偿拉取
|
|
|
|
|
final nextRes = await getConversationList(
|
|
|
|
|
res.data!.nextSeq!,
|
|
|
|
|
count,
|
|
|
|
|
);
|
|
|
|
|
if (nextRes.success && nextRes.data != null) {
|
|
|
|
|
viewList.addAll(nextRes.data as List<ConversationViewModel>);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-21 15:46:30 +08:00
|
|
|
|
return ImResult(
|
|
|
|
|
success: res.code == 0,
|
|
|
|
|
code: res.code,
|
|
|
|
|
desc: res.desc,
|
|
|
|
|
data: viewList,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-21 10:50:38 +08:00
|
|
|
|
///获取所有会话数据
|
|
|
|
|
Future<ImResult<V2TimConversationResult>> getConvData(String nextSeq, int count) async {
|
|
|
|
|
final res = await TencentImSDKPlugin.v2TIMManager.getConversationManager().getConversationList(nextSeq: nextSeq, count: count);
|
|
|
|
|
return ImResult.wrap(res);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///获取指定会话
|
|
|
|
|
Future<ImResult> getConversation({
|
|
|
|
|
required String conversationID,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMConversationManager.instance.getConversation(conversationID: conversationID); //c2c_conversationID,group_conversationID
|
|
|
|
|
|
|
|
|
|
return ImResult<V2TimConversation?>(
|
|
|
|
|
success: res.code == 0 && res.data != null,
|
|
|
|
|
code: res.code,
|
|
|
|
|
desc: res.desc,
|
|
|
|
|
data: res.data,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-26 17:38:59 +08:00
|
|
|
|
/// 搜索本地消息
|
|
|
|
|
Future<ImResult<V2TimMessageSearchResult>> searchLocalMessages({
|
|
|
|
|
required String page,
|
|
|
|
|
required String conversationID,
|
|
|
|
|
|
|
|
|
|
/// 关键词匹配机制or=0,and=1,
|
|
|
|
|
int type = 1,
|
|
|
|
|
|
|
|
|
|
/// ['你好','周末']
|
|
|
|
|
required List<String> keywordList,
|
|
|
|
|
|
|
|
|
|
/// 默认自定义消息
|
|
|
|
|
List<int> messageTypeList = const [1, 2],
|
|
|
|
|
}) async {
|
|
|
|
|
final searchParam = V2TimMessageSearchParam(
|
|
|
|
|
type: type,
|
|
|
|
|
conversationID: conversationID,
|
|
|
|
|
keywordList: keywordList,
|
|
|
|
|
messageTypeList: messageTypeList,
|
|
|
|
|
pageSize: 100,
|
|
|
|
|
// pageIndex: page,
|
|
|
|
|
searchCursor: page,
|
|
|
|
|
);
|
|
|
|
|
final V2TimValueCallback<V2TimMessageSearchResult> res = await TIMMessageManager.instance.searchLocalMessages(searchParam: searchParam);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-21 10:50:38 +08:00
|
|
|
|
/// 获取消息
|
|
|
|
|
Future<ImResult<List<V2TimMessage>>> findMessages({
|
|
|
|
|
required List<String> messageIDList,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMMessageManager.instance.findMessages(messageIDList: messageIDList);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 修改消息
|
|
|
|
|
Future<ImResult<V2TimMessageChangeInfo>> modifyMessage({
|
|
|
|
|
required V2TimMessage message,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMMessageManager.instance.modifyMessage(message: message);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-21 15:46:30 +08:00
|
|
|
|
/// 获取聊天记录 如果是群聊传 groupID,单聊传 userID,二选一
|
|
|
|
|
Future<ImResult<List<V2TimMessage>>> getHistoryMessageList({
|
|
|
|
|
HistoryMsgGetTypeEnum getType = HistoryMsgGetTypeEnum.V2TIM_GET_LOCAL_OLDER_MSG,
|
|
|
|
|
String? userID,
|
|
|
|
|
String? groupID,
|
|
|
|
|
int? lastMsgSeq,
|
2025-08-21 10:50:38 +08:00
|
|
|
|
int count = 10,
|
2025-07-21 15:46:30 +08:00
|
|
|
|
V2TimMessage? lastMsg,
|
|
|
|
|
List<int>? messageTypeList,
|
|
|
|
|
List<int>? messageSeqList,
|
|
|
|
|
int? timeBegin,
|
|
|
|
|
int? timePeriod,
|
|
|
|
|
}) async {
|
|
|
|
|
if ((userID == null || userID.isEmpty) && (groupID == null || groupID.isEmpty)) {
|
|
|
|
|
return ImResult(
|
|
|
|
|
success: false,
|
|
|
|
|
code: -1,
|
|
|
|
|
desc: 'userID 或 groupID 必须至少传入一个',
|
|
|
|
|
data: [],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final isC2C = userID != null && groupID == null;
|
|
|
|
|
|
|
|
|
|
final manager = TencentImSDKPlugin.v2TIMManager.getMessageManager();
|
|
|
|
|
|
|
|
|
|
V2TimValueCallback<List<V2TimMessage>> res;
|
|
|
|
|
|
|
|
|
|
if (!isC2C && lastMsg == null && lastMsgSeq != null) {
|
|
|
|
|
// 群聊
|
|
|
|
|
res = await manager.getHistoryMessageList(
|
|
|
|
|
getType: getType,
|
|
|
|
|
userID: userID,
|
|
|
|
|
groupID: groupID,
|
|
|
|
|
count: count,
|
|
|
|
|
lastMsgSeq: lastMsgSeq, //群聊用,包含最后一条msg
|
|
|
|
|
messageTypeList: messageTypeList,
|
|
|
|
|
messageSeqList: messageSeqList,
|
|
|
|
|
timeBegin: timeBegin,
|
|
|
|
|
timePeriod: timePeriod,
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
// 单聊
|
|
|
|
|
res = await manager.getHistoryMessageList(
|
|
|
|
|
getType: getType,
|
|
|
|
|
userID: userID,
|
|
|
|
|
groupID: groupID,
|
|
|
|
|
count: count,
|
|
|
|
|
lastMsg: lastMsg, // 单聊用,不包含最后一条msg
|
|
|
|
|
messageTypeList: messageTypeList,
|
|
|
|
|
messageSeqList: messageSeqList,
|
|
|
|
|
timeBegin: timeBegin,
|
|
|
|
|
timePeriod: timePeriod,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ImResult<List<V2TimMessage>>(
|
|
|
|
|
success: res.code == 0,
|
|
|
|
|
code: res.code,
|
|
|
|
|
desc: res.desc,
|
|
|
|
|
data: res.data ?? [],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///
|
|
|
|
|
/// 清理指定单聊会话的未读数
|
|
|
|
|
///
|
|
|
|
|
Future<ImResult> clearConversationUnreadCount({
|
|
|
|
|
required String conversationID,
|
|
|
|
|
// 0表示全部清除
|
|
|
|
|
int cleanTimestamp = 0,
|
|
|
|
|
int cleanSequence = 0,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMConversationManager.instance.cleanConversationUnreadMessageCount(
|
|
|
|
|
conversationID: conversationID,
|
|
|
|
|
cleanTimestamp: cleanTimestamp, // 单聊生效
|
|
|
|
|
cleanSequence: cleanSequence, // 群聊生效
|
|
|
|
|
);
|
|
|
|
|
|
2025-08-21 10:50:38 +08:00
|
|
|
|
return ImResult.wrapNoData(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 获取自己的userId
|
|
|
|
|
Future<ImResult> selfUserId() async {
|
|
|
|
|
V2TimValueCallback<String> self = await TencentImSDKPlugin.v2TIMManager.getLoginUser();
|
|
|
|
|
String? userId = self.data;
|
|
|
|
|
return ImResult(
|
|
|
|
|
success: self.code == 0,
|
|
|
|
|
code: self.code,
|
|
|
|
|
desc: self.desc,
|
|
|
|
|
data: userId,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 查询当前登录用户的个人信息
|
|
|
|
|
Future<ImResult> selfInfo() async {
|
|
|
|
|
// 获取当前登录的用户 ID
|
|
|
|
|
final idRes = await selfUserId();
|
|
|
|
|
// 获取用户信息
|
|
|
|
|
V2TimValueCallback<List<V2TimUserFullInfo>> res = await TencentImSDKPlugin.v2TIMManager.getUsersInfo(userIDList: [idRes.data]);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
return ImResult(
|
|
|
|
|
success: res.code == 0,
|
|
|
|
|
code: res.code,
|
|
|
|
|
desc: res.desc,
|
2025-08-21 10:50:38 +08:00
|
|
|
|
data: res.data?.isNotEmpty == true ? res.data!.first : null,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 查询其他人的信息
|
|
|
|
|
Future<ImResult> otherInfo(id) async {
|
|
|
|
|
// 获取用户信息
|
|
|
|
|
V2TimValueCallback<List<V2TimUserFullInfo>> res = await TencentImSDKPlugin.v2TIMManager.getUsersInfo(userIDList: [id]);
|
|
|
|
|
return ImResult(
|
|
|
|
|
success: res.code == 0,
|
|
|
|
|
code: res.code,
|
|
|
|
|
desc: res.desc,
|
|
|
|
|
data: res.data?.isNotEmpty == true ? res.data!.first : null,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 设置个人资料
|
|
|
|
|
Future<ImResult> setSelfInfo({
|
|
|
|
|
required V2TimUserFullInfo userFullInfo,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TencentImSDKPlugin.v2TIMManager.setSelfInfo(
|
|
|
|
|
userFullInfo: userFullInfo,
|
|
|
|
|
);
|
|
|
|
|
return ImResult.wrapNoData(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 检查是否是好友(双向或单向)
|
|
|
|
|
Future<ImResult> isMyFriend(String userID, FriendTypeEnum checkType) async {
|
|
|
|
|
final res = await TIMFriendshipManager.instance.checkFriend(
|
|
|
|
|
userIDList: [userID],
|
|
|
|
|
checkType: checkType, //V2TIM_FRIEND_TYPE_BOTH V2TIM_FRIEND_TYPE_SINGLE
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (res.code == 0 && res.data != null && res.data!.isNotEmpty) {
|
|
|
|
|
final resultType = res.data!.first.resultType;
|
|
|
|
|
final isFriend = resultType == 3; //0=无, 1=单向, 2=我在对方列表,3=双向
|
|
|
|
|
return ImResult(
|
|
|
|
|
success: true,
|
|
|
|
|
desc: res.desc,
|
|
|
|
|
code: res.code,
|
|
|
|
|
data: isFriend,
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
return ImResult(
|
|
|
|
|
success: false,
|
|
|
|
|
code: res.code,
|
|
|
|
|
desc: res.desc,
|
|
|
|
|
data: false,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 添加好友
|
|
|
|
|
Future<ImResult<V2TimFriendOperationResult>> addFriend({
|
|
|
|
|
required String userID,
|
|
|
|
|
String? remark,
|
|
|
|
|
String? friendGroup,
|
|
|
|
|
String? addWording,
|
|
|
|
|
String? addSource,
|
|
|
|
|
required FriendTypeEnum addType,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMFriendshipManager.instance.addFriend(
|
|
|
|
|
userID: userID,
|
|
|
|
|
remark: remark,
|
|
|
|
|
friendGroup: friendGroup,
|
|
|
|
|
addWording: addWording,
|
|
|
|
|
addSource: addSource,
|
|
|
|
|
addType: addType,
|
|
|
|
|
);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///接受好友申请
|
|
|
|
|
Future<ImResult<V2TimFriendOperationResult>> acceptFriendApplication({
|
|
|
|
|
required FriendResponseTypeEnum responseType,
|
|
|
|
|
required FriendApplicationTypeEnum type, // V2TIM_FRIEND_ACCEPT_AGREE,同意添加单向好友;V2TIM_FRIEND_ACCEPT_AGREE_AND_ADD,同意并添加为双向好友
|
|
|
|
|
required String userID,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMFriendshipManager.instance.acceptFriendApplication(
|
|
|
|
|
responseType: responseType,
|
|
|
|
|
type: type,
|
|
|
|
|
userID: userID,
|
|
|
|
|
);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 拉黑
|
|
|
|
|
Future<ImResult<List<V2TimFriendOperationResult>>> addToBlackList({
|
|
|
|
|
required List<String> userIDList,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMFriendshipManager.instance.addToBlackList(userIDList: userIDList);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 取消拉黑
|
|
|
|
|
Future<ImResult<List<V2TimFriendOperationResult>>> deleteFromBlackList({
|
|
|
|
|
required List<String> userIDList,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMFriendshipManager.instance.deleteFromBlackList(userIDList: userIDList);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///获取好友列表
|
|
|
|
|
Future<ImResult<List<V2TimFriendInfo>>> getFriendList() async {
|
|
|
|
|
final res = await TIMFriendshipManager.instance.getFriendList();
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// set好友备注
|
|
|
|
|
Future<ImResult> setFriendInfo({
|
|
|
|
|
required String userID,
|
|
|
|
|
String? friendRemark,
|
|
|
|
|
Map<String, String>? friendCustomInfo,
|
|
|
|
|
}) async {
|
|
|
|
|
late V2TimCallback res;
|
|
|
|
|
res = await TIMFriendshipManager.instance.setFriendInfo(
|
|
|
|
|
userID: userID,
|
|
|
|
|
friendRemark: friendRemark,
|
|
|
|
|
friendCustomInfo: friendCustomInfo,
|
|
|
|
|
);
|
|
|
|
|
return ImResult.wrapNoData(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 获取好友信息
|
|
|
|
|
Future<ImResult<List<V2TimFriendInfoResult>>> getFriendInfo({
|
|
|
|
|
required List<String> userIDList,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMFriendshipManager.instance.getFriendsInfo(userIDList: userIDList);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///关注
|
|
|
|
|
Future<ImResult<List<V2TimFollowOperationResult>>> followUser({
|
|
|
|
|
required List<String> userIDList,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMFriendshipManager.instance.followUser(
|
|
|
|
|
userIDList: userIDList,
|
|
|
|
|
);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///取关
|
|
|
|
|
Future<ImResult<List<V2TimFollowOperationResult>>> unfollowUser({
|
|
|
|
|
required List<String> userIDList,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMFriendshipManager.instance.unfollowUser(
|
|
|
|
|
userIDList: userIDList,
|
|
|
|
|
);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// check关注的类型
|
|
|
|
|
/// 0:不是好友也没有关注
|
|
|
|
|
/// 1:你关注了对方(单向)
|
|
|
|
|
/// 2:对方关注了你(单向)
|
|
|
|
|
/// 3:互相关注(双向好友)
|
|
|
|
|
Future<ImResult<List<V2TimFollowTypeCheckResult>>> checkFollowType({
|
|
|
|
|
required List<String> userIDList,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMFriendshipManager.instance.checkFollowType(
|
|
|
|
|
userIDList: userIDList,
|
|
|
|
|
);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///获取指定用户的 关注/粉丝/互关 数量信息
|
|
|
|
|
Future<ImResult<List<V2TimFollowInfo>>> getUserFollowInfo({
|
|
|
|
|
required List<String> userIDList,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMFriendshipManager.instance.getUserFollowInfo(userIDList: userIDList);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 获取双向关注列表(互关好友)
|
|
|
|
|
/// [nextCursor] 分页游标,首次传空字符串
|
|
|
|
|
Future<ImResult<V2TimUserInfoResult>> getMutualFollowersList({
|
|
|
|
|
required String nextCursor,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMFriendshipManager.instance.getMutualFollowersList(
|
|
|
|
|
nextCursor: nextCursor,
|
|
|
|
|
);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 获取我的粉丝列表
|
|
|
|
|
/// [nextCursor] 分页游标,首次传空字符串
|
|
|
|
|
Future<ImResult<V2TimUserInfoResult>> getMyFollowersList({
|
|
|
|
|
required String nextCursor,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMFriendshipManager.instance.getMyFollowersList(
|
|
|
|
|
nextCursor: nextCursor,
|
2025-07-21 15:46:30 +08:00
|
|
|
|
);
|
2025-08-21 10:50:38 +08:00
|
|
|
|
return ImResult.wrap(res);
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|
2025-09-03 11:25:31 +08:00
|
|
|
|
|
|
|
|
|
/// 获取我的关注列表
|
|
|
|
|
/// [nextCursor] 分页游标,首次传空字符串
|
|
|
|
|
Future<ImResult<V2TimUserInfoResult>> getMyFollowingList({
|
|
|
|
|
required String nextCursor,
|
|
|
|
|
}) async {
|
|
|
|
|
final res = await TIMFriendshipManager.instance.getMyFollowingList(
|
|
|
|
|
nextCursor: nextCursor,
|
|
|
|
|
);
|
|
|
|
|
return ImResult.wrap(res);
|
|
|
|
|
}
|
2025-07-21 15:46:30 +08:00
|
|
|
|
}
|