fix: properly dispose VideoPlayerController

This ensures that a playing video stops playing when we navigate away from the chat.

I also reorganized the code a little.
pull/1740/head
Rafał Hirsch 5 months ago
parent 7c1c1ad25c
commit d9ee3fbec6
No known key found for this signature in database

@ -37,22 +37,30 @@ class EventVideoPlayer extends StatefulWidget {
} }
class EventVideoPlayerState extends State<EventVideoPlayer> { class EventVideoPlayerState extends State<EventVideoPlayer> {
ChewieController? _chewieManager; ChewieController? _chewieController;
VideoPlayerController? _videoPlayerController;
bool _isDownloading = false; bool _isDownloading = false;
String? _networkUri;
File? _tmpFile;
void _downloadAction() async { void _downloadAction() async {
if (PlatformInfos.isDesktop) { if (PlatformInfos.isDesktop) {
widget.event.saveFile(context); widget.event.saveFile(context);
return; return;
} }
setState(() => _isDownloading = true); setState(() => _isDownloading = true);
try { try {
final videoFile = await widget.event.downloadAndDecryptAttachment(); final videoFile = await widget.event.downloadAndDecryptAttachment();
// Dispose the controllers if we already have them.
_disposeControllers();
late VideoPlayerController videoPlayerController;
// Create the VideoPlayerController from the contents of videoFile.
if (kIsWeb) { if (kIsWeb) {
final blob = html.Blob([videoFile.bytes]); final blob = html.Blob([videoFile.bytes]);
_networkUri = html.Url.createObjectUrlFromBlob(blob); final networkUri = Uri.parse(html.Url.createObjectUrlFromBlob(blob));
videoPlayerController = VideoPlayerController.networkUrl(networkUri);
} else { } else {
final tempDir = await getTemporaryDirectory(); final tempDir = await getTemporaryDirectory();
final fileName = Uri.encodeComponent( final fileName = Uri.encodeComponent(
@ -62,25 +70,19 @@ class EventVideoPlayerState extends State<EventVideoPlayer> {
if (await file.exists() == false) { if (await file.exists() == false) {
await file.writeAsBytes(videoFile.bytes); await file.writeAsBytes(videoFile.bytes);
} }
_tmpFile = file; videoPlayerController = VideoPlayerController.file(file);
} }
final tmpFile = _tmpFile; _videoPlayerController = videoPlayerController;
final networkUri = _networkUri;
if (kIsWeb && networkUri != null && _chewieManager == null) { await videoPlayerController.initialize();
_chewieManager ??= ChewieController(
videoPlayerController: // Create a ChewieController on top.
VideoPlayerController.networkUrl(Uri.parse(networkUri)), _chewieController = ChewieController(
autoPlay: true, videoPlayerController: videoPlayerController,
autoInitialize: true, useRootNavigator: !kIsWeb,
);
} else if (!kIsWeb && tmpFile != null && _chewieManager == null) {
_chewieManager ??= ChewieController(
useRootNavigator: false,
videoPlayerController: VideoPlayerController.file(tmpFile),
autoPlay: true, autoPlay: true,
autoInitialize: true, autoInitialize: true,
); );
}
} on IOException catch (e) { } on IOException catch (e) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
@ -90,15 +92,20 @@ class EventVideoPlayerState extends State<EventVideoPlayer> {
} catch (e, s) { } catch (e, s) {
ErrorReporter(context, 'Unable to play video').onErrorCallback(e, s); ErrorReporter(context, 'Unable to play video').onErrorCallback(e, s);
} finally { } finally {
// Workaround for Chewie needs time to get the aspectRatio
await Future.delayed(const Duration(milliseconds: 100));
setState(() => _isDownloading = false); setState(() => _isDownloading = false);
} }
} }
void _disposeControllers() {
_chewieController?.dispose();
_videoPlayerController?.dispose();
_chewieController = null;
_videoPlayerController = null;
}
@override @override
void dispose() { void dispose() {
_chewieManager?.dispose(); _disposeControllers();
super.dispose(); super.dispose();
} }
@ -118,7 +125,7 @@ class EventVideoPlayerState extends State<EventVideoPlayer> {
const width = 300.0; const width = 300.0;
final chewieManager = _chewieManager; final chewieController = _chewieController;
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
spacing: 8, spacing: 8,
@ -128,8 +135,8 @@ class EventVideoPlayerState extends State<EventVideoPlayer> {
borderRadius: BorderRadius.circular(AppConfig.borderRadius), borderRadius: BorderRadius.circular(AppConfig.borderRadius),
child: SizedBox( child: SizedBox(
height: width, height: width,
child: chewieManager != null child: chewieController != null
? Center(child: Chewie(controller: chewieManager)) ? Center(child: Chewie(controller: chewieController))
: Stack( : Stack(
children: [ children: [
if (hasThumbnail) if (hasThumbnail)

Loading…
Cancel
Save