diff --git a/lib/pangea/activity_sessions/activity_participant_list.dart b/lib/pangea/activity_sessions/activity_participant_list.dart new file mode 100644 index 000000000..1f6c1181c --- /dev/null +++ b/lib/pangea/activity_sessions/activity_participant_list.dart @@ -0,0 +1,115 @@ +import 'package:flutter/material.dart'; + +import 'package:collection/collection.dart'; +import 'package:matrix/matrix.dart'; + +import 'package:fluffychat/pangea/activity_sessions/activity_participant_indicator.dart'; +import 'package:fluffychat/pangea/activity_sessions/activity_role_model.dart'; +import 'package:fluffychat/pangea/activity_sessions/activity_room_extension.dart'; +import 'package:fluffychat/widgets/avatar.dart'; + +class ActivityParticipantList extends StatelessWidget { + final Room room; + final Function(String)? onTap; + + final bool Function(String)? canSelect; + final bool Function(String)? isSelected; + final double Function(ActivityRoleModel?)? getOpacity; + + const ActivityParticipantList({ + super.key, + required this.room, + this.onTap, + this.canSelect, + this.isSelected, + this.getOpacity, + }); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + final availableRoles = room.activityPlan!.roles; + final assignedRoles = room.assignedRoles ?? {}; + + final remainingMembers = room.getParticipants().where( + (p) => !assignedRoles.values.any((r) => r.userId == p.id), + ); + + return Column( + spacing: 12.0, + mainAxisSize: MainAxisSize.min, + children: [ + Wrap( + alignment: WrapAlignment.center, + spacing: 12.0, + runSpacing: 12.0, + children: availableRoles.values.map((availableRole) { + final assignedRole = assignedRoles[availableRole.id]; + final user = room.getParticipants().firstWhereOrNull( + (u) => u.id == assignedRole?.userId, + ); + + final selectable = + canSelect != null ? canSelect!(availableRole.id) : true; + + return ActivityParticipantIndicator( + availableRole: availableRole, + assignedRole: assignedRole, + opacity: getOpacity != null ? getOpacity!(assignedRole) : 1.0, + avatarUrl: availableRole.avatarUrl ?? user?.avatarUrl?.toString(), + onTap: onTap != null && selectable + ? () => onTap!(availableRole.id) + : null, + selected: + isSelected != null ? isSelected!(availableRole.id) : false, + ); + }).toList(), + ), + Wrap( + alignment: WrapAlignment.center, + spacing: 12.0, + runSpacing: 12.0, + children: remainingMembers.map((member) { + return 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, + ), + 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, + ), + ), + ], + ), + ), + ); + }).toList(), + ), + ], + ); + } +} diff --git a/lib/pangea/activity_sessions/activity_state_event.dart b/lib/pangea/activity_sessions/activity_state_event.dart index c6a6bf23d..a2c35f6c9 100644 --- a/lib/pangea/activity_sessions/activity_state_event.dart +++ b/lib/pangea/activity_sessions/activity_state_event.dart @@ -1,14 +1,12 @@ import 'package:flutter/material.dart'; -import 'package:collection/collection.dart'; import 'package:matrix/matrix.dart'; import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/chat/events/state_message.dart'; import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart'; -import 'package:fluffychat/pangea/activity_sessions/activity_participant_indicator.dart'; +import 'package:fluffychat/pangea/activity_sessions/activity_participant_list.dart'; import 'package:fluffychat/pangea/activity_sessions/activity_room_extension.dart'; -import 'package:fluffychat/widgets/avatar.dart'; class ActivityStateEvent extends StatelessWidget { final Event event; @@ -22,15 +20,6 @@ class ActivityStateEvent extends StatelessWidget { try { final activity = ActivityPlanModel.fromJson(event.content); - final availableRoles = event.room.activityPlan!.roles; - final assignedRoles = event.room.assignedRoles ?? {}; - - final remainingMembers = event.room.getParticipants().where( - (p) => !assignedRoles.values.any((r) => r.userId == p.id), - ); - - final theme = Theme.of(context); - return Container( padding: const EdgeInsets.symmetric( horizontal: 24.0, @@ -48,69 +37,10 @@ class ActivityStateEvent extends StatelessWidget { ), if (event.room.ownRole != null || event.room.remainingRoles == 0) ...[ - Wrap( - alignment: WrapAlignment.center, - spacing: 12.0, - runSpacing: 12.0, - children: availableRoles.values.map((availableRole) { - final assignedRole = assignedRoles[availableRole.id]; - final user = event.room.getParticipants().firstWhereOrNull( - (u) => u.id == assignedRole?.userId, - ); - - return ActivityParticipantIndicator( - availableRole: availableRole, - assignedRole: assignedRole, - opacity: assignedRole == null || assignedRole.isFinished - ? 0.5 - : 1.0, - avatarUrl: - availableRole.avatarUrl ?? user?.avatarUrl?.toString(), - ); - }).toList(), - ), - Wrap( - alignment: WrapAlignment.center, - spacing: 12.0, - runSpacing: 12.0, - children: remainingMembers.map((member) { - return 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, - ), - 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, - ), - ), - ], - ), - ), - ); - }).toList(), + ActivityParticipantList( + room: event.room, + getOpacity: (role) => + role == null || role.isFinished ? 0.5 : 1.0, ), ], ], diff --git a/lib/pangea/activity_sessions/activity_unfinished_status_message.dart b/lib/pangea/activity_sessions/activity_unfinished_status_message.dart index 33881f315..0f02d656b 100644 --- a/lib/pangea/activity_sessions/activity_unfinished_status_message.dart +++ b/lib/pangea/activity_sessions/activity_unfinished_status_message.dart @@ -4,7 +4,7 @@ import 'package:matrix/matrix.dart'; import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/l10n/l10n.dart'; -import 'package:fluffychat/pangea/activity_sessions/activity_participant_indicator.dart'; +import 'package:fluffychat/pangea/activity_sessions/activity_participant_list.dart'; import 'package:fluffychat/pangea/activity_sessions/activity_room_extension.dart'; import 'package:fluffychat/widgets/future_loading_dialog.dart'; @@ -47,18 +47,11 @@ class ActivityUnfinishedStatusMessageState children: [ if (!completed) ...[ if (unassignedIds.isNotEmpty) - Wrap( - alignment: WrapAlignment.center, - spacing: 12.0, - runSpacing: 12.0, - children: unassignedIds.map((id) { - return ActivityParticipantIndicator( - availableRole: availableRoles[id]!, - selected: _selectedRoleId == id, - onTap: () => _selectRole(id), - avatarUrl: availableRoles[id]?.avatarUrl, - ); - }).toList(), + ActivityParticipantList( + room: widget.room, + onTap: _selectRole, + isSelected: (id) => _selectedRoleId == id, + canSelect: (id) => unassignedIds.contains(id), ), const SizedBox(height: 16.0), Text( diff --git a/lib/pangea/space_analytics/space_analytics_view.dart b/lib/pangea/space_analytics/space_analytics_view.dart index 83715a10f..9ad405310 100644 --- a/lib/pangea/space_analytics/space_analytics_view.dart +++ b/lib/pangea/space_analytics/space_analytics_view.dart @@ -173,22 +173,27 @@ class SpaceAnalyticsView extends StatelessWidget { controller.downloads.length, ), icon: Icons.group_outlined, + mini: mini, ), _TableHeaderCell( text: L10n.of(context).level, icon: Icons.star, + mini: mini, ), _TableHeaderCell( text: L10n.of(context).vocab, icon: Symbols.dictionary, + mini: mini, ), _TableHeaderCell( text: L10n.of(context).grammar, icon: Symbols.toys_and_games, + mini: mini, ), _TableHeaderCell( text: L10n.of(context).activities, icon: Icons.radar, + mini: mini, ), ], ), @@ -263,18 +268,21 @@ class SpaceAnalyticsView extends StatelessWidget { text: download.summary?.level?.toString(), downloadStatus: download.downloadStatus, requestStatus: download.requestStatus, + mini: mini, ), _TableContentCell( text: download.summary?.numLemmas .toString(), downloadStatus: download.downloadStatus, requestStatus: download.requestStatus, + mini: mini, ), _TableContentCell( text: download.summary?.numMorphConstructs .toString(), downloadStatus: download.downloadStatus, requestStatus: download.requestStatus, + mini: mini, ), _TableContentCell( text: download @@ -282,6 +290,7 @@ class SpaceAnalyticsView extends StatelessWidget { .toString(), downloadStatus: download.downloadStatus, requestStatus: download.requestStatus, + mini: mini, ), ], );