diff --git a/lib/controller/message/chat_controller.dart b/lib/controller/message/chat_controller.dart index adbe2df..6aafcc9 100644 --- a/lib/controller/message/chat_controller.dart +++ b/lib/controller/message/chat_controller.dart @@ -84,6 +84,9 @@ class ChatController extends GetxController { messages.assignAll(validMessages); } + // 通知UI更新 + update(); + // 更新游标 if (validMessages.isNotEmpty) { _cursor = validMessages.last.msgId; diff --git a/lib/im/im_manager.dart b/lib/im/im_manager.dart index 84d4d77..d5715dc 100644 --- a/lib/im/im_manager.dart +++ b/lib/im/im_manager.dart @@ -9,7 +9,7 @@ class IMManager { final storage = GetStorage(); // 静态getter用于instance访问 static IMManager get instance => _instance; - + bool _isInitialized = false; IMManager._internal() { @@ -48,22 +48,24 @@ class IMManager { try { // 消息监听器 - // 连接监听器 - EMClient.getInstance.addConnectionEventHandler('', EMConnectionEventHandler( - onConnected: () { - print('Connected to IM server'); - }, - onDisconnected: () { - print('Disconnected from IM server:'); - }, - onTokenDidExpire: () { - print('IM token about to expire'); - }, - onUserKickedByOtherDevice: () { - print('User kicked out of IM server'); - }, - )); + EMClient.getInstance.addConnectionEventHandler( + '', + EMConnectionEventHandler( + onConnected: () { + print('Connected to IM server'); + }, + onDisconnected: () { + print('Disconnected from IM server:'); + }, + onTokenDidExpire: () { + print('IM token about to expire'); + }, + onUserKickedByOtherDevice: () { + print('User kicked out of IM server'); + }, + ), + ); EMClient.getInstance.chatManager.addEventHandler( // EMChatEventHandler 对应的 key。 "", @@ -72,44 +74,28 @@ class IMManager { for (var msg in messages) { switch (msg.body.type) { case MessageType.TXT: - { - - } + {} break; case MessageType.IMAGE: - { - - } + {} break; case MessageType.VIDEO: - { - - } + {} break; case MessageType.LOCATION: - { - - } + {} break; case MessageType.VOICE: - { - - } + {} break; case MessageType.FILE: - { - - } + {} break; case MessageType.CUSTOM: - { - - } + {} break; case MessageType.COMBINE: - { - - } + {} break; case MessageType.CMD: { @@ -172,10 +158,8 @@ class IMManager { content: content, ); - // 发送消息 - await EMClient.getInstance.chatManager.sendMessage(message); print('Text message sent successfully'); - return message; + return await EMClient.getInstance.chatManager.sendMessage(message); } catch (e) { print('Failed to send text message: $e'); return null; @@ -212,7 +196,9 @@ class IMManager { /// 获取好有列表 Future> getContacts(String userId) async { - return await EMClient.getInstance.userInfoManager.fetchUserInfoById([userId]); + return await EMClient.getInstance.userInfoManager.fetchUserInfoById([ + userId, + ]); } /// 获取指定会话的消息记录 @@ -222,15 +208,20 @@ class IMManager { String? startMsgId, }) async { EMConversationType convType = EMConversationType.Chat; - EMCursorResult cursor = await EMClient.getInstance.chatManager.fetchHistoryMessagesByOption( - conversationId, convType, pageSize: pageSize - ); + EMCursorResult cursor = await EMClient.getInstance.chatManager + .fetchHistoryMessagesByOption( + conversationId, + convType, + pageSize: pageSize, + ); return cursor.data; } /// 获取用户信息 Future getUserInfo(String userId) async { - var data = await EMClient.getInstance.userInfoManager.fetchUserInfoById([userId]); + var data = await EMClient.getInstance.userInfoManager.fetchUserInfoById([ + userId, + ]); return data[userId]; } diff --git a/lib/pages/message/chat_page.dart b/lib/pages/message/chat_page.dart index 7c39780..d1c89a6 100644 --- a/lib/pages/message/chat_page.dart +++ b/lib/pages/message/chat_page.dart @@ -48,22 +48,24 @@ class ChatPage extends StatelessWidget { // 消息列表区域 Expanded( child: Container( - alignment: Alignment.topCenter, + color: Color(0xffF5F5F5), child: ListView.builder( - reverse: true, - itemCount: controller.messages.length, - itemBuilder: (context, index) { - final message = controller.messages[index]; - final isSentByMe = message.direction == MessageDirection.SEND; - // 获取上一条消息(如果存在) - final previousMessage = index > 0 ? controller.messages[index - 1] : null; - return MessageItem( - message: message, - isSentByMe: false, - previousMessage: previousMessage, - ); - }, - ), + reverse: true, + padding: EdgeInsets.all(16.w), + itemCount: controller.messages.length, + itemBuilder: (context, index) { + final message = controller.messages[index]; + final isSentByMe = message.direction == MessageDirection.SEND; + // 获取上一条消息(如果存在) + final previousMessage = index > 0 ? controller.messages[index - 1] : null; + + return MessageItem( + message: message, + isSentByMe: isSentByMe, + previousMessage: previousMessage, + ); + }, + ), ), ), // 使用抽离的聊天输入栏组件 diff --git a/lib/widget/message/message_item.dart b/lib/widget/message/message_item.dart index 309ca23..30db38a 100644 --- a/lib/widget/message/message_item.dart +++ b/lib/widget/message/message_item.dart @@ -49,7 +49,7 @@ class MessageItem extends StatelessWidget { topLeft: isSentByMe ? Radius.circular(12.w) : Radius.circular(0), topRight: isSentByMe ? Radius.circular(0) : Radius.circular(12.w), bottomLeft: Radius.circular(12.w), - bottomRight: Radius.circular(0), + bottomRight: Radius.circular(12.w), ), ), child: Text( diff --git a/lib/widget/message/text_item.dart b/lib/widget/message/text_item.dart new file mode 100644 index 0000000..ef8a70a --- /dev/null +++ b/lib/widget/message/text_item.dart @@ -0,0 +1,107 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:im_flutter_sdk/im_flutter_sdk.dart'; + +import '../../../generated/assets.dart'; + +class TextItem extends StatelessWidget { + final EMTextMessageBody textBody; + final bool isSentByMe; + final bool showTime; + final String formattedTime; + + const TextItem({ + required this.textBody, + required this.isSentByMe, + required this.showTime, + required this.formattedTime, + super.key, + }); + + @override + Widget build(BuildContext context) { + 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), + Container( + constraints: BoxConstraints(maxWidth: 240.w), + margin: EdgeInsets.only(top: 10.h), + padding: EdgeInsets.symmetric( + horizontal: 12.w, + vertical: 8.h, + ), + decoration: BoxDecoration( + color: isSentByMe ? Color(0xff8E7BF6) : Colors.white, // 发送方紫色,接收方白色 + borderRadius: BorderRadius.only( + topLeft: isSentByMe ? Radius.circular(12.w) : Radius.circular(0), + topRight: isSentByMe ? Radius.circular(0) : Radius.circular(12.w), + bottomLeft: Radius.circular(12.w), + bottomRight: Radius.circular(12.w), + ), + ), + child: Text( + textBody.content, + style: TextStyle( + fontSize: 14.sp, + color: isSentByMe ? Colors.white : Colors.black, // 发送方白色文字,接收方黑色文字 + ), + ), + ), + 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() { + return Container( + width: 40.w, + height: 40.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20.w), + image: DecorationImage( + image: AssetImage(Assets.imagesAvatarsExample), + fit: BoxFit.cover, + ), + ), + ); + } +} \ No newline at end of file