flutter/lib/IM/im_service.dart
2025-07-21 15:46:30 +08:00

308 lines
9.3 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:logger/logger.dart';
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';
import 'package:loopin/models/conversation_view_model.dart';
import 'package:tencent_cloud_chat_sdk/enum/history_msg_get_type_enum.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_user_full_info.dart';
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';
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");
// 登录成功后注册高级消息监听器
final messageService = ImMessageListenerService();
Get.put<ImMessageListenerService>(messageService, permanent: true);
await messageService.init();
// 注册关系链监听器
final friendListener = ImFriendListeners();
logger.i(friendListener);
Get.put<ImFriendListeners>(friendListener, permanent: true);
friendListener.register();
/// 注册消息未读数监听器
Get.put(GlobalBadge(), permanent: true);
// Get.lazyPut<GlobalBadge>(() => GlobalBadge());
} 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) {
/// 移出消息监听器
Get.find<ImMessageListenerService>().onClose();
Get.delete<ImMessageListenerService>(force: true);
/// 移出关系链监听器
Get.find<ImFriendListeners>().unregister();
Get.delete<ImFriendListeners>(force: true);
/// 清理tabbar
Get.find<TabBarController>().badgeMap.clear();
/// 移出未读消息监听器
Get.find<GlobalBadge>().onClose();
Get.delete<GlobalBadge>(force: true);
/// 反初始化
ImCore.unInit();
}
return ImResult(
success: res.code == 0,
code: res.code,
desc: res.desc,
);
}
/// 查询会话记录
Future<ImResult> getConversationList(String nextSeq, int count) async {
final res = await TencentImSDKPlugin.v2TIMManager.getConversationManager().getConversationList(nextSeq: nextSeq, count: count);
if (res.code != 0) {
return ImResult(
success: false,
code: res.code,
desc: res.desc,
);
}
final convList = res.data?.conversationList ?? [];
final userIDList = <String>[];
final groupIDList = <String>[];
// 提前收集所有需要批量查询的 userID 和 groupID
for (var conv in convList) {
if ((conv.faceUrl == null || conv.faceUrl!.isEmpty)) {
if (conv.userID != null) {
userIDList.add(conv.userID!);
} else if (conv.groupID != null) {
groupIDList.add(conv.groupID!);
}
}
}
Map<String, String?> userFaceUrlMap = {};
Map<String, String?> groupFaceUrlMap = {};
String isCustomAdmin = '0';
if (userIDList.isNotEmpty) {
final userRes = await TencentImSDKPlugin.v2TIMManager.getUsersInfo(userIDList: userIDList);
if (userRes.code == 0) {
for (var user in userRes.data!) {
final userId = user.userID ?? '';
userFaceUrlMap[userId] = user.faceUrl;
// 读取管理员标识
final customInfo = user.customInfo;
if (customInfo != null) {
isCustomAdmin = customInfo['Tag_Profile_Custom_admin'] ?? '0';
}
}
}
}
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;
// 如果 faceUrl 本身为空,尝试从查到的 map 中取值
if (faceUrl == null || faceUrl.isEmpty) {
if (conv.userID != null) {
faceUrl = userFaceUrlMap[conv.userID!];
} else if (conv.groupID != null) {
faceUrl = groupFaceUrlMap[conv.groupID!];
}
}
return ConversationViewModel(conversation: conv, faceUrl: faceUrl, isCustomAdmin: isCustomAdmin);
}).toList();
return ImResult(
success: res.code == 0,
code: res.code,
desc: res.desc,
data: viewList,
);
}
/// 获取自己的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]);
return ImResult(
success: res.code == 0,
code: res.code,
desc: res.desc,
data: res.data?.isNotEmpty == true ? res.data![0] : null,
);
}
///获取指定会话
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,
);
}
/// 获取聊天记录 如果是群聊传 groupID单聊传 userID二选一
Future<ImResult<List<V2TimMessage>>> getHistoryMessageList({
HistoryMsgGetTypeEnum getType = HistoryMsgGetTypeEnum.V2TIM_GET_LOCAL_OLDER_MSG,
String? userID,
String? groupID,
int? lastMsgSeq,
int count = 20,
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, // 群聊生效
);
return ImResult(
success: res.code == 0,
code: res.code,
desc: res.desc,
);
}
}