Browse Source

feat(chat): 实现消息列表展示与发送功能

- 添加消息列表状态管理
- 实现消息发送并更新列表
- 支持分页加载历史消息
- 构建文本消息展示UI
- 添加消息方向判断逻辑
- 实现加载更多消息功能
ios
Jolie 4 months ago
parent
commit
fb2ee6fd13
2 changed files with 133 additions and 4 deletions
  1. 58
      lib/controller/message/chat_controller.dart
  2. 79
      lib/pages/message/chat_page.dart

58
lib/controller/message/chat_controller.dart

@ -8,14 +8,21 @@ class ChatController extends GetxController {
// //
final Rx<EMUserInfo?> userInfo = Rx<EMUserInfo?>(null); final Rx<EMUserInfo?> userInfo = Rx<EMUserInfo?>(null);
//
final RxList<EMMessage> messages = RxList<EMMessage>([]);
//
String? _cursor;
ChatController({required this.userId}); ChatController({required this.userId});
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
//
//
fetchUserInfo(); fetchUserInfo();
fetchMessages();
} }
/// ///
@ -43,7 +50,12 @@ class ChatController extends GetxController {
Future<bool> sendMessage(String content) async { Future<bool> sendMessage(String content) async {
try { try {
final message = await IMManager.instance.sendTextMessage(content, userId); final message = await IMManager.instance.sendTextMessage(content, userId);
return message != null;
if (message != null) {
//
messages.insert(0, message);
return true;
}
return false;
} catch (e) { } catch (e) {
if (Get.isLogEnable) { if (Get.isLogEnable) {
Get.log('发送消息失败: $e'); Get.log('发送消息失败: $e');
@ -51,4 +63,46 @@ class ChatController extends GetxController {
return false; return false;
} }
} }
///
Future<void> fetchMessages({bool loadMore = false}) async {
try {
final List<EMMessage?> fetchedMessages = await IMManager.instance.getMessages(
userId,
pageSize: 20,
startMsgId: loadMore ? _cursor : null,
);
// null消息
final List<EMMessage> validMessages = fetchedMessages.whereType<EMMessage>().toList();
if (loadMore) {
//
messages.addAll(validMessages);
} else {
//
messages.assignAll(validMessages);
}
//
if (validMessages.isNotEmpty) {
_cursor = validMessages.last.msgId;
}
if (Get.isLogEnable) {
Get.log('获取消息成功,数量: ${validMessages.length}');
}
} catch (e) {
if (Get.isLogEnable) {
Get.log('获取消息失败: $e');
}
}
}
///
Future<void> loadMoreMessages() async {
if (_cursor != null) {
await fetchMessages(loadMore: true);
}
}
} }

79
lib/pages/message/chat_page.dart

@ -2,6 +2,7 @@ import 'package:dating_touchme_app/extension/ex_widget.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:im_flutter_sdk/im_flutter_sdk.dart';
import '../../controller/message/chat_controller.dart'; import '../../controller/message/chat_controller.dart';
import '../../generated/assets.dart'; import '../../generated/assets.dart';
@ -12,6 +13,77 @@ class ChatPage extends StatelessWidget {
const ChatPage({required this.userId, super.key}); const ChatPage({required this.userId, super.key});
//
Widget _buildMessageItem(EMMessage message, bool isSentByMe) {
//
if (message.body.type == MessageType.TXT) {
final textBody = message.body as EMTextMessageBody;
return 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),
padding: EdgeInsets.symmetric(
horizontal: 12.w,
vertical: 8.h,
),
decoration: BoxDecoration(
color: isSentByMe ? Color(0xff98E165) : Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12.w),
topRight: Radius.circular(12.w),
bottomLeft: isSentByMe ? Radius.circular(12.w) : Radius.circular(0),
bottomRight: isSentByMe ? Radius.circular(0) : Radius.circular(12.w),
),
),
child: Text(
textBody.content,
style: TextStyle(
fontSize: 14.sp,
color: isSentByMe ? Colors.black : Colors.black,
),
),
),
if (isSentByMe) SizedBox(width: 8.w),
if (isSentByMe) _buildAvatar(),
],
),
);
}
//
return Container(
padding: EdgeInsets.symmetric(
horizontal: 16.w,
vertical: 8.h,
),
child: Text('不支持的消息类型'),
);
}
//
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,
),
),
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GetBuilder<ChatController>( return GetBuilder<ChatController>(
@ -47,9 +119,12 @@ class ChatPage extends StatelessWidget {
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: ListView.builder( child: ListView.builder(
reverse: true, reverse: true,
itemCount: 10,
itemCount: controller.messages.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return Container();
final message = controller.messages[index];
print('message: $message');
final isSentByMe = message.direction == MessageDirection.SEND;
return _buildMessageItem(message, isSentByMe);
}, },
), ),
), ),

Loading…
Cancel
Save