diff --git a/lib/pages/chat/events/audio_player.dart b/lib/pages/chat/events/audio_player.dart index 418dfc0f4..2531105c7 100644 --- a/lib/pages/chat/events/audio_player.dart +++ b/lib/pages/chat/events/audio_player.dart @@ -15,7 +15,6 @@ import 'package:path_provider/path_provider.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pangea/toolbar/message_practice/message_audio_card.dart'; -import 'package:fluffychat/pangea/toolbar/message_selection_overlay.dart'; import 'package:fluffychat/utils/error_reporter.dart'; import 'package:fluffychat/utils/file_description.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; @@ -34,7 +33,6 @@ class AudioPlayerWidget extends StatefulWidget { final String roomId; final String senderId; final PangeaAudioFile? matrixFile; - final MessageOverlayController? overlayController; final bool autoplay; // Pangea# @@ -50,7 +48,6 @@ class AudioPlayerWidget extends StatefulWidget { required this.roomId, required this.senderId, this.matrixFile, - this.overlayController, this.autoplay = false, // Pangea# super.key, @@ -72,7 +69,6 @@ class AudioPlayerState extends State { String? _durationString; // #Pangea - StreamSubscription? _onAudioPositionChanged; StreamSubscription? _onAudioStateChanged; double playbackSpeed = 1.0; @@ -154,7 +150,6 @@ class AudioPlayerState extends State { audioPlayer.dispose(); matrix.voiceMessageEventId.value = matrix.audioPlayer = null; // #Pangea - _onAudioPositionChanged?.cancel(); _onAudioStateChanged?.cancel(); // Pangea# } @@ -262,18 +257,6 @@ class AudioPlayerState extends State { // #Pangea audioPlayer.setSpeed(playbackSpeed); - _onAudioPositionChanged?.cancel(); - _onAudioPositionChanged = - matrix.audioPlayer!.positionStream.listen((state) { - // Pass current timestamp to overlay, so it can highlight as necessary - if (widget.matrixFile?.tokens != null) { - widget.overlayController?.highlightCurrentText( - state.inMilliseconds, - widget.matrixFile!.tokens!, - ); - } - }); - _onAudioStateChanged?.cancel(); _onAudioStateChanged = matrix.audioPlayer!.playerStateStream.listen((state) { diff --git a/lib/pangea/toolbar/message_selection_overlay.dart b/lib/pangea/toolbar/message_selection_overlay.dart index b988b9e56..4dacbbdb8 100644 --- a/lib/pangea/toolbar/message_selection_overlay.dart +++ b/lib/pangea/toolbar/message_selection_overlay.dart @@ -193,9 +193,15 @@ class MessageOverlayController extends State return; } - if (selectedSpan == _selectedSpan) return; + if (selectedSpan == _selectedSpan) { + selectModeController.setPlayingToken(selectedToken?.text); + return; + } + _selectedSpan = selectedSpan; selectedTokenNotifier.value = selectedToken; + selectModeController.setPlayingToken(selectedToken?.text); + if (mounted) { setState(() {}); if (selectedToken != null && isNewToken(selectedToken!)) { diff --git a/lib/pangea/toolbar/reading_assistance/select_mode_buttons.dart b/lib/pangea/toolbar/reading_assistance/select_mode_buttons.dart index 42f7c1ae0..52cf02b7a 100644 --- a/lib/pangea/toolbar/reading_assistance/select_mode_buttons.dart +++ b/lib/pangea/toolbar/reading_assistance/select_mode_buttons.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:collection/collection.dart'; import 'package:just_audio/just_audio.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:matrix/matrix.dart'; @@ -156,6 +157,8 @@ class SelectModeButtonsState extends State { if (messageEvent.isAudioMessage == true) { controller.fetchTranscription(); } + + controller.playTokenNotifier.addListener(_playToken); } @override @@ -165,6 +168,7 @@ class SelectModeButtonsState extends State { matrix?.voiceMessageEventId.value = null; _audioSub?.cancel(); _playerStateSub?.cancel(); + controller.playTokenNotifier.removeListener(_playToken); super.dispose(); } @@ -304,6 +308,26 @@ class SelectModeButtonsState extends State { } } + void _playToken() { + final token = controller.playTokenNotifier.value; + + if (token == null || + controller.audioFile?.$1.tokens == null || + controller.selectedMode.value != SelectMode.audio) { + return; + } + + final ttsToken = controller.audioFile!.$1.tokens!.firstWhereOrNull( + (t) => t.text == token, + ); + + if (ttsToken != null && matrix?.audioPlayer != null) { + final start = Duration(milliseconds: ttsToken.startMS); + matrix!.audioPlayer!.seek(start); + matrix!.audioPlayer!.play(); + } + } + @override Widget build(BuildContext context) { final theme = Theme.of(context); diff --git a/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart b/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart index 79b2ab38f..0d3a40a0e 100644 --- a/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart +++ b/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart @@ -10,6 +10,7 @@ import 'package:fluffychat/pangea/analytics_misc/lemma_emoji_setter_mixin.dart'; import 'package:fluffychat/pangea/common/utils/async_state.dart'; import 'package:fluffychat/pangea/constructs/construct_identifier.dart'; import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart'; +import 'package:fluffychat/pangea/events/models/pangea_token_text_model.dart'; import 'package:fluffychat/pangea/speech_to_text/speech_to_text_response_model.dart'; import 'package:fluffychat/pangea/toolbar/message_practice/message_audio_card.dart'; import 'package:fluffychat/pangea/toolbar/reading_assistance/select_mode_buttons.dart'; @@ -92,10 +93,13 @@ class SelectModeController with LemmaEmojiSetter { ValueNotifier<(ConstructIdentifier, String)?>(null); final StreamController contentChangedStream = StreamController.broadcast(); + ValueNotifier playTokenNotifier = + ValueNotifier(null); void dispose() { selectedMode.dispose(); constructEmojiNotifier.dispose(); + playTokenNotifier.dispose(); _transcriptLoader.dispose(); _translationLoader.dispose(); _sttTranslationLoader.dispose(); @@ -197,6 +201,9 @@ class SelectModeController with LemmaEmojiSetter { ) => constructEmojiNotifier.value = (constructId, emoji); + void setPlayingToken(PangeaTokenText? token) => + playTokenNotifier.value = token; + Future fetchAudio() => _audioLoader.load(); Future fetchTranslation() => _translationLoader.load(); Future fetchTranscription() => _transcriptLoader.load();