import 'package:elysia/page/ChatRoomPage.dart'; import 'package:elysia/plugin/Notify.dart'; import 'package:flutter/material.dart'; import 'package:flutter_chat_list_builder/flutter_chat_list_builder.dart'; import '../../plugin/C.dart'; import '../../plugin/CacheAavatar.dart'; import '../../plugin/ChatInput.dart'; import '../../plugin/HTTP.dart'; import '../../plugin/MarkdownSelectableText.dart'; import '../../plugin/UID.dart'; class Message { final String messageId; final String msg; final bool isMeSend; bool isSending; // 新增字段:是否正在发送 Message(this.messageId, this.msg, this.isMeSend, {this.isSending = false}); } class ChatPage extends StatefulWidget { final String roomId; final String robotAvatar; final String robotName; const ChatPage({ Key? key, required this.roomId, required this.robotAvatar, required this.robotName, }) : super(key: key); @override _ChatPageState createState() => _ChatPageState(); } class _ChatPageState extends State { late ChatListController controller; int size = 50; int current = 0; @override void initState() { super.initState(); controller = ChatListController(); C.socket.addMessageListener(onMessage); } @override void dispose() { try { controller.dispose(); } catch (e) {} C.socket.removeMessageListener(onMessage); C.PUSH_STATUS = true; super.dispose(); } void onMessage(dynamic message) { if (message["roomId"] == widget.roomId) { controller.addNewMessage(Message(message["messageId"],message["content"], false)); ChatRoomPage.flushData!({ "roomId": message["roomId"], "message": message["content"], }); } else { Notify.showNotification( channel: NotifyChannel.message, title: message["name"], body: message["content"], smallIcon: message["avatar"], payload: { "type": C.NOTIFY_MESSAGE, "roomId": message["roomId"], "avatar": message["avatar"], "name": message["name"], }, ); ChatRoomPage.flushData!({ "roomId": message["roomId"], "message": message["content"], }); } } @override Widget build(BuildContext context) { final theme = Theme.of(context); final activeColor = theme.colorScheme.primary; return Scaffold( appBar: AppBar( title: Text( widget.robotName, style: const TextStyle(color: Colors.black), ), centerTitle: true, backgroundColor: Colors.grey[100], leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.black), onPressed: () => Navigator.pop(context), ), elevation: 0, ), body: Column( children: [ Expanded( child: Padding( padding: EdgeInsets.symmetric(horizontal: 10), child: ChatListBuilder( controller: controller, loadHistory: () async { current++; dynamic result = await HTTP .create('${C.BASE_URL}/chat/history/${widget.roomId}') .setHeader(C.TOKEN) .setParam({"size": size, "current": current}) .setRequestType(RequestType.GET) .execute(); if (result['code'] != 200) { return LoadHistoryResponse(isHasMore: false, data: []); } List data = result['data']['result']; int rows = result['data']['rows']; print("加载历史第 $current 页"); return LoadHistoryResponse( isHasMore: current < rows, data: List.generate( data.length, (index) => Message( data[index]['messageId'], data[index]['message'] ?? "", data[index]['from'] == 1, ), ), ); }, loadingBackgroundColor: Colors.white, itemBuilder: (_, element) { if (element.isMeSend) { return Row( textDirection: TextDirection.rtl, crossAxisAlignment: CrossAxisAlignment.center, children: [ CacheAvatar( url: C.PROFILE["avatar"], size: Size(40, 40), ), Container( margin: const EdgeInsets.all(10), padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 2, ), constraints: BoxConstraints( maxWidth: MediaQuery.of(context).size.width * 0.7, ), decoration: BoxDecoration( color: activeColor, borderRadius: BorderRadius.circular(15), ), child: MarkdownSelectableText( element.msg, style: TextStyle(fontSize: 16), ), ), if (element.isSending) const Padding( padding: EdgeInsets.only(right: 8.0), child: SizedBox( width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2), ), ), ], ); } else { return Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ CacheAvatar( url: widget.robotAvatar, size: Size(40, 40), ), Container( margin: const EdgeInsets.all(10), padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 2, ), constraints: BoxConstraints( maxWidth: MediaQuery.of(context).size.width * 0.7, ), decoration: BoxDecoration( color: Colors.grey[200], borderRadius: BorderRadius.circular(15), ), child: MarkdownSelectableText( element.msg, style: TextStyle(fontSize: 16), ), ), ], ); } }, ), ), ), ChatInput( onSend: (str) async { String uid =UID.getShort(); // 先添加一个正在发送的消息 final message = Message(uid, str, true, isSending: true); ChatRoomPage.flushData!({ "roomId": widget.roomId, "message": str, }); controller.addNewMessage(message); Future.delayed(const Duration(milliseconds: 300), () { controller.scrollController.animateTo( controller.scrollController.position.maxScrollExtent, duration: const Duration(milliseconds: 300), curve: Curves.easeOut, ); }); // 发送消息 await HTTP .create("${C.BASE_URL}/chat/send/${widget.roomId}") .setHeader(C.TOKEN) .setParam({"message": str,"messageId":uid}) .setRequestType(RequestType.POST) .execute(); // 请求完成后,取消 loading setState(() { message.isSending = false; }); }, ), const SizedBox(height: 10), ], ), ); } }