From dea50a51fdc7836b7a0a5865ed781dbd7792f390 Mon Sep 17 00:00:00 2001 From: ggurdin <46800240+ggurdin@users.noreply.github.com> Date: Tue, 5 Aug 2025 12:02:20 -0400 Subject: [PATCH] chore: some small updates to activity session UI (#3630) --- lib/l10n/intl_en.arb | 4 +- lib/pages/chat/chat_view.dart | 16 ++--- .../activity_finished_status_message.dart | 16 +++-- .../activity_pinned_message.dart | 16 +++-- .../activity_planner/activity_plan_model.dart | 3 +- .../activity_room_extension.dart | 20 +++++- .../activity_unfinished_status_message.dart | 61 +++++++++++-------- .../chat/widgets/activity_state_event.dart | 11 +++- 8 files changed, 93 insertions(+), 54 deletions(-) diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 1ded34254..9b2c72baa 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -5132,7 +5132,7 @@ } } }, - "endActivityTitle": "Wrapped up my part", + "endActivityTitle": "I'm Done", "endActivityDesc": "Did you complete the objectives?\nThis is your confirmation that you're stepping back from texting. But don’t worry, the fun continues in the chat! Feel free to hang out and enjoy the show until everyone clicks 'Done'.", - "archiveToAnalytics": "Archive to Analytics" + "archiveToAnalytics": "Add to my Completed Activities" } diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index aeabaf585..f1914204a 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -125,13 +125,15 @@ class ChatView extends StatelessWidget { if (!controller.room.isArchived) { // #Pangea return [ - IconButton( - icon: const Icon(Icons.search_outlined), - tooltip: L10n.of(context).search, - onPressed: () { - context.go('/rooms/${controller.room.id}/search'); - }, - ), + if (controller.room.activityPlan == null || + !controller.room.showActivityChatUI) + IconButton( + icon: const Icon(Icons.search_outlined), + tooltip: L10n.of(context).search, + onPressed: () { + context.go('/rooms/${controller.room.id}/search'); + }, + ), IconButton( icon: const Icon(Icons.settings_outlined), tooltip: L10n.of(context).chatDetails, diff --git a/lib/pangea/activity_planner/activity_finished_status_message.dart b/lib/pangea/activity_planner/activity_finished_status_message.dart index 4c99c0d95..5f1abf1d6 100644 --- a/lib/pangea/activity_planner/activity_finished_status_message.dart +++ b/lib/pangea/activity_planner/activity_finished_status_message.dart @@ -198,15 +198,13 @@ class ActivityFinishedStatusMessageState runSpacing: 12.0, children: widget.room.activityRoles .map( - (role) => Opacity( - opacity: _highlightedRole == role ? 1.0 : 0.5, - child: ActivityParticipantIndicator( - onTap: _highlightedRole == role - ? null - : () => _highlightRole(role), - role: role, - displayname: role.userId.localpart, - ), + (role) => ActivityParticipantIndicator( + onTap: _highlightedRole == role + ? null + : () => _highlightRole(role), + role: role, + displayname: role.userId.localpart, + selected: _highlightedRole == role, ), ) .toList(), diff --git a/lib/pangea/activity_planner/activity_pinned_message.dart b/lib/pangea/activity_planner/activity_pinned_message.dart index 24fbb2d50..30e10d40e 100644 --- a/lib/pangea/activity_planner/activity_pinned_message.dart +++ b/lib/pangea/activity_planner/activity_pinned_message.dart @@ -66,7 +66,7 @@ class ActivityPinnedMessageState extends State { Widget build(BuildContext context) { // if the room has no activity, or if it doesn't have the permission // levels for sending the required events, don't show the pinned message - if (!room.showActivityChatUI) { + if (!room.isActiveInActivity) { return const SizedBox.shrink(); } @@ -88,8 +88,7 @@ class ActivityPinnedMessageState extends State { : theme.colorScheme.surface, ), child: ChatAppBarListTile( - title: room.activityPlan?.markdown ?? - L10n.of(context).loadingPleaseWait, + title: "🎯 ${room.activityPlan!.learningObjective}", leading: const SizedBox(width: 18.0), trailing: Padding( padding: const EdgeInsets.only(right: 12.0), @@ -102,13 +101,18 @@ class ActivityPinnedMessageState extends State { horizontal: 12.0, vertical: 4.0, ), - backgroundColor: theme.colorScheme.onSurface, + backgroundColor: AppConfig.yellowDark, foregroundColor: theme.colorScheme.surface, + disabledBackgroundColor: + AppConfig.yellowDark.withAlpha(100), + disabledForegroundColor: + theme.colorScheme.surface.withAlpha(100), ), child: Text( - L10n.of(context).done, + L10n.of(context).endActivityTitle, style: const TextStyle( - fontSize: 12.0, + fontSize: 16.0, + fontWeight: FontWeight.w900, ), ), ), diff --git a/lib/pangea/activity_planner/activity_plan_model.dart b/lib/pangea/activity_planner/activity_plan_model.dart index 7ea09a68a..36597339d 100644 --- a/lib/pangea/activity_planner/activity_plan_model.dart +++ b/lib/pangea/activity_planner/activity_plan_model.dart @@ -92,8 +92,7 @@ class ActivityPlanModel { /// use target emoji for learning objective /// use step emoji for instructions String get markdown { - String markdown = - ''' **$title** \n🎯 $learningObjective \nπŸͺœ $instructions \n\nπŸ“– '''; + String markdown = '''🎯 $learningObjective \nπŸͺœ $instructions \n\nπŸ“–'''; // cycle through vocab with index for (var i = 0; i < vocab.length; i++) { // if the lemma appears more than once in the vocab list, show the pos diff --git a/lib/pangea/activity_planner/activity_room_extension.dart b/lib/pangea/activity_planner/activity_room_extension.dart index 30c2a5ecd..9c6733515 100644 --- a/lib/pangea/activity_planner/activity_room_extension.dart +++ b/lib/pangea/activity_planner/activity_room_extension.dart @@ -32,7 +32,7 @@ extension ActivityRoomExtension on Room { } } - Future setActivityRole({ + Future startActivity({ String? role, }) async { await client.setRoomStateWithKey( @@ -46,6 +46,21 @@ extension ActivityRoomExtension on Room { ); } + Future continueActivity() async { + final role = activityRole(client.userID!); + if (role == null || !role.isFinished || role.isArchived) return; + + role.finishedAt = null; + final syncFuture = client.waitForRoomInSync(id); + await client.setRoomStateWithKey( + id, + PangeaEventTypes.activityRole, + client.userID!, + role.toJson(), + ); + await syncFuture; + } + Future finishActivity() async { final role = activityRole(client.userID!); if (role == null) return; @@ -214,6 +229,9 @@ extension ActivityRoomExtension on Room { return role == null || role.isFinished; } + bool get hasCompletedActivity => + activityRole(client.userID!)?.isFinished ?? false; + bool get activityIsFinished { return activityRoles.isNotEmpty && activityRoles.every((r) => r.isFinished); } diff --git a/lib/pangea/activity_planner/activity_unfinished_status_message.dart b/lib/pangea/activity_planner/activity_unfinished_status_message.dart index 50ad48920..b31d85a33 100644 --- a/lib/pangea/activity_planner/activity_unfinished_status_message.dart +++ b/lib/pangea/activity_planner/activity_unfinished_status_message.dart @@ -38,28 +38,30 @@ class ActivityUnfinishedStatusMessageState return Column( children: [ - if (unassignedRoles > 0) - Wrap( - spacing: 12.0, - runSpacing: 12.0, - children: List.generate(unassignedRoles, (index) { - return ActivityParticipantIndicator( - selected: _selectedRole == index, - onTap: () => _selectRole(index), - ); - }), + if (!widget.room.hasCompletedActivity) ...[ + if (unassignedRoles > 0) + Wrap( + spacing: 12.0, + runSpacing: 12.0, + children: List.generate(unassignedRoles, (index) { + return ActivityParticipantIndicator( + selected: _selectedRole == index, + onTap: () => _selectRole(index), + ); + }), + ), + const SizedBox(height: 16.0), + Text( + unassignedRoles > 0 + ? L10n.of(context).unjoinedActivityMessage + : L10n.of(context).fullActivityMessage, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: isColumnMode ? 16.0 : 12.0, + ), ), - const SizedBox(height: 16.0), - Text( - unassignedRoles > 0 - ? L10n.of(context).unjoinedActivityMessage - : L10n.of(context).fullActivityMessage, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: isColumnMode ? 16.0 : 12.0, - ), - ), - const SizedBox(height: 16.0), + const SizedBox(height: 16.0), + ], if (unassignedRoles > 0) ElevatedButton( style: ElevatedButton.styleFrom( @@ -70,19 +72,28 @@ class ActivityUnfinishedStatusMessageState foregroundColor: theme.colorScheme.onPrimaryContainer, backgroundColor: theme.colorScheme.primaryContainer, ), - onPressed: _selectedRole != null + onPressed: widget.room.hasCompletedActivity ? () { showFutureLoadingDialog( context: context, - future: () => widget.room.setActivityRole(), + future: widget.room.continueActivity, ); } - : null, + : _selectedRole != null + ? () { + showFutureLoadingDialog( + context: context, + future: widget.room.startActivity, + ); + } + : null, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - L10n.of(context).confirmRole, + widget.room.hasCompletedActivity + ? L10n.of(context).continueText + : L10n.of(context).confirmRole, style: TextStyle( fontSize: isColumnMode ? 16.0 : 12.0, ), diff --git a/lib/pangea/chat/widgets/activity_state_event.dart b/lib/pangea/chat/widgets/activity_state_event.dart index 34f2bd764..7a49c3e66 100644 --- a/lib/pangea/chat/widgets/activity_state_event.dart +++ b/lib/pangea/chat/widgets/activity_state_event.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.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_participant_indicator.dart'; import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart'; @@ -17,15 +18,21 @@ class ActivityStateEvent extends StatelessWidget { final activity = ActivityPlanModel.fromJson(event.content); final roles = event.room.activityRoles; - return Padding( + return Container( padding: const EdgeInsets.symmetric( horizontal: 24.0, vertical: 16.0, ), + constraints: const BoxConstraints( + maxWidth: FluffyThemes.maxTimelineWidth, + ), child: Column( spacing: 12.0, children: [ - Text(activity.markdown), + Text( + activity.markdown, + style: const TextStyle(fontSize: 14.0), + ), if (roles.isNotEmpty) Wrap( spacing: 12.0,