From 7c1c1ad25c6030d2a116df8e5fd993ba8bd8c32f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Hirsch?= Date: Fri, 28 Mar 2025 22:00:19 +0100 Subject: [PATCH 1/4] chore: upgrade chewie and video_player packages This bumps the minimum Flutter version to 3.27. I think this is not an issue, since e93fdebe2017f6c6491ceb93d57c71148d1b4f0d upgraded to 3.29.2 already. --- pubspec.lock | 34 +++++++++++++++++----------------- pubspec.yaml | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index e5369f057..51d98a87b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -178,10 +178,10 @@ packages: dependency: "direct main" description: name: chewie - sha256: "335df378c025588aef400c704bd71f0daea479d4cd57c471c88c056c1144e7cd" + sha256: "0bf6f7692cb65f7b8f59a2a17025b9cbe8f75ab4251e66161a4fc86162475fb6" url: "https://pub.dev" source: hosted - version: "1.8.5" + version: "1.11.0" cli_util: dependency: transitive description: @@ -2124,42 +2124,42 @@ packages: dependency: "direct main" description: name: video_player - sha256: "4a8c3492d734f7c39c2588a3206707a05ee80cef52e8c7f3b2078d430c84bc17" + sha256: "7d78f0cfaddc8c19d4cb2d3bebe1bfef11f2103b0a03e5398b303a1bf65eeb14" url: "https://pub.dev" source: hosted - version: "2.9.2" + version: "2.9.5" video_player_android: dependency: transitive description: name: video_player_android - sha256: ae5287ca367e206eb74d7b3dc1ce0b8912ab9a3fc0597b6a101a0a5239f229d3 + sha256: ae7d4f1b41e3ac6d24dd9b9d5d6831b52d74a61bdd90a7a6262a33d8bb97c29a url: "https://pub.dev" source: hosted - version: "2.7.9" + version: "2.8.2" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - sha256: cd5ab8a8bc0eab65ab0cea40304097edc46da574c8c1ecdee96f28cd8ef3792f + sha256: "84b4752745eeccb6e75865c9aab39b3d28eb27ba5726d352d45db8297fbd75bc" url: "https://pub.dev" source: hosted - version: "2.6.2" + version: "2.7.0" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface - sha256: "229d7642ccd9f3dc4aba169609dd6b5f3f443bb4cc15b82f7785fcada5af9bbb" + sha256: df534476c341ab2c6a835078066fc681b8265048addd853a1e3c78740316a844 url: "https://pub.dev" source: hosted - version: "6.2.3" + version: "6.3.0" video_player_web: dependency: transitive description: name: video_player_web - sha256: "6dcdd298136523eaf7dfc31abaf0dfba9aa8a8dbc96670e87e9d42b6f2caf774" + sha256: "3ef40ea6d72434edbfdba4624b90fd3a80a0740d260667d91e7ecd2d79e13476" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.4" vm_service: dependency: transitive description: @@ -2172,18 +2172,18 @@ packages: dependency: "direct main" description: name: wakelock_plus - sha256: bf4ee6f17a2fa373ed3753ad0e602b7603f8c75af006d5b9bdade263928c0484 + sha256: b90fbcc8d7bdf3b883ea9706d9d76b9978cb1dfa4351fcc8014d6ec31a493354 url: "https://pub.dev" source: hosted - version: "1.2.8" + version: "1.2.11" wakelock_plus_platform_interface: dependency: transitive description: name: wakelock_plus_platform_interface - sha256: "422d1cdbb448079a8a62a5a770b69baa489f8f7ca21aef47800c726d404f9d16" + sha256: "70e780bc99796e1db82fe764b1e7dcb89a86f1e5b3afb1db354de50f2e41eb7a" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" watcher: dependency: transitive description: @@ -2298,4 +2298,4 @@ packages: version: "3.1.2" sdks: dart: ">=3.7.0-0 <4.0.0" - flutter: ">=3.24.0" + flutter: ">=3.27.0" diff --git a/pubspec.yaml b/pubspec.yaml index 82fa2aff7..5bfee702e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: async: ^2.11.0 badges: ^3.1.2 blurhash_dart: ^1.2.1 - chewie: ^1.8.1 + chewie: ^1.11.0 collection: ^1.18.0 cross_file: ^0.3.4+2 cupertino_icons: any From d9ee3fbec68eb61577261c72f978325f5894dfce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Hirsch?= Date: Wed, 2 Apr 2025 21:04:01 +0200 Subject: [PATCH 2/4] 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. --- lib/pages/chat/events/video_player.dart | 63 ++++++++++++++----------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/lib/pages/chat/events/video_player.dart b/lib/pages/chat/events/video_player.dart index ad3dfaf15..59bb06694 100644 --- a/lib/pages/chat/events/video_player.dart +++ b/lib/pages/chat/events/video_player.dart @@ -37,22 +37,30 @@ class EventVideoPlayer extends StatefulWidget { } class EventVideoPlayerState extends State { - ChewieController? _chewieManager; + ChewieController? _chewieController; + VideoPlayerController? _videoPlayerController; bool _isDownloading = false; - String? _networkUri; - File? _tmpFile; void _downloadAction() async { if (PlatformInfos.isDesktop) { widget.event.saveFile(context); return; } + setState(() => _isDownloading = true); + try { 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) { final blob = html.Blob([videoFile.bytes]); - _networkUri = html.Url.createObjectUrlFromBlob(blob); + final networkUri = Uri.parse(html.Url.createObjectUrlFromBlob(blob)); + videoPlayerController = VideoPlayerController.networkUrl(networkUri); } else { final tempDir = await getTemporaryDirectory(); final fileName = Uri.encodeComponent( @@ -62,25 +70,19 @@ class EventVideoPlayerState extends State { if (await file.exists() == false) { await file.writeAsBytes(videoFile.bytes); } - _tmpFile = file; - } - final tmpFile = _tmpFile; - final networkUri = _networkUri; - if (kIsWeb && networkUri != null && _chewieManager == null) { - _chewieManager ??= ChewieController( - videoPlayerController: - VideoPlayerController.networkUrl(Uri.parse(networkUri)), - autoPlay: true, - autoInitialize: true, - ); - } else if (!kIsWeb && tmpFile != null && _chewieManager == null) { - _chewieManager ??= ChewieController( - useRootNavigator: false, - videoPlayerController: VideoPlayerController.file(tmpFile), - autoPlay: true, - autoInitialize: true, - ); + videoPlayerController = VideoPlayerController.file(file); } + _videoPlayerController = videoPlayerController; + + await videoPlayerController.initialize(); + + // Create a ChewieController on top. + _chewieController = ChewieController( + videoPlayerController: videoPlayerController, + useRootNavigator: !kIsWeb, + autoPlay: true, + autoInitialize: true, + ); } on IOException catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( @@ -90,15 +92,20 @@ class EventVideoPlayerState extends State { } catch (e, s) { ErrorReporter(context, 'Unable to play video').onErrorCallback(e, s); } finally { - // Workaround for Chewie needs time to get the aspectRatio - await Future.delayed(const Duration(milliseconds: 100)); setState(() => _isDownloading = false); } } + void _disposeControllers() { + _chewieController?.dispose(); + _videoPlayerController?.dispose(); + _chewieController = null; + _videoPlayerController = null; + } + @override void dispose() { - _chewieManager?.dispose(); + _disposeControllers(); super.dispose(); } @@ -118,7 +125,7 @@ class EventVideoPlayerState extends State { const width = 300.0; - final chewieManager = _chewieManager; + final chewieController = _chewieController; return Column( mainAxisSize: MainAxisSize.min, spacing: 8, @@ -128,8 +135,8 @@ class EventVideoPlayerState extends State { borderRadius: BorderRadius.circular(AppConfig.borderRadius), child: SizedBox( height: width, - child: chewieManager != null - ? Center(child: Chewie(controller: chewieManager)) + child: chewieController != null + ? Center(child: Chewie(controller: chewieController)) : Stack( children: [ if (hasThumbnail) From cfcbf944ffaccffcec3a90e5a9080ab16471fdc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Hirsch?= Date: Wed, 2 Apr 2025 21:04:01 +0200 Subject: [PATCH 3/4] feat: support inline video playback on macOS It turns out that video_player supports macOS, so we can simply enable it. --- lib/pages/chat/events/video_player.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pages/chat/events/video_player.dart b/lib/pages/chat/events/video_player.dart index 59bb06694..dd7917b34 100644 --- a/lib/pages/chat/events/video_player.dart +++ b/lib/pages/chat/events/video_player.dart @@ -41,8 +41,12 @@ class EventVideoPlayerState extends State { VideoPlayerController? _videoPlayerController; bool _isDownloading = false; + // The video_player package only doesn't support Windows and Linux. + final _supportsVideoPlayer = + !PlatformInfos.isWindows && !PlatformInfos.isLinux; + void _downloadAction() async { - if (PlatformInfos.isDesktop) { + if (!_supportsVideoPlayer) { widget.event.saveFile(context); return; } From 706d0bf060a63d77a50b695a3583fe659c37725f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Hirsch?= Date: Wed, 2 Apr 2025 21:27:09 +0200 Subject: [PATCH 4/4] feat: clearly mark when a video is to be downloaded This shows a download icon instead of the play icon on top of the video if the video player isn't supported. --- lib/pages/chat/events/video_player.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pages/chat/events/video_player.dart b/lib/pages/chat/events/video_player.dart index dd7917b34..5cb5cf913 100644 --- a/lib/pages/chat/events/video_player.dart +++ b/lib/pages/chat/events/video_player.dart @@ -170,7 +170,9 @@ class EventVideoPlayerState extends State { strokeWidth: 2, ), ) - : const Icon(Icons.play_circle_outlined), + : _supportsVideoPlayer + ? const Icon(Icons.play_circle_outlined) + : const Icon(Icons.file_download_outlined), tooltip: _isDownloading ? L10n.of(context).loadingPleaseWait : L10n.of(context).videoWithSize(