fix: play audio from file on mobile (#2690)

This commit is contained in:
ggurdin 2025-05-06 13:56:03 -04:00 committed by GitHub
parent a66c7bada4
commit ed376aed06
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@ -8,6 +9,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:just_audio/just_audio.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:matrix/matrix.dart';
import 'package:path_provider/path_provider.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/chat/events/audio_player.dart';
@ -63,7 +65,9 @@ class SelectModeButtonsState extends State<SelectModeButtons> {
final AudioPlayer _audioPlayer = AudioPlayer();
bool _isLoadingAudio = false;
PangeaAudioFile? _audioFile;
PangeaAudioFile? _audioBytes;
File? _audioFile;
String? _audioError;
StreamSubscription? _onPlayerStateChanged;
StreamSubscription? _onAudioPositionChanged;
@ -81,11 +85,12 @@ class SelectModeButtonsState extends State<SelectModeButtons> {
}
setState(() {});
});
_onAudioPositionChanged ??= _audioPlayer.positionStream.listen((state) {
if (_audioFile != null) {
if (_audioBytes != null) {
widget.overlayController.highlightCurrentText(
state.inMilliseconds,
_audioFile!.tokens,
_audioBytes!.tokens,
);
}
});
@ -107,13 +112,17 @@ class SelectModeButtonsState extends State<SelectModeButtons> {
String? get l2Code =>
MatrixState.pangeaController.languageController.activeL2Code();
Future<void> _updateMode(SelectMode mode) async {
void _clear() {
setState(() => _audioError = null);
widget.overlayController.updateSelectedSpan(null);
if (_selectedMode == SelectMode.translate) {
widget.overlayController.setShowTranslation(false, null);
}
}
Future<void> _updateMode(SelectMode mode) async {
_clear();
setState(
() => _selectedMode =
_selectedMode == mode && mode != SelectMode.audio ? null : mode,
@ -154,13 +163,22 @@ class SelectModeButtonsState extends State<SelectModeButtons> {
);
if (localEvent != null) {
_audioFile = await localEvent.getPangeaAudioFile();
_audioBytes = await localEvent.getPangeaAudioFile();
} else {
_audioFile = await messageEvent!.getMatrixAudioFile(
_audioBytes = await messageEvent!.getMatrixAudioFile(
langCode,
);
}
if (!kIsWeb) {
final tempDir = await getTemporaryDirectory();
File? file;
file = File('${tempDir.path}/${_audioBytes!.name}');
await file.writeAsBytes(_audioBytes!.bytes);
setState(() => _audioFile = file);
}
if (mounted) setState(() => _isLoadingAudio = false);
} catch (e, s) {
debugger(when: kDebugMode);
@ -178,26 +196,43 @@ class SelectModeButtonsState extends State<SelectModeButtons> {
}
Future<void> _playAudio() async {
if (_audioPlayer.playerState.playing) {
await _audioPlayer.pause();
return;
} else if (_audioPlayer.position != Duration.zero) {
await _audioPlayer.play();
return;
}
try {
if (_audioPlayer.playerState.playing) {
await _audioPlayer.pause();
return;
} else if (_audioPlayer.position != Duration.zero) {
await _audioPlayer.play();
return;
}
if (_audioFile == null) {
await _fetchAudio();
}
if (_audioBytes == null) {
await _fetchAudio();
}
if (_audioFile == null) return;
await _audioPlayer.setAudioSource(
BytesAudioSource(
_audioFile!.bytes,
_audioFile!.mimeType,
),
);
_audioPlayer.play();
if (_audioBytes == null) return;
if (_audioFile != null) {
await _audioPlayer.setFilePath(_audioFile!.path);
} else {
await _audioPlayer.setAudioSource(
BytesAudioSource(
_audioBytes!.bytes,
_audioBytes!.mimeType,
),
);
}
_audioPlayer.play();
} catch (e, s) {
setState(() => _audioError = e.toString());
ErrorHandler.logError(
e: e,
s: s,
m: 'something wrong playing message audio',
data: {
'event': messageEvent?.event.toJson(),
},
);
}
}
Future<void> _fetchRepresentation() async {
@ -233,11 +268,20 @@ class SelectModeButtonsState extends State<SelectModeButtons> {
Widget icon(SelectMode mode) {
if (mode == SelectMode.audio) {
if (_audioError != null) {
return Icon(
Icons.error_outline,
size: 20,
color: Theme.of(context).colorScheme.error,
);
}
if (_isLoadingAudio) {
return const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator.adaptive(),
return const Center(
child: SizedBox(
height: 20.0,
width: 20.0,
child: CircularProgressIndicator.adaptive(),
),
);
} else {
return Icon(
@ -252,10 +296,12 @@ class SelectModeButtonsState extends State<SelectModeButtons> {
if (mode == SelectMode.translate) {
if (_isLoadingTranslation) {
return const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator.adaptive(),
return const Center(
child: SizedBox(
height: 20.0,
width: 20.0,
child: CircularProgressIndicator.adaptive(),
),
);
} else if (_repEvent != null) {
return Icon(