From 40589dbb759770c0e5345e30045091fc9ea38509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A5=D0=B0=D0=BB=D0=B8=D0=BC=D0=BE=D0=B2=20=D0=A0=D1=83?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D0=BC?= Date: Fri, 15 May 2026 00:10:34 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=BE=D0=B2=D1=82=D0=BE=D1=80=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20=D0=B2=D1=85=D0=BE=D0=B4=20=D0=B2=20=D0=B0=D0=BA?= =?UTF-8?q?=D0=BA=D0=B0=D1=83=D0=BD=D1=82,=20=D0=BE=D1=87=D0=B8=D1=81?= =?UTF-8?q?=D1=82=D0=BA=D0=B0=20=D0=BA=D1=8D=D1=88=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client-mobile/l10n/app_en.arb | 6 +- client-mobile/l10n/app_ru.arb | 6 +- client-mobile/lib/app.dart | 23 +- .../lib/core/network/signalr_service.dart | 33 +- .../auth_local_datasource_impl.dart | 2 + .../chat_local_datasource_impl.dart | 6 + .../chat_remote_datasource_impl.dart | 52 +- .../repositories/chat_repository_impl.dart | 21 + .../domain/repositories/chat_repository.dart | 3 + .../chat/presentation/bloc/chat_bloc.dart | 47 +- .../chat/presentation/bloc/chat_event.dart | 5 +- .../presentation/bloc/chat_event.freezed.dart | 788 +++++++++++++++++- .../chat/presentation/bloc/chat_state.dart | 12 +- .../presentation/bloc/chat_state.freezed.dart | 738 +++++++++++----- .../presentation/pages/chat_detail_page.dart | 230 +++-- .../chat/presentation/pages/chats_page.dart | 10 +- .../lib/internal/di/injection_container.dart | 2 + client-mobile/lib/l10n/app_localizations.dart | 24 + .../lib/l10n/app_localizations_en.dart | 14 + .../lib/l10n/app_localizations_ru.dart | 14 + client-mobile/lib/main.dart | 5 + 21 files changed, 1732 insertions(+), 309 deletions(-) diff --git a/client-mobile/l10n/app_en.arb b/client-mobile/l10n/app_en.arb index 053f424..c467e9a 100644 --- a/client-mobile/l10n/app_en.arb +++ b/client-mobile/l10n/app_en.arb @@ -80,5 +80,9 @@ "enterUsername": "Enter login", "invalidUsername": "Login must be at least 3 characters and without Cyrillic", "loginFailed": "Login failed. Check your login and password", - "registrationFailed": "Registration failed" + "registrationFailed": "Registration failed", + "online": "online", + "lastSeen": "last seen {date} at {time}", + "noMessages": "No messages yet", + "messageHint": "Message" } diff --git a/client-mobile/l10n/app_ru.arb b/client-mobile/l10n/app_ru.arb index 109d918..546682e 100644 --- a/client-mobile/l10n/app_ru.arb +++ b/client-mobile/l10n/app_ru.arb @@ -80,5 +80,9 @@ "enterUsername": "Введите логин", "invalidUsername": "Логин должен быть от 3 символов и без кириллицы", "loginFailed": "Ошибка входа. Проверьте логин и пароль", - "registrationFailed": "Ошибка регистрации" + "registrationFailed": "Ошибка регистрации", + "online": "в сети", + "lastSeen": "был(а) в сети {date} в {time}", + "noMessages": "Сообщений пока нет", + "messageHint": "Сообщение" } diff --git a/client-mobile/lib/app.dart b/client-mobile/lib/app.dart index e3444a1..17f8020 100644 --- a/client-mobile/lib/app.dart +++ b/client-mobile/lib/app.dart @@ -56,13 +56,26 @@ class MessengerApp extends StatelessWidget { GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], - home: BlocBuilder( - builder: (context, authState) { - return authState.maybeWhen( - authenticated: (_) => const MainScreen(), - orElse: () => const LoginPage(), + home: BlocListener( + listener: (context, authState) { + authState.maybeWhen( + authenticated: (userId) { + context.read().add(ChatEvent.started(userId: userId)); + }, + unauthenticated: () { + context.read().add(const ChatEvent.cacheCleared()); + }, + orElse: () {}, ); }, + child: BlocBuilder( + builder: (context, authState) { + return authState.maybeWhen( + authenticated: (_) => const MainScreen(), + orElse: () => const LoginPage(), + ); + }, + ), ), ); }, diff --git a/client-mobile/lib/core/network/signalr_service.dart b/client-mobile/lib/core/network/signalr_service.dart index 7cc486f..3a7b7f1 100644 --- a/client-mobile/lib/core/network/signalr_service.dart +++ b/client-mobile/lib/core/network/signalr_service.dart @@ -13,6 +13,9 @@ class SignalRService { SignalRService(this.prefs); Future init() async { + if (_hubConnection != null) { + await stop(); + } final apiUrl = prefs.getString('api_url') ?? 'https://api.messenger.app'; final token = prefs.getString('access_token'); @@ -33,12 +36,38 @@ class SignalRService { }); _hubConnection?.on('ReceiveMessage', _handleReceiveMessage); + _hubConnection?.on('user_typing', _handleUserTyping); + _hubConnection?.on('user_stopped_typing', _handleUserStoppedTyping); try { await _hubConnection?.start(); - // print('[SignalR] Connection started'); } catch (e) { - // print('[SignalR] Error starting connection: $e'); + // ignore + } + } + + final _typingController = StreamController>.broadcast(); + Stream> get typingUpdates => _typingController.stream; + + void _handleUserTyping(List? 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}); + } + } + + void _handleUserStoppedTyping(List? 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}); + } + } + + Future sendTypingStatus(String chatId, bool isTyping) async { + if (isTyping) { + await _hubConnection?.invoke('typing_start', args: [chatId]); + } else { + await _hubConnection?.invoke('typing_stop', args: [chatId]); } } diff --git a/client-mobile/lib/features/auth/data/datasources/auth_local_datasource_impl.dart b/client-mobile/lib/features/auth/data/datasources/auth_local_datasource_impl.dart index 9c6777f..884ee8d 100644 --- a/client-mobile/lib/features/auth/data/datasources/auth_local_datasource_impl.dart +++ b/client-mobile/lib/features/auth/data/datasources/auth_local_datasource_impl.dart @@ -26,6 +26,8 @@ class AuthLocalDataSourceImpl implements AuthLocalDataSource { @override Future saveToken(String token) async { + // ignore: avoid_print + print('[DEBUG] Saving new access token (starts with: ${token.substring(0, 10)}...)'); await sharedPreferences.setString(_accessTokenKey, token); } diff --git a/client-mobile/lib/features/chat/data/datasources/chat_local_datasource_impl.dart b/client-mobile/lib/features/chat/data/datasources/chat_local_datasource_impl.dart index b56e1d8..e2d09b9 100644 --- a/client-mobile/lib/features/chat/data/datasources/chat_local_datasource_impl.dart +++ b/client-mobile/lib/features/chat/data/datasources/chat_local_datasource_impl.dart @@ -90,10 +90,16 @@ class ChatLocalDataSourceImpl implements ChatLocalDataSource { @override Future> clearCache() async { + // ignore: avoid_print + print('[DEBUG] ChatLocalDataSource.clearCache calling isar.clear()'); try { await isar.writeTxn(() => isar.clear()); + // ignore: avoid_print + print('[DEBUG] ChatLocalDataSource.clearCache SUCCESS'); return const Result.success(null); } catch (e) { + // ignore: avoid_print + print('[DEBUG] ChatLocalDataSource.clearCache ERROR: $e'); return Result.failure(AppError.database(message: e.toString())); } } diff --git a/client-mobile/lib/features/chat/data/datasources/chat_remote_datasource_impl.dart b/client-mobile/lib/features/chat/data/datasources/chat_remote_datasource_impl.dart index 08215f7..4b0e65f 100644 --- a/client-mobile/lib/features/chat/data/datasources/chat_remote_datasource_impl.dart +++ b/client-mobile/lib/features/chat/data/datasources/chat_remote_datasource_impl.dart @@ -137,16 +137,23 @@ class ChatRemoteDataSourceImpl implements ChatRemoteDataSource { } Chat _mapChatJson(Map json, {String? currentUserId}) { - final members = (json['members'] as List?)?.map((m) { - final userData = m['user'] as Map?; + final membersData = json['members'] ?? json['participants']; + final members = (membersData as List?)?.map((m) { + final userData = m is Map ? (m['user'] ?? m) : m; return User( - id: m['userId'] ?? (userData?['id'] ?? ''), - name: userData?['displayName'] ?? '', - avatarUrl: userData?['avatar'], + id: (m is Map ? m['userId'] : null) ?? (userData?['id'] ?? ''), + name: userData?['displayName'] ?? (userData?['name'] ?? ''), + avatarUrl: userData?['avatar'] ?? userData?['avatarUrl'], + isOnline: userData?['isOnline'] ?? userData?['IsOnline'] ?? false, + lastSeen: _parseDateTime(userData?['lastSeen'] ?? userData?['LastSeen']), ); }).toList(); - final lastMsgJson = json['lastMessage'] ?? (json['messages'] as List?)?.firstOrNull; + dynamic lastMsgRaw = json['lastMessage']; + if (lastMsgRaw is List && lastMsgRaw.isNotEmpty) { + lastMsgRaw = lastMsgRaw.first; + } + final lastMsgJson = lastMsgRaw ?? (json['messages'] as List?)?.firstOrNull; final type = json['type']?.toString().toLowerCase() ?? 'personal'; String title = json['name'] ?? ''; @@ -171,21 +178,36 @@ class ChatRemoteDataSourceImpl implements ChatRemoteDataSource { participants: members, unreadCount: json['unreadCount'] ?? 0, isPinned: json['isPinned'] ?? false, - lastMessage: lastMsgJson != null ? _mapMessageJson(lastMsgJson) : null, - lastMessageTime: lastMsgJson != null ? DateTime.parse(lastMsgJson['createdAt']) : null, + lastMessage: lastMsgJson != null && lastMsgJson is Map + ? _mapMessageJson(lastMsgJson) + : null, + lastMessageTime: lastMsgJson != null && lastMsgJson is Map + ? _parseDateTime(lastMsgJson['createdAt']) + : null, ); } Message _mapMessageJson(Map json) { return Message( - id: json['id'], - chatId: json['chatId'], - senderId: json['senderId'], + id: json['id'] ?? '', + chatId: json['chatId'] ?? '', + senderId: json['userId'] ?? (json['senderId'] ?? ''), content: json['content'] ?? '', - messageType: json['type'] ?? 'Text', - createdAt: json['createdAt'] != null ? DateTime.parse(json['createdAt']) : null, - updatedAt: json['updatedAt'] != null ? DateTime.parse(json['updatedAt']) : null, - isRead: (json['readBy'] as List?)?.isNotEmpty ?? false, + messageType: json['type']?.toString().toLowerCase() ?? 'text', + createdAt: _parseDateTime(json['createdAt']), + updatedAt: _parseDateTime(json['updatedAt']), + isRead: json['isRead'] ?? false, + media: json['media'] is Map ? json['media'] as Map : null, ); } + + DateTime? _parseDateTime(String? dateStr) { + if (dateStr == null) return null; + // If it doesn't have a timezone indicator, assume it's UTC + String normalized = dateStr; + if (!normalized.endsWith('Z') && !normalized.contains('+')) { + normalized += 'Z'; + } + return DateTime.parse(normalized).toLocal(); + } } 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 aab3b30..99bd5ca 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 @@ -21,6 +21,12 @@ class ChatRepositoryImpl implements ChatRepository { @override Stream get messageStream => signalRService.messages; + @override + Stream> get typingStream => signalRService.typingUpdates; + + @override + Future sendTypingStatus(String chatId, bool isTyping) => signalRService.sendTypingStatus(chatId, isTyping); + @override Future initSignalR() => signalRService.init(); @@ -29,6 +35,8 @@ class ChatRepositoryImpl implements ChatRepository { @override Future>> getChats({String? currentUserId}) async { + // ignore: avoid_print + print('[DEBUG] ChatRepository.getChats for user: $currentUserId'); // 1. Return cached chats immediately if available final cachedResult = await localDataSource.getCachedChats(); @@ -36,10 +44,14 @@ class ChatRepositoryImpl implements ChatRepository { final remoteResult = await remoteDataSource.getChats(currentUserId: currentUserId); if (remoteResult.isSuccess) { final chats = remoteResult.data!; + // ignore: avoid_print + print('[DEBUG] Remote getChats success: ${chats.length} chats'); await localDataSource.cacheChats(chats); return Result.success(chats); } + // ignore: avoid_print + print('[DEBUG] Remote getChats failed or empty'); // If remote fails, return cached or error return cachedResult; } @@ -97,13 +109,19 @@ class ChatRepositoryImpl implements ChatRepository { @override Future>> getMessages(String chatId, {String? cursor}) async { + // ignore: avoid_print + print('[DEBUG] ChatRepository.getMessages for chat: $chatId'); if (cursor == null) { final cached = await localDataSource.getMessagesFromCache(chatId); final remote = await remoteDataSource.getMessages(chatId); if (remote.isSuccess) { + // ignore: avoid_print + print('[DEBUG] Remote getMessages success: ${remote.data!.length} messages'); await localDataSource.cacheMessages(chatId, remote.data!); return remote; } + // ignore: avoid_print + print('[DEBUG] Remote getMessages failed: ${remote.failure?.message}'); return cached; } else { return remoteDataSource.getMessages(chatId, cursor: cursor); @@ -130,4 +148,7 @@ class ChatRepositoryImpl implements ChatRepository { } return result; } + + @override + Future> clearCache() => localDataSource.clearCache(); } diff --git a/client-mobile/lib/features/chat/domain/repositories/chat_repository.dart b/client-mobile/lib/features/chat/domain/repositories/chat_repository.dart index a0e7605..11c7a31 100644 --- a/client-mobile/lib/features/chat/domain/repositories/chat_repository.dart +++ b/client-mobile/lib/features/chat/domain/repositories/chat_repository.dart @@ -12,8 +12,11 @@ abstract class ChatRepository { Future>> getMessages(String chatId, {String? cursor}); Future> togglePin(String chatId); Future> clearChat(String chatId); + Future> clearCache(); Stream get messageStream; + Stream> get typingStream; + Future sendTypingStatus(String chatId, bool isTyping); Future initSignalR(); Future disposeSignalR(); } 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 40cf70e..6cdb608 100644 --- a/client-mobile/lib/features/chat/presentation/bloc/chat_bloc.dart +++ b/client-mobile/lib/features/chat/presentation/bloc/chat_bloc.dart @@ -9,6 +9,7 @@ import 'chat_state.dart'; class ChatBloc extends Bloc { final ChatRepository chatRepository; StreamSubscription? _messageSubscription; + StreamSubscription? _typingSubscription; ChatBloc({required this.chatRepository}) : super(const ChatState.initial()) { on(_onStarted); @@ -17,20 +18,29 @@ class ChatBloc extends Bloc { on(_onMessagesRequested); on(_onMessageSent); on(_onFavoritesRequested); + on(_onTypingUpdated); + on(_onSendTypingStatus); + on(_onCacheCleared); _messageSubscription = chatRepository.messageStream.listen((message) { - // Handle real-time messages add(ChatEvent.messagesRequested(message.chatId)); }); + + _typingSubscription = chatRepository.typingStream.listen((data) { + add(ChatEvent.typingUpdated(data['chatId'], data['userId'], data['isTyping'])); + }); } Future _onStarted(ChatEventStarted event, Emitter emit) async { + // ignore: avoid_print + print('[DEBUG] ChatBloc._onStarted for user: ${event.userId}'); // Start SignalR in background chatRepository.initSignalR().catchError((e) { // Log or handle SignalR init error }); // Immediately trigger chats loading - add(const ChatEvent.chatsLoaded()); + add(ChatEvent.chatsLoaded(currentUserId: event.userId)); + add(const ChatEvent.favoritesRequested()); } Future _onChatsLoaded(ChatEventChatsLoaded event, Emitter emit) async { @@ -83,9 +93,42 @@ class ChatBloc extends Bloc { ); } + Future _onTypingUpdated(ChatEventTypingUpdated event, Emitter emit) async { + final Map> newTypingUsers = Map.from(state.typingUsers); + final Set chatTypingUsers = Set.from(newTypingUsers[event.chatId] ?? {}); + + if (event.isTyping) { + chatTypingUsers.add(event.userId); + } else { + chatTypingUsers.remove(event.userId); + } + + if (chatTypingUsers.isEmpty) { + newTypingUsers.remove(event.chatId); + } else { + newTypingUsers[event.chatId] = chatTypingUsers; + } + + emit(state.copyWith(typingUsers: newTypingUsers)); + } + + Future _onSendTypingStatus(ChatEventSendTypingStatus event, Emitter emit) async { + await chatRepository.sendTypingStatus(event.chatId, event.isTyping); + } + + Future _onCacheCleared(ChatEventCacheCleared event, Emitter emit) async { + // ignore: avoid_print + print('[DEBUG] ChatBloc._onCacheCleared START'); + await chatRepository.clearCache(); + // ignore: avoid_print + print('[DEBUG] ChatBloc._onCacheCleared END'); + emit(const ChatState.initial()); + } + @override Future close() { _messageSubscription?.cancel(); + _typingSubscription?.cancel(); chatRepository.disposeSignalR(); return super.close(); } 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 2826f5c..778f097 100644 --- a/client-mobile/lib/features/chat/presentation/bloc/chat_event.dart +++ b/client-mobile/lib/features/chat/presentation/bloc/chat_event.dart @@ -4,10 +4,13 @@ part 'chat_event.freezed.dart'; @freezed class ChatEvent with _$ChatEvent { - const factory ChatEvent.started() = ChatEventStarted; + const factory ChatEvent.started({String? userId}) = ChatEventStarted; 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.messageSent(String chatId, String content) = ChatEventMessageSent; const factory ChatEvent.favoritesRequested() = ChatEventFavoritesRequested; + const factory ChatEvent.typingUpdated(String chatId, String userId, bool isTyping) = ChatEventTypingUpdated; + const factory ChatEvent.sendTypingStatus(String chatId, bool isTyping) = ChatEventSendTypingStatus; + const factory ChatEvent.cacheCleared() = ChatEventCacheCleared; } 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 6f14888..e796178 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 @@ -18,32 +18,44 @@ final _privateConstructorUsedError = UnsupportedError( mixin _$ChatEvent { @optionalTypeArgs TResult when({ - required TResult Function() started, + 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(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, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ - TResult? Function()? started, + TResult? Function(String? userId)? started, TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, 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, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ - TResult Function()? started, + TResult Function(String? userId)? started, TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, 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(), }) => throw _privateConstructorUsedError; @@ -57,6 +69,9 @@ mixin _$ChatEvent { 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, }) => throw _privateConstructorUsedError; @optionalTypeArgs @@ -67,6 +82,9 @@ mixin _$ChatEvent { TResult? Function(ChatEventMessagesRequested value)? messagesRequested, 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, }) => throw _privateConstructorUsedError; @optionalTypeArgs @@ -77,6 +95,9 @@ mixin _$ChatEvent { TResult Function(ChatEventMessagesRequested value)? messagesRequested, 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(), }) => throw _privateConstructorUsedError; @@ -104,6 +125,8 @@ abstract class _$$ChatEventStartedImplCopyWith<$Res> { factory _$$ChatEventStartedImplCopyWith(_$ChatEventStartedImpl value, $Res Function(_$ChatEventStartedImpl) then) = __$$ChatEventStartedImplCopyWithImpl<$Res>; + @useResult + $Res call({String? userId}); } /// @nodoc @@ -113,66 +136,103 @@ class __$$ChatEventStartedImplCopyWithImpl<$Res> __$$ChatEventStartedImplCopyWithImpl(_$ChatEventStartedImpl _value, $Res Function(_$ChatEventStartedImpl) _then) : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? userId = freezed, + }) { + return _then(_$ChatEventStartedImpl( + userId: freezed == userId + ? _value.userId + : userId // ignore: cast_nullable_to_non_nullable + as String?, + )); + } } /// @nodoc class _$ChatEventStartedImpl implements ChatEventStarted { - const _$ChatEventStartedImpl(); + const _$ChatEventStartedImpl({this.userId}); + + @override + final String? userId; @override String toString() { - return 'ChatEvent.started()'; + return 'ChatEvent.started(userId: $userId)'; } @override bool operator ==(Object other) { return identical(this, other) || - (other.runtimeType == runtimeType && other is _$ChatEventStartedImpl); + (other.runtimeType == runtimeType && + other is _$ChatEventStartedImpl && + (identical(other.userId, userId) || other.userId == userId)); } @override - int get hashCode => runtimeType.hashCode; + int get hashCode => Object.hash(runtimeType, userId); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatEventStartedImplCopyWith<_$ChatEventStartedImpl> get copyWith => + __$$ChatEventStartedImplCopyWithImpl<_$ChatEventStartedImpl>( + this, _$identity); @override @optionalTypeArgs TResult when({ - required TResult Function() started, + 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(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 started(); + return started(userId); } @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function()? started, + TResult? Function(String? userId)? started, TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, 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 started?.call(); + return started?.call(userId); } @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? started, + TResult Function(String? userId)? started, TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, 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 (started != null) { - return started(); + return started(userId); } return orElse(); } @@ -188,6 +248,9 @@ class _$ChatEventStartedImpl implements ChatEventStarted { 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 started(this); } @@ -201,6 +264,9 @@ class _$ChatEventStartedImpl implements ChatEventStarted { TResult? Function(ChatEventMessagesRequested value)? messagesRequested, 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 started?.call(this); } @@ -214,6 +280,9 @@ class _$ChatEventStartedImpl implements ChatEventStarted { TResult Function(ChatEventMessagesRequested value)? messagesRequested, 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 (started != null) { @@ -224,7 +293,13 @@ class _$ChatEventStartedImpl implements ChatEventStarted { } abstract class ChatEventStarted implements ChatEvent { - const factory ChatEventStarted() = _$ChatEventStartedImpl; + const factory ChatEventStarted({final String? userId}) = + _$ChatEventStartedImpl; + + String? get userId; + @JsonKey(ignore: true) + _$$ChatEventStartedImplCopyWith<_$ChatEventStartedImpl> get copyWith => + throw _privateConstructorUsedError; } /// @nodoc @@ -294,12 +369,16 @@ class _$ChatEventChatsLoadedImpl implements ChatEventChatsLoaded { @override @optionalTypeArgs TResult when({ - required TResult Function() started, + 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(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 chatsLoaded(currentUserId); } @@ -307,12 +386,16 @@ class _$ChatEventChatsLoadedImpl implements ChatEventChatsLoaded { @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function()? started, + TResult? Function(String? userId)? started, TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, 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 chatsLoaded?.call(currentUserId); } @@ -320,12 +403,16 @@ class _$ChatEventChatsLoadedImpl implements ChatEventChatsLoaded { @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? started, + TResult Function(String? userId)? started, TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, 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 (chatsLoaded != null) { @@ -345,6 +432,9 @@ class _$ChatEventChatsLoadedImpl implements ChatEventChatsLoaded { 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 chatsLoaded(this); } @@ -358,6 +448,9 @@ class _$ChatEventChatsLoadedImpl implements ChatEventChatsLoaded { TResult? Function(ChatEventMessagesRequested value)? messagesRequested, 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 chatsLoaded?.call(this); } @@ -371,6 +464,9 @@ class _$ChatEventChatsLoadedImpl implements ChatEventChatsLoaded { TResult Function(ChatEventMessagesRequested value)? messagesRequested, 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 (chatsLoaded != null) { @@ -456,12 +552,16 @@ class _$ChatEventChatSelectedImpl implements ChatEventChatSelected { @override @optionalTypeArgs TResult when({ - required TResult Function() started, + 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(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 chatSelected(chatId); } @@ -469,12 +569,16 @@ class _$ChatEventChatSelectedImpl implements ChatEventChatSelected { @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function()? started, + TResult? Function(String? userId)? started, TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, 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 chatSelected?.call(chatId); } @@ -482,12 +586,16 @@ class _$ChatEventChatSelectedImpl implements ChatEventChatSelected { @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? started, + TResult Function(String? userId)? started, TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, 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 (chatSelected != null) { @@ -507,6 +615,9 @@ class _$ChatEventChatSelectedImpl implements ChatEventChatSelected { 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 chatSelected(this); } @@ -520,6 +631,9 @@ class _$ChatEventChatSelectedImpl implements ChatEventChatSelected { TResult? Function(ChatEventMessagesRequested value)? messagesRequested, 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 chatSelected?.call(this); } @@ -533,6 +647,9 @@ class _$ChatEventChatSelectedImpl implements ChatEventChatSelected { TResult Function(ChatEventMessagesRequested value)? messagesRequested, 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 (chatSelected != null) { @@ -627,12 +744,16 @@ class _$ChatEventMessagesRequestedImpl implements ChatEventMessagesRequested { @override @optionalTypeArgs TResult when({ - required TResult Function() started, + 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(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 messagesRequested(chatId, cursor); } @@ -640,12 +761,16 @@ class _$ChatEventMessagesRequestedImpl implements ChatEventMessagesRequested { @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function()? started, + TResult? Function(String? userId)? started, TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, 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 messagesRequested?.call(chatId, cursor); } @@ -653,12 +778,16 @@ class _$ChatEventMessagesRequestedImpl implements ChatEventMessagesRequested { @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? started, + TResult Function(String? userId)? started, TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, 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 (messagesRequested != null) { @@ -678,6 +807,9 @@ class _$ChatEventMessagesRequestedImpl implements ChatEventMessagesRequested { 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 messagesRequested(this); } @@ -691,6 +823,9 @@ class _$ChatEventMessagesRequestedImpl implements ChatEventMessagesRequested { TResult? Function(ChatEventMessagesRequested value)? messagesRequested, 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 messagesRequested?.call(this); } @@ -704,6 +839,9 @@ class _$ChatEventMessagesRequestedImpl implements ChatEventMessagesRequested { TResult Function(ChatEventMessagesRequested value)? messagesRequested, 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 (messagesRequested != null) { @@ -798,12 +936,16 @@ class _$ChatEventMessageSentImpl implements ChatEventMessageSent { @override @optionalTypeArgs TResult when({ - required TResult Function() started, + 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(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 messageSent(chatId, content); } @@ -811,12 +953,16 @@ class _$ChatEventMessageSentImpl implements ChatEventMessageSent { @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function()? started, + TResult? Function(String? userId)? started, TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, 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 messageSent?.call(chatId, content); } @@ -824,12 +970,16 @@ class _$ChatEventMessageSentImpl implements ChatEventMessageSent { @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? started, + TResult Function(String? userId)? started, TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, 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 (messageSent != null) { @@ -849,6 +999,9 @@ class _$ChatEventMessageSentImpl implements ChatEventMessageSent { 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 messageSent(this); } @@ -862,6 +1015,9 @@ class _$ChatEventMessageSentImpl implements ChatEventMessageSent { TResult? Function(ChatEventMessagesRequested value)? messagesRequested, 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 messageSent?.call(this); } @@ -875,6 +1031,9 @@ class _$ChatEventMessageSentImpl implements ChatEventMessageSent { TResult Function(ChatEventMessagesRequested value)? messagesRequested, 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 (messageSent != null) { @@ -936,12 +1095,16 @@ class _$ChatEventFavoritesRequestedImpl implements ChatEventFavoritesRequested { @override @optionalTypeArgs TResult when({ - required TResult Function() started, + 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(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 favoritesRequested(); } @@ -949,12 +1112,16 @@ class _$ChatEventFavoritesRequestedImpl implements ChatEventFavoritesRequested { @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function()? started, + TResult? Function(String? userId)? started, TResult? Function(String? currentUserId)? chatsLoaded, TResult? Function(String chatId)? chatSelected, TResult? Function(String chatId, String? cursor)? messagesRequested, 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 favoritesRequested?.call(); } @@ -962,12 +1129,16 @@ class _$ChatEventFavoritesRequestedImpl implements ChatEventFavoritesRequested { @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? started, + TResult Function(String? userId)? started, TResult Function(String? currentUserId)? chatsLoaded, TResult Function(String chatId)? chatSelected, TResult Function(String chatId, String? cursor)? messagesRequested, 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 (favoritesRequested != null) { @@ -987,6 +1158,9 @@ class _$ChatEventFavoritesRequestedImpl implements ChatEventFavoritesRequested { 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 favoritesRequested(this); } @@ -1000,6 +1174,9 @@ class _$ChatEventFavoritesRequestedImpl implements ChatEventFavoritesRequested { TResult? Function(ChatEventMessagesRequested value)? messagesRequested, 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 favoritesRequested?.call(this); } @@ -1013,6 +1190,9 @@ class _$ChatEventFavoritesRequestedImpl implements ChatEventFavoritesRequested { TResult Function(ChatEventMessagesRequested value)? messagesRequested, 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 (favoritesRequested != null) { @@ -1026,3 +1206,553 @@ abstract class ChatEventFavoritesRequested implements ChatEvent { const factory ChatEventFavoritesRequested() = _$ChatEventFavoritesRequestedImpl; } + +/// @nodoc +abstract class _$$ChatEventTypingUpdatedImplCopyWith<$Res> { + factory _$$ChatEventTypingUpdatedImplCopyWith( + _$ChatEventTypingUpdatedImpl value, + $Res Function(_$ChatEventTypingUpdatedImpl) then) = + __$$ChatEventTypingUpdatedImplCopyWithImpl<$Res>; + @useResult + $Res call({String chatId, String userId, bool isTyping}); +} + +/// @nodoc +class __$$ChatEventTypingUpdatedImplCopyWithImpl<$Res> + extends _$ChatEventCopyWithImpl<$Res, _$ChatEventTypingUpdatedImpl> + implements _$$ChatEventTypingUpdatedImplCopyWith<$Res> { + __$$ChatEventTypingUpdatedImplCopyWithImpl( + _$ChatEventTypingUpdatedImpl _value, + $Res Function(_$ChatEventTypingUpdatedImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? chatId = null, + Object? userId = null, + Object? isTyping = null, + }) { + return _then(_$ChatEventTypingUpdatedImpl( + null == chatId + ? _value.chatId + : chatId // ignore: cast_nullable_to_non_nullable + as String, + null == userId + ? _value.userId + : userId // ignore: cast_nullable_to_non_nullable + as String, + null == isTyping + ? _value.isTyping + : isTyping // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc + +class _$ChatEventTypingUpdatedImpl implements ChatEventTypingUpdated { + const _$ChatEventTypingUpdatedImpl(this.chatId, this.userId, this.isTyping); + + @override + final String chatId; + @override + final String userId; + @override + final bool isTyping; + + @override + String toString() { + return 'ChatEvent.typingUpdated(chatId: $chatId, userId: $userId, isTyping: $isTyping)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatEventTypingUpdatedImpl && + (identical(other.chatId, chatId) || other.chatId == chatId) && + (identical(other.userId, userId) || other.userId == userId) && + (identical(other.isTyping, isTyping) || + other.isTyping == isTyping)); + } + + @override + int get hashCode => Object.hash(runtimeType, chatId, userId, isTyping); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatEventTypingUpdatedImplCopyWith<_$ChatEventTypingUpdatedImpl> + get copyWith => __$$ChatEventTypingUpdatedImplCopyWithImpl< + _$ChatEventTypingUpdatedImpl>(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(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 typingUpdated(chatId, userId, isTyping); + } + + @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(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 typingUpdated?.call(chatId, userId, isTyping); + } + + @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(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 (typingUpdated != null) { + return typingUpdated(chatId, userId, isTyping); + } + 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(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 typingUpdated(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(ChatEventMessageSent value)? messageSent, + TResult? Function(ChatEventFavoritesRequested value)? favoritesRequested, + TResult? Function(ChatEventTypingUpdated value)? typingUpdated, + TResult? Function(ChatEventSendTypingStatus value)? sendTypingStatus, + TResult? Function(ChatEventCacheCleared value)? cacheCleared, + }) { + return typingUpdated?.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(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 (typingUpdated != null) { + return typingUpdated(this); + } + return orElse(); + } +} + +abstract class ChatEventTypingUpdated implements ChatEvent { + const factory ChatEventTypingUpdated( + final String chatId, final String userId, final bool isTyping) = + _$ChatEventTypingUpdatedImpl; + + String get chatId; + String get userId; + bool get isTyping; + @JsonKey(ignore: true) + _$$ChatEventTypingUpdatedImplCopyWith<_$ChatEventTypingUpdatedImpl> + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$ChatEventSendTypingStatusImplCopyWith<$Res> { + factory _$$ChatEventSendTypingStatusImplCopyWith( + _$ChatEventSendTypingStatusImpl value, + $Res Function(_$ChatEventSendTypingStatusImpl) then) = + __$$ChatEventSendTypingStatusImplCopyWithImpl<$Res>; + @useResult + $Res call({String chatId, bool isTyping}); +} + +/// @nodoc +class __$$ChatEventSendTypingStatusImplCopyWithImpl<$Res> + extends _$ChatEventCopyWithImpl<$Res, _$ChatEventSendTypingStatusImpl> + implements _$$ChatEventSendTypingStatusImplCopyWith<$Res> { + __$$ChatEventSendTypingStatusImplCopyWithImpl( + _$ChatEventSendTypingStatusImpl _value, + $Res Function(_$ChatEventSendTypingStatusImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? chatId = null, + Object? isTyping = null, + }) { + return _then(_$ChatEventSendTypingStatusImpl( + null == chatId + ? _value.chatId + : chatId // ignore: cast_nullable_to_non_nullable + as String, + null == isTyping + ? _value.isTyping + : isTyping // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc + +class _$ChatEventSendTypingStatusImpl implements ChatEventSendTypingStatus { + const _$ChatEventSendTypingStatusImpl(this.chatId, this.isTyping); + + @override + final String chatId; + @override + final bool isTyping; + + @override + String toString() { + return 'ChatEvent.sendTypingStatus(chatId: $chatId, isTyping: $isTyping)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatEventSendTypingStatusImpl && + (identical(other.chatId, chatId) || other.chatId == chatId) && + (identical(other.isTyping, isTyping) || + other.isTyping == isTyping)); + } + + @override + int get hashCode => Object.hash(runtimeType, chatId, isTyping); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatEventSendTypingStatusImplCopyWith<_$ChatEventSendTypingStatusImpl> + get copyWith => __$$ChatEventSendTypingStatusImplCopyWithImpl< + _$ChatEventSendTypingStatusImpl>(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(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 sendTypingStatus(chatId, isTyping); + } + + @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(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 sendTypingStatus?.call(chatId, isTyping); + } + + @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(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 (sendTypingStatus != null) { + return sendTypingStatus(chatId, isTyping); + } + 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(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 sendTypingStatus(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(ChatEventMessageSent value)? messageSent, + TResult? Function(ChatEventFavoritesRequested value)? favoritesRequested, + TResult? Function(ChatEventTypingUpdated value)? typingUpdated, + TResult? Function(ChatEventSendTypingStatus value)? sendTypingStatus, + TResult? Function(ChatEventCacheCleared value)? cacheCleared, + }) { + return sendTypingStatus?.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(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 (sendTypingStatus != null) { + return sendTypingStatus(this); + } + return orElse(); + } +} + +abstract class ChatEventSendTypingStatus implements ChatEvent { + const factory ChatEventSendTypingStatus( + final String chatId, final bool isTyping) = + _$ChatEventSendTypingStatusImpl; + + String get chatId; + bool get isTyping; + @JsonKey(ignore: true) + _$$ChatEventSendTypingStatusImplCopyWith<_$ChatEventSendTypingStatusImpl> + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$ChatEventCacheClearedImplCopyWith<$Res> { + factory _$$ChatEventCacheClearedImplCopyWith( + _$ChatEventCacheClearedImpl value, + $Res Function(_$ChatEventCacheClearedImpl) then) = + __$$ChatEventCacheClearedImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$ChatEventCacheClearedImplCopyWithImpl<$Res> + extends _$ChatEventCopyWithImpl<$Res, _$ChatEventCacheClearedImpl> + implements _$$ChatEventCacheClearedImplCopyWith<$Res> { + __$$ChatEventCacheClearedImplCopyWithImpl(_$ChatEventCacheClearedImpl _value, + $Res Function(_$ChatEventCacheClearedImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$ChatEventCacheClearedImpl implements ChatEventCacheCleared { + const _$ChatEventCacheClearedImpl(); + + @override + String toString() { + return 'ChatEvent.cacheCleared()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ChatEventCacheClearedImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @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(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 cacheCleared(); + } + + @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(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 cacheCleared?.call(); + } + + @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(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 (cacheCleared != null) { + return cacheCleared(); + } + 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(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 cacheCleared(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(ChatEventMessageSent value)? messageSent, + TResult? Function(ChatEventFavoritesRequested value)? favoritesRequested, + TResult? Function(ChatEventTypingUpdated value)? typingUpdated, + TResult? Function(ChatEventSendTypingStatus value)? sendTypingStatus, + TResult? Function(ChatEventCacheCleared value)? cacheCleared, + }) { + return cacheCleared?.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(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 (cacheCleared != null) { + return cacheCleared(this); + } + return orElse(); + } +} + +abstract class ChatEventCacheCleared implements ChatEvent { + const factory ChatEventCacheCleared() = _$ChatEventCacheClearedImpl; +} 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 4b6fbae..a6426ef 100644 --- a/client-mobile/lib/features/chat/presentation/bloc/chat_state.dart +++ b/client-mobile/lib/features/chat/presentation/bloc/chat_state.dart @@ -6,10 +6,10 @@ part 'chat_state.freezed.dart'; @freezed class ChatState with _$ChatState { - const factory ChatState.initial() = ChatInitial; - const factory ChatState.loading() = ChatLoading; - const factory ChatState.chatsLoaded(List chats) = _ChatsLoaded; - const factory ChatState.chatSelected(Chat chat, List messages) = _ChatSelected; - const factory ChatState.messagesLoaded(List messages) = _MessagesLoaded; - const factory ChatState.error(String message) = ChatError; + const factory ChatState.initial({@Default({}) Map> typingUsers}) = ChatInitial; + 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.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 ec47ab1..bf6c0b8 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 @@ -16,34 +16,56 @@ final _privateConstructorUsedError = UnsupportedError( /// @nodoc mixin _$ChatState { + Map> get typingUsers => + throw _privateConstructorUsedError; @optionalTypeArgs TResult when({ - required TResult Function() initial, - required TResult Function() loading, - required TResult Function(List chats) chatsLoaded, - required TResult Function(Chat chat, List messages) chatSelected, - required TResult Function(List messages) messagesLoaded, - required TResult Function(String message) error, + required TResult Function(Map> typingUsers) initial, + required TResult Function(Map> typingUsers) loading, + required TResult Function( + List chats, Map> typingUsers) + chatsLoaded, + required TResult Function(Chat chat, List messages, + Map> typingUsers) + chatSelected, + required TResult Function( + List messages, Map> typingUsers) + messagesLoaded, + required TResult Function( + String message, Map> typingUsers) + error, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ - TResult? Function()? initial, - TResult? Function()? loading, - TResult? Function(List chats)? chatsLoaded, - TResult? Function(Chat chat, List messages)? chatSelected, - TResult? Function(List messages)? messagesLoaded, - TResult? Function(String message)? error, + TResult? Function(Map> typingUsers)? initial, + TResult? Function(Map> typingUsers)? loading, + TResult? Function(List chats, Map> typingUsers)? + chatsLoaded, + TResult? Function(Chat chat, List messages, + Map> typingUsers)? + chatSelected, + TResult? Function( + List messages, Map> typingUsers)? + messagesLoaded, + TResult? Function(String message, Map> typingUsers)? + error, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ - TResult Function()? initial, - TResult Function()? loading, - TResult Function(List chats)? chatsLoaded, - TResult Function(Chat chat, List messages)? chatSelected, - TResult Function(List messages)? messagesLoaded, - TResult Function(String message)? error, + TResult Function(Map> typingUsers)? initial, + TResult Function(Map> typingUsers)? loading, + TResult Function(List chats, Map> typingUsers)? + chatsLoaded, + TResult Function(Chat chat, List messages, + Map> typingUsers)? + chatSelected, + TResult Function( + List messages, Map> typingUsers)? + messagesLoaded, + TResult Function(String message, Map> typingUsers)? + error, required TResult orElse(), }) => throw _privateConstructorUsedError; @@ -78,12 +100,18 @@ mixin _$ChatState { required TResult orElse(), }) => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $ChatStateCopyWith get copyWith => + throw _privateConstructorUsedError; } /// @nodoc abstract class $ChatStateCopyWith<$Res> { factory $ChatStateCopyWith(ChatState value, $Res Function(ChatState) then) = _$ChatStateCopyWithImpl<$Res, ChatState>; + @useResult + $Res call({Map> typingUsers}); } /// @nodoc @@ -95,13 +123,30 @@ class _$ChatStateCopyWithImpl<$Res, $Val extends ChatState> final $Val _value; // ignore: unused_field final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? typingUsers = null, + }) { + return _then(_value.copyWith( + typingUsers: null == typingUsers + ? _value.typingUsers + : typingUsers // ignore: cast_nullable_to_non_nullable + as Map>, + ) as $Val); + } } /// @nodoc -abstract class _$$ChatInitialImplCopyWith<$Res> { +abstract class _$$ChatInitialImplCopyWith<$Res> + implements $ChatStateCopyWith<$Res> { factory _$$ChatInitialImplCopyWith( _$ChatInitialImpl value, $Res Function(_$ChatInitialImpl) then) = __$$ChatInitialImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({Map> typingUsers}); } /// @nodoc @@ -111,66 +156,120 @@ class __$$ChatInitialImplCopyWithImpl<$Res> __$$ChatInitialImplCopyWithImpl( _$ChatInitialImpl _value, $Res Function(_$ChatInitialImpl) _then) : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? typingUsers = null, + }) { + return _then(_$ChatInitialImpl( + typingUsers: null == typingUsers + ? _value._typingUsers + : typingUsers // ignore: cast_nullable_to_non_nullable + as Map>, + )); + } } /// @nodoc class _$ChatInitialImpl implements ChatInitial { - const _$ChatInitialImpl(); + const _$ChatInitialImpl( + {final Map> typingUsers = const {}}) + : _typingUsers = typingUsers; + + final Map> _typingUsers; + @override + @JsonKey() + Map> get typingUsers { + if (_typingUsers is EqualUnmodifiableMapView) return _typingUsers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_typingUsers); + } @override String toString() { - return 'ChatState.initial()'; + return 'ChatState.initial(typingUsers: $typingUsers)'; } @override bool operator ==(Object other) { return identical(this, other) || - (other.runtimeType == runtimeType && other is _$ChatInitialImpl); + (other.runtimeType == runtimeType && + other is _$ChatInitialImpl && + const DeepCollectionEquality() + .equals(other._typingUsers, _typingUsers)); } @override - int get hashCode => runtimeType.hashCode; + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_typingUsers)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatInitialImplCopyWith<_$ChatInitialImpl> get copyWith => + __$$ChatInitialImplCopyWithImpl<_$ChatInitialImpl>(this, _$identity); @override @optionalTypeArgs TResult when({ - required TResult Function() initial, - required TResult Function() loading, - required TResult Function(List chats) chatsLoaded, - required TResult Function(Chat chat, List messages) chatSelected, - required TResult Function(List messages) messagesLoaded, - required TResult Function(String message) error, + required TResult Function(Map> typingUsers) initial, + required TResult Function(Map> typingUsers) loading, + required TResult Function( + List chats, Map> typingUsers) + chatsLoaded, + required TResult Function(Chat chat, List messages, + Map> typingUsers) + chatSelected, + required TResult Function( + List messages, Map> typingUsers) + messagesLoaded, + required TResult Function( + String message, Map> typingUsers) + error, }) { - return initial(); + return initial(typingUsers); } @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function()? initial, - TResult? Function()? loading, - TResult? Function(List chats)? chatsLoaded, - TResult? Function(Chat chat, List messages)? chatSelected, - TResult? Function(List messages)? messagesLoaded, - TResult? Function(String message)? error, + TResult? Function(Map> typingUsers)? initial, + TResult? Function(Map> typingUsers)? loading, + TResult? Function(List chats, Map> typingUsers)? + chatsLoaded, + TResult? Function(Chat chat, List messages, + Map> typingUsers)? + chatSelected, + TResult? Function( + List messages, Map> typingUsers)? + messagesLoaded, + TResult? Function(String message, Map> typingUsers)? + error, }) { - return initial?.call(); + return initial?.call(typingUsers); } @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? initial, - TResult Function()? loading, - TResult Function(List chats)? chatsLoaded, - TResult Function(Chat chat, List messages)? chatSelected, - TResult Function(List messages)? messagesLoaded, - TResult Function(String message)? error, + TResult Function(Map> typingUsers)? initial, + TResult Function(Map> typingUsers)? loading, + TResult Function(List chats, Map> typingUsers)? + chatsLoaded, + TResult Function(Chat chat, List messages, + Map> typingUsers)? + chatSelected, + TResult Function( + List messages, Map> typingUsers)? + messagesLoaded, + TResult Function(String message, Map> typingUsers)? + error, required TResult orElse(), }) { if (initial != null) { - return initial(); + return initial(typingUsers); } return orElse(); } @@ -220,14 +319,26 @@ class _$ChatInitialImpl implements ChatInitial { } abstract class ChatInitial implements ChatState { - const factory ChatInitial() = _$ChatInitialImpl; + const factory ChatInitial({final Map> typingUsers}) = + _$ChatInitialImpl; + + @override + Map> get typingUsers; + @override + @JsonKey(ignore: true) + _$$ChatInitialImplCopyWith<_$ChatInitialImpl> get copyWith => + throw _privateConstructorUsedError; } /// @nodoc -abstract class _$$ChatLoadingImplCopyWith<$Res> { +abstract class _$$ChatLoadingImplCopyWith<$Res> + implements $ChatStateCopyWith<$Res> { factory _$$ChatLoadingImplCopyWith( _$ChatLoadingImpl value, $Res Function(_$ChatLoadingImpl) then) = __$$ChatLoadingImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({Map> typingUsers}); } /// @nodoc @@ -237,66 +348,120 @@ class __$$ChatLoadingImplCopyWithImpl<$Res> __$$ChatLoadingImplCopyWithImpl( _$ChatLoadingImpl _value, $Res Function(_$ChatLoadingImpl) _then) : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? typingUsers = null, + }) { + return _then(_$ChatLoadingImpl( + typingUsers: null == typingUsers + ? _value._typingUsers + : typingUsers // ignore: cast_nullable_to_non_nullable + as Map>, + )); + } } /// @nodoc class _$ChatLoadingImpl implements ChatLoading { - const _$ChatLoadingImpl(); + const _$ChatLoadingImpl( + {final Map> typingUsers = const {}}) + : _typingUsers = typingUsers; + + final Map> _typingUsers; + @override + @JsonKey() + Map> get typingUsers { + if (_typingUsers is EqualUnmodifiableMapView) return _typingUsers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_typingUsers); + } @override String toString() { - return 'ChatState.loading()'; + return 'ChatState.loading(typingUsers: $typingUsers)'; } @override bool operator ==(Object other) { return identical(this, other) || - (other.runtimeType == runtimeType && other is _$ChatLoadingImpl); + (other.runtimeType == runtimeType && + other is _$ChatLoadingImpl && + const DeepCollectionEquality() + .equals(other._typingUsers, _typingUsers)); } @override - int get hashCode => runtimeType.hashCode; + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_typingUsers)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ChatLoadingImplCopyWith<_$ChatLoadingImpl> get copyWith => + __$$ChatLoadingImplCopyWithImpl<_$ChatLoadingImpl>(this, _$identity); @override @optionalTypeArgs TResult when({ - required TResult Function() initial, - required TResult Function() loading, - required TResult Function(List chats) chatsLoaded, - required TResult Function(Chat chat, List messages) chatSelected, - required TResult Function(List messages) messagesLoaded, - required TResult Function(String message) error, + required TResult Function(Map> typingUsers) initial, + required TResult Function(Map> typingUsers) loading, + required TResult Function( + List chats, Map> typingUsers) + chatsLoaded, + required TResult Function(Chat chat, List messages, + Map> typingUsers) + chatSelected, + required TResult Function( + List messages, Map> typingUsers) + messagesLoaded, + required TResult Function( + String message, Map> typingUsers) + error, }) { - return loading(); + return loading(typingUsers); } @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function()? initial, - TResult? Function()? loading, - TResult? Function(List chats)? chatsLoaded, - TResult? Function(Chat chat, List messages)? chatSelected, - TResult? Function(List messages)? messagesLoaded, - TResult? Function(String message)? error, + TResult? Function(Map> typingUsers)? initial, + TResult? Function(Map> typingUsers)? loading, + TResult? Function(List chats, Map> typingUsers)? + chatsLoaded, + TResult? Function(Chat chat, List messages, + Map> typingUsers)? + chatSelected, + TResult? Function( + List messages, Map> typingUsers)? + messagesLoaded, + TResult? Function(String message, Map> typingUsers)? + error, }) { - return loading?.call(); + return loading?.call(typingUsers); } @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? initial, - TResult Function()? loading, - TResult Function(List chats)? chatsLoaded, - TResult Function(Chat chat, List messages)? chatSelected, - TResult Function(List messages)? messagesLoaded, - TResult Function(String message)? error, + TResult Function(Map> typingUsers)? initial, + TResult Function(Map> typingUsers)? loading, + TResult Function(List chats, Map> typingUsers)? + chatsLoaded, + TResult Function(Chat chat, List messages, + Map> typingUsers)? + chatSelected, + TResult Function( + List messages, Map> typingUsers)? + messagesLoaded, + TResult Function(String message, Map> typingUsers)? + error, required TResult orElse(), }) { if (loading != null) { - return loading(); + return loading(typingUsers); } return orElse(); } @@ -346,16 +511,26 @@ class _$ChatLoadingImpl implements ChatLoading { } abstract class ChatLoading implements ChatState { - const factory ChatLoading() = _$ChatLoadingImpl; + const factory ChatLoading({final Map> typingUsers}) = + _$ChatLoadingImpl; + + @override + Map> get typingUsers; + @override + @JsonKey(ignore: true) + _$$ChatLoadingImplCopyWith<_$ChatLoadingImpl> get copyWith => + throw _privateConstructorUsedError; } /// @nodoc -abstract class _$$ChatsLoadedImplCopyWith<$Res> { +abstract class _$$ChatsLoadedImplCopyWith<$Res> + implements $ChatStateCopyWith<$Res> { factory _$$ChatsLoadedImplCopyWith( _$ChatsLoadedImpl value, $Res Function(_$ChatsLoadedImpl) then) = __$$ChatsLoadedImplCopyWithImpl<$Res>; + @override @useResult - $Res call({List chats}); + $Res call({List chats, Map> typingUsers}); } /// @nodoc @@ -370,12 +545,17 @@ class __$$ChatsLoadedImplCopyWithImpl<$Res> @override $Res call({ Object? chats = null, + Object? typingUsers = null, }) { return _then(_$ChatsLoadedImpl( null == chats ? _value._chats : chats // ignore: cast_nullable_to_non_nullable as List, + typingUsers: null == typingUsers + ? _value._typingUsers + : typingUsers // ignore: cast_nullable_to_non_nullable + as Map>, )); } } @@ -383,7 +563,10 @@ class __$$ChatsLoadedImplCopyWithImpl<$Res> /// @nodoc class _$ChatsLoadedImpl implements _ChatsLoaded { - const _$ChatsLoadedImpl(final List chats) : _chats = chats; + const _$ChatsLoadedImpl(final List chats, + {final Map> typingUsers = const {}}) + : _chats = chats, + _typingUsers = typingUsers; final List _chats; @override @@ -393,9 +576,18 @@ class _$ChatsLoadedImpl implements _ChatsLoaded { return EqualUnmodifiableListView(_chats); } + final Map> _typingUsers; + @override + @JsonKey() + Map> get typingUsers { + if (_typingUsers is EqualUnmodifiableMapView) return _typingUsers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_typingUsers); + } + @override String toString() { - return 'ChatState.chatsLoaded(chats: $chats)'; + return 'ChatState.chatsLoaded(chats: $chats, typingUsers: $typingUsers)'; } @override @@ -403,12 +595,16 @@ class _$ChatsLoadedImpl implements _ChatsLoaded { return identical(this, other) || (other.runtimeType == runtimeType && other is _$ChatsLoadedImpl && - const DeepCollectionEquality().equals(other._chats, _chats)); + const DeepCollectionEquality().equals(other._chats, _chats) && + const DeepCollectionEquality() + .equals(other._typingUsers, _typingUsers)); } @override - int get hashCode => - Object.hash(runtimeType, const DeepCollectionEquality().hash(_chats)); + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(_chats), + const DeepCollectionEquality().hash(_typingUsers)); @JsonKey(ignore: true) @override @@ -419,42 +615,62 @@ class _$ChatsLoadedImpl implements _ChatsLoaded { @override @optionalTypeArgs TResult when({ - required TResult Function() initial, - required TResult Function() loading, - required TResult Function(List chats) chatsLoaded, - required TResult Function(Chat chat, List messages) chatSelected, - required TResult Function(List messages) messagesLoaded, - required TResult Function(String message) error, + required TResult Function(Map> typingUsers) initial, + required TResult Function(Map> typingUsers) loading, + required TResult Function( + List chats, Map> typingUsers) + chatsLoaded, + required TResult Function(Chat chat, List messages, + Map> typingUsers) + chatSelected, + required TResult Function( + List messages, Map> typingUsers) + messagesLoaded, + required TResult Function( + String message, Map> typingUsers) + error, }) { - return chatsLoaded(chats); + return chatsLoaded(chats, typingUsers); } @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function()? initial, - TResult? Function()? loading, - TResult? Function(List chats)? chatsLoaded, - TResult? Function(Chat chat, List messages)? chatSelected, - TResult? Function(List messages)? messagesLoaded, - TResult? Function(String message)? error, + TResult? Function(Map> typingUsers)? initial, + TResult? Function(Map> typingUsers)? loading, + TResult? Function(List chats, Map> typingUsers)? + chatsLoaded, + TResult? Function(Chat chat, List messages, + Map> typingUsers)? + chatSelected, + TResult? Function( + List messages, Map> typingUsers)? + messagesLoaded, + TResult? Function(String message, Map> typingUsers)? + error, }) { - return chatsLoaded?.call(chats); + return chatsLoaded?.call(chats, typingUsers); } @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? initial, - TResult Function()? loading, - TResult Function(List chats)? chatsLoaded, - TResult Function(Chat chat, List messages)? chatSelected, - TResult Function(List messages)? messagesLoaded, - TResult Function(String message)? error, + TResult Function(Map> typingUsers)? initial, + TResult Function(Map> typingUsers)? loading, + TResult Function(List chats, Map> typingUsers)? + chatsLoaded, + TResult Function(Chat chat, List messages, + Map> typingUsers)? + chatSelected, + TResult Function( + List messages, Map> typingUsers)? + messagesLoaded, + TResult Function(String message, Map> typingUsers)? + error, required TResult orElse(), }) { if (chatsLoaded != null) { - return chatsLoaded(chats); + return chatsLoaded(chats, typingUsers); } return orElse(); } @@ -504,21 +720,30 @@ class _$ChatsLoadedImpl implements _ChatsLoaded { } abstract class _ChatsLoaded implements ChatState { - const factory _ChatsLoaded(final List chats) = _$ChatsLoadedImpl; + const factory _ChatsLoaded(final List chats, + {final Map> typingUsers}) = _$ChatsLoadedImpl; List get chats; + @override + Map> get typingUsers; + @override @JsonKey(ignore: true) _$$ChatsLoadedImplCopyWith<_$ChatsLoadedImpl> get copyWith => throw _privateConstructorUsedError; } /// @nodoc -abstract class _$$ChatSelectedImplCopyWith<$Res> { +abstract class _$$ChatSelectedImplCopyWith<$Res> + implements $ChatStateCopyWith<$Res> { factory _$$ChatSelectedImplCopyWith( _$ChatSelectedImpl value, $Res Function(_$ChatSelectedImpl) then) = __$$ChatSelectedImplCopyWithImpl<$Res>; + @override @useResult - $Res call({Chat chat, List messages}); + $Res call( + {Chat chat, + List messages, + Map> typingUsers}); $ChatCopyWith<$Res> get chat; } @@ -536,6 +761,7 @@ class __$$ChatSelectedImplCopyWithImpl<$Res> $Res call({ Object? chat = null, Object? messages = null, + Object? typingUsers = null, }) { return _then(_$ChatSelectedImpl( null == chat @@ -546,6 +772,10 @@ class __$$ChatSelectedImplCopyWithImpl<$Res> ? _value._messages : messages // ignore: cast_nullable_to_non_nullable as List, + typingUsers: null == typingUsers + ? _value._typingUsers + : typingUsers // ignore: cast_nullable_to_non_nullable + as Map>, )); } @@ -561,8 +791,10 @@ class __$$ChatSelectedImplCopyWithImpl<$Res> /// @nodoc class _$ChatSelectedImpl implements _ChatSelected { - const _$ChatSelectedImpl(this.chat, final List messages) - : _messages = messages; + const _$ChatSelectedImpl(this.chat, final List messages, + {final Map> typingUsers = const {}}) + : _messages = messages, + _typingUsers = typingUsers; @override final Chat chat; @@ -574,9 +806,18 @@ class _$ChatSelectedImpl implements _ChatSelected { return EqualUnmodifiableListView(_messages); } + final Map> _typingUsers; + @override + @JsonKey() + Map> get typingUsers { + if (_typingUsers is EqualUnmodifiableMapView) return _typingUsers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_typingUsers); + } + @override String toString() { - return 'ChatState.chatSelected(chat: $chat, messages: $messages)'; + return 'ChatState.chatSelected(chat: $chat, messages: $messages, typingUsers: $typingUsers)'; } @override @@ -585,12 +826,17 @@ class _$ChatSelectedImpl implements _ChatSelected { (other.runtimeType == runtimeType && other is _$ChatSelectedImpl && (identical(other.chat, chat) || other.chat == chat) && - const DeepCollectionEquality().equals(other._messages, _messages)); + const DeepCollectionEquality().equals(other._messages, _messages) && + const DeepCollectionEquality() + .equals(other._typingUsers, _typingUsers)); } @override int get hashCode => Object.hash( - runtimeType, chat, const DeepCollectionEquality().hash(_messages)); + runtimeType, + chat, + const DeepCollectionEquality().hash(_messages), + const DeepCollectionEquality().hash(_typingUsers)); @JsonKey(ignore: true) @override @@ -601,42 +847,62 @@ class _$ChatSelectedImpl implements _ChatSelected { @override @optionalTypeArgs TResult when({ - required TResult Function() initial, - required TResult Function() loading, - required TResult Function(List chats) chatsLoaded, - required TResult Function(Chat chat, List messages) chatSelected, - required TResult Function(List messages) messagesLoaded, - required TResult Function(String message) error, + required TResult Function(Map> typingUsers) initial, + required TResult Function(Map> typingUsers) loading, + required TResult Function( + List chats, Map> typingUsers) + chatsLoaded, + required TResult Function(Chat chat, List messages, + Map> typingUsers) + chatSelected, + required TResult Function( + List messages, Map> typingUsers) + messagesLoaded, + required TResult Function( + String message, Map> typingUsers) + error, }) { - return chatSelected(chat, messages); + return chatSelected(chat, messages, typingUsers); } @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function()? initial, - TResult? Function()? loading, - TResult? Function(List chats)? chatsLoaded, - TResult? Function(Chat chat, List messages)? chatSelected, - TResult? Function(List messages)? messagesLoaded, - TResult? Function(String message)? error, + TResult? Function(Map> typingUsers)? initial, + TResult? Function(Map> typingUsers)? loading, + TResult? Function(List chats, Map> typingUsers)? + chatsLoaded, + TResult? Function(Chat chat, List messages, + Map> typingUsers)? + chatSelected, + TResult? Function( + List messages, Map> typingUsers)? + messagesLoaded, + TResult? Function(String message, Map> typingUsers)? + error, }) { - return chatSelected?.call(chat, messages); + return chatSelected?.call(chat, messages, typingUsers); } @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? initial, - TResult Function()? loading, - TResult Function(List chats)? chatsLoaded, - TResult Function(Chat chat, List messages)? chatSelected, - TResult Function(List messages)? messagesLoaded, - TResult Function(String message)? error, + TResult Function(Map> typingUsers)? initial, + TResult Function(Map> typingUsers)? loading, + TResult Function(List chats, Map> typingUsers)? + chatsLoaded, + TResult Function(Chat chat, List messages, + Map> typingUsers)? + chatSelected, + TResult Function( + List messages, Map> typingUsers)? + messagesLoaded, + TResult Function(String message, Map> typingUsers)? + error, required TResult orElse(), }) { if (chatSelected != null) { - return chatSelected(chat, messages); + return chatSelected(chat, messages, typingUsers); } return orElse(); } @@ -686,23 +952,28 @@ class _$ChatSelectedImpl implements _ChatSelected { } abstract class _ChatSelected implements ChatState { - const factory _ChatSelected(final Chat chat, final List messages) = - _$ChatSelectedImpl; + const factory _ChatSelected(final Chat chat, final List messages, + {final Map> typingUsers}) = _$ChatSelectedImpl; Chat get chat; List get messages; + @override + Map> get typingUsers; + @override @JsonKey(ignore: true) _$$ChatSelectedImplCopyWith<_$ChatSelectedImpl> get copyWith => throw _privateConstructorUsedError; } /// @nodoc -abstract class _$$MessagesLoadedImplCopyWith<$Res> { +abstract class _$$MessagesLoadedImplCopyWith<$Res> + implements $ChatStateCopyWith<$Res> { factory _$$MessagesLoadedImplCopyWith(_$MessagesLoadedImpl value, $Res Function(_$MessagesLoadedImpl) then) = __$$MessagesLoadedImplCopyWithImpl<$Res>; + @override @useResult - $Res call({List messages}); + $Res call({List messages, Map> typingUsers}); } /// @nodoc @@ -717,12 +988,17 @@ class __$$MessagesLoadedImplCopyWithImpl<$Res> @override $Res call({ Object? messages = null, + Object? typingUsers = null, }) { return _then(_$MessagesLoadedImpl( null == messages ? _value._messages : messages // ignore: cast_nullable_to_non_nullable as List, + typingUsers: null == typingUsers + ? _value._typingUsers + : typingUsers // ignore: cast_nullable_to_non_nullable + as Map>, )); } } @@ -730,8 +1006,10 @@ class __$$MessagesLoadedImplCopyWithImpl<$Res> /// @nodoc class _$MessagesLoadedImpl implements _MessagesLoaded { - const _$MessagesLoadedImpl(final List messages) - : _messages = messages; + const _$MessagesLoadedImpl(final List messages, + {final Map> typingUsers = const {}}) + : _messages = messages, + _typingUsers = typingUsers; final List _messages; @override @@ -741,9 +1019,18 @@ class _$MessagesLoadedImpl implements _MessagesLoaded { return EqualUnmodifiableListView(_messages); } + final Map> _typingUsers; + @override + @JsonKey() + Map> get typingUsers { + if (_typingUsers is EqualUnmodifiableMapView) return _typingUsers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_typingUsers); + } + @override String toString() { - return 'ChatState.messagesLoaded(messages: $messages)'; + return 'ChatState.messagesLoaded(messages: $messages, typingUsers: $typingUsers)'; } @override @@ -751,12 +1038,16 @@ class _$MessagesLoadedImpl implements _MessagesLoaded { return identical(this, other) || (other.runtimeType == runtimeType && other is _$MessagesLoadedImpl && - const DeepCollectionEquality().equals(other._messages, _messages)); + const DeepCollectionEquality().equals(other._messages, _messages) && + const DeepCollectionEquality() + .equals(other._typingUsers, _typingUsers)); } @override - int get hashCode => - Object.hash(runtimeType, const DeepCollectionEquality().hash(_messages)); + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(_messages), + const DeepCollectionEquality().hash(_typingUsers)); @JsonKey(ignore: true) @override @@ -768,42 +1059,62 @@ class _$MessagesLoadedImpl implements _MessagesLoaded { @override @optionalTypeArgs TResult when({ - required TResult Function() initial, - required TResult Function() loading, - required TResult Function(List chats) chatsLoaded, - required TResult Function(Chat chat, List messages) chatSelected, - required TResult Function(List messages) messagesLoaded, - required TResult Function(String message) error, + required TResult Function(Map> typingUsers) initial, + required TResult Function(Map> typingUsers) loading, + required TResult Function( + List chats, Map> typingUsers) + chatsLoaded, + required TResult Function(Chat chat, List messages, + Map> typingUsers) + chatSelected, + required TResult Function( + List messages, Map> typingUsers) + messagesLoaded, + required TResult Function( + String message, Map> typingUsers) + error, }) { - return messagesLoaded(messages); + return messagesLoaded(messages, typingUsers); } @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function()? initial, - TResult? Function()? loading, - TResult? Function(List chats)? chatsLoaded, - TResult? Function(Chat chat, List messages)? chatSelected, - TResult? Function(List messages)? messagesLoaded, - TResult? Function(String message)? error, + TResult? Function(Map> typingUsers)? initial, + TResult? Function(Map> typingUsers)? loading, + TResult? Function(List chats, Map> typingUsers)? + chatsLoaded, + TResult? Function(Chat chat, List messages, + Map> typingUsers)? + chatSelected, + TResult? Function( + List messages, Map> typingUsers)? + messagesLoaded, + TResult? Function(String message, Map> typingUsers)? + error, }) { - return messagesLoaded?.call(messages); + return messagesLoaded?.call(messages, typingUsers); } @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? initial, - TResult Function()? loading, - TResult Function(List chats)? chatsLoaded, - TResult Function(Chat chat, List messages)? chatSelected, - TResult Function(List messages)? messagesLoaded, - TResult Function(String message)? error, + TResult Function(Map> typingUsers)? initial, + TResult Function(Map> typingUsers)? loading, + TResult Function(List chats, Map> typingUsers)? + chatsLoaded, + TResult Function(Chat chat, List messages, + Map> typingUsers)? + chatSelected, + TResult Function( + List messages, Map> typingUsers)? + messagesLoaded, + TResult Function(String message, Map> typingUsers)? + error, required TResult orElse(), }) { if (messagesLoaded != null) { - return messagesLoaded(messages); + return messagesLoaded(messages, typingUsers); } return orElse(); } @@ -853,22 +1164,27 @@ class _$MessagesLoadedImpl implements _MessagesLoaded { } abstract class _MessagesLoaded implements ChatState { - const factory _MessagesLoaded(final List messages) = - _$MessagesLoadedImpl; + const factory _MessagesLoaded(final List messages, + {final Map> typingUsers}) = _$MessagesLoadedImpl; List get messages; + @override + Map> get typingUsers; + @override @JsonKey(ignore: true) _$$MessagesLoadedImplCopyWith<_$MessagesLoadedImpl> get copyWith => throw _privateConstructorUsedError; } /// @nodoc -abstract class _$$ChatErrorImplCopyWith<$Res> { +abstract class _$$ChatErrorImplCopyWith<$Res> + implements $ChatStateCopyWith<$Res> { factory _$$ChatErrorImplCopyWith( _$ChatErrorImpl value, $Res Function(_$ChatErrorImpl) then) = __$$ChatErrorImplCopyWithImpl<$Res>; + @override @useResult - $Res call({String message}); + $Res call({String message, Map> typingUsers}); } /// @nodoc @@ -883,12 +1199,17 @@ class __$$ChatErrorImplCopyWithImpl<$Res> @override $Res call({ Object? message = null, + Object? typingUsers = null, }) { return _then(_$ChatErrorImpl( null == message ? _value.message : message // ignore: cast_nullable_to_non_nullable as String, + typingUsers: null == typingUsers + ? _value._typingUsers + : typingUsers // ignore: cast_nullable_to_non_nullable + as Map>, )); } } @@ -896,14 +1217,24 @@ class __$$ChatErrorImplCopyWithImpl<$Res> /// @nodoc class _$ChatErrorImpl implements ChatError { - const _$ChatErrorImpl(this.message); + const _$ChatErrorImpl(this.message, + {final Map> typingUsers = const {}}) + : _typingUsers = typingUsers; @override final String message; + final Map> _typingUsers; + @override + @JsonKey() + Map> get typingUsers { + if (_typingUsers is EqualUnmodifiableMapView) return _typingUsers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_typingUsers); + } @override String toString() { - return 'ChatState.error(message: $message)'; + return 'ChatState.error(message: $message, typingUsers: $typingUsers)'; } @override @@ -911,11 +1242,14 @@ class _$ChatErrorImpl implements ChatError { return identical(this, other) || (other.runtimeType == runtimeType && other is _$ChatErrorImpl && - (identical(other.message, message) || other.message == message)); + (identical(other.message, message) || other.message == message) && + const DeepCollectionEquality() + .equals(other._typingUsers, _typingUsers)); } @override - int get hashCode => Object.hash(runtimeType, message); + int get hashCode => Object.hash( + runtimeType, message, const DeepCollectionEquality().hash(_typingUsers)); @JsonKey(ignore: true) @override @@ -926,42 +1260,62 @@ class _$ChatErrorImpl implements ChatError { @override @optionalTypeArgs TResult when({ - required TResult Function() initial, - required TResult Function() loading, - required TResult Function(List chats) chatsLoaded, - required TResult Function(Chat chat, List messages) chatSelected, - required TResult Function(List messages) messagesLoaded, - required TResult Function(String message) error, + required TResult Function(Map> typingUsers) initial, + required TResult Function(Map> typingUsers) loading, + required TResult Function( + List chats, Map> typingUsers) + chatsLoaded, + required TResult Function(Chat chat, List messages, + Map> typingUsers) + chatSelected, + required TResult Function( + List messages, Map> typingUsers) + messagesLoaded, + required TResult Function( + String message, Map> typingUsers) + error, }) { - return error(message); + return error(message, typingUsers); } @override @optionalTypeArgs TResult? whenOrNull({ - TResult? Function()? initial, - TResult? Function()? loading, - TResult? Function(List chats)? chatsLoaded, - TResult? Function(Chat chat, List messages)? chatSelected, - TResult? Function(List messages)? messagesLoaded, - TResult? Function(String message)? error, + TResult? Function(Map> typingUsers)? initial, + TResult? Function(Map> typingUsers)? loading, + TResult? Function(List chats, Map> typingUsers)? + chatsLoaded, + TResult? Function(Chat chat, List messages, + Map> typingUsers)? + chatSelected, + TResult? Function( + List messages, Map> typingUsers)? + messagesLoaded, + TResult? Function(String message, Map> typingUsers)? + error, }) { - return error?.call(message); + return error?.call(message, typingUsers); } @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? initial, - TResult Function()? loading, - TResult Function(List chats)? chatsLoaded, - TResult Function(Chat chat, List messages)? chatSelected, - TResult Function(List messages)? messagesLoaded, - TResult Function(String message)? error, + TResult Function(Map> typingUsers)? initial, + TResult Function(Map> typingUsers)? loading, + TResult Function(List chats, Map> typingUsers)? + chatsLoaded, + TResult Function(Chat chat, List messages, + Map> typingUsers)? + chatSelected, + TResult Function( + List messages, Map> typingUsers)? + messagesLoaded, + TResult Function(String message, Map> typingUsers)? + error, required TResult orElse(), }) { if (error != null) { - return error(message); + return error(message, typingUsers); } return orElse(); } @@ -1011,9 +1365,13 @@ class _$ChatErrorImpl implements ChatError { } abstract class ChatError implements ChatState { - const factory ChatError(final String message) = _$ChatErrorImpl; + const factory ChatError(final String message, + {final Map> typingUsers}) = _$ChatErrorImpl; String get message; + @override + Map> get typingUsers; + @override @JsonKey(ignore: true) _$$ChatErrorImplCopyWith<_$ChatErrorImpl> get copyWith => throw _privateConstructorUsedError; 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 d8b2e3d..0f4d0f9 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,84 +35,206 @@ class _ChatDetailPageState extends State { @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(widget.chat.type == 'favorites' ? AppLocalizations.of(context)!.favorites : widget.chat.title), - if (widget.chat.type != 'favorites') - Text( - AppLocalizations.of(context)!.connected, - style: const TextStyle(fontSize: 12, fontWeight: FontWeight.normal), - ), - ], - ), - 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), - loading: () => const Center(child: CircularProgressIndicator()), - error: (msg) => Center(child: Text('Ошибка: $msg')), - orElse: () => const Center(child: Text('Начните общение')), - ); - }, + return BlocBuilder( + builder: (context, state) { + final currentChat = state.maybeWhen( + chatSelected: (chat, _, __) => chat, + orElse: () => widget.chat, + ); + + return Scaffold( + appBar: AppBar( + centerTitle: false, + title: 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: () {}), + ], ), - _buildMessageInput(), - ], - ), + body: Column( + children: [ + Expanded( + child: state.maybeWhen( + chatSelected: (_, 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), + ], + ), + ); + }, ); } + Widget _buildPresenceStatus(Chat chat, ChatState state) { + // Check typing status first + final typingInChat = state.typingUsers[chat.id]; + final otherMemberTyping = typingInChat?.any((id) => id != widget.currentUserId) ?? false; + + if (otherMemberTyping) { + return const Text( + 'печатает...', + style: TextStyle(fontSize: 12, color: Colors.white70, fontWeight: FontWeight.normal, fontStyle: FontStyle.italic), + ); + } + + final participants = chat.participants; + if (participants == null || participants.isEmpty) { + return const SizedBox.shrink(); + } + + final otherMember = participants.firstWhere( + (m) => m.id != widget.currentUserId, + orElse: () => participants[0], + ); + + final l10n = AppLocalizations.of(context)!; + final locale = Localizations.localeOf(context).languageCode; + + if (otherMember.isOnline == true) { + return Row( + children: [ + Container( + width: 6, + height: 6, + decoration: const BoxDecoration( + color: Colors.greenAccent, + shape: BoxShape.circle, + ), + ), + const SizedBox(width: 4), + Text( + l10n.online, + style: const TextStyle(fontSize: 12, color: Colors.white70, fontWeight: FontWeight.normal), + ), + ], + ); + } else if (otherMember.lastSeen != null) { + final lastSeen = otherMember.lastSeen!.toLocal(); + final timeStr = DateFormat.Hm(locale).format(lastSeen); + final dateStr = _formatDate(lastSeen, locale); + return Text( + l10n.lastSeen(dateStr, timeStr), + style: const TextStyle(fontSize: 12, color: Colors.white70, fontWeight: FontWeight.normal), + ); + } + return const SizedBox.shrink(); + } + + String _formatDate(DateTime date, String locale) { + final now = DateTime.now(); + final localDate = date.toLocal(); + if (localDate.year == now.year) { + return DateFormat.MMMMd(locale).format(localDate); + } + return DateFormat.yMMMMd(locale).format(localDate); + } + Widget _buildMessageList(List messages) { + final l10n = AppLocalizations.of(context)!; + final locale = Localizations.localeOf(context).languageCode; + if (messages.isEmpty) { - return const Center(child: Text('Сообщений пока нет')); + return Center(child: Text(l10n.noMessages)); + } + + final List items = []; + for (int i = 0; i < messages.length; i++) { + final message = messages[i]; + items.add(message); + + if (message.createdAt != null) { + final localCreatedAt = message.createdAt!.toLocal(); + final currentDay = DateTime(localCreatedAt.year, localCreatedAt.month, localCreatedAt.day); + + if (i == messages.length - 1) { + items.add(currentDay); + } else { + final nextMessage = messages[i + 1]; + if (nextMessage.createdAt != null) { + final nextLocalCreatedAt = nextMessage.createdAt!.toLocal(); + final nextDay = DateTime(nextLocalCreatedAt.year, nextLocalCreatedAt.month, nextLocalCreatedAt.day); + if (currentDay != nextDay) { + items.add(currentDay); + } + } + } + } } return ListView.builder( controller: _scrollController, reverse: true, padding: const EdgeInsets.all(16), - itemCount: messages.length, + itemCount: items.length, itemBuilder: (context, index) { - final message = messages[index]; + final item = items[index]; + + if (item is DateTime) { + return Center( + child: Container( + margin: const EdgeInsets.symmetric(vertical: 16), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.1), + borderRadius: BorderRadius.circular(12), + ), + child: Text( + _formatDate(item, locale), + style: const TextStyle(fontSize: 12, color: Colors.black54), + ), + ), + ); + } + + final message = item as Message; final isMe = message.senderId == widget.currentUserId; return Align( alignment: isMe ? Alignment.centerRight : Alignment.centerLeft, child: Container( - margin: const EdgeInsets.symmetric(vertical: 4), + margin: const EdgeInsets.symmetric(vertical: 2, horizontal: 8), + constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.75), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( - color: isMe ? Theme.of(context).primaryColor : Colors.grey[200], + color: isMe ? const Color(0xFFE3F2FD) : Colors.white, borderRadius: BorderRadius.circular(16).copyWith( - bottomRight: isMe ? const Radius.circular(0) : const Radius.circular(16), - bottomLeft: !isMe ? const Radius.circular(0) : const Radius.circular(16), + bottomRight: isMe ? const Radius.circular(2) : const Radius.circular(16), + bottomLeft: !isMe ? const Radius.circular(2) : const Radius.circular(16), ), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 2, + offset: const Offset(0, 1), + ), + ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, children: [ Text( message.content, - style: TextStyle(color: isMe ? Colors.white : Colors.black87), + style: const TextStyle(color: Colors.black87, fontSize: 16), ), - const SizedBox(height: 4), + const SizedBox(height: 2), if (message.createdAt != null) Text( - DateFormat.Hm().format(message.createdAt!), - style: TextStyle( + DateFormat.Hm(locale).format(message.createdAt!.toLocal()), + style: const TextStyle( fontSize: 10, - color: isMe ? Colors.white70 : Colors.black45, + color: Colors.black45, ), ), ], @@ -123,7 +245,7 @@ class _ChatDetailPageState extends State { ); } - Widget _buildMessageInput() { + Widget _buildMessageInput(Chat chat) { return Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( @@ -143,16 +265,19 @@ class _ChatDetailPageState extends State { Expanded( child: TextField( controller: _messageController, - decoration: const InputDecoration( - hintText: 'Сообщение', + decoration: InputDecoration( + hintText: AppLocalizations.of(context)!.messageHint, border: InputBorder.none, ), - onSubmitted: (_) => _sendMessage(), + onChanged: (value) { + context.read().add(ChatEvent.sendTypingStatus(chat.id, value.isNotEmpty)); + }, + onSubmitted: (_) => _sendMessage(chat.id), ), ), IconButton( icon: const Icon(Icons.send), - onPressed: _sendMessage, + onPressed: () => _sendMessage(chat.id), color: Theme.of(context).primaryColor, ), ], @@ -161,10 +286,11 @@ class _ChatDetailPageState extends State { ); } - void _sendMessage() { + void _sendMessage(String chatId) { final content = _messageController.text.trim(); if (content.isNotEmpty) { - context.read().add(ChatEvent.messageSent(widget.chat.id, content)); + context.read().add(ChatEvent.messageSent(chatId, content)); + context.read().add(ChatEvent.sendTypingStatus(chatId, false)); _messageController.clear(); } } 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 d65f16b..3f986d8 100644 --- a/client-mobile/lib/features/chat/presentation/pages/chats_page.dart +++ b/client-mobile/lib/features/chat/presentation/pages/chats_page.dart @@ -47,7 +47,7 @@ class _ChatsPageState extends State { body: BlocConsumer( listener: (context, state) { state.whenOrNull( - chatSelected: (chat, _) { + chatSelected: (chat, _, __) { final authState = context.read().state; final userId = authState.maybeWhen( authenticated: (id) => id, @@ -72,9 +72,9 @@ class _ChatsPageState extends State { }, builder: (context, state) { return state.maybeWhen( - loading: () => const Center(child: CircularProgressIndicator()), - chatsLoaded: (chats) => _buildChatList(chats, l10n), - error: (message) => Center(child: Text('${l10n.error}: $message')), + loading: (_) => const Center(child: CircularProgressIndicator()), + chatsLoaded: (chats, _) => _buildChatList(chats, l10n), + error: (message, _) => Center(child: Text('${l10n.error}: $message')), orElse: () => const Center(child: CircularProgressIndicator()), ); }, @@ -141,7 +141,7 @@ class _ChatsPageState extends State { children: [ if (chat.lastMessageTime != null) Text( - DateFormat.Hm().format(chat.lastMessageTime!), + DateFormat.Hm().format(chat.lastMessageTime!.toLocal()), style: const TextStyle(fontSize: 12, color: Colors.grey), ), const SizedBox(height: 4), diff --git a/client-mobile/lib/internal/di/injection_container.dart b/client-mobile/lib/internal/di/injection_container.dart index 5ea083f..f17408b 100644 --- a/client-mobile/lib/internal/di/injection_container.dart +++ b/client-mobile/lib/internal/di/injection_container.dart @@ -57,6 +57,8 @@ Future initDependencies() async { dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) { final token = prefs.getString('access_token'); + // ignore: avoid_print + print('[DEBUG] Dio Request: ${options.path}, Token present: ${token != null}'); if (token != null) { options.headers['Authorization'] = 'Bearer $token'; } diff --git a/client-mobile/lib/l10n/app_localizations.dart b/client-mobile/lib/l10n/app_localizations.dart index b3c26e7..d4b21b4 100644 --- a/client-mobile/lib/l10n/app_localizations.dart +++ b/client-mobile/lib/l10n/app_localizations.dart @@ -583,6 +583,30 @@ abstract class AppLocalizations { /// In ru, this message translates to: /// **'Ошибка регистрации'** String get registrationFailed; + + /// No description provided for @online. + /// + /// In ru, this message translates to: + /// **'в сети'** + String get online; + + /// No description provided for @lastSeen. + /// + /// In ru, this message translates to: + /// **'был(а) в сети {date} в {time}'** + String lastSeen(Object date, Object time); + + /// No description provided for @noMessages. + /// + /// In ru, this message translates to: + /// **'Сообщений пока нет'** + String get noMessages; + + /// No description provided for @messageHint. + /// + /// In ru, this message translates to: + /// **'Сообщение'** + String get messageHint; } class _AppLocalizationsDelegate diff --git a/client-mobile/lib/l10n/app_localizations_en.dart b/client-mobile/lib/l10n/app_localizations_en.dart index dfd6213..7d50365 100644 --- a/client-mobile/lib/l10n/app_localizations_en.dart +++ b/client-mobile/lib/l10n/app_localizations_en.dart @@ -251,4 +251,18 @@ class AppLocalizationsEn extends AppLocalizations { @override String get registrationFailed => 'Registration failed'; + + @override + String get online => 'online'; + + @override + String lastSeen(Object date, Object time) { + return 'last seen $date at $time'; + } + + @override + String get noMessages => 'No messages yet'; + + @override + String get messageHint => 'Message'; } diff --git a/client-mobile/lib/l10n/app_localizations_ru.dart b/client-mobile/lib/l10n/app_localizations_ru.dart index df308bf..d9f7905 100644 --- a/client-mobile/lib/l10n/app_localizations_ru.dart +++ b/client-mobile/lib/l10n/app_localizations_ru.dart @@ -251,4 +251,18 @@ class AppLocalizationsRu extends AppLocalizations { @override String get registrationFailed => 'Ошибка регистрации'; + + @override + String get online => 'в сети'; + + @override + String lastSeen(Object date, Object time) { + return 'был(а) в сети $date в $time'; + } + + @override + String get noMessages => 'Сообщений пока нет'; + + @override + String get messageHint => 'Сообщение'; } diff --git a/client-mobile/lib/main.dart b/client-mobile/lib/main.dart index cdac889..16e3601 100644 --- a/client-mobile/lib/main.dart +++ b/client-mobile/lib/main.dart @@ -1,10 +1,15 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:intl/date_symbol_data_local.dart'; import 'internal/di/injection_container.dart' as di; import 'app.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); + + // Initialize date formatting for Russian and English + await initializeDateFormatting('ru', null); + await initializeDateFormatting('en', null); // Set preferred orientations await SystemChrome.setPreferredOrientations([