feat: moving to lemma def over contextual translation

This commit is contained in:
wcjord 2024-12-30 12:12:15 -05:00
parent 0368ce3ea7
commit f626d5fe7e
14 changed files with 303 additions and 303 deletions

View file

@ -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<String, List<String>> morphCategoriesAndLabels = {
"Pos": [
"ADJ",
@ -165,3 +171,50 @@ const Map<String, List<String>> 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;
}
}

View file

@ -0,0 +1,3 @@
// this should be an enum eventually though we're using a class for now
class Morphs {}

View file

@ -229,12 +229,13 @@ class ConstructListModel {
final List<ConstructUses> morphConstructs = constructList(
type: ConstructTypeEnum.morph,
);
final List<String> 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();

View file

@ -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 "🌺";
}
}

View file

@ -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<String> getDistractorDefinitions(
LemmaDefinitionRequest req, int count) {
_clearExpiredEntries();
final List<String> 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

View file

@ -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<POSActivitySequence> 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,

View file

@ -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,

View file

@ -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<MessageActivityResponse> 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,
),
),
);
}
}

View file

@ -30,14 +30,11 @@ class EmojiPracticeButtonState extends State<EmojiPracticeButton> {
}
}
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<EmojiPracticeButton> {
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(),
);

View file

@ -84,12 +84,14 @@ class WordAudioButtonState extends State<WordTextWithAudioButton> {
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,
),
],
),

View file

@ -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<void> _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 ?? "..."),
),
);
}

View file

@ -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<ActivityMorph> 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<MorphologicalListWidget> {
// 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<String> seq = MorphActivityGenerator().getSequence(
MatrixState.pangeaController.languageController.userL2?.langCode,
token.pos,
);
final List<ActivityMorph> _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<void> _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<ActivityMorph> 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<MorphologicalListWidget> {
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),

View file

@ -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<PartOfSpeechWidget> {
late Future<String> _partOfSpeech;
@override
void initState() {
super.initState();
_partOfSpeech = _fetchPartOfSpeech();
}
Future<String> _fetchPartOfSpeech() async {
if (widget.token.shouldDoPosActivity) {
return '?';
} else {
return widget.token.pos;
}
}
@override
Widget build(BuildContext context) {
return FutureBuilder<String>(
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
},
);
}
},
);
}
}

View file

@ -38,7 +38,7 @@ class WordZoomWidget extends StatefulWidget {
}
class WordZoomWidgetState extends State<WordZoomWidget> {
ActivityTypeEnum? _activityType;
ActivityTypeEnum _activityType = ActivityTypeEnum.wordMeaning;
// morphological activities
String? _selectedMorphFeature;
@ -72,6 +72,8 @@ class WordZoomWidgetState extends State<WordZoomWidget> {
});
}
});
// if learner should do translation activity then setActivityType to wordMeaning
}
@override
@ -89,23 +91,10 @@ class WordZoomWidgetState extends State<WordZoomWidget> {
}
}
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<WordZoomWidget> {
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<WordZoomWidget> {
}
}
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<WordZoomWidget> {
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<WordZoomWidget> {
token: widget.token,
onPressed: () => _setActivityType(
_activityType == ActivityTypeEnum.emoji
? null
? ActivityTypeEnum.wordMeaning
: ActivityTypeEnum.emoji,
),
setEmoji: _setEmoji,
@ -229,7 +259,7 @@ class WordZoomWidgetState extends State<WordZoomWidget> {
token: widget.token,
onPressed: () => _setActivityType(
_activityType == ActivityTypeEnum.lemmaId
? null
? ActivityTypeEnum.wordMeaning
: ActivityTypeEnum.lemmaId,
),
lemma: _lemma,
@ -238,34 +268,7 @@ class WordZoomWidgetState extends State<WordZoomWidget> {
],
),
),
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,