diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index 1f14ff87f..55123234c 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -78,6 +78,10 @@ abstract class AppConfig { static const Color silver = Color.fromARGB(255, 192, 192, 192); static const Color bronze = Color.fromARGB(255, 205, 127, 50); static const Color goldLight = Color.fromARGB(255, 254, 223, 73); + + static const Color yellowLight = Color.fromARGB(255, 247, 218, 120); + static const Color yellowDark = Color.fromARGB(255, 253, 191, 1); + static const Color error = Colors.red; static const int overlayAnimationDuration = 250; static const int roomCreationTimeoutSeconds = 15; 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 de1c909b3..5dd9ea0c5 100644 --- a/lib/pangea/analytics_details_popup/vocab_analytics_details_view.dart +++ b/lib/pangea/analytics_details_popup/vocab_analytics_details_view.dart @@ -132,8 +132,6 @@ class VocabDetailsView extends StatelessWidget { : LemmaMeaningWidget( constructUse: _construct, langCode: _userL2!, - controller: null, - token: null, style: Theme.of(context).textTheme.bodyLarge, leading: TextSpan( text: L10n.of(context).meaningSectionHeader, diff --git a/lib/pangea/toolbar/widgets/practice_activity/word_audio_button.dart b/lib/pangea/toolbar/widgets/practice_activity/word_audio_button.dart index 4ee0383d2..cac792e8c 100644 --- a/lib/pangea/toolbar/widgets/practice_activity/word_audio_button.dart +++ b/lib/pangea/toolbar/widgets/practice_activity/word_audio_button.dart @@ -13,6 +13,7 @@ class WordAudioButton extends StatefulWidget { final String uniqueID; final String langCode; final EdgeInsets? padding; + final double? iconSize; /// If defined, this callback will be called instead of the default one final void Function()? callbackOverride; @@ -26,6 +27,7 @@ class WordAudioButton extends StatefulWidget { this.baseOpacity = 1, this.callbackOverride, this.padding, + this.iconSize, }); @override @@ -118,6 +120,7 @@ class WordAudioButtonState extends State { color: _isPlaying ? Theme.of(context).colorScheme.primary : null, + size: widget.iconSize, ), ), ), diff --git a/lib/pangea/toolbar/widgets/word_zoom/lemma_meaning_builder.dart b/lib/pangea/toolbar/widgets/word_zoom/lemma_meaning_builder.dart new file mode 100644 index 000000000..7e2be07f9 --- /dev/null +++ b/lib/pangea/toolbar/widgets/word_zoom/lemma_meaning_builder.dart @@ -0,0 +1,107 @@ +import 'package:flutter/material.dart'; + +import 'package:fluffychat/pangea/constructs/construct_identifier.dart'; +import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart'; +import 'package:fluffychat/pangea/lemmas/lemma_info_repo.dart'; +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 LemmaMeaningBuilder extends StatefulWidget { + final String langCode; + final ConstructIdentifier constructId; + final Widget Function( + BuildContext context, + LemmaMeaningBuilderState controller, + ) builder; + + const LemmaMeaningBuilder({ + super.key, + required this.langCode, + required this.constructId, + required this.builder, + }); + + @override + LemmaMeaningBuilderState createState() => LemmaMeaningBuilderState(); +} + +class LemmaMeaningBuilderState extends State { + bool editMode = false; + LemmaInfoResponse? lemmaInfo; + bool isLoading = true; + String? error; + + TextEditingController controller = TextEditingController(); + + @override + void initState() { + super.initState(); + _fetchLemmaMeaning(); + } + + @override + void didUpdateWidget(covariant LemmaMeaningBuilder oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.constructId != widget.constructId || + oldWidget.langCode != widget.langCode) { + _fetchLemmaMeaning(); + } + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + LemmaInfoRequest get _request => LemmaInfoRequest( + lemma: widget.constructId.lemma, + partOfSpeech: widget.constructId.category, + lemmaLang: widget.langCode, + userL1: + MatrixState.pangeaController.languageController.userL1?.langCode ?? + LanguageKeys.defaultLanguage, + ); + + Future _fetchLemmaMeaning() async { + setState(() { + isLoading = true; + error = null; + }); + + try { + final resp = await LemmaInfoRepo.get(_request); + lemmaInfo = resp; + controller.text = resp.meaning; + } catch (e) { + error = e.toString(); + } finally { + if (mounted) setState(() => isLoading = false); + } + } + + void toggleEditMode(bool value) => setState(() => editMode = value); + + Future editLemmaMeaning(String userEdit) async { + final originalMeaning = lemmaInfo; + + if (originalMeaning != null) { + LemmaInfoRepo.set( + _request, + LemmaInfoResponse(emoji: originalMeaning.emoji, meaning: userEdit), + ); + + toggleEditMode(false); + _fetchLemmaMeaning(); + } + } + + @override + Widget build(BuildContext context) { + return widget.builder( + context, + this, + ); + } +} diff --git a/lib/pangea/toolbar/widgets/word_zoom/lemma_meaning_widget.dart b/lib/pangea/toolbar/widgets/word_zoom/lemma_meaning_widget.dart index 623b74841..3b27b599a 100644 --- a/lib/pangea/toolbar/widgets/word_zoom/lemma_meaning_widget.dart +++ b/lib/pangea/toolbar/widgets/word_zoom/lemma_meaning_widget.dart @@ -3,250 +3,138 @@ import 'dart:developer'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:material_symbols_icons/symbols.dart'; - import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart'; import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart'; -import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; -import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart'; -import 'package:fluffychat/pangea/lemmas/lemma_info_repo.dart'; -import 'package:fluffychat/pangea/lemmas/lemma_info_request.dart'; -import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart'; -import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart'; -import 'package:fluffychat/pangea/toolbar/enums/message_mode_enum.dart'; -import 'package:fluffychat/pangea/toolbar/enums/reading_assistance_mode_enum.dart'; -import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart'; -import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/word_zoom_activity_button.dart'; -import 'package:fluffychat/widgets/matrix.dart'; +import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/lemma_meaning_builder.dart'; -class LemmaMeaningWidget extends StatefulWidget { +class LemmaMeaningWidget extends StatelessWidget { final ConstructUses constructUse; final String langCode; final TextStyle? style; final InlineSpan? leading; - /// These are not present if this widget is used outside the chat - /// (e.g. in the vocab details view) - /// TODO: let the user assign the meaning in the vocab details view - final MessageOverlayController? controller; - final PangeaToken? token; - const LemmaMeaningWidget({ super.key, required this.constructUse, required this.langCode, - required this.controller, - required this.token, this.style, this.leading, }); - @override - LemmaMeaningWidgetState createState() => LemmaMeaningWidgetState(); -} - -class LemmaMeaningWidgetState extends State { - bool _editMode = false; - late TextEditingController _controller; - LemmaInfoResponse? _lemmaInfo; - bool _isLoading = true; - String? _error; - - String get _lemma => widget.constructUse.lemma; - - @override - void initState() { - super.initState(); - _controller = TextEditingController(); - _fetchLemmaMeaning(); - } - - @override - void didUpdateWidget(covariant LemmaMeaningWidget oldWidget) { - super.didUpdateWidget(oldWidget); - if (oldWidget.constructUse != widget.constructUse || - oldWidget.langCode != widget.langCode) { - _fetchLemmaMeaning(); - } - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - LemmaInfoRequest get _request => LemmaInfoRequest( - lemma: _lemma, - partOfSpeech: widget.constructUse.category, - - /// This assumes that the user's L2 is the language of the lemma - lemmaLang: widget.langCode, - userL1: - MatrixState.pangeaController.languageController.userL1?.langCode ?? - LanguageKeys.defaultLanguage, - ); - - Future _fetchLemmaMeaning() async { - setState(() { - _isLoading = true; - _error = null; - }); - try { - _lemmaInfo = await LemmaInfoRepo.get(_request); - } catch (e) { - _error = e.toString(); - } finally { - if (mounted) setState(() => _isLoading = false); - } - } - - void _toggleEditMode(bool value) => setState(() => _editMode = value); - - Future editLemmaMeaning(String userEdit) async { - final originalMeaning = _lemmaInfo; - - if (originalMeaning != null) { - LemmaInfoRepo.set( - _request, - LemmaInfoResponse(emoji: originalMeaning.emoji, meaning: userEdit), - ); - - _toggleEditMode(false); - _fetchLemmaMeaning(); - } - } - @override Widget build(BuildContext context) { - if (widget.token != null && - widget.controller?.practiceSelection != null && - widget.controller!.practiceSelection!.hasActiveActivityByToken( - ActivityTypeEnum.wordMeaning, - widget.token!, - ) && - widget.controller!.readingAssistanceMode == - ReadingAssistanceMode.practiceMode) { - return WordZoomActivityButton( - icon: const Icon(Symbols.dictionary), - isSelected: widget.controller?.toolbarMode == MessageMode.wordMeaning, - onPressed: widget.controller != null - ? () { - // TODO: it would be better to explicitly set to wordMeaningChoice here - widget.controller!.updateToolbarMode(MessageMode.wordMeaning); - } - : () => {}, - opacity: - widget.controller?.toolbarMode == MessageMode.wordMeaning ? 1 : 0.4, - ); - } + return LemmaMeaningBuilder( + langCode: langCode, + constructId: constructUse.id, + builder: (context, controller) { + if (controller.isLoading) { + return const TextLoadingShimmer(); + } - if (_isLoading) { - return const TextLoadingShimmer(); - } + if (controller.error != null) { + debugger(when: kDebugMode); + return Text( + L10n.of(context).oopsSomethingWentWrong, + textAlign: TextAlign.center, + ); + } - if (_error != null) { - debugger(when: kDebugMode); - return Text( - L10n.of(context).oopsSomethingWentWrong, - textAlign: TextAlign.center, - ); - } - - if (_editMode) { - _controller.text = _lemmaInfo?.meaning ?? ""; - return Material( - type: MaterialType.transparency, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "${L10n.of(context).pangeaBotIsFallible} ${L10n.of(context).whatIsMeaning(_lemma, widget.constructUse.category)}", - textAlign: TextAlign.center, - style: const TextStyle(fontStyle: FontStyle.italic), - ), - const SizedBox(height: 10), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: TextField( - minLines: 1, - maxLines: 3, - controller: _controller, - decoration: InputDecoration( - hintText: _lemmaInfo?.meaning, - ), - ), - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.center, + if (controller.editMode) { + controller.controller.text = controller.lemmaInfo?.meaning ?? ""; + return Material( + type: MaterialType.transparency, + child: Column( + mainAxisSize: MainAxisSize.min, children: [ - ElevatedButton( - onPressed: () => _toggleEditMode(false), - style: ElevatedButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - ), - child: Text(L10n.of(context).cancel), + Text( + "${L10n.of(context).pangeaBotIsFallible} ${L10n.of(context).whatIsMeaning( + constructUse.lemma, + constructUse.category, + )}", + textAlign: TextAlign.center, + style: const TextStyle(fontStyle: FontStyle.italic), ), - const SizedBox(width: 10), - ElevatedButton( - onPressed: () => _controller.text != _lemmaInfo?.meaning && - _controller.text.isNotEmpty - ? editLemmaMeaning(_controller.text) - : null, - style: ElevatedButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), + const SizedBox(height: 10), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: TextField( + minLines: 1, + maxLines: 3, + controller: controller.controller, + decoration: InputDecoration( + hintText: controller.lemmaInfo?.meaning, ), - padding: const EdgeInsets.symmetric(horizontal: 10), ), - child: Text(L10n.of(context).saveChanges), ), - ], - ), - ], - ), - ); - } - - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Flexible( - child: Tooltip( - triggerMode: TooltipTriggerMode.tap, - message: L10n.of(context).doubleClickToEdit, - child: GestureDetector( - onLongPress: () => _toggleEditMode(true), - onDoubleTap: () => _toggleEditMode(true), - child: RichText( - textAlign: - widget.leading == null ? TextAlign.center : TextAlign.start, - text: TextSpan( - style: widget.style?.copyWith( - color: widget.controller?.toolbarMode == - MessageMode.wordMeaning - ? Theme.of(context).colorScheme.primary - : null, - ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.center, children: [ - if (widget.leading != null) widget.leading!, - if (widget.leading != null) - const WidgetSpan(child: SizedBox(width: 6.0)), - TextSpan( - text: _lemmaInfo?.meaning, + ElevatedButton( + onPressed: () => controller.toggleEditMode(false), + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + padding: const EdgeInsets.symmetric(horizontal: 10), + ), + child: Text(L10n.of(context).cancel), + ), + const SizedBox(width: 10), + ElevatedButton( + onPressed: () => controller.controller.text != + controller.lemmaInfo?.meaning && + controller.controller.text.isNotEmpty + ? controller + .editLemmaMeaning(controller.controller.text) + : null, + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + padding: const EdgeInsets.symmetric(horizontal: 10), + ), + child: Text(L10n.of(context).saveChanges), ), ], ), + ], + ), + ); + } + + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: Tooltip( + triggerMode: TooltipTriggerMode.tap, + message: L10n.of(context).doubleClickToEdit, + child: GestureDetector( + onLongPress: () => controller.toggleEditMode(true), + onDoubleTap: () => controller.toggleEditMode(true), + 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/toolbar/widgets/word_zoom/lemma_widget.dart b/lib/pangea/toolbar/widgets/word_zoom/lemma_widget.dart deleted file mode 100644 index 80a8f4083..000000000 --- a/lib/pangea/toolbar/widgets/word_zoom/lemma_widget.dart +++ /dev/null @@ -1,191 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:fluffychat/l10n/l10n.dart'; -import 'package:fluffychat/pangea/common/constants/model_keys.dart'; -import 'package:fluffychat/pangea/common/utils/error_handler.dart'; -import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart'; -import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; -import 'package:fluffychat/pangea/events/models/tokens_event_content_model.dart'; -import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; -import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart'; -import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/word_audio_button.dart'; -import 'package:fluffychat/widgets/future_loading_dialog.dart'; - -class LemmaWidget extends StatefulWidget { - final PangeaToken token; - final PangeaMessageEvent pangeaMessageEvent; - final VoidCallback onEdit; - final VoidCallback onEditDone; - final MessageOverlayController? overlayController; - - const LemmaWidget({ - super.key, - required this.token, - required this.pangeaMessageEvent, - required this.onEdit, - required this.onEditDone, - required this.overlayController, - }); - - @override - LemmaWidgetState createState() => LemmaWidgetState(); -} - -class LemmaWidgetState extends State { - bool _editMode = false; - late TextEditingController _controller; - - @override - void initState() { - super.initState(); - _controller = TextEditingController(); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - void _toggleEditMode(bool value) { - value ? widget.onEdit() : widget.onEditDone(); - setState(() => _editMode = value); - } - - Future _editLemma() async { - try { - final existingTokens = widget.pangeaMessageEvent.originalSent!.tokens! - .map((token) => PangeaToken.fromJson(token.toJson())) - .toList(); - - // change the morphological tag in the selected token - final tokenIndex = existingTokens.indexWhere( - (token) => token.text.offset == widget.token.text.offset, - ); - - if (tokenIndex == -1) { - throw Exception("Token not found in message"); - } - - existingTokens[tokenIndex].lemma.text = _controller.text; - await widget.pangeaMessageEvent.room.pangeaSendTextEvent( - widget.pangeaMessageEvent.messageDisplayText, - editEventId: widget.pangeaMessageEvent.eventId, - originalSent: widget.pangeaMessageEvent.originalSent?.content, - originalWritten: widget.pangeaMessageEvent.originalWritten?.content, - tokensSent: PangeaMessageTokens( - tokens: existingTokens, - detections: widget.pangeaMessageEvent.originalSent!.detections, - ), - tokensWritten: widget.pangeaMessageEvent.originalWritten?.tokens != null - ? PangeaMessageTokens( - tokens: widget.pangeaMessageEvent.originalWritten!.tokens!, - detections: - widget.pangeaMessageEvent.originalWritten?.detections, - ) - : null, - choreo: widget.pangeaMessageEvent.originalSent?.choreo, - messageTag: ModelKey.messageTagLemmaEdit, - ); - - _toggleEditMode(false); - } catch (e) { - SnackBar( - content: Text(L10n.of(context).oopsSomethingWentWrong), - ); - ErrorHandler.logError( - e: e, - data: { - "token": widget.token.toJson(), - "pangeaMessageEvent": widget.pangeaMessageEvent.event.content, - }, - ); - } - } - - @override - Widget build(BuildContext context) { - if (_editMode) { - _controller.text = widget.token.lemma.text; - return Material( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - spacing: 10.0, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "${L10n.of(context).pangeaBotIsFallible} ${L10n.of(context).whatIsLemma}", - textAlign: TextAlign.center, - style: const TextStyle(fontStyle: FontStyle.italic), - ), - TextField( - minLines: 1, - maxLines: 3, - controller: _controller, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - onPressed: () => _toggleEditMode(false), - style: ElevatedButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - ), - child: Text(L10n.of(context).cancel), - ), - const SizedBox(width: 10), - ElevatedButton( - onPressed: () { - _controller.text != widget.token.lemma.text - ? showFutureLoadingDialog( - context: context, - future: () async => _editLemma(), - ) - : null; - }, - style: ElevatedButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - ), - child: Text(L10n.of(context).saveChanges), - ), - ], - ), - ], - ), - ), - ); - } - - return Expanded( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Flexible( - child: Padding( - padding: const EdgeInsets.all(4.0), - child: Text( - widget.token.lemma.text, - style: Theme.of(context).textTheme.headlineSmall, - textAlign: TextAlign.center, - ), - ), - ), - WordAudioButton( - text: widget.token.lemma.text, - baseOpacity: 0.4, - uniqueID: "lemma-content-${widget.token.text.content}", - langCode: widget.pangeaMessageEvent.messageDisplayLangCode, - padding: const EdgeInsets.all(4.0), - ), - ], - ), - ); - } -} diff --git a/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart b/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart index 02e4f38f3..a3e9481cb 100644 --- a/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart +++ b/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart @@ -1,17 +1,20 @@ import 'package:flutter/material.dart'; import 'package:fluffychat/config/app_config.dart'; +import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart'; import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart'; import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart'; import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; -import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart'; +import 'package:fluffychat/pangea/learning_settings/models/language_model.dart'; +import 'package:fluffychat/pangea/learning_settings/utils/p_language_store.dart'; import 'package:fluffychat/pangea/lemmas/construct_xp_widget.dart'; import 'package:fluffychat/pangea/lemmas/lemma_reaction_picker.dart'; +import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_widget.dart'; import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart'; import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart'; -import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/lemma_meaning_widget.dart'; -import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/lemma_widget.dart'; +import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/word_audio_button.dart'; +import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/lemma_meaning_builder.dart'; import 'package:fluffychat/widgets/matrix.dart'; class WordZoomWidget extends StatelessWidget { @@ -28,8 +31,6 @@ class WordZoomWidget extends StatelessWidget { PangeaToken get _selectedToken => overlayController.selectedToken!; - void _onEditDone() => overlayController.initializeTokensAndMode(); - bool get hasEmojiActivity => overlayController.practiceSelection?.hasActiveActivityByToken( ActivityTypeEnum.emoji, @@ -40,159 +41,199 @@ class WordZoomWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return ConstrainedBox( + return Container( + padding: const EdgeInsets.all(12.0), constraints: const BoxConstraints( - minHeight: AppConfig.toolbarMinHeight, - maxHeight: AppConfig.toolbarMaxHeight, + minHeight: AppConfig.toolbarMinHeight - 8, + maxHeight: AppConfig.toolbarMaxHeight - 8, maxWidth: AppConfig.toolbarMinWidth, ), child: SingleChildScrollView( - padding: const EdgeInsets.all(8.0), child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + spacing: 12.0, mainAxisSize: MainAxisSize.min, children: [ - Container( - constraints: const BoxConstraints( - minHeight: 40, - ), - color: Theme.of(context).colorScheme.surface, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - //@ggurdin - might need to play with size to properly center - SizedBox( - width: 24.0, - height: 24.0, - child: IconButton( - onPressed: () => overlayController.updateSelectedSpan( + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: 24.0, + height: 24.0, + child: MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () => overlayController.updateSelectedSpan( token.text, ), - icon: const Icon(Icons.close), - style: IconButton.styleFrom( - padding: EdgeInsets.zero, + child: const Icon( + Icons.close, + size: 16.0, ), ), ), - LemmaWidget( - token: _selectedToken, - pangeaMessageEvent: messageEvent, - // onEdit: () => _setHideCenterContent(true), - onEdit: () { - debugPrint("what are we doing edits with?"); - }, - onEditDone: () { - debugPrint("what are we doing edits with?"); - _onEditDone(); - }, - overlayController: overlayController, + ), + Text( + token.text.content, + style: TextStyle( + fontSize: 32.0, + fontWeight: FontWeight.w600, + height: 1.2, + color: Theme.of(context).brightness == Brightness.light + ? AppConfig.yellowDark + : AppConfig.yellowLight, ), - ConstructXpWidget( - id: token.vocabConstructID, - onTap: () => showDialog( - context: context, - builder: (context) => AnalyticsPopupWrapper( - constructZoom: token.vocabConstructID, - view: ConstructTypeEnum.vocab, - ), + ), + ConstructXpWidget( + id: token.vocabConstructID, + onTap: () => showDialog( + context: context, + builder: (context) => AnalyticsPopupWrapper( + constructZoom: token.vocabConstructID, + view: ConstructTypeEnum.vocab, ), ), - ], - ), + ), + ], ), - const SizedBox( - height: 8.0, + LemmaMeaningBuilder( + langCode: messageEvent.messageDisplayLangCode, + constructId: token.vocabConstructID, + builder: (context, controller) { + if (controller.editMode) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "${L10n.of(context).pangeaBotIsFallible} ${L10n.of(context).whatIsMeaning( + token.vocabConstructID.lemma, + token.vocabConstructID.category, + )}", + textAlign: TextAlign.center, + style: const TextStyle(fontStyle: FontStyle.italic), + ), + const SizedBox(height: 10), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: TextField( + minLines: 1, + maxLines: 3, + controller: controller.controller, + decoration: InputDecoration( + hintText: controller.lemmaInfo?.meaning, + ), + ), + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + onPressed: () => controller.toggleEditMode(false), + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + padding: + const EdgeInsets.symmetric(horizontal: 10), + ), + child: Text(L10n.of(context).cancel), + ), + const SizedBox(width: 10), + ElevatedButton( + onPressed: () => controller.controller.text != + controller.lemmaInfo?.meaning && + controller.controller.text.isNotEmpty + ? controller.editLemmaMeaning( + controller.controller.text, + ) + : null, + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + padding: + const EdgeInsets.symmetric(horizontal: 10), + ), + child: Text(L10n.of(context).saveChanges), + ), + ], + ), + ], + ); + } + + return Column( + spacing: 12.0, + mainAxisSize: MainAxisSize.min, + children: [ + if (MatrixState + .pangeaController.languageController.showTrancription) + PhoneticTranscriptionWidget( + text: token.text.content, + textLanguage: PLanguageStore.byLangCode( + messageEvent.messageDisplayLangCode, + ) ?? + LanguageModel.unknown, + style: const TextStyle(fontSize: 14.0), + iconSize: 24.0, + ) + else + WordAudioButton( + text: token.text.content, + uniqueID: "lemma-content-${token.text.content}", + langCode: messageEvent.messageDisplayLangCode, + iconSize: 24.0, + ), + LemmaReactionPicker( + cId: _selectedToken.vocabConstructID, + controller: overlayController.widget.chatController, + ), + if (controller.error != null) + Text( + L10n.of(context).oopsSomethingWentWrong, + textAlign: TextAlign.center, + ) + else if (controller.isLoading || + controller.lemmaInfo == null) + const CircularProgressIndicator.adaptive() + else + GestureDetector( + onLongPress: () => controller.toggleEditMode(true), + onDoubleTap: () => controller.toggleEditMode(true), + child: token.lemma.text == token.text.content + ? 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: token.lemma.text), + const WidgetSpan( + child: SizedBox(width: 8.0), + ), + const TextSpan(text: ":"), + const WidgetSpan( + child: SizedBox(width: 8.0), + ), + TextSpan( + text: controller.lemmaInfo!.meaning, + ), + ], + ), + ), + ), + ], + ); + }, ), - LemmaReactionPicker( - cId: _selectedToken.vocabConstructID, - controller: overlayController.widget.chatController, - ), - // Row( - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // Container( - // constraints: const BoxConstraints( - // minHeight: 40, - // ), - // alignment: Alignment.center, - // child: LemmaEmojiRow( - // cId: _selectedToken.vocabConstructID, - // onTapOverride: overlayController.hideWordCardContent && - // hasEmojiActivity - // ? () => overlayController.updateToolbarMode( - // MessageMode.wordEmoji, - // ) - // : null, - // isSelected: - // overlayController.toolbarMode == MessageMode.wordEmoji, - // emojiSetCallback: () => overlayController.setState(() {}), - // shouldShowEmojis: !hasEmojiActivity, - // ), - // ), - // ], - // ), - const SizedBox( - height: 8.0, - ), - Container( - constraints: const BoxConstraints( - minHeight: 40, - ), - alignment: Alignment.center, - child: Wrap( - alignment: WrapAlignment.center, - runAlignment: WrapAlignment.center, - crossAxisAlignment: WrapCrossAlignment.center, - spacing: 8, - children: [ - LemmaMeaningWidget( - constructUse: token.vocabConstructID.constructUses, - langCode: MatrixState.pangeaController.languageController - .userL2?.langCodeShort ?? - LanguageKeys.defaultLanguage, - token: overlayController.selectedToken!, - controller: overlayController, - style: Theme.of(context).textTheme.bodyLarge, - ), - ], - ), - ), - // const SizedBox( - // height: 8.0, - // ), - // Wrap( - // alignment: WrapAlignment.center, - // crossAxisAlignment: WrapCrossAlignment.center, - // spacing: 8.0, - // children: [ - // if (token.text.content.toLowerCase() != - // token.lemma.text.toLowerCase()) ...[ - // Text( - // _selectedToken.text.content, - // style: Theme.of(context).textTheme.bodyLarge, - // overflow: TextOverflow.ellipsis, - // ), - // WordAudioButton( - // text: _selectedToken.text.content, - // baseOpacity: 0.4, - // uniqueID: "word-zoom-audio-${_selectedToken.text.content}", - // langCode: overlayController - // .pangeaMessageEvent!.messageDisplayLangCode, - // ), - // ], - // ..._selectedToken.morphsBasicallyEligibleForPracticeByPriority - // .map( - // (cId) => MorphologicalListItem( - // morphFeature: MorphFeaturesEnumExtension.fromString( - // cId.category, - // ), - // token: _selectedToken, - // overlayController: overlayController, - // ), - // ), - // ], - // ), ], ), ),