import 'package:get/get.dart'; import 'package:im_flutter_sdk/im_flutter_sdk.dart'; import '../../im/im_manager.dart'; import '../../model/mine/user_base_data.dart'; // 扩展类用于存储用户信息(包括业务系统的信息) class ExtendedUserInfo { final String userId; final String? nickName; final String? avatarUrl; ExtendedUserInfo({ required this.userId, this.nickName, this.avatarUrl, }); // 从 EMUserInfo 创建 factory ExtendedUserInfo.fromEMUserInfo(EMUserInfo emUserInfo) { return ExtendedUserInfo( userId: emUserInfo.userId, nickName: emUserInfo.nickName, avatarUrl: emUserInfo.avatarUrl, ); } // 从 UserBaseData 创建 factory ExtendedUserInfo.fromUserBaseData(UserBaseData userBaseData, {String? avatarUrl}) { return ExtendedUserInfo( userId: userBaseData.userId, nickName: userBaseData.nickName, avatarUrl: avatarUrl, ); } } class ConversationController extends GetxController { // 会话列表数据 final conversations = [].obs; // 加载状态 final isLoading = false.obs; // 错误消息 final errorMessage = ''.obs; // 用户信息缓存(userId -> ExtendedUserInfo) final Map _userInfoCache = {}; /// 缓存用户信息(公开方法,供 ChatController 调用) void cacheUserInfo(String userId, ExtendedUserInfo userInfo) { _userInfoCache[userId] = userInfo; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 已缓存用户信息: userId=$userId, nickName=${userInfo.nickName}'); } } @override void onInit() { super.onInit(); // 初始化时检查 IM 登录状态,如果已登录则加载会话列表 _checkAndLoadConversations(); } /// 检查 IM 登录状态并加载会话列表 Future _checkAndLoadConversations() async { // 如果已登录,直接加载 if (IMManager.instance.isLoggedIn) { await loadConversations(); return; } // 如果未登录,等待登录完成(最多等待 10 秒) if (Get.isLogEnable) { Get.log('⏳ [ConversationController] IM 未登录,等待登录完成...'); } int retryCount = 0; const maxRetries = 20; // 最多重试 20 次(每次 500ms,总共 10 秒) while (retryCount < maxRetries && !IMManager.instance.isLoggedIn) { await Future.delayed(Duration(milliseconds: 500)); retryCount++; } if (IMManager.instance.isLoggedIn) { if (Get.isLogEnable) { Get.log('✅ [ConversationController] IM 已登录,开始加载会话列表'); } await loadConversations(); } else { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] IM 登录超时,显示错误提示'); } errorMessage.value = 'IM 未登录,请稍后重试'; isLoading.value = false; } } /// 加载会话列表 Future loadConversations() async { if (isLoading.value) return; // 检查 IM 登录状态 if (!IMManager.instance.isLoggedIn) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] IM 未登录,无法加载会话列表'); } errorMessage.value = 'IM 未登录,无法加载会话列表'; isLoading.value = false; return; } try { isLoading.value = true; errorMessage.value = ''; // 从IMManager获取会话列表 final List convList = await IMManager.instance .getConversations(); // 更新会话列表 conversations.value = convList; // 从所有会话的历史消息中提取用户信息并缓存(应用重启后恢复用户信息) _extractUserInfoFromConversations(convList); // 使用GetX日志系统 if (Get.isLogEnable) { Get.log('Loaded ${convList.length} conversations'); } } catch (e) { // 使用GetX日志系统 if (Get.isLogEnable) { Get.log('Failed to load conversations: $e'); } errorMessage.value = '加载会话列表失败,请稍后重试'; } finally { isLoading.value = false; } } /// 从所有会话的历史消息中提取用户信息并缓存 /// 这样应用重启后也能恢复用户信息 /// 注意:只提取对方(接收到的消息)的用户信息,不提取自己的信息 Future _extractUserInfoFromConversations(List convList) async { try { for (var conversation in convList) { try { // conversation.id 是对方用户ID final targetUserId = conversation.id; // 如果缓存中已有该用户信息,跳过 if (_userInfoCache.containsKey(targetUserId)) continue; // 获取会话的最新消息(最多获取最近20条) final messages = await conversation.loadMessages( loadCount: 20, ); // 从消息中提取用户信息 // 接收消息:提取发送者信息(sender_ 前缀) // 发送消息:提取接收者信息(receiver_ 前缀) for (var message in messages) { Map? attributes; try { attributes = message.attributes; } catch (e) { continue; } if (attributes == null || attributes.isEmpty) { continue; } if (message.direction == MessageDirection.RECEIVE) { // 接收到的消息:从扩展字段中提取发送者信息(sender_ 前缀) final fromUserId = message.from; if (fromUserId != null && fromUserId == targetUserId) { // 优先使用 sender_ 前缀的字段(发送者信息) final nickName = attributes['sender_nickName'] as String? ?? attributes['nickName'] as String?; final avatarUrl = attributes['sender_avatarUrl'] as String? ?? attributes['avatarUrl'] as String?; if (nickName != null || avatarUrl != null) { final extendedInfo = ExtendedUserInfo( userId: targetUserId, nickName: nickName, avatarUrl: avatarUrl, ); _userInfoCache[targetUserId] = extendedInfo; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 从接收消息恢复对方用户信息: userId=$targetUserId, nickName=$nickName'); } // 找到一个就足够了,跳出循环 break; } } } else if (message.direction == MessageDirection.SEND) { // 发送的消息:从扩展字段中提取接收者信息(receiver_ 前缀) final toUserId = message.to; if (toUserId != null && toUserId == targetUserId) { // 使用 receiver_ 前缀的字段(接收者信息) final nickName = attributes['receiver_nickName'] as String?; final avatarUrl = attributes['receiver_avatarUrl'] as String?; if (nickName != null || avatarUrl != null) { final extendedInfo = ExtendedUserInfo( userId: targetUserId, nickName: nickName, avatarUrl: avatarUrl, ); _userInfoCache[targetUserId] = extendedInfo; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 从发送消息恢复对方用户信息: userId=$targetUserId, nickName=$nickName'); } // 找到一个就足够了,跳出循环 break; } } } } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 从会话提取用户信息失败: ${conversation.id}, 错误: $e'); } } } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 批量提取用户信息失败: $e'); } } } /// 刷新会话列表 Future refreshConversations() async { await loadConversations(); } /// 清除会话列表和用户信息缓存(用于退出登录时) void clearConversations() { conversations.clear(); _userInfoCache.clear(); errorMessage.value = ''; isLoading.value = false; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 已清除会话列表和用户信息缓存'); } } /// 获取会话的最新消息 String getLastMessageContent(EMMessage? message) { if(message?.body.type == MessageType.TXT){ final body = message?.body as EMTextMessageBody; return body.content; }else if(message?.body.type == MessageType.IMAGE){ return '[图片]'; }else if(message?.body.type == MessageType.VOICE){ return '[语音]'; }else if(message?.body.type == MessageType.VIDEO){ return '[视频]'; }else if(message?.body.type == MessageType.FILE){ return '[文件]'; }else if(message?.body.type == MessageType.LOCATION){ return '[位置]'; }else if(message?.body.type == MessageType.CUSTOM){ final body = message?.body as EMCustomMessageBody; // 检查是否是分享房间类型 if(body.event == 'live_room_invite'){ return '[分享房间]'; } return '[自定义消息]'; } return '暂无消息'; } /// 获取会话的未读消息数量 Future getUnreadCount(EMConversation conversation) async { try { // 简化实现,返回0 return await conversation.unreadCount(); } catch (e) { if (Get.isLogEnable) { Get.log('Error getting unread count: $e'); } return 0; } } /// 格式化消息时间 String formatMessageTime(int timestamp) { DateTime messageTime = DateTime.fromMillisecondsSinceEpoch(timestamp); DateTime now = DateTime.now(); // 检查是否是今天 if (messageTime.year == now.year && messageTime.month == now.month && messageTime.day == now.day) { // 今天显示时:分 return '${messageTime.hour.toString().padLeft(2, '0')}:${messageTime.minute.toString().padLeft(2, '0')}'; } // 检查是否是昨天 DateTime yesterday = now.subtract(Duration(days: 1)); if (messageTime.year == yesterday.year && messageTime.month == yesterday.month && messageTime.day == yesterday.day) { return '昨天'; } // 其他日期显示月-日 return '${messageTime.month.toString().padLeft(2, '0')}-${messageTime.day.toString().padLeft(2, '0')}'; } Future loadContact(String userId) async{ try { // 1. 先从缓存中查找(优先级最高) if (_userInfoCache.containsKey(userId)) { final cachedUser = _userInfoCache[userId]!; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 从缓存获取到用户信息: $userId, nickName=${cachedUser.nickName}, avatarUrl=${cachedUser.avatarUrl}'); } return cachedUser; } // 2. 尝试从会话的历史消息中提取用户信息(从消息扩展字段) // 这是最重要的数据源,因为用户信息存储在消息扩展字段中 // 注意:conversation.id 是对方用户ID,应该从接收到的消息中提取对方的信息 try { final conversation = await EMClient.getInstance.chatManager.getConversation( userId, type: EMConversationType.Chat, createIfNeed: false, ); if (conversation != null) { // 获取最近的消息(最多20条),查找包含用户信息的消息 final messages = await conversation.loadMessages( loadCount: 20, ); // 从消息中查找用户信息(只查找接收到的消息,因为那是对方的用户信息) // conversation.id 是对方用户ID,所以应该从接收到的消息中提取对方的信息 if (Get.isLogEnable) { Get.log('🔍 [ConversationController] 开始从会话历史消息查找用户信息: userId=$userId, 消息数量=${messages.length}'); } // 先打印所有消息的详细信息,用于调试 if (Get.isLogEnable) { for (var msg in messages) { final fromId = msg.from; final toId = msg.to; final direction = msg.direction; Map? attrs; try { attrs = msg.attributes; } catch (e) { attrs = null; } Get.log(' 📨 消息: msgId=${msg.msgId}, 方向=$direction, from=$fromId, to=$toId, attributes=$attrs'); } } for (var message in messages) { Map? attributes; try { attributes = message.attributes; } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 无法访问 message.attributes: $e'); } continue; } if (attributes == null || attributes.isEmpty) { continue; } if (message.direction == MessageDirection.RECEIVE) { // 接收到的消息:从扩展字段中提取发送者信息(sender_ 前缀) // conversation.id 是对方用户ID,应该从接收到的消息中提取发送者(对方)的信息 final fromUserId = message.from; if (fromUserId != null && fromUserId == userId) { // 优先使用 sender_ 前缀的字段(发送者信息) final nickName = attributes['sender_nickName'] as String? ?? attributes['nickName'] as String?; final avatarUrl = attributes['sender_avatarUrl'] as String? ?? attributes['avatarUrl'] as String?; if (Get.isLogEnable) { Get.log('🔍 [ConversationController] 从接收消息提取发送者信息: msgId=${message.msgId}, fromUserId=$fromUserId, nickName=$nickName, avatarUrl=$avatarUrl'); } if (nickName != null || avatarUrl != null) { final extendedInfo = ExtendedUserInfo( userId: userId, nickName: nickName, avatarUrl: avatarUrl, ); _userInfoCache[userId] = extendedInfo; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 从接收消息扩展字段获取到对方用户信息: userId=$userId, nickName=$nickName'); } return extendedInfo; } } } else if (message.direction == MessageDirection.SEND) { // 发送的消息:从扩展字段中提取接收者信息(receiver_ 前缀) // conversation.id 是对方用户ID,应该从发送的消息中提取接收者(对方)的信息 final toUserId = message.to; if (toUserId != null && toUserId == userId) { // 使用 receiver_ 前缀的字段(接收者信息) final nickName = attributes['receiver_nickName'] as String?; final avatarUrl = attributes['receiver_avatarUrl'] as String?; if (Get.isLogEnable) { Get.log('🔍 [ConversationController] 从发送消息提取接收者信息: msgId=${message.msgId}, toUserId=$toUserId, nickName=$nickName, avatarUrl=$avatarUrl'); } if (nickName != null || avatarUrl != null) { final extendedInfo = ExtendedUserInfo( userId: userId, nickName: nickName, avatarUrl: avatarUrl, ); _userInfoCache[userId] = extendedInfo; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 从发送消息扩展字段获取到对方用户信息: userId=$userId, nickName=$nickName'); } return extendedInfo; } } } } if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 在会话历史消息中未找到用户信息: userId=$userId'); } } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 从会话消息提取用户信息失败: $e'); } } // 3. 如果从消息扩展字段获取不到,尝试从环信获取用户信息(作为备选) try { var data = await IMManager.instance.getContacts(userId); var emUserInfo = data[userId]; if (emUserInfo != null && (emUserInfo.nickName?.isNotEmpty ?? false)) { final extendedInfo = ExtendedUserInfo.fromEMUserInfo(emUserInfo); _userInfoCache[userId] = extendedInfo; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 从环信获取到用户信息: $userId, nickName=${extendedInfo.nickName}'); } return extendedInfo; } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 从环信获取用户信息失败: $e'); } } // 4. 如果都获取不到,返回一个基本的 ExtendedUserInfo(至少显示用户ID) final fallbackInfo = ExtendedUserInfo(userId: userId); _userInfoCache[userId] = fallbackInfo; if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 未从任何来源获取到用户信息,使用默认值: $userId'); } return fallbackInfo; } catch (e) { if (Get.isLogEnable) { Get.log('❌ [ConversationController] 获取用户信息失败: $userId, 错误: $e'); } // 即使出错也返回一个基本的 ExtendedUserInfo final fallbackInfo = ExtendedUserInfo(userId: userId); _userInfoCache[userId] = fallbackInfo; return fallbackInfo; } } Future lastMessage(EMConversation conversation) async{ return await conversation.latestMessage(); } /// 删除会话 Future deleteConversation(String conversationId) async { try { final success = await IMManager.instance.deleteConversation( conversationId, ); if (success) { conversations.removeWhere((element) => element.id == conversationId); } return success; } catch (e) { if (Get.isLogEnable) { Get.log('删除会话失败: $e'); } return false; } } }