From 49c09b3c35d20c4744ddb29926bf660314d3031f Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sat, 16 May 2026 16:22:49 -0400 Subject: [PATCH] easy widgets ported to use new event format --- lib/widgets/chat_page/composer/chat_box.dart | 13 ++-- .../chat_page/composer/mention_overlay.dart | 60 ++++++++++++------- .../chat_page/composer/relation_preview.dart | 21 ++++--- lib/widgets/chat_page/html/mention_chip.dart | 53 ++++++++-------- .../lazy_loading/message_avatar.dart | 23 ++++--- .../lazy_loading/message_displayname.dart | 10 ++-- lib/widgets/chat_page/member_list.dart | 44 ++++++++------ lib/widgets/chat_page/room_chat.dart | 2 +- 8 files changed, 132 insertions(+), 94 deletions(-) diff --git a/lib/widgets/chat_page/composer/chat_box.dart b/lib/widgets/chat_page/composer/chat_box.dart index 340010c..f793fda 100644 --- a/lib/widgets/chat_page/composer/chat_box.dart +++ b/lib/widgets/chat_page/composer/chat_box.dart @@ -5,13 +5,14 @@ import "package:fluttertagger/fluttertagger.dart"; import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:nexus/controllers/power_level_controller.dart"; import "package:nexus/models/configs/power_level_config.dart"; +import "package:nexus/models/event.dart"; import "package:nexus/models/relation_type.dart"; import "package:nexus/widgets/chat_page/composer/mention_overlay.dart"; import "package:nexus/widgets/chat_page/composer/relation_preview.dart"; import "package:nexus/widgets/chat_page/emoji_picker_button.dart"; class ChatBox extends HookConsumerWidget { - final Message? relatedMessage; + final Event? relatedEvent; final RelationType relationType; final VoidCallback onDismiss; final FocusNode? node; @@ -22,7 +23,7 @@ class ChatBox extends HookConsumerWidget { }) onSend; const ChatBox({ - required this.relatedMessage, + required this.relatedEvent, required this.relationType, required this.onDismiss, required this.onSend, @@ -38,10 +39,8 @@ class ChatBox extends HookConsumerWidget { final shouldMention = useState(true); final query = useState(""); - if (relationType == RelationType.edit && - relatedMessage is TextMessage && - controller.value.text.isEmpty) { - controller.value.text = relatedMessage?.metadata?["editSource"] ?? ""; + if (relationType == RelationType.edit && controller.value.text.isEmpty) { + controller.value.text = relatedEvent?.localContent?.editSource ?? ""; } void send() { @@ -72,7 +71,7 @@ class ChatBox extends HookConsumerWidget { child: Column( children: [ RelationPreview( - relatedMessage, + relatedEvent, shouldMention: shouldMention.value, toggleShouldMention: () => shouldMention.value = !shouldMention.value, diff --git a/lib/widgets/chat_page/composer/mention_overlay.dart b/lib/widgets/chat_page/composer/mention_overlay.dart index b650421..b2a5492 100644 --- a/lib/widgets/chat_page/composer/mention_overlay.dart +++ b/lib/widgets/chat_page/composer/mention_overlay.dart @@ -4,6 +4,7 @@ import "package:nexus/controllers/members_by_type_controller.dart"; import "package:nexus/controllers/rooms_controller.dart"; import "package:nexus/controllers/via_controller.dart"; import "package:nexus/helpers/extensions/better_when.dart"; +import "package:nexus/models/content/membership.dart"; import "package:nexus/models/membership_status.dart"; import "package:nexus/widgets/avatar_or_hash.dart"; import "package:nexus/widgets/loading.dart"; @@ -43,33 +44,48 @@ class MentionOverlay extends ConsumerWidget { ? members : members.where( (member) => - member.userId.toLowerCase().contains( - query.toLowerCase(), - ) == - true || - member.displayName - .toLowerCase() + member.stateKey + ?.toLowerCase() .contains( query.toLowerCase(), ) == - true, + true || + switch (member.content) { + MembershipContent( + :final displayName, + ) => + displayName + .toLowerCase() + .contains( + query.toLowerCase(), + ) == + true, + _ => false, + }, )) .map( - (member) => ListTile( - leading: AvatarOrHash( - member.avatarUrl, - member.displayName, - ), - title: Text(member.displayName), - subtitle: Text(member.userId), - onTap: () => addTag( - id: "[@${member.displayName}](matrix:u/${member.userId.substring(1)})", - name: member.userId - .substring(1) - .split(":") - .first, - ), - ), + (member) => switch (member.content) { + MembershipContent( + :final displayName, + :final avatarUrl, + ) => + ListTile( + leading: AvatarOrHash( + avatarUrl, + displayName, + ), + title: Text(displayName), + subtitle: Text(member.stateKey!), + onTap: () => addTag( + id: "[@$displayName](matrix:u/${member.stateKey!.substring(1)})", + name: member.stateKey! + .substring(1) + .split(":") + .first, + ), + ), + _ => SizedBox.shrink(), + }, ) .toList(), ), diff --git a/lib/widgets/chat_page/composer/relation_preview.dart b/lib/widgets/chat_page/composer/relation_preview.dart index bd7dec1..d4d3649 100644 --- a/lib/widgets/chat_page/composer/relation_preview.dart +++ b/lib/widgets/chat_page/composer/relation_preview.dart @@ -1,18 +1,19 @@ import "package:flutter/material.dart"; import "package:hooks_riverpod/hooks_riverpod.dart"; +import "package:nexus/models/event.dart"; import "package:nexus/models/relation_type.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; + final Event? relatedEvent; final RelationType relationType; final VoidCallback onDismiss; final bool shouldMention; final VoidCallback toggleShouldMention; const RelationPreview( - this.relatedMessage, { + this.relatedEvent, { required this.relationType, required this.onDismiss, required this.shouldMention, @@ -22,7 +23,7 @@ class RelationPreview extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - if (relatedMessage == null) return SizedBox.shrink(); + if (relatedEvent == null) return SizedBox.shrink(); final theme = Theme.of(context); return Container( @@ -37,7 +38,7 @@ class RelationPreview extends ConsumerWidget { style: TextStyle(fontWeight: FontWeight.bold), ), - MessageAvatar(relatedMessage!), + MessageAvatar(relatedEvent!), Expanded( child: Row( @@ -45,16 +46,20 @@ class RelationPreview extends ConsumerWidget { children: [ Flexible( child: MessageDisplayname( - relatedMessage!, + relatedEvent!, style: theme.textTheme.labelMedium?.copyWith( fontWeight: FontWeight.bold, ), ), ), Expanded( - child: Text( - relatedMessage?.metadata?["body"] ?? - relatedMessage?.metadata?["eventType"] ?? + child: Text(switch (relatedEvent?.content) { + + _ => "" + } + + relatedEvent?.metadata?["body"] ?? + relatedEvent?.metadata?["eventType"] ?? "", maxLines: 1, overflow: TextOverflow.ellipsis, diff --git a/lib/widgets/chat_page/html/mention_chip.dart b/lib/widgets/chat_page/html/mention_chip.dart index 575ad03..059b997 100644 --- a/lib/widgets/chat_page/html/mention_chip.dart +++ b/lib/widgets/chat_page/html/mention_chip.dart @@ -10,35 +10,38 @@ class MentionChip extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final membership = content.mention!.startsWith("@") == true + final mention = content.mention; + final membership = mention?.startsWith("@") == true ? ref - .watch(UserController.provider(content.mention!)) + .watch(UserController.provider(mention!)) .whenOrNull(data: (data) => data) : null; - return InkWell( - onTapUp: (details) { - content.mention; - if (membership != null) { - context.showUserPopover( - membership, - globalPosition: details.globalPosition, - ); - } - }, - child: IgnorePointer( - child: Chip( - label: Text( - (membership == null ? null : "@${membership.displayName}") ?? - content.mention!, - style: TextStyle( - fontWeight: FontWeight.bold, - color: Theme.of(context).colorScheme.onPrimary, + return mention == null + ? SizedBox.shrink() + : InkWell( + onTapUp: (details) { + if (membership != null) { + context.showUserPopover( + membership, + mention, + globalPosition: details.globalPosition, + ); + } + }, + child: IgnorePointer( + child: Chip( + label: Text( + (membership == null ? null : "@${membership.displayName}") ?? + mention, + style: TextStyle( + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.onPrimary, + ), + ), + backgroundColor: Theme.of(context).colorScheme.primary, + ), ), - ), - backgroundColor: Theme.of(context).colorScheme.primary, - ), - ), - ); + ); } } diff --git a/lib/widgets/chat_page/lazy_loading/message_avatar.dart b/lib/widgets/chat_page/lazy_loading/message_avatar.dart index 4cc6665..7615be0 100644 --- a/lib/widgets/chat_page/lazy_loading/message_avatar.dart +++ b/lib/widgets/chat_page/lazy_loading/message_avatar.dart @@ -3,22 +3,29 @@ import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:nexus/controllers/author_controller.dart"; import "package:nexus/helpers/extensions/better_when.dart"; import "package:nexus/helpers/extensions/show_user_popover.dart"; +import "package:nexus/models/content/membership.dart"; +import "package:nexus/models/event.dart"; import "package:nexus/widgets/avatar_or_hash.dart"; class MessageAvatar extends ConsumerWidget { - final Message message; + final Event event; final double height; - const MessageAvatar(this.message, {this.height = 16, super.key}); + const MessageAvatar(this.event, {this.height = 16, super.key}); @override Widget build(BuildContext context, WidgetRef ref) => ref - .watch(AuthorController.provider(message)) + .watch(AuthorController.provider(event)) .betterWhen( data: (membership) => InkWell( - onTapUp: (details) => context.showUserPopover( - membership, - globalPosition: details.globalPosition, - ), + onTapUp: (details) { + if (event.content is MembershipContent) { + context.showUserPopover( + event.content as MembershipContent, + event.stateKey!, + globalPosition: details.globalPosition, + ); + } + }, child: AvatarOrHash( membership.avatarUrl, membership.displayName, @@ -26,6 +33,6 @@ class MessageAvatar extends ConsumerWidget { ), ), loading: () => - AvatarOrHash(null, message.sender.substring(1), height: height), + AvatarOrHash(null, event.stateKey!.substring(1), height: height), ); } diff --git a/lib/widgets/chat_page/lazy_loading/message_displayname.dart b/lib/widgets/chat_page/lazy_loading/message_displayname.dart index 72565e6..aa198ae 100644 --- a/lib/widgets/chat_page/lazy_loading/message_displayname.dart +++ b/lib/widgets/chat_page/lazy_loading/message_displayname.dart @@ -3,13 +3,14 @@ import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:nexus/controllers/author_controller.dart"; import "package:nexus/helpers/extensions/better_when.dart"; import "package:nexus/helpers/extensions/show_user_popover.dart"; +import "package:nexus/models/event.dart"; class MessageDisplayname extends ConsumerWidget { - final Message message; + final Event event; final TextStyle? style; final bool clickable; const MessageDisplayname( - this.message, { + this.event, { this.clickable = true, this.style, super.key, @@ -17,17 +18,18 @@ class MessageDisplayname extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) => ref - .watch(AuthorController.provider(message)) + .watch(AuthorController.provider(event)) .betterWhen( data: (membership) => InkWell( onTapUp: clickable ? (details) => context.showUserPopover( membership, + event.stateKey!, globalPosition: details.globalPosition, ) : null, child: Text( - "${membership.displayName}${message.metadata?["pmp"] == null ? "" : " (via ${message.sender})"}", + "${membership.displayName}${event.pmp == null ? "" : " (via ${event.stateKey})"}", style: style, overflow: TextOverflow.ellipsis, ), diff --git a/lib/widgets/chat_page/member_list.dart b/lib/widgets/chat_page/member_list.dart index 8be1ddd..3af1f0a 100644 --- a/lib/widgets/chat_page/member_list.dart +++ b/lib/widgets/chat_page/member_list.dart @@ -4,6 +4,7 @@ import "package:hooks_riverpod/hooks_riverpod.dart"; import "package:nexus/controllers/members_by_type_controller.dart"; import "package:nexus/helpers/extensions/better_when.dart"; import "package:nexus/helpers/extensions/show_user_popover.dart"; +import "package:nexus/models/content/membership.dart"; import "package:nexus/models/membership_status.dart"; import "package:nexus/widgets/avatar_or_hash.dart"; @@ -62,26 +63,31 @@ class MemberList extends HookConsumerWidget { child: ListView( children: members .map( - (member) => InkWell( - onTapUp: (details) => context.showUserPopover( - member, - globalPosition: details.globalPosition, - ), - child: ListTile( - leading: AvatarOrHash( - member.avatarUrl, - member.displayName, + (member) => switch (member.content) { + MembershipContent( + :final avatarUrl, + :final displayName, + ) => + InkWell( + onTapUp: (details) => context.showUserPopover( + member.content as MembershipContent, + member.stateKey!, + globalPosition: details.globalPosition, + ), + child: ListTile( + leading: AvatarOrHash(avatarUrl, displayName), + title: Text( + displayName, + overflow: TextOverflow.ellipsis, + ), + subtitle: Text( + member.stateKey!, + overflow: TextOverflow.ellipsis, + ), + ), ), - title: Text( - member.displayName, - overflow: TextOverflow.ellipsis, - ), - subtitle: Text( - member.userId, - overflow: TextOverflow.ellipsis, - ), - ), - ), + _ => SizedBox.shrink(), + }, ) .toList(), ), diff --git a/lib/widgets/chat_page/room_chat.dart b/lib/widgets/chat_page/room_chat.dart index 3507d84..b4639e5 100644 --- a/lib/widgets/chat_page/room_chat.dart +++ b/lib/widgets/chat_page/room_chat.dart @@ -371,7 +371,7 @@ class RoomChat extends HookConsumerWidget { ) .onError(showError), relationType: relationType.value, - relatedMessage: relatedMessage.value, + relatedEvent: relatedMessage.value, onDismiss: () => relatedMessage.value = null, ),