Fetch replies in toMessage not at runtime

This commit is contained in:
Henry Hiles 2025-12-23 18:46:31 -05:00
commit 7ce4d3c9fb
No known key found for this signature in database
3 changed files with 67 additions and 90 deletions

View file

@ -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<TextMessage?> {
final String id;
MessageController(this.id);
@override
Future<TextMessage?> 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, TextMessage?, String>(
MessageController.new,
);
}

View file

@ -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 ??

View file

@ -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: () =>