diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index d41126e2b..61dbba716 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -406,7 +406,7 @@ class ChatController extends State pangeaController.getAnalytics.analyticsStream.stream.listen((update) { if (update.targetID == null) return; OverlayUtil.showOverlay( - overlayKey: update.targetID, + overlayKey: "${update.targetID ?? ""}_points", followerAnchor: Alignment.bottomCenter, targetAnchor: Alignment.bottomCenter, context: context, diff --git a/lib/pangea/analytics_misc/gain_points_animation.dart b/lib/pangea/analytics_misc/gain_points_animation.dart index 77d032ddd..088c008b7 100644 --- a/lib/pangea/analytics_misc/gain_points_animation.dart +++ b/lib/pangea/analytics_misc/gain_points_animation.dart @@ -119,7 +119,7 @@ class PointsGainedAnimationState extends State _controller?.forward().then( (_) { if (!mounted) return; - MatrixState.pAnyState.closeOverlay(widget.targetID); + MatrixState.pAnyState.closeOverlay("${widget.targetID}_points"); }, ); } @@ -132,7 +132,7 @@ class PointsGainedAnimationState extends State _offsetAnimation == null) { WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) { - MatrixState.pAnyState.closeOverlay(widget.targetID); + MatrixState.pAnyState.closeOverlay("${widget.targetID}_points"); } }); return const SizedBox(); diff --git a/lib/pangea/message_token_text/message_token_button.dart b/lib/pangea/message_token_text/message_token_button.dart index dcb13e46f..4750dab8f 100644 --- a/lib/pangea/message_token_text/message_token_button.dart +++ b/lib/pangea/message_token_text/message_token_button.dart @@ -11,7 +11,9 @@ import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/message_token_text/dotted_border_painter.dart'; -import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart'; +import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart'; +import 'package:fluffychat/pangea/morphs/morph_features_enum.dart'; +import 'package:fluffychat/pangea/morphs/morph_icon.dart'; import 'package:fluffychat/pangea/practice_activities/practice_choice.dart'; import 'package:fluffychat/pangea/practice_activities/practice_target.dart'; import 'package:fluffychat/pangea/toolbar/enums/message_mode_enum.dart'; @@ -181,17 +183,12 @@ class MessageTokenButtonState extends State // ); } - bool get isActivityCompleteForToken { - if (activity?.activityType == ActivityTypeEnum.morphId) { - return (activity?.record.completeResponses ?? 0) > 0; - } - for (final response in activity!.record.responses) { - if (response.cId == widget.token.vocabConstructID && response.isCorrect) { - return true; - } - } - return false; - } + bool get isActivityCompleteForToken => + activity?.isCompleteByToken( + widget.token, + activity!.morphFeature, + ) == + true; Color get color { if (activity == null) { @@ -209,6 +206,31 @@ class MessageTokenButtonState extends State if (MessageMode.wordEmoji == widget.overlayController?.toolbarMode) { return SizedBox(height: height, child: emojiView); } + if (MessageMode.wordMorph == widget.overlayController?.toolbarMode && + activity?.morphFeature != null) { + final morphFeature = activity!.morphFeature!; + final morphTag = widget.token.morphIdByFeature(morphFeature); + if (morphTag != null) { + return Tooltip( + message: getGrammarCopy( + category: morphFeature.toShortString(), + lemma: morphTag.lemma, + context: context, + ), + child: SizedBox( + width: widget.width, + height: height, + child: Center( + child: MorphIcon( + morphFeature: morphFeature, + morphTag: morphTag.lemma, + size: const Size(24.0, 24.0), + ), + ), + ), + ); + } + } return SizedBox(height: height); } @@ -216,6 +238,7 @@ class MessageTokenButtonState extends State if (activity?.morphFeature == null) { return SizedBox(height: height); } + final bool isSelected = (widget.overlayController?.selectedMorph?.token == widget.token && widget.overlayController?.selectedMorph?.morph == diff --git a/lib/pangea/practice_activities/practice_target.dart b/lib/pangea/practice_activities/practice_target.dart index 4c9aff650..df034d20b 100644 --- a/lib/pangea/practice_activities/practice_target.dart +++ b/lib/pangea/practice_activities/practice_target.dart @@ -74,8 +74,8 @@ class PracticeTarget { Map toJson() { return { 'tokens': tokens.map((e) => e.toJson()).toList(), - 'activityType': activityType.index, - 'morphFeature': morphFeature?.index, + 'activityType': activityType.name, + 'morphFeature': morphFeature?.name, 'userL2': userL2, }; } @@ -114,6 +114,13 @@ class PracticeTarget { ); return false; } + + if (activityType == ActivityTypeEnum.morphId) { + return record.responses.any( + (res) => res.cId == token.morphIdByFeature(morph!) && res.isCorrect, + ); + } + return record.responses.any( (res) => res.cId == token.vocabConstructID && res.isCorrect, ); diff --git a/lib/pangea/toolbar/reading_assistance_input_row/message_morph_choice_item.dart b/lib/pangea/toolbar/reading_assistance_input_row/message_morph_choice_item.dart index efbd4a90b..9ce498b25 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/message_morph_choice_item.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/message_morph_choice_item.dart @@ -61,7 +61,7 @@ class MessageMorphChoiceItemState extends State { @override Widget build(BuildContext context) { final color = _color; - final iconSize = FluffyThemes.isColumnMode(context) ? 40.0 : 24.0; + final iconSize = FluffyThemes.isColumnMode(context) ? 32.0 : 24.0; final style = FluffyThemes.isColumnMode(context) ? Theme.of(context).textTheme.bodyLarge : Theme.of(context).textTheme.bodySmall; diff --git a/lib/pangea/toolbar/reading_assistance_input_row/practice_match_card.dart b/lib/pangea/toolbar/reading_assistance_input_row/practice_match_card.dart index b8f69b053..9ef6ffb2a 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/practice_match_card.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/practice_match_card.dart @@ -3,6 +3,8 @@ import 'dart:developer'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:collection/collection.dart'; + import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pangea/choreographer/widgets/choice_animation.dart'; import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart'; @@ -89,6 +91,9 @@ class MatchActivityCard extends StatelessWidget { isSelected: overlayController.selectedChoice == cf, isCorrect: wasCorrect, child: PracticeMatchItem( + token: currentActivity.practiceTarget.tokens.firstWhereOrNull( + (t) => t.vocabConstructID == cf.form.cId, + ), isSelected: overlayController.selectedChoice == cf, isCorrect: wasCorrect, constructForm: cf, diff --git a/lib/pangea/toolbar/reading_assistance_input_row/practice_match_item.dart b/lib/pangea/toolbar/reading_assistance_input_row/practice_match_item.dart index 174280f0d..ea7aa6084 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/practice_match_item.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/practice_match_item.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; +import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/practice_activities/practice_choice.dart'; import 'package:fluffychat/pangea/toolbar/controllers/tts_controller.dart'; import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart'; @@ -13,6 +14,7 @@ class PracticeMatchItem extends StatefulWidget { const PracticeMatchItem({ super.key, required this.content, + required this.token, required this.constructForm, required this.isCorrect, required this.isSelected, @@ -22,6 +24,7 @@ class PracticeMatchItem extends StatefulWidget { }); final Widget content; + final PangeaToken? token; final PracticeChoice constructForm; final String? audioContent; final MessageOverlayController overlayController; @@ -131,7 +134,9 @@ class PracticeMatchItemState extends State { void onTap() { play(); - widget.overlayController.onChoiceSelect(widget.constructForm); + isCorrect == null || !isCorrect! || widget.token == null + ? widget.overlayController.onChoiceSelect(widget.constructForm) + : widget.overlayController.updateSelectedSpan(widget.token!.text); } @override diff --git a/lib/pangea/toolbar/widgets/message_selection_overlay.dart b/lib/pangea/toolbar/widgets/message_selection_overlay.dart index 59e180021..7e69bf297 100644 --- a/lib/pangea/toolbar/widgets/message_selection_overlay.dart +++ b/lib/pangea/toolbar/widgets/message_selection_overlay.dart @@ -222,7 +222,7 @@ class MessageOverlayController extends State return; } - _updateSelectedSpan(widget._initialSelectedToken!.text); + updateSelectedSpan(widget._initialSelectedToken!.text); int retries = 0; while (retries < 5 && @@ -285,14 +285,14 @@ class MessageOverlayController extends State } /// Update [selectedSpan] - void _updateSelectedSpan(PangeaTokenText selectedSpan, [bool force = false]) { + void updateSelectedSpan(PangeaTokenText selectedSpan, [bool force = false]) { if (selectedMorph != null) { selectedMorph = null; } // close overlay of previous token if (selectedToken != null) { MatrixState.pAnyState.closeOverlay( - selectedToken!.text.uniqueKey, + "${selectedToken!.text.uniqueKey}_toolbar", ); } @@ -329,7 +329,7 @@ class MessageOverlayController extends State closePrevOverlay: false, backDropToDismiss: false, addBorder: false, - overlayKey: selectedToken!.text.uniqueKey, + overlayKey: "${selectedToken!.text.uniqueKey}_toolbar", maxHeight: AppConfig.toolbarMaxHeight, maxWidth: AppConfig.toolbarMinWidth, ); @@ -341,7 +341,7 @@ class MessageOverlayController extends State // close overlay of any selected token if (_selectedSpan != null) { - _updateSelectedSpan(_selectedSpan!); + updateSelectedSpan(_selectedSpan!); } toolbarMode = mode; @@ -383,7 +383,7 @@ class MessageOverlayController extends State toolbarMode = MessageMode.wordMorph; // // close overlay of previous token if (_selectedSpan != null && _selectedSpan != newMorph.token.text) { - _updateSelectedSpan(_selectedSpan!); + updateSelectedSpan(_selectedSpan!); } selectedMorph = newMorph; setState(() {}); @@ -543,7 +543,7 @@ class MessageOverlayController extends State ); } - _updateSelectedSpan(token.text); + updateSelectedSpan(token.text); } /// Whether the given token is currently selected or highlighted