dont fetch members on load

This commit is contained in:
Henry Hiles 2026-03-22 14:30:46 -04:00
commit 8b056d8ed1
No known key found for this signature in database
21 changed files with 206 additions and 137 deletions

View file

@ -86,10 +86,11 @@ class ChatBox extends HookConsumerWidget {
child: Column(
children: [
RelationPreview(
relatedMessage,
room: room,
shouldMention: shouldMention.value,
toggleShouldMention: () =>
shouldMention.value = !shouldMention.value,
relatedMessage: relatedMessage,
relationType: relationType,
onDismiss: onDismiss,
),

View file

@ -0,0 +1,32 @@
import "package:flutter/widgets.dart";
import "package:flutter_chat_core/flutter_chat_core.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/controllers/member_controller.dart";
import "package:nexus/helpers/extensions/better_when.dart";
import "package:nexus/models/configs/member_config.dart";
import "package:nexus/models/room.dart";
import "package:nexus/widgets/avatar_or_hash.dart";
class MessageAvatar extends ConsumerWidget {
final Message message;
final Room room;
final double height;
const MessageAvatar(this.message, this.room, {this.height = 16, super.key});
@override
Widget build(BuildContext context, WidgetRef ref) => ref
.watch(
MemberController.provider(
MemberConfig(room: room, userId: message.authorId),
),
)
.betterWhen(
data: (membership) => AvatarOrHash(
membership.avatarUrl,
membership.displayName,
height: height,
),
loading: () =>
AvatarOrHash(null, message.authorId.substring(1), height: height),
);
}

View file

@ -0,0 +1,30 @@
import "package:flutter/widgets.dart";
import "package:flutter_chat_core/flutter_chat_core.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/controllers/member_controller.dart";
import "package:nexus/helpers/extensions/better_when.dart";
import "package:nexus/models/configs/member_config.dart";
import "package:nexus/models/room.dart";
class MessageDisplayname extends ConsumerWidget {
final Message message;
final Room room;
final TextStyle? style;
const MessageDisplayname(this.message, this.room, {this.style, super.key});
@override
Widget build(BuildContext context, WidgetRef ref) => ref
.watch(
MemberController.provider(
MemberConfig(room: room, userId: message.authorId),
),
)
.betterWhen(
data: (membership) => Text(
membership.displayName,
style: style,
overflow: TextOverflow.ellipsis,
),
loading: SizedBox.shrink,
);
}

View file

@ -36,18 +36,9 @@ class MemberList extends ConsumerWidget {
builder: (context) =>
Dialog(child: Text("TODO: Open member popover")),
),
leading: AvatarOrHash(
Uri.tryParse(member.content["avatar_url"] ?? ""),
member.content["displayname"].toString(),
),
title: Text(
member.content["displayname"].toString(),
overflow: TextOverflow.ellipsis,
),
subtitle: Text(
member.stateKey ?? "Unknown User",
overflow: TextOverflow.ellipsis,
),
leading: AvatarOrHash(member.avatarUrl, member.displayName),
title: Text(member.displayName, overflow: TextOverflow.ellipsis),
subtitle: Text(member.userId, overflow: TextOverflow.ellipsis),
),
),
],

View file

@ -40,39 +40,29 @@ class MentionOverlay extends ConsumerWidget {
? members
: members.where(
(member) =>
member.stateKey?.toLowerCase().contains(
member.userId.toLowerCase().contains(
query.toLowerCase(),
) ==
true ||
(member.content["displayname"] as String?)
?.toLowerCase()
.contains(query.toLowerCase()) ==
member.displayName.toLowerCase().contains(
query.toLowerCase(),
) ==
true,
))
.map(
(member) => ListTile(
leading: AvatarOrHash(
Uri.tryParse(
member.content["avatar_url"] ?? "",
),
member.content["displayname"] ?? "",
member.avatarUrl,
member.displayName,
),
title: Text(
member.content["displayname"] as String? ??
member.stateKey ??
"Unknown User",
),
subtitle: member.stateKey != null
? Text(member.stateKey!)
: null,
title: Text(member.displayName),
subtitle: Text(member.userId),
onTap: () => addTag(
id: "[@${member.content["displayname"]}](https://matrix.to/#/${member.stateKey})",
name:
member.stateKey
?.substring(1)
.split(":")
.first ??
"Unknown User",
id: "[@${member.displayName}](https://matrix.to/#/${member.userId})",
name: member.userId
.substring(1)
.split(":")
.first,
),
),
)

View file

@ -1,12 +1,21 @@
import "package:flutter/material.dart";
import "package:flutter_chat_core/flutter_chat_core.dart";
import "package:nexus/widgets/avatar_or_hash.dart";
import "package:nexus/models/room.dart";
import "package:nexus/widgets/chat_page/lazy_loading/message_avatar.dart";
import "package:nexus/widgets/chat_page/lazy_loading/message_displayname.dart";
class MessageWrapper extends StatelessWidget {
final Message message;
final Widget child;
final Room room;
final MessageGroupStatus? groupStatus;
const MessageWrapper(this.message, this.child, this.groupStatus, {super.key});
const MessageWrapper(
this.message,
this.child,
this.groupStatus,
this.room, {
super.key,
});
@override
Widget build(BuildContext context) => ClipRRect(
@ -24,11 +33,7 @@ class MessageWrapper extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
groupStatus?.isFirst != false
? AvatarOrHash(
Uri.parse(message.metadata?["avatarUrl"] ?? ""),
height: 40,
message.metadata?["displayName"] ?? "",
)
? MessageAvatar(message, room, height: 40)
: SizedBox(width: 40),
Expanded(
child: Column(
@ -36,9 +41,9 @@ class MessageWrapper extends StatelessWidget {
spacing: 4,
children: [
if (groupStatus?.isFirst != false)
Text(
message.metadata?["displayName"] ?? message.authorId,
overflow: TextOverflow.ellipsis,
MessageDisplayname(
message,
room,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),

View file

@ -2,7 +2,9 @@ import "package:flutter/material.dart";
import "package:flutter_chat_core/flutter_chat_core.dart";
import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:nexus/models/relation_type.dart";
import "package:nexus/widgets/avatar_or_hash.dart";
import "package:nexus/models/room.dart";
import "package:nexus/widgets/chat_page/lazy_loading/message_avatar.dart";
import "package:nexus/widgets/chat_page/lazy_loading/message_displayname.dart";
class RelationPreview extends ConsumerWidget {
final Message? relatedMessage;
@ -10,8 +12,11 @@ class RelationPreview extends ConsumerWidget {
final VoidCallback onDismiss;
final bool shouldMention;
final VoidCallback toggleShouldMention;
const RelationPreview({
required this.relatedMessage,
final Room room;
const RelationPreview(
this.relatedMessage, {
required this.room,
required this.relationType,
required this.onDismiss,
required this.shouldMention,
@ -36,14 +41,10 @@ class RelationPreview extends ConsumerWidget {
"Editing message:",
style: TextStyle(fontWeight: FontWeight.bold),
),
AvatarOrHash(
Uri.tryParse(relatedMessage?.metadata?["avatarUrl"] ?? ""),
relatedMessage?.metadata?["displayName"]?.toString() ?? "",
height: 16,
),
Text(
relatedMessage!.metadata?["displayName"] ??
relatedMessage!.authorId,
MessageAvatar(relatedMessage!, room),
MessageDisplayname(
relatedMessage!,
room,
style: theme.textTheme.labelMedium?.copyWith(
fontWeight: FontWeight.bold,
),

View file

@ -1,15 +1,15 @@
import "dart:math";
import "package:flutter/material.dart";
import "package:flutter_chat_core/flutter_chat_core.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/controllers/event_controller.dart";
import "package:nexus/controllers/message_controller.dart";
import "package:nexus/helpers/extensions/better_when.dart";
import "package:nexus/models/message_config.dart";
import "package:nexus/models/configs/message_config.dart";
import "package:nexus/models/requests/get_event_request.dart";
import "package:nexus/models/room.dart";
import "package:nexus/widgets/avatar_or_hash.dart";
import "package:nexus/widgets/chat_page/html/quoted.dart";
import "package:nexus/widgets/chat_page/lazy_loading/message_avatar.dart";
import "package:nexus/widgets/chat_page/lazy_loading/message_displayname.dart";
typedef OnTapReply = void Function(Message message)?;
@ -61,73 +61,28 @@ class ReplyWidget extends ConsumerWidget {
return SizedBox.shrink();
}
final smallerText =
message is TextMessage &&
replyMessage.metadata?["body"] != null
? replyMessage.metadata!["body"].substring(
0,
min(
max(
max(
(message as TextMessage)
.text
.length -
(replyMessage
.metadata?["displayName"]
as String)
.length -
5,
message
.metadata?["displayName"]
.length,
),
5,
),
replyMessage.metadata!["body"].length,
),
)
: null;
final replyText =
(smallerText == null ||
smallerText.length ==
replyMessage
.metadata!["body"]
.length)
? replyMessage.metadata!["body"]
: "$smallerText...";
return InkWell(
onTap: () => onTapReply?.call(replyMessage),
child: Row(
mainAxisSize: MainAxisSize.min,
spacing: 8,
children: [
AvatarOrHash(
Uri.tryParse(
replyMessage.metadata?["avatarUrl"] ??
"",
),
replyMessage.metadata?["displayName"] ??
"",
height: 16,
),
MessageAvatar(message, room),
Flexible(
child: Text(
replyMessage
.metadata?["displayName"] ??
replyMessage.authorId,
child: MessageDisplayname(
replyMessage,
room,
style: Theme.of(context)
.textTheme
.labelMedium
?.copyWith(
fontWeight: FontWeight.bold,
),
overflow: TextOverflow.ellipsis,
),
),
Flexible(
child: Text(
replyText,
replyMessage.metadata!["body"],
overflow: TextOverflow.ellipsis,
style: Theme.of(
context,

View file

@ -320,6 +320,7 @@ class RoomChat extends HookConsumerWidget {
),
),
groupStatus,
room,
),
systemMessageBuilder:

View file

@ -109,6 +109,7 @@ class TextMessageWrapper extends StatelessWidget {
),
),
groupStatus,
room,
);
}
}