diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index c63a6fa83..da9c883ab 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -30,7 +30,6 @@ import 'package:fluffychat/pangea/widgets/igc/pangea_text_controller.dart'; import 'package:fluffychat/utils/adaptive_bottom_sheet.dart'; import 'package:fluffychat/utils/error_reporter.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart'; -import 'package:fluffychat/utils/matrix_sdk_extensions/filtered_timeline_extension.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/widgets/app_lock.dart'; @@ -1546,48 +1545,52 @@ class ChatController extends State return currentState; } - List get events => - timeline!.events.where((event) => event.isVisibleInGui).toList(); - - final Map _messageToolbarControllers = {}; final Map _pangeaMessageEvents = {}; + final Map _toolbarDisplayControllers = {}; - PangeaMessageEvent? pangeaMessageEvent(String eventId) { - final Event? event = - events.firstWhereOrNull((event) => event.eventId == eventId); - if (timeline == null || event == null || event.type != EventTypes.Message) { - return null; + void setPangeaMessageEvent(String eventId) { + final Event? event = timeline!.events.firstWhereOrNull( + (e) => e.eventId == eventId, + ); + if (event == null || timeline == null) return; + _pangeaMessageEvents[eventId] = PangeaMessageEvent( + event: event, + timeline: timeline!, + ownMessage: event.senderId == room.client.userID, + ); + _pangeaMessageEvents[eventId]!.setDisplayRepresentation(context); + } + + void setToolbarDisplayController(String eventId) { + final Event? event = timeline!.events.firstWhereOrNull( + (e) => e.eventId == eventId, + ); + if (event == null || timeline == null) return; + if (_pangeaMessageEvents[eventId] == null) { + setPangeaMessageEvent(eventId); + if (_pangeaMessageEvents[eventId] == null) return; } - if (!_pangeaMessageEvents.containsKey(eventId)) { - _pangeaMessageEvents[eventId] = PangeaMessageEvent( - event: event, - timeline: timeline!, - ownMessage: event.senderId == Matrix.of(context).client.userID, - ); + _toolbarDisplayControllers[eventId] = ToolbarDisplayController( + targetId: event.eventId, + pangeaMessageEvent: _pangeaMessageEvents[eventId]!, + immersionMode: choreographer.immersionMode, + controller: this, + ); + _toolbarDisplayControllers[eventId]!.setToolbar(); + } + + PangeaMessageEvent? getPangeaMessageEvent(String eventId) { + if (_pangeaMessageEvents[eventId] == null) { + setPangeaMessageEvent(eventId); } return _pangeaMessageEvents[eventId]; } - ToolbarDisplayController? messageToolbarController(String eventId) { - final Event? event = - events.firstWhereOrNull((event) => event.eventId == eventId); - if (timeline == null || event == null || event.type != EventTypes.Message) { - return null; + ToolbarDisplayController? getToolbarDisplayController(String eventId) { + if (_toolbarDisplayControllers[eventId] == null) { + setToolbarDisplayController(eventId); } - - final PangeaMessageEvent? messageEvent = pangeaMessageEvent(eventId); - if (messageEvent == null) return null; - - if (!_messageToolbarControllers.containsKey(event.eventId)) { - _messageToolbarControllers[event.eventId] = ToolbarDisplayController( - targetId: event.eventId, - pangeaMessageEvent: messageEvent, - immersionMode: choreographer.immersionMode, - controller: this, - ); - _messageToolbarControllers[event.eventId]!.setToolbar(); - } - return _messageToolbarControllers[eventId]; + return _toolbarDisplayControllers[eventId]; } // Pangea# diff --git a/lib/pages/chat/chat_event_list.dart b/lib/pages/chat/chat_event_list.dart index d8fc89ebc..30f733d1d 100644 --- a/lib/pages/chat/chat_event_list.dart +++ b/lib/pages/chat/chat_event_list.dart @@ -24,12 +24,10 @@ class ChatEventList extends StatelessWidget { Widget build(BuildContext context) { final horizontalPadding = FluffyThemes.isColumnMode(context) ? 8.0 : 0.0; - // #Pangea - // final events = controller.timeline!.events - // .where((event) => event.isVisibleInGui) - // .toList(); - final events = controller.events; - // Pangea# + final events = controller.timeline!.events + .where((event) => event.isVisibleInGui) + .toList(); + final animateInEventIndex = controller.animateInEventIndex; // create a map of eventId --> index to greatly improve performance of diff --git a/lib/pages/chat/events/message.dart b/lib/pages/chat/events/message.dart index 4f4d06d86..61bf83061 100644 --- a/lib/pages/chat/events/message.dart +++ b/lib/pages/chat/events/message.dart @@ -5,7 +5,6 @@ import 'package:fluffychat/pangea/models/language_model.dart'; import 'package:fluffychat/pangea/models/pangea_message_event.dart'; import 'package:fluffychat/pangea/widgets/chat/message_toolbar.dart'; import 'package:fluffychat/utils/date_time_extension.dart'; -import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/string_color.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/hover_builder.dart'; @@ -15,7 +14,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:matrix/matrix.dart'; import 'package:swipe_to_action/swipe_to_action.dart'; -import 'package:vibration/vibration.dart'; import '../../../config/app_config.dart'; import 'message_content.dart'; @@ -144,9 +142,9 @@ class Message extends StatelessWidget { // #Pangea final PangeaMessageEvent? pangeaMessageEvent = - controller.pangeaMessageEvent(event.eventId); + controller.getPangeaMessageEvent(event.eventId); final ToolbarDisplayController? toolbarController = - controller.messageToolbarController(event.eventId); + controller.getToolbarDisplayController(event.eventId); // Pangea# final resetAnimateIn = this.resetAnimateIn; diff --git a/lib/pages/chat/events/message_content.dart b/lib/pages/chat/events/message_content.dart index fd4791d3c..51bf1e969 100644 --- a/lib/pages/chat/events/message_content.dart +++ b/lib/pages/chat/events/message_content.dart @@ -1,16 +1,13 @@ import 'package:fluffychat/pages/chat/events/html_message.dart'; import 'package:fluffychat/pages/chat/events/video_player.dart'; -import 'package:fluffychat/pangea/models/language_model.dart'; import 'package:fluffychat/pangea/models/pangea_message_event.dart'; import 'package:fluffychat/pangea/widgets/chat/message_context_menu.dart'; -import 'package:fluffychat/pangea/widgets/chat/message_text_selection.dart'; import 'package:fluffychat/pangea/widgets/chat/message_toolbar.dart'; import 'package:fluffychat/pangea/widgets/igc/pangea_rich_text.dart'; import 'package:fluffychat/utils/adaptive_bottom_sheet.dart'; import 'package:fluffychat/utils/date_time_extension.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/widgets/avatar.dart'; -import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_linkify/flutter_linkify.dart'; @@ -173,7 +170,7 @@ class MessageContent extends StatelessWidget { event.isRichMessage // #Pangea && - !(pangeaMessageEvent?.showRichText ?? false) + !(pangeaMessageEvent?.showRichText(selected) ?? false) // Pangea# ) { var html = event.formattedText; @@ -273,7 +270,7 @@ class MessageContent extends StatelessWidget { decoration: event.redacted ? TextDecoration.lineThrough : null, height: 1.3, ); - if (pangeaMessageEvent?.showRichText ?? false) { + if (pangeaMessageEvent?.showRichText(selected) ?? false) { return PangeaRichText( style: messageTextStyle, pangeaMessageEvent: pangeaMessageEvent!, diff --git a/lib/pangea/models/pangea_message_event.dart b/lib/pangea/models/pangea_message_event.dart index d46ad0dc3..2be000eb1 100644 --- a/lib/pangea/models/pangea_message_event.dart +++ b/lib/pangea/models/pangea_message_event.dart @@ -2,7 +2,6 @@ import 'dart:convert'; import 'dart:developer'; import 'package:collection/collection.dart'; -import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/constants/model_keys.dart'; import 'package:fluffychat/pangea/constants/pangea_message_types.dart'; import 'package:fluffychat/pangea/controllers/text_to_speech_controller.dart'; @@ -27,7 +26,6 @@ class PangeaMessageEvent { final Timeline timeline; final bool ownMessage; bool _isValidPangeaMessageEvent = true; - RepresentationEvent? _displayRepresentation; PangeaMessageEvent({ required Event event, @@ -71,7 +69,7 @@ class PangeaMessageEvent { .firstOrNull ?? _event; - bool get showRichText { + bool showRichText(bool selected) { if (!_isValidPangeaMessageEvent) { return false; } @@ -81,7 +79,7 @@ class PangeaMessageEvent { if ([EventStatus.error, EventStatus.sending].contains(_event.status)) { return false; } - // if (ownMessage && !selected) return false; + if (ownMessage && !selected) return false; return true; } @@ -187,7 +185,7 @@ class PangeaMessageEvent { final elementLangCode = transcription[ModelKey.langCode]; final elementText = transcription[ModelKey.text]; - // Check if both language code and text match + // Check if both language code and text matsch return elementLangCode == langCode && elementText == text; }, ); @@ -402,34 +400,36 @@ class PangeaMessageEvent { return langCode ?? LanguageKeys.unknownLanguage; } - Future getDisplayRepresentation( + RepresentationEvent? _displayRepresentation; + + RepresentationEvent? displayRepresentation(String langCode) => + _displayRepresentation; + + Future setDisplayRepresentation( BuildContext context, ) async { - if (messageDisplayLangCode == LanguageKeys.unknownLanguage) return null; - if (_displayRepresentation != null) return _displayRepresentation; - _displayRepresentation = representationByLanguage(messageDisplayLangCode); - if (_displayRepresentation != null) { - return _displayRepresentation; + if (messageDisplayLangCode == LanguageKeys.unknownLanguage || + _displayRepresentation != null) { + return; } + _displayRepresentation = representationByLanguage(messageDisplayLangCode); + if (_displayRepresentation != null) return; try { _displayRepresentation = await representationByLanguageGlobal( context: context, langCode: messageDisplayLangCode, ); - return _displayRepresentation; + return; } catch (err, s) { ErrorHandler.logError( m: "error in getDisplayRepresentation", e: err, s: s, ); - return null; } } - String get displayMessageText => _displayRepresentation?.text ?? body; - // List get activities => //each match is turned into an activity that other students can access //they're not told the answer but have to find it themselves diff --git a/lib/pangea/widgets/chat/message_audio_card.dart b/lib/pangea/widgets/chat/message_audio_card.dart index dd306be54..c523e5048 100644 --- a/lib/pangea/widgets/chat/message_audio_card.dart +++ b/lib/pangea/widgets/chat/message_audio_card.dart @@ -1,10 +1,6 @@ import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pages/chat/events/audio_player.dart'; import 'package:fluffychat/pangea/models/pangea_message_event.dart'; -import 'package:fluffychat/pangea/models/pangea_representation_event.dart'; -import 'package:fluffychat/pangea/utils/bot_style.dart'; -import 'package:fluffychat/pangea/utils/error_handler.dart'; -import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:matrix/matrix.dart'; @@ -57,10 +53,7 @@ class MessageAudioCardState extends State { void fetchAudio() { if (!mounted) return; - // final String? text = widget.messageEvent.displayMessageText; - // if (text == null || text.isEmpty) return; setState(() => _isLoading = true); - widget.messageEvent .getAudioGlobal(widget.messageEvent.messageDisplayLangCode) .then((Event? event) { @@ -81,18 +74,20 @@ class MessageAudioCardState extends State { @override void initState() { super.initState(); - widget.messageEvent - .getDisplayRepresentation(context) - .then((_) => fetchAudio()); + fetchAudio(); + } + + @override + void dispose() { + super.dispose(); + setState(() => _isLoading = false); } @override Widget build(BuildContext context) { final playButton = InkWell( borderRadius: BorderRadius.circular(64), - onTap: () => widget.messageEvent - .getDisplayRepresentation(context) - .then((event) => event == null ? null : fetchAudio), + onTap: fetchAudio, child: Material( color: AppConfig.primaryColor.withAlpha(64), borderRadius: BorderRadius.circular(64), diff --git a/lib/pangea/widgets/chat/message_translation_card.dart b/lib/pangea/widgets/chat/message_translation_card.dart index 5cb22e919..3ff08a84b 100644 --- a/lib/pangea/widgets/chat/message_translation_card.dart +++ b/lib/pangea/widgets/chat/message_translation_card.dart @@ -63,10 +63,12 @@ class MessageTranslationCardState extends State { ) .then((RepresentationEvent? event) => repEvent = event) .whenComplete( - () => setState(() => _fetchingRepresentation = false), - ); + () { + setState(() => _fetchingRepresentation = false); + }, + ); } else { - setState(() {}); + if (mounted) setState(() {}); } } @@ -76,6 +78,12 @@ class MessageTranslationCardState extends State { fetchRepresentation(context); } + @override + void dispose() { + super.dispose(); + setState(() => _fetchingRepresentation = false); + } + @override Widget build(BuildContext context) { return Padding( diff --git a/lib/pangea/widgets/igc/pangea_rich_text.dart b/lib/pangea/widgets/igc/pangea_rich_text.dart index a2d32adb2..cdd86b1b1 100644 --- a/lib/pangea/widgets/igc/pangea_rich_text.dart +++ b/lib/pangea/widgets/igc/pangea_rich_text.dart @@ -1,3 +1,4 @@ +import 'dart:developer'; import 'dart:ui'; import 'package:fluffychat/config/app_config.dart'; @@ -9,7 +10,9 @@ import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:fluffychat/pangea/widgets/chat/message_context_menu.dart'; import 'package:fluffychat/pangea/widgets/chat/message_toolbar.dart'; import 'package:fluffychat/widgets/matrix.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; + import '../../models/pangea_match_model.dart'; class PangeaRichText extends StatefulWidget { @@ -32,28 +35,56 @@ class PangeaRichText extends StatefulWidget { class PangeaRichTextState extends State { final PangeaController pangeaController = MatrixState.pangeaController; - RepresentationEvent? repEvent; bool _fetchingRepresentation = false; double get blur => _fetchingRepresentation && widget.immersionMode ? 5 : 0; + String textSpan = ""; @override void initState() { super.initState(); - setTextSpan(); + updateTextSpan(); } - Future setTextSpan() async { - setState(() => _fetchingRepresentation = true); - try { - await widget.pangeaMessageEvent.getDisplayRepresentation(context); - } catch (err) { - ErrorHandler.logError(e: err); - } - setState(() => _fetchingRepresentation = false); + void updateTextSpan() { + setState(() { + textSpan = getTextSpan(); + }); + } - widget.toolbarController.toolbar?.textSelection.setMessageText( - widget.pangeaMessageEvent.displayMessageText, + @override + void didUpdateWidget(PangeaRichText oldWidget) { + super.didUpdateWidget(oldWidget); + updateTextSpan(); + } + + String getTextSpan() { + if (widget.pangeaMessageEvent.eventId.contains("webdebug")) { + debugger(when: kDebugMode); + } + + final RepresentationEvent? repEvent = + widget.pangeaMessageEvent.representationByLanguage( + widget.pangeaMessageEvent.messageDisplayLangCode, ); + + if (repEvent == null) { + setState(() => _fetchingRepresentation = true); + + widget.pangeaMessageEvent + .representationByLanguageGlobal( + context: context, + langCode: widget.pangeaMessageEvent.messageDisplayLangCode, + ) + .onError((error, stackTrace) => ErrorHandler.logError()) + .then((_) { + widget.toolbarController.toolbar?.textSelection.setMessageText( + repEvent?.text ?? widget.pangeaMessageEvent.body, + ); + }).whenComplete(() => setState(() => _fetchingRepresentation = false)); + return widget.pangeaMessageEvent.body; + } + + return repEvent.text; } @override @@ -79,7 +110,7 @@ class PangeaRichTextState extends State { ), ), TextSpan( - text: widget.pangeaMessageEvent.displayMessageText, + text: textSpan, style: widget.style, children: [ if (_fetchingRepresentation)