From c8d3faec6d632548cbd067ce598b0623650d2e1b Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 18 Apr 2023 11:23:56 -0500 Subject: [PATCH] fix(mobile): video player disposes early (#2275) * fix(mobile): video player disposes early * fixed show download button based on asset state * style icon size * disable screensleep on video player * better position for video * better scroll physics on iOS --- .../asset_viewer/ui/top_control_app_bar.dart | 10 ++- .../asset_viewer/views/gallery_viewer.dart | 6 +- .../asset_viewer/views/video_viewer_page.dart | 70 ++++++++++--------- mobile/lib/shared/models/asset.dart | 2 + 4 files changed, 53 insertions(+), 35 deletions(-) diff --git a/mobile/lib/modules/asset_viewer/ui/top_control_app_bar.dart b/mobile/lib/modules/asset_viewer/ui/top_control_app_bar.dart index 6bfdff7487..b3267098df 100644 --- a/mobile/lib/modules/asset_viewer/ui/top_control_app_bar.dart +++ b/mobile/lib/modules/asset_viewer/ui/top_control_app_bar.dart @@ -27,7 +27,7 @@ class TopControlAppBar extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - const double iconSize = 18.0; + const double iconSize = 22.0; Widget buildFavoriteButton() { return IconButton( @@ -82,6 +82,14 @@ class TopControlAppBar extends HookConsumerWidget { color: Colors.grey[200], ), ), + if (asset.storage == AssetState.merged) + IconButton( + onPressed: onDownloadPressed, + icon: Icon( + Icons.cloud_download_outlined, + color: Colors.grey[200], + ), + ), if (asset.isRemote) IconButton( onPressed: () { diff --git a/mobile/lib/modules/asset_viewer/views/gallery_viewer.dart b/mobile/lib/modules/asset_viewer/views/gallery_viewer.dart index b9b3f8e0ed..d1508225c5 100644 --- a/mobile/lib/modules/asset_viewer/views/gallery_viewer.dart +++ b/mobile/lib/modules/asset_viewer/views/gallery_viewer.dart @@ -301,7 +301,8 @@ class GalleryViewerPage extends HookConsumerWidget { onFavorite: () { toggleFavorite(assetList[indexOfAsset.value]); }, - onDownloadPressed: assetList[indexOfAsset.value].isLocal + onDownloadPressed: assetList[indexOfAsset.value].storage == + AssetState.local ? null : () { ref.watch(imageViewerStateProvider.notifier).downloadAsset( @@ -391,7 +392,7 @@ class GalleryViewerPage extends HookConsumerWidget { scrollPhysics: isZoomed.value ? const NeverScrollableScrollPhysics() // Don't allow paging while scrolled in : (Platform.isIOS - ? const BouncingScrollPhysics() // Use bouncing physics for iOS + ? const ScrollPhysics() // Use bouncing physics for iOS : const ClampingScrollPhysics() // Use heavy physics for Android ), itemCount: assetList.length, @@ -516,6 +517,7 @@ class GalleryViewerPage extends HookConsumerWidget { filterQuality: FilterQuality.high, maxScale: 1.0, minScale: 1.0, + basePosition: Alignment.bottomCenter, child: SafeArea( child: VideoViewerPage( onPlaying: () => isPlayingVideo.value = true, diff --git a/mobile/lib/modules/asset_viewer/views/video_viewer_page.dart b/mobile/lib/modules/asset_viewer/views/video_viewer_page.dart index d9a4524b17..37f6f98774 100644 --- a/mobile/lib/modules/asset_viewer/views/video_viewer_page.dart +++ b/mobile/lib/modules/asset_viewer/views/video_viewer_page.dart @@ -30,10 +30,10 @@ class VideoViewerPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - if (asset.isLocal) { + if (asset.storage == AssetState.local && asset.livePhotoVideoId == null) { final AsyncValue videoFile = ref.watch(_fileFamily(asset.local!)); return videoFile.when( - data: (data) => VideoThumbnailPlayer( + data: (data) => VideoPlayer( file: data, isMotionVideo: false, onVideoEnded: () {}, @@ -59,7 +59,7 @@ class VideoViewerPage extends HookConsumerWidget { return Stack( children: [ - VideoThumbnailPlayer( + VideoPlayer( url: videoUrl, jwtToken: Store.get(StoreKey.accessToken), isMotionVideo: isMotionVideo, @@ -85,7 +85,7 @@ final _fileFamily = return file; }); -class VideoThumbnailPlayer extends StatefulWidget { +class VideoPlayer extends StatefulWidget { final String? url; final String? jwtToken; final File? file; @@ -95,7 +95,7 @@ class VideoThumbnailPlayer extends StatefulWidget { final Function()? onPlaying; final Function()? onPaused; - const VideoThumbnailPlayer({ + const VideoPlayer({ Key? key, this.url, this.jwtToken, @@ -107,10 +107,10 @@ class VideoThumbnailPlayer extends StatefulWidget { }) : super(key: key); @override - State createState() => _VideoThumbnailPlayerState(); + State createState() => _VideoPlayerState(); } -class _VideoThumbnailPlayerState extends State { +class _VideoPlayerState extends State { late VideoPlayerController videoPlayerController; ChewieController? chewieController; @@ -120,14 +120,17 @@ class _VideoThumbnailPlayerState extends State { initializePlayer(); videoPlayerController.addListener(() { - if (videoPlayerController.value.isPlaying) { - widget.onPlaying?.call(); - } else if (!videoPlayerController.value.isPlaying) { - widget.onPaused?.call(); - } - if (videoPlayerController.value.position == - videoPlayerController.value.duration) { - widget.onVideoEnded(); + if (videoPlayerController.value.isInitialized) { + if (videoPlayerController.value.isPlaying) { + widget.onPlaying?.call(); + } else if (!videoPlayerController.value.isPlaying) { + widget.onPaused?.call(); + } + + if (videoPlayerController.value.position == + videoPlayerController.value.duration) { + widget.onVideoEnded(); + } } }); } @@ -145,14 +148,14 @@ class _VideoThumbnailPlayerState extends State { _createChewieController(); setState(() {}); } catch (e) { - debugPrint("ERROR initialize video player"); + debugPrint("ERROR initialize video player $e"); } } _createChewieController() { chewieController = ChewieController( controlsSafeAreaMinimum: const EdgeInsets.only( - bottom: 156, + bottom: 100, ), showOptions: true, showControlsOnInitialize: false, @@ -160,6 +163,7 @@ class _VideoThumbnailPlayerState extends State { autoPlay: true, autoInitialize: true, allowFullScreen: true, + allowedScreenSleep: false, showControls: !widget.isMotionVideo, hideControlsTimer: const Duration(seconds: 5), ); @@ -175,20 +179,22 @@ class _VideoThumbnailPlayerState extends State { @override Widget build(BuildContext context) { - return chewieController?.videoPlayerController.value.isInitialized == true - ? SizedBox( - child: Chewie( - controller: chewieController!, - ), - ) - : const Center( - child: SizedBox( - width: 75, - height: 75, - child: CircularProgressIndicator.adaptive( - strokeWidth: 2, - ), - ), - ); + if (chewieController?.videoPlayerController.value.isInitialized == true) { + return SizedBox( + child: Chewie( + controller: chewieController!, + ), + ); + } else { + return const Center( + child: SizedBox( + width: 75, + height: 75, + child: CircularProgressIndicator.adaptive( + strokeWidth: 2, + ), + ), + ); + } } } diff --git a/mobile/lib/shared/models/asset.dart b/mobile/lib/shared/models/asset.dart index f39a53eb2a..a2e23268c9 100644 --- a/mobile/lib/shared/models/asset.dart +++ b/mobile/lib/shared/models/asset.dart @@ -371,6 +371,8 @@ class Asset { "fileName": "$fileName", "isFavorite": $isFavorite, "isLocal": $isLocal, + "isRemote: $isRemote, + "storage": $storage, "width": ${width ?? "N/A"}, "height": ${height ?? "N/A"}, "isArchived": $isArchived