From ffc600caf824ec96ea03269b618b4ecf035b0df8 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Mon, 3 Nov 2025 09:27:26 -0500 Subject: [PATCH 1/3] fix: disable lemma emoji row buttons when onSelect does nothing --- lib/pangea/lemmas/lemma_emoji_picker.dart | 6 ++++-- lib/pangea/lemmas/lemma_reaction_picker.dart | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/pangea/lemmas/lemma_emoji_picker.dart b/lib/pangea/lemmas/lemma_emoji_picker.dart index d3c20b2fa..c99a79214 100644 --- a/lib/pangea/lemmas/lemma_emoji_picker.dart +++ b/lib/pangea/lemmas/lemma_emoji_picker.dart @@ -4,7 +4,7 @@ import 'package:fluffychat/pangea/toolbar/reading_assistance_input_row/lemma_emo class LemmaEmojiPicker extends StatelessWidget { final List emojis; - final Function(String) onSelect; + final Function(String)? onSelect; final bool loading; final Function(String)? disabled; @@ -36,7 +36,9 @@ class LemmaEmojiPicker extends StatelessWidget { opacity: isDisabled ? 0.33 : 1, child: LemmaEmojiChoiceItem( content: emoji, - onTap: isDisabled ? null : () => onSelect(emoji), + onTap: isDisabled || onSelect == null + ? null + : () => onSelect!(emoji), ), ); }).toList(), diff --git a/lib/pangea/lemmas/lemma_reaction_picker.dart b/lib/pangea/lemmas/lemma_reaction_picker.dart index 6f3e2ab92..cf72c433f 100644 --- a/lib/pangea/lemmas/lemma_reaction_picker.dart +++ b/lib/pangea/lemmas/lemma_reaction_picker.dart @@ -75,7 +75,7 @@ class LemmaReactionPicker extends StatelessWidget { return LemmaEmojiPicker( emojis: emojis, - onSelect: (emoji) => setEmoji(emoji, context), + onSelect: event != null ? (emoji) => setEmoji(emoji, context) : null, disabled: (emoji) => sentReactions.contains(emoji), loading: loading, ); From b909e87c0dd3b272ac03e1581d6e080e1c620441 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Mon, 3 Nov 2025 09:36:26 -0500 Subject: [PATCH 2/3] chore: add padding to the bottom of course settings page --- .../course_settings/course_settings.dart | 267 +++++++++--------- 1 file changed, 136 insertions(+), 131 deletions(-) diff --git a/lib/pangea/course_settings/course_settings.dart b/lib/pangea/course_settings/course_settings.dart index 295360fe0..c85acba8d 100644 --- a/lib/pangea/course_settings/course_settings.dart +++ b/lib/pangea/course_settings/course_settings.dart @@ -122,146 +122,151 @@ class CourseSettings extends StatelessWidget { return Column( spacing: isColumnMode ? 40.0 : 36.0, mainAxisSize: MainAxisSize.min, - children: controller.course!.topicIds.mapIndexed((index, topicId) { - final topic = controller.course!.loadedTopics[topicId]; - if (topic == null) { - return const SizedBox(); - } + children: [ + ...controller.course!.topicIds.mapIndexed((index, topicId) { + final topic = controller.course!.loadedTopics[topicId]; + if (topic == null) { + return const SizedBox(); + } - final usersInTopic = userTopics[topicId] ?? []; - final activityError = controller.activityErrors[topicId]; + final usersInTopic = userTopics[topicId] ?? []; + final activityError = controller.activityErrors[topicId]; - final bool locked = topicIndex == null ? false : index > topicIndex; - final disabled = - locked || controller.loadingActivities || activityError != null; - return AbsorbPointer( - absorbing: disabled, - child: Opacity( - opacity: disabled ? 0.5 : 1.0, - child: Column( - spacing: 12.0, - mainAxisSize: MainAxisSize.min, - children: [ - LayoutBuilder( - builder: (context, constraints) { - return Row( - spacing: 8.0, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Flexible( - child: Row( - spacing: 4.0, - mainAxisSize: MainAxisSize.min, - children: [ - Stack( - children: [ - ClipPath( - clipper: PinClipper(), - child: ImageByUrl( - imageUrl: topic.imageUrl, - width: 54.0, - replacement: Container( + final bool locked = topicIndex == null ? false : index > topicIndex; + final disabled = + locked || controller.loadingActivities || activityError != null; + return AbsorbPointer( + absorbing: disabled, + child: Opacity( + opacity: disabled ? 0.5 : 1.0, + child: Column( + spacing: 12.0, + mainAxisSize: MainAxisSize.min, + children: [ + LayoutBuilder( + builder: (context, constraints) { + return Row( + spacing: 8.0, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Flexible( + child: Row( + spacing: 4.0, + mainAxisSize: MainAxisSize.min, + children: [ + Stack( + children: [ + ClipPath( + clipper: PinClipper(), + child: ImageByUrl( + imageUrl: topic.imageUrl, + width: 54.0, + replacement: Container( + width: 54.0, + height: 54.0, + decoration: BoxDecoration( + color: theme.colorScheme.secondary, + ), + ), + ), + ), + if (locked) + const Positioned( + bottom: 0, + right: 0, + child: Icon(Icons.lock, size: 24.0), + ) + else if (controller.loadingActivities) + const SizedBox( width: 54.0, height: 54.0, - decoration: BoxDecoration( - color: theme.colorScheme.secondary, - ), - ), - ), - ), - if (locked) - const Positioned( - bottom: 0, - right: 0, - child: Icon(Icons.lock, size: 24.0), - ) - else if (controller.loadingActivities) - const SizedBox( - width: 54.0, - height: 54.0, - child: - CircularProgressIndicator.adaptive(), - ), - ], - ), - Flexible( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - topic.title, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: titleFontSize, - ), - ), - if (topic.location != null) - CourseInfoChip( - icon: Icons.location_on, - text: topic.location!, - fontSize: descFontSize, - iconSize: iconSize, - ), - if (constraints.maxWidth < 700.0) - Padding( - padding: - const EdgeInsetsGeometry.symmetric( - vertical: 4.0, - ), - child: TopicParticipantList( - room: room, - users: usersInTopic, - avatarSize: - isColumnMode ? 50.0 : 25.0, - overlap: isColumnMode ? 20.0 : 8.0, - ), + child: CircularProgressIndicator + .adaptive(), ), ], ), - ), - ], - ), - ), - if (constraints.maxWidth >= 700.0) - TopicParticipantList( - room: room, - users: usersInTopic, - avatarSize: isColumnMode ? 50.0 : 25.0, - overlap: isColumnMode ? 20.0 : 8.0, - ), - ], - ); - }, - ), - if (!locked) - controller.loadingActivities - ? ActivityCardPlaceholder( - activityCount: topic.activityIds.length, - ) - : activityError != null - ? ErrorIndicator( - message: L10n.of(context).oopsSomethingWentWrong, - ) - : topic.loadedActivities.isNotEmpty - ? SizedBox( - height: isColumnMode ? 290.0 : 210.0, - child: TopicActivitiesList( - room: room, - activities: topic.loadedActivities, - loading: controller.loadingCourseSummary, - hasCompletedActivity: - controller.hasCompletedActivity, + Flexible( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + topic.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: titleFontSize, + ), + ), + if (topic.location != null) + CourseInfoChip( + icon: Icons.location_on, + text: topic.location!, + fontSize: descFontSize, + iconSize: iconSize, + ), + if (constraints.maxWidth < 700.0) + Padding( + padding: const EdgeInsetsGeometry + .symmetric( + vertical: 4.0, + ), + child: TopicParticipantList( + room: room, + users: usersInTopic, + avatarSize: + isColumnMode ? 50.0 : 25.0, + overlap: isColumnMode ? 20.0 : 8.0, + ), + ), + ], ), - ) - : const SizedBox(), - ], + ), + ], + ), + ), + if (constraints.maxWidth >= 700.0) + TopicParticipantList( + room: room, + users: usersInTopic, + avatarSize: isColumnMode ? 50.0 : 25.0, + overlap: isColumnMode ? 20.0 : 8.0, + ), + ], + ); + }, + ), + if (!locked) + controller.loadingActivities + ? ActivityCardPlaceholder( + activityCount: topic.activityIds.length, + ) + : activityError != null + ? ErrorIndicator( + message: + L10n.of(context).oopsSomethingWentWrong, + ) + : topic.loadedActivities.isNotEmpty + ? SizedBox( + height: isColumnMode ? 290.0 : 210.0, + child: TopicActivitiesList( + room: room, + activities: topic.loadedActivities, + loading: controller.loadingCourseSummary, + hasCompletedActivity: + controller.hasCompletedActivity, + ), + ) + : const SizedBox(), + ], + ), ), - ), - ); - }).toList(), + ); + }), + const SizedBox(height: 16.0), + ], ); } } From 5627d55eaa9d4b8ee0d1684aa6ed18c1b44bd63a Mon Sep 17 00:00:00 2001 From: ggurdin Date: Mon, 3 Nov 2025 10:09:29 -0500 Subject: [PATCH 3/3] fix: don't show activity summary unsubscribed message if summary is present --- .../activity_finished_status_message.dart | 83 ++++++++++--------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/lib/pangea/activity_sessions/activity_session_chat/activity_finished_status_message.dart b/lib/pangea/activity_sessions/activity_session_chat/activity_finished_status_message.dart index ee98276fd..ec2de0dbd 100644 --- a/lib/pangea/activity_sessions/activity_session_chat/activity_finished_status_message.dart +++ b/lib/pangea/activity_sessions/activity_session_chat/activity_finished_status_message.dart @@ -77,48 +77,51 @@ class ActivityFinishedStatusMessage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, children: controller.room.isActivityFinished ? [ - if (summary?.isLoading ?? false) ...[ - Text( - L10n.of(context).generatingSummary, - style: const TextStyle( - fontStyle: FontStyle.italic, + if (summary?.summary == null) ...[ + if (summary?.isLoading ?? false) ...[ + Text( + L10n.of(context).generatingSummary, + style: const TextStyle( + fontStyle: FontStyle.italic, + ), ), - ), - const SizedBox( - height: 36.0, - width: 36.0, - child: CircularProgressIndicator(), - ), - ] else if (isSubscribed == false) - ErrorIndicator( - message: L10n.of(context) - .subscribeToUnlockActivitySummaries, - onTap: () { - MatrixState.pangeaController.subscriptionController - .showPaywall(context); - }, - ) - else if (summary?.hasError ?? false) ...[ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon( - Icons.school_outlined, - size: 24.0, - ), - const SizedBox(width: 8), - Flexible( - child: Text( - L10n.of(context).activitySummaryError, - textAlign: TextAlign.center, + const SizedBox( + height: 36.0, + width: 36.0, + child: CircularProgressIndicator(), + ), + ] else if (isSubscribed == false) + ErrorIndicator( + message: L10n.of(context) + .subscribeToUnlockActivitySummaries, + onTap: () { + MatrixState + .pangeaController.subscriptionController + .showPaywall(context); + }, + ) + else if (summary?.hasError ?? false) ...[ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon( + Icons.school_outlined, + size: 24.0, ), - ), - ], - ), - TextButton( - onPressed: () => controller.room.fetchSummaries(), - child: Text(L10n.of(context).requestSummaries), - ), + const SizedBox(width: 8), + Flexible( + child: Text( + L10n.of(context).activitySummaryError, + textAlign: TextAlign.center, + ), + ), + ], + ), + TextButton( + onPressed: () => controller.room.fetchSummaries(), + child: Text(L10n.of(context).requestSummaries), + ), + ], ], if (!controller.room.hasArchivedActivity) ...[ Text(