Pārlūkot izejas kodu

Update like-unlike interactions

Vishnu Mohandas 4 gadi atpakaļ
vecāks
revīzija
be2522d85f

+ 13 - 1
lib/db/files_db.dart

@@ -149,7 +149,7 @@ class FilesDB {
     return _convertToFiles(results);
     return _convertToFiles(results);
   }
   }
 
 
-  Future<List<File>> getAllInCollection(
+  Future<List<File>> getAllInCollectionBeforeCreationTime(
       int collectionID, int beforeCreationTime, int limit) async {
       int collectionID, int beforeCreationTime, int limit) async {
     final db = await instance.database;
     final db = await instance.database;
     final results = await db.query(
     final results = await db.query(
@@ -163,6 +163,18 @@ class FilesDB {
     return _convertToFiles(results);
     return _convertToFiles(results);
   }
   }
 
 
+  Future<List<File>> getAllInCollection(int collectionID) async {
+    final db = await instance.database;
+    final results = await db.query(
+      table,
+      where:
+          '$columnCollectionID = ?',
+      whereArgs: [collectionID],
+      orderBy: '$columnCreationTime DESC',
+    );
+    return _convertToFiles(results);
+  }
+
   Future<List<File>> getFilesCreatedWithinDuration(
   Future<List<File>> getFilesCreatedWithinDuration(
       int startCreationTime, int endCreationTime) async {
       int startCreationTime, int endCreationTime) async {
     final db = await instance.database;
     final db = await instance.database;

+ 4 - 2
lib/models/device_folder.dart

@@ -4,13 +4,15 @@ import 'package:photos/models/file.dart';
 class DeviceFolder {
 class DeviceFolder {
   final String name;
   final String name;
   final String path;
   final String path;
+  final List<File> Function() loader;
   final File thumbnail;
   final File thumbnail;
   final GalleryItemsFilter filter;
   final GalleryItemsFilter filter;
 
 
   DeviceFolder(
   DeviceFolder(
     this.name,
     this.name,
     this.path,
     this.path,
-    this.thumbnail,
+    this.loader,
+    this.thumbnail, {
     this.filter,
     this.filter,
-  );
+  });
 }
 }

+ 0 - 17
lib/models/filters/device_folder_name_filter.dart

@@ -1,17 +0,0 @@
-import 'package:photos/core/configuration.dart';
-import 'package:photos/models/filters/gallery_items_filter.dart';
-import 'package:photos/models/file.dart';
-import 'package:path/path.dart' as path;
-
-class DeviceFolderNameFilter implements GalleryItemsFilter {
-  final String folderName;
-
-  DeviceFolderNameFilter(this.folderName);
-
-  @override
-  bool shouldInclude(File file) {
-    return (file.ownerID == null ||
-            file.ownerID == Configuration.instance.getUserID()) &&
-        path.basename(file.deviceFolder) == folderName;
-  }
-}

+ 0 - 10
lib/models/filters/favorite_items_filter.dart

@@ -1,10 +0,0 @@
-import 'package:photos/services/favorites_service.dart';
-import 'package:photos/models/filters/gallery_items_filter.dart';
-import 'package:photos/models/file.dart';
-
-class FavoriteItemsFilter implements GalleryItemsFilter {
-  @override
-  bool shouldInclude(File file) {
-    return FavoritesService.instance.isLiked(file);
-  }
-}

+ 0 - 10
lib/models/filters/video_file_filter.dart

@@ -1,10 +0,0 @@
-import 'package:photos/models/file.dart';
-import 'package:photos/models/file_type.dart';
-import 'package:photos/models/filters/gallery_items_filter.dart';
-
-class VideoFileFilter implements GalleryItemsFilter {
-  @override
-  bool shouldInclude(File file) {
-    return file.fileType == FileType.video;
-  }
-}

+ 31 - 29
lib/services/favorites_service.dart

@@ -1,6 +1,7 @@
 import 'package:flutter_sodium/flutter_sodium.dart';
 import 'package:flutter_sodium/flutter_sodium.dart';
 import 'package:photos/core/configuration.dart';
 import 'package:photos/core/configuration.dart';
 import 'package:photos/core/event_bus.dart';
 import 'package:photos/core/event_bus.dart';
+import 'package:photos/db/files_db.dart';
 import 'package:photos/events/local_photos_updated_event.dart';
 import 'package:photos/events/local_photos_updated_event.dart';
 import 'package:photos/models/collection.dart';
 import 'package:photos/models/collection.dart';
 import 'package:photos/models/file.dart';
 import 'package:photos/models/file.dart';
@@ -10,17 +11,19 @@ import 'package:photos/utils/file_uploader.dart';
 import 'package:shared_preferences/shared_preferences.dart';
 import 'package:shared_preferences/shared_preferences.dart';
 
 
 class FavoritesService {
 class FavoritesService {
-  static final _favoritePhotoIdsKey = "favorite_photo_ids";
   static final _favoritesCollectionIDKey = "favorites_collection_id";
   static final _favoritesCollectionIDKey = "favorites_collection_id";
 
 
+  final _cachedFavoriteFiles = Set<File>();
   Configuration _config;
   Configuration _config;
   CollectionsService _collectionsService;
   CollectionsService _collectionsService;
   FileUploader _fileUploader;
   FileUploader _fileUploader;
+  FilesDB _filesDB;
 
 
   FavoritesService._privateConstructor() {
   FavoritesService._privateConstructor() {
     _config = Configuration.instance;
     _config = Configuration.instance;
     _collectionsService = CollectionsService.instance;
     _collectionsService = CollectionsService.instance;
     _fileUploader = FileUploader.instance;
     _fileUploader = FileUploader.instance;
+    _filesDB = FilesDB.instance;
   }
   }
   static FavoritesService instance = FavoritesService._privateConstructor();
   static FavoritesService instance = FavoritesService._privateConstructor();
 
 
@@ -28,36 +31,19 @@ class FavoritesService {
 
 
   Future<void> init() async {
   Future<void> init() async {
     _preferences = await SharedPreferences.getInstance();
     _preferences = await SharedPreferences.getInstance();
+    if (_preferences.containsKey(_favoritesCollectionIDKey)) {
+      final collectionID = _preferences.getInt(_favoritesCollectionIDKey);
+      _cachedFavoriteFiles
+          .addAll((await _filesDB.getAllInCollection(collectionID)).toSet());
+    }
   }
   }
 
 
-  bool isLiked(File photo) {
-    return getLiked().contains(photo.generatedID.toString());
-  }
-
-  bool hasFavorites() {
-    return getLiked().isNotEmpty;
-  }
-
-  Future<bool> setLiked(File photo, bool isLiked) {
-    final liked = getLiked();
-    if (isLiked) {
-      liked.add(photo.generatedID.toString());
-    } else {
-      liked.remove(photo.generatedID.toString());
-    }
-    Bus.instance.fire(LocalPhotosUpdatedEvent());
-    return _preferences
-        .setStringList(_favoritePhotoIdsKey, liked.toList())
-        .then((_) => isLiked);
+  Set<File> getFavoriteFiles() {
+    return _cachedFavoriteFiles;
   }
   }
 
 
-  Set<String> getLiked() {
-    final value = _preferences.getStringList(_favoritePhotoIdsKey);
-    if (value == null) {
-      return Set<String>();
-    } else {
-      return value.toSet();
-    }
+  bool isLiked(File file) {
+    return _cachedFavoriteFiles.contains(file);
   }
   }
 
 
   Future<void> addToFavorites(File file) async {
   Future<void> addToFavorites(File file) async {
@@ -66,8 +52,22 @@ class FavoritesService {
     if (fileID == null) {
     if (fileID == null) {
       file.collectionID = collectionID;
       file.collectionID = collectionID;
       fileID = (await _fileUploader.encryptAndUploadFile(file)).uploadedFileID;
       fileID = (await _fileUploader.encryptAndUploadFile(file)).uploadedFileID;
+      await _filesDB.update(
+        file.generatedID,
+        file.uploadedFileID,
+        file.ownerID,
+        file.collectionID,
+        file.updationTime,
+        file.encryptedKey,
+        file.keyDecryptionNonce,
+        file.fileDecryptionHeader,
+        file.thumbnailDecryptionHeader,
+        file.metadataDecryptionHeader,
+      );
     } else {
     } else {
-      return _collectionsService.addToCollection(collectionID, [file]);
+      await _collectionsService.addToCollection(collectionID, [file]);
+      _cachedFavoriteFiles.add(file);
+      Bus.instance.fire(LocalPhotosUpdatedEvent());
     }
     }
   }
   }
 
 
@@ -77,7 +77,9 @@ class FavoritesService {
     if (fileID == null) {
     if (fileID == null) {
       // Do nothing, ignore
       // Do nothing, ignore
     } else {
     } else {
-      return _collectionsService.removeFromCollection(collectionID, [file]);
+      await _collectionsService.removeFromCollection(collectionID, [file]);
+      _cachedFavoriteFiles.remove(file);
+      Bus.instance.fire(LocalPhotosUpdatedEvent());
     }
     }
   }
   }
 
 

+ 4 - 1
lib/ui/detail_page.dart

@@ -182,6 +182,7 @@ class _DetailPageState extends State<DetailPage> {
       isLiked: FavoritesService.instance.isLiked(file),
       isLiked: FavoritesService.instance.isLiked(file),
       onTap: (oldValue) async {
       onTap: (oldValue) async {
         final isLiked = !oldValue;
         final isLiked = !oldValue;
+        bool hasError = false;
         if (isLiked) {
         if (isLiked) {
           final dialog =
           final dialog =
               createProgressDialog(context, "Adding to favorites...");
               createProgressDialog(context, "Adding to favorites...");
@@ -192,6 +193,7 @@ class _DetailPageState extends State<DetailPage> {
           } catch (e, s) {
           } catch (e, s) {
             _logger.severe(e, s);
             _logger.severe(e, s);
             await dialog.hide();
             await dialog.hide();
+            hasError = true;
             showGenericErrorDialog(context);
             showGenericErrorDialog(context);
           } finally {
           } finally {
             await dialog.hide();
             await dialog.hide();
@@ -206,12 +208,13 @@ class _DetailPageState extends State<DetailPage> {
           } catch (e, s) {
           } catch (e, s) {
             _logger.severe(e, s);
             _logger.severe(e, s);
             await dialog.hide();
             await dialog.hide();
+            hasError = true;
             showGenericErrorDialog(context);
             showGenericErrorDialog(context);
           } finally {
           } finally {
             await dialog.hide();
             await dialog.hide();
           }
           }
         }
         }
-        return isLiked;
+        return hasError ? oldValue : isLiked;
       },
       },
       likeBuilder: (isLiked) {
       likeBuilder: (isLiked) {
         return Icon(
         return Icon(

+ 1 - 16
lib/ui/device_folder_page.dart

@@ -2,8 +2,6 @@ import 'package:flutter/material.dart';
 import 'package:photos/core/event_bus.dart';
 import 'package:photos/core/event_bus.dart';
 import 'package:photos/events/local_photos_updated_event.dart';
 import 'package:photos/events/local_photos_updated_event.dart';
 import 'package:photos/models/device_folder.dart';
 import 'package:photos/models/device_folder.dart';
-import 'package:photos/models/file.dart';
-import 'package:photos/repositories/file_repository.dart';
 import 'package:photos/models/selected_files.dart';
 import 'package:photos/models/selected_files.dart';
 import 'package:photos/ui/gallery.dart';
 import 'package:photos/ui/gallery.dart';
 import 'package:photos/ui/gallery_app_bar_widget.dart';
 import 'package:photos/ui/gallery_app_bar_widget.dart';
@@ -23,7 +21,7 @@ class _DeviceFolderPageState extends State<DeviceFolderPage> {
   @override
   @override
   Widget build(Object context) {
   Widget build(Object context) {
     var gallery = Gallery(
     var gallery = Gallery(
-      syncLoader: () => _getFilteredFiles(FileRepository.instance.files),
+      syncLoader: widget.folder.loader,
       reloadEvent: Bus.instance.on<LocalPhotosUpdatedEvent>(),
       reloadEvent: Bus.instance.on<LocalPhotosUpdatedEvent>(),
       tagPrefix: "device_folder:" + widget.folder.path,
       tagPrefix: "device_folder:" + widget.folder.path,
       selectedFiles: _selectedFiles,
       selectedFiles: _selectedFiles,
@@ -38,17 +36,4 @@ class _DeviceFolderPageState extends State<DeviceFolderPage> {
       body: gallery,
       body: gallery,
     );
     );
   }
   }
-
-  List<File> _getFilteredFiles(List<File> unfilteredFiles) {
-    if (widget.folder.filter == null) {
-      return unfilteredFiles;
-    }
-    final List<File> filteredFiles = List<File>();
-    for (File file in unfilteredFiles) {
-      if (widget.folder.filter.shouldInclude(file)) {
-        filteredFiles.add(file);
-      }
-    }
-    return filteredFiles;
-  }
 }
 }

+ 26 - 12
lib/ui/device_folders_gallery_widget.dart

@@ -5,11 +5,10 @@ import 'package:flutter/widgets.dart';
 import 'package:photos/core/event_bus.dart';
 import 'package:photos/core/event_bus.dart';
 import 'package:photos/db/files_db.dart';
 import 'package:photos/db/files_db.dart';
 import 'package:photos/events/local_photos_updated_event.dart';
 import 'package:photos/events/local_photos_updated_event.dart';
+import 'package:photos/models/file.dart';
+import 'package:photos/repositories/file_repository.dart';
 import 'package:photos/services/favorites_service.dart';
 import 'package:photos/services/favorites_service.dart';
 import 'package:photos/models/device_folder.dart';
 import 'package:photos/models/device_folder.dart';
-import 'package:photos/models/filters/favorite_items_filter.dart';
-import 'package:photos/models/filters/device_folder_name_filter.dart';
-import 'package:photos/models/filters/video_file_filter.dart';
 import 'package:photos/ui/common_elements.dart';
 import 'package:photos/ui/common_elements.dart';
 import 'package:photos/ui/device_folder_page.dart';
 import 'package:photos/ui/device_folder_page.dart';
 import 'package:photos/ui/loading_widget.dart';
 import 'package:photos/ui/loading_widget.dart';
@@ -76,25 +75,40 @@ class _DeviceFolderGalleryWidgetState extends State<DeviceFolderGalleryWidget> {
     final paths = await FilesDB.instance.getLocalPaths();
     final paths = await FilesDB.instance.getLocalPaths();
     final folders = List<DeviceFolder>();
     final folders = List<DeviceFolder>();
     for (final path in paths) {
     for (final path in paths) {
-      final file = await FilesDB.instance.getLatestFileInPath(path);
+      final thumbnail = await FilesDB.instance.getLatestFileInPath(path);
+      final files = List<File>();
+      for (File file in FileRepository.instance.files) {
+        if (file.deviceFolder == path) {
+          files.add(file);
+        }
+      }
       final folderName = p.basename(path);
       final folderName = p.basename(path);
-      folders.add(
-          DeviceFolder(folderName, path, file, DeviceFolderNameFilter(folderName)));
+      folders.add(DeviceFolder(folderName, path, () => files, thumbnail));
     }
     }
     folders.sort((first, second) {
     folders.sort((first, second) {
       return second.thumbnail.creationTime
       return second.thumbnail.creationTime
           .compareTo(first.thumbnail.creationTime);
           .compareTo(first.thumbnail.creationTime);
     });
     });
-    if (FavoritesService.instance.hasFavorites()) {
-      final file = await FilesDB.instance.getLatestFileAmongGeneratedIDs(
-          FavoritesService.instance.getLiked().toList());
-      folders.insert(0,
-          DeviceFolder("Favorites", "/Favorites", file, FavoriteItemsFilter()));
+    final favorites = FavoritesService.instance.getFavoriteFiles().toList();
+    favorites.sort((first, second) {
+      return second.creationTime.compareTo(first.creationTime);
+    });
+    if (favorites.length > 0) {
+      folders.insert(
+          0,
+          DeviceFolder("Favorites", "/Favorites", () {
+            final favorites =
+                FavoritesService.instance.getFavoriteFiles().toList();
+            favorites.sort((first, second) {
+              return second.creationTime.compareTo(first.creationTime);
+            });
+            return favorites;
+          }, favorites[0]));
     }
     }
     final videos = await FilesDB.instance.getAllVideos();
     final videos = await FilesDB.instance.getAllVideos();
     if (videos.length > 0) {
     if (videos.length > 0) {
       folders.insert(
       folders.insert(
-          0, DeviceFolder("Videos", "/Videos", videos[0], VideoFileFilter()));
+          0, DeviceFolder("Videos", "/Videos", () => videos, videos[0]));
     }
     }
     return folders;
     return folders;
   }
   }

+ 7 - 6
lib/ui/shared_collection_page.dart

@@ -20,12 +20,13 @@ class _SharedCollectionPageState extends State<SharedCollectionPage> {
   @override
   @override
   Widget build(Object context) {
   Widget build(Object context) {
     var gallery = Gallery(
     var gallery = Gallery(
-      asyncLoader: (lastFile, limit) => FilesDB.instance.getAllInCollection(
-          widget.collection.id,
-          lastFile == null
-              ? DateTime.now().microsecondsSinceEpoch
-              : lastFile.creationTime,
-          limit),
+      asyncLoader: (lastFile, limit) => FilesDB.instance
+          .getAllInCollectionBeforeCreationTime(
+              widget.collection.id,
+              lastFile == null
+                  ? DateTime.now().microsecondsSinceEpoch
+                  : lastFile.creationTime,
+              limit),
       // onRefresh: () => FolderSharingService.instance.syncDiff(widget.folder),
       // onRefresh: () => FolderSharingService.instance.syncDiff(widget.folder),
       tagPrefix: "shared_collection",
       tagPrefix: "shared_collection",
       selectedFiles: _selectedFiles,
       selectedFiles: _selectedFiles,