vishnukvmd 2 лет назад
Родитель
Сommit
4d09bff81e

+ 1 - 1
ios/Podfile.lock

@@ -321,7 +321,7 @@ SPEC CHECKSUMS:
   FirebaseInstallations: 0a115432c4e223c5ab20b0dbbe4cbefa793a0e8e
   FirebaseMessaging: 732623518591384f61c287e3d8f65294beb7ffb3
   fk_user_agent: 1f47ec39291e8372b1d692b50084b0d54103c545
-  Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
+  Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
   flutter_email_sender: 02d7443217d8c41483223627972bfdc09f74276b
   flutter_image_compress: 5a5e9aee05b6553048b8df1c3bc456d0afaac433
   flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721

+ 1 - 1
lib/core/cache/thumbnail_cache.dart

@@ -5,7 +5,7 @@ import 'package:photos/core/constants.dart';
 import 'package:photos/models/ente_file.dart';
 
 class ThumbnailLruCache {
-  static final LRUMap<String, Uint8List?> _map = LRUMap(1000);
+  static final LRUMap<String, Uint8List?> _map = LRUMap(250);
 
   static Uint8List? get(EnteFile enteFile, [int? size]) {
     return _map.get(

+ 11 - 6
lib/ui/huge_listview/lazy_loading_gallery.dart

@@ -5,8 +5,8 @@ import 'dart:math';
 
 import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
-import 'package:flutter/rendering.dart';
 import 'package:flutter/services.dart';
+import 'package:local_hero/local_hero.dart';
 import 'package:logging/logging.dart';
 import 'package:photos/core/constants.dart';
 import 'package:photos/core/event_bus.dart';
@@ -33,6 +33,7 @@ class LazyLoadingGallery extends StatefulWidget {
   final String tag;
   final String logTag;
   final Stream<int> currentIndexStream;
+  final int imagesPerRow;
 
   LazyLoadingGallery(
     this.files,
@@ -44,6 +45,7 @@ class LazyLoadingGallery extends StatefulWidget {
     this.tag,
     this.currentIndexStream, {
     this.logTag = "",
+    this.imagesPerRow,
     Key key,
   }) : super(key: key ?? UniqueKey());
 
@@ -251,6 +253,7 @@ class _LazyLoadingGalleryState extends State<LazyLoadingGallery> {
           _files.length > kRecycleLimit,
           _toggleSelectAllFromDay,
           _areAllFromDaySelected,
+          widget.imagesPerRow,
         ),
       );
     }
@@ -278,6 +281,7 @@ class LazyLoadingGridView extends StatefulWidget {
   final bool shouldRecycle;
   final ValueNotifier toggleSelectAllFromDay;
   final ValueNotifier areAllFilesSelected;
+  final int imagesPerRow;
 
   LazyLoadingGridView(
     this.tag,
@@ -287,7 +291,8 @@ class LazyLoadingGridView extends StatefulWidget {
     this.shouldRender,
     this.shouldRecycle,
     this.toggleSelectAllFromDay,
-    this.areAllFilesSelected, {
+    this.areAllFilesSelected,
+    this.imagesPerRow, {
     Key key,
   }) : super(key: key ?? UniqueKey());
 
@@ -383,10 +388,10 @@ class _LazyLoadingGridViewState extends State<LazyLoadingGridView> {
         return _buildFile(context, widget.filesInDay[index]);
       },
       itemCount: widget.filesInDay.length,
-      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
+      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
         crossAxisSpacing: 2,
         mainAxisSpacing: 2,
-        crossAxisCount: 4,
+        crossAxisCount: widget.imagesPerRow ?? 4,
       ),
       padding: const EdgeInsets.all(0),
     );
@@ -405,8 +410,8 @@ class _LazyLoadingGridViewState extends State<LazyLoadingGridView> {
         HapticFeedback.lightImpact();
         _selectFile(file);
       },
-      child: ClipRRect(
-        borderRadius: BorderRadius.circular(1),
+      child: LocalHero(
+        tag: widget.tag + file.tag,
         child: Stack(
           children: [
             Hero(

+ 0 - 2
lib/ui/viewer/file/thumbnail_widget.dart

@@ -179,7 +179,6 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
           _loadNetworkImage();
         } else {
           if (await doesLocalFileExist(widget.file) == false) {
-            _logger.info("Deleting file " + widget.file.tag);
             FilesDB.instance.deleteLocalFile(widget.file);
             Bus.instance.fire(
               LocalPhotosUpdatedEvent(
@@ -197,7 +196,6 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
         final imageProvider = Image.memory(thumbData).image;
         _cacheAndRender(imageProvider);
       }
-      ThumbnailLruCache.put(widget.file, thumbData, thumbnailSmallSize);
     }).catchError((e) {
       _logger.warning("Could not load image: ", e);
       _errorLoadingLocalThumbnail = true;

+ 124 - 69
lib/ui/viewer/gallery/gallery.dart

@@ -3,7 +3,9 @@
 import 'dart:async';
 
 import 'package:flutter/foundation.dart';
+import 'package:flutter/gestures.dart';
 import 'package:flutter/material.dart';
+import 'package:local_hero/local_hero.dart';
 import 'package:logging/logging.dart';
 import 'package:photos/core/constants.dart';
 import 'package:photos/core/event_bus.dart';
@@ -203,76 +205,118 @@ class _GalleryState extends State<Gallery> {
     return _getListView();
   }
 
+  int _imagesPerRow = 4;
+  ScaleUpdateDetails _lastScaleUpdateDetails;
+
   Widget _getListView() {
-    return HugeListView<List<File>>(
-      key: _hugeListViewKey,
-      controller: _itemScroller,
-      startIndex: 0,
-      totalCount: _collatedFiles.length,
-      isDraggableScrollbarEnabled: _collatedFiles.length > 10,
-      waitBuilder: (_) {
-        return const EnteLoadingWidget();
-      },
-      emptyResultBuilder: (_) {
-        final List<Widget> children = [];
-        if (widget.header != null) {
-          children.add(widget.header);
-        }
-        children.add(
-          Expanded(
-            child: widget.emptyState,
-          ),
-        );
-        if (widget.footer != null) {
-          children.add(widget.footer);
-        }
-        return Column(
-          mainAxisAlignment: MainAxisAlignment.spaceBetween,
-          children: children,
-        );
-      },
-      itemBuilder: (context, index) {
-        Widget gallery;
-        gallery = LazyLoadingGallery(
-          _collatedFiles[index],
-          index,
-          widget.reloadEvent,
-          widget.removalEventTypes,
-          widget.asyncLoader,
-          widget.selectedFiles,
-          widget.tagPrefix,
-          Bus.instance
-              .on<GalleryIndexUpdatedEvent>()
-              .where((event) => event.tag == widget.tagPrefix)
-              .map((event) => event.index),
-          logTag: _logTag,
-        );
-        if (widget.header != null && index == 0) {
-          gallery = Column(children: [widget.header, gallery]);
-        }
-        if (widget.footer != null && index == _collatedFiles.length - 1) {
-          gallery = Column(children: [gallery, widget.footer]);
-        }
-        return gallery;
-      },
-      labelTextBuilder: (int index) {
-        return getMonthAndYear(
-          DateTime.fromMicrosecondsSinceEpoch(
-            _collatedFiles[index][0].creationTime,
-          ),
-        );
-      },
-      thumbBackgroundColor:
-          Theme.of(context).colorScheme.galleryThumbBackgroundColor,
-      thumbDrawColor: Theme.of(context).colorScheme.galleryThumbDrawColor,
-      thumbPadding: widget.header != null
-          ? const EdgeInsets.only(top: 60)
-          : const EdgeInsets.all(0),
-      bottomSafeArea: widget.scrollBottomSafeArea,
-      firstShown: (int firstIndex) {
-        Bus.instance
-            .fire(GalleryIndexUpdatedEvent(widget.tagPrefix, firstIndex));
-      },
+    return LocalHeroScope(
+      duration: const Duration(milliseconds: 100),
+      child:
+          RawGestureDetector(
+        gestures: {
+          AllowMultipleGestureRecognizer: GestureRecognizerFactoryWithHandlers<
+              AllowMultipleGestureRecognizer>(
+            () => AllowMultipleGestureRecognizer(), //constructor
+            (AllowMultipleGestureRecognizer instance) {
+              instance.onUpdate = (details) {
+                if (details.pointerCount == 2) {
+                  _lastScaleUpdateDetails = details;
+                }
+              };
+              instance.onEnd = (details) {
+                if (_lastScaleUpdateDetails != null) {
+                  if (_lastScaleUpdateDetails.verticalScale > 1 &&
+                      _lastScaleUpdateDetails.horizontalScale > 1) {
+                    _logger.info("zoomed in");
+                    if (_imagesPerRow > 2) {
+                      _imagesPerRow--;
+                    }
+                  } else if (_lastScaleUpdateDetails.verticalScale < 1 &&
+                      _lastScaleUpdateDetails.horizontalScale < 1) {
+                    _logger.info("zoomed out");
+                    if (_imagesPerRow < 4) {
+                      _imagesPerRow++;
+                    }
+                  }
+                  _lastScaleUpdateDetails = null;
+                  setState(() {});
+                }
+              };
+            },
+          )
+        },
+        child: HugeListView<List<File>>(
+          key: _hugeListViewKey,
+          controller: _itemScroller,
+          startIndex: 0,
+          totalCount: _collatedFiles.length,
+          isDraggableScrollbarEnabled: _collatedFiles.length > 10,
+          waitBuilder: (_) {
+            return const EnteLoadingWidget();
+          },
+          emptyResultBuilder: (_) {
+            final List<Widget> children = [];
+            if (widget.header != null) {
+              children.add(widget.header);
+            }
+            children.add(
+              Expanded(
+                child: widget.emptyState,
+              ),
+            );
+            if (widget.footer != null) {
+              children.add(widget.footer);
+            }
+            return Column(
+              mainAxisAlignment: MainAxisAlignment.spaceBetween,
+              children: children,
+            );
+          },
+          itemBuilder: (context, index) {
+            Widget gallery;
+            gallery = LazyLoadingGallery(
+              _collatedFiles[index],
+              index,
+              widget.reloadEvent,
+              widget.removalEventTypes,
+              widget.asyncLoader,
+              widget.selectedFiles,
+              widget.tagPrefix,
+              Bus.instance
+                  .on<GalleryIndexUpdatedEvent>()
+                  .where((event) => event.tag == widget.tagPrefix)
+                  .map((event) => event.index),
+              logTag: _logTag,
+              imagesPerRow: _imagesPerRow,
+            );
+            if (widget.header != null && index == 0) {
+              gallery = Column(children: [widget.header, gallery]);
+            }
+            if (widget.footer != null && index == _collatedFiles.length - 1) {
+              gallery = Column(children: [gallery, widget.footer]);
+            }
+            return gallery;
+          },
+          labelTextBuilder: (int index) {
+            return getMonthAndYear(
+              DateTime.fromMicrosecondsSinceEpoch(
+                _collatedFiles[index][0].creationTime,
+              ),
+            );
+          },
+          thumbBackgroundColor:
+              Theme.of(context).colorScheme.galleryThumbBackgroundColor,
+          thumbDrawColor: Theme.of(context).colorScheme.galleryThumbDrawColor,
+          thumbPadding: widget.header != null
+              ? const EdgeInsets.only(top: 60)
+              : const EdgeInsets.all(0),
+          bottomSafeArea: widget.scrollBottomSafeArea,
+          firstShown: (int firstIndex) {
+            Bus.instance
+                .fire(GalleryIndexUpdatedEvent(widget.tagPrefix, firstIndex));
+          },
+        ),
+      ),
     );
   }
 
@@ -315,3 +359,14 @@ class GalleryIndexUpdatedEvent {
 
   GalleryIndexUpdatedEvent(this.tag, this.index);
 }
+
+// Custom Gesture Recognizer.
+// rejectGesture() is overridden. When a gesture is rejected, this is the function that is called. By default, it disposes of the
+// Recognizer and runs clean up. However we modified it so that instead the Recognizer is disposed of, it is actually manually added.
+// The result is instead you have one Recognizer winning the Arena, you have two. It is a win-win.
+class AllowMultipleGestureRecognizer extends ScaleGestureRecognizer {
+  @override
+  void rejectGesture(int pointer) {
+    acceptGesture(pointer);
+  }
+}

+ 1 - 1
lib/utils/thumbnail_util.dart

@@ -62,7 +62,7 @@ Future<Uint8List> getThumbnailFromServer(File file) async {
 
 Future<Uint8List> getThumbnailFromLocal(
   File file, {
-  int size = thumbnailSmallSize,
+  int size = thumbnailLargeSize,
   int quality = thumbnailQuality,
 }) async {
   final lruCachedThumbnail = ThumbnailLruCache.get(file, size);

+ 21 - 21
pubspec.lock

@@ -49,7 +49,7 @@ packages:
       name: async
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.8.2"
+    version: "2.9.0"
   background_fetch:
     dependency: "direct main"
     description:
@@ -98,14 +98,7 @@ packages:
       name: characters
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.2.0"
-  charcode:
-    dependency: transitive
-    description:
-      name: charcode
-      url: "https://pub.dartlang.org"
-    source: hosted
-    version: "1.3.1"
+    version: "1.2.1"
   chewie:
     dependency: "direct main"
     description:
@@ -119,7 +112,7 @@ packages:
       name: clock
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.0"
+    version: "1.1.1"
   collection:
     dependency: "direct main"
     description:
@@ -308,7 +301,7 @@ packages:
       name: fake_async
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.3.0"
+    version: "1.3.1"
   fast_base58:
     dependency: "direct main"
     description:
@@ -742,6 +735,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "1.1.11"
+  local_hero:
+    dependency: "direct main"
+    description:
+      name: local_hero
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.2.0"
   logging:
     dependency: "direct main"
     description:
@@ -762,14 +762,14 @@ packages:
       name: matcher
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.12.11"
+    version: "0.12.12"
   material_color_utilities:
     dependency: transitive
     description:
       name: material_color_utilities
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.1.4"
+    version: "0.1.5"
   media_extension:
     dependency: "direct main"
     description:
@@ -785,7 +785,7 @@ packages:
       name: meta
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.7.0"
+    version: "1.8.0"
   mime:
     dependency: transitive
     description:
@@ -913,7 +913,7 @@ packages:
       name: path
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.8.1"
+    version: "1.8.2"
   path_drawing:
     dependency: transitive
     description:
@@ -1254,7 +1254,7 @@ packages:
       name: source_span
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.8.2"
+    version: "1.9.0"
   sprintf:
     dependency: transitive
     description:
@@ -1310,7 +1310,7 @@ packages:
       name: string_scanner
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.0"
+    version: "1.1.1"
   syncfusion_flutter_core:
     dependency: "direct main"
     description:
@@ -1338,28 +1338,28 @@ packages:
       name: term_glyph
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.2.0"
+    version: "1.2.1"
   test:
     dependency: "direct dev"
     description:
       name: test
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.21.1"
+    version: "1.21.4"
   test_api:
     dependency: transitive
     description:
       name: test_api
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.4.9"
+    version: "0.4.12"
   test_core:
     dependency: transitive
     description:
       name: test_core
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.4.13"
+    version: "0.4.16"
   timezone:
     dependency: transitive
     description:

+ 1 - 0
pubspec.yaml

@@ -75,6 +75,7 @@ dependencies:
   like_button: ^2.0.2
   loading_animations: ^2.1.0
   local_auth: ^1.1.5
+  local_hero: ^0.2.0
   logging: ^1.0.1
   lottie: ^1.2.2
   media_extension: