Просмотр исходного кода

Set the zoom-scale correctly once full-res image has loaded

vishnukvmd 2 лет назад
Родитель
Сommit
06c28c615f
1 измененных файлов с 51 добавлено и 1 удалено
  1. 51 1
      lib/ui/viewer/file/zoomable_image.dart

+ 51 - 1
lib/ui/viewer/file/zoomable_image.dart

@@ -35,7 +35,7 @@ class ZoomableImage extends StatefulWidget {
 
 class _ZoomableImageState extends State<ZoomableImage>
     with SingleTickerProviderStateMixin {
-  final Logger _logger = Logger("ZoomableImage");
+  late Logger _logger;
   late File _photo;
   ImageProvider? _imageProvider;
   bool _loadedSmallThumbnail = false;
@@ -45,10 +45,13 @@ class _ZoomableImageState extends State<ZoomableImage>
   bool _loadedFinalImage = false;
   ValueChanged<PhotoViewScaleState>? _scaleStateChangedCallback;
   bool _isZooming = false;
+  PhotoViewController _photoViewController = PhotoViewController();
+  int? _thumbnailWidth;
 
   @override
   void initState() {
     _photo = widget.photo;
+    _logger = Logger("ZoomableImage_" + _photo.displayName);
     debugPrint('initState for ${_photo.toString()}');
     _scaleStateChangedCallback = (value) {
       if (widget.shouldDisableScroll != null) {
@@ -61,6 +64,12 @@ class _ZoomableImageState extends State<ZoomableImage>
     super.initState();
   }
 
+  @override
+  void dispose() {
+    _photoViewController.dispose();
+    super.dispose();
+  }
+
   @override
   Widget build(BuildContext context) {
     if (_photo.isRemoteFile) {
@@ -75,6 +84,7 @@ class _ZoomableImageState extends State<ZoomableImage>
         axis: Axis.vertical,
         child: PhotoView(
           imageProvider: _imageProvider,
+          controller: _photoViewController,
           scaleStateChangedCallback: _scaleStateChangedCallback,
           minScale: PhotoViewComputedScale.contained,
           gaplessPlayback: true,
@@ -106,6 +116,7 @@ class _ZoomableImageState extends State<ZoomableImage>
       if (cachedThumbnail != null) {
         _imageProvider = Image.memory(cachedThumbnail).image;
         _loadedSmallThumbnail = true;
+        _captureThumbnailDimensions(_imageProvider!);
       } else {
         getThumbnailFromServer(_photo).then((file) {
           final imageProvider = Image.memory(file).image;
@@ -115,6 +126,7 @@ class _ZoomableImageState extends State<ZoomableImage>
                 setState(() {
                   _imageProvider = imageProvider;
                   _loadedSmallThumbnail = true;
+                  _captureThumbnailDimensions(_imageProvider!);
                 });
               }
             }).catchError((e) {
@@ -211,14 +223,52 @@ class _ZoomableImageState extends State<ZoomableImage>
     if (mounted) {
       precacheImage(imageProvider, context).then((value) {
         if (mounted) {
+          _updatePhotoViewController(imageProvider);
           setState(() {
             _imageProvider = imageProvider;
             _loadedFinalImage = true;
+            _logger.info("Final image loaded");
           });
         }
       });
     }
   }
 
+  void _captureThumbnailDimensions(ImageProvider imageProvider) {
+    imageProvider.resolve(const ImageConfiguration()).addListener(
+      ImageStreamListener(
+        ((imageInfo, _) {
+          _thumbnailWidth = imageInfo.image.width;
+        }),
+      ),
+    );
+  }
+
+  void _updatePhotoViewController(ImageProvider<Object> imageProvider) {
+    imageProvider.resolve(const ImageConfiguration()).addListener(
+      ImageStreamListener(
+        ((imageInfo, _) {
+          if (_loadedFinalImage ||
+              _thumbnailWidth == null ||
+              _photoViewController.scale == null) {
+            return;
+          }
+          final scale = _photoViewController.scale! /
+              (imageInfo.image.width / _thumbnailWidth!);
+          final currentPosition = _photoViewController.value.position;
+          final positionScaleFactor = 1 / scale;
+          final newPosition = currentPosition.scale(
+            positionScaleFactor,
+            positionScaleFactor,
+          );
+          _photoViewController = PhotoViewController(
+            initialPosition: newPosition,
+            initialScale: scale,
+          );
+        }),
+      ),
+    );
+  }
+
   bool _isGIF() => _photo.displayName.toLowerCase().endsWith(".gif");
 }