Получение и отправка текста, статусы сообщения
This commit is contained in:
@@ -7,8 +7,14 @@ class SignalRService {
|
||||
final SharedPreferences prefs;
|
||||
HubConnection? _hubConnection;
|
||||
final _messageController = StreamController<Message>.broadcast();
|
||||
final _typingController = StreamController<Map<String, dynamic>>.broadcast();
|
||||
final _statusController = StreamController<Map<String, dynamic>>.broadcast();
|
||||
final _readReceiptController = StreamController<Map<String, dynamic>>.broadcast();
|
||||
|
||||
Stream<Message> get messages => _messageController.stream;
|
||||
Stream<Map<String, dynamic>> get typingUpdates => _typingController.stream;
|
||||
Stream<Map<String, dynamic>> get statusUpdates => _statusController.stream;
|
||||
Stream<Map<String, dynamic>> get readReceipts => _readReceiptController.stream;
|
||||
|
||||
SignalRService(this.prefs);
|
||||
|
||||
@@ -54,13 +60,46 @@ class SignalRService {
|
||||
print('[SignalR] Reconnected! ID: $connectionId');
|
||||
});
|
||||
|
||||
// Handle multiple possible event names to be safe
|
||||
_hubConnection?.on('ReceiveMessage', _handleReceiveMessage);
|
||||
_hubConnection?.on('receiveMessage', _handleReceiveMessage);
|
||||
_hubConnection?.on('UserTyping', _handleUserTyping);
|
||||
// Event names verified from backend source code (MessageNotifier.cs)
|
||||
_hubConnection?.on('new_message', _handleReceiveMessage);
|
||||
_hubConnection?.on('new_message_received', _handleReceiveMessage); // Optional fallback
|
||||
|
||||
_hubConnection?.on('user_typing', _handleUserTyping);
|
||||
_hubConnection?.on('UserStoppedTyping', _handleUserStoppedTyping);
|
||||
_hubConnection?.on('user_stopped_typing', _handleUserStoppedTyping);
|
||||
_hubConnection?.on('user_online', (args) {
|
||||
// ignore: avoid_print
|
||||
print('[SignalR] user_online: $args');
|
||||
if (args != null && args.isNotEmpty) {
|
||||
final data = args[0] as Map<String, dynamic>;
|
||||
_statusController.add({'userId': data['userId'] ?? data['UserId'], 'isOnline': true});
|
||||
}
|
||||
});
|
||||
_hubConnection?.on('user_offline', (args) {
|
||||
// ignore: avoid_print
|
||||
print('[SignalR] user_offline: $args');
|
||||
if (args != null && args.isNotEmpty) {
|
||||
final data = args[0] as Map<String, dynamic>;
|
||||
_statusController.add({
|
||||
'userId': data['userId'] ?? data['UserId'],
|
||||
'isOnline': false,
|
||||
'lastSeen': data['lastSeen'] ?? data['LastSeen']
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
_hubConnection?.on('messages_read', (args) {
|
||||
// ignore: avoid_print
|
||||
print('[SignalR] messages_read: $args');
|
||||
if (args != null && args.isNotEmpty) {
|
||||
final data = args[0] as Map<String, dynamic>;
|
||||
_readReceiptController.add({
|
||||
'chatId': data['chatId'] ?? data['ChatId'],
|
||||
'userId': data['userId'] ?? data['UserId'],
|
||||
'lastReadMessageId': data['lastReadMessageId'] ?? data['LastReadMessageId'],
|
||||
'lastReadSequenceId': data['lastReadSequenceId'] ?? data['LastReadSequenceId'],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
// ignore: avoid_print
|
||||
@@ -74,8 +113,17 @@ class SignalRService {
|
||||
}
|
||||
}
|
||||
|
||||
final _typingController = StreamController<Map<String, dynamic>>.broadcast();
|
||||
Stream<Map<String, dynamic>> get typingUpdates => _typingController.stream;
|
||||
Future<void> markMessagesAsRead(String chatId, String lastReadMessageId, int lastReadSequenceId) async {
|
||||
// ignore: avoid_print
|
||||
print('[SignalR] markMessagesAsRead: chatId=$chatId, msgId=$lastReadMessageId, seqId=$lastReadSequenceId');
|
||||
await _hubConnection?.invoke('read_messages', args: [
|
||||
{
|
||||
'ChatId': chatId,
|
||||
'LastReadMessageId': lastReadMessageId,
|
||||
'LastReadSequenceId': lastReadSequenceId,
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
void _handleUserTyping(List<dynamic>? arguments) {
|
||||
// ignore: avoid_print
|
||||
@@ -109,15 +157,18 @@ class SignalRService {
|
||||
if (arguments != null && arguments.isNotEmpty) {
|
||||
final data = arguments[0] as Map<String, dynamic>;
|
||||
final message = Message(
|
||||
id: data['id'] ?? '',
|
||||
chatId: data['chatId'] ?? '',
|
||||
senderId: data['userId'] ?? (data['senderId'] ?? ''),
|
||||
content: data['content'] ?? '',
|
||||
messageType: data['type']?.toString().toLowerCase() ?? 'text',
|
||||
createdAt: _parseDateTime(data['createdAt']),
|
||||
updatedAt: _parseDateTime(data['updatedAt']),
|
||||
isRead: data['isRead'] ?? false,
|
||||
media: data['media'] is Map<String, dynamic> ? data['media'] as Map<String, dynamic> : null,
|
||||
id: (data['id'] ?? data['Id'] ?? '').toString(),
|
||||
chatId: (data['chatId'] ?? data['ChatId'] ?? '').toString(),
|
||||
senderId: (data['senderId'] ?? data['SenderId'] ?? data['userId'] ?? data['UserId'] ?? '').toString(),
|
||||
content: data['content'] ?? data['Content'] ?? '',
|
||||
messageType: (data['type'] ?? data['Type'] ?? 'text').toString().toLowerCase(),
|
||||
sequenceId: int.tryParse((data['sequenceId'] ?? data['SequenceId'] ?? '0').toString()) ?? 0,
|
||||
createdAt: _parseDateTime(data['createdAt'] ?? data['CreatedAt']),
|
||||
updatedAt: _parseDateTime(data['updatedAt'] ?? data['UpdatedAt']),
|
||||
status: (data['isRead'] ?? data['IsRead'] ?? false) ? MessageStatus.read : MessageStatus.delivered,
|
||||
media: (data['media'] ?? data['Media']) is Map<String, dynamic>
|
||||
? (data['media'] ?? data['Media']) as Map<String, dynamic>
|
||||
: null,
|
||||
);
|
||||
_messageController.add(message);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user