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.
 
 
 
 
 

330 lines
10 KiB

import 'package:im_flutter_sdk/im_flutter_sdk.dart';
/// 环信在线状态管理器
class ChatPresenceManager {
// 单例模式
static final ChatPresenceManager _instance = ChatPresenceManager._internal();
factory ChatPresenceManager() => _instance;
ChatPresenceManager._internal();
// 用户ID到在线状态的映射
final Map<String, bool> _onlineStatusMap = {};
// 用户ID到EMPresence的映射
final Map<String, EMPresence> _presenceMap = {};
// 监听器ID集合(避免重复添加监听器)
final Set<String> _listenerIds = {};
// 在线状态变化回调
final Map<String, Function(bool)> _statusCallbacks = {};
// 详细状态变化回调
final Map<String, Function(EMPresence)> _presenceCallbacks = {};
/// 订阅用户在线状态
/// [userId] 目标用户ID
/// [onStatusChanged] 状态变化回调(可选)
/// [onPresenceChanged] 详细状态变化回调(可选)
Future<void> subscribeUserPresence({
required String userId,
Function(bool)? onStatusChanged,
Function(EMPresence)? onPresenceChanged,
}) async {
try {
// 存储回调
if (onStatusChanged != null) {
_statusCallbacks[userId] = onStatusChanged;
}
if (onPresenceChanged != null) {
_presenceCallbacks[userId] = onPresenceChanged;
}
// 订阅用户状态(7天有效期)
await EMClient.getInstance.presenceManager.subscribe(
members: [userId],
expiry: 604800,
);
// 立即获取一次当前状态(会触发回调,更新UI)
await _fetchUserPresence(userId);
// 设置监听器(如果尚未设置)
_setupPresenceListener(userId);
print('✅ [ChatPresenceManager] 订阅成功: userId=$userId');
} on EMError catch (e) {
print('订阅用户[$userId]在线状态失败: ${e.code}, ${e.description}');
rethrow;
}
}
/// 批量订阅多个用户的在线状态
Future<void> subscribeUsersPresence({
required List<String> userIds,
Function(String, bool)? onStatusChanged,
Function(String, EMPresence)? onPresenceChanged,
}) async {
if (userIds.isEmpty) return;
try {
// 批量订阅(环信最多支持100个)
await EMClient.getInstance.presenceManager.subscribe(
members: userIds,
expiry: 604800,
);
// 为每个用户设置回调
for (final userId in userIds) {
if (onStatusChanged != null) {
_statusCallbacks[userId] = (isOnline) => onStatusChanged(userId, isOnline);
}
if (onPresenceChanged != null) {
_presenceCallbacks[userId] = (presence) => onPresenceChanged(userId, presence);
}
// 立即获取一次当前状态
await _fetchUserPresence(userId);
}
// 设置监听器
_setupBatchPresenceListener();
} on EMError catch (e) {
print('批量订阅用户在线状态失败: ${e.code}, ${e.description}');
rethrow;
}
}
/// 获取用户的在线状态
bool isUserOnline(String userId) {
return _onlineStatusMap[userId] ?? false;
}
/// 获取用户的详细在线状态信息
EMPresence? getUserPresence(String userId) {
return _presenceMap[userId];
}
/// 获取在线状态文本描述
String getStatusDescription(String userId) {
final presence = _presenceMap[userId];
if (presence == null) return '未知';
final statusDesc = presence.statusDescription?.toLowerCase() ?? '';
// 根据标准状态返回
if (statusDesc.contains('online')) return '在线';
if (statusDesc.contains('away')) return '离开';
if (statusDesc.contains('busy')) return '忙碌';
if (statusDesc.contains('dnd')) return '勿扰';
if (statusDesc.contains('offline')) return '离线';
return '未知';
}
/// 获取在线状态颜色
int getStatusColor(String userId) {
final isOnline = _onlineStatusMap[userId] ?? false;
final presence = _presenceMap[userId];
if (!isOnline) return 0xFF999999; // 灰色
final statusDesc = presence?.statusDescription?.toLowerCase() ?? '';
if (statusDesc.contains('busy')) return 0xFFFF3B30; // 红色
if (statusDesc.contains('away')) return 0xFFFF9500; // 橙色
if (statusDesc.contains('dnd')) return 0xFFAF52DE; // 紫色
if (statusDesc.contains('online')) return 0xFF34C759; // 绿色
return 0xFF34C759; // 默认绿色
}
/// 手动刷新用户在线状态
Future<void> refreshUserPresence(String userId) async {
try {
await _fetchUserPresence(userId);
} on EMError catch (e) {
print('刷新用户[$userId]在线状态失败: ${e.code}, ${e.description}');
rethrow;
}
}
/// 取消订阅用户在线状态
Future<void> unsubscribeUserPresence(String userId) async {
try {
// 取消订阅
await EMClient.getInstance.presenceManager.unsubscribe(members: [userId]);
// 清理回调
_statusCallbacks.remove(userId);
_presenceCallbacks.remove(userId);
_onlineStatusMap.remove(userId);
_presenceMap.remove(userId);
} on EMError catch (e) {
print('取消订阅用户[$userId]在线状态失败: ${e.code}, ${e.description}');
rethrow;
}
}
/// 批量取消订阅
Future<void> unsubscribeUsersPresence(List<String> userIds) async {
if (userIds.isEmpty) return;
try {
await EMClient.getInstance.presenceManager.unsubscribe(members: userIds);
for (final userId in userIds) {
_statusCallbacks.remove(userId);
_presenceCallbacks.remove(userId);
_onlineStatusMap.remove(userId);
_presenceMap.remove(userId);
}
} on EMError catch (e) {
print('批量取消订阅在线状态失败: ${e.code}, ${e.description}');
rethrow;
}
}
/// 清理所有订阅和监听器
Future<void> dispose() async {
// 清理监听器
for (final listenerId in _listenerIds) {
try {
EMClient.getInstance.presenceManager.removeEventHandler(listenerId);
} catch (e) {
// 忽略清理错误
}
}
_listenerIds.clear();
// 清理回调
_statusCallbacks.clear();
_presenceCallbacks.clear();
// 清理数据
_onlineStatusMap.clear();
_presenceMap.clear();
}
/// 私有方法:获取用户在线状态
Future<void> _fetchUserPresence(String userId) async {
try {
List<EMPresence> presences = await EMClient.getInstance.presenceManager
.fetchPresenceStatus(members: [userId]);
if (presences.isNotEmpty) {
final presence = presences.first;
print('📥 [ChatPresenceManager] 获取到Presence状态: userId=$userId, statusDescription=${presence.statusDescription}');
_presenceMap[userId] = presence;
_updateOnlineStatus(userId, presence);
} else {
print('⚠️ [ChatPresenceManager] 未获取到Presence状态: userId=$userId');
}
} on EMError catch (e) {
print('获取用户[$userId]在线状态失败: ${e.code}, ${e.description}');
rethrow;
}
}
/// 私有方法:更新在线状态
void _updateOnlineStatus(String userId, EMPresence presence) {
final statusDesc = presence.statusDescription?.toLowerCase() ?? '';
final oldStatus = _onlineStatusMap[userId] ?? false;
bool newStatus;
// 判断在线状态逻辑
if (statusDesc.contains('online') || statusDesc.contains('available')) {
newStatus = true;
} else if (statusDesc.contains('offline')) {
newStatus = false;
} else {
// away、busy、dnd 等状态,默认算"在线"(可根据业务需求调整)
newStatus = true;
}
// 检查是否是首次设置状态
final isFirstTime = !_onlineStatusMap.containsKey(userId);
// 更新状态
_onlineStatusMap[userId] = newStatus;
// 打印调试信息
print('🔄 [ChatPresenceManager] 更新在线状态: userId=$userId, statusDescription=$statusDesc, oldStatus=$oldStatus, newStatus=$newStatus, isFirstTime=$isFirstTime');
// 触发回调(如果状态发生变化,或者首次设置)
if (isFirstTime || oldStatus != newStatus) {
print('✅ [ChatPresenceManager] 触发状态回调: userId=$userId, isOnline=$newStatus');
_statusCallbacks[userId]?.call(newStatus);
}
// 始终触发详细回调
_presenceCallbacks[userId]?.call(presence);
}
/// 私有方法:设置在线状态监听器
void _setupPresenceListener(String userId) {
final listenerId = 'presence_$userId';
if (_listenerIds.contains(listenerId)) return;
EMClient.getInstance.presenceManager.addEventHandler(
listenerId,
EMPresenceEventHandler(
onPresenceStatusChanged: (list) {
print('📡 [ChatPresenceManager] 收到Presence状态变化通知: userId=$userId, 变化数量=${list.length}');
for (var presence in list) {
if (presence.publisher == userId) {
print('✅ [ChatPresenceManager] 匹配到目标用户: userId=$userId');
_presenceMap[userId] = presence;
_updateOnlineStatus(userId, presence);
break;
}
}
},
),
);
_listenerIds.add(listenerId);
}
/// 私有方法:设置批量监听器
void _setupBatchPresenceListener() {
const listenerId = 'presence_batch_listener';
if (_listenerIds.contains(listenerId)) return;
EMClient.getInstance.presenceManager.addEventHandler(
listenerId,
EMPresenceEventHandler(
onPresenceStatusChanged: (list) {
for (var presence in list) {
final userId = presence.publisher;
if (userId != null && _statusCallbacks.containsKey(userId)) {
_presenceMap[userId] = presence;
_updateOnlineStatus(userId, presence);
}
}
},
),
);
_listenerIds.add(listenerId);
}
/// 私有方法:刷新所有已订阅用户的状态
Future<void> _refreshAllSubscribedUsers() async {
final userIds = _statusCallbacks.keys.toList();
if (userIds.isEmpty) return;
try {
List<EMPresence> presences = await EMClient.getInstance.presenceManager
.fetchPresenceStatus(members: userIds);
for (var presence in presences) {
final publisherId = presence.publisher;
if (publisherId != null && publisherId.isNotEmpty) {
_presenceMap[publisherId] = presence;
_updateOnlineStatus(publisherId, presence);
}
}
} on EMError catch (e) {
print('刷新所有订阅用户状态失败: ${e.code}, ${e.description}');
}
}
}