Browse Source

Refactor selection (#1278)

Ashil 2 years ago
parent
commit
060b5a457d

+ 33 - 19
lib/models/selected_files.dart

@@ -6,35 +6,49 @@ import 'package:photos/models/file.dart';
 
 class SelectedFiles extends ChangeNotifier {
   final files = <File>{};
-  final lastSelections = <File>{};
 
-  void toggleSelection(File file) {
+  ///This variable is used to track the files that were involved in last selection
+  ///operation (select/unselect). Each [LazyGridView] checks this variable on
+  ///change in [SelectedFiles] to see if any of it's files were involved in last
+  ///select/unselect operation. If yes, then it will rebuild itself.
+  final lastSelectionOperationFiles = <File>{};
+
+  void toggleSelection(File fileToToggle) {
     // To handle the cases, where the file might have changed due to upload
     // or any other update, using file.generatedID to track if this file was already
     // selected or not
     final File? alreadySelected = files.firstWhereOrNull(
-      (element) => _isMatch(file, element),
+      (element) => _isMatch(fileToToggle, element),
     );
     if (alreadySelected != null) {
       files.remove(alreadySelected);
     } else {
-      files.add(file);
+      files.add(fileToToggle);
     }
-    lastSelections.clear();
-    lastSelections.add(file);
+    lastSelectionOperationFiles.clear();
+    lastSelectionOperationFiles.add(fileToToggle);
     notifyListeners();
   }
 
-  void selectAll(Set<File> selectedFiles) {
-    files.addAll(selectedFiles);
-    lastSelections.clear();
-    lastSelections.addAll(selectedFiles);
+  void toggleGroupSelection(Set<File> filesToToggle) {
+    if (files.containsAll(filesToToggle)) {
+      unSelectAll(filesToToggle);
+    } else {
+      selectAll(filesToToggle);
+    }
+  }
+
+  void selectAll(Set<File> filesToSelect) {
+    files.addAll(filesToSelect);
+    lastSelectionOperationFiles.clear();
+    lastSelectionOperationFiles.addAll(filesToSelect);
     notifyListeners();
   }
 
-  void unSelectAll(Set<File> selectedFiles, {bool skipNotify = false}) {
-    files.removeWhere((file) => selectedFiles.contains(file));
-    lastSelections.clear();
+  void unSelectAll(Set<File> filesToUnselect, {bool skipNotify = false}) {
+    files.removeWhere((file) => filesToUnselect.contains(file));
+    lastSelectionOperationFiles.clear();
+    lastSelectionOperationFiles.addAll(filesToUnselect);
     if (!skipNotify) {
       notifyListeners();
     }
@@ -48,7 +62,7 @@ class SelectedFiles extends ChangeNotifier {
   }
 
   bool isPartOfLastSelected(File file) {
-    final File? matchedFile = lastSelections.firstWhereOrNull(
+    final File? matchedFile = lastSelectionOperationFiles.firstWhereOrNull(
       (element) => _isMatch(file, element),
     );
     return matchedFile != null;
@@ -67,15 +81,15 @@ class SelectedFiles extends ChangeNotifier {
 
   void clearAll() {
     Bus.instance.fire(ClearSelectionsEvent());
-    lastSelections.addAll(files);
+    lastSelectionOperationFiles.addAll(files);
     files.clear();
     notifyListeners();
   }
 
-  /// Retains only the files that are present in the [images] set. Takes the
-  /// intersection of the two sets.
-  void filesToRetain(Set<File> images) {
-    files.retainAll(images);
+  ///Retains only the files that are present in the [filesToRetain] set in
+  ///[files]. Takes the intersection of the two sets.
+  void retainFiles(Set<File> filesToRetain) {
+    files.retainAll(filesToRetain);
     notifyListeners();
   }
 }

+ 1 - 1
lib/ui/map/map_pull_up_gallery.dart

@@ -121,7 +121,7 @@ class _MapPullUpGalleryState extends State<MapPullUpGallery> {
                   logger.info("Visible images: ${images.length}");
                   //To retain only selected files that are in view (visible)
                   WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
-                    _selectedFiles.filesToRetain(images.toSet());
+                    _selectedFiles.retainFiles(images.toSet());
                   });
 
                   if (images.isEmpty) {

+ 1 - 26
lib/ui/viewer/gallery/component/grid/lazy_grid_view.dart

@@ -18,8 +18,6 @@ class LazyGridView extends StatefulWidget {
   final SelectedFiles? selectedFiles;
   final bool shouldRender;
   final bool shouldRecycle;
-  final ValueNotifier toggleSelectAllFromDay;
-  final ValueNotifier areAllFilesSelected;
   final int? photoGridSize;
   final bool limitSelectionToOne;
 
@@ -30,8 +28,6 @@ class LazyGridView extends StatefulWidget {
     this.selectedFiles,
     this.shouldRender,
     this.shouldRecycle,
-    this.toggleSelectAllFromDay,
-    this.areAllFilesSelected,
     this.photoGridSize, {
     this.limitSelectionToOne = false,
     Key? key,
@@ -57,7 +53,6 @@ class _LazyGridViewState extends State<LazyGridView> {
         setState(() {});
       }
     });
-    widget.toggleSelectAllFromDay.addListener(_toggleSelectAllFromDayListener);
     super.initState();
   }
 
@@ -65,8 +60,7 @@ class _LazyGridViewState extends State<LazyGridView> {
   void dispose() {
     widget.selectedFiles?.removeListener(_selectedFilesListener);
     _clearSelectionsEvent.cancel();
-    widget.toggleSelectAllFromDay
-        .removeListener(_toggleSelectAllFromDayListener);
+
     super.dispose();
   }
 
@@ -106,13 +100,6 @@ class _LazyGridViewState extends State<LazyGridView> {
   }
 
   void _selectedFilesListener() {
-    if (widget.selectedFiles!.files
-        .toSet()
-        .containsAll(widget.filesInGroup.toSet())) {
-      widget.areAllFilesSelected.value = true;
-    } else {
-      widget.areAllFilesSelected.value = false;
-    }
     bool shouldRefresh = false;
     for (final file in widget.filesInGroup) {
       if (widget.selectedFiles!.isPartOfLastSelected(file)) {
@@ -123,16 +110,4 @@ class _LazyGridViewState extends State<LazyGridView> {
       setState(() {});
     }
   }
-
-  void _toggleSelectAllFromDayListener() {
-    if (widget.selectedFiles!.files
-        .toSet()
-        .containsAll(widget.filesInGroup.toSet())) {
-      setState(() {
-        widget.selectedFiles!.unSelectAll(widget.filesInGroup.toSet());
-      });
-    } else {
-      widget.selectedFiles!.selectAll(widget.filesInGroup.toSet());
-    }
-  }
 }

+ 0 - 6
lib/ui/viewer/gallery/component/group/group_gallery.dart

@@ -13,8 +13,6 @@ class GroupGallery extends StatelessWidget {
   final String tag;
   final GalleryLoader asyncLoader;
   final SelectedFiles? selectedFiles;
-  final ValueNotifier<bool> toggleSelectAllFromDay;
-  final ValueNotifier<bool> areAllFromDaySelected;
   final bool limitSelectionToOne;
 
   const GroupGallery({
@@ -23,8 +21,6 @@ class GroupGallery extends StatelessWidget {
     required this.tag,
     required this.asyncLoader,
     required this.selectedFiles,
-    required this.toggleSelectAllFromDay,
-    required this.areAllFromDaySelected,
     required this.limitSelectionToOne,
     super.key,
   });
@@ -47,8 +43,6 @@ class GroupGallery extends StatelessWidget {
           selectedFiles,
           index == 0,
           files.length > kRecycleLimit,
-          toggleSelectAllFromDay,
-          areAllFromDaySelected,
           photoGridSize,
           limitSelectionToOne: limitSelectionToOne,
         ),

+ 29 - 18
lib/ui/viewer/gallery/component/group/lazy_group_gallery.dart

@@ -51,6 +51,8 @@ class LazyGroupGallery extends StatefulWidget {
 
 class _LazyGroupGalleryState extends State<LazyGroupGallery> {
   static const numberOfGroupsToRenderBeforeAndAfter = 8;
+  late final ValueNotifier<bool> _showSelectAllButtonNotifier;
+  late final ValueNotifier<bool> _areAllFromGroupSelectedNotifer;
 
   late Logger _logger;
 
@@ -58,16 +60,14 @@ class _LazyGroupGalleryState extends State<LazyGroupGallery> {
   late StreamSubscription<FilesUpdatedEvent>? _reloadEventSubscription;
   late StreamSubscription<int> _currentIndexSubscription;
   bool? _shouldRender;
-  final ValueNotifier<bool> _toggleSelectAllFromDay = ValueNotifier(false);
-  late final ValueNotifier<bool> _showSelectAllButton;
-  final ValueNotifier<bool> _areAllFromDaySelected = ValueNotifier(false);
 
   @override
   void initState() {
-    //this is for removing the 'select all from day' icon on unselecting all files with 'cancel'
     super.initState();
+    _areAllFromGroupSelectedNotifer = ValueNotifier(_areAllFromGroupSelected());
+
     widget.selectedFiles?.addListener(_selectedFilesListener);
-    _showSelectAllButton = ValueNotifier(widget.showSelectAllByDefault);
+    _showSelectAllButtonNotifier = ValueNotifier(widget.showSelectAllByDefault);
     _init();
   }
 
@@ -89,6 +89,16 @@ class _LazyGroupGalleryState extends State<LazyGroupGallery> {
     });
   }
 
+  bool _areAllFromGroupSelected() {
+    if (widget.selectedFiles != null &&
+        widget.selectedFiles!.files.length >= widget.files.length) {
+      widget.selectedFiles!.files.containsAll(widget.files);
+      return widget.selectedFiles!.files.containsAll(widget.files);
+    } else {
+      return false;
+    }
+  }
+
   Future _onReload(FilesUpdatedEvent event) async {
     final DateTime groupDate =
         DateTime.fromMicrosecondsSinceEpoch(_files[0].creationTime!);
@@ -133,10 +143,8 @@ class _LazyGroupGalleryState extends State<LazyGroupGallery> {
   void dispose() {
     _reloadEventSubscription?.cancel();
     _currentIndexSubscription.cancel();
+    _areAllFromGroupSelectedNotifer.dispose();
     widget.selectedFiles?.removeListener(_selectedFilesListener);
-    _toggleSelectAllFromDay.dispose();
-    _showSelectAllButton.dispose();
-    _areAllFromDaySelected.dispose();
     super.dispose();
   }
 
@@ -167,7 +175,7 @@ class _LazyGroupGalleryState extends State<LazyGroupGallery> {
             widget.limitSelectionToOne
                 ? const SizedBox.shrink()
                 : ValueListenableBuilder(
-                    valueListenable: _showSelectAllButton,
+                    valueListenable: _showSelectAllButtonNotifier,
                     builder: (context, dynamic value, _) {
                       return !value
                           ? const SizedBox.shrink()
@@ -177,7 +185,8 @@ class _LazyGroupGalleryState extends State<LazyGroupGallery> {
                                 width: 48,
                                 height: 44,
                                 child: ValueListenableBuilder(
-                                  valueListenable: _areAllFromDaySelected,
+                                  valueListenable:
+                                      _areAllFromGroupSelectedNotifer,
                                   builder: (context, dynamic value, _) {
                                     return value
                                         ? const Icon(
@@ -194,10 +203,9 @@ class _LazyGroupGalleryState extends State<LazyGroupGallery> {
                                 ),
                               ),
                               onTap: () {
-                                //this value has no significance
-                                //changing only to notify the listeners
-                                _toggleSelectAllFromDay.value =
-                                    !_toggleSelectAllFromDay.value;
+                                widget.selectedFiles?.toggleGroupSelection(
+                                  _files.toSet(),
+                                );
                               },
                             );
                     },
@@ -211,8 +219,6 @@ class _LazyGroupGalleryState extends State<LazyGroupGallery> {
                 tag: widget.tag,
                 asyncLoader: widget.asyncLoader,
                 selectedFiles: widget.selectedFiles,
-                toggleSelectAllFromDay: _toggleSelectAllFromDay,
-                areAllFromDaySelected: _areAllFromDaySelected,
                 limitSelectionToOne: widget.limitSelectionToOne,
               )
             // todo: perf eval should we have separate PlaceHolder for Groups
@@ -226,10 +232,15 @@ class _LazyGroupGalleryState extends State<LazyGroupGallery> {
   }
 
   void _selectedFilesListener() {
+    if (widget.selectedFiles == null) return;
+    _areAllFromGroupSelectedNotifer.value =
+        widget.selectedFiles!.files.containsAll(widget.files.toSet());
+
+    //Can remove this if we decide to show select all by default for all galleries
     if (widget.selectedFiles!.files.isEmpty && !widget.showSelectAllByDefault) {
-      _showSelectAllButton.value = false;
+      _showSelectAllButtonNotifier.value = false;
     } else {
-      _showSelectAllButton.value = true;
+      _showSelectAllButtonNotifier.value = true;
     }
   }
 }