From e55d7c4c582ec8943615701df17d72a5ec0fc493 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 23 Nov 2025 14:50:38 -0500 Subject: [PATCH] fix read indicators --- lib/controllers/client_controller.dart | 9 +++------ lib/controllers/database_controller.dart | 18 ++++++++++++++++++ lib/controllers/room_chat_controller.dart | 3 ++- lib/helpers/extension_helper.dart | 1 + lib/widgets/avatar_or_hash.dart | 13 +++++++------ lib/widgets/chat_page/room_chat.dart | 6 +++++- 6 files changed, 36 insertions(+), 14 deletions(-) create mode 100644 lib/controllers/database_controller.dart diff --git a/lib/controllers/client_controller.dart b/lib/controllers/client_controller.dart index 4faf631..3c7740e 100644 --- a/lib/controllers/client_controller.dart +++ b/lib/controllers/client_controller.dart @@ -1,21 +1,20 @@ import "dart:convert"; import "dart:io"; import "package:flutter/foundation.dart"; +import "package:nexus/controllers/database_controller.dart"; import "package:vodozemac/vodozemac.dart" as voz; import "package:flutter_vodozemac/flutter_vodozemac.dart" as voz_fl; import "package:matrix/matrix.dart"; import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:nexus/controllers/secure_storage_controller.dart"; import "package:nexus/models/session_backup.dart"; -import "package:path/path.dart"; -import "package:path_provider/path_provider.dart"; -import "package:sqflite_common_ffi/sqflite_ffi.dart"; class ClientController extends AsyncNotifier { static const sessionBackupKey = "sessionBackup"; @override Future build() async { if (!voz.isInitialized()) await voz_fl.init(); + final client = Client( "nexus", logLevel: kReleaseMode ? Level.warning : Level.verbose, @@ -23,9 +22,7 @@ class ClientController extends AsyncNotifier { supportedLoginTypes: {AuthenticationTypes.password}, database: await MatrixSdkDatabase.init( "nexus", - database: await databaseFactoryFfi.openDatabase( - join((await getApplicationSupportDirectory()).path, "database.db"), - ), + database: await ref.watch(DatabaseController.provider.future), ), ); diff --git a/lib/controllers/database_controller.dart b/lib/controllers/database_controller.dart new file mode 100644 index 0000000..706560b --- /dev/null +++ b/lib/controllers/database_controller.dart @@ -0,0 +1,18 @@ +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:path/path.dart"; +import "package:path_provider/path_provider.dart"; +import "package:sqflite_common_ffi/sqflite_ffi.dart"; + +class DatabaseController extends AsyncNotifier { + @override + Future build() async { + databaseFactory = databaseFactoryFfi; + return databaseFactoryFfi.openDatabase( + join((await getApplicationSupportDirectory()).path, "database.db"), + ); + } + + static final provider = AsyncNotifierProvider( + DatabaseController.new, + ); +} diff --git a/lib/controllers/room_chat_controller.dart b/lib/controllers/room_chat_controller.dart index 101b57e..312a6c9 100644 --- a/lib/controllers/room_chat_controller.dart +++ b/lib/controllers/room_chat_controller.dart @@ -64,7 +64,8 @@ class RoomChatController extends AsyncNotifier { Future markRead() async { final controller = await future; - await room.setReadMarker(controller.messages.last.id); + final id = controller.messages.last.id; + await room.setReadMarker(id, mRead: id); } Future updateMessage(Message message, Message newMessage) async => diff --git a/lib/helpers/extension_helper.dart b/lib/helpers/extension_helper.dart index 3e64b8a..8c5f9fa 100644 --- a/lib/helpers/extension_helper.dart +++ b/lib/helpers/extension_helper.dart @@ -65,6 +65,7 @@ extension ToMessage on Event { return switch (type) { EventTypes.Encrypted => asText.copyWith( text: "Unable to decrypt message.", + metadata: {"formatted": "Unable to decrypt message.", ...metadata}, ), EventTypes.Message => switch (messageType) { MessageTypes.Image => Message.image( diff --git a/lib/widgets/avatar_or_hash.dart b/lib/widgets/avatar_or_hash.dart index f078363..7ca6e88 100644 --- a/lib/widgets/avatar_or_hash.dart +++ b/lib/widgets/avatar_or_hash.dart @@ -29,12 +29,13 @@ class AvatarOrHash extends StatelessWidget { width: height, height: height, child: Center( - child: ClipRRect( - borderRadius: BorderRadius.all(Radius.circular(4)), - child: Badge( - isLabelVisible: hasBadge, - smallSize: 10, - backgroundColor: Theme.of(context).colorScheme.primary, + child: Badge( + isLabelVisible: hasBadge, + label: SizedBox.shrink(), + offset: Offset(8, -8), + backgroundColor: Theme.of(context).colorScheme.primary, + child: ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(4)), child: SizedBox( width: height, height: height, diff --git a/lib/widgets/chat_page/room_chat.dart b/lib/widgets/chat_page/room_chat.dart index b901b17..d603de6 100644 --- a/lib/widgets/chat_page/room_chat.dart +++ b/lib/widgets/chat_page/room_chat.dart @@ -21,6 +21,7 @@ import "package:nexus/widgets/chat_page/room_appbar.dart"; import "package:nexus/widgets/chat_page/spoiler_text.dart"; import "package:nexus/widgets/chat_page/top_widget.dart"; import "package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart"; +import "package:nexus/widgets/loading.dart"; class RoomChat extends HookConsumerWidget { final bool isDesktop; @@ -110,12 +111,15 @@ class RoomChat extends HookConsumerWidget { onTap: () => replyToMessage.value = message, ), builders: Builders( + loadMoreBuilder: (_) => Loading(), chatAnimatedListBuilder: (_, itemBuilder) => ChatAnimatedList( itemBuilder: itemBuilder, // TODO: Load earlier onEndReached: notifier.loadOlder, - onStartReached: () => notifier.markRead(), + onStartReached: () async { + notifier.markRead(); + }, ), composerBuilder: (_) => ChatBox( replyToMessage: replyToMessage.value,