fix: always pass lemma info and phonetic transcription in token feedback request

This commit is contained in:
ggurdin 2025-12-09 14:37:15 -05:00
parent 67e77cfd90
commit c2defa9023
No known key found for this signature in database
GPG key ID: A01CB41737CBB478
13 changed files with 419 additions and 261 deletions

View file

@ -150,7 +150,7 @@ class ConstructIdentifier {
uses: [],
);
LemmaInfoRequest get _lemmaInfoRequest => LemmaInfoRequest(
LemmaInfoRequest get lemmaInfoRequest => LemmaInfoRequest(
partOfSpeech: category,
lemmaLang:
MatrixState.pangeaController.userController.userL2?.langCodeShort ??
@ -163,7 +163,7 @@ class ConstructIdentifier {
/// [lemmmaLang] if not set, assumed to be userL2
Future<LemmaInfoResponse> getLemmaInfo() => LemmaInfoRepo.get(
_lemmaInfoRequest,
lemmaInfoRequest,
);
List<String> get userSetEmoji => userLemmaInfo.emojis ?? [];

View file

@ -13,10 +13,13 @@ import 'package:fluffychat/widgets/matrix.dart';
class LemmaInfoRepo {
static final GetStorage _lemmaStorage = GetStorage('lemma_storage');
static void set(LemmaInfoRequest request, LemmaInfoResponse response) {
static Future<void> set(
LemmaInfoRequest request,
LemmaInfoResponse response,
) async {
// set expireAt if not set
response.expireAt ??= DateTime.now().add(const Duration(days: 100));
_lemmaStorage.write(request.storageKey, response.toJson());
await _lemmaStorage.write(request.storageKey, response.toJson());
}
static LemmaInfoResponse? getCached(LemmaInfoRequest request) {

View file

@ -22,6 +22,11 @@ class LemmaInfoResponse implements JsonSerializable {
);
}
static LemmaInfoResponse get error => LemmaInfoResponse(
emoji: [],
meaning: 'ERROR',
);
@override
Map<String, dynamic> toJson() {
return {

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/pangea/common/utils/async_state.dart';
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
import 'package:fluffychat/pangea/languages/language_constants.dart';
import 'package:fluffychat/pangea/lemmas/lemma_info_repo.dart';
@ -7,6 +8,14 @@ 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<LemmaInfoResponse> {
final LemmaInfoRequest request;
_LemmaMeaningLoader(this.request) : super();
@override
Future<LemmaInfoResponse> fetch() => LemmaInfoRepo.get(request);
}
class LemmaMeaningBuilder extends StatefulWidget {
final String langCode;
final ConstructIdentifier constructId;
@ -27,14 +36,12 @@ class LemmaMeaningBuilder extends StatefulWidget {
}
class LemmaMeaningBuilderState extends State<LemmaMeaningBuilder> {
LemmaInfoResponse? lemmaInfo;
bool isLoading = true;
Object? error;
late _LemmaMeaningLoader _loader;
@override
void initState() {
super.initState();
_fetchLemmaMeaning();
_reload();
}
@override
@ -42,10 +49,25 @@ class LemmaMeaningBuilderState extends State<LemmaMeaningBuilder> {
super.didUpdateWidget(oldWidget);
if (oldWidget.constructId != widget.constructId ||
oldWidget.langCode != widget.langCode) {
_fetchLemmaMeaning();
_loader.dispose();
_reload();
}
}
@override
void dispose() {
_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;
LemmaInfoRequest get _request => LemmaInfoRequest(
lemma: widget.constructId.lemma,
partOfSpeech: widget.constructId.category,
@ -54,27 +76,19 @@ class LemmaMeaningBuilderState extends State<LemmaMeaningBuilder> {
LanguageKeys.defaultLanguage,
);
Future<void> _fetchLemmaMeaning() async {
setState(() {
isLoading = true;
error = null;
});
try {
final resp = await LemmaInfoRepo.get(_request);
lemmaInfo = resp;
} catch (e) {
error = e;
} finally {
if (mounted) setState(() => isLoading = false);
}
void _reload() {
_loader = _LemmaMeaningLoader(_request);
_loader.load();
}
@override
Widget build(BuildContext context) {
return widget.builder(
context,
this,
return ValueListenableBuilder(
valueListenable: _loader.state,
builder: (context, _, __) => widget.builder(
context,
this,
),
);
}
}

View file

@ -0,0 +1,102 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/pangea/common/utils/async_state.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_text_model.dart';
import 'package:fluffychat/pangea/languages/language_arc_model.dart';
import 'package:fluffychat/pangea/languages/language_model.dart';
import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_request.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'phonetic_transcription_repo.dart';
class _TranscriptLoader extends AsyncLoader<String> {
final PhoneticTranscriptionRequest request;
_TranscriptLoader(this.request) : super();
@override
Future<String> fetch() async {
final resp = await PhoneticTranscriptionRepo.get(request);
return resp.phoneticTranscriptionResult.phoneticTranscription.first
.phoneticL1Transcription.content;
}
}
class PhoneticTranscriptionBuilder extends StatefulWidget {
final LanguageModel textLanguage;
final String text;
final Widget Function(
BuildContext context,
PhoneticTranscriptionBuilderState controller,
) builder;
const PhoneticTranscriptionBuilder({
super.key,
required this.textLanguage,
required this.text,
required this.builder,
});
@override
PhoneticTranscriptionBuilderState createState() =>
PhoneticTranscriptionBuilderState();
}
class PhoneticTranscriptionBuilderState
extends State<PhoneticTranscriptionBuilder> {
late _TranscriptLoader _loader;
@override
void initState() {
super.initState();
_reload();
}
@override
void didUpdateWidget(covariant PhoneticTranscriptionBuilder oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.text != widget.text ||
oldWidget.textLanguage != widget.textLanguage) {
_loader.dispose();
_reload();
}
}
@override
void dispose() {
_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;
String? get transcription => _loader.value;
PhoneticTranscriptionRequest get _transcriptRequest =>
PhoneticTranscriptionRequest(
arc: LanguageArc(
l1: MatrixState.pangeaController.userController.userL1!,
l2: widget.textLanguage,
),
content: PangeaTokenText.fromString(widget.text),
);
void _reload() {
_loader = _TranscriptLoader(_transcriptRequest);
_loader.load();
}
@override
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: _loader.state,
builder: (context, _, __) => widget.builder(
context,
this,
),
);
}
}

View file

@ -4,13 +4,9 @@ import 'package:flutter/material.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/common/network/requests.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/common/widgets/error_indicator.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_text_model.dart';
import 'package:fluffychat/pangea/languages/language_arc_model.dart';
import 'package:fluffychat/pangea/languages/language_model.dart';
import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_repo.dart';
import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_request.dart';
import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_builder.dart';
import 'package:fluffychat/pangea/text_to_speech/tts_controller.dart';
import 'package:fluffychat/widgets/hover_builder.dart';
import 'package:fluffychat/widgets/matrix.dart';
@ -43,79 +39,6 @@ class PhoneticTranscriptionWidget extends StatefulWidget {
class _PhoneticTranscriptionWidgetState
extends State<PhoneticTranscriptionWidget> {
bool _isPlaying = false;
bool _isLoading = false;
Object? _error;
String? _transcription;
@override
void initState() {
super.initState();
_fetchTranscription();
}
@override
void didUpdateWidget(
covariant PhoneticTranscriptionWidget oldWidget,
) {
super.didUpdateWidget(oldWidget);
if (oldWidget.text != widget.text ||
oldWidget.textLanguage != widget.textLanguage) {
_fetchTranscription();
}
}
Future<void> _fetchTranscription() async {
try {
setState(() {
_isLoading = true;
_error = null;
_transcription = null;
});
if (MatrixState.pangeaController.userController.userL1 == null) {
ErrorHandler.logError(
e: Exception('User L1 is not set'),
data: {
'text': widget.text,
'textLanguageCode': widget.textLanguage.langCode,
},
);
_error = Exception('User L1 is not set');
return;
}
final req = PhoneticTranscriptionRequest(
arc: LanguageArc(
l1: MatrixState.pangeaController.userController.userL1!,
l2: widget.textLanguage,
),
content: PangeaTokenText.fromString(widget.text),
// arc can be omitted for default empty map
);
final res = await PhoneticTranscriptionRepo.get(req);
_transcription = res.phoneticTranscriptionResult.phoneticTranscription
.first.phoneticL1Transcription.content;
} catch (e, s) {
_error = e;
if (e is! UnsubscribedException) {
ErrorHandler.logError(
e: e,
s: s,
data: {
'text': widget.text,
'textLanguageCode': widget.textLanguage.langCode,
},
);
}
} finally {
if (mounted) {
setState(() {
_isLoading = false;
widget.onTranscriptionFetched?.call();
});
}
}
}
Future<void> _handleAudioTap() async {
if (_isPlaying) {
@ -156,14 +79,15 @@ class _PhoneticTranscriptionWidgetState
link: MatrixState.pAnyState
.layerLinkAndKey("phonetic-transcription-${widget.text}")
.link,
child: Row(
child: PhoneticTranscriptionBuilder(
key: MatrixState.pAnyState
.layerLinkAndKey("phonetic-transcription-${widget.text}")
.key,
mainAxisSize: MainAxisSize.min,
children: [
if (_error != null)
_error is UnsubscribedException
textLanguage: widget.textLanguage,
text: widget.text,
builder: (context, controller) {
if (controller.isError) {
return controller.error is UnsubscribedException
? ErrorIndicator(
message: L10n.of(context)
.subscribeToUnlockTranscriptions,
@ -176,37 +100,44 @@ class _PhoneticTranscriptionWidgetState
: ErrorIndicator(
message:
L10n.of(context).failedToFetchTranscription,
)
else if (_isLoading || _transcription == null)
const SizedBox(
);
}
if (controller.isLoading ||
controller.transcription == null) {
return const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator.adaptive(),
)
else
Flexible(
child: Text(
_transcription!,
textScaler: TextScaler.noScaling,
style: widget.style ??
Theme.of(context).textTheme.bodyMedium,
);
}
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,
),
),
),
if (_transcription != null && _error == null)
const SizedBox(width: 8),
if (_transcription != null && _error == null)
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,
),
),
),
],
],
);
},
),
),
),

View file

@ -8,8 +8,8 @@ import 'package:fluffychat/pangea/events/models/tokens_event_content_model.dart'
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/pangea/languages/language_arc_model.dart';
import 'package:fluffychat/pangea/languages/p_language_store.dart';
import 'package:fluffychat/pangea/lemmas/lemma_info_repo.dart';
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
import 'package:fluffychat/pangea/lemmas/user_set_lemma_info.dart';
import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_repo.dart';
import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_request.dart';
import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_response.dart';
@ -115,19 +115,11 @@ class TokenInfoFeedbackDialog extends StatelessWidget {
Future<void> _updateLemmaInfo(
PangeaToken token,
LemmaInfoResponse response,
) async {
final construct = token.vocabConstructID;
final currentLemmaInfo = construct.userLemmaInfo;
final updatedLemmaInfo = UserSetLemmaInfo(
meaning: response.meaning,
emojis: response.emoji,
);
if (currentLemmaInfo != updatedLemmaInfo) {
await construct.setUserLemmaInfo(updatedLemmaInfo);
}
}
) =>
LemmaInfoRepo.set(
token.vocabConstructID.lemmaInfoRequest,
response,
);
Future<void> _updatePhoneticTranscription(
PhoneticTranscriptionResponse response,

View file

@ -8,8 +8,8 @@ class TokenInfoFeedbackRequestData {
final String detectedLanguage;
final List<PangeaToken> tokens;
final int selectedToken;
final LemmaInfoResponse? lemmaInfo;
final String? phonetics;
final LemmaInfoResponse lemmaInfo;
final String phonetics;
final String wordCardL1;
TokenInfoFeedbackRequestData({
@ -19,8 +19,8 @@ class TokenInfoFeedbackRequestData {
required this.detectedLanguage,
required this.tokens,
required this.selectedToken,
this.lemmaInfo,
this.phonetics,
required this.lemmaInfo,
required this.phonetics,
required this.wordCardL1,
});
@ -67,7 +67,7 @@ class TokenInfoFeedbackRequest {
'detected_language': data.detectedLanguage,
'tokens': data.tokens.map((token) => token.toJson()).toList(),
'selected_token': data.selectedToken,
'lemma_info': data.lemmaInfo?.toJson(),
'lemma_info': data.lemmaInfo.toJson(),
'phonetics': data.phonetics,
'user_feedback': userFeedback,
'word_card_l1': data.wordCardL1,

View file

@ -0,0 +1,72 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/l10n/l10n.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';
class LemmaMeaningDisplay extends StatelessWidget {
final String langCode;
final ConstructIdentifier constructId;
final String text;
const LemmaMeaningDisplay({
super.key,
required this.langCode,
required this.constructId,
required this.text,
});
@override
Widget build(BuildContext context) {
return LemmaMeaningBuilder(
langCode: langCode,
constructId: constructId,
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 CircularProgressIndicator.adaptive();
}
if (constructId.lemma.toLowerCase() == text.toLowerCase()) {
return Text(
controller.lemmaInfo!.meaning,
style: const TextStyle(
fontSize: 14.0,
),
textAlign: TextAlign.center,
);
}
return RichText(
text: TextSpan(
style: DefaultTextStyle.of(context).style.copyWith(
fontSize: 14.0,
),
children: [
TextSpan(
text: constructId.lemma,
),
const WidgetSpan(
child: SizedBox(width: 8.0),
),
const TextSpan(text: ":"),
const WidgetSpan(
child: SizedBox(width: 8.0),
),
TextSpan(
text: controller.lemmaInfo!.meaning,
),
],
),
);
},
);
}
}

View file

@ -4,21 +4,26 @@ import 'package:collection/collection.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
import 'package:fluffychat/pangea/lemmas/lemma_meaning_builder.dart';
import 'package:fluffychat/pangea/toolbar/reading_assistance/lemma_emoji_picker.dart';
class LemmaReactionPicker extends StatelessWidget {
final List<String> emojis;
final bool loading;
final Event? event;
final ConstructIdentifier construct;
final String langCode;
const LemmaReactionPicker({
super.key,
required this.emojis,
required this.loading,
required this.event,
required this.construct,
required this.langCode,
this.event,
});
Future<void> setEmoji(String emoji) async {
Future<void> setEmoji(
String emoji,
List<String> emojis,
) async {
if (event?.room.timeline == null) {
throw Exception("Timeline is null in reaction picker");
}
@ -63,33 +68,44 @@ class LemmaReactionPicker extends StatelessWidget {
@override
Widget build(BuildContext context) {
final sentReactions = <String>{};
if (event?.room.timeline != null) {
sentReactions.addAll(
event!
.aggregatedEvents(
event!.room.timeline!,
RelationshipTypes.reaction,
)
.where(
(event) =>
event.senderId == event.room.client.userID &&
event.type == 'm.reaction',
)
.map(
(event) => event.content
.tryGetMap<String, Object?>('m.relates_to')
?.tryGet<String>('key'),
)
.whereType<String>(),
);
}
return LemmaMeaningBuilder(
langCode: langCode,
constructId: construct,
builder: (context, controller) {
final sentReactions = <String>{};
if (event?.room.timeline != null) {
sentReactions.addAll(
event!
.aggregatedEvents(
event!.room.timeline!,
RelationshipTypes.reaction,
)
.where(
(event) =>
event.senderId == event.room.client.userID &&
event.type == 'm.reaction',
)
.map(
(event) => event.content
.tryGetMap<String, Object?>('m.relates_to')
?.tryGet<String>('key'),
)
.whereType<String>(),
);
}
return LemmaEmojiPicker(
emojis: emojis,
onSelect: event?.room.timeline != null ? setEmoji : null,
disabled: (emoji) => sentReactions.contains(emoji),
loading: loading,
return LemmaEmojiPicker(
emojis: controller.lemmaInfo?.emoji ?? [],
onSelect: event?.room.timeline != null
? (emoji) => setEmoji(
emoji,
controller.lemmaInfo?.emoji ?? [],
)
: null,
disabled: (emoji) => sentReactions.contains(emoji),
loading: controller.isLoading,
);
},
);
}
}

View file

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:matrix/matrix_api_lite/model/message_types.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
import 'package:fluffychat/pangea/token_info_feedback/token_info_feedback_request.dart';
import 'package:fluffychat/pangea/toolbar/message_selection_overlay.dart';
import 'package:fluffychat/pangea/toolbar/word_card/word_zoom_widget.dart';
@ -50,7 +51,7 @@ class ReadingAssistanceContent extends StatelessWidget {
onClose: () => overlayController.updateSelectedSpan(null),
langCode: overlayController.pangeaMessageEvent.messageDisplayLangCode,
onDismissNewWordOverlay: () => overlayController.setState(() {}),
onFlagTokenInfo: () {
onFlagTokenInfo: (LemmaInfoResponse lemmaInfo, String phonetics) {
if (selectedTokenIndex < 0) return;
final requestData = TokenInfoFeedbackRequestData(
userId: Matrix.of(context).client.userID!,
@ -61,6 +62,8 @@ class ReadingAssistanceContent extends StatelessWidget {
tokens: tokens ?? [],
selectedToken: selectedTokenIndex,
wordCardL1: MatrixState.pangeaController.userController.userL1Code!,
lemmaInfo: lemmaInfo,
phonetics: phonetics,
);
overlayController.widget.chatController.showTokenFeedbackDialog(
requestData,

View file

@ -0,0 +1,62 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
import 'package:fluffychat/pangea/languages/language_model.dart';
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
import 'package:fluffychat/pangea/lemmas/lemma_meaning_builder.dart';
import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_builder.dart';
class TokenFeedbackButton extends StatelessWidget {
final LanguageModel textLanguage;
final ConstructIdentifier constructId;
final String text;
final Function(LemmaInfoResponse, String) onFlagTokenInfo;
const TokenFeedbackButton({
super.key,
required this.textLanguage,
required this.constructId,
required this.text,
required this.onFlagTokenInfo,
});
@override
Widget build(BuildContext context) {
return LemmaMeaningBuilder(
langCode: textLanguage.langCode,
constructId: constructId,
builder: (context, lemmaController) {
return PhoneticTranscriptionBuilder(
textLanguage: textLanguage,
text: text,
builder: (context, transcriptController) {
final enabled = (lemmaController.lemmaInfo != null ||
lemmaController.isError) &&
(transcriptController.transcription != null ||
transcriptController.isError);
final lemmaInfo =
lemmaController.lemmaInfo ?? LemmaInfoResponse.error;
final transcript = transcriptController.transcription ?? 'ERROR';
return IconButton(
icon: const Icon(Icons.flag_outlined),
onPressed: enabled
? () {
onFlagTokenInfo(
lemmaInfo,
transcript,
);
}
: null,
tooltip: enabled ? L10n.of(context).reportWordIssueTooltip : null,
);
},
);
},
);
}
}

View file

@ -3,18 +3,18 @@ import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/common/widgets/error_indicator.dart';
import 'package:fluffychat/pangea/common/widgets/word_audio_button.dart';
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_text_model.dart';
import 'package:fluffychat/pangea/languages/language_model.dart';
import 'package:fluffychat/pangea/languages/p_language_store.dart';
import 'package:fluffychat/pangea/lemmas/lemma_meaning_builder.dart';
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_widget.dart';
import 'package:fluffychat/pangea/toolbar/reading_assistance/new_word_overlay.dart';
import 'package:fluffychat/pangea/toolbar/word_card/lemma_meaning_display.dart';
import 'package:fluffychat/pangea/toolbar/word_card/lemma_reaction_picker.dart';
import 'package:fluffychat/pangea/toolbar/word_card/message_unsubscribed_card.dart';
import 'package:fluffychat/pangea/toolbar/word_card/token_feedback_button.dart';
import 'package:fluffychat/widgets/matrix.dart';
class WordZoomWidget extends StatelessWidget {
@ -28,10 +28,7 @@ class WordZoomWidget extends StatelessWidget {
final Event? event;
final VoidCallback? onDismissNewWordOverlay;
final VoidCallback? onFlagTokenInfo;
// final TokenInfoFeedbackRequestData? requestData;
// final PangeaMessageEvent? pangeaMessageEvent;
final Function(LemmaInfoResponse, String)? onFlagTokenInfo;
const WordZoomWidget({
super.key,
@ -55,6 +52,8 @@ class WordZoomWidget extends StatelessWidget {
final bool? subscribed =
MatrixState.pangeaController.subscriptionController.isSubscribed;
final overlayColor = Theme.of(context).scaffoldBackgroundColor;
final showTranscript =
MatrixState.pangeaController.userController.showTranscription;
final Widget content = subscribed != null && !subscribed
? const MessageUnsubscribedCard()
@ -106,11 +105,14 @@ class WordZoomWidget extends StatelessWidget {
),
),
onFlagTokenInfo != null
? IconButton(
icon: const Icon(Icons.flag_outlined),
onPressed: onFlagTokenInfo,
tooltip:
L10n.of(context).reportWordIssueTooltip,
? TokenFeedbackButton(
textLanguage: PLanguageStore.byLangCode(
langCode,
) ??
LanguageModel.unknown,
constructId: construct,
text: token.content,
onFlagTokenInfo: onFlagTokenInfo!,
)
: const SizedBox(
width: 40.0,
@ -118,17 +120,12 @@ class WordZoomWidget extends StatelessWidget {
),
],
),
LemmaMeaningBuilder(
langCode: langCode,
constructId: construct,
builder: (context, controller) {
return Column(
spacing: 12.0,
mainAxisSize: MainAxisSize.min,
children: [
if (MatrixState.pangeaController.userController
.showTranscription)
PhoneticTranscriptionWidget(
Column(
spacing: 12.0,
mainAxisSize: MainAxisSize.min,
children: [
showTranscript
? PhoneticTranscriptionWidget(
text: token.content,
textLanguage: PLanguageStore.byLangCode(
langCode,
@ -137,62 +134,23 @@ class WordZoomWidget extends StatelessWidget {
style: const TextStyle(fontSize: 14.0),
iconSize: 24.0,
)
else
WordAudioButton(
: WordAudioButton(
text: token.content,
uniqueID: "lemma-content-${token.content}",
langCode: langCode,
iconSize: 24.0,
),
LemmaReactionPicker(
emojis: controller.lemmaInfo?.emoji ?? [],
loading: controller.isLoading,
event: event,
),
if (controller.error != null)
ErrorIndicator(
message: L10n.of(context)
.errorFetchingDefinition,
style: const TextStyle(fontSize: 14.0),
)
else if (controller.isLoading ||
controller.lemmaInfo == null)
const CircularProgressIndicator.adaptive()
else
construct.lemma.toLowerCase() ==
token.content.toLowerCase()
? Text(
controller.lemmaInfo!.meaning,
style:
const TextStyle(fontSize: 14.0),
textAlign: TextAlign.center,
)
: RichText(
text: TextSpan(
style: DefaultTextStyle.of(context)
.style
.copyWith(
fontSize: 14.0,
),
children: [
TextSpan(text: construct.lemma),
const WidgetSpan(
child: SizedBox(width: 8.0),
),
const TextSpan(text: ":"),
const WidgetSpan(
child: SizedBox(width: 8.0),
),
TextSpan(
text: controller
.lemmaInfo!.meaning,
),
],
),
),
],
);
},
LemmaReactionPicker(
construct: construct,
langCode: langCode,
event: event,
),
LemmaMeaningDisplay(
langCode: langCode,
constructId: construct,
text: token.content,
),
],
),
],
),