Merge pull request #5452 from pangeachat/5425-expand-role-card-if-neededavailable-space

5425 expand role card if neededavailable space
This commit is contained in:
ggurdin 2026-01-27 11:54:17 -05:00 committed by GitHub
commit 0c0cadb743
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 93 additions and 54 deletions

View file

@ -45,6 +45,7 @@ class ActivityParticipantIndicator extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final borderRadius = this.borderRadius ?? BorderRadius.circular(8.0);
return MouseRegion(
cursor: SystemMouseCursors.basic,
child: GestureDetector(
@ -99,20 +100,21 @@ class ActivityParticipantIndicator extends StatelessWidget {
opacity: opacity,
child: ShimmerBackground(
enabled: shimmer,
borderRadius: borderRadius,
child: Container(
alignment: Alignment.center,
padding: padding ??
const EdgeInsets.symmetric(
vertical: 4.0,
horizontal: 8.0,
),
decoration: BoxDecoration(
borderRadius: borderRadius ?? BorderRadius.circular(8.0),
borderRadius: borderRadius,
color: (hovered || selected) && selectable
? theme.colorScheme.surfaceContainerHighest
: theme.colorScheme.surface.withAlpha(130),
),
height: 125.0,
constraints: const BoxConstraints(maxWidth: 100.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [

View file

@ -52,51 +52,79 @@ class ActivityParticipantList extends StatelessWidget {
spacing: 12.0,
mainAxisSize: MainAxisSize.min,
children: [
Wrap(
alignment: WrapAlignment.center,
spacing: 12.0,
runSpacing: 12.0,
children: availableRoles.map((availableRole) {
final selected =
isSelected != null ? isSelected!(availableRole.id) : false;
LayoutBuilder(
builder: (context, constraints) {
const minItemWidth = 125.0;
final assignedRole = assignedRoles[availableRole.id] ??
(selected
? ActivityRoleModel(
id: availableRole.id,
userId: Matrix.of(context).client.userID!,
role: availableRole.name,
)
: null);
final rows = (availableRoles.length /
(constraints.maxWidth / minItemWidth))
.ceil();
final User? user = participants.participants.firstWhereOrNull(
(u) => u.id == assignedRole?.userId,
) ??
course?.getParticipants().firstWhereOrNull(
(u) => u.id == assignedRole?.userId,
final entriesPerRow = (availableRoles.length / rows).ceil();
return Column(
spacing: 8.0,
children: List.generate(rows, (rowIndex) {
final entries = availableRoles
.skip(rowIndex * entriesPerRow)
.take(entriesPerRow)
.toList();
return Row(
spacing: 8.0,
mainAxisAlignment: MainAxisAlignment.center,
children: entries.map((availableRole) {
final selected = isSelected != null
? isSelected!(availableRole.id)
: false;
final assignedRole = assignedRoles[availableRole.id] ??
(selected
? ActivityRoleModel(
id: availableRole.id,
userId: Matrix.of(context).client.userID!,
role: availableRole.name,
)
: null);
final User? user =
participants.participants.firstWhereOrNull(
(u) => u.id == assignedRole?.userId,
) ??
course?.getParticipants().firstWhereOrNull(
(u) => u.id == assignedRole?.userId,
);
final selectable = canSelect != null
? canSelect!(availableRole.id)
: true;
final shimmering = isShimmering != null
? isShimmering!(availableRole.id)
: false;
return Expanded(
child: ActivityParticipantIndicator(
name: availableRole.name,
userId: assignedRole?.userId,
opacity: getOpacity != null
? getOpacity!(assignedRole)
: 1.0,
user: user,
onTap: onTap != null && selectable
? () => onTap!(availableRole.id)
: null,
selected: selected,
selectable: selectable,
shimmer: shimmering,
room: room,
),
);
final selectable =
canSelect != null ? canSelect!(availableRole.id) : true;
final shimmering = isShimmering != null
? isShimmering!(availableRole.id)
: false;
return ActivityParticipantIndicator(
name: availableRole.name,
userId: assignedRole?.userId,
opacity: getOpacity != null ? getOpacity!(assignedRole) : 1.0,
user: user,
onTap: onTap != null && selectable
? () => onTap!(availableRole.id)
: null,
selected: selected,
selectable: selectable,
shimmer: shimmering,
room: room,
}).toList(),
);
}),
);
}).toList(),
},
),
Wrap(
alignment: WrapAlignment.center,

View file

@ -290,14 +290,20 @@ class ButtonControlledCarouselView extends StatelessWidget {
(role) => role.userId == p.participantId,
);
final userRoleInfo = availableRoles[userRole.id]!;
return ActivityParticipantIndicator(
name: userRoleInfo.name,
userId: p.participantId,
user: user,
borderRadius: BorderRadius.circular(4),
selected: highlightedRole?.id == userRole.id,
onTap: () => _scrollToUser(userRole, index, cardWidth),
room: controller.room,
return SizedBox(
width: 100.0,
height: 125.0,
child: Center(
child: ActivityParticipantIndicator(
name: userRoleInfo.name,
userId: p.participantId,
user: user,
borderRadius: BorderRadius.circular(4),
selected: highlightedRole?.id == userRole.id,
onTap: () => _scrollToUser(userRole, index, cardWidth),
room: controller.room,
),
),
);
},
);

View file

@ -9,6 +9,7 @@ class ShimmerBackground extends StatelessWidget {
final Color shimmerColor;
final Color? baseColor;
final bool enabled;
final BorderRadius? borderRadius;
const ShimmerBackground({
super.key,
@ -16,10 +17,13 @@ class ShimmerBackground extends StatelessWidget {
this.shimmerColor = AppConfig.goldLight,
this.baseColor,
this.enabled = true,
this.borderRadius,
});
@override
Widget build(BuildContext context) {
final borderRadius =
this.borderRadius ?? BorderRadius.circular(AppConfig.borderRadius);
return Stack(
children: [
child,
@ -27,7 +31,7 @@ class ShimmerBackground extends StatelessWidget {
Positioned.fill(
child: IgnorePointer(
child: ClipRRect(
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
borderRadius: borderRadius,
child: Shimmer.fromColors(
baseColor: baseColor ?? shimmerColor.withValues(alpha: 0.1),
highlightColor: shimmerColor.withValues(alpha: 0.6),
@ -35,8 +39,7 @@ class ShimmerBackground extends StatelessWidget {
child: Container(
decoration: BoxDecoration(
color: shimmerColor.withValues(alpha: 0.3),
borderRadius:
BorderRadius.circular(AppConfig.borderRadius),
borderRadius: borderRadius,
),
),
),