From c6816aea03842d9e206bc6d475ae6bdb900b1bdb Mon Sep 17 00:00:00 2001 From: ggurdin <46800240+ggurdin@users.noreply.github.com> Date: Mon, 15 Sep 2025 16:19:24 -0400 Subject: [PATCH] chore: show user menu on click participant item (#3992) --- .../activity_participant_indicator.dart | 157 +++++++++--------- .../activity_participant_list.dart | 68 ++++---- .../activity_user_summaries_widget.dart | 2 +- 3 files changed, 118 insertions(+), 109 deletions(-) diff --git a/lib/pangea/activity_sessions/activity_participant_indicator.dart b/lib/pangea/activity_sessions/activity_participant_indicator.dart index 0a2e6ff70..202cee416 100644 --- a/lib/pangea/activity_sessions/activity_participant_indicator.dart +++ b/lib/pangea/activity_sessions/activity_participant_indicator.dart @@ -7,11 +7,12 @@ import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/utils/string_color.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/hover_builder.dart'; +import 'package:fluffychat/widgets/member_actions_popup_menu_button.dart'; class ActivityParticipantIndicator extends StatelessWidget { final String name; final String? userId; - final String? avatarUrl; + final User? user; final VoidCallback? onTap; final bool selected; @@ -23,7 +24,7 @@ class ActivityParticipantIndicator extends StatelessWidget { const ActivityParticipantIndicator({ super.key, required this.name, - this.avatarUrl, + this.user, this.userId, this.selected = false, this.onTap, @@ -35,82 +36,84 @@ class ActivityParticipantIndicator extends StatelessWidget { @override Widget build(BuildContext context) { final theme = Theme.of(context); - return AbsorbPointer( - absorbing: onTap == null, - child: MouseRegion( - cursor: SystemMouseCursors.click, - child: GestureDetector( - onTap: onTap, - child: HoverBuilder( - builder: (context, hovered) { - return Opacity( - opacity: opacity, - child: Container( - padding: padding ?? - const EdgeInsets.symmetric( - vertical: 4.0, - horizontal: 8.0, - ), - decoration: BoxDecoration( - borderRadius: borderRadius ?? BorderRadius.circular(8.0), - color: hovered || selected - ? theme.colorScheme.surfaceContainerHighest - : Colors.transparent, - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - userId != null - ? avatarUrl == null || avatarUrl!.startsWith("mxc") - ? Avatar( - mxContent: avatarUrl != null - ? Uri.parse(avatarUrl!) - : null, - name: userId!.localpart, - size: 60.0, - userId: userId, - ) - : ClipRRect( - borderRadius: BorderRadius.circular(30), - child: CachedNetworkImage( - imageUrl: avatarUrl!, - width: 60.0, - height: 60.0, - fit: BoxFit.cover, - ), - ) - : CircleAvatar( - radius: 30.0, - backgroundColor: - theme.colorScheme.primaryContainer, - child: const Icon( - Icons.question_mark, - size: 30.0, - ), - ), - Text( - name, - style: const TextStyle( - fontSize: 12.0, - ), - ), - Text( - userId?.localpart ?? L10n.of(context).openRoleLabel, - style: TextStyle( - fontSize: 12.0, - color: - (Theme.of(context).brightness == Brightness.light - ? userId?.localpart?.darkColor - : userId?.localpart?.lightColorText) ?? - name.lightColorAvatar, - ), - ), - ], - ), + return MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: onTap ?? + (user != null + ? () => showMemberActionsPopupMenu( + context: context, + user: user!, + ) + : null), + child: HoverBuilder( + builder: (context, hovered) { + return Opacity( + opacity: opacity, + child: Container( + padding: padding ?? + const EdgeInsets.symmetric( + vertical: 4.0, + horizontal: 8.0, + ), + decoration: BoxDecoration( + borderRadius: borderRadius ?? BorderRadius.circular(8.0), + color: hovered || selected + ? theme.colorScheme.surfaceContainerHighest + : Colors.transparent, ), - ); - }, - ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + userId != null + ? user?.avatarUrl == null || + user!.avatarUrl!.toString().startsWith("mxc") + ? Avatar( + mxContent: user?.avatarUrl != null + ? user!.avatarUrl! + : null, + name: userId!.localpart, + size: 60.0, + userId: userId, + ) + : ClipRRect( + borderRadius: BorderRadius.circular(30), + child: CachedNetworkImage( + imageUrl: user!.avatarUrl!.toString(), + width: 60.0, + height: 60.0, + fit: BoxFit.cover, + ), + ) + : CircleAvatar( + radius: 30.0, + backgroundColor: theme.colorScheme.primaryContainer, + child: const Icon( + Icons.question_mark, + size: 30.0, + ), + ), + Text( + name, + style: const TextStyle( + fontSize: 12.0, + ), + ), + Text( + userId?.localpart ?? L10n.of(context).openRoleLabel, + style: TextStyle( + fontSize: 12.0, + color: (Theme.of(context).brightness == Brightness.light + ? userId?.localpart?.darkColor + : userId?.localpart?.lightColorText) ?? + name.lightColorAvatar, + ), + ), + ], + ), + ), + ); + }, ), ), ); diff --git a/lib/pangea/activity_sessions/activity_participant_list.dart b/lib/pangea/activity_sessions/activity_participant_list.dart index db49014fe..a5595fe83 100644 --- a/lib/pangea/activity_sessions/activity_participant_list.dart +++ b/lib/pangea/activity_sessions/activity_participant_list.dart @@ -10,6 +10,7 @@ import 'package:fluffychat/pangea/activity_sessions/activity_room_extension.dart import 'package:fluffychat/pangea/spaces/utils/load_participants_util.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/matrix.dart'; +import 'package:fluffychat/widgets/member_actions_popup_menu_button.dart'; class ActivityParticipantList extends StatelessWidget { final ActivityPlanModel activity; @@ -79,8 +80,7 @@ class ActivityParticipantList extends StatelessWidget { name: availableRole.name, userId: assignedRole?.userId, opacity: getOpacity != null ? getOpacity!(assignedRole) : 1.0, - avatarUrl: - availableRole.avatarUrl ?? user?.avatarUrl?.toString(), + user: user, onTap: onTap != null && selectable ? () => onTap!(availableRole.id) : null, @@ -93,39 +93,45 @@ class ActivityParticipantList extends StatelessWidget { spacing: 12.0, runSpacing: 12.0, children: remainingMembers.map((member) { - return Container( - decoration: BoxDecoration( - color: theme.colorScheme.primaryContainer, - borderRadius: BorderRadius.circular(18.0), + return InkWell( + onTap: () => showMemberActionsPopupMenu( + context: context, + user: member, ), - padding: const EdgeInsets.all(4.0), - child: Opacity( - opacity: 0.5, - child: Row( - spacing: 4.0, - mainAxisSize: MainAxisSize.min, - children: [ - Avatar( - size: 18.0, - mxContent: member.avatarUrl, - name: member.calcDisplayname(), - userId: member.id, - ), - ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 80.0, + child: Container( + decoration: BoxDecoration( + color: theme.colorScheme.primaryContainer, + borderRadius: BorderRadius.circular(18.0), + ), + padding: const EdgeInsets.all(4.0), + child: Opacity( + opacity: 0.5, + child: Row( + spacing: 4.0, + mainAxisSize: MainAxisSize.min, + children: [ + Avatar( + size: 18.0, + mxContent: member.avatarUrl, + name: member.calcDisplayname(), + userId: member.id, ), - child: Text( - member.calcDisplayname(), - style: TextStyle( - fontSize: 12.0, - color: theme.colorScheme.onPrimaryContainer, + ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 80.0, + ), + child: Text( + member.calcDisplayname(), + style: TextStyle( + fontSize: 12.0, + color: theme.colorScheme.onPrimaryContainer, + ), + overflow: TextOverflow.ellipsis, + maxLines: 1, ), - overflow: TextOverflow.ellipsis, - maxLines: 1, ), - ), - ], + ], + ), ), ), ); diff --git a/lib/pangea/activity_sessions/activity_user_summaries_widget.dart b/lib/pangea/activity_sessions/activity_user_summaries_widget.dart index f371b58f1..4bc2e6de8 100644 --- a/lib/pangea/activity_sessions/activity_user_summaries_widget.dart +++ b/lib/pangea/activity_sessions/activity_user_summaries_widget.dart @@ -236,7 +236,7 @@ class ButtonControlledCarouselView extends StatelessWidget { return ActivityParticipantIndicator( name: userRoleInfo.name, userId: p.participantId, - avatarUrl: userRoleInfo.avatarUrl ?? user?.avatarUrl?.toString(), + user: user, borderRadius: BorderRadius.circular(4), selected: controller.highlightedRole?.id == userRole.id, onTap: () {