diff --git a/lib/pangea/constants/morph_categories_and_labels.dart b/lib/pangea/constants/morph_categories_and_labels.dart index 6eb056a53..8c0b27674 100644 --- a/lib/pangea/constants/morph_categories_and_labels.dart +++ b/lib/pangea/constants/morph_categories_and_labels.dart @@ -1,3 +1,9 @@ +import 'dart:developer'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:material_symbols_icons/symbols.dart'; + const Map> morphCategoriesAndLabels = { "Pos": [ "ADJ", @@ -165,3 +171,50 @@ const Map> morphCategoriesAndLabels = { "Voice": ["Act", "Mid", "Pass", "Antip", "Cau", "Dir", "Inv", "Rcp", "Caus"], "X": ["X"], }; + +// TODO Use the icons that Khue is creating +IconData getIconForMorphFeature(String feature) { + // Define a function to get the icon based on the universal dependency morphological feature (key) + switch (feature.toLowerCase()) { + case 'number': + // google material 123 icon + return Icons.format_list_numbered; + case 'gender': + return Icons.wc; + case 'tense': + return Icons.access_time; + case 'mood': + return Icons.mood; + case 'person': + return Icons.person; + case 'case': + return Icons.format_list_bulleted; + case 'degree': + return Icons.trending_up; + case 'verbform': + return Icons.text_format; + case 'voice': + return Icons.record_voice_over; + case 'aspect': + return Icons.aspect_ratio; + case 'prontype': + return Icons.text_fields; + case 'numtype': + return Icons.format_list_numbered; + case 'poss': + return Icons.account_balance; + case 'reflex': + return Icons.refresh; + case 'foreign': + return Icons.language; + case 'abbr': + return Icons.text_format; + case 'nountype': + return Symbols.abc; + case 'pos': + return Symbols.toys_and_games; + default: + debugger(when: kDebugMode); + return Icons.help_outline; + } +} diff --git a/lib/pangea/enum/morphs_enum.dart b/lib/pangea/enum/morphs_enum.dart new file mode 100644 index 000000000..9badda44d --- /dev/null +++ b/lib/pangea/enum/morphs_enum.dart @@ -0,0 +1,3 @@ +// this should be an enum eventually though we're using a class for now + +class Morphs {} diff --git a/lib/pangea/models/analytics/construct_list_model.dart b/lib/pangea/models/analytics/construct_list_model.dart index 5a355b3bb..e37ebdb48 100644 --- a/lib/pangea/models/analytics/construct_list_model.dart +++ b/lib/pangea/models/analytics/construct_list_model.dart @@ -229,12 +229,13 @@ class ConstructListModel { final List morphConstructs = constructList( type: ConstructTypeEnum.morph, ); - final List possibleDistractors = morphConstructs .where( (c) => c.category == morphFeature.toLowerCase() && - c.lemma.toLowerCase() != morphTag.toLowerCase(), + c.lemma.toLowerCase() != morphTag.toLowerCase() && + c.lemma.isNotEmpty && + c.lemma != "X", ) .map((c) => c.lemma) .toList(); diff --git a/lib/pangea/models/pangea_token_model.dart b/lib/pangea/models/pangea_token_model.dart index 546103025..37a51f098 100644 --- a/lib/pangea/models/pangea_token_model.dart +++ b/lib/pangea/models/pangea_token_model.dart @@ -322,7 +322,7 @@ class PangeaToken { } } - bool get shouldDoPosActivity => shouldDoMorphActivity("Pos"); + bool get shouldDoPosActivity => shouldDoMorphActivity("pos"); bool shouldDoMorphActivity(String feature) { return shouldDoActivity( @@ -582,11 +582,14 @@ class PangeaToken { } String get xpEmoji { - if (xp < 5) { + if (xp < 30) { + // bean emoji + return "🫛"; + } else if (xp < 100) { + // sprout emoji return "🌱"; - } else if (xp < 10) { - return "🌿"; } else { + // flower emoji return "🌺"; } } diff --git a/lib/pangea/repo/lemma_definition_repo.dart b/lib/pangea/repo/lemma_definition_repo.dart index 20e592952..7d0b728e6 100644 --- a/lib/pangea/repo/lemma_definition_repo.dart +++ b/lib/pangea/repo/lemma_definition_repo.dart @@ -132,6 +132,23 @@ class LemmaDictionaryRepo { return response; } + /// From the cache, get a random set of cached definitions that are not for a specific lemma + static List getDistractorDefinitions( + LemmaDefinitionRequest req, int count) { + _clearExpiredEntries(); + + final List definitions = []; + for (final entry in _cache.entries) { + if (entry.key.lemma != req.lemma) { + definitions.add(entry.value.definition); + } + } + + definitions.shuffle(); + + return definitions.take(count).toList(); + } + static void _clearExpiredEntries() { final now = DateTime.now(); final expiredKeys = _cacheTimestamps.entries diff --git a/lib/pangea/repo/practice/morph_activity_generator.dart b/lib/pangea/repo/practice/morph_activity_generator.dart index 6703f7d28..966d6a443 100644 --- a/lib/pangea/repo/practice/morph_activity_generator.dart +++ b/lib/pangea/repo/practice/morph_activity_generator.dart @@ -1,6 +1,7 @@ import 'dart:developer'; import 'package:fluffychat/pangea/enum/activity_type_enum.dart'; +import 'package:fluffychat/pangea/enum/analytics/morph_categories_enum.dart'; import 'package:fluffychat/pangea/enum/construct_type_enum.dart'; import 'package:fluffychat/pangea/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/models/practice_activities.dart/message_activity_request.dart'; @@ -30,14 +31,15 @@ class MorphActivityGenerator { "SCONJ": [], "PUNCT": [], "VERB": ["Tense", "Aspect"], + "X": [], }, }; /// Get the sequence of activities for a given part of speech /// The sequence is a list of morphological features that should be practiced /// in order for the given part of speech - Future getSequence(String langCode, String pos) async { - if (!sequence.containsKey(langCode)) { + POSActivitySequence getSequence(String? langCode, String pos) { + if (langCode == null || !sequence.containsKey(langCode)) { langCode = "en"; } final MorphActivitySequence morphActivitySequence = sequence[langCode]!; @@ -89,7 +91,8 @@ class MorphActivityGenerator { langCode: req.userL2, activityType: ActivityTypeEnum.morphId, content: ActivityContent( - question: "", + question: + "${getMorphologicalCategoryCopy(morphFeature, MatrixState.pangeaController.matrixState.context) ?? ""}?", choices: distractors + [morphTag], answers: [morphTag], spanDisplayDetails: null, diff --git a/lib/pangea/repo/practice/practice_repo.dart b/lib/pangea/repo/practice/practice_repo.dart index ffe2e2d52..518ac6378 100644 --- a/lib/pangea/repo/practice/practice_repo.dart +++ b/lib/pangea/repo/practice/practice_repo.dart @@ -16,6 +16,7 @@ import 'package:fluffychat/pangea/network/urls.dart'; import 'package:fluffychat/pangea/repo/practice/emoji_activity_generator.dart'; import 'package:fluffychat/pangea/repo/practice/lemma_activity_generator.dart'; import 'package:fluffychat/pangea/repo/practice/morph_activity_generator.dart'; +import 'package:fluffychat/pangea/repo/practice/word_meaning_activity_generator.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; @@ -40,9 +41,10 @@ class PracticeGenerationController { late PangeaController _pangeaController; - final MorphActivityGenerator _morph = MorphActivityGenerator(); - final EmojiActivityGenerator _emoji = EmojiActivityGenerator(); - final LemmaActivityGenerator _lemma = LemmaActivityGenerator(); + final _morph = MorphActivityGenerator(); + final _emoji = EmojiActivityGenerator(); + final _lemma = LemmaActivityGenerator(); + final _wordMeaning = WordMeaningActivityGenerator(); PracticeGenerationController() { _pangeaController = MatrixState.pangeaController; @@ -126,10 +128,9 @@ class PracticeGenerationController { return _lemma.get(req); case ActivityTypeEnum.morphId: return _morph.get(req); - case ActivityTypeEnum.wordFocusListening: - // TODO bring clientside because more efficient case ActivityTypeEnum.wordMeaning: - // TODO get correct answer with translation and distractors with distractor service + return _wordMeaning.get(req); + case ActivityTypeEnum.wordFocusListening: case ActivityTypeEnum.hiddenWordListening: return _fetchFromServer( accessToken: accessToken, diff --git a/lib/pangea/repo/practice/word_meaning_activity_generator.dart b/lib/pangea/repo/practice/word_meaning_activity_generator.dart new file mode 100644 index 000000000..4f5b20fed --- /dev/null +++ b/lib/pangea/repo/practice/word_meaning_activity_generator.dart @@ -0,0 +1,47 @@ +import 'package:fluffychat/pangea/enum/activity_type_enum.dart'; +import 'package:fluffychat/pangea/enum/construct_type_enum.dart'; +import 'package:fluffychat/pangea/models/practice_activities.dart/message_activity_request.dart'; +import 'package:fluffychat/pangea/models/practice_activities.dart/multiple_choice_activity_model.dart'; +import 'package:fluffychat/pangea/models/practice_activities.dart/practice_activity_model.dart'; +import 'package:fluffychat/pangea/repo/lemma_definition_repo.dart'; + +class WordMeaningActivityGenerator { + Future get( + MessageActivityRequest req, + ) async { + final ConstructIdentifier lemmaId = ConstructIdentifier( + lemma: req.targetTokens[0].lemma.text, + type: ConstructTypeEnum.vocab, + category: req.targetTokens[0].pos, + ); + + final LemmaDefinitionRequest lemmaDefReq = LemmaDefinitionRequest( + lemma: lemmaId.lemma, + partOfSpeech: lemmaId.category, + + /// This assumes that the user's L2 is the language of the lemma + lemmaLang: req.userL2, + userL1: req.userL1, + ); + + final res = await LemmaDictionaryRepo.get(lemmaDefReq); + + final choices = + LemmaDictionaryRepo.getDistractorDefinitions(lemmaDefReq, 3); + + return MessageActivityResponse( + activity: PracticeActivityModel( + tgtConstructs: [lemmaId], + targetTokens: req.targetTokens, + langCode: req.userL2, + activityType: ActivityTypeEnum.wordMeaning, + content: ActivityContent( + question: "?", + choices: choices, + answers: [res.definition], + spanDisplayDetails: null, + ), + ), + ); + } +} diff --git a/lib/pangea/widgets/practice_activity/emoji_practice_button.dart b/lib/pangea/widgets/practice_activity/emoji_practice_button.dart index 19391b1ad..1f5d533a4 100644 --- a/lib/pangea/widgets/practice_activity/emoji_practice_button.dart +++ b/lib/pangea/widgets/practice_activity/emoji_practice_button.dart @@ -30,14 +30,11 @@ class EmojiPracticeButtonState extends State { } } - bool get _canDoActivity { - final canDo = widget.token.shouldDoActivity( - a: ActivityTypeEnum.emoji, - feature: null, - tag: null, - ); - return canDo; - } + bool get _shouldDoActivity => widget.token.shouldDoActivity( + a: ActivityTypeEnum.emoji, + feature: null, + tag: null, + ); @override Widget build(BuildContext context) { @@ -45,17 +42,20 @@ class EmojiPracticeButtonState extends State { return SizedBox( height: 40, width: 40, - child: _canDoActivity || emoji != null - ? IconButton( - onPressed: () { - widget.onPressed(); - if (widget.emoji == null && emoji != null) { - widget.setEmoji(emoji); - } - }, - icon: emoji == null - ? const Icon(Icons.add_reaction_outlined) - : Text(emoji), + child: _shouldDoActivity || emoji != null + ? Opacity( + opacity: _shouldDoActivity ? 0.5 : 1, + child: IconButton( + onPressed: () { + widget.onPressed(); + if (widget.emoji == null && emoji != null) { + widget.setEmoji(emoji); + } + }, + icon: emoji == null + ? const Icon(Icons.add_reaction_outlined) + : Text(emoji), + ), ) : const SizedBox.shrink(), ); diff --git a/lib/pangea/widgets/practice_activity/word_text_with_audio_button.dart b/lib/pangea/widgets/practice_activity/word_text_with_audio_button.dart index fcd52dc60..7a92cd6c6 100644 --- a/lib/pangea/widgets/practice_activity/word_text_with_audio_button.dart +++ b/lib/pangea/widgets/practice_activity/word_text_with_audio_button.dart @@ -84,12 +84,14 @@ class WordAudioButtonState extends State { color: _isPlaying ? Theme.of(context).colorScheme.secondary : null, + fontSize: + Theme.of(context).textTheme.titleLarge?.fontSize, ), ), const SizedBox(width: 4), Icon( _isPlaying ? Icons.play_arrow : Icons.play_arrow_outlined, - size: Theme.of(context).textTheme.bodyMedium?.fontSize, + size: Theme.of(context).textTheme.titleLarge?.fontSize, ), ], ), diff --git a/lib/pangea/widgets/word_zoom/contextual_translation_widget.dart b/lib/pangea/widgets/word_zoom/contextual_translation_widget.dart index d84443f1f..5ddb71fdc 100644 --- a/lib/pangea/widgets/word_zoom/contextual_translation_widget.dart +++ b/lib/pangea/widgets/word_zoom/contextual_translation_widget.dart @@ -1,9 +1,8 @@ import 'package:fluffychat/pangea/constants/language_constants.dart'; import 'package:fluffychat/pangea/models/pangea_token_model.dart'; -import 'package:fluffychat/pangea/repo/full_text_translation_repo.dart'; +import 'package:fluffychat/pangea/repo/lemma_definition_repo.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; -import 'package:material_symbols_icons/symbols.dart'; class ContextualTranslationWidget extends StatefulWidget { final PangeaToken token; @@ -48,26 +47,40 @@ class ContextualTranslationWidgetState } Future _fetchDefinition() async { - final FullTextTranslationResponseModel response = - await FullTextTranslationRepo.translate( - accessToken: MatrixState.pangeaController.userController.accessToken, - request: FullTextTranslationRequestModel( - text: widget.fullText, - tgtLang: - MatrixState.pangeaController.languageController.userL1?.langCode ?? - LanguageKeys.defaultLanguage, - userL2: - MatrixState.pangeaController.languageController.userL2?.langCode ?? - LanguageKeys.defaultLanguage, - userL1: - MatrixState.pangeaController.languageController.userL1?.langCode ?? - LanguageKeys.defaultLanguage, - offset: widget.token.text.offset, - length: widget.token.text.length, - deepL: false, - ), + // final FullTextTranslationResponseModel response = + // await FullTextTranslationRepo.translate( + // accessToken: MatrixState.pangeaController.userController.accessToken, + // request: FullTextTranslationRequestModel( + // text: widget.fullText, + // tgtLang: + // MatrixState.pangeaController.languageController.userL1?.langCode ?? + // LanguageKeys.defaultLanguage, + // userL2: + // MatrixState.pangeaController.languageController.userL2?.langCode ?? + // LanguageKeys.defaultLanguage, + // userL1: + // MatrixState.pangeaController.languageController.userL1?.langCode ?? + // LanguageKeys.defaultLanguage, + // offset: widget.token.text.offset, + // length: widget.token.text.length, + // deepL: false, + // ), + // ); + // widget.setDefinition(response.bestTranslation); + final LemmaDefinitionRequest lemmaDefReq = LemmaDefinitionRequest( + lemma: widget.token.lemma.text, + partOfSpeech: widget.token.pos, + + /// This assumes that the user's L2 is the language of the lemma + lemmaLang: widget.langCode, + userL1: + MatrixState.pangeaController.languageController.userL1?.langCode ?? + LanguageKeys.defaultLanguage, ); - widget.setDefinition(response.bestTranslation); + + final res = await LemmaDictionaryRepo.get(lemmaDefReq); + + widget.setDefinition(res.definition); } @override @@ -75,12 +88,12 @@ class ContextualTranslationWidgetState return Center( child: SizedBox( height: 60, - width: 60, - child: IconButton( - iconSize: 30, - onPressed: widget.onPressed, - icon: const Icon(Symbols.dictionary), - ), + // child: IconButton( + // iconSize: 30, + // onPressed: widget.onPressed, + // icon: const Icon(Symbols.dictionary), + // ), + child: Text(widget.definition ?? "..."), ), ); } diff --git a/lib/pangea/widgets/word_zoom/morphological_widget.dart b/lib/pangea/widgets/word_zoom/morphological_widget.dart index 23b88f181..3c8b37829 100644 --- a/lib/pangea/widgets/word_zoom/morphological_widget.dart +++ b/lib/pangea/widgets/word_zoom/morphological_widget.dart @@ -1,11 +1,10 @@ -import 'dart:developer'; - -import 'package:fluffychat/pangea/enum/activity_type_enum.dart'; +import 'package:fluffychat/pangea/constants/morph_categories_and_labels.dart'; import 'package:fluffychat/pangea/enum/analytics/morph_categories_enum.dart'; import 'package:fluffychat/pangea/models/pangea_token_model.dart'; -import 'package:flutter/foundation.dart'; +import 'package:fluffychat/pangea/repo/practice/morph_activity_generator.dart'; +import 'package:fluffychat/pangea/utils/error_handler.dart'; +import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; -import 'package:material_symbols_icons/symbols.dart'; class ActivityMorph { final String morphFeature; @@ -19,7 +18,7 @@ class ActivityMorph { }); } -class MorphologicalListWidget extends StatefulWidget { +class MorphologicalListWidget extends StatelessWidget { final PangeaToken token; final String? selectedMorphFeature; final Function(String?) setMorphFeature; @@ -33,147 +32,53 @@ class MorphologicalListWidget extends StatefulWidget { required this.completedActivities, }); - @override - MorphologicalListWidgetState createState() => MorphologicalListWidgetState(); -} + List get _visibleMorphs { + // we always start with the part of speech + final visibleMorphs = [ + ActivityMorph( + morphFeature: "pos", + morphTag: token.pos, + revealed: !token.shouldDoPosActivity, + // revealed: !shouldDoActivity || !canGenerateDistractors, + ), + ]; -class MorphologicalListWidgetState extends State { - // TODO: make this is a list of morphological features icons based on MorphActivityGenerator.getSequence - // For each item in the sequence, - // if shouldDoActivity is true, show the template icon then stop - // if shouldDoActivity is false, show the actual icon and value then go to the next item + // each pos has a defined set of morphological features to display and do activities for + final List seq = MorphActivityGenerator().getSequence( + MatrixState.pangeaController.languageController.userL2?.langCode, + token.pos, + ); - final List _morphs = []; - - @override - void initState() { - super.initState(); - _setMorphs(); - } - - @override - void didUpdateWidget(covariant MorphologicalListWidget oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.token != oldWidget.token) { - _setMorphs(); - } - - if (widget.completedActivities != oldWidget.completedActivities && - oldWidget.selectedMorphFeature != null) { - final oldSelectedMorphIndex = _morphs.indexWhere( - (morph) => morph.morphFeature == oldWidget.selectedMorphFeature, - ); - if (oldSelectedMorphIndex != -1 && - oldSelectedMorphIndex < _morphs.length) { - setState( - () => _morphs[oldSelectedMorphIndex].revealed = true, - ); - - final nextIndex = oldSelectedMorphIndex + 1; - if (nextIndex < _morphs.length) { - widget.setMorphFeature(_morphs[nextIndex].morphFeature); - } else { - widget.setMorphFeature(null); - } + for (final String feature in seq) { + // don't add any more if the last one is not revealed yet + if (!visibleMorphs.last.revealed) { + break; } - } - } - Future _setMorphs() async { - _morphs.clear(); - final morphEntries = widget.token.morph.entries.toList(); - for (final morphEntry in morphEntries) { - final morphFeature = morphEntry.key; - final morphTag = morphEntry.value; - final shouldDoActivity = widget.token.shouldDoMorphActivity(morphFeature); - final canGenerateDistractors = await widget.token.canGenerateDistractors( - ActivityTypeEnum.morphId, - morphFeature: morphFeature, - morphTag: morphTag, - ); - _morphs.add( + // check that the feature is in token.morph + if (!token.morph.containsKey(feature)) { + ErrorHandler.logError( + m: "Morphological feature suggested for pos but not found in token", + data: { + "feature": feature, + "token": token, + "lang_code": MatrixState + .pangeaController.languageController.userL2?.langCode, + }, + ); + continue; + } + + visibleMorphs.add( ActivityMorph( - morphFeature: morphFeature, - morphTag: morphTag, - revealed: !shouldDoActivity || !canGenerateDistractors, + morphFeature: feature, + morphTag: token.morph[feature], + revealed: !token.shouldDoMorphActivity(feature), ), ); } - _morphs.sort((a, b) { - if (a.revealed && !b.revealed) { - return -1; - } else if (!a.revealed && b.revealed) { - return 1; - } - - if (a.morphFeature.toLowerCase() == "pos") { - return -1; - } else if (b.morphFeature.toLowerCase() == "pos") { - return 1; - } - - return a.morphFeature.compareTo(b.morphFeature); - }); - } - - List get _visibleMorphs { - final lastRevealedIndex = _morphs.lastIndexWhere((morph) => morph.revealed); - - // if none of the morphs are revealed, show only the first one - if (lastRevealedIndex == -1) { - return _morphs.take(1).toList(); - } - - // show all the revealed morphs + the first one with an activity - return _morphs.take(lastRevealedIndex + 2).toList(); - } - - // TODO Use the icons that Khue is creating - IconData _getIconForMorphFeature(String feature) { - // Define a function to get the icon based on the universal dependency morphological feature (key) - switch (feature.toLowerCase()) { - case 'number': - // google material 123 icon - return Icons.format_list_numbered; - case 'gender': - return Icons.wc; - case 'tense': - return Icons.access_time; - case 'mood': - return Icons.mood; - case 'person': - return Icons.person; - case 'case': - return Icons.format_list_bulleted; - case 'degree': - return Icons.trending_up; - case 'verbform': - return Icons.text_format; - case 'voice': - return Icons.record_voice_over; - case 'aspect': - return Icons.aspect_ratio; - case 'prontype': - return Icons.text_fields; - case 'numtype': - return Icons.format_list_numbered; - case 'poss': - return Icons.account_balance; - case 'reflex': - return Icons.refresh; - case 'foreign': - return Icons.language; - case 'abbr': - return Icons.text_format; - case 'nountype': - return Symbols.abc; - case 'pos': - return Symbols.toys_and_games; - default: - debugger(when: kDebugMode); - return Icons.help_outline; - } + return visibleMorphs; } @override @@ -183,11 +88,11 @@ class MorphologicalListWidgetState extends State { return Padding( padding: const EdgeInsets.all(2.0), child: MorphologicalActivityButton( - onPressed: widget.setMorphFeature, + onPressed: setMorphFeature, morphCategory: morph.morphFeature, - icon: _getIconForMorphFeature(morph.morphFeature), + icon: getIconForMorphFeature(morph.morphFeature), isUnlocked: morph.revealed, - isSelected: widget.selectedMorphFeature == morph.morphFeature, + isSelected: selectedMorphFeature == morph.morphFeature, ), ); }).toList(), @@ -222,7 +127,7 @@ class MorphologicalActivityButton extends StatelessWidget { context, ), child: Opacity( - opacity: (isUnlocked && !isSelected) ? 0.75 : 1, + opacity: isSelected ? 1 : 0.5, child: IconButton( onPressed: () => onPressed(morphCategory), icon: Icon(icon), diff --git a/lib/pangea/widgets/word_zoom/part_of_speech_widget.dart b/lib/pangea/widgets/word_zoom/part_of_speech_widget.dart deleted file mode 100644 index 12b828954..000000000 --- a/lib/pangea/widgets/word_zoom/part_of_speech_widget.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:fluffychat/pangea/models/pangea_token_model.dart'; - -class PartOfSpeechWidget extends StatefulWidget { - final PangeaToken token; - - const PartOfSpeechWidget({super.key, required this.token}); - - @override - _PartOfSpeechWidgetState createState() => _PartOfSpeechWidgetState(); -} - -class _PartOfSpeechWidgetState extends State { - late Future _partOfSpeech; - - @override - void initState() { - super.initState(); - _partOfSpeech = _fetchPartOfSpeech(); - } - - Future _fetchPartOfSpeech() async { - if (widget.token.shouldDoPosActivity) { - return '?'; - } else { - return widget.token.pos; - } - } - - @override - Widget build(BuildContext context) { - return FutureBuilder( - future: _partOfSpeech, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const CircularProgressIndicator(); - } else if (snapshot.hasError) { - return Text('Error: ${snapshot.error}'); - } else { - return ActionChip( - avatar: const Icon(Icons.label), - label: Text(snapshot.data ?? 'No part of speech found'), - onPressed: () { - // Handle chip click - }, - ); - } - }, - ); - } -} diff --git a/lib/pangea/widgets/word_zoom/word_zoom_widget.dart b/lib/pangea/widgets/word_zoom/word_zoom_widget.dart index a22d0d53d..76254cad7 100644 --- a/lib/pangea/widgets/word_zoom/word_zoom_widget.dart +++ b/lib/pangea/widgets/word_zoom/word_zoom_widget.dart @@ -38,7 +38,7 @@ class WordZoomWidget extends StatefulWidget { } class WordZoomWidgetState extends State { - ActivityTypeEnum? _activityType; + ActivityTypeEnum _activityType = ActivityTypeEnum.wordMeaning; // morphological activities String? _selectedMorphFeature; @@ -72,6 +72,8 @@ class WordZoomWidgetState extends State { }); } }); + + // if learner should do translation activity then setActivityType to wordMeaning } @override @@ -89,23 +91,10 @@ class WordZoomWidgetState extends State { } } - bool _showActivityCard(ActivityTypeEnum? activityType) { - if (activityType == null) return false; - final shouldDo = widget.token.shouldDoActivity( - a: activityType, - feature: _selectedMorphFeature, - tag: _selectedMorphFeature == null - ? null - : widget.token.morph[_selectedMorphFeature], - ); - - return canGenerateActivity[activityType]! && shouldDo; - } - void _clean() { if (mounted) { setState(() { - _activityType = null; + _activityType = ActivityTypeEnum.wordMeaning; _selectedMorphFeature = null; _definition = null; _lemma = null; @@ -117,11 +106,13 @@ class WordZoomWidgetState extends State { void _setSelectedMorphFeature(String? feature) { _selectedMorphFeature = _selectedMorphFeature == feature ? null : feature; _setActivityType( - _selectedMorphFeature == null ? null : ActivityTypeEnum.morphId, + _selectedMorphFeature == null + ? ActivityTypeEnum.wordMeaning + : ActivityTypeEnum.morphId, ); } - void _setActivityType(ActivityTypeEnum? activityType) { + void _setActivityType(ActivityTypeEnum activityType) { if (mounted) setState(() => _activityType = activityType); } @@ -164,6 +155,45 @@ class WordZoomWidgetState extends State { } } + Widget get _wordZoomCenterWidget { + if (widget.token.shouldDoActivity( + a: _activityType, + feature: _selectedMorphFeature, + tag: _selectedMorphFeature == null + ? null + : widget.token.morph[_selectedMorphFeature], + ) && + canGenerateActivity[_activityType]!) { + PracticeActivityCard( + pangeaMessageEvent: widget.messageEvent, + targetTokensAndActivityType: TargetTokensAndActivityType( + tokens: [widget.token], + activityType: _activityType, + ), + overlayController: widget.overlayController, + morphFeature: _selectedMorphFeature, + wordDetailsController: this, + ); + } + + if (_activityType == ActivityTypeEnum.wordMeaning) { + return ContextualTranslationWidget( + token: widget.token, + fullText: widget.messageEvent.messageDisplayText, + langCode: widget.messageEvent.messageDisplayLangCode, + onPressed: () => _setActivityType(ActivityTypeEnum.wordMeaning), + definition: _definition, + setDefinition: _setDefinition, + ); + } + + return Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [_activityAnswer], + ); + } + Widget get _activityAnswer { switch (_activityType) { case ActivityTypeEnum.morphId: @@ -180,7 +210,7 @@ class WordZoomWidgetState extends State { case ActivityTypeEnum.wordMeaning: return _definition != null ? Text(_definition!) - : const Text("defintion is null"); + : const Text("definition is null"); case ActivityTypeEnum.lemmaId: return _lemma != null ? Text(_lemma!) : const Text("lemma is null"); case ActivityTypeEnum.emoji: @@ -215,7 +245,7 @@ class WordZoomWidgetState extends State { token: widget.token, onPressed: () => _setActivityType( _activityType == ActivityTypeEnum.emoji - ? null + ? ActivityTypeEnum.wordMeaning : ActivityTypeEnum.emoji, ), setEmoji: _setEmoji, @@ -229,7 +259,7 @@ class WordZoomWidgetState extends State { token: widget.token, onPressed: () => _setActivityType( _activityType == ActivityTypeEnum.lemmaId - ? null + ? ActivityTypeEnum.wordMeaning : ActivityTypeEnum.lemmaId, ), lemma: _lemma, @@ -238,34 +268,7 @@ class WordZoomWidgetState extends State { ], ), ), - if (_activityType != null) - if (_showActivityCard(_activityType)) - PracticeActivityCard( - pangeaMessageEvent: widget.messageEvent, - targetTokensAndActivityType: TargetTokensAndActivityType( - tokens: [widget.token], - activityType: _activityType!, - ), - overlayController: widget.overlayController, - morphFeature: _selectedMorphFeature, - wordDetailsController: this, - ) - else - Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [_activityAnswer], - ) - else - ContextualTranslationWidget( - token: widget.token, - fullText: widget.messageEvent.messageDisplayText, - langCode: widget.messageEvent.messageDisplayLangCode, - onPressed: () => - _setActivityType(ActivityTypeEnum.wordMeaning), - definition: _definition, - setDefinition: _setDefinition, - ), + _wordZoomCenterWidget, MorphologicalListWidget( token: widget.token, setMorphFeature: _setSelectedMorphFeature,