import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:im_flutter_sdk/im_flutter_sdk.dart'; import 'package:get/get.dart'; import '../../generated/assets.dart'; import '../../controller/discover/room_controller.dart'; import '../../controller/global.dart'; import '../../controller/message/chat_controller.dart'; import '../../controller/overlay_controller.dart'; import '../../rtc/rtc_manager.dart'; import '../../pages/discover/live_room_page.dart'; class RoomItem extends StatelessWidget { final EMMessage message; final bool isSentByMe; final bool showTime; final String formattedTime; final VoidCallback? onResend; const RoomItem({ required this.message, required this.isSentByMe, required this.showTime, required this.formattedTime, this.onResend, super.key, }); /// 从自定义消息中解析房间信息 Map? _parseRoomInfo() { try { if (message.body.type == MessageType.CUSTOM) { final customBody = message.body as EMCustomMessageBody; // 检查是否是直播间邀请消息 if (customBody.event == 'live_room_invite') { final params = customBody.params; print('📋 [RoomItem] 解析到的房间信息: $params'); return params; } } } catch (e) { print('❌ [RoomItem] 解析房间信息失败: $e'); } return null; } /// 获取频道ID String _getChannelId() { final roomInfo = _parseRoomInfo(); return roomInfo?['channelId'] ?? ''; } /// 获取主持人昵称 String _getAnchorName() { final roomInfo = _parseRoomInfo(); return roomInfo?['anchorName'] ?? '主持人'; } /// 获取主持人头像 String _getAnchorAvatar() { final roomInfo = _parseRoomInfo(); final avatar = roomInfo?['anchorAvatar'] ?? ''; // 清理头像URL(移除反引号) return avatar.trim().replaceAll('`', ''); } /// 获取封面图片(如果有的话,否则使用头像) String _getCoverImage() { final roomInfo = _parseRoomInfo(); // 优先使用封面图片,如果没有则使用头像 final coverImage = roomInfo?['coverImage'] ?? roomInfo?['anchorAvatar'] ?? ''; final cleanedUrl = coverImage.trim().replaceAll('`', ''); print('📸 [RoomItem] 封面图片URL: $cleanedUrl'); return cleanedUrl; } /// 处理点击事件 void _handleTap() async { final channelId = _getChannelId(); if (channelId.isEmpty) { return; } // 获取当前直播间ID final currentChannelId = RTCManager.instance.currentChannelId; // 隐藏小窗口 if (Get.isRegistered()) { final overlayController = Get.find(); overlayController.hide(); } // 获取 RoomController final roomController = Get.isRegistered() ? Get.find() : Get.put(RoomController()); // 如果频道ID一致,取消小窗口并进入直播间 if (currentChannelId != null && currentChannelId == channelId) { // 如果当前不在 LiveRoomPage,则导航到 LiveRoomPage final currentRoute = Get.currentRoute; if (currentRoute != '/LiveRoomPage' && !currentRoute.contains('LiveRoomPage')) { Get.to(() => const LiveRoomPage(id: 0)); } return; } // 如果不一致,退出当前直播间并进入新的直播间 if (currentChannelId != null && currentChannelId.isNotEmpty) { // 退出当前直播间 await roomController.leaveChannel(); } // 加入新的直播间 await roomController.joinChannel(channelId); } @override Widget build(BuildContext context) { final roomInfo = _parseRoomInfo(); if (roomInfo == null) { return SizedBox.shrink(); } final anchorName = _getAnchorName(); final anchorAvatar = _getAnchorAvatar(); final coverImage = _getCoverImage(); return Column( children: [ // 显示时间 if (showTime) _buildTimeLabel(), Container( padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h), child: Row( mainAxisAlignment: isSentByMe ? MainAxisAlignment.end : MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ if (!isSentByMe) _buildAvatar(), if (!isSentByMe) SizedBox(width: 8.w), // 发送消息时,状态在左侧 if (isSentByMe) Align( alignment: Alignment.center, child: Container( margin: EdgeInsets.only(top: 10.h), child: _buildMessageStatus(), ), ), if (isSentByMe) SizedBox(width: 10.w), // 直播间卡片 GestureDetector( onTap: _handleTap, child: Container( constraints: BoxConstraints(maxWidth: 150.w, maxHeight: 150.w), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12.w), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 8, offset: Offset(0, 2), ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(12.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 封面图片 Stack( children: [ Container( width: 150.w, height: 150.w, color: Colors.grey[200], child: coverImage.isNotEmpty ? CachedNetworkImage( imageUrl: coverImage, width: 150.w, height: 150.w, fit: BoxFit.cover, placeholder: (context, url) => Container( width: 150.w, height: 150.w, color: Colors.grey[200], child: Center( child: CircularProgressIndicator( strokeWidth: 2, color: Colors.grey[600], ), ), ), errorWidget: (context, url, error) { print('❌ [RoomItem] 封面图片加载失败: $url, error: $error'); return Container( width: 150.w, height: 150.w, color: Colors.grey[200], child: Icon( Icons.live_tv, size: 40.w, color: Colors.grey[400], ), ); }, ) : Container( width: 150.w, height: 150.w, color: Colors.grey[200], child: Icon( Icons.live_tv, size: 40.w, color: Colors.grey[400], ), ), ), // 直播中标签 Positioned( top: 8.w, left: 8.w, child: Container( padding: EdgeInsets.symmetric( horizontal: 8.w, vertical: 4.w, ), decoration: BoxDecoration( color: const Color.fromRGBO(117, 98, 249, 1), borderRadius: BorderRadius.circular(4.w), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.play_circle_filled, size: 12.w, color: Colors.white, ), SizedBox(width: 4.w), Text( '直播间', style: TextStyle( fontSize: 11.sp, color: Colors.white, fontWeight: FontWeight.w500, ), ), ], ), ), ), Positioned( left: 8.w, bottom: 8.w, child: Row( children: [ // 头像 ClipRRect( borderRadius: BorderRadius.circular(12.w), child: Container( width: 24.w, height: 24.w, color: Colors.grey[300], child: anchorAvatar.isNotEmpty ? CachedNetworkImage( imageUrl: anchorAvatar, width: 24.w, height: 24.w, fit: BoxFit.cover, placeholder: (context, url) => Container( width: 24.w, height: 24.w, color: Colors.grey[300], child: Center( child: SizedBox( width: 12.w, height: 12.w, child: CircularProgressIndicator( strokeWidth: 1.5, color: Colors.grey[600], ), ), ), ), errorWidget: (context, url, error) { print('❌ [RoomItem] 头像加载失败: $url, error: $error'); return Image.asset( Assets.imagesUserAvatar, width: 24.w, height: 24.w, fit: BoxFit.cover, ); }, ) : Image.asset( Assets.imagesUserAvatar, width: 24.w, height: 24.w, fit: BoxFit.cover, ), ), ), SizedBox(width: 5.w), // 标题 Container( constraints: BoxConstraints( maxWidth: 100.w, ), child: Text( anchorName, style: TextStyle( fontSize: 11.sp, color: Colors.white, fontWeight: FontWeight.w500, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ], ), ) ], ), ], ), ), ), ), if (isSentByMe) SizedBox(width: 8.w), if (isSentByMe) _buildAvatar(), ], ), ), ], ); } // 构建时间标签 Widget _buildTimeLabel() { return Container( alignment: Alignment.center, padding: EdgeInsets.symmetric(horizontal: 16.w), child: Container( padding: EdgeInsets.symmetric(horizontal: 12.w), child: Text( formattedTime, style: TextStyle(fontSize: 12.sp, color: Colors.grey), ), ), ); } // 构建头像 Widget _buildAvatar() { String? avatarUrl; if (isSentByMe) { // 发送的消息:使用当前登录用户的头像 // 优先从消息 attributes 中获取 try { final attributes = message.attributes; if (attributes != null) { avatarUrl = attributes['sender_avatarUrl'] as String? ?? attributes['avatarUrl'] as String?; } } catch (e) { // 忽略错误 } // 如果消息中没有,使用当前登录用户的头像 if (avatarUrl == null || avatarUrl.isEmpty) { avatarUrl = GlobalData().userData?.profilePhoto; } } else { // 接收的消息:使用发送者的头像 try { final attributes = message.attributes; if (attributes != null) { avatarUrl = attributes['sender_avatarUrl'] as String? ?? attributes['avatarUrl'] as String?; } } catch (e) { // 忽略错误 } // 如果消息中没有,尝试从 ChatController 获取对方用户头像 if ((avatarUrl == null || avatarUrl.isEmpty)) { try { // 尝试从 Get 获取 ChatController final chatController = Get.find(); avatarUrl = chatController.userAvatarUrl; } catch (e) { // ChatController 可能不存在,忽略错误 } } } // 清理头像URL(移除反引号) if (avatarUrl != null && avatarUrl.isNotEmpty) { avatarUrl = avatarUrl.trim().replaceAll('`', ''); } return ClipOval( child: avatarUrl != null && avatarUrl.isNotEmpty ? CachedNetworkImage( imageUrl: avatarUrl, width: 40.w, height: 40.w, fit: BoxFit.cover, placeholder: (context, url) => Image.asset( Assets.imagesUserAvatar, width: 40.w, height: 40.w, fit: BoxFit.cover, ), errorWidget: (context, url, error) => Image.asset( Assets.imagesUserAvatar, width: 40.w, height: 40.w, fit: BoxFit.cover, ), ) : Image.asset( Assets.imagesUserAvatar, width: 40.w, height: 40.w, fit: BoxFit.cover, ), ); } // 构建消息状态(发送中、已发送、失败重发) Widget _buildMessageStatus() { if (!isSentByMe) { return SizedBox.shrink(); } final status = message.status; if (status == MessageStatus.FAIL) { // 发送失败,显示重发按钮 return GestureDetector( onTap: onResend, child: Container( width: 44.w, height: 26.h, decoration: BoxDecoration( color: Color.fromRGBO(248, 85, 66, 1), borderRadius: BorderRadius.circular(8.w), ), child: Center( child: Text( '重发', style: TextStyle( fontSize: 12.sp, color: Colors.white, ), ), ), ), ); } else if (status == MessageStatus.PROGRESS) { // 发送中,不显示loading return SizedBox.shrink(); } else { // 发送成功,不显示任何状态 return SizedBox.shrink(); } } }