308 lines
9.3 KiB
Dart
308 lines
9.3 KiB
Dart
![]() |
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,
|
|||
|
);
|
|||
|
}
|
|||
|
}
|