diff --git a/lib/pangea/activity_sessions/activity_participant_indicator.dart b/lib/pangea/activity_sessions/activity_participant_indicator.dart index 12fb4f77a..c8c06a259 100644 --- a/lib/pangea/activity_sessions/activity_participant_indicator.dart +++ b/lib/pangea/activity_sessions/activity_participant_indicator.dart @@ -2,7 +2,9 @@ import 'package:flutter/material.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:matrix/matrix.dart'; +import 'package:shimmer/shimmer.dart'; +import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/utils/string_color.dart'; import 'package:fluffychat/widgets/avatar.dart'; @@ -17,6 +19,7 @@ class ActivityParticipantIndicator extends StatelessWidget { final VoidCallback? onTap; final bool selected; final bool selectable; + final bool shimmer; final double opacity; final EdgeInsetsGeometry? padding; @@ -29,6 +32,7 @@ class ActivityParticipantIndicator extends StatelessWidget { this.userId, this.selected = false, this.selectable = true, + this.shimmer = false, this.onTap, this.opacity = 1.0, this.padding, @@ -70,35 +74,46 @@ class ActivityParticipantIndicator extends StatelessWidget { 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, + Shimmer.fromColors( + enabled: shimmer && !selected, + baseColor: shimmer && !selected + ? AppConfig.gold.withAlpha(20) + : Colors.transparent, + highlightColor: shimmer && !selected + ? AppConfig.gold.withAlpha(50) + : Colors.transparent, + child: 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( diff --git a/lib/pangea/activity_sessions/activity_participant_list.dart b/lib/pangea/activity_sessions/activity_participant_list.dart index b8fab53e4..d3decbf81 100644 --- a/lib/pangea/activity_sessions/activity_participant_list.dart +++ b/lib/pangea/activity_sessions/activity_participant_list.dart @@ -20,6 +20,7 @@ class ActivityParticipantList extends StatelessWidget { final bool Function(String)? canSelect; final bool Function(String)? isSelected; + final bool Function(String)? isShimmering; final double Function(ActivityRoleModel?)? getOpacity; const ActivityParticipantList({ @@ -31,6 +32,7 @@ class ActivityParticipantList extends StatelessWidget { this.onTap, this.canSelect, this.isSelected, + this.isShimmering, this.getOpacity, }); @@ -76,6 +78,10 @@ class ActivityParticipantList extends StatelessWidget { final selectable = canSelect != null ? canSelect!(availableRole.id) : true; + final shimmering = isShimmering != null + ? isShimmering!(availableRole.id) + : false; + return ActivityParticipantIndicator( name: availableRole.name, userId: assignedRole?.userId, @@ -86,6 +92,7 @@ class ActivityParticipantList extends StatelessWidget { : null, selected: selected, selectable: selectable, + shimmer: shimmering, ); }).toList(), ), diff --git a/lib/pangea/activity_sessions/activity_session_start/activity_session_start_page.dart b/lib/pangea/activity_sessions/activity_session_start/activity_session_start_page.dart index 468a166cd..bc27ed213 100644 --- a/lib/pangea/activity_sessions/activity_session_start/activity_session_start_page.dart +++ b/lib/pangea/activity_sessions/activity_session_start/activity_session_start_page.dart @@ -179,6 +179,21 @@ class ActivitySessionStartController extends State return unassignedIds.contains(id); } + bool isParticipantShimmering(String id) { + if (state != SessionState.notSelectedRole) { + return false; + } + + final availableRoles = activity!.roles; + final assignedRoles = activityRoom?.assignedRoles ?? + roomSummaries?[widget.roomId]?.activityRoles.roles ?? + {}; + final unassignedIds = availableRoles.keys + .where((id) => !assignedRoles.containsKey(id)) + .toList(); + return unassignedIds.contains(id); + } + bool isParticipantSelected(String id) { if (state == SessionState.confirmedRole) { return activityRoom?.ownRoleState?.id == id; diff --git a/lib/pangea/activity_sessions/activity_session_start/activity_sessions_start_view.dart b/lib/pangea/activity_sessions/activity_session_start/activity_sessions_start_view.dart index 77f656fbe..1ca855d3b 100644 --- a/lib/pangea/activity_sessions/activity_session_start/activity_sessions_start_view.dart +++ b/lib/pangea/activity_sessions/activity_session_start/activity_sessions_start_view.dart @@ -161,6 +161,8 @@ class ActivitySessionStartView extends StatelessWidget { onTapParticipant: controller.selectRole, isParticipantSelected: controller.isParticipantSelected, + isParticipantShimmering: + controller.isParticipantShimmering, canSelectParticipant: controller.canSelectParticipant, assignedRoles: controller.assignedRoles, diff --git a/lib/pangea/activity_sessions/activity_summary_widget.dart b/lib/pangea/activity_sessions/activity_summary_widget.dart index a1ae85035..2be683199 100644 --- a/lib/pangea/activity_sessions/activity_summary_widget.dart +++ b/lib/pangea/activity_sessions/activity_summary_widget.dart @@ -31,6 +31,7 @@ class ActivitySummary extends StatelessWidget { final Function(String)? onTapParticipant; final bool Function(String)? canSelectParticipant; final bool Function(String)? isParticipantSelected; + final bool Function(String)? isParticipantShimmering; final double Function(ActivityRoleModel?)? getParticipantOpacity; final ValueNotifier>? usedVocab; @@ -45,6 +46,7 @@ class ActivitySummary extends StatelessWidget { this.onTapParticipant, this.canSelectParticipant, this.isParticipantSelected, + this.isParticipantShimmering, this.getParticipantOpacity, this.room, this.course, @@ -82,6 +84,7 @@ class ActivitySummary extends StatelessWidget { onTap: onTapParticipant, canSelect: canSelectParticipant, isSelected: isParticipantSelected, + isShimmering: isParticipantShimmering, getOpacity: getParticipantOpacity, ), DecoratedBox(