From 03e04ee752c7a1c4bbd626326358cbbcb164d580 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 4 Sep 2024 10:20:22 -0400 Subject: [PATCH] improved text selection handling, added text selection handling for HTML messages, clear selection on close overlay --- lib/pages/chat/chat.dart | 14 ++++++- lib/pages/chat/events/html_message.dart | 3 ++ .../widgets/chat/message_text_selection.dart | 41 ++++++++++++------- lib/pangea/widgets/chat/message_toolbar.dart | 3 +- .../chat/message_translation_card.dart | 5 ++- 5 files changed, 47 insertions(+), 19 deletions(-) diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 69f37136c..f0fa968f2 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -1250,7 +1250,7 @@ class ChatController extends State void pickEmojiReactionAction(Iterable allReactionEvents) async { // #Pangea - MatrixState.pAnyState.closeAllOverlays(); + closeSelectionOverlay(); // Pangea# _allReactionEvents = allReactionEvents; emojiPickerType = EmojiPickerType.reaction; @@ -1271,9 +1271,19 @@ class ChatController extends State // Pangea# } + // #Pangea + /// Close the combined selection view overlay and clear the message + /// text and selection stored for the text in that overlay + void closeSelectionOverlay() { + MatrixState.pAnyState.closeAllOverlays(); + textSelection.clearMessageText(); + textSelection.onSelection(null); + } + // Pangea# + void clearSelectedEvents() => setState(() { // #Pangea - MatrixState.pAnyState.closeAllOverlays(); + closeSelectionOverlay(); // Pangea# selectedEvents.clear(); showEmojiPicker = false; diff --git a/lib/pages/chat/events/html_message.dart b/lib/pages/chat/events/html_message.dart index 5bd4ef9bc..803869a75 100644 --- a/lib/pages/chat/events/html_message.dart +++ b/lib/pages/chat/events/html_message.dart @@ -71,6 +71,9 @@ class HtmlMessage extends StatelessWidget { @override Widget build(BuildContext context) { + // #Pangea + controller.textSelection.setMessageText(html); + // Pangea# final fontSize = AppConfig.messageFontSize * AppConfig.fontSizeFactor; final linkColor = textColor.withAlpha(150); diff --git a/lib/pangea/widgets/chat/message_text_selection.dart b/lib/pangea/widgets/chat/message_text_selection.dart index 0a332a545..2396d08bf 100644 --- a/lib/pangea/widgets/chat/message_text_selection.dart +++ b/lib/pangea/widgets/chat/message_text_selection.dart @@ -1,28 +1,41 @@ import 'dart:async'; +/// Contains information about the text currently being shown in a +/// toolbar overlay message and any selection within that text. +/// The ChatController contains one instance of this class, and it's values +/// should be updated each time an overlay is openned or closed, or when +/// an overlay's text selection changes. class MessageTextSelection { + /// The currently selected text in the overlay message. String? selectedText; - String messageText = ""; + + /// The full text displayed in the overlay message. + String? messageText; + + /// A stream that emits the currently selected text whenever it changes. final StreamController selectionStream = StreamController.broadcast(); - void setMessageText(String text) { - messageText = text; - } + /// Sets messageText to match the text currently being displayed in the overlay. + /// Text in messages is displayed in a variety of ways, i.e., direct message content, + /// translation, HTML rendered message, etc. This method should be called wherever the + /// text displayed in the overlay is determined. + void setMessageText(String text) => messageText = text; - void onSelection(String? text) => text == null || text.isEmpty - ? clearTextSelection() - : setTextSelection(text); + /// Clears the messageText value. Called when the message selection overlay is closed. + void clearMessageText() => messageText = null; - void setTextSelection(String selection) { - selectedText = selection; + /// Updates the selectedText value and emits it to the selectionStream. + void onSelection(String? text) { + text == null || text.isEmpty ? selectedText = null : selectedText = text; selectionStream.add(selectedText); } - void clearTextSelection() { - selectedText = null; - selectionStream.add(selectedText); + /// Returns the index of the selected text within the message text. + /// If the selected text is not found, returns null. + int? get offset { + if (selectedText == null || messageText == null) return null; + final index = messageText!.indexOf(selectedText!); + return index > -1 ? index : null; } - - int get offset => messageText.indexOf(selectedText!); } diff --git a/lib/pangea/widgets/chat/message_toolbar.dart b/lib/pangea/widgets/chat/message_toolbar.dart index 2bdfe6b7a..4d41918a8 100644 --- a/lib/pangea/widgets/chat/message_toolbar.dart +++ b/lib/pangea/widgets/chat/message_toolbar.dart @@ -141,6 +141,7 @@ class MessageToolbarState extends State { void showDefinition() { debugPrint("show definition"); if (widget.textSelection.selectedText == null || + widget.textSelection.messageText == null || widget.textSelection.selectedText!.isEmpty) { toolbarContent = const SelectToDefine(); return; @@ -149,7 +150,7 @@ class MessageToolbarState extends State { toolbarContent = WordDataCard( word: widget.textSelection.selectedText!, wordLang: widget.pangeaMessageEvent.messageDisplayLangCode, - fullText: widget.textSelection.messageText, + fullText: widget.textSelection.messageText!, fullTextLang: widget.pangeaMessageEvent.messageDisplayLangCode, hasInfo: true, room: widget.controller.room, diff --git a/lib/pangea/widgets/chat/message_translation_card.dart b/lib/pangea/widgets/chat/message_translation_card.dart index 10e75a47a..278c7d7ed 100644 --- a/lib/pangea/widgets/chat/message_translation_card.dart +++ b/lib/pangea/widgets/chat/message_translation_card.dart @@ -52,7 +52,8 @@ class MessageTranslationCardState extends State { Future translateSelection() async { if (widget.selection.selectedText == null || l1Code == null || - l2Code == null) { + l2Code == null || + widget.selection.messageText == null) { selectionTranslation = null; return; } @@ -64,7 +65,7 @@ class MessageTranslationCardState extends State { final resp = await FullTextTranslationRepo.translate( accessToken: accessToken, request: FullTextTranslationRequestModel( - text: widget.selection.messageText, + text: widget.selection.messageText!, tgtLang: l1Code!, userL1: l1Code!, userL2: l2Code!,