From 7ce4d3c9fb914e5c905d514dbd4e7783d812609e Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Tue, 23 Dec 2025 18:46:31 -0500 Subject: [PATCH] Fetch replies in toMessage not at runtime --- lib/controllers/message_controller.dart | 23 ---- lib/helpers/extensions/event_to_message.dart | 7 +- lib/widgets/chat_page/top_widget.dart | 127 +++++++++---------- 3 files changed, 67 insertions(+), 90 deletions(-) delete mode 100644 lib/controllers/message_controller.dart diff --git a/lib/controllers/message_controller.dart b/lib/controllers/message_controller.dart deleted file mode 100644 index 69d3e37..0000000 --- a/lib/controllers/message_controller.dart +++ /dev/null @@ -1,23 +0,0 @@ -import "package:flutter_chat_core/flutter_chat_core.dart"; -import "package:flutter_riverpod/flutter_riverpod.dart"; -import "package:nexus/controllers/selected_room_controller.dart"; -import "package:nexus/helpers/extensions/event_to_message.dart"; - -class MessageController extends AsyncNotifier { - final String id; - MessageController(this.id); - - @override - Future build() async { - final room = await ref.watch(SelectedRoomController.provider.future); - if (room == null) return null; - - final event = await room.roomData.getEventById(id); - return (await event?.toMessage(mustBeText: true)) as TextMessage?; - } - - static final provider = AsyncNotifierProvider.family - .autoDispose( - MessageController.new, - ); -} diff --git a/lib/helpers/extensions/event_to_message.dart b/lib/helpers/extensions/event_to_message.dart index 0455285..e39b20e 100644 --- a/lib/helpers/extensions/event_to_message.dart +++ b/lib/helpers/extensions/event_to_message.dart @@ -15,13 +15,18 @@ extension EventToMessage on Event { final newEvent = (unsigned?["m.relations"] as Map?)?["m.replace"]; final event = newEvent == null ? this : Event.fromJson(newEvent, room); + final replyEvent = replyId == null + ? null + : await room.getEventById(replyId); + final newContent = event.content["m.new_content"] as Map?; final metadata = { "formatted": newContent?["formatted_body"] ?? newContent?["body"] ?? event.content["formatted_body"] ?? - event.content["body"], + event.body, + "reply": await replyEvent?.toMessage(mustBeText: true), "eventType": event.type, "displayName": event.senderFromMemoryOrFallback.displayName ?? diff --git a/lib/widgets/chat_page/top_widget.dart b/lib/widgets/chat_page/top_widget.dart index 95f613c..15f59bd 100644 --- a/lib/widgets/chat_page/top_widget.dart +++ b/lib/widgets/chat_page/top_widget.dart @@ -3,8 +3,6 @@ import "package:flutter/material.dart"; import "package:flutter_chat_core/flutter_chat_core.dart"; import "package:flutter_chat_ui/flutter_chat_ui.dart"; import "package:flutter_riverpod/flutter_riverpod.dart"; -import "package:nexus/controllers/message_controller.dart"; -import "package:nexus/helpers/extensions/better_when.dart"; import "package:nexus/widgets/chat_page/quoted.dart"; class TopWidget extends ConsumerWidget { @@ -24,74 +22,71 @@ class TopWidget extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) => Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (message.replyToMessageId != null) ...[ - ref - .watch(MessageController.provider(message.replyToMessageId!)) - .betterWhen( - loading: SizedBox.shrink, - data: (replyMessage) { - if (replyMessage == null) return SizedBox.shrink(); + Builder( + builder: (_) { + final replyMessage = message.metadata?["reply"] as TextMessage?; - // Black magic to limit reply preview length - final smallerText = message is TextMessage - ? replyMessage.text.substring( - 0, - min( - max( - max( - (message as TextMessage).text.length - 20, - message.metadata?["displayName"].length, - ), - 5, - ), - replyMessage.text.length, - ), - ) - : null; - final replyText = - (smallerText == null || - smallerText.length == replyMessage.text.length) - ? replyMessage.text - : "$smallerText..."; - - return InkWell( - // TODO: Scroll to original message - onTap: () => showAboutDialog(context: context), - child: Quoted( - Row( - mainAxisSize: MainAxisSize.min, - spacing: 8, - children: [ - Avatar( - userId: replyMessage.authorId, - headers: headers, - size: 16, - ), - Flexible( - child: Text( - replyMessage.metadata?["displayName"] ?? - replyMessage.authorId, - style: Theme.of(context).textTheme.labelMedium - ?.copyWith(fontWeight: FontWeight.bold), - overflow: TextOverflow.ellipsis, - ), - ), - Flexible( - child: Text( - replyText, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.labelMedium, - maxLines: 1, - ), - ), - ], + if (replyMessage == null) return SizedBox.shrink(); + final smallerText = message is TextMessage + ? replyMessage.text.substring( + 0, + min( + max( + max( + (message as TextMessage).text.length - 20, + message.metadata?["displayName"].length, + ), + 5, ), + replyMessage.text.length, ), - ); - }, + ) + : null; + final replyText = + (smallerText == null || + smallerText.length == replyMessage.text.length) + ? replyMessage.text + : "$smallerText..."; + + return Padding( + padding: EdgeInsets.only(bottom: 12), + child: InkWell( + // TODO: Scroll to original message + onTap: () => showAboutDialog(context: context), + child: Quoted( + Row( + mainAxisSize: MainAxisSize.min, + spacing: 8, + children: [ + Avatar( + userId: replyMessage.authorId, + headers: headers, + size: 16, + ), + Flexible( + child: Text( + replyMessage.metadata?["displayName"] ?? + replyMessage.authorId, + style: Theme.of(context).textTheme.labelMedium + ?.copyWith(fontWeight: FontWeight.bold), + overflow: TextOverflow.ellipsis, + ), + ), + Flexible( + child: Text( + replyText, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.labelMedium, + maxLines: 1, + ), + ), + ], + ), + ), ), - SizedBox(height: 12), - ], + ); + }, + ), if (alwaysShow || groupStatus?.isFirst != false) InkWell( onTap: () =>