Преглед на файлове

Motion photos use placeholder image for more seamless loading

Marty Fuhry преди 2 години
родител
ревизия
1242754690
променени са 2 файла, в които са добавени 59 реда и са изтрити 36 реда
  1. 39 30
      mobile/lib/modules/asset_viewer/views/gallery_viewer.dart
  2. 20 6
      mobile/lib/modules/asset_viewer/views/video_viewer_page.dart

+ 39 - 30
mobile/lib/modules/asset_viewer/views/gallery_viewer.dart

@@ -373,6 +373,26 @@ class GalleryViewerPage extends HookConsumerWidget {
       );
     }
 
+    ImageProvider imageProvider(Asset asset) {
+      if (asset.isLocal) {
+        return localImageProvider(asset);
+      } else {
+        if (isLoadOriginal.value) {
+          return originalImageProvider(asset);
+        } else if (isLoadPreview.value) {
+          return remoteThumbnailImageProvider(
+            asset,
+            api.ThumbnailFormat.JPEG,
+          );
+        } else {
+          return remoteThumbnailImageProvider(
+            asset,
+            api.ThumbnailFormat.WEBP,
+          );
+        }
+      }
+    }
+
     return Scaffold(
       backgroundColor: Colors.black,
       body: WillPopScope(
@@ -466,26 +486,10 @@ class GalleryViewerPage extends HookConsumerWidget {
                   : null,
               builder: (context, index) {
                 getAssetExif();
+                // Create image provider
+                final ImageProvider provider = imageProvider(assetList[index]);
+
                 if (assetList[index].isImage && !isPlayingMotionVideo.value) {
-                  // Show photo
-                  final ImageProvider provider;
-                  if (assetList[index].isLocal) {
-                    provider = localImageProvider(assetList[index]);
-                  } else {
-                    if (isLoadOriginal.value) {
-                      provider = originalImageProvider(assetList[index]);
-                    } else if (isLoadPreview.value) {
-                      provider = remoteThumbnailImageProvider(
-                        assetList[index],
-                        api.ThumbnailFormat.JPEG,
-                      );
-                    } else {
-                      provider = remoteThumbnailImageProvider(
-                        assetList[index],
-                        api.ThumbnailFormat.WEBP,
-                      );
-                    }
-                  }
                   return PhotoViewGalleryPageOptions(
                     onDragStart: (_, details, __) =>
                         localPosition = details.localPosition,
@@ -518,18 +522,23 @@ class GalleryViewerPage extends HookConsumerWidget {
                     maxScale: 1.0,
                     minScale: 1.0,
                     basePosition: Alignment.bottomCenter,
-                    child: SafeArea(
-                      child: VideoViewerPage(
-                        onPlaying: () => isPlayingVideo.value = true,
-                        onPaused: () => isPlayingVideo.value = false,
-                        asset: assetList[index],
-                        isMotionVideo: isPlayingMotionVideo.value,
-                        onVideoEnded: () {
-                          if (isPlayingMotionVideo.value) {
-                            isPlayingMotionVideo.value = false;
-                          }
-                        },
+                    child: VideoViewerPage(
+                      onPlaying: () => isPlayingVideo.value = true,
+                      onPaused: () => isPlayingVideo.value = false,
+                      asset: assetList[index],
+                      isMotionVideo: isPlayingMotionVideo.value,
+                      placeholder: Image(
+                        image: provider,
+                        fit: BoxFit.fitWidth,
+                        height: MediaQuery.of(context).size.height,
+                        width: MediaQuery.of(context).size.width,
+                        alignment: Alignment.center,
                       ),
+                      onVideoEnded: () {
+                        if (isPlayingMotionVideo.value) {
+                          isPlayingMotionVideo.value = false;
+                        }
+                      },
                     ),
                   );
                 }

+ 20 - 6
mobile/lib/modules/asset_viewer/views/video_viewer_page.dart

@@ -15,6 +15,7 @@ import 'package:video_player/video_player.dart';
 class VideoViewerPage extends HookConsumerWidget {
   final Asset asset;
   final bool isMotionVideo;
+  final Widget? placeholder;
   final VoidCallback onVideoEnded;
   final VoidCallback? onPlaying;
   final VoidCallback? onPaused;
@@ -26,6 +27,7 @@ class VideoViewerPage extends HookConsumerWidget {
     required this.onVideoEnded,
     this.onPlaying,
     this.onPaused,
+    this.placeholder,
   }) : super(key: key);
 
   @override
@@ -66,6 +68,7 @@ class VideoViewerPage extends HookConsumerWidget {
           onVideoEnded: onVideoEnded,
           onPaused: onPaused,
           onPlaying: onPlaying,
+          placeholder: placeholder,
         ),
         if (downloadAssetStatus == DownloadAssetStatus.loading)
           const Center(
@@ -95,6 +98,10 @@ class VideoPlayer extends StatefulWidget {
   final Function()? onPlaying;
   final Function()? onPaused;
 
+  /// The placeholder to show while the video is loading
+  /// usually, a thumbnail of the video
+  final Widget? placeholder;
+
   const VideoPlayer({
     Key? key,
     this.url,
@@ -104,6 +111,7 @@ class VideoPlayer extends StatefulWidget {
     required this.isMotionVideo,
     this.onPlaying,
     this.onPaused,
+    this.placeholder,
   }) : super(key: key);
 
   @override
@@ -186,12 +194,18 @@ class _VideoPlayerState extends State<VideoPlayer> {
         ),
       );
     } else {
-      return const Center(
-        child: SizedBox(
-          width: 75,
-          height: 75,
-          child: CircularProgressIndicator.adaptive(
-            strokeWidth: 2,
+      return SizedBox(
+        height: MediaQuery.of(context).size.height,
+        width: MediaQuery.of(context).size.width,
+        child: Center(
+          child: Stack(
+            children: [
+              if (widget.placeholder != null)
+                widget.placeholder!,
+              const Center(
+                child: ImmichLoadingIndicator(),
+              ),
+            ],
           ),
         ),
       );