From 257fb465be7ecccbbc4d89a5ef5ca58039f107c8 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Mon, 19 Jan 2026 12:18:27 -0500 Subject: [PATCH] chore: reload info in word card in vocab details after submitting token feedback --- .../analytics_details_popup.dart | 34 +++++- .../vocab_analytics_details_view.dart | 32 ++---- .../lemmas/lemma_highlight_emoji_row.dart | 71 ++++++------ lib/pangea/lemmas/lemma_meaning_builder.dart | 59 +++++----- lib/pangea/lemmas/lemma_meaning_widget.dart | 77 ------------- .../phonetic_transcription_builder.dart | 66 +++++------ .../phonetic_transcription_widget.dart | 104 +++++++++--------- .../show_token_feedback_dialog.dart | 3 + .../word_card/lemma_meaning_display.dart | 87 +++++++-------- .../toolbar/word_card/word_zoom_widget.dart | 4 + 10 files changed, 236 insertions(+), 301 deletions(-) delete mode 100644 lib/pangea/lemmas/lemma_meaning_widget.dart diff --git a/lib/pangea/analytics_details_popup/analytics_details_popup.dart b/lib/pangea/analytics_details_popup/analytics_details_popup.dart index 4a227e243..7bfa27c6a 100644 --- a/lib/pangea/analytics_details_popup/analytics_details_popup.dart +++ b/lib/pangea/analytics_details_popup/analytics_details_popup.dart @@ -18,9 +18,13 @@ import 'package:fluffychat/pangea/analytics_summary/learning_progress_indicators import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/constructs/construct_identifier.dart'; import 'package:fluffychat/pangea/constructs/construct_level_enum.dart'; +import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; +import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart'; import 'package:fluffychat/pangea/morphs/default_morph_mapping.dart'; import 'package:fluffychat/pangea/morphs/morph_models.dart'; import 'package:fluffychat/pangea/morphs/morph_repo.dart'; +import 'package:fluffychat/pangea/token_info_feedback/show_token_feedback_dialog.dart'; +import 'package:fluffychat/pangea/token_info_feedback/token_info_feedback_request.dart'; import 'package:fluffychat/widgets/matrix.dart'; class ConstructAnalyticsView extends StatefulWidget { @@ -49,6 +53,7 @@ class ConstructAnalyticsViewState extends State { FocusNode searchFocusNode = FocusNode(); ConstructLevelEnum? selectedConstructLevel; StreamSubscription? _constructUpdateSub; + final ValueNotifier reloadNotifier = ValueNotifier(0); @override void initState() { @@ -72,6 +77,7 @@ class ConstructAnalyticsViewState extends State { searchController.dispose(); _constructUpdateSub?.cancel(); searchFocusNode.dispose(); + reloadNotifier.dispose(); super.dispose(); } @@ -162,6 +168,29 @@ class ConstructAnalyticsViewState extends State { }); } + Future onFlagTokenInfo( + PangeaToken token, + LemmaInfoResponse lemmaInfo, + String phonetics, + ) async { + final requestData = TokenInfoFeedbackRequestData( + userId: Matrix.of(context).client.userID!, + detectedLanguage: MatrixState.pangeaController.userController.userL2Code!, + tokens: [token], + selectedToken: 0, + wordCardL1: MatrixState.pangeaController.userController.userL1Code!, + lemmaInfo: lemmaInfo, + phonetics: phonetics, + ); + + await TokenFeedbackUtil.showTokenFeedbackDialog( + context, + requestData: requestData, + langCode: MatrixState.pangeaController.userController.userL2Code!, + onUpdated: () => reloadNotifier.value++, + ); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -182,7 +211,10 @@ class ConstructAnalyticsViewState extends State { : MorphDetailsView(constructId: widget.construct!) : widget.construct == null ? VocabAnalyticsListView(controller: this) - : VocabDetailsView(constructId: widget.construct!), + : VocabDetailsView( + constructId: widget.construct!, + controller: this, + ), ), ], ), diff --git a/lib/pangea/analytics_details_popup/vocab_analytics_details_view.dart b/lib/pangea/analytics_details_popup/vocab_analytics_details_view.dart index 58bafc387..79dda8441 100644 --- a/lib/pangea/analytics_details_popup/vocab_analytics_details_view.dart +++ b/lib/pangea/analytics_details_popup/vocab_analytics_details_view.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:collection/collection.dart'; import 'package:fluffychat/l10n/l10n.dart'; +import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart'; import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_usage_content.dart'; import 'package:fluffychat/pangea/analytics_details_popup/construct_xp_progress_bar.dart'; import 'package:fluffychat/pangea/analytics_details_popup/word_text_with_audio_button.dart'; @@ -12,8 +13,6 @@ import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/events/models/pangea_token_text_model.dart'; import 'package:fluffychat/pangea/lemmas/lemma.dart'; import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart'; -import 'package:fluffychat/pangea/token_info_feedback/show_token_feedback_dialog.dart'; -import 'package:fluffychat/pangea/token_info_feedback/token_info_feedback_request.dart'; import 'package:fluffychat/pangea/toolbar/word_card/word_zoom_widget.dart'; import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart'; import 'package:fluffychat/widgets/future_loading_dialog.dart'; @@ -23,10 +22,12 @@ import 'package:fluffychat/widgets/matrix.dart'; /// Displays information about selected lemma, and its usage class VocabDetailsView extends StatelessWidget { final ConstructIdentifier constructId; + final ConstructAnalyticsViewState controller; const VocabDetailsView({ super.key, required this.constructId, + required this.controller, }); Future _blockLemma(BuildContext context) async { @@ -93,27 +94,12 @@ class VocabDetailsView extends StatelessWidget { MatrixState.pangeaController.userController.userL2Code!, construct: constructId, onClose: Navigator.of(context).pop, - onFlagTokenInfo: - (LemmaInfoResponse lemmaInfo, String phonetics) { - final requestData = TokenInfoFeedbackRequestData( - userId: Matrix.of(context).client.userID!, - detectedLanguage: MatrixState - .pangeaController.userController.userL2Code!, - tokens: [token], - selectedToken: 0, - wordCardL1: MatrixState - .pangeaController.userController.userL1Code!, - lemmaInfo: lemmaInfo, - phonetics: phonetics, - ); - - TokenFeedbackUtil.showTokenFeedbackDialog( - context, - requestData: requestData, - langCode: MatrixState - .pangeaController.userController.userL2Code!, - ); - }, + onFlagTokenInfo: ( + LemmaInfoResponse lemmaInfo, + String phonetics, + ) => + controller.onFlagTokenInfo(token, lemmaInfo, phonetics), + reloadNotifier: controller.reloadNotifier, maxWidth: double.infinity, ), ), diff --git a/lib/pangea/lemmas/lemma_highlight_emoji_row.dart b/lib/pangea/lemmas/lemma_highlight_emoji_row.dart index 4dec278b9..70d7ed1c2 100644 --- a/lib/pangea/lemmas/lemma_highlight_emoji_row.dart +++ b/lib/pangea/lemmas/lemma_highlight_emoji_row.dart @@ -6,6 +6,7 @@ import 'package:shimmer/shimmer.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/analytics_data/analytics_updater_mixin.dart'; +import 'package:fluffychat/pangea/common/utils/async_state.dart'; import 'package:fluffychat/pangea/common/widgets/shimmer_background.dart'; import 'package:fluffychat/pangea/constructs/construct_identifier.dart'; import 'package:fluffychat/pangea/lemmas/lemma_meaning_builder.dart'; @@ -49,35 +50,15 @@ class LemmaHighlightEmojiRowState extends State constructId: widget.cId, messageInfo: widget.messageInfo, builder: (context, controller) { - if (controller.error != null) { - return const SizedBox.shrink(); - } - - final emojis = controller.lemmaInfo?.emoji; - return SizedBox( - height: 70.0, - child: Row( - spacing: 4.0, - mainAxisSize: MainAxisSize.min, - children: emojis == null || emojis.isEmpty - ? List.generate( - 3, - (_) => Shimmer.fromColors( - baseColor: Colors.transparent, - highlightColor: - Theme.of(context).colorScheme.primary.withAlpha(70), - child: Container( - height: 55.0, - width: 55.0, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.primary, - borderRadius: - BorderRadius.circular(AppConfig.borderRadius), - ), - ), - ), - ) - : emojis.map( + return switch (controller.state) { + AsyncError() => const SizedBox.shrink(), + AsyncLoaded(value: final lemmaInfo) => SizedBox( + height: 70.0, + child: Row( + spacing: 4.0, + mainAxisSize: MainAxisSize.min, + children: [ + ...lemmaInfo.emoji.map( (emoji) { final targetId = "${widget.targetId}-$emoji"; return EmojiChoiceItem( @@ -94,9 +75,35 @@ class LemmaHighlightEmojiRowState extends State enabled: widget.enabled, ); }, - ).toList(), - ), - ); + ), + ], + ), + ), + _ => SizedBox( + height: 70.0, + child: Row( + spacing: 4.0, + mainAxisSize: MainAxisSize.min, + children: List.generate( + 3, + (_) => Shimmer.fromColors( + baseColor: Colors.transparent, + highlightColor: + Theme.of(context).colorScheme.primary.withAlpha(70), + child: Container( + height: 55.0, + width: 55.0, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.primary, + borderRadius: + BorderRadius.circular(AppConfig.borderRadius), + ), + ), + ), + ), + ), + ), + }; }, ); } diff --git a/lib/pangea/lemmas/lemma_meaning_builder.dart b/lib/pangea/lemmas/lemma_meaning_builder.dart index b6cfcd0f3..78a598833 100644 --- a/lib/pangea/lemmas/lemma_meaning_builder.dart +++ b/lib/pangea/lemmas/lemma_meaning_builder.dart @@ -8,29 +8,11 @@ import 'package:fluffychat/pangea/lemmas/lemma_info_request.dart'; import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart'; import 'package:fluffychat/widgets/matrix.dart'; -class _LemmaMeaningLoader extends AsyncLoader { - final LemmaInfoRequest request; - _LemmaMeaningLoader(this.request) : super(); - - @override - Future fetch() async { - final result = await LemmaInfoRepo.get( - MatrixState.pangeaController.userController.accessToken, - request, - ); - - if (result.isError) { - throw result.asError!.error; - } - - return result.asValue!.value; - } -} - class LemmaMeaningBuilder extends StatefulWidget { final String langCode; final ConstructIdentifier constructId; final Map messageInfo; + final ValueNotifier? reloadNotifier; final Widget Function( BuildContext context, @@ -43,6 +25,7 @@ class LemmaMeaningBuilder extends StatefulWidget { required this.constructId, required this.builder, required this.messageInfo, + this.reloadNotifier, }); @override @@ -50,12 +33,14 @@ class LemmaMeaningBuilder extends StatefulWidget { } class LemmaMeaningBuilderState extends State { - late _LemmaMeaningLoader _loader; + final ValueNotifier> _loader = + ValueNotifier(const AsyncState.idle()); @override void initState() { super.initState(); - _reload(); + _load(); + widget.reloadNotifier?.addListener(_load); } @override @@ -63,24 +48,22 @@ class LemmaMeaningBuilderState extends State { super.didUpdateWidget(oldWidget); if (oldWidget.constructId != widget.constructId || oldWidget.langCode != widget.langCode) { - _loader.dispose(); - _reload(); + _load(); } } @override void dispose() { + widget.reloadNotifier?.removeListener(_load); _loader.dispose(); super.dispose(); } - bool get isLoading => _loader.isLoading; - bool get isError => _loader.isError; - - Object? get error => - isError ? (_loader.state.value as AsyncError).error : null; - - LemmaInfoResponse? get lemmaInfo => _loader.value; + AsyncState get state => _loader.value; + bool get isError => _loader.value is AsyncError; + bool get isLoaded => _loader.value is AsyncLoaded; + LemmaInfoResponse? get lemmaInfo => + isLoaded ? (_loader.value as AsyncLoaded).value : null; LemmaInfoRequest get _request => LemmaInfoRequest( lemma: widget.constructId.lemma, @@ -91,15 +74,23 @@ class LemmaMeaningBuilderState extends State { messageInfo: widget.messageInfo, ); - void _reload() { - _loader = _LemmaMeaningLoader(_request); - _loader.load(); + Future _load() async { + _loader.value = const AsyncState.loading(); + final result = await LemmaInfoRepo.get( + MatrixState.pangeaController.userController.accessToken, + _request, + ); + + if (!mounted) return; + result.isError + ? _loader.value = AsyncState.error(result.asError!.error) + : _loader.value = AsyncState.loaded(result.asValue!.value); } @override Widget build(BuildContext context) { return ValueListenableBuilder( - valueListenable: _loader.state, + valueListenable: _loader, builder: (context, _, __) => widget.builder( context, this, diff --git a/lib/pangea/lemmas/lemma_meaning_widget.dart b/lib/pangea/lemmas/lemma_meaning_widget.dart deleted file mode 100644 index e2daea447..000000000 --- a/lib/pangea/lemmas/lemma_meaning_widget.dart +++ /dev/null @@ -1,77 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:fluffychat/l10n/l10n.dart'; -import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart'; -import 'package:fluffychat/pangea/common/network/requests.dart'; -import 'package:fluffychat/pangea/common/widgets/error_indicator.dart'; -import 'package:fluffychat/pangea/constructs/construct_identifier.dart'; -import 'package:fluffychat/pangea/lemmas/lemma_meaning_builder.dart'; -import 'package:fluffychat/widgets/matrix.dart'; - -class LemmaMeaningWidget extends StatelessWidget { - final ConstructIdentifier constructId; - final TextStyle? style; - final InlineSpan? leading; - final Map messageInfo; - - const LemmaMeaningWidget({ - super.key, - required this.constructId, - required this.messageInfo, - this.style, - this.leading, - }); - - @override - Widget build(BuildContext context) { - return LemmaMeaningBuilder( - langCode: MatrixState.pangeaController.userController.userL2!.langCode, - constructId: constructId, - messageInfo: messageInfo, - builder: (context, controller) { - if (controller.isLoading) { - return const TextLoadingShimmer(); - } - - if (controller.error != null) { - if (controller.error is UnsubscribedException) { - return ErrorIndicator( - message: L10n.of(context).subscribeToUnlockDefinitions, - style: style, - onTap: () { - MatrixState.pangeaController.subscriptionController - .showPaywall(context); - }, - ); - } - return ErrorIndicator( - message: L10n.of(context).errorFetchingDefinition, - style: style, - ); - } - - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Flexible( - child: RichText( - textAlign: leading == null ? TextAlign.center : TextAlign.start, - text: TextSpan( - style: style, - children: [ - if (leading != null) leading!, - if (leading != null) - const WidgetSpan(child: SizedBox(width: 6.0)), - TextSpan( - text: controller.lemmaInfo?.meaning, - ), - ], - ), - ), - ), - ], - ); - }, - ); - } -} diff --git a/lib/pangea/phonetic_transcription/phonetic_transcription_builder.dart b/lib/pangea/phonetic_transcription/phonetic_transcription_builder.dart index 366f9b1fe..3627f78a3 100644 --- a/lib/pangea/phonetic_transcription/phonetic_transcription_builder.dart +++ b/lib/pangea/phonetic_transcription/phonetic_transcription_builder.dart @@ -8,29 +8,10 @@ import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_ import 'package:fluffychat/widgets/matrix.dart'; import 'phonetic_transcription_repo.dart'; -class _TranscriptLoader extends AsyncLoader { - final PhoneticTranscriptionRequest request; - _TranscriptLoader(this.request) : super(); - - @override - Future fetch() async { - final resp = await PhoneticTranscriptionRepo.get( - MatrixState.pangeaController.userController.accessToken, - request, - ); - - if (resp.isError) { - throw resp.asError!.error; - } - - return resp.asValue!.value.phoneticTranscriptionResult.phoneticTranscription - .first.phoneticL1Transcription.content; - } -} - class PhoneticTranscriptionBuilder extends StatefulWidget { final LanguageModel textLanguage; final String text; + final ValueNotifier? reloadNotifier; final Widget Function( BuildContext context, @@ -42,6 +23,7 @@ class PhoneticTranscriptionBuilder extends StatefulWidget { required this.textLanguage, required this.text, required this.builder, + this.reloadNotifier, }); @override @@ -51,12 +33,14 @@ class PhoneticTranscriptionBuilder extends StatefulWidget { class PhoneticTranscriptionBuilderState extends State { - late _TranscriptLoader _loader; + final ValueNotifier> _loader = + ValueNotifier(const AsyncState.idle()); @override void initState() { super.initState(); - _reload(); + _load(); + widget.reloadNotifier?.addListener(_load); } @override @@ -64,27 +48,24 @@ class PhoneticTranscriptionBuilderState super.didUpdateWidget(oldWidget); if (oldWidget.text != widget.text || oldWidget.textLanguage != widget.textLanguage) { - _loader.dispose(); - _reload(); + _load(); } } @override void dispose() { + widget.reloadNotifier?.removeListener(_load); _loader.dispose(); super.dispose(); } - bool get isLoading => _loader.isLoading; - bool get isError => _loader.isError; + AsyncState get state => _loader.value; + bool get isError => _loader.value is AsyncError; + bool get isLoaded => _loader.value is AsyncLoaded; + String? get transcription => + isLoaded ? (_loader.value as AsyncLoaded).value : null; - Object? get error => - isError ? (_loader.state.value as AsyncError).error : null; - - String? get transcription => _loader.value; - - PhoneticTranscriptionRequest get _transcriptRequest => - PhoneticTranscriptionRequest( + PhoneticTranscriptionRequest get _request => PhoneticTranscriptionRequest( arc: LanguageArc( l1: MatrixState.pangeaController.userController.userL1!, l2: widget.textLanguage, @@ -92,15 +73,26 @@ class PhoneticTranscriptionBuilderState content: PangeaTokenText.fromString(widget.text), ); - void _reload() { - _loader = _TranscriptLoader(_transcriptRequest); - _loader.load(); + Future _load() async { + _loader.value = const AsyncState.loading(); + final resp = await PhoneticTranscriptionRepo.get( + MatrixState.pangeaController.userController.accessToken, + _request, + ); + + if (!mounted) return; + resp.isError + ? _loader.value = AsyncState.error(resp.asError!.error) + : _loader.value = AsyncState.loaded( + resp.asValue!.value.phoneticTranscriptionResult + .phoneticTranscription.first.phoneticL1Transcription.content, + ); } @override Widget build(BuildContext context) { return ValueListenableBuilder( - valueListenable: _loader.state, + valueListenable: _loader, builder: (context, _, __) => widget.builder( context, this, diff --git a/lib/pangea/phonetic_transcription/phonetic_transcription_widget.dart b/lib/pangea/phonetic_transcription/phonetic_transcription_widget.dart index 7736c13b9..de6a7c494 100644 --- a/lib/pangea/phonetic_transcription/phonetic_transcription_widget.dart +++ b/lib/pangea/phonetic_transcription/phonetic_transcription_widget.dart @@ -1,10 +1,9 @@ -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart'; import 'package:fluffychat/pangea/common/network/requests.dart'; +import 'package:fluffychat/pangea/common/utils/async_state.dart'; import 'package:fluffychat/pangea/common/widgets/error_indicator.dart'; import 'package:fluffychat/pangea/languages/language_model.dart'; import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_builder.dart'; @@ -22,6 +21,7 @@ class PhoneticTranscriptionWidget extends StatefulWidget { final int? maxLines; final VoidCallback? onTranscriptionFetched; + final ValueNotifier? reloadNotifier; const PhoneticTranscriptionWidget({ super.key, @@ -32,6 +32,7 @@ class PhoneticTranscriptionWidget extends StatefulWidget { this.iconColor, this.maxLines, this.onTranscriptionFetched, + this.reloadNotifier, }); @override @@ -85,59 +86,58 @@ class _PhoneticTranscriptionWidgetState key: MatrixState.pAnyState.layerLinkAndKey(targetId).key, textLanguage: widget.textLanguage, text: widget.text, + reloadNotifier: widget.reloadNotifier, builder: (context, controller) { - if (controller.isError) { - return controller.error is UnsubscribedException - ? ErrorIndicator( - message: L10n.of(context) - .subscribeToUnlockTranscriptions, - onTap: () { - MatrixState - .pangeaController.subscriptionController - .showPaywall(context); - }, - ) - : ErrorIndicator( - message: - L10n.of(context).failedToFetchTranscription, - ); - } - - if (controller.isLoading || - controller.transcription == null) { - return const TextLoadingShimmer( - width: 125.0, - height: 20.0, - ); - } - - return Row( - spacing: 8.0, - mainAxisSize: MainAxisSize.min, - children: [ - Flexible( - child: Text( - controller.transcription!, - textScaler: TextScaler.noScaling, - style: widget.style ?? - Theme.of(context).textTheme.bodyMedium, - maxLines: widget.maxLines, - overflow: TextOverflow.ellipsis, - ), + return switch (controller.state) { + AsyncError(error: final error) => + error is UnsubscribedException + ? ErrorIndicator( + message: L10n.of(context) + .subscribeToUnlockTranscriptions, + onTap: () { + MatrixState + .pangeaController.subscriptionController + .showPaywall(context); + }, + ) + : ErrorIndicator( + message: + L10n.of(context).failedToFetchTranscription, + ), + AsyncLoaded(value: final transcription) => Row( + spacing: 8.0, + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: Text( + transcription, + textScaler: TextScaler.noScaling, + style: widget.style ?? + Theme.of(context).textTheme.bodyMedium, + maxLines: widget.maxLines, + overflow: TextOverflow.ellipsis, + ), + ), + Tooltip( + message: _isPlaying + ? L10n.of(context).stop + : L10n.of(context).playAudio, + child: Icon( + _isPlaying + ? Icons.pause_outlined + : Icons.volume_up, + size: widget.iconSize ?? 24, + color: widget.iconColor ?? + Theme.of(context).iconTheme.color, + ), + ), + ], ), - Tooltip( - message: _isPlaying - ? L10n.of(context).stop - : L10n.of(context).playAudio, - child: Icon( - _isPlaying ? Icons.pause_outlined : Icons.volume_up, - size: widget.iconSize ?? 24, - color: widget.iconColor ?? - Theme.of(context).iconTheme.color, - ), + _ => const TextLoadingShimmer( + width: 125.0, + height: 20.0, ), - ], - ); + }; }, ), ), diff --git a/lib/pangea/token_info_feedback/show_token_feedback_dialog.dart b/lib/pangea/token_info_feedback/show_token_feedback_dialog.dart index 7d60c9181..9d34b7141 100644 --- a/lib/pangea/token_info_feedback/show_token_feedback_dialog.dart +++ b/lib/pangea/token_info_feedback/show_token_feedback_dialog.dart @@ -12,6 +12,7 @@ class TokenFeedbackUtil { required TokenInfoFeedbackRequestData requestData, required String langCode, PangeaMessageEvent? event, + VoidCallback? onUpdated, }) async { final resp = await showDialog( context: context, @@ -23,6 +24,8 @@ class TokenFeedbackUtil { ); if (resp == null) return; + + onUpdated?.call(); await showDialog( context: context, builder: (context) { diff --git a/lib/pangea/toolbar/word_card/lemma_meaning_display.dart b/lib/pangea/toolbar/word_card/lemma_meaning_display.dart index 1859282b6..70dd51f3e 100644 --- a/lib/pangea/toolbar/word_card/lemma_meaning_display.dart +++ b/lib/pangea/toolbar/word_card/lemma_meaning_display.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart'; +import 'package:fluffychat/pangea/common/utils/async_state.dart'; import 'package:fluffychat/pangea/common/widgets/error_indicator.dart'; import 'package:fluffychat/pangea/constructs/construct_identifier.dart'; import 'package:fluffychat/pangea/lemmas/lemma_meaning_builder.dart'; @@ -12,6 +13,7 @@ class LemmaMeaningDisplay extends StatelessWidget { final ConstructIdentifier constructId; final String text; final Map messageInfo; + final ValueNotifier? reloadNotifier; const LemmaMeaningDisplay({ super.key, @@ -19,6 +21,7 @@ class LemmaMeaningDisplay extends StatelessWidget { required this.constructId, required this.text, required this.messageInfo, + this.reloadNotifier, }); @override @@ -27,53 +30,47 @@ class LemmaMeaningDisplay extends StatelessWidget { langCode: langCode, constructId: constructId, messageInfo: messageInfo, + reloadNotifier: reloadNotifier, builder: (context, controller) { - if (controller.isError) { - return ErrorIndicator( - message: L10n.of(context).errorFetchingDefinition, - style: const TextStyle(fontSize: 14.0), - ); - } - - if (controller.isLoading || controller.lemmaInfo == null) { - return const TextLoadingShimmer( - width: 125.0, - height: 20.0, - ); - } - - final pos = getGrammarCopy( - category: "POS", - lemma: constructId.category, - context: context, - ) ?? - L10n.of(context).other; - - return RichText( - maxLines: 2, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.center, - text: TextSpan( - style: DefaultTextStyle.of(context).style.copyWith( - fontSize: 14.0, - ), - children: [ - TextSpan( - text: "${constructId.lemma} ($pos)", + return switch (controller.state) { + AsyncError() => ErrorIndicator( + message: L10n.of(context).errorFetchingDefinition, + style: const TextStyle(fontSize: 14.0), + ), + AsyncLoaded(value: final lemmaInfo) => RichText( + maxLines: 2, + overflow: TextOverflow.ellipsis, + textAlign: TextAlign.center, + text: TextSpan( + style: DefaultTextStyle.of(context).style.copyWith( + fontSize: 14.0, + ), + children: [ + TextSpan( + text: "${constructId.lemma} (${getGrammarCopy( + category: "POS", + lemma: constructId.category, + context: context, + ) ?? L10n.of(context).other})", + ), + const WidgetSpan( + child: SizedBox(width: 8.0), + ), + const TextSpan(text: ":"), + const WidgetSpan( + child: SizedBox(width: 8.0), + ), + TextSpan( + text: lemmaInfo.meaning, + ), + ], ), - const WidgetSpan( - child: SizedBox(width: 8.0), - ), - const TextSpan(text: ":"), - const WidgetSpan( - child: SizedBox(width: 8.0), - ), - TextSpan( - text: controller.lemmaInfo!.meaning, - ), - ], - ), - ); + ), + _ => const TextLoadingShimmer( + width: 125.0, + height: 20.0, + ), + }; }, ); } diff --git a/lib/pangea/toolbar/word_card/word_zoom_widget.dart b/lib/pangea/toolbar/word_card/word_zoom_widget.dart index 0d53ba459..4e9b40ffc 100644 --- a/lib/pangea/toolbar/word_card/word_zoom_widget.dart +++ b/lib/pangea/toolbar/word_card/word_zoom_widget.dart @@ -30,6 +30,7 @@ class WordZoomWidget extends StatelessWidget { final bool enableEmojiSelection; final VoidCallback? onDismissNewWordOverlay; final Function(LemmaInfoResponse, String)? onFlagTokenInfo; + final ValueNotifier? reloadNotifier; final double? maxWidth; const WordZoomWidget({ @@ -42,6 +43,7 @@ class WordZoomWidget extends StatelessWidget { this.enableEmojiSelection = true, this.onDismissNewWordOverlay, this.onFlagTokenInfo, + this.reloadNotifier, this.maxWidth, }); @@ -143,6 +145,7 @@ class WordZoomWidget extends StatelessWidget { style: const TextStyle(fontSize: 14.0), iconSize: 24.0, maxLines: 2, + reloadNotifier: reloadNotifier, ) : WordAudioButton( text: token.content, @@ -161,6 +164,7 @@ class WordZoomWidget extends StatelessWidget { constructId: construct, text: token.content, messageInfo: event?.content ?? {}, + reloadNotifier: reloadNotifier, ), ], ),