implemented chat long-polling and optimistic updates, centralized notification management, optimized avatar caching

This commit is contained in:
2026-05-10 15:47:55 +02:00
parent 6ae396e605
commit 1458d8ce49
15 changed files with 712 additions and 146 deletions
+11 -15
View File
@@ -7,7 +7,6 @@ import '../../../notification/notify_updater.dart';
import '../../../routing/app_routes.dart';
import '../../../state/app/infrastructure/loadable_state/loadable_state.dart';
import '../../../state/app/infrastructure/loadable_state/view/loadable_state_consumer.dart';
import '../../../state/app/infrastructure/utility_widgets/bloc_module.dart';
import '../../../state/app/modules/chat_list/bloc/chat_list_bloc.dart';
import '../../../state/app/modules/chat_list/bloc/chat_list_state.dart';
import '../../../state/app/modules/settings/bloc/settings_cubit.dart';
@@ -19,15 +18,13 @@ import 'search_chat.dart';
import 'widgets/chat_tile.dart';
import 'widgets/split_view_placeholder.dart';
// Reads from the global ChatListBloc in main.dart — re-providing a local
// one here would shadow it and split the state in two.
class ChatList extends StatelessWidget {
const ChatList({super.key});
@override
Widget build(BuildContext context) =>
BlocModule<ChatListBloc, LoadableState<ChatListState>>(
create: (_) => ChatListBloc(),
child: (context, bloc, _) => const _ChatListView(),
);
Widget build(BuildContext context) => const _ChatListView();
}
class _ChatListView extends StatefulWidget {
@@ -65,14 +62,6 @@ class _ChatListViewState extends State<_ChatListView> {
final resolved = AppRoutes.resolvePendingChat(context);
if (resolved == null) return;
AppRoutes.pendingChatToken.value = null;
// Replace any chat already pushed on top of the chat list so a freshly
// tapped notification doesn't stack indefinitely on previous chats.
final navigator = Navigator.of(context);
if (navigator.canPop()) {
navigator.popUntil((route) => route.isFirst);
}
AppRoutes.openChatView(
context,
room: resolved.room,
@@ -193,7 +182,14 @@ class _ChatListViewState extends State<_ChatListView> {
.talkSettings
.drafts
.containsKey(room.token);
return ChatTile(data: room, hasDraft: hasDraft);
// Stable key keeps element identity across re-sorts so the
// inner UserAvatar reuses its cached bytes instead of
// flashing on every list update.
return ChatTile(
key: ValueKey(room.token),
data: room,
hasDraft: hasDraft,
);
}).toList(),
);
},