From 8df77c6ed762de2586551d516b7c810d1ef466ce Mon Sep 17 00:00:00 2001 From: ggurdin Date: Tue, 5 Nov 2024 16:10:43 -0500 Subject: [PATCH] in message toolbar, use the display representation instead of originalSent so that immersion mode still works --- .../pangea_message_event.dart | 8 ++-- .../widgets/chat/message_audio_card.dart | 19 ++-------- .../chat/message_selection_overlay.dart | 8 +++- lib/pangea/widgets/chat/message_toolbar.dart | 37 ++++++++++++++++--- .../widgets/chat/overlay_message_text.dart | 26 +++++++------ lib/pangea/widgets/igc/pangea_rich_text.dart | 7 +--- .../practice_activity_card.dart | 25 ++++++------- .../target_tokens_controller.dart | 11 +++--- 8 files changed, 77 insertions(+), 64 deletions(-) diff --git a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart index 74d4483dc..0a21003f5 100644 --- a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart +++ b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart @@ -564,13 +564,13 @@ class PangeaMessageEvent { return langCode ?? LanguageKeys.unknownLanguage; } + RepresentationEvent? get messageDisplayRepresentation => + representationByLanguage(messageDisplayLangCode); + /// Gets the message display text for the current language code. /// If the message display text is not available for the current language code, /// it returns the message body. - String get messageDisplayText { - final String? text = representationByLanguage(messageDisplayLangCode)?.text; - return text ?? body; - } + String get messageDisplayText => messageDisplayRepresentation?.text ?? body; List? errorSteps(String lemma) { final RepresentationEvent? repEvent = originalSent ?? originalWritten; diff --git a/lib/pangea/widgets/chat/message_audio_card.dart b/lib/pangea/widgets/chat/message_audio_card.dart index cc41605c9..5b6f9b539 100644 --- a/lib/pangea/widgets/chat/message_audio_card.dart +++ b/lib/pangea/widgets/chat/message_audio_card.dart @@ -14,7 +14,6 @@ import 'package:fluffychat/pangea/widgets/chat/tts_controller.dart'; import 'package:fluffychat/pangea/widgets/igc/card_error_widget.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:matrix/matrix.dart'; class MessageAudioCard extends StatefulWidget { @@ -147,15 +146,10 @@ class MessageAudioCardState extends State { try { final String langCode = widget.messageEvent.messageDisplayLangCode; - final String? text = - widget.messageEvent.representationByLanguage(langCode)?.text; - - if (text == null) { - //TODO - handle error but get out of flow - } - - final Event? localEvent = - widget.messageEvent.getTextToSpeechLocal(langCode, text!); + final Event? localEvent = widget.messageEvent.getTextToSpeechLocal( + langCode, + widget.messageEvent.messageDisplayText, + ); if (localEvent != null) { audioFile = await localEvent.getPangeaAudioFile(); @@ -172,11 +166,6 @@ class MessageAudioCardState extends State { debugPrint(StackTrace.current.toString()); if (!mounted) return; setState(() => _isLoading = false); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(L10n.of(context)!.errorGettingAudio), - ), - ); ErrorHandler.logError( e: e, s: s, diff --git a/lib/pangea/widgets/chat/message_selection_overlay.dart b/lib/pangea/widgets/chat/message_selection_overlay.dart index baa84ccc7..541eee747 100644 --- a/lib/pangea/widgets/chat/message_selection_overlay.dart +++ b/lib/pangea/widgets/chat/message_selection_overlay.dart @@ -18,6 +18,7 @@ import 'package:fluffychat/pangea/widgets/chat/overlay_footer.dart'; import 'package:fluffychat/pangea/widgets/chat/overlay_header.dart'; import 'package:fluffychat/pangea/widgets/chat/overlay_message.dart'; import 'package:fluffychat/pangea/widgets/chat/tts_controller.dart'; +import 'package:fluffychat/pangea/widgets/practice_activity/target_tokens_controller.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/foundation.dart'; @@ -74,6 +75,8 @@ class MessageOverlayController extends State bool isPlayingAudio = false; bool get showToolbarButtons => !widget._pangeaMessageEvent.isAudioMessage; + final TargetTokensController targetTokensController = + TargetTokensController(); @override void initState() { @@ -106,8 +109,8 @@ class MessageOverlayController extends State }, ).listen((_) => setState(() {})); - setInitialToolbarMode(); tts.setupTTS(); + setInitialToolbarMode(); } /// We need to check if the setState call is safe to call immediately @@ -487,7 +490,8 @@ class MessageOverlayController extends State MessageToolbar( pangeaMessageEvent: widget._pangeaMessageEvent, overLayController: this, - tts: tts, + ttsController: tts, + targetTokensController: targetTokensController, ), SizedBox( height: adjustedMessageHeight, diff --git a/lib/pangea/widgets/chat/message_toolbar.dart b/lib/pangea/widgets/chat/message_toolbar.dart index ffca4f32c..0c5c80dfa 100644 --- a/lib/pangea/widgets/chat/message_toolbar.dart +++ b/lib/pangea/widgets/chat/message_toolbar.dart @@ -10,10 +10,13 @@ import 'package:fluffychat/pangea/widgets/chat/message_selection_overlay.dart'; import 'package:fluffychat/pangea/widgets/chat/message_speech_to_text_card.dart'; import 'package:fluffychat/pangea/widgets/chat/message_translation_card.dart'; import 'package:fluffychat/pangea/widgets/chat/message_unsubscribed_card.dart'; +import 'package:fluffychat/pangea/widgets/chat/toolbar_content_loading_indicator.dart'; import 'package:fluffychat/pangea/widgets/chat/tts_controller.dart'; +import 'package:fluffychat/pangea/widgets/igc/card_error_widget.dart'; import 'package:fluffychat/pangea/widgets/igc/word_data_card.dart'; import 'package:fluffychat/pangea/widgets/message_display_card.dart'; import 'package:fluffychat/pangea/widgets/practice_activity/practice_activity_card.dart'; +import 'package:fluffychat/pangea/widgets/practice_activity/target_tokens_controller.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -24,13 +27,15 @@ const double minCardHeight = 70; class MessageToolbar extends StatelessWidget { final PangeaMessageEvent pangeaMessageEvent; final MessageOverlayController overLayController; - final TtsController tts; + final TtsController ttsController; + final TargetTokensController targetTokensController; const MessageToolbar({ super.key, required this.pangeaMessageEvent, required this.overLayController, - required this.tts, + required this.ttsController, + required this.targetTokensController, }); Widget toolbarContent(BuildContext context) { @@ -58,7 +63,7 @@ class MessageToolbar extends StatelessWidget { messageEvent: pangeaMessageEvent, overlayController: overLayController, selection: overLayController.selectedSpan, - tts: tts, + tts: ttsController, setIsPlayingAudio: overLayController.setIsPlayingAudio, ); case MessageMode.speechToText: @@ -67,8 +72,27 @@ class MessageToolbar extends StatelessWidget { ); case MessageMode.definition: if (!overLayController.isSelection) { - return MessageDisplayCard( - displayText: L10n.of(context)!.selectToDefine, + return FutureBuilder( + future: targetTokensController.targetTokens(pangeaMessageEvent), + builder: (context, snapshot) { + if (snapshot.connectionState != ConnectionState.done) { + return const ToolbarContentLoadingIndicator(); + } else if (snapshot.hasError || + snapshot.data == null || + snapshot.data!.isEmpty) { + return const Padding( + padding: EdgeInsets.all(8), + child: CardErrorWidget( + error: "No tokens available", + maxWidth: AppConfig.toolbarMinWidth, + ), + ); + } else { + return MessageDisplayCard( + displayText: L10n.of(context)!.selectToDefine, + ); + } + }, ); } else { try { @@ -106,7 +130,8 @@ class MessageToolbar extends StatelessWidget { return PracticeActivityCard( pangeaMessageEvent: pangeaMessageEvent, overlayController: overLayController, - tts: tts, + ttsController: ttsController, + targetTokensController: targetTokensController, ); default: debugger(when: kDebugMode); diff --git a/lib/pangea/widgets/chat/overlay_message_text.dart b/lib/pangea/widgets/chat/overlay_message_text.dart index f23cbba5c..79f5b8a91 100644 --- a/lib/pangea/widgets/chat/overlay_message_text.dart +++ b/lib/pangea/widgets/chat/overlay_message_text.dart @@ -29,17 +29,19 @@ class OverlayMessageTextState extends State { @override void initState() { - tokens = widget.pangeaMessageEvent.originalSent?.tokens; - if (widget.pangeaMessageEvent.originalSent != null && tokens == null) { - widget.pangeaMessageEvent.originalSent! - .tokensGlobal( - widget.pangeaMessageEvent.senderId, - widget.pangeaMessageEvent.originServerTs, - ) - .then((tokens) { - // this isn't currently working because originalSent's _event is null - setState(() => this.tokens = tokens); - }); + final repEvent = widget.pangeaMessageEvent.messageDisplayRepresentation; + if (repEvent != null) { + tokens = repEvent.tokens; + if (tokens == null) { + repEvent + .tokensGlobal( + widget.pangeaMessageEvent.senderId, + widget.pangeaMessageEvent.originServerTs, + ) + .then((tokens) { + setState(() => this.tokens = tokens); + }); + } } super.initState(); } @@ -70,7 +72,7 @@ class OverlayMessageTextState extends State { // Convert the entire message into a list of characters final Characters messageCharacters = - widget.pangeaMessageEvent.event.body.characters; + widget.pangeaMessageEvent.messageDisplayText.characters; // When building token positions, use grapheme cluster indices final List tokenPositions = []; diff --git a/lib/pangea/widgets/igc/pangea_rich_text.dart b/lib/pangea/widgets/igc/pangea_rich_text.dart index 9da9b45b6..8eecdd2f8 100644 --- a/lib/pangea/widgets/igc/pangea_rich_text.dart +++ b/lib/pangea/widgets/igc/pangea_rich_text.dart @@ -91,12 +91,7 @@ class PangeaRichTextState extends State { debugger(when: kDebugMode); } - repEvent = widget.pangeaMessageEvent - .representationByLanguage( - widget.pangeaMessageEvent.messageDisplayLangCode, - ) - ?.content; - + repEvent = widget.pangeaMessageEvent.messageDisplayRepresentation?.content; if (repEvent == null) { setState(() => _fetchingRepresentation = true); widget.pangeaMessageEvent diff --git a/lib/pangea/widgets/practice_activity/practice_activity_card.dart b/lib/pangea/widgets/practice_activity/practice_activity_card.dart index 00b11f658..6692bd1ce 100644 --- a/lib/pangea/widgets/practice_activity/practice_activity_card.dart +++ b/lib/pangea/widgets/practice_activity/practice_activity_card.dart @@ -31,13 +31,15 @@ import 'package:flutter_gen/gen_l10n/l10n.dart'; class PracticeActivityCard extends StatefulWidget { final PangeaMessageEvent pangeaMessageEvent; final MessageOverlayController overlayController; - final TtsController tts; + final TtsController ttsController; + final TargetTokensController targetTokensController; const PracticeActivityCard({ super.key, required this.pangeaMessageEvent, required this.overlayController, - required this.tts, + required this.ttsController, + required this.targetTokensController, }); @override @@ -51,10 +53,6 @@ class PracticeActivityCardState extends State { PracticeActivityRecordModel? currentCompletionRecord; bool fetchingActivity = false; - // tracks the target tokens for the current message - // in a separate controller to manage the state - TargetTokensController targetTokensController = TargetTokensController(); - List get practiceActivities => widget.pangeaMessageEvent.practiceActivities; @@ -124,7 +122,7 @@ class PracticeActivityCardState extends State { return null; } - if (widget.pangeaMessageEvent.originalSent == null) { + if (widget.pangeaMessageEvent.messageDisplayRepresentation == null) { debugger(when: kDebugMode); _updateFetchingActivity(false); ErrorHandler.logError( @@ -142,8 +140,8 @@ class PracticeActivityCardState extends State { MessageActivityRequest( userL1: pangeaController.languageController.userL1!.langCode, userL2: pangeaController.languageController.userL2!.langCode, - messageText: widget.pangeaMessageEvent.originalSent!.text, - tokensWithXP: await targetTokensController.targetTokens( + messageText: widget.pangeaMessageEvent.messageDisplayText, + tokensWithXP: await widget.targetTokensController.targetTokens( widget.pangeaMessageEvent, ), messageId: widget.pangeaMessageEvent.eventId, @@ -151,7 +149,8 @@ class PracticeActivityCardState extends State { .map((activity) => activity.activityRequestMetaData) .toList(), activityQualityFeedback: activityFeedback, - clientCompatibleActivities: widget.tts.isLanguageFullySupported + clientCompatibleActivities: widget + .ttsController.isLanguageFullySupported ? ActivityTypeEnum.values : ActivityTypeEnum.values .where((type) => type != ActivityTypeEnum.wordFocusListening) @@ -221,7 +220,7 @@ class PracticeActivityCardState extends State { // update the target tokens with the new construct uses // NOTE - multiple choice activity is handling adding these to analytics - await targetTokensController.updateTokensWithConstructs( + await widget.targetTokensController.updateTokensWithConstructs( currentCompletionRecord!.usesForAllResponses( currentActivity!, metadata, @@ -320,7 +319,7 @@ class PracticeActivityCardState extends State { return MultipleChoiceActivity( practiceCardController: this, currentActivity: currentActivity!, - tts: widget.tts, + tts: widget.ttsController, eventID: widget.pangeaMessageEvent.eventId, ); case ActivityTypeEnum.wordFocusListening: @@ -329,7 +328,7 @@ class PracticeActivityCardState extends State { return MultipleChoiceActivity( practiceCardController: this, currentActivity: currentActivity!, - tts: widget.tts, + tts: widget.ttsController, eventID: widget.pangeaMessageEvent.eventId, ); // default: diff --git a/lib/pangea/widgets/practice_activity/target_tokens_controller.dart b/lib/pangea/widgets/practice_activity/target_tokens_controller.dart index 69be7f6c2..f424d0d50 100644 --- a/lib/pangea/widgets/practice_activity/target_tokens_controller.dart +++ b/lib/pangea/widgets/practice_activity/target_tokens_controller.dart @@ -38,12 +38,11 @@ class TargetTokensController { Future> _initialize( PangeaMessageEvent pangeaMessageEvent, ) async { - final tokens = await pangeaMessageEvent - .representationByLanguage(pangeaMessageEvent.messageDisplayLangCode) - ?.tokensGlobal( - pangeaMessageEvent.senderId, - pangeaMessageEvent.originServerTs, - ); + final tokens = + await pangeaMessageEvent.messageDisplayRepresentation?.tokensGlobal( + pangeaMessageEvent.senderId, + pangeaMessageEvent.originServerTs, + ); if (tokens == null || tokens.isEmpty) { debugger(when: kDebugMode);