Selaa lähdekoodia

Merge pull request #474 from ente-io/part_5_local_file_speed

Part 5: Fix minor issues for while showing local files
Neeraj Gupta 2 vuotta sitten
vanhempi
commit
ff5117f55f

+ 6 - 6
lib/core/configuration.dart

@@ -56,8 +56,8 @@ class Configuration {
   static const keyShouldKeepDeviceAwake = "should_keep_device_awake";
   static const keyShouldHideFromRecents = "should_hide_from_recents";
   static const keyShouldShowLockScreen = "should_show_lock_screen";
-  static const keyHasSkippedBackupFolderSelection =
-      "has_skipped_backup_folder_selection";
+  static const keyHasSelectedAnyBackupFolder =
+      "has_selected_any_folder_for_backup";
   static const lastTempFolderClearTimeKey = "last_temp_folder_clear_time";
   static const nameKey = "name";
   static const secretKeyKey = "secret_key";
@@ -576,12 +576,12 @@ class Configuration {
     return _volatilePassword;
   }
 
-  Future<void> skipBackupFolderSelection() async {
-    await _preferences.setBool(keyHasSkippedBackupFolderSelection, true);
+  Future<void> setHasSelectedAnyBackupFolder(bool val) async {
+    await _preferences.setBool(keyHasSelectedAnyBackupFolder, val);
   }
 
-  bool hasSkippedBackupFolderSelection() {
-    return _preferences.getBool(keyHasSkippedBackupFolderSelection) ?? false;
+  bool hasSelectedAnyBackupFolder() {
+    return _preferences.getBool(keyHasSelectedAnyBackupFolder) ?? false;
   }
 
   bool hasSelectedAllFoldersForBackup() {

+ 4 - 3
lib/db/device_files_db.dart

@@ -128,7 +128,6 @@ extension DeviceFiles on FilesDB {
     return result;
   }
 
-  // todo: covert it to batch
   Future<void> insertLocalAssets(
     List<LocalPathAsset> localPathAssets, {
     bool shouldAutoBackup = false,
@@ -136,17 +135,18 @@ extension DeviceFiles on FilesDB {
     final Database db = await database;
     final Map<String, Set<String>> pathIDToLocalIDsMap = {};
     try {
+      final batch = db.batch();
       final Set<String> existingPathIds = await getDevicePathIDs();
       for (LocalPathAsset localPathAsset in localPathAssets) {
         pathIDToLocalIDsMap[localPathAsset.pathID] = localPathAsset.localIDs;
         if (existingPathIds.contains(localPathAsset.pathID)) {
-          await db.rawUpdate(
+          batch.rawUpdate(
             "UPDATE device_collections SET name = ? where id = "
             "?",
             [localPathAsset.pathName, localPathAsset.pathID],
           );
         } else {
-          await db.insert(
+          batch.insert(
             "device_collections",
             {
               "id": localPathAsset.pathID,
@@ -157,6 +157,7 @@ extension DeviceFiles on FilesDB {
           );
         }
       }
+      await batch.commit(noResult: true);
       // add the mappings for localIDs
       if (pathIDToLocalIDsMap.isNotEmpty) {
         await insertPathIDToLocalIDMapping(pathIDToLocalIDsMap);

+ 0 - 8
lib/models/collection_items.dart

@@ -1,16 +1,8 @@
 // @dart=2.9
 
 import 'package:photos/models/collection.dart';
-import 'package:photos/models/device_collection.dart';
 import 'package:photos/models/file.dart';
 
-class CollectionItems {
-  final List<DeviceCollection> deviceCollections;
-  final List<CollectionWithThumbnail> collections;
-
-  CollectionItems(this.deviceCollections, this.collections);
-}
-
 class CollectionWithThumbnail {
   final Collection collection;
   final File thumbnail;

+ 24 - 14
lib/services/local_sync_service.dart

@@ -149,23 +149,33 @@ class LocalSyncService {
     if (hasUpdated) {
       Bus.instance.fire(BackupFoldersUpdatedEvent());
     }
-    // migrate the backed up folder settings
-    if (!_prefs.containsKey(hasImportedDeviceCollections)) {
-      final pathsToBackUp = Configuration.instance.getPathsToBackUp();
-      final entriesToBackUp = Map.fromEntries(
-        result
-            .where((element) => pathsToBackUp.contains(element.item1.name))
-            .map((e) => MapEntry(e.item1.id, true)),
-      );
-      if (entriesToBackUp.isNotEmpty) {
-        await _db.updateDevicePathSyncStatus(entriesToBackUp);
-        Bus.instance.fire(BackupFoldersUpdatedEvent());
-      }
-      await _prefs.setBool(hasImportedDeviceCollections, true);
+    // migrate the backed up folder settings after first import is done remove
+    // after 6 months?
+    if (!_prefs.containsKey(hasImportedDeviceCollections) &&
+        _prefs.containsKey(kHasCompletedFirstImportKey)) {
+      await _migrateOldSettings(result);
     }
     return hasUpdated;
   }
 
+  Future<void> _migrateOldSettings(
+    List<Tuple2<AssetPathEntity, String>> result,
+  ) async {
+    final pathsToBackUp = Configuration.instance.getPathsToBackUp();
+    final entriesToBackUp = Map.fromEntries(
+      result
+          .where((element) => pathsToBackUp.contains(element.item1.name))
+          .map((e) => MapEntry(e.item1.id, true)),
+    );
+    if (entriesToBackUp.isNotEmpty) {
+      await _db.updateDevicePathSyncStatus(entriesToBackUp);
+      Bus.instance.fire(BackupFoldersUpdatedEvent());
+    }
+    await Configuration.instance
+        .setHasSelectedAnyBackupFolder(pathsToBackUp.isNotEmpty);
+    await _prefs.setBool(hasImportedDeviceCollections, true);
+  }
+
   bool isDeviceFileMigrationDone() {
     return _prefs.containsKey(hasImportedDeviceCollections);
   }
@@ -392,7 +402,7 @@ class LocalSyncService {
       if (hasGrantedLimitedPermissions()) {
         syncAll();
       } else {
-        sync();
+        sync().then((value) => _refreshDeviceFolderCountAndCover());
       }
     });
     PhotoManager.startChangeNotify();

+ 2 - 1
lib/services/remote_sync_service.dart

@@ -350,7 +350,7 @@ class RemoteSyncService {
         if (localIDsInOtherFileEntries.contains(pendingUpload.localID)) {
           entriesToDelete.add(pendingUpload.generatedID);
         } else {
-          pendingUpload.collectionID = -1;
+          pendingUpload.collectionID = null;
           entriesToUpdate.add(pendingUpload);
         }
       }
@@ -646,6 +646,7 @@ class RemoteSyncService {
           " remoteFiles seen first time",
     );
     if (needsGalleryReload) {
+      _logger.fine('force reload home gallery');
       Bus.instance.fire(ForceReloadHomeGalleryEvent());
     }
   }

+ 4 - 0
lib/ui/backup_folder_selection_page.dart

@@ -184,6 +184,10 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
                             }
                             await RemoteSyncService.instance
                                 .updateDeviceFolderSyncStatus(syncStatus);
+                            await Configuration.instance
+                                .setHasSelectedAnyBackupFolder(
+                              _selectedDevicePathIDs.isNotEmpty,
+                            );
                             await Configuration.instance
                                 .setSelectAllFoldersForBackup(
                               _allDevicePathIDs.length ==

+ 69 - 24
lib/ui/collections/device_folders_grid_view_widget.dart

@@ -1,19 +1,43 @@
 // @dart=2.9
 
+import 'dart:async';
+
 import 'package:flutter/material.dart';
+import 'package:photos/core/event_bus.dart';
+import 'package:photos/db/device_files_db.dart';
+import 'package:photos/db/files_db.dart';
+import 'package:photos/events/backup_folders_updated_event.dart';
 import 'package:photos/models/device_collection.dart';
 import 'package:photos/services/local_sync_service.dart';
 import 'package:photos/ui/collections/device_folder_icon_widget.dart';
-import 'package:photos/ui/viewer/gallery/empte_state.dart';
-
-class DeviceFoldersGridViewWidget extends StatelessWidget {
-  final List<DeviceCollection> deviceCollections;
+import 'package:photos/ui/common/loading_widget.dart';
+import 'package:photos/ui/viewer/gallery/empty_state.dart';
 
-  const DeviceFoldersGridViewWidget(
-    this.deviceCollections, {
+class DeviceFoldersGridViewWidget extends StatefulWidget {
+  const DeviceFoldersGridViewWidget({
     Key key,
   }) : super(key: key);
 
+  @override
+  State<DeviceFoldersGridViewWidget> createState() =>
+      _DeviceFoldersGridViewWidgetState();
+}
+
+class _DeviceFoldersGridViewWidgetState
+    extends State<DeviceFoldersGridViewWidget> {
+  StreamSubscription<BackupFoldersUpdatedEvent> _backupFoldersUpdatedEvent;
+
+  @override
+  void initState() {
+    _backupFoldersUpdatedEvent =
+        Bus.instance.on<BackupFoldersUpdatedEvent>().listen((event) {
+      if (mounted) {
+        setState(() {});
+      }
+    });
+    super.initState();
+  }
+
   @override
   Widget build(BuildContext context) {
     final bool isMigrationDone =
@@ -24,26 +48,47 @@ class DeviceFoldersGridViewWidget extends StatelessWidget {
         height: 170,
         child: Align(
           alignment: Alignment.centerLeft,
-          child: deviceCollections.isEmpty
-              ? (isMigrationDone
-                  ? const EmptyState()
-                  : const EmptyState(
-                      text: "Importing....",
-                    ))
-              : ListView.builder(
-                  shrinkWrap: true,
-                  scrollDirection: Axis.horizontal,
-                  padding: const EdgeInsets.fromLTRB(6, 0, 6, 0),
-                  physics: const ScrollPhysics(),
-                  // to disable GridView's scrolling
-                  itemBuilder: (context, index) {
-                    final deviceCollection = deviceCollections[index];
-                    return DeviceFolderIcon(deviceCollection);
-                  },
-                  itemCount: deviceCollections.length,
-                ),
+          child: FutureBuilder<List<DeviceCollection>>(
+            future: FilesDB.instance
+                .getDeviceCollections(includeCoverThumbnail: true),
+            builder: (context, snapshot) {
+              if (snapshot.hasData) {
+                return snapshot.data.isEmpty
+                    ? Padding(
+                        padding: const EdgeInsets.all(22),
+                        child: (isMigrationDone
+                            ? const EmptyState()
+                            : const EmptyState(
+                                text: "Importing....",
+                              )),
+                      )
+                    : ListView.builder(
+                        shrinkWrap: true,
+                        scrollDirection: Axis.horizontal,
+                        padding: const EdgeInsets.fromLTRB(6, 0, 6, 0),
+                        physics: const ScrollPhysics(),
+                        // to disable GridView's scrolling
+                        itemBuilder: (context, index) {
+                          final deviceCollection = snapshot.data[index];
+                          return DeviceFolderIcon(deviceCollection);
+                        },
+                        itemCount: snapshot.data.length,
+                      );
+              } else if (snapshot.hasError) {
+                return Text(snapshot.error.toString());
+              } else {
+                return const EnteLoadingWidget();
+              }
+            },
+          ),
         ),
       ),
     );
   }
+
+  @override
+  void dispose() {
+    _backupFoldersUpdatedEvent?.cancel();
+    super.dispose();
+  }
 }

+ 9 - 26
lib/ui/collections_gallery_widget.dart

@@ -6,14 +6,10 @@ import 'package:flutter/material.dart';
 import 'package:logging/logging.dart';
 import 'package:photos/core/configuration.dart';
 import 'package:photos/core/event_bus.dart';
-import 'package:photos/db/device_files_db.dart';
-import 'package:photos/db/files_db.dart';
-import 'package:photos/events/backup_folders_updated_event.dart';
 import 'package:photos/events/collection_updated_event.dart';
 import 'package:photos/events/local_photos_updated_event.dart';
 import 'package:photos/events/user_logged_out_event.dart';
 import 'package:photos/models/collection_items.dart';
-import 'package:photos/models/device_collection.dart';
 import 'package:photos/services/collections_service.dart';
 import 'package:photos/ui/collections/device_folders_grid_view_widget.dart';
 import 'package:photos/ui/collections/ente_section_title.dart';
@@ -22,7 +18,7 @@ import 'package:photos/ui/collections/remote_collections_grid_view_widget.dart';
 import 'package:photos/ui/collections/section_title.dart';
 import 'package:photos/ui/collections/trash_button_widget.dart';
 import 'package:photos/ui/common/loading_widget.dart';
-import 'package:photos/ui/viewer/gallery/empte_state.dart';
+import 'package:photos/ui/viewer/gallery/empty_state.dart';
 import 'package:photos/utils/local_settings.dart';
 
 class CollectionsGalleryWidget extends StatefulWidget {
@@ -38,7 +34,6 @@ class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget>
   final _logger = Logger("CollectionsGallery");
   StreamSubscription<LocalPhotosUpdatedEvent> _localFilesSubscription;
   StreamSubscription<CollectionUpdatedEvent> _collectionUpdatesSubscription;
-  StreamSubscription<BackupFoldersUpdatedEvent> _backupFoldersUpdatedEvent;
   StreamSubscription<UserLoggedOutEvent> _loggedOutEvent;
   AlbumSortKey sortKey;
   String _loadReason = "init";
@@ -59,11 +54,6 @@ class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget>
       _loadReason = (UserLoggedOutEvent).toString();
       setState(() {});
     });
-    _backupFoldersUpdatedEvent =
-        Bus.instance.on<BackupFoldersUpdatedEvent>().listen((event) {
-      _loadReason = (BackupFoldersUpdatedEvent).toString();
-      setState(() {});
-    });
     sortKey = LocalSettings.instance.albumSortKey();
     super.initState();
   }
@@ -72,7 +62,7 @@ class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget>
   Widget build(BuildContext context) {
     super.build(context);
     _logger.info("Building, trigger: $_loadReason");
-    return FutureBuilder<CollectionItems>(
+    return FutureBuilder<List<CollectionWithThumbnail>>(
       future: _getCollections(),
       builder: (context, snapshot) {
         if (snapshot.hasData) {
@@ -86,12 +76,9 @@ class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget>
     );
   }
 
-  Future<CollectionItems> _getCollections() async {
-    final filesDB = FilesDB.instance;
+  Future<List<CollectionWithThumbnail>> _getCollections() async {
     final collectionsService = CollectionsService.instance;
     final userID = Configuration.instance.getUserID();
-    final List<DeviceCollection> deviceCollections =
-        await filesDB.getDeviceCollections(includeCoverThumbnail: true);
     final List<CollectionWithThumbnail> collectionsWithThumbnail = [];
     final latestCollectionFiles =
         await collectionsService.getLatestCollectionFiles();
@@ -115,10 +102,12 @@ class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget>
         }
       },
     );
-    return CollectionItems(deviceCollections, collectionsWithThumbnail);
+    return collectionsWithThumbnail;
   }
 
-  Widget _getCollectionsGalleryWidget(CollectionItems items) {
+  Widget _getCollectionsGalleryWidget(
+    List<CollectionWithThumbnail> collections,
+  ) {
     final TextStyle trashAndHiddenTextStyle = Theme.of(context)
         .textTheme
         .subtitle1
@@ -134,12 +123,7 @@ class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget>
             const SizedBox(height: 12),
             const SectionTitle("On device"),
             const SizedBox(height: 12),
-            items.deviceCollections.isEmpty
-                ? const Padding(
-                    padding: EdgeInsets.all(22),
-                    child: EmptyState(),
-                  )
-                : DeviceFoldersGridViewWidget(items.deviceCollections),
+            const DeviceFoldersGridViewWidget(),
             const Padding(padding: EdgeInsets.all(4)),
             const Divider(),
             Row(
@@ -152,7 +136,7 @@ class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget>
             ),
             const SizedBox(height: 12),
             Configuration.instance.hasConfiguredAccount()
-                ? RemoteCollectionsGridViewWidget(items.collections)
+                ? RemoteCollectionsGridViewWidget(collections)
                 : const EmptyState(),
             const SizedBox(height: 10),
             const Divider(),
@@ -247,7 +231,6 @@ class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget>
     _localFilesSubscription.cancel();
     _collectionUpdatesSubscription.cancel();
     _loggedOutEvent.cancel();
-    _backupFoldersUpdatedEvent.cancel();
     super.dispose();
   }
 

+ 1 - 1
lib/ui/home_widget.dart

@@ -297,7 +297,7 @@ class _HomeWidgetState extends State<HomeWidget> {
     }
 
     final bool showBackupFolderHook =
-        Configuration.instance.getPathsToBackUp().isEmpty &&
+        !Configuration.instance.hasSelectedAnyBackupFolder() &&
             !LocalSyncService.instance.hasGrantedLimitedPermissions() &&
             CollectionsService.instance.getActiveCollections().isEmpty;
     return Stack(

+ 1 - 1
lib/ui/tools/deduplicate_page.dart

@@ -12,7 +12,7 @@ import 'package:photos/services/collections_service.dart';
 import 'package:photos/services/deduplication_service.dart';
 import 'package:photos/ui/viewer/file/detail_page.dart';
 import 'package:photos/ui/viewer/file/thumbnail_widget.dart';
-import 'package:photos/ui/viewer/gallery/empte_state.dart';
+import 'package:photos/ui/viewer/gallery/empty_state.dart';
 import 'package:photos/utils/data_util.dart';
 import 'package:photos/utils/delete_file_util.dart';
 import 'package:photos/utils/navigation_util.dart';

+ 13 - 2
lib/ui/viewer/gallery/collection_page.dart

@@ -6,8 +6,10 @@ import 'package:photos/db/files_db.dart';
 import 'package:photos/events/collection_updated_event.dart';
 import 'package:photos/events/files_updated_event.dart';
 import 'package:photos/models/collection_items.dart';
+import 'package:photos/models/file_load_result.dart';
 import 'package:photos/models/gallery_type.dart';
 import 'package:photos/models/selected_files.dart';
+import 'package:photos/services/ignored_files_service.dart';
 import 'package:photos/ui/viewer/gallery/gallery.dart';
 import 'package:photos/ui/viewer/gallery/gallery_app_bar_widget.dart';
 import 'package:photos/ui/viewer/gallery/gallery_overlay_widget.dart';
@@ -29,14 +31,23 @@ class CollectionPage extends StatelessWidget {
   Widget build(Object context) {
     final initialFiles = c.thumbnail != null ? [c.thumbnail] : null;
     final gallery = Gallery(
-      asyncLoader: (creationStartTime, creationEndTime, {limit, asc}) {
-        return FilesDB.instance.getFilesInCollection(
+      asyncLoader: (creationStartTime, creationEndTime, {limit, asc}) async {
+        final FileLoadResult result =
+            await FilesDB.instance.getFilesInCollection(
           c.collection.id,
           creationStartTime,
           creationEndTime,
           limit: limit,
           asc: asc,
         );
+        // hide ignored files from home page UI
+        final ignoredIDs = await IgnoredFilesService.instance.ignoredIDs;
+        result.files.removeWhere(
+          (f) =>
+              f.uploadedFileID == null &&
+              IgnoredFilesService.instance.shouldSkipUpload(ignoredIDs, f),
+        );
+        return result;
       },
       reloadEvent: Bus.instance
           .on<CollectionUpdatedEvent>()

+ 0 - 0
lib/ui/viewer/gallery/empte_state.dart → lib/ui/viewer/gallery/empty_state.dart


+ 1 - 1
lib/ui/viewer/gallery/gallery.dart

@@ -15,7 +15,7 @@ import 'package:photos/models/selected_files.dart';
 import 'package:photos/ui/common/loading_widget.dart';
 import 'package:photos/ui/huge_listview/huge_listview.dart';
 import 'package:photos/ui/huge_listview/lazy_loading_gallery.dart';
-import 'package:photos/ui/viewer/gallery/empte_state.dart';
+import 'package:photos/ui/viewer/gallery/empty_state.dart';
 import 'package:photos/utils/date_time_util.dart';
 import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
 

+ 4 - 3
lib/utils/delete_file_util.dart

@@ -34,7 +34,7 @@ Future<void> deleteFilesFromEverywhere(
 ) async {
   final dialog = createProgressDialog(context, "Deleting...");
   await dialog.show();
-  _logger.info("Trying to delete files " + files.toString());
+  _logger.info("Trying to deleteFilesFromEverywhere " + files.toString());
   final List<String> localAssetIDs = [];
   final List<String> localSharedMediaIDs = [];
   final List<String> alreadyDeletedIDs = []; // to ignore already deleted files
@@ -151,7 +151,8 @@ Future<void> deleteFilesFromRemoteOnly(
   final dialog = createProgressDialog(context, "Deleting...");
   await dialog.show();
   _logger.info(
-    "Trying to delete files " + files.map((f) => f.uploadedFileID).toString(),
+    "Trying to deleteFilesFromRemoteOnly " +
+        files.map((f) => f.uploadedFileID).toString(),
   );
   final updatedCollectionIDs = <int>{};
   final List<int> uploadedFileIDs = [];
@@ -192,7 +193,7 @@ Future<void> deleteFilesOnDeviceOnly(
 ) async {
   final dialog = createProgressDialog(context, "Deleting...");
   await dialog.show();
-  _logger.info("Trying to delete files " + files.toString());
+  _logger.info("Trying to deleteFilesOnDeviceOnly" + files.toString());
   final List<String> localAssetIDs = [];
   final List<String> localSharedMediaIDs = [];
   final List<String> alreadyDeletedIDs = []; // to ignore already deleted files