diff --git a/client-mobile/lib/core/network/signalr_service.dart b/client-mobile/lib/core/network/signalr_service.dart index 3a7b7f1..4f788ad 100644 --- a/client-mobile/lib/core/network/signalr_service.dart +++ b/client-mobile/lib/core/network/signalr_service.dart @@ -13,6 +13,13 @@ class SignalRService { SignalRService(this.prefs); Future init() async { + if (_hubConnection?.state == HubConnectionState.Connected || + _hubConnection?.state == HubConnectionState.Connecting) { + // ignore: avoid_print + print('[SignalR] Connection already active or connecting. Skipping init.'); + return; + } + if (_hubConnection != null) { await stop(); } @@ -22,27 +29,48 @@ class SignalRService { if (token == null) return; final hubUrl = '${apiUrl.replaceAll(RegExp(r'/+$'), '')}/hubs/chat'; + // ignore: avoid_print + print('[SignalR] Initializing connection to: $hubUrl'); _hubConnection = HubConnectionBuilder() .withUrl(hubUrl, options: HttpConnectionOptions( accessTokenFactory: () async => token, - // logging: (level, message) => print('[SignalR] $level: $message'), )) .withAutomaticReconnect() .build(); _hubConnection?.onclose(({error}) { - // print('[SignalR] Connection closed: $error'); + // ignore: avoid_print + print('[SignalR] Connection closed. Error: $error'); }); + _hubConnection?.onreconnecting(({error}) { + // ignore: avoid_print + print('[SignalR] Reconnecting... Error: $error'); + }); + + _hubConnection?.onreconnected(({connectionId}) { + // ignore: avoid_print + 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); _hubConnection?.on('user_typing', _handleUserTyping); + _hubConnection?.on('UserStoppedTyping', _handleUserStoppedTyping); _hubConnection?.on('user_stopped_typing', _handleUserStoppedTyping); try { + // ignore: avoid_print + print('[SignalR] Starting connection...'); await _hubConnection?.start(); + // ignore: avoid_print + print('[SignalR] Connection started successfully. State: ${_hubConnection?.state}'); } catch (e) { - // ignore + // ignore: avoid_print + print('[SignalR] Connection failed: $e'); } } @@ -50,6 +78,8 @@ class SignalRService { Stream> get typingUpdates => _typingController.stream; void _handleUserTyping(List? arguments) { + // ignore: avoid_print + print('[SignalR] _handleUserTyping: $arguments'); if (arguments != null && arguments.isNotEmpty) { final data = arguments[0] as Map; _typingController.add({'chatId': data['ChatId'] ?? data['chatId'], 'userId': data['UserId'] ?? data['userId'], 'isTyping': true}); @@ -57,6 +87,8 @@ class SignalRService { } void _handleUserStoppedTyping(List? arguments) { + // ignore: avoid_print + print('[SignalR] _handleUserStoppedTyping: $arguments'); if (arguments != null && arguments.isNotEmpty) { final data = arguments[0] as Map; _typingController.add({'chatId': data['ChatId'] ?? data['chatId'], 'userId': data['UserId'] ?? data['userId'], 'isTyping': false}); @@ -72,13 +104,34 @@ class SignalRService { } void _handleReceiveMessage(List? arguments) { + // ignore: avoid_print + print('[SignalR] _handleReceiveMessage: $arguments'); if (arguments != null && arguments.isNotEmpty) { final data = arguments[0] as Map; - // Map JSON to Message entity and add to stream - // I'll need a Message.fromJson mapper + 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 ? data['media'] as Map : null, + ); + _messageController.add(message); } } + DateTime? _parseDateTime(String? dateStr) { + if (dateStr == null) return null; + String normalized = dateStr; + if (!normalized.endsWith('Z') && !normalized.contains('+')) { + normalized += 'Z'; + } + return DateTime.parse(normalized).toLocal(); + } + Future stop() async { await _hubConnection?.stop(); _hubConnection = null; diff --git a/client-mobile/lib/features/chat/data/repositories/chat_repository_impl.dart b/client-mobile/lib/features/chat/data/repositories/chat_repository_impl.dart index 99bd5ca..cd25abe 100644 --- a/client-mobile/lib/features/chat/data/repositories/chat_repository_impl.dart +++ b/client-mobile/lib/features/chat/data/repositories/chat_repository_impl.dart @@ -121,7 +121,7 @@ class ChatRepositoryImpl implements ChatRepository { return remote; } // ignore: avoid_print - print('[DEBUG] Remote getMessages failed: ${remote.failure?.message}'); + print('[DEBUG] Remote getMessages failed: ${remote.error?.message}'); return cached; } else { return remoteDataSource.getMessages(chatId, cursor: cursor); diff --git a/client-mobile/lib/features/chat/presentation/bloc/chat_bloc.dart b/client-mobile/lib/features/chat/presentation/bloc/chat_bloc.dart index 6cdb608..735967c 100644 --- a/client-mobile/lib/features/chat/presentation/bloc/chat_bloc.dart +++ b/client-mobile/lib/features/chat/presentation/bloc/chat_bloc.dart @@ -16,6 +16,7 @@ class ChatBloc extends Bloc { on(_onChatsLoaded); on(_onChatSelected); on(_onMessagesRequested); + on(_onMessageReceived); on(_onMessageSent); on(_onFavoritesRequested); on(_onTypingUpdated); @@ -23,7 +24,7 @@ class ChatBloc extends Bloc { on(_onCacheCleared); _messageSubscription = chatRepository.messageStream.listen((message) { - add(ChatEvent.messagesRequested(message.chatId)); + add(ChatEvent.messageReceived(message)); }); _typingSubscription = chatRepository.typingStream.listen((data) { @@ -40,7 +41,6 @@ class ChatBloc extends Bloc { }); // Immediately trigger chats loading add(ChatEvent.chatsLoaded(currentUserId: event.userId)); - add(const ChatEvent.favoritesRequested()); } Future _onChatsLoaded(ChatEventChatsLoaded event, Emitter emit) async { @@ -53,42 +53,114 @@ class ChatBloc extends Bloc { } Future _onChatSelected(ChatEventChatSelected event, Emitter emit) async { - emit(const ChatState.loading()); + final currentChatId = state.maybeMap( + chatSelected: (s) => s.chat.id, + messagesLoaded: (s) => s.chat.id, + orElse: () => null, + ); + + if (currentChatId == event.chatId) { + // Already in this chat, just refresh messages + final messagesResult = await chatRepository.getMessages(event.chatId); + messagesResult.fold( + (error) => null, + (messages) { + final currentChat = state.maybeMap( + chatSelected: (s) => s.chat, + messagesLoaded: (s) => s.chat, + orElse: () => null, + ); + if (currentChat != null) { + emit(ChatState.messagesLoaded(currentChat, messages, typingUsers: state.typingUsers)); + } + }, + ); + return; + } + + emit(ChatState.loading(typingUsers: state.typingUsers)); final chatResult = await chatRepository.getChatById(event.chatId); final messagesResult = await chatRepository.getMessages(event.chatId); chatResult.fold( - (error) => emit(ChatState.error(error.message ?? 'Failed to load chat')), + (error) => emit(ChatState.error(error.message ?? 'Failed to load chat', typingUsers: state.typingUsers)), (chat) { messagesResult.fold( - (error) => emit(ChatState.chatSelected(chat, [])), - (messages) => emit(ChatState.chatSelected(chat, messages)), + (error) => emit(ChatState.chatSelected(chat, [], typingUsers: state.typingUsers)), + (messages) => emit(ChatState.chatSelected(chat, messages, typingUsers: state.typingUsers)), ); }, ); } Future _onMessagesRequested(ChatEventMessagesRequested event, Emitter emit) async { + final currentChat = state.maybeMap( + chatSelected: (s) => s.chat, + messagesLoaded: (s) => s.chat, + orElse: () => null, + ); + + // Only fetch if it's the current chat or we are in chats list final result = await chatRepository.getMessages(event.chatId); result.fold( - (error) => emit(ChatState.error(error.message ?? 'Failed to load messages')), - (messages) => emit(ChatState.messagesLoaded(messages)), + (error) => null, // Don't emit error state for background updates to avoid UI flickering + (messages) { + if (currentChat != null && currentChat.id == event.chatId) { + // If we are in the chat, update messages and switch to messagesLoaded (stable state) + emit(ChatState.messagesLoaded(currentChat, messages, typingUsers: state.typingUsers)); + } + // If we are in the list, the list will update via local cache anyway or on next fetch + }, + ); + } + + Future _onMessageReceived(ChatEventMessageReceived event, Emitter emit) async { + final message = event.message; + final currentChat = state.maybeMap( + chatSelected: (s) => s.chat, + messagesLoaded: (s) => s.chat, + orElse: () => null, + ); + + if (currentChat != null && currentChat.id == message.chatId) { + final List currentMessages = state.maybeMap( + chatSelected: (s) => s.messages, + messagesLoaded: (s) => s.messages, + orElse: () => [], + ); + + // Check for duplicates + if (currentMessages.any((m) => m.id == message.id)) return; + + final updatedMessages = List.from(currentMessages)..insert(0, message); + // Ensure sorting if needed (usually messages are already in order from stream) + + emit(ChatState.messagesLoaded(currentChat, updatedMessages, typingUsers: state.typingUsers)); + } + + // Also trigger chats refresh if we are in chatsLoaded state to update last message/unread + state.maybeMap( + chatsLoaded: (_) => add(ChatEvent.chatsLoaded(currentUserId: currentChat?.participants?.firstWhere((p) => p.id != '').id)), // userId logic might need to be better + orElse: () => null, ); } Future _onMessageSent(ChatEventMessageSent event, Emitter emit) async { final result = await chatRepository.sendMessage(event.chatId, event.content); result.fold( - (error) => emit(ChatState.error(error.message ?? 'Failed to send message')), - (_) => add(ChatEvent.messagesRequested(event.chatId)), + (error) => emit(ChatState.error(error.message ?? 'Failed to send message', typingUsers: state.typingUsers)), + (_) { + // Optimistically or via refresh + add(ChatEvent.messagesRequested(event.chatId)); + }, ); } Future _onFavoritesRequested(ChatEventFavoritesRequested event, Emitter emit) async { - emit(const ChatState.loading()); + emit(ChatState.loading(typingUsers: state.typingUsers)); final result = await chatRepository.getOrCreateFavorites(); result.fold( - (error) => emit(ChatState.error(error.message ?? 'Failed to open Favorites')), + (error) => emit(ChatState.error(error.message ?? 'Failed to open Favorites', typingUsers: state.typingUsers)), (chat) => add(ChatEvent.chatSelected(chat.id)), ); } @@ -109,7 +181,19 @@ class ChatBloc extends Bloc { newTypingUsers[event.chatId] = chatTypingUsers; } - emit(state.copyWith(typingUsers: newTypingUsers)); + state.maybeMap( + chatSelected: (s) { + // If it's the current chat, transition to stable state + if (s.chat.id == event.chatId) { + emit(ChatState.messagesLoaded(s.chat, s.messages, typingUsers: newTypingUsers)); + } else { + emit(s.copyWith(typingUsers: newTypingUsers)); + } + }, + messagesLoaded: (s) => emit(s.copyWith(typingUsers: newTypingUsers)), + chatsLoaded: (s) => emit(s.copyWith(typingUsers: newTypingUsers)), + orElse: () => emit(state.copyWith(typingUsers: newTypingUsers)), + ); } Future _onSendTypingStatus(ChatEventSendTypingStatus event, Emitter emit) async { diff --git a/client-mobile/lib/features/chat/presentation/bloc/chat_event.dart b/client-mobile/lib/features/chat/presentation/bloc/chat_event.dart index 778f097..beab581 100644 --- a/client-mobile/lib/features/chat/presentation/bloc/chat_event.dart +++ b/client-mobile/lib/features/chat/presentation/bloc/chat_event.dart @@ -1,4 +1,5 @@ import 'package:freezed_annotation/freezed_annotation.dart'; +import '../../domain/entities/message.dart'; part 'chat_event.freezed.dart'; @@ -8,6 +9,7 @@ class ChatEvent with _$ChatEvent { const factory ChatEvent.chatsLoaded({String? currentUserId}) = ChatEventChatsLoaded; const factory ChatEvent.chatSelected(String chatId) = ChatEventChatSelected; const factory ChatEvent.messagesRequested(String chatId, {String? cursor}) = ChatEventMessagesRequested; + const factory ChatEvent.messageReceived(Message message) = ChatEventMessageReceived; const factory ChatEvent.messageSent(String chatId, String content) = ChatEventMessageSent; const factory ChatEvent.favoritesRequested() = ChatEventFavoritesRequested; const factory ChatEvent.typingUpdated(String chatId, String userId, bool isTyping) = ChatEventTypingUpdated; diff --git a/client-mobile/lib/features/chat/presentation/bloc/chat_event.freezed.dart b/client-mobile/lib/features/chat/presentation/bloc/chat_event.freezed.dart index e796178..6e61edf 100644 --- a/client-mobile/lib/features/chat/presentation/bloc/chat_event.freezed.dart +++ b/client-mobile/lib/features/chat/presentation/bloc/chat_event.freezed.dart @@ -22,6 +22,7 @@ mixin _$ChatEvent { required TResult Function(String? currentUserId) chatsLoaded, required TResult Function(String chatId) chatSelected, required TResult Function(String chatId, String? cursor) messagesRequested, + required TResult Function(Message message) messageReceived, required TResult Function(String chatId, String content) messageSent, required TResult Function() favoritesRequested, required TResult Function(String chatId, String userId, bool isTyping) @@ -36,6 +37,7 @@ mixin _$ChatEvent { TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, + TResult? Function(Message message)? messageReceived, TResult? Function(String chatId, String content)? messageSent, TResult? Function()? favoritesRequested, TResult? Function(String chatId, String userId, bool isTyping)? @@ -50,6 +52,7 @@ mixin _$ChatEvent { TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, + TResult Function(Message message)? messageReceived, TResult Function(String chatId, String content)? messageSent, TResult Function()? favoritesRequested, TResult Function(String chatId, String userId, bool isTyping)? @@ -66,6 +69,7 @@ mixin _$ChatEvent { required TResult Function(ChatEventChatSelected value) chatSelected, required TResult Function(ChatEventMessagesRequested value) messagesRequested, + required TResult Function(ChatEventMessageReceived value) messageReceived, required TResult Function(ChatEventMessageSent value) messageSent, required TResult Function(ChatEventFavoritesRequested value) favoritesRequested, @@ -80,6 +84,7 @@ mixin _$ChatEvent { TResult? Function(ChatEventChatsLoaded value)? chatsLoaded, TResult? Function(ChatEventChatSelected value)? chatSelected, TResult? Function(ChatEventMessagesRequested value)? messagesRequested, + TResult? Function(ChatEventMessageReceived value)? messageReceived, TResult? Function(ChatEventMessageSent value)? messageSent, TResult? Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult? Function(ChatEventTypingUpdated value)? typingUpdated, @@ -93,6 +98,7 @@ mixin _$ChatEvent { TResult Function(ChatEventChatsLoaded value)? chatsLoaded, TResult Function(ChatEventChatSelected value)? chatSelected, TResult Function(ChatEventMessagesRequested value)? messagesRequested, + TResult Function(ChatEventMessageReceived value)? messageReceived, TResult Function(ChatEventMessageSent value)? messageSent, TResult Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult Function(ChatEventTypingUpdated value)? typingUpdated, @@ -189,6 +195,7 @@ class _$ChatEventStartedImpl implements ChatEventStarted { required TResult Function(String? currentUserId) chatsLoaded, required TResult Function(String chatId) chatSelected, required TResult Function(String chatId, String? cursor) messagesRequested, + required TResult Function(Message message) messageReceived, required TResult Function(String chatId, String content) messageSent, required TResult Function() favoritesRequested, required TResult Function(String chatId, String userId, bool isTyping) @@ -206,6 +213,7 @@ class _$ChatEventStartedImpl implements ChatEventStarted { TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, + TResult? Function(Message message)? messageReceived, TResult? Function(String chatId, String content)? messageSent, TResult? Function()? favoritesRequested, TResult? Function(String chatId, String userId, bool isTyping)? @@ -223,6 +231,7 @@ class _$ChatEventStartedImpl implements ChatEventStarted { TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, + TResult Function(Message message)? messageReceived, TResult Function(String chatId, String content)? messageSent, TResult Function()? favoritesRequested, TResult Function(String chatId, String userId, bool isTyping)? @@ -245,6 +254,7 @@ class _$ChatEventStartedImpl implements ChatEventStarted { required TResult Function(ChatEventChatSelected value) chatSelected, required TResult Function(ChatEventMessagesRequested value) messagesRequested, + required TResult Function(ChatEventMessageReceived value) messageReceived, required TResult Function(ChatEventMessageSent value) messageSent, required TResult Function(ChatEventFavoritesRequested value) favoritesRequested, @@ -262,6 +272,7 @@ class _$ChatEventStartedImpl implements ChatEventStarted { TResult? Function(ChatEventChatsLoaded value)? chatsLoaded, TResult? Function(ChatEventChatSelected value)? chatSelected, TResult? Function(ChatEventMessagesRequested value)? messagesRequested, + TResult? Function(ChatEventMessageReceived value)? messageReceived, TResult? Function(ChatEventMessageSent value)? messageSent, TResult? Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult? Function(ChatEventTypingUpdated value)? typingUpdated, @@ -278,6 +289,7 @@ class _$ChatEventStartedImpl implements ChatEventStarted { TResult Function(ChatEventChatsLoaded value)? chatsLoaded, TResult Function(ChatEventChatSelected value)? chatSelected, TResult Function(ChatEventMessagesRequested value)? messagesRequested, + TResult Function(ChatEventMessageReceived value)? messageReceived, TResult Function(ChatEventMessageSent value)? messageSent, TResult Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult Function(ChatEventTypingUpdated value)? typingUpdated, @@ -373,6 +385,7 @@ class _$ChatEventChatsLoadedImpl implements ChatEventChatsLoaded { required TResult Function(String? currentUserId) chatsLoaded, required TResult Function(String chatId) chatSelected, required TResult Function(String chatId, String? cursor) messagesRequested, + required TResult Function(Message message) messageReceived, required TResult Function(String chatId, String content) messageSent, required TResult Function() favoritesRequested, required TResult Function(String chatId, String userId, bool isTyping) @@ -390,6 +403,7 @@ class _$ChatEventChatsLoadedImpl implements ChatEventChatsLoaded { TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, + TResult? Function(Message message)? messageReceived, TResult? Function(String chatId, String content)? messageSent, TResult? Function()? favoritesRequested, TResult? Function(String chatId, String userId, bool isTyping)? @@ -407,6 +421,7 @@ class _$ChatEventChatsLoadedImpl implements ChatEventChatsLoaded { TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, + TResult Function(Message message)? messageReceived, TResult Function(String chatId, String content)? messageSent, TResult Function()? favoritesRequested, TResult Function(String chatId, String userId, bool isTyping)? @@ -429,6 +444,7 @@ class _$ChatEventChatsLoadedImpl implements ChatEventChatsLoaded { required TResult Function(ChatEventChatSelected value) chatSelected, required TResult Function(ChatEventMessagesRequested value) messagesRequested, + required TResult Function(ChatEventMessageReceived value) messageReceived, required TResult Function(ChatEventMessageSent value) messageSent, required TResult Function(ChatEventFavoritesRequested value) favoritesRequested, @@ -446,6 +462,7 @@ class _$ChatEventChatsLoadedImpl implements ChatEventChatsLoaded { TResult? Function(ChatEventChatsLoaded value)? chatsLoaded, TResult? Function(ChatEventChatSelected value)? chatSelected, TResult? Function(ChatEventMessagesRequested value)? messagesRequested, + TResult? Function(ChatEventMessageReceived value)? messageReceived, TResult? Function(ChatEventMessageSent value)? messageSent, TResult? Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult? Function(ChatEventTypingUpdated value)? typingUpdated, @@ -462,6 +479,7 @@ class _$ChatEventChatsLoadedImpl implements ChatEventChatsLoaded { TResult Function(ChatEventChatsLoaded value)? chatsLoaded, TResult Function(ChatEventChatSelected value)? chatSelected, TResult Function(ChatEventMessagesRequested value)? messagesRequested, + TResult Function(ChatEventMessageReceived value)? messageReceived, TResult Function(ChatEventMessageSent value)? messageSent, TResult Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult Function(ChatEventTypingUpdated value)? typingUpdated, @@ -556,6 +574,7 @@ class _$ChatEventChatSelectedImpl implements ChatEventChatSelected { required TResult Function(String? currentUserId) chatsLoaded, required TResult Function(String chatId) chatSelected, required TResult Function(String chatId, String? cursor) messagesRequested, + required TResult Function(Message message) messageReceived, required TResult Function(String chatId, String content) messageSent, required TResult Function() favoritesRequested, required TResult Function(String chatId, String userId, bool isTyping) @@ -573,6 +592,7 @@ class _$ChatEventChatSelectedImpl implements ChatEventChatSelected { TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, + TResult? Function(Message message)? messageReceived, TResult? Function(String chatId, String content)? messageSent, TResult? Function()? favoritesRequested, TResult? Function(String chatId, String userId, bool isTyping)? @@ -590,6 +610,7 @@ class _$ChatEventChatSelectedImpl implements ChatEventChatSelected { TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, + TResult Function(Message message)? messageReceived, TResult Function(String chatId, String content)? messageSent, TResult Function()? favoritesRequested, TResult Function(String chatId, String userId, bool isTyping)? @@ -612,6 +633,7 @@ class _$ChatEventChatSelectedImpl implements ChatEventChatSelected { required TResult Function(ChatEventChatSelected value) chatSelected, required TResult Function(ChatEventMessagesRequested value) messagesRequested, + required TResult Function(ChatEventMessageReceived value) messageReceived, required TResult Function(ChatEventMessageSent value) messageSent, required TResult Function(ChatEventFavoritesRequested value) favoritesRequested, @@ -629,6 +651,7 @@ class _$ChatEventChatSelectedImpl implements ChatEventChatSelected { TResult? Function(ChatEventChatsLoaded value)? chatsLoaded, TResult? Function(ChatEventChatSelected value)? chatSelected, TResult? Function(ChatEventMessagesRequested value)? messagesRequested, + TResult? Function(ChatEventMessageReceived value)? messageReceived, TResult? Function(ChatEventMessageSent value)? messageSent, TResult? Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult? Function(ChatEventTypingUpdated value)? typingUpdated, @@ -645,6 +668,7 @@ class _$ChatEventChatSelectedImpl implements ChatEventChatSelected { TResult Function(ChatEventChatsLoaded value)? chatsLoaded, TResult Function(ChatEventChatSelected value)? chatSelected, TResult Function(ChatEventMessagesRequested value)? messagesRequested, + TResult Function(ChatEventMessageReceived value)? messageReceived, TResult Function(ChatEventMessageSent value)? messageSent, TResult Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult Function(ChatEventTypingUpdated value)? typingUpdated, @@ -748,6 +772,7 @@ class _$ChatEventMessagesRequestedImpl implements ChatEventMessagesRequested { required TResult Function(String? currentUserId) chatsLoaded, required TResult Function(String chatId) chatSelected, required TResult Function(String chatId, String? cursor) messagesRequested, + required TResult Function(Message message) messageReceived, required TResult Function(String chatId, String content) messageSent, required TResult Function() favoritesRequested, required TResult Function(String chatId, String userId, bool isTyping) @@ -765,6 +790,7 @@ class _$ChatEventMessagesRequestedImpl implements ChatEventMessagesRequested { TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, + TResult? Function(Message message)? messageReceived, TResult? Function(String chatId, String content)? messageSent, TResult? Function()? favoritesRequested, TResult? Function(String chatId, String userId, bool isTyping)? @@ -782,6 +808,7 @@ class _$ChatEventMessagesRequestedImpl implements ChatEventMessagesRequested { TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, + TResult Function(Message message)? messageReceived, TResult Function(String chatId, String content)? messageSent, TResult Function()? favoritesRequested, TResult Function(String chatId, String userId, bool isTyping)? @@ -804,6 +831,7 @@ class _$ChatEventMessagesRequestedImpl implements ChatEventMessagesRequested { required TResult Function(ChatEventChatSelected value) chatSelected, required TResult Function(ChatEventMessagesRequested value) messagesRequested, + required TResult Function(ChatEventMessageReceived value) messageReceived, required TResult Function(ChatEventMessageSent value) messageSent, required TResult Function(ChatEventFavoritesRequested value) favoritesRequested, @@ -821,6 +849,7 @@ class _$ChatEventMessagesRequestedImpl implements ChatEventMessagesRequested { TResult? Function(ChatEventChatsLoaded value)? chatsLoaded, TResult? Function(ChatEventChatSelected value)? chatSelected, TResult? Function(ChatEventMessagesRequested value)? messagesRequested, + TResult? Function(ChatEventMessageReceived value)? messageReceived, TResult? Function(ChatEventMessageSent value)? messageSent, TResult? Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult? Function(ChatEventTypingUpdated value)? typingUpdated, @@ -837,6 +866,7 @@ class _$ChatEventMessagesRequestedImpl implements ChatEventMessagesRequested { TResult Function(ChatEventChatsLoaded value)? chatsLoaded, TResult Function(ChatEventChatSelected value)? chatSelected, TResult Function(ChatEventMessagesRequested value)? messagesRequested, + TResult Function(ChatEventMessageReceived value)? messageReceived, TResult Function(ChatEventMessageSent value)? messageSent, TResult Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult Function(ChatEventTypingUpdated value)? typingUpdated, @@ -862,6 +892,206 @@ abstract class ChatEventMessagesRequested implements ChatEvent { get copyWith => throw _privateConstructorUsedError; } +/// @nodoc +abstract class _$$ChatEventMessageReceivedImplCopyWith<$Res> { + factory _$$ChatEventMessageReceivedImplCopyWith( + _$ChatEventMessageReceivedImpl value, + $Res Function(_$ChatEventMessageReceivedImpl) then) = + __$$ChatEventMessageReceivedImplCopyWithImpl<$Res>; + @useResult + $Res call({Message message}); + + $MessageCopyWith<$Res> get message; +} + +/// @nodoc +class __$$ChatEventMessageReceivedImplCopyWithImpl<$Res> + extends _$ChatEventCopyWithImpl<$Res, _$ChatEventMessageReceivedImpl> + implements _$$ChatEventMessageReceivedImplCopyWith<$Res> { + __$$ChatEventMessageReceivedImplCopyWithImpl( + _$ChatEventMessageReceivedImpl _value, + $Res Function(_$ChatEventMessageReceivedImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? message = null, + }) { + return _then(_$ChatEventMessageReceivedImpl( + null == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as Message, + )); + } + + @override + @pragma('vm:prefer-inline') + $MessageCopyWith<$Res> get message { + return $MessageCopyWith<$Res>(_value.message, (value) { + return _then(_value.copyWith(message: value)); + }); + } +} + +/// @nodoc + +class _$ChatEventMessageReceivedImpl implements ChatEventMessageReceived { + const _$ChatEventMessageReceivedImpl(this.message); + + @override + final Message message; + + @override + String toString() { + return 'ChatEvent.messageReceived(message: $message)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatEventMessageReceivedImpl && + (identical(other.message, message) || other.message == message)); + } + + @override + int get hashCode => Object.hash(runtimeType, message); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatEventMessageReceivedImplCopyWith<_$ChatEventMessageReceivedImpl> + get copyWith => __$$ChatEventMessageReceivedImplCopyWithImpl< + _$ChatEventMessageReceivedImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(String? userId) started, + required TResult Function(String? currentUserId) chatsLoaded, + required TResult Function(String chatId) chatSelected, + required TResult Function(String chatId, String? cursor) messagesRequested, + required TResult Function(Message message) messageReceived, + required TResult Function(String chatId, String content) messageSent, + required TResult Function() favoritesRequested, + required TResult Function(String chatId, String userId, bool isTyping) + typingUpdated, + required TResult Function(String chatId, bool isTyping) sendTypingStatus, + required TResult Function() cacheCleared, + }) { + return messageReceived(message); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(String? userId)? started, + TResult? Function(String? currentUserId)? chatsLoaded, + TResult? Function(String chatId)? chatSelected, + TResult? Function(String chatId, String? cursor)? messagesRequested, + TResult? Function(Message message)? messageReceived, + TResult? Function(String chatId, String content)? messageSent, + TResult? Function()? favoritesRequested, + TResult? Function(String chatId, String userId, bool isTyping)? + typingUpdated, + TResult? Function(String chatId, bool isTyping)? sendTypingStatus, + TResult? Function()? cacheCleared, + }) { + return messageReceived?.call(message); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String? userId)? started, + TResult Function(String? currentUserId)? chatsLoaded, + TResult Function(String chatId)? chatSelected, + TResult Function(String chatId, String? cursor)? messagesRequested, + TResult Function(Message message)? messageReceived, + TResult Function(String chatId, String content)? messageSent, + TResult Function()? favoritesRequested, + TResult Function(String chatId, String userId, bool isTyping)? + typingUpdated, + TResult Function(String chatId, bool isTyping)? sendTypingStatus, + TResult Function()? cacheCleared, + required TResult orElse(), + }) { + if (messageReceived != null) { + return messageReceived(message); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(ChatEventStarted value) started, + required TResult Function(ChatEventChatsLoaded value) chatsLoaded, + required TResult Function(ChatEventChatSelected value) chatSelected, + required TResult Function(ChatEventMessagesRequested value) + messagesRequested, + required TResult Function(ChatEventMessageReceived value) messageReceived, + required TResult Function(ChatEventMessageSent value) messageSent, + required TResult Function(ChatEventFavoritesRequested value) + favoritesRequested, + required TResult Function(ChatEventTypingUpdated value) typingUpdated, + required TResult Function(ChatEventSendTypingStatus value) sendTypingStatus, + required TResult Function(ChatEventCacheCleared value) cacheCleared, + }) { + return messageReceived(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(ChatEventStarted value)? started, + TResult? Function(ChatEventChatsLoaded value)? chatsLoaded, + TResult? Function(ChatEventChatSelected value)? chatSelected, + TResult? Function(ChatEventMessagesRequested value)? messagesRequested, + TResult? Function(ChatEventMessageReceived value)? messageReceived, + TResult? Function(ChatEventMessageSent value)? messageSent, + TResult? Function(ChatEventFavoritesRequested value)? favoritesRequested, + TResult? Function(ChatEventTypingUpdated value)? typingUpdated, + TResult? Function(ChatEventSendTypingStatus value)? sendTypingStatus, + TResult? Function(ChatEventCacheCleared value)? cacheCleared, + }) { + return messageReceived?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(ChatEventStarted value)? started, + TResult Function(ChatEventChatsLoaded value)? chatsLoaded, + TResult Function(ChatEventChatSelected value)? chatSelected, + TResult Function(ChatEventMessagesRequested value)? messagesRequested, + TResult Function(ChatEventMessageReceived value)? messageReceived, + TResult Function(ChatEventMessageSent value)? messageSent, + TResult Function(ChatEventFavoritesRequested value)? favoritesRequested, + TResult Function(ChatEventTypingUpdated value)? typingUpdated, + TResult Function(ChatEventSendTypingStatus value)? sendTypingStatus, + TResult Function(ChatEventCacheCleared value)? cacheCleared, + required TResult orElse(), + }) { + if (messageReceived != null) { + return messageReceived(this); + } + return orElse(); + } +} + +abstract class ChatEventMessageReceived implements ChatEvent { + const factory ChatEventMessageReceived(final Message message) = + _$ChatEventMessageReceivedImpl; + + Message get message; + @JsonKey(ignore: true) + _$$ChatEventMessageReceivedImplCopyWith<_$ChatEventMessageReceivedImpl> + get copyWith => throw _privateConstructorUsedError; +} + /// @nodoc abstract class _$$ChatEventMessageSentImplCopyWith<$Res> { factory _$$ChatEventMessageSentImplCopyWith(_$ChatEventMessageSentImpl value, @@ -940,6 +1170,7 @@ class _$ChatEventMessageSentImpl implements ChatEventMessageSent { required TResult Function(String? currentUserId) chatsLoaded, required TResult Function(String chatId) chatSelected, required TResult Function(String chatId, String? cursor) messagesRequested, + required TResult Function(Message message) messageReceived, required TResult Function(String chatId, String content) messageSent, required TResult Function() favoritesRequested, required TResult Function(String chatId, String userId, bool isTyping) @@ -957,6 +1188,7 @@ class _$ChatEventMessageSentImpl implements ChatEventMessageSent { TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, + TResult? Function(Message message)? messageReceived, TResult? Function(String chatId, String content)? messageSent, TResult? Function()? favoritesRequested, TResult? Function(String chatId, String userId, bool isTyping)? @@ -974,6 +1206,7 @@ class _$ChatEventMessageSentImpl implements ChatEventMessageSent { TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, + TResult Function(Message message)? messageReceived, TResult Function(String chatId, String content)? messageSent, TResult Function()? favoritesRequested, TResult Function(String chatId, String userId, bool isTyping)? @@ -996,6 +1229,7 @@ class _$ChatEventMessageSentImpl implements ChatEventMessageSent { required TResult Function(ChatEventChatSelected value) chatSelected, required TResult Function(ChatEventMessagesRequested value) messagesRequested, + required TResult Function(ChatEventMessageReceived value) messageReceived, required TResult Function(ChatEventMessageSent value) messageSent, required TResult Function(ChatEventFavoritesRequested value) favoritesRequested, @@ -1013,6 +1247,7 @@ class _$ChatEventMessageSentImpl implements ChatEventMessageSent { TResult? Function(ChatEventChatsLoaded value)? chatsLoaded, TResult? Function(ChatEventChatSelected value)? chatSelected, TResult? Function(ChatEventMessagesRequested value)? messagesRequested, + TResult? Function(ChatEventMessageReceived value)? messageReceived, TResult? Function(ChatEventMessageSent value)? messageSent, TResult? Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult? Function(ChatEventTypingUpdated value)? typingUpdated, @@ -1029,6 +1264,7 @@ class _$ChatEventMessageSentImpl implements ChatEventMessageSent { TResult Function(ChatEventChatsLoaded value)? chatsLoaded, TResult Function(ChatEventChatSelected value)? chatSelected, TResult Function(ChatEventMessagesRequested value)? messagesRequested, + TResult Function(ChatEventMessageReceived value)? messageReceived, TResult Function(ChatEventMessageSent value)? messageSent, TResult Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult Function(ChatEventTypingUpdated value)? typingUpdated, @@ -1099,6 +1335,7 @@ class _$ChatEventFavoritesRequestedImpl implements ChatEventFavoritesRequested { required TResult Function(String? currentUserId) chatsLoaded, required TResult Function(String chatId) chatSelected, required TResult Function(String chatId, String? cursor) messagesRequested, + required TResult Function(Message message) messageReceived, required TResult Function(String chatId, String content) messageSent, required TResult Function() favoritesRequested, required TResult Function(String chatId, String userId, bool isTyping) @@ -1116,6 +1353,7 @@ class _$ChatEventFavoritesRequestedImpl implements ChatEventFavoritesRequested { TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, + TResult? Function(Message message)? messageReceived, TResult? Function(String chatId, String content)? messageSent, TResult? Function()? favoritesRequested, TResult? Function(String chatId, String userId, bool isTyping)? @@ -1133,6 +1371,7 @@ class _$ChatEventFavoritesRequestedImpl implements ChatEventFavoritesRequested { TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, + TResult Function(Message message)? messageReceived, TResult Function(String chatId, String content)? messageSent, TResult Function()? favoritesRequested, TResult Function(String chatId, String userId, bool isTyping)? @@ -1155,6 +1394,7 @@ class _$ChatEventFavoritesRequestedImpl implements ChatEventFavoritesRequested { required TResult Function(ChatEventChatSelected value) chatSelected, required TResult Function(ChatEventMessagesRequested value) messagesRequested, + required TResult Function(ChatEventMessageReceived value) messageReceived, required TResult Function(ChatEventMessageSent value) messageSent, required TResult Function(ChatEventFavoritesRequested value) favoritesRequested, @@ -1172,6 +1412,7 @@ class _$ChatEventFavoritesRequestedImpl implements ChatEventFavoritesRequested { TResult? Function(ChatEventChatsLoaded value)? chatsLoaded, TResult? Function(ChatEventChatSelected value)? chatSelected, TResult? Function(ChatEventMessagesRequested value)? messagesRequested, + TResult? Function(ChatEventMessageReceived value)? messageReceived, TResult? Function(ChatEventMessageSent value)? messageSent, TResult? Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult? Function(ChatEventTypingUpdated value)? typingUpdated, @@ -1188,6 +1429,7 @@ class _$ChatEventFavoritesRequestedImpl implements ChatEventFavoritesRequested { TResult Function(ChatEventChatsLoaded value)? chatsLoaded, TResult Function(ChatEventChatSelected value)? chatSelected, TResult Function(ChatEventMessagesRequested value)? messagesRequested, + TResult Function(ChatEventMessageReceived value)? messageReceived, TResult Function(ChatEventMessageSent value)? messageSent, TResult Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult Function(ChatEventTypingUpdated value)? typingUpdated, @@ -1295,6 +1537,7 @@ class _$ChatEventTypingUpdatedImpl implements ChatEventTypingUpdated { required TResult Function(String? currentUserId) chatsLoaded, required TResult Function(String chatId) chatSelected, required TResult Function(String chatId, String? cursor) messagesRequested, + required TResult Function(Message message) messageReceived, required TResult Function(String chatId, String content) messageSent, required TResult Function() favoritesRequested, required TResult Function(String chatId, String userId, bool isTyping) @@ -1312,6 +1555,7 @@ class _$ChatEventTypingUpdatedImpl implements ChatEventTypingUpdated { TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, + TResult? Function(Message message)? messageReceived, TResult? Function(String chatId, String content)? messageSent, TResult? Function()? favoritesRequested, TResult? Function(String chatId, String userId, bool isTyping)? @@ -1329,6 +1573,7 @@ class _$ChatEventTypingUpdatedImpl implements ChatEventTypingUpdated { TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, + TResult Function(Message message)? messageReceived, TResult Function(String chatId, String content)? messageSent, TResult Function()? favoritesRequested, TResult Function(String chatId, String userId, bool isTyping)? @@ -1351,6 +1596,7 @@ class _$ChatEventTypingUpdatedImpl implements ChatEventTypingUpdated { required TResult Function(ChatEventChatSelected value) chatSelected, required TResult Function(ChatEventMessagesRequested value) messagesRequested, + required TResult Function(ChatEventMessageReceived value) messageReceived, required TResult Function(ChatEventMessageSent value) messageSent, required TResult Function(ChatEventFavoritesRequested value) favoritesRequested, @@ -1368,6 +1614,7 @@ class _$ChatEventTypingUpdatedImpl implements ChatEventTypingUpdated { TResult? Function(ChatEventChatsLoaded value)? chatsLoaded, TResult? Function(ChatEventChatSelected value)? chatSelected, TResult? Function(ChatEventMessagesRequested value)? messagesRequested, + TResult? Function(ChatEventMessageReceived value)? messageReceived, TResult? Function(ChatEventMessageSent value)? messageSent, TResult? Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult? Function(ChatEventTypingUpdated value)? typingUpdated, @@ -1384,6 +1631,7 @@ class _$ChatEventTypingUpdatedImpl implements ChatEventTypingUpdated { TResult Function(ChatEventChatsLoaded value)? chatsLoaded, TResult Function(ChatEventChatSelected value)? chatSelected, TResult Function(ChatEventMessagesRequested value)? messagesRequested, + TResult Function(ChatEventMessageReceived value)? messageReceived, TResult Function(ChatEventMessageSent value)? messageSent, TResult Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult Function(ChatEventTypingUpdated value)? typingUpdated, @@ -1491,6 +1739,7 @@ class _$ChatEventSendTypingStatusImpl implements ChatEventSendTypingStatus { required TResult Function(String? currentUserId) chatsLoaded, required TResult Function(String chatId) chatSelected, required TResult Function(String chatId, String? cursor) messagesRequested, + required TResult Function(Message message) messageReceived, required TResult Function(String chatId, String content) messageSent, required TResult Function() favoritesRequested, required TResult Function(String chatId, String userId, bool isTyping) @@ -1508,6 +1757,7 @@ class _$ChatEventSendTypingStatusImpl implements ChatEventSendTypingStatus { TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, + TResult? Function(Message message)? messageReceived, TResult? Function(String chatId, String content)? messageSent, TResult? Function()? favoritesRequested, TResult? Function(String chatId, String userId, bool isTyping)? @@ -1525,6 +1775,7 @@ class _$ChatEventSendTypingStatusImpl implements ChatEventSendTypingStatus { TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, + TResult Function(Message message)? messageReceived, TResult Function(String chatId, String content)? messageSent, TResult Function()? favoritesRequested, TResult Function(String chatId, String userId, bool isTyping)? @@ -1547,6 +1798,7 @@ class _$ChatEventSendTypingStatusImpl implements ChatEventSendTypingStatus { required TResult Function(ChatEventChatSelected value) chatSelected, required TResult Function(ChatEventMessagesRequested value) messagesRequested, + required TResult Function(ChatEventMessageReceived value) messageReceived, required TResult Function(ChatEventMessageSent value) messageSent, required TResult Function(ChatEventFavoritesRequested value) favoritesRequested, @@ -1564,6 +1816,7 @@ class _$ChatEventSendTypingStatusImpl implements ChatEventSendTypingStatus { TResult? Function(ChatEventChatsLoaded value)? chatsLoaded, TResult? Function(ChatEventChatSelected value)? chatSelected, TResult? Function(ChatEventMessagesRequested value)? messagesRequested, + TResult? Function(ChatEventMessageReceived value)? messageReceived, TResult? Function(ChatEventMessageSent value)? messageSent, TResult? Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult? Function(ChatEventTypingUpdated value)? typingUpdated, @@ -1580,6 +1833,7 @@ class _$ChatEventSendTypingStatusImpl implements ChatEventSendTypingStatus { TResult Function(ChatEventChatsLoaded value)? chatsLoaded, TResult Function(ChatEventChatSelected value)? chatSelected, TResult Function(ChatEventMessagesRequested value)? messagesRequested, + TResult Function(ChatEventMessageReceived value)? messageReceived, TResult Function(ChatEventMessageSent value)? messageSent, TResult Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult Function(ChatEventTypingUpdated value)? typingUpdated, @@ -1650,6 +1904,7 @@ class _$ChatEventCacheClearedImpl implements ChatEventCacheCleared { required TResult Function(String? currentUserId) chatsLoaded, required TResult Function(String chatId) chatSelected, required TResult Function(String chatId, String? cursor) messagesRequested, + required TResult Function(Message message) messageReceived, required TResult Function(String chatId, String content) messageSent, required TResult Function() favoritesRequested, required TResult Function(String chatId, String userId, bool isTyping) @@ -1667,6 +1922,7 @@ class _$ChatEventCacheClearedImpl implements ChatEventCacheCleared { TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, + TResult? Function(Message message)? messageReceived, TResult? Function(String chatId, String content)? messageSent, TResult? Function()? favoritesRequested, TResult? Function(String chatId, String userId, bool isTyping)? @@ -1684,6 +1940,7 @@ class _$ChatEventCacheClearedImpl implements ChatEventCacheCleared { TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, + TResult Function(Message message)? messageReceived, TResult Function(String chatId, String content)? messageSent, TResult Function()? favoritesRequested, TResult Function(String chatId, String userId, bool isTyping)? @@ -1706,6 +1963,7 @@ class _$ChatEventCacheClearedImpl implements ChatEventCacheCleared { required TResult Function(ChatEventChatSelected value) chatSelected, required TResult Function(ChatEventMessagesRequested value) messagesRequested, + required TResult Function(ChatEventMessageReceived value) messageReceived, required TResult Function(ChatEventMessageSent value) messageSent, required TResult Function(ChatEventFavoritesRequested value) favoritesRequested, @@ -1723,6 +1981,7 @@ class _$ChatEventCacheClearedImpl implements ChatEventCacheCleared { TResult? Function(ChatEventChatsLoaded value)? chatsLoaded, TResult? Function(ChatEventChatSelected value)? chatSelected, TResult? Function(ChatEventMessagesRequested value)? messagesRequested, + TResult? Function(ChatEventMessageReceived value)? messageReceived, TResult? Function(ChatEventMessageSent value)? messageSent, TResult? Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult? Function(ChatEventTypingUpdated value)? typingUpdated, @@ -1739,6 +1998,7 @@ class _$ChatEventCacheClearedImpl implements ChatEventCacheCleared { TResult Function(ChatEventChatsLoaded value)? chatsLoaded, TResult Function(ChatEventChatSelected value)? chatSelected, TResult Function(ChatEventMessagesRequested value)? messagesRequested, + TResult Function(ChatEventMessageReceived value)? messageReceived, TResult Function(ChatEventMessageSent value)? messageSent, TResult Function(ChatEventFavoritesRequested value)? favoritesRequested, TResult Function(ChatEventTypingUpdated value)? typingUpdated, diff --git a/client-mobile/lib/features/chat/presentation/bloc/chat_state.dart b/client-mobile/lib/features/chat/presentation/bloc/chat_state.dart index a6426ef..baa0364 100644 --- a/client-mobile/lib/features/chat/presentation/bloc/chat_state.dart +++ b/client-mobile/lib/features/chat/presentation/bloc/chat_state.dart @@ -10,6 +10,6 @@ class ChatState with _$ChatState { const factory ChatState.loading({@Default({}) Map> typingUsers}) = ChatLoading; const factory ChatState.chatsLoaded(List chats, {@Default({}) Map> typingUsers}) = _ChatsLoaded; const factory ChatState.chatSelected(Chat chat, List messages, {@Default({}) Map> typingUsers}) = _ChatSelected; - const factory ChatState.messagesLoaded(List messages, {@Default({}) Map> typingUsers}) = _MessagesLoaded; + const factory ChatState.messagesLoaded(Chat chat, List messages, {@Default({}) Map> typingUsers}) = _MessagesLoaded; const factory ChatState.error(String message, {@Default({}) Map> typingUsers}) = ChatError; } diff --git a/client-mobile/lib/features/chat/presentation/bloc/chat_state.freezed.dart b/client-mobile/lib/features/chat/presentation/bloc/chat_state.freezed.dart index bf6c0b8..43caeeb 100644 --- a/client-mobile/lib/features/chat/presentation/bloc/chat_state.freezed.dart +++ b/client-mobile/lib/features/chat/presentation/bloc/chat_state.freezed.dart @@ -28,8 +28,8 @@ mixin _$ChatState { required TResult Function(Chat chat, List messages, Map> typingUsers) chatSelected, - required TResult Function( - List messages, Map> typingUsers) + required TResult Function(Chat chat, List messages, + Map> typingUsers) messagesLoaded, required TResult Function( String message, Map> typingUsers) @@ -45,8 +45,8 @@ mixin _$ChatState { TResult? Function(Chat chat, List messages, Map> typingUsers)? chatSelected, - TResult? Function( - List messages, Map> typingUsers)? + TResult? Function(Chat chat, List messages, + Map> typingUsers)? messagesLoaded, TResult? Function(String message, Map> typingUsers)? error, @@ -61,8 +61,8 @@ mixin _$ChatState { TResult Function(Chat chat, List messages, Map> typingUsers)? chatSelected, - TResult Function( - List messages, Map> typingUsers)? + TResult Function(Chat chat, List messages, + Map> typingUsers)? messagesLoaded, TResult Function(String message, Map> typingUsers)? error, @@ -222,8 +222,8 @@ class _$ChatInitialImpl implements ChatInitial { required TResult Function(Chat chat, List messages, Map> typingUsers) chatSelected, - required TResult Function( - List messages, Map> typingUsers) + required TResult Function(Chat chat, List messages, + Map> typingUsers) messagesLoaded, required TResult Function( String message, Map> typingUsers) @@ -242,8 +242,8 @@ class _$ChatInitialImpl implements ChatInitial { TResult? Function(Chat chat, List messages, Map> typingUsers)? chatSelected, - TResult? Function( - List messages, Map> typingUsers)? + TResult? Function(Chat chat, List messages, + Map> typingUsers)? messagesLoaded, TResult? Function(String message, Map> typingUsers)? error, @@ -261,8 +261,8 @@ class _$ChatInitialImpl implements ChatInitial { TResult Function(Chat chat, List messages, Map> typingUsers)? chatSelected, - TResult Function( - List messages, Map> typingUsers)? + TResult Function(Chat chat, List messages, + Map> typingUsers)? messagesLoaded, TResult Function(String message, Map> typingUsers)? error, @@ -414,8 +414,8 @@ class _$ChatLoadingImpl implements ChatLoading { required TResult Function(Chat chat, List messages, Map> typingUsers) chatSelected, - required TResult Function( - List messages, Map> typingUsers) + required TResult Function(Chat chat, List messages, + Map> typingUsers) messagesLoaded, required TResult Function( String message, Map> typingUsers) @@ -434,8 +434,8 @@ class _$ChatLoadingImpl implements ChatLoading { TResult? Function(Chat chat, List messages, Map> typingUsers)? chatSelected, - TResult? Function( - List messages, Map> typingUsers)? + TResult? Function(Chat chat, List messages, + Map> typingUsers)? messagesLoaded, TResult? Function(String message, Map> typingUsers)? error, @@ -453,8 +453,8 @@ class _$ChatLoadingImpl implements ChatLoading { TResult Function(Chat chat, List messages, Map> typingUsers)? chatSelected, - TResult Function( - List messages, Map> typingUsers)? + TResult Function(Chat chat, List messages, + Map> typingUsers)? messagesLoaded, TResult Function(String message, Map> typingUsers)? error, @@ -623,8 +623,8 @@ class _$ChatsLoadedImpl implements _ChatsLoaded { required TResult Function(Chat chat, List messages, Map> typingUsers) chatSelected, - required TResult Function( - List messages, Map> typingUsers) + required TResult Function(Chat chat, List messages, + Map> typingUsers) messagesLoaded, required TResult Function( String message, Map> typingUsers) @@ -643,8 +643,8 @@ class _$ChatsLoadedImpl implements _ChatsLoaded { TResult? Function(Chat chat, List messages, Map> typingUsers)? chatSelected, - TResult? Function( - List messages, Map> typingUsers)? + TResult? Function(Chat chat, List messages, + Map> typingUsers)? messagesLoaded, TResult? Function(String message, Map> typingUsers)? error, @@ -662,8 +662,8 @@ class _$ChatsLoadedImpl implements _ChatsLoaded { TResult Function(Chat chat, List messages, Map> typingUsers)? chatSelected, - TResult Function( - List messages, Map> typingUsers)? + TResult Function(Chat chat, List messages, + Map> typingUsers)? messagesLoaded, TResult Function(String message, Map> typingUsers)? error, @@ -855,8 +855,8 @@ class _$ChatSelectedImpl implements _ChatSelected { required TResult Function(Chat chat, List messages, Map> typingUsers) chatSelected, - required TResult Function( - List messages, Map> typingUsers) + required TResult Function(Chat chat, List messages, + Map> typingUsers) messagesLoaded, required TResult Function( String message, Map> typingUsers) @@ -875,8 +875,8 @@ class _$ChatSelectedImpl implements _ChatSelected { TResult? Function(Chat chat, List messages, Map> typingUsers)? chatSelected, - TResult? Function( - List messages, Map> typingUsers)? + TResult? Function(Chat chat, List messages, + Map> typingUsers)? messagesLoaded, TResult? Function(String message, Map> typingUsers)? error, @@ -894,8 +894,8 @@ class _$ChatSelectedImpl implements _ChatSelected { TResult Function(Chat chat, List messages, Map> typingUsers)? chatSelected, - TResult Function( - List messages, Map> typingUsers)? + TResult Function(Chat chat, List messages, + Map> typingUsers)? messagesLoaded, TResult Function(String message, Map> typingUsers)? error, @@ -973,7 +973,12 @@ abstract class _$$MessagesLoadedImplCopyWith<$Res> __$$MessagesLoadedImplCopyWithImpl<$Res>; @override @useResult - $Res call({List messages, Map> typingUsers}); + $Res call( + {Chat chat, + List messages, + Map> typingUsers}); + + $ChatCopyWith<$Res> get chat; } /// @nodoc @@ -987,10 +992,15 @@ class __$$MessagesLoadedImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ + Object? chat = null, Object? messages = null, Object? typingUsers = null, }) { return _then(_$MessagesLoadedImpl( + null == chat + ? _value.chat + : chat // ignore: cast_nullable_to_non_nullable + as Chat, null == messages ? _value._messages : messages // ignore: cast_nullable_to_non_nullable @@ -1001,16 +1011,26 @@ class __$$MessagesLoadedImplCopyWithImpl<$Res> as Map>, )); } + + @override + @pragma('vm:prefer-inline') + $ChatCopyWith<$Res> get chat { + return $ChatCopyWith<$Res>(_value.chat, (value) { + return _then(_value.copyWith(chat: value)); + }); + } } /// @nodoc class _$MessagesLoadedImpl implements _MessagesLoaded { - const _$MessagesLoadedImpl(final List messages, + const _$MessagesLoadedImpl(this.chat, final List messages, {final Map> typingUsers = const {}}) : _messages = messages, _typingUsers = typingUsers; + @override + final Chat chat; final List _messages; @override List get messages { @@ -1030,7 +1050,7 @@ class _$MessagesLoadedImpl implements _MessagesLoaded { @override String toString() { - return 'ChatState.messagesLoaded(messages: $messages, typingUsers: $typingUsers)'; + return 'ChatState.messagesLoaded(chat: $chat, messages: $messages, typingUsers: $typingUsers)'; } @override @@ -1038,6 +1058,7 @@ class _$MessagesLoadedImpl implements _MessagesLoaded { return identical(this, other) || (other.runtimeType == runtimeType && other is _$MessagesLoadedImpl && + (identical(other.chat, chat) || other.chat == chat) && const DeepCollectionEquality().equals(other._messages, _messages) && const DeepCollectionEquality() .equals(other._typingUsers, _typingUsers)); @@ -1046,6 +1067,7 @@ class _$MessagesLoadedImpl implements _MessagesLoaded { @override int get hashCode => Object.hash( runtimeType, + chat, const DeepCollectionEquality().hash(_messages), const DeepCollectionEquality().hash(_typingUsers)); @@ -1067,14 +1089,14 @@ class _$MessagesLoadedImpl implements _MessagesLoaded { required TResult Function(Chat chat, List messages, Map> typingUsers) chatSelected, - required TResult Function( - List messages, Map> typingUsers) + required TResult Function(Chat chat, List messages, + Map> typingUsers) messagesLoaded, required TResult Function( String message, Map> typingUsers) error, }) { - return messagesLoaded(messages, typingUsers); + return messagesLoaded(chat, messages, typingUsers); } @override @@ -1087,13 +1109,13 @@ class _$MessagesLoadedImpl implements _MessagesLoaded { TResult? Function(Chat chat, List messages, Map> typingUsers)? chatSelected, - TResult? Function( - List messages, Map> typingUsers)? + TResult? Function(Chat chat, List messages, + Map> typingUsers)? messagesLoaded, TResult? Function(String message, Map> typingUsers)? error, }) { - return messagesLoaded?.call(messages, typingUsers); + return messagesLoaded?.call(chat, messages, typingUsers); } @override @@ -1106,15 +1128,15 @@ class _$MessagesLoadedImpl implements _MessagesLoaded { TResult Function(Chat chat, List messages, Map> typingUsers)? chatSelected, - TResult Function( - List messages, Map> typingUsers)? + TResult Function(Chat chat, List messages, + Map> typingUsers)? messagesLoaded, TResult Function(String message, Map> typingUsers)? error, required TResult orElse(), }) { if (messagesLoaded != null) { - return messagesLoaded(messages, typingUsers); + return messagesLoaded(chat, messages, typingUsers); } return orElse(); } @@ -1164,9 +1186,10 @@ class _$MessagesLoadedImpl implements _MessagesLoaded { } abstract class _MessagesLoaded implements ChatState { - const factory _MessagesLoaded(final List messages, + const factory _MessagesLoaded(final Chat chat, final List messages, {final Map> typingUsers}) = _$MessagesLoadedImpl; + Chat get chat; List get messages; @override Map> get typingUsers; @@ -1268,8 +1291,8 @@ class _$ChatErrorImpl implements ChatError { required TResult Function(Chat chat, List messages, Map> typingUsers) chatSelected, - required TResult Function( - List messages, Map> typingUsers) + required TResult Function(Chat chat, List messages, + Map> typingUsers) messagesLoaded, required TResult Function( String message, Map> typingUsers) @@ -1288,8 +1311,8 @@ class _$ChatErrorImpl implements ChatError { TResult? Function(Chat chat, List messages, Map> typingUsers)? chatSelected, - TResult? Function( - List messages, Map> typingUsers)? + TResult? Function(Chat chat, List messages, + Map> typingUsers)? messagesLoaded, TResult? Function(String message, Map> typingUsers)? error, @@ -1307,8 +1330,8 @@ class _$ChatErrorImpl implements ChatError { TResult Function(Chat chat, List messages, Map> typingUsers)? chatSelected, - TResult Function( - List messages, Map> typingUsers)? + TResult Function(Chat chat, List messages, + Map> typingUsers)? messagesLoaded, TResult Function(String message, Map> typingUsers)? error, diff --git a/client-mobile/lib/features/chat/presentation/pages/chat_detail_page.dart b/client-mobile/lib/features/chat/presentation/pages/chat_detail_page.dart index 0f4d0f9..dcac956 100644 --- a/client-mobile/lib/features/chat/presentation/pages/chat_detail_page.dart +++ b/client-mobile/lib/features/chat/presentation/pages/chat_detail_page.dart @@ -35,44 +35,48 @@ class _ChatDetailPageState extends State { @override Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - final currentChat = state.maybeWhen( - chatSelected: (chat, _, __) => chat, - orElse: () => widget.chat, - ); - - return Scaffold( - appBar: AppBar( - centerTitle: false, - title: Column( + return Scaffold( + appBar: AppBar( + centerTitle: false, + title: BlocBuilder( + builder: (context, state) { + final currentChat = state.maybeWhen( + chatSelected: (chat, _, __) => chat, + messagesLoaded: (chat, _, __) => chat, + orElse: () => widget.chat, + ); + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(currentChat.type == 'favorites' ? AppLocalizations.of(context)!.favorites : currentChat.title), if (currentChat.type != 'favorites') _buildPresenceStatus(currentChat, state), ], - ), - actions: [ - IconButton(icon: const Icon(Icons.more_vert), onPressed: () {}), - ], - ), - body: Column( - children: [ - Expanded( - child: state.maybeWhen( + ); + }, + ), + actions: [ + IconButton(icon: const Icon(Icons.more_vert), onPressed: () {}), + ], + ), + body: Column( + children: [ + Expanded( + child: BlocBuilder( + builder: (context, state) { + return state.maybeWhen( chatSelected: (_, messages, __) => _buildMessageList(messages), - messagesLoaded: (messages, _) => _buildMessageList(messages), + messagesLoaded: (_, messages, __) => _buildMessageList(messages), loading: (_) => const Center(child: CircularProgressIndicator()), error: (msg, _) => Center(child: Text('Ошибка: $msg')), orElse: () => const Center(child: Text('Начните общение')), - ), - ), - _buildMessageInput(currentChat), - ], + ); + }, + ), ), - ); - }, + _buildMessageInput(widget.chat), + ], + ), ); } diff --git a/client-mobile/lib/features/chat/presentation/pages/chats_page.dart b/client-mobile/lib/features/chat/presentation/pages/chats_page.dart index 3f986d8..4fadf69 100644 --- a/client-mobile/lib/features/chat/presentation/pages/chats_page.dart +++ b/client-mobile/lib/features/chat/presentation/pages/chats_page.dart @@ -29,6 +29,8 @@ class _ChatsPageState extends State { context.read().add(ChatEvent.chatsLoaded(currentUserId: userId)); } + bool _isNavigating = false; + @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; @@ -48,6 +50,21 @@ class _ChatsPageState extends State { listener: (context, state) { state.whenOrNull( chatSelected: (chat, _, __) { + if (_isNavigating) return; + + // Extra safety: check if we are already on chat_detail + bool isAlreadyOnDetail = false; + Navigator.popUntil(context, (route) { + if (route.settings.name == 'chat_detail') { + isAlreadyOnDetail = true; + } + return true; + }); + + if (isAlreadyOnDetail) return; + + _isNavigating = true; + final authState = context.read().state; final userId = authState.maybeWhen( authenticated: (id) => id, @@ -56,12 +73,14 @@ class _ChatsPageState extends State { Navigator.of(context).push( MaterialPageRoute( + settings: const RouteSettings(name: 'chat_detail'), builder: (_) => ChatDetailPage( chat: chat, currentUserId: userId, ), ), ).then((_) { + _isNavigating = false; // Reload chats when returning from detail page if (context.mounted) { context.read().add(ChatEvent.chatsLoaded(currentUserId: userId));