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.
 
 
 
 
 

279 lines
9.4 KiB

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 'text_item.dart';
import 'image_item.dart';
import 'voice_item.dart';
import 'video_item.dart';
import 'call_item.dart';
import 'gift_item.dart';
import 'room_item.dart';
import '../../controller/message/chat_controller.dart';
class MessageItem extends StatelessWidget {
final EMMessage message;
final bool isSentByMe;
final EMMessage? previousMessage;
final ChatController? chatController; // 可选:直接传入的 controller
const MessageItem({
required this.message,
required this.isSentByMe,
this.previousMessage,
this.chatController,
super.key,
});
// 检查是否是通话消息(通过消息内容识别)
bool _isCallMessage() {
try {
if (message.body.type == MessageType.TXT) {
final textBody = message.body as EMTextMessageBody;
final content = textBody.content;
// 检查是否是通话消息(以 [CALL:] 开头)
return content.startsWith('[CALL:]');
}
} catch (e) {
// 解析失败,不是通话消息
}
return false;
}
// 检查是否是礼物消息(支持新格式的自定义消息和旧格式的文本消息)
bool _isGiftMessage() {
try {
// 新格式:自定义消息
if (message.body.type == MessageType.CUSTOM) {
final customBody = message.body as EMCustomMessageBody;
return customBody.event == 'gift';
}
// 旧格式:文本消息,内容以 [GIFT:] 开头
if (message.body.type == MessageType.TXT) {
final textBody = message.body as EMTextMessageBody;
return textBody.content.startsWith('[GIFT:]');
}
} catch (e) {
// 解析失败,不是礼物消息
}
return false;
}
// 检查是否是直播间邀请消息
bool _isRoomInviteMessage() {
try {
if (message.body.type == MessageType.CUSTOM) {
final customBody = message.body as EMCustomMessageBody;
return customBody.event == 'live_room_invite';
}
} catch (e) {
// 解析失败,不是直播间邀请消息
}
return false;
}
@override
Widget build(BuildContext context) {
print('📨 [MessageItem] 渲染消息,类型: ${message.body.type}');
// 处理通话消息(通过文本消息的扩展属性识别)
if (message.body.type == MessageType.TXT && _isCallMessage()) {
return CallItem(
message: message,
isSentByMe: isSentByMe,
showTime: shouldShowTime(),
formattedTime: formatMessageTime(message.serverTime),
onResend: () {
// 通过传入的 controller 或 Get 找到 ChatController 并调用重发方法
try {
final controller = chatController ?? Get.find<ChatController>();
controller.resendMessage(message);
} catch (e) {
print('重发消息失败: $e');
}
},
);
}
// 处理礼物消息(支持新格式的自定义消息和旧格式的文本消息)
if (_isGiftMessage()) {
return GiftItem(
message: message,
isSentByMe: isSentByMe,
showTime: shouldShowTime(),
formattedTime: formatMessageTime(message.serverTime),
onResend: () {
// 通过传入的 controller 或 Get 找到 ChatController 并调用重发方法
try {
final controller = chatController ?? Get.find<ChatController>();
controller.resendMessage(message);
} catch (e) {
print('重发消息失败: $e');
}
},
);
}
// 处理直播间邀请消息(自定义消息)
if (message.body.type == MessageType.CUSTOM && _isRoomInviteMessage()) {
return RoomItem(
message: message,
isSentByMe: isSentByMe,
showTime: shouldShowTime(),
formattedTime: formatMessageTime(message.serverTime),
onResend: () {
// 通过传入的 controller 或 Get 找到 ChatController 并调用重发方法
try {
final controller = chatController ?? Get.find<ChatController>();
controller.resendMessage(message);
} catch (e) {
print('重发消息失败: $e');
}
},
);
}
// 处理文本消息
if (message.body.type == MessageType.TXT) {
final textBody = message.body as EMTextMessageBody;
return TextItem(
textBody: textBody,
isSentByMe: isSentByMe,
showTime: shouldShowTime(),
formattedTime: formatMessageTime(message.serverTime),
message: message,
onResend: () {
// 通过传入的 controller 或 Get 找到 ChatController 并调用重发方法
try {
final controller = chatController ?? Get.find<ChatController>();
controller.resendMessage(message);
} catch (e) {
print('重发消息失败: $e');
}
},
);
}
// 处理图片消息
else if (message.body.type == MessageType.IMAGE) {
final imageBody = message.body as EMImageMessageBody;
return ImageItem(
imageBody: imageBody,
isSentByMe: isSentByMe,
showTime: shouldShowTime(),
formattedTime: formatMessageTime(message.serverTime),
message: message,
onResend: () {
// 通过传入的 controller 或 Get 找到 ChatController 并调用重发方法
try {
final controller = chatController ?? Get.find<ChatController>();
controller.resendMessage(message);
} catch (e) {
print('重发消息失败: $e');
}
},
);
}
// 处理语音消息
else if (message.body.type == MessageType.VOICE) {
final voiceBody = message.body as EMVoiceMessageBody;
return VoiceItem(
voiceBody: voiceBody,
messageId: message.msgId, // 传递消息ID作为音频唯一标识
message: message, // 传递消息对象以获取状态和错误码
isSentByMe: isSentByMe,
showTime: shouldShowTime(),
formattedTime: formatMessageTime(message.serverTime),
onResend: () {
// 通过传入的 controller 或 Get 找到 ChatController 并调用重发方法
try {
final controller = chatController ?? Get.find<ChatController>();
controller.resendMessage(message);
} catch (e) {
print('重发消息失败: $e');
}
},
);
}
// 处理视频消息
else if (message.body.type == MessageType.VIDEO) {
print('🎬 [MessageItem] 检测到视频消息,准备渲染 VideoItem');
final videoBody = message.body as EMVideoMessageBody;
return VideoItem(
videoBody: videoBody,
isSentByMe: isSentByMe,
showTime: shouldShowTime(),
formattedTime: formatMessageTime(message.serverTime),
message: message,
onResend: () {
// 通过传入的 controller 或 Get 找到 ChatController 并调用重发方法
try {
final controller = chatController ?? Get.find<ChatController>();
controller.resendMessage(message);
} catch (e) {
print('重发消息失败: $e');
}
},
);
}
// 非文本消息显示占位符
print('⚠️ [MessageItem] 不支持的消息类型: ${message.body.type}');
return Column(
children: [
if (shouldShowTime()) _buildTimeLabel(),
Container(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
child: Text('不支持的消息类型: ${message.body.type}'),
),
],
);
}
// 判断是否需要显示时间
bool shouldShowTime() {
if (previousMessage == null) {
return true; // 第一条消息显示时间
}
// 判断距离上一条消息是否超过20分钟(1200000毫秒)
return (message.serverTime - previousMessage!.serverTime) > 1200000;
}
// 构建时间标签
Widget _buildTimeLabel() {
final formattedTime = formatMessageTime(message.serverTime);
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),
),
),
);
}
// 格式化消息时间
String formatMessageTime(int timestamp) {
final date = DateTime.fromMillisecondsSinceEpoch(timestamp);
final now = DateTime.now();
final today = DateTime(now.year, now.month, now.day);
final yesterday = DateTime(now.year, now.month, now.day - 1);
final messageDate = DateTime(date.year, date.month, date.day);
if (messageDate.isAtSameMomentAs(today)) {
// 今天的消息显示时间
return '今天 ${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}';
} else if (messageDate.isAtSameMomentAs(yesterday)) {
// 昨天的消息
return '昨天 ${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}';
} else {
// 其他日期显示完整日期和时间
return '${date.month}${date.day}${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}';
}
}
}