use a text span with a recognizer instead of a WidgetSpan

Fixes displaynames not ellipsising properly
This commit is contained in:
Henry Hiles 2026-10-26 12:45:54 -04:00
commit f971c50df0
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
2 changed files with 139 additions and 67 deletions

View file

@ -11,6 +11,7 @@ import "package:nexus/helpers/extensions/is_shown_as_message.dart";
import "package:nexus/helpers/extensions/show_adaptive_menu.dart";
import "package:nexus/helpers/extensions/success_scheme.dart";
import "package:nexus/helpers/hooks/chat_scroll.dart";
import "package:nexus/helpers/hooks/tap_recognizer.dart";
import "package:nexus/models/content/avatar.dart";
import "package:nexus/models/content/canonical_alias.dart";
import "package:nexus/models/content/content.dart";
@ -26,7 +27,6 @@ import "package:nexus/models/content/server_acl.dart";
import "package:nexus/models/content/topic.dart";
import "package:nexus/models/event.dart";
import "package:nexus/widgets/error_dialog.dart";
import "package:nexus/widgets/lazy_loading/message_displayname.dart";
import "package:nexus/widgets/renderers/message.dart";
import "package:nexus/widgets/reaction_row.dart";
import "package:nexus/widgets/read_receipts_row.dart";
@ -39,6 +39,7 @@ import "package:nexus/widgets/renderers/pinned_events_diff.dart";
import "package:nexus/widgets/renderers/server_acl_diff.dart";
import "package:nexus/widgets/swipe_to_reply.dart";
import "package:nexus/widgets/timestamp.dart";
import "package:nexus/widgets/user_span.dart";
class const EventRenderer(
final int eventRowId, {
@ -64,6 +65,7 @@ class const EventRenderer(
final errorStyle = TextStyle(color: colorScheme.error);
final focusNode = useFocusNode();
useListenable(focusNode);
final senderRecognizer = useTapRecognizer();
final (event, previousEvent) = ref.watch(
RoomsController.provider.select((rooms) {
@ -130,10 +132,7 @@ class const EventRenderer(
details: details,
trailing: Timestamp(event.timestamp),
[
WidgetSpan(
alignment: .middle,
child: MessageDisplayname(event, shouldWrap: maxLines == null),
),
UserSpan.sender(context, ref, event, recognizer: senderRecognizer),
TextSpan(text: text),
],
);

View file

@ -1,18 +1,18 @@
import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:material_ui/material_ui.dart";
import "package:nexus/helpers/extensions/get_localpart.dart";
import "package:nexus/helpers/extensions/show_user_popover.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/helpers/extensions/displayname_color.dart";
import "package:nexus/helpers/extensions/get_localpart.dart";
import "package:nexus/helpers/hooks/tap_recognizer.dart";
import "package:nexus/models/content/membership.dart";
import "package:nexus/models/event.dart";
import "package:nexus/widgets/lazy_loading/message_displayname.dart";
import "package:nexus/widgets/renderers/generic_event.dart";
import "package:nexus/widgets/user_span.dart";
class const MembershipRenderer(
final Event event, {
final int? maxLines,
super.key,
}) extends ConsumerWidget {
}) extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
assert(
@ -20,6 +20,8 @@ class const MembershipRenderer(
"Make sure to only pass membership events to MembershipRenderer",
);
final targetRecognizer = useTapRecognizer();
final senderRecognizer = useTapRecognizer();
final previous = switch (event.previousContent) {
MembershipContent(:final status) => status,
_ => null,
@ -30,22 +32,15 @@ class const MembershipRenderer(
Icons.people,
maxLines: maxLines,
[
WidgetSpan(
alignment: .middle,
child: InkWell(
onTap: () => context.showUserPopover(
event.stateKey!,
roomId: event.roomId,
),
child: Text(
overflow: .ellipsis,
content.displayName ?? event.stateKey!.localpart,
maxLines: 1,
style: .new(
color: ref.displaynameColor(event.roomId, event.stateKey!),
fontWeight: .bold,
),
),
UserSpan(
context,
content.displayName ?? event.stateKey!.localpart,
userId: event.stateKey!,
roomId: event.roomId,
recognizer: targetRecognizer,
style: .new(
color: ref.displaynameColor(event.roomId, event.stateKey!),
fontWeight: .bold,
),
),
TextSpan(
@ -61,10 +56,7 @@ class const MembershipRenderer(
}} the room${event.sender == event.stateKey ? "" : " by"}",
),
if (event.sender != event.stateKey)
WidgetSpan(
alignment: .middle,
child: MessageDisplayname(event, shouldWrap: maxLines == null),
),
UserSpan.sender(context, ref, event, recognizer: senderRecognizer),
if (content.reason != null)
TextSpan(text: "for \"${content.reason}\""),
],