Anonymous
Как мгновенно отобразить полученные сообщения в виджете Flutter ChatBox с помощью Socket.IO
Сообщение
Anonymous » 26 июн 2024, 08:18
Я создаю приложение для чата, используя Flutter и Socket.IO. У меня есть виджет ChatBox, где пользователи могут отправлять и получать сообщения. Однако я столкнулся с проблемой, когда полученные сообщения не отображаются сразу. Кроме того, сообщения отображаются неправильно.
Вот моя текущая реализация:
< div class="snippet-code">
Код: Выделить всё
class ChatBox extends StatefulWidget {
const ChatBox({super.key, required this.liveID, required this.username});
final int liveID;
final String username;
@override
State createState() => _ChatBoxState();
}
class _ChatBoxState extends State {
final TextEditingController _messageController = TextEditingController();
bool _showEmojiPicker = false;
late IO.Socket socket;
int? currentUserID;
String? currentUsername;
List _messages = [];
final StreamController _streamController = StreamController();
Stream get messagesStream => _streamController.stream;
void _onEmojiSelected(Emoji emoji) {
_messageController
..text += emoji.emoji
..selection = TextSelection.fromPosition(
TextPosition(offset: _messageController.text.length),
);
}
void _onBackspacePressed() {
_messageController
..text = _messageController.text.characters.skipLast(1).toString()
..selection = TextSelection.fromPosition(
TextPosition(offset: _messageController.text.length),
);
}
@override
void initState() {
super.initState();
_loadCurrentUserID();
_initializeSocket();
}
@override
void dispose() {
_messageController.dispose();
_streamController.close();
socket.disconnect();
super.dispose();
}
Future _loadCurrentUserID() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
currentUserID = prefs.getInt('loginUserId');
currentUsername = prefs.getString('username'); // Assuming you have stored the username
});
}
void _initializeSocket() {
socket = IO.io('https://socket.example.com', {
'transports': ['websocket'],
'autoConnect': false,
});
socket.connect();
socket.onConnect((_) {
debugPrint('connected to websocket');
});
socket.onDisconnect((_) {
debugPrint('disconnected from websocket');
});
socket.on('chat_list_message', (data) {
debugPrint('Received message: $data');
_streamController.add(data);
// setState(() {
// if (data is Map && data['message'] is List && data['message'].isNotEmpty) {
// for (var messageObj in data['message']) {
// if (messageObj is Map && messageObj.containsKey('message')) {
// String messageContent = messageObj['message'];
// _messages.add(ChatMessage(
// userID: messageObj['userID'],
// liveID: messageObj['liveID'],
// message: messageContent,
// username: messageObj['username'],
// ));
// debugPrint('Received Message: $messageContent');
// } else {
// debugPrint('Unexpected message object: $messageObj');
// }
// }
// }
// });
});
socket.onError((error) {
debugPrint('Socket error: $error');
});
}
void _sendMessage() {
String message = _messageController.text.trim();
if (message.isNotEmpty) {
final newMessage = {
'userID': currentUserID,
'liveID': widget.liveID,
'message': message,
'username': currentUsername ?? 'Unknown',
'time': DateTime.now().toIso8601String(),
};
setState(() {
_messages.add(ChatMessage.fromJson(newMessage));
});
socket.emit('add_chat_message', newMessage);
_messageController.clear();
}
}
@override
Widget build(BuildContext context) {
return BlocListener(
listener: (context, state) {
if (state is ChatDataLiveSuccess) {
setState(() {
_messages = state.allChatDataLives ?? [];
});
} else if (state is ChatDataLiveFail) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(state.message)),
);
}
},
child: SizedBox(
height: 150,
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Expanded(
child: Divider(
color: Theme.of(context).primaryColor,
height: 1,
thickness: 1.5,
),
),
const SizedBox(width: 8.0),
Text(
'New Message',
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.bodySmall,
maxLines: 1,
),
const SizedBox(width: 8.0),
Expanded(
child: Divider(
color: Theme.of(context).primaryColor,
height: 1,
thickness: 1.5,
),
),
],
),
),
Expanded(
child: ListView.builder(
itemCount: _messages.length,
itemBuilder: (context, index) {
final message = _messages[index];
return Row(
children: [
const SizedBox(width: 20),
Text(
'${widget.username} : ',
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.bodyMedium,
maxLines: 1,
),
const SizedBox(width: 10),
Text(
message.message ?? '',
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.bodySmall,
maxLines: 1,
),
],
);
},
),
),
Container(
margin: const EdgeInsets.only(left: 12.0, top: 12),
child: Row(
children: [
Expanded(
child: TextField(
controller: _messageController,
decoration: const InputDecoration(
hintText: 'Type your message...',
border: OutlineInputBorder(),
),
),
),
const SizedBox(width: 8.0),
IconButton(
icon: const Icon(Icons.emoji_emotions),
onPressed: () {
setState(() {
_showEmojiPicker = !_showEmojiPicker;
});
},
),
IconButton(
icon: const Icon(Icons.send),
onPressed: () {
_sendMessage();
},
),
],
),
),
Offstage(
offstage: !_showEmojiPicker,
child: SizedBox(
height: 250,
child: EmojiPicker(
onEmojiSelected: (category, emoji) {
_onEmojiSelected(emoji);
},
onBackspacePressed: _onBackspacePressed,
config: const Config(
height: 200,
checkPlatformCompatibility: true,
emojiViewConfig: EmojiViewConfig(
emojiSizeMax: 32,
),
swapCategoryAndBottomBar: false,
),
),
),
),
],
),
),
);
}
}
Внесенные изменения:
Правильно Анализ данных: при получении событияchat_list_message я проанализировал каждое сообщение в списке и добавил его в _messages.
Немедленное обновление пользовательского интерфейса: использовал setState, чтобы гарантировать немедленное обновление пользовательского интерфейса при получении новых сообщений. .
Правильное отображение: отрегулировано отображение сообщений, чтобы они правильно отображались в дереве виджетов.
Если у вас возникнут какие-либо дополнительные проблемы или вам понадобится подробнее, спрашивайте!
Подробнее здесь:
https://stackoverflow.com/questions/786 ... -with-sock
1719379105
Anonymous
Я создаю приложение для чата, используя Flutter и Socket.IO. У меня есть виджет ChatBox, где пользователи могут отправлять и получать сообщения. Однако я столкнулся с проблемой, когда полученные сообщения не отображаются сразу. Кроме того, сообщения отображаются неправильно. Вот моя текущая реализация: < div class="snippet-code"> [code]class ChatBox extends StatefulWidget { const ChatBox({super.key, required this.liveID, required this.username}); final int liveID; final String username; @override State createState() => _ChatBoxState(); } class _ChatBoxState extends State { final TextEditingController _messageController = TextEditingController(); bool _showEmojiPicker = false; late IO.Socket socket; int? currentUserID; String? currentUsername; List _messages = []; final StreamController _streamController = StreamController(); Stream get messagesStream => _streamController.stream; void _onEmojiSelected(Emoji emoji) { _messageController ..text += emoji.emoji ..selection = TextSelection.fromPosition( TextPosition(offset: _messageController.text.length), ); } void _onBackspacePressed() { _messageController ..text = _messageController.text.characters.skipLast(1).toString() ..selection = TextSelection.fromPosition( TextPosition(offset: _messageController.text.length), ); } @override void initState() { super.initState(); _loadCurrentUserID(); _initializeSocket(); } @override void dispose() { _messageController.dispose(); _streamController.close(); socket.disconnect(); super.dispose(); } Future _loadCurrentUserID() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); setState(() { currentUserID = prefs.getInt('loginUserId'); currentUsername = prefs.getString('username'); // Assuming you have stored the username }); } void _initializeSocket() { socket = IO.io('https://socket.example.com', { 'transports': ['websocket'], 'autoConnect': false, }); socket.connect(); socket.onConnect((_) { debugPrint('connected to websocket'); }); socket.onDisconnect((_) { debugPrint('disconnected from websocket'); }); socket.on('chat_list_message', (data) { debugPrint('Received message: $data'); _streamController.add(data); // setState(() { // if (data is Map && data['message'] is List && data['message'].isNotEmpty) { // for (var messageObj in data['message']) { // if (messageObj is Map && messageObj.containsKey('message')) { // String messageContent = messageObj['message']; // _messages.add(ChatMessage( // userID: messageObj['userID'], // liveID: messageObj['liveID'], // message: messageContent, // username: messageObj['username'], // )); // debugPrint('Received Message: $messageContent'); // } else { // debugPrint('Unexpected message object: $messageObj'); // } // } // } // }); }); socket.onError((error) { debugPrint('Socket error: $error'); }); } void _sendMessage() { String message = _messageController.text.trim(); if (message.isNotEmpty) { final newMessage = { 'userID': currentUserID, 'liveID': widget.liveID, 'message': message, 'username': currentUsername ?? 'Unknown', 'time': DateTime.now().toIso8601String(), }; setState(() { _messages.add(ChatMessage.fromJson(newMessage)); }); socket.emit('add_chat_message', newMessage); _messageController.clear(); } } @override Widget build(BuildContext context) { return BlocListener( listener: (context, state) { if (state is ChatDataLiveSuccess) { setState(() { _messages = state.allChatDataLives ?? []; }); } else if (state is ChatDataLiveFail) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(state.message)), ); } }, child: SizedBox( height: 150, child: Column( children: [ Padding( padding: const EdgeInsets.all(8.0), child: Row( children: [ Expanded( child: Divider( color: Theme.of(context).primaryColor, height: 1, thickness: 1.5, ), ), const SizedBox(width: 8.0), Text( 'New Message', overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.bodySmall, maxLines: 1, ), const SizedBox(width: 8.0), Expanded( child: Divider( color: Theme.of(context).primaryColor, height: 1, thickness: 1.5, ), ), ], ), ), Expanded( child: ListView.builder( itemCount: _messages.length, itemBuilder: (context, index) { final message = _messages[index]; return Row( children: [ const SizedBox(width: 20), Text( '${widget.username} : ', overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.bodyMedium, maxLines: 1, ), const SizedBox(width: 10), Text( message.message ?? '', overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.bodySmall, maxLines: 1, ), ], ); }, ), ), Container( margin: const EdgeInsets.only(left: 12.0, top: 12), child: Row( children: [ Expanded( child: TextField( controller: _messageController, decoration: const InputDecoration( hintText: 'Type your message...', border: OutlineInputBorder(), ), ), ), const SizedBox(width: 8.0), IconButton( icon: const Icon(Icons.emoji_emotions), onPressed: () { setState(() { _showEmojiPicker = !_showEmojiPicker; }); }, ), IconButton( icon: const Icon(Icons.send), onPressed: () { _sendMessage(); }, ), ], ), ), Offstage( offstage: !_showEmojiPicker, child: SizedBox( height: 250, child: EmojiPicker( onEmojiSelected: (category, emoji) { _onEmojiSelected(emoji); }, onBackspacePressed: _onBackspacePressed, config: const Config( height: 200, checkPlatformCompatibility: true, emojiViewConfig: EmojiViewConfig( emojiSizeMax: 32, ), swapCategoryAndBottomBar: false, ), ), ), ), ], ), ), ); } }[/code] Внесенные изменения: Правильно Анализ данных: при получении событияchat_list_message я проанализировал каждое сообщение в списке и добавил его в _messages. Немедленное обновление пользовательского интерфейса: использовал setState, чтобы гарантировать немедленное обновление пользовательского интерфейса при получении новых сообщений. . Правильное отображение: отрегулировано отображение сообщений, чтобы они правильно отображались в дереве виджетов. Если у вас возникнут какие-либо дополнительные проблемы или вам понадобится подробнее, спрашивайте! Подробнее здесь: [url]https://stackoverflow.com/questions/78670437/how-to-display-received-messages-immediately-in-flutter-chatbox-widget-with-sock[/url]