Browse Source

Optimize collection loading

Vishnu Mohandas 4 năm trước cách đây
mục cha
commit
ef06cfbea0

+ 95 - 2
lib/db/files_db.dart

@@ -85,7 +85,12 @@ class FilesDB {
             $columnCreationTime TEXT NOT NULL,
             $columnUpdationTime TEXT,
             UNIQUE($columnUploadedFileID, $columnCollectionID)
-          )
+          );
+
+          CREATE INDEX collection_id_index ON $table($columnCollectionID);
+          CREATE INDEX device_folder_index ON $table($columnDeviceFolder);
+          CREATE INDEX creation_time_index ON $table($columnCreationTime);
+          CREATE INDEX updation_time_index ON $table($columnUpdationTime);
           ''');
   }
 
@@ -120,6 +125,17 @@ class FilesDB {
     return _convertToFiles(results)[0];
   }
 
+  Future<List<File>> getDeduplicatedFiles() async {
+    _logger.info("Getting files for collection");
+    final db = await instance.database;
+    final results = await db.query(table,
+        where: '$columnIsDeleted = 0',
+        orderBy: '$columnCreationTime DESC',
+        groupBy:
+            'IFNULL($columnUploadedFileID, $columnGeneratedID), IFNULL($columnLocalID, $columnGeneratedID)');
+    return _convertToFiles(results);
+  }
+
   Future<List<File>> getFiles() async {
     final db = await instance.database;
     final results = await db.query(
@@ -206,6 +222,84 @@ class FilesDB {
     return _convertToFiles(results);
   }
 
+  Future<Map<int, File>> getLastCreatedFilesInCollections(
+      List<int> collectionIDs) async {
+    final db = await instance.database;
+    final rows = await db.rawQuery('''
+      SELECT 
+        $columnGeneratedID,
+        $columnLocalID,
+        $columnUploadedFileID,
+        $columnOwnerID,
+        $columnCollectionID,
+        $columnTitle,
+        $columnDeviceFolder,
+        $columnLatitude,
+        $columnLongitude,
+        $columnFileType,
+        $columnRemoteFolderID,
+        $columnIsEncrypted,
+        $columnModificationTime,
+        $columnEncryptedKey,
+        $columnKeyDecryptionNonce,
+        $columnFileDecryptionHeader,
+        $columnThumbnailDecryptionHeader,
+        $columnMetadataDecryptionHeader,
+        $columnIsDeleted,
+        $columnUpdationTime,
+        MAX($columnCreationTime) as $columnCreationTime
+      FROM $table
+      WHERE $columnCollectionID IN (${collectionIDs.join(', ')})
+      GROUP BY $columnCollectionID
+      ORDER BY $columnCreationTime DESC;
+    ''');
+    final result = Map<int, File>();
+    final files = _convertToFiles(rows);
+    for (final file in files) {
+      result[file.collectionID] = file;
+    }
+    return result;
+  }
+
+  Future<Map<int, File>> getLastUpdatedFilesInCollections(
+      List<int> collectionIDs) async {
+    final db = await instance.database;
+    final rows = await db.rawQuery('''
+      SELECT 
+        $columnGeneratedID,
+        $columnLocalID,
+        $columnUploadedFileID,
+        $columnOwnerID,
+        $columnCollectionID,
+        $columnTitle,
+        $columnDeviceFolder,
+        $columnLatitude,
+        $columnLongitude,
+        $columnFileType,
+        $columnRemoteFolderID,
+        $columnIsEncrypted,
+        $columnModificationTime,
+        $columnEncryptedKey,
+        $columnKeyDecryptionNonce,
+        $columnFileDecryptionHeader,
+        $columnThumbnailDecryptionHeader,
+        $columnMetadataDecryptionHeader,
+        $columnIsDeleted,
+        $columnCreationTime,
+        MAX($columnUpdationTime) AS $columnUpdationTime
+      FROM $table
+      WHERE $columnCollectionID IN (${collectionIDs.join(', ')})
+      GROUP BY $columnCollectionID
+      ORDER BY $columnUpdationTime DESC;
+    ''');
+    final result = Map<int, File>();
+    final files = _convertToFiles(rows);
+    for (final file in files) {
+      result[file.collectionID] = file;
+    }
+    return result;
+  }
+
   Future<List<File>> getMatchingFiles(
       String title, String deviceFolder, int creationTime, int modificationTime,
       {String alternateTitle}) async {
@@ -300,7 +394,6 @@ class FilesDB {
       table,
       columns: [columnDeviceFolder],
       distinct: true,
-      where: '$columnRemoteFolderID IS NULL',
     );
     List<String> result = List<String>();
     for (final row in rows) {

+ 1 - 2
lib/repositories/file_repository.dart

@@ -5,7 +5,7 @@ import 'package:photos/events/local_photos_updated_event.dart';
 import 'package:photos/models/file.dart';
 
 class FileRepository {
-  final _logger = Logger("PhotoRepository");
+  final _logger = Logger("FileRepository");
   final _files = List<File>();
 
   FileRepository._privateConstructor();
@@ -32,7 +32,6 @@ class FileRepository {
     }
     _files.clear();
     _files.addAll(deduplicatedFiles);
-
     return _files;
   }
 

+ 19 - 18
lib/ui/collections_gallery_widget.dart

@@ -106,8 +106,11 @@ class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget> {
   }
 
   Future<CollectionItems> _getCollections() async {
+    final filesDB = FilesDB.instance;
+    final collectionsService = CollectionsService.instance;
     final userID = Configuration.instance.getUserID();
-    final paths = await FilesDB.instance.getLocalPaths();
+    // Query takes ~3 seconds, find out why
+    final paths = await filesDB.getLocalPaths();
     final folders = List<DeviceFolder>();
     for (final path in paths) {
       final files = List<File>();
@@ -120,34 +123,32 @@ class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget> {
       final folderName = p.basename(path);
       folders.add(DeviceFolder(folderName, path, () => files, files[0]));
     }
+
     folders.sort((first, second) {
       return second.thumbnail.creationTime
           .compareTo(first.thumbnail.creationTime);
     });
-
     final collectionsWithThumbnail = List<CollectionWithThumbnail>();
-    final collections = CollectionsService.instance.getCollections();
-
+    final collections = collectionsService.getCollections();
+    final ownedCollectionIDs = List<int>();
     for (final c in collections) {
       if (c.ownerID != userID) {
         continue;
+      } else {
+        ownedCollectionIDs.add(c.id);
       }
-      final thumbnail = await FilesDB.instance.getLatestFileInCollection(c.id);
-      if (thumbnail == null) {
-        continue;
-      }
-      final lastUpdatedFile =
-          await FilesDB.instance.getLastModifiedFileInCollection(c.id);
+    }
+    final thumbnails =
+        await filesDB.getLastCreatedFilesInCollections(ownedCollectionIDs);
+    final lastUpdatedFiles =
+        await filesDB.getLastUpdatedFilesInCollections(ownedCollectionIDs);
+    for (final collectionID in lastUpdatedFiles.keys) {
       collectionsWithThumbnail.add(CollectionWithThumbnail(
-        c,
-        thumbnail,
-        lastUpdatedFile,
-      ));
+          collectionsService.getCollectionByID(collectionID),
+          thumbnails[collectionID],
+          lastUpdatedFiles[collectionID]));
     }
-    collectionsWithThumbnail.sort((first, second) {
-      return second.lastUpdatedFile.updationTime
-          .compareTo(first.lastUpdatedFile.updationTime);
-    });
+
     return CollectionItems(folders, collectionsWithThumbnail);
   }