You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
556 lines
18 KiB
556 lines
18 KiB
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:get_storage/get_storage.dart';
|
|
import 'package:im_flutter_sdk/im_flutter_sdk.dart';
|
|
|
|
import '../../im/im_manager.dart';
|
|
import '../../model/home/marriage_data.dart';
|
|
import '../../pages/home/report_page.dart';
|
|
import '../../pages/home/user_information_page.dart';
|
|
import '../message/conversation_controller.dart';
|
|
|
|
class ChatSettingsController extends GetxController {
|
|
final String userId;
|
|
final MarriageData? userData;
|
|
final _storage = GetStorage();
|
|
|
|
// 用户信息
|
|
final Rx<EMUserInfo?> userInfo = Rx<EMUserInfo?>(null);
|
|
|
|
// 用户miId(用于跳转到用户主页)
|
|
String? miId;
|
|
|
|
// 是否拉黑
|
|
final RxBool isBlacklisted = RxBool(false);
|
|
|
|
// 是否关注
|
|
final RxBool isFollowing = RxBool(false);
|
|
|
|
// 备注名
|
|
final RxString remark = RxString('');
|
|
|
|
ChatSettingsController({
|
|
required this.userId,
|
|
this.userData,
|
|
});
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
|
|
try {
|
|
// 验证 userId
|
|
if (userId.isEmpty) {
|
|
print('❌ [ChatSettings] userId 为空');
|
|
return;
|
|
}
|
|
|
|
// 如果传入了用户信息,优先使用(同步操作,安全)
|
|
if (userData != null) {
|
|
try {
|
|
miId = userData!.miId;
|
|
} catch (e) {
|
|
print('❌ [ChatSettings] 设置 miId 失败: $e');
|
|
}
|
|
}
|
|
|
|
// 加载备注名(同步,立即执行,安全)
|
|
try {
|
|
loadRemark();
|
|
} catch (e) {
|
|
print('❌ [ChatSettings] 加载备注名失败: $e');
|
|
}
|
|
|
|
// 延迟执行异步操作,避免阻塞 UI
|
|
Future.microtask(() {
|
|
try {
|
|
// 如果传入了用户信息,同步到缓存
|
|
if (userData != null) {
|
|
_syncUserDataToCache();
|
|
}
|
|
// 初始化时获取用户信息(异步,不阻塞)
|
|
fetchUserInfo();
|
|
// 检查黑名单状态(异步,不阻塞)
|
|
checkBlacklistStatus();
|
|
// 检查关注状态(异步,不阻塞)
|
|
checkFollowStatus();
|
|
} catch (e, stackTrace) {
|
|
print('❌ [ChatSettings] 异步初始化失败: $e');
|
|
print('堆栈跟踪: $stackTrace');
|
|
}
|
|
});
|
|
} catch (e, stackTrace) {
|
|
print('❌ [ChatSettings] onInit 失败: $e');
|
|
print('堆栈跟踪: $stackTrace');
|
|
}
|
|
}
|
|
|
|
/// 将传入的用户信息同步到 ConversationController 缓存
|
|
void _syncUserDataToCache() {
|
|
try {
|
|
if (userData == null) return;
|
|
|
|
if (Get.isRegistered<ConversationController>()) {
|
|
try {
|
|
final conversationController = Get.find<ConversationController>();
|
|
final extendedInfo = ExtendedUserInfo(
|
|
userId: userId,
|
|
nickName: userData!.nickName,
|
|
avatarUrl: userData!.profilePhoto.trim().replaceAll('`', ''),
|
|
);
|
|
conversationController.cacheUserInfo(userId, extendedInfo);
|
|
if (Get.isLogEnable) {
|
|
Get.log('✅ [ChatSettings] 已同步用户信息到缓存: nickName=${userData!.nickName}');
|
|
}
|
|
} catch (e) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('⚠️ [ChatSettings] 获取 ConversationController 失败: $e');
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('⚠️ [ChatSettings] 同步用户信息到缓存失败: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 获取用户信息
|
|
Future<void> fetchUserInfo() async {
|
|
try {
|
|
// 0. 如果传入了用户信息,优先使用(已在 onInit 中处理)
|
|
if (userData != null) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('✅ [ChatSettings] 使用传入的用户信息: nickName=${userData!.nickName}, miId=${userData!.miId}');
|
|
}
|
|
// 仍然尝试从IM获取,以便更新 userInfo.value
|
|
}
|
|
|
|
// 1. 优先从ConversationController的缓存中获取用户信息
|
|
if (Get.isRegistered<ConversationController>()) {
|
|
try {
|
|
final conversationController = Get.find<ConversationController>();
|
|
final cachedUserInfo = conversationController.getCachedUserInfo(userId);
|
|
if (cachedUserInfo != null && (cachedUserInfo.nickName != null || cachedUserInfo.avatarUrl != null)) {
|
|
// 使用缓存中的用户信息创建 EMUserInfo
|
|
// 注意:EMUserInfo 可能没有公开构造函数,所以我们先尝试从IM获取
|
|
// 如果IM没有,我们使用缓存的信息来显示
|
|
if (Get.isLogEnable) {
|
|
Get.log('✅ [ChatSettings] 从缓存获取到用户信息: userId=$userId, nickName=${cachedUserInfo.nickName}');
|
|
}
|
|
}
|
|
} catch (e) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('⚠️ [ChatSettings] 获取 ConversationController 失败: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2. 尝试从IM获取用户信息
|
|
EMUserInfo? info;
|
|
try {
|
|
info = await IMManager.instance.getUserInfo(userId);
|
|
if (info != null && (info.nickName?.isNotEmpty ?? false)) {
|
|
userInfo.value = info;
|
|
if (Get.isLogEnable) {
|
|
Get.log('✅ [ChatSettings] 从IM获取到用户信息: ${info.nickName}');
|
|
}
|
|
}
|
|
} catch (e) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('⚠️ [ChatSettings] 从IM获取用户信息失败: $e');
|
|
}
|
|
}
|
|
|
|
// 3. 如果IM没有用户信息,尝试从会话历史消息中提取
|
|
if (userInfo.value == null || (userInfo.value?.nickName?.isEmpty ?? true)) {
|
|
await _fetchUserInfoFromConversation();
|
|
}
|
|
|
|
// 4. 尝试从会话历史消息中获取miId
|
|
await _tryGetMiIdFromConversation();
|
|
} catch (e) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('❌ [ChatSettings] 获取用户信息失败: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 从会话历史消息中提取用户信息
|
|
Future<void> _fetchUserInfoFromConversation() async {
|
|
try {
|
|
final conversation = await EMClient.getInstance.chatManager.getConversation(
|
|
userId,
|
|
type: EMConversationType.Chat,
|
|
createIfNeed: false,
|
|
);
|
|
|
|
if (conversation == null) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('⚠️ [ChatSettings] 会话不存在: $userId');
|
|
}
|
|
return;
|
|
}
|
|
|
|
final messages = await conversation.loadMessages(loadCount: 20);
|
|
|
|
for (var message in messages) {
|
|
try {
|
|
final attributes = message.attributes;
|
|
if (attributes == null || attributes.isEmpty) {
|
|
continue;
|
|
}
|
|
|
|
String? nickName;
|
|
String? avatarUrl;
|
|
|
|
if (message.direction == MessageDirection.RECEIVE) {
|
|
// 接收到的消息:从扩展字段中提取发送者信息(sender_ 前缀)
|
|
final fromUserId = message.from;
|
|
if (fromUserId != null && fromUserId == userId) {
|
|
nickName = attributes['sender_nickName'] as String? ?? attributes['nickName'] as String?;
|
|
avatarUrl = attributes['sender_avatarUrl'] as String? ?? attributes['avatarUrl'] as String?;
|
|
}
|
|
} else if (message.direction == MessageDirection.SEND) {
|
|
// 发送的消息:从扩展字段中提取接收者信息(receiver_ 前缀)
|
|
final toUserId = message.to;
|
|
if (toUserId != null && toUserId == userId) {
|
|
nickName = attributes['receiver_nickName'] as String?;
|
|
avatarUrl = attributes['receiver_avatarUrl'] as String?;
|
|
}
|
|
}
|
|
|
|
if (nickName != null || avatarUrl != null) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('✅ [ChatSettings] 从消息扩展字段提取到用户信息: nickName=$nickName, avatarUrl=$avatarUrl');
|
|
}
|
|
|
|
// 将提取到的用户信息保存到 ConversationController 的缓存中
|
|
if (Get.isRegistered<ConversationController>()) {
|
|
try {
|
|
final conversationController = Get.find<ConversationController>();
|
|
final extendedInfo = ExtendedUserInfo(
|
|
userId: userId,
|
|
nickName: nickName,
|
|
avatarUrl: avatarUrl,
|
|
);
|
|
conversationController.cacheUserInfo(userId, extendedInfo);
|
|
} catch (e) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('⚠️ [ChatSettings] 获取 ConversationController 失败: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
// 如果IM没有返回用户信息,尝试再次从IM获取(可能信息已更新)
|
|
if (userInfo.value == null || (userInfo.value?.nickName?.isEmpty ?? true)) {
|
|
try {
|
|
final imInfo = await IMManager.instance.getUserInfo(userId);
|
|
if (imInfo != null) {
|
|
userInfo.value = imInfo;
|
|
}
|
|
} catch (e) {
|
|
// 忽略错误,使用缓存的信息
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
} catch (e) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// 再次尝试从缓存获取
|
|
if (Get.isRegistered<ConversationController>()) {
|
|
try {
|
|
final conversationController = Get.find<ConversationController>();
|
|
final cachedUserInfo = conversationController.getCachedUserInfo(userId);
|
|
if (cachedUserInfo != null && userInfo.value == null) {
|
|
// 如果IM没有返回用户信息,但缓存中有,尝试再次从IM获取
|
|
// 或者直接使用缓存的信息(通过 getDisplayName 方法)
|
|
if (Get.isLogEnable) {
|
|
Get.log('✅ [ChatSettings] 使用缓存中的用户信息: nickName=${cachedUserInfo.nickName}');
|
|
}
|
|
}
|
|
} catch (e) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('⚠️ [ChatSettings] 获取 ConversationController 失败: $e');
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('❌ [ChatSettings] 从会话提取用户信息失败: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 尝试从会话历史消息中获取miId
|
|
Future<void> _tryGetMiIdFromConversation() async {
|
|
try {
|
|
final conversation = await EMClient.getInstance.chatManager.getConversation(
|
|
userId,
|
|
type: EMConversationType.Chat,
|
|
createIfNeed: false,
|
|
);
|
|
if (conversation != null) {
|
|
final messages = await conversation.loadMessages(loadCount: 20);
|
|
for (var message in messages) {
|
|
try {
|
|
final attributes = message.attributes;
|
|
if (attributes != null && attributes.isNotEmpty) {
|
|
// 尝试从消息扩展字段中获取miId
|
|
final msgMiId = attributes['sender_miId'] as String? ??
|
|
attributes['receiver_miId'] as String? ??
|
|
attributes['miId'] as String?;
|
|
if (msgMiId != null && msgMiId.isNotEmpty) {
|
|
miId = msgMiId;
|
|
if (Get.isLogEnable) {
|
|
Get.log('从消息扩展字段获取到miId: $miId');
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('从会话获取miId失败: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 检查黑名单状态
|
|
Future<void> checkBlacklistStatus() async {
|
|
try {
|
|
// 从服务器获取黑名单列表
|
|
final blacklist = await IMManager.instance.getBlacklist();
|
|
isBlacklisted.value = blacklist.contains(userId);
|
|
} catch (e) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('检查黑名单状态失败: $e');
|
|
}
|
|
isBlacklisted.value = false;
|
|
}
|
|
}
|
|
|
|
/// 检查关注状态
|
|
Future<void> checkFollowStatus() async {
|
|
try {
|
|
// TODO: 调用实际的API检查关注状态
|
|
// 这里暂时模拟
|
|
isFollowing.value = false;
|
|
} catch (e) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('检查关注状态失败: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 切换黑名单状态
|
|
Future<void> toggleBlacklist(bool value) async {
|
|
try {
|
|
if (value) {
|
|
// 加入黑名单
|
|
await IMManager.instance.addToBlacklist(userId);
|
|
isBlacklisted.value = true;
|
|
SmartDialog.showToast('已加入黑名单');
|
|
} else {
|
|
// 移出黑名单
|
|
await IMManager.instance.removeFromBlacklist(userId);
|
|
isBlacklisted.value = false;
|
|
SmartDialog.showToast('已移出黑名单');
|
|
}
|
|
update();
|
|
} catch (e) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('操作黑名单失败: $e');
|
|
}
|
|
SmartDialog.showToast('操作失败,请重试');
|
|
}
|
|
}
|
|
|
|
/// 切换关注状态
|
|
Future<void> toggleFollow() async {
|
|
try {
|
|
if (isFollowing.value) {
|
|
// 取消关注
|
|
// TODO: 调用实际的取消关注API
|
|
isFollowing.value = false;
|
|
SmartDialog.showToast('已取消关注');
|
|
} else {
|
|
// 关注
|
|
// TODO: 调用实际的关注API
|
|
isFollowing.value = true;
|
|
SmartDialog.showToast('已关注');
|
|
}
|
|
update();
|
|
} catch (e) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('操作关注失败: $e');
|
|
}
|
|
SmartDialog.showToast('操作失败,请重试');
|
|
}
|
|
}
|
|
|
|
/// 加载备注名
|
|
void loadRemark() {
|
|
final savedRemark = _storage.read<String>('remark_$userId');
|
|
if (savedRemark != null) {
|
|
remark.value = savedRemark;
|
|
}
|
|
}
|
|
|
|
/// 设置备注名
|
|
Future<void> setRemark(String newRemark) async {
|
|
try {
|
|
// 保存到本地存储
|
|
await _storage.write('remark_$userId', newRemark);
|
|
remark.value = newRemark;
|
|
SmartDialog.showToast('备注名设置成功');
|
|
update();
|
|
} catch (e) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('设置备注名失败: $e');
|
|
}
|
|
SmartDialog.showToast('设置失败,请重试');
|
|
}
|
|
}
|
|
|
|
/// 获取显示名称(优先显示备注名,其次显示昵称)
|
|
String getDisplayName() {
|
|
try {
|
|
if (remark.value.isNotEmpty) {
|
|
return remark.value;
|
|
}
|
|
|
|
// 优先使用传入的用户信息
|
|
if (userData != null && userData!.nickName.isNotEmpty) {
|
|
return userData!.nickName;
|
|
}
|
|
|
|
// 其次使用 IM 返回的用户信息
|
|
if (userInfo.value != null && userInfo.value!.nickName != null && userInfo.value!.nickName!.isNotEmpty) {
|
|
return userInfo.value!.nickName!;
|
|
}
|
|
|
|
// 如果 IM 没有,尝试从 ConversationController 缓存中获取
|
|
if (Get.isRegistered<ConversationController>()) {
|
|
try {
|
|
final conversationController = Get.find<ConversationController>();
|
|
final cachedUserInfo = conversationController.getCachedUserInfo(userId);
|
|
if (cachedUserInfo != null && cachedUserInfo.nickName != null && cachedUserInfo.nickName!.isNotEmpty) {
|
|
return cachedUserInfo.nickName!;
|
|
}
|
|
} catch (e) {
|
|
// 忽略错误,使用默认值
|
|
}
|
|
}
|
|
|
|
return userId.isNotEmpty ? userId : '未知用户';
|
|
} catch (e) {
|
|
print('❌ [ChatSettings] getDisplayName 失败: $e');
|
|
return userId.isNotEmpty ? userId : '未知用户';
|
|
}
|
|
}
|
|
|
|
/// 获取用户头像URL
|
|
String? getAvatarUrl() {
|
|
try {
|
|
// 优先使用传入的用户信息
|
|
if (userData != null && userData!.profilePhoto.isNotEmpty) {
|
|
return userData!.profilePhoto.trim().replaceAll('`', '');
|
|
}
|
|
|
|
// 其次使用 IM 返回的用户信息
|
|
if (userInfo.value != null && userInfo.value!.avatarUrl != null && userInfo.value!.avatarUrl!.isNotEmpty) {
|
|
return userInfo.value!.avatarUrl!;
|
|
}
|
|
|
|
// 如果 IM 没有,尝试从 ConversationController 缓存中获取
|
|
if (Get.isRegistered<ConversationController>()) {
|
|
try {
|
|
final conversationController = Get.find<ConversationController>();
|
|
final cachedUserInfo = conversationController.getCachedUserInfo(userId);
|
|
if (cachedUserInfo != null && cachedUserInfo.avatarUrl != null && cachedUserInfo.avatarUrl!.isNotEmpty) {
|
|
return cachedUserInfo.avatarUrl!;
|
|
}
|
|
} catch (e) {
|
|
// 忽略错误,返回 null
|
|
}
|
|
}
|
|
|
|
return null;
|
|
} catch (e) {
|
|
print('❌ [ChatSettings] getAvatarUrl 失败: $e');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// 举报用户
|
|
void reportUser() {
|
|
// 跳转到举报页面
|
|
Get.to(() => ReportPage());
|
|
}
|
|
|
|
/// 跳转到用户主页
|
|
Future<void> navigateToUserProfile() async {
|
|
try {
|
|
String? targetMiId;
|
|
String targetUserId = userId;
|
|
|
|
// 优先使用传入的用户信息中的 miId
|
|
if (userData != null && userData!.miId.isNotEmpty) {
|
|
targetMiId = userData!.miId;
|
|
targetUserId = userData!.userId.isNotEmpty ? userData!.userId : userId;
|
|
} else if (miId != null && miId!.isNotEmpty) {
|
|
// 如果已经有miId,直接使用
|
|
targetMiId = miId;
|
|
} else {
|
|
// 如果没有miId,尝试从会话中获取
|
|
await _tryGetMiIdFromConversation();
|
|
if (miId != null && miId!.isNotEmpty) {
|
|
targetMiId = miId;
|
|
}
|
|
}
|
|
|
|
// 验证参数
|
|
if (targetMiId == null || targetMiId.isEmpty) {
|
|
SmartDialog.showToast('无法获取用户信息,请稍后重试');
|
|
if (Get.isLogEnable) {
|
|
Get.log('❌ [ChatSettings] 无法跳转到用户主页:miId为空');
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (targetUserId.isEmpty) {
|
|
SmartDialog.showToast('用户ID无效');
|
|
if (Get.isLogEnable) {
|
|
Get.log('❌ [ChatSettings] 无法跳转到用户主页:userId为空');
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (Get.isLogEnable) {
|
|
Get.log('✅ [ChatSettings] 跳转到用户主页:miId=$targetMiId, userId=$targetUserId');
|
|
}
|
|
|
|
// 跳转到用户主页
|
|
await Get.to(() => UserInformationPage(
|
|
miId: targetMiId!,
|
|
userId: targetUserId,
|
|
));
|
|
} catch (e, stackTrace) {
|
|
if (Get.isLogEnable) {
|
|
Get.log('❌ [ChatSettings] 跳转到用户主页失败: $e');
|
|
Get.log('堆栈跟踪: $stackTrace');
|
|
}
|
|
SmartDialog.showToast('跳转失败,请稍后重试');
|
|
}
|
|
}
|
|
}
|
|
|