Forráskód Böngészése

Remove SharedCollection

Vishnu Mohandas 4 éve
szülő
commit
3630a25fb5

+ 1 - 72
lib/db/collections_db.dart

@@ -3,7 +3,6 @@ import 'dart:io';
 import 'package:path/path.dart';
 import 'package:path_provider/path_provider.dart';
 import 'package:photos/models/collection.dart';
-import 'package:photos/models/shared_collection.dart';
 import 'package:sqflite/sqflite.dart';
 
 class CollectionsDB {
@@ -11,7 +10,6 @@ class CollectionsDB {
   static final _databaseVersion = 1;
 
   static final collectionsTable = 'collections';
-  static final sharedCollectionsTable = 'shared_collections';
 
   static final columnID = 'collection_id';
   static final columnOwnerID = 'owner_id';
@@ -49,7 +47,7 @@ class CollectionsDB {
                   $columnID INTEGER PRIMARY KEY NOT NULL,
                   $columnOwnerID INTEGER NOT NULL,
                   $columnEncryptedKey TEXT NOT NULL,
-                  $columnKeyDecryptionNonce TEXT NOT NULL,
+                  $columnKeyDecryptionNonce TEXT,
                   $columnName TEXT NOT NULL,
                   $columnType TEXT NOT NULL,
                   $columnEncryptedPath TEXT,
@@ -57,17 +55,6 @@ class CollectionsDB {
                   $columnCreationTime TEXT NOT NULL
                 )
                 ''');
-
-    await db.execute('''
-                CREATE TABLE $sharedCollectionsTable (
-                  $columnID INTEGER PRIMARY KEY NOT NULL,
-                  $columnOwnerID INTEGER NOT NULL,
-                  $columnEncryptedKey TEXT NOT NULL,
-                  $columnName TEXT NOT NULL,
-                  $columnType TEXT NOT NULL,
-                  $columnCreationTime TEXT NOT NULL
-                )
-                ''');
   }
 
   Future<List<dynamic>> insert(List<Collection> collections) async {
@@ -80,18 +67,6 @@ class CollectionsDB {
     return await batch.commit();
   }
 
-  Future<List<dynamic>> insertSharedCollections(
-      List<SharedCollection> collections) async {
-    final db = await instance.database;
-    var batch = db.batch();
-    for (final collection in collections) {
-      batch.insert(
-          sharedCollectionsTable, _getRowForSharedCollection(collection),
-          conflictAlgorithm: ConflictAlgorithm.replace);
-    }
-    return await batch.commit();
-  }
-
   Future<List<Collection>> getAllCollections() async {
     final db = await instance.database;
     final rows = await db.query(collectionsTable);
@@ -102,16 +77,6 @@ class CollectionsDB {
     return collections;
   }
 
-  Future<List<SharedCollection>> getAllSharedCollections() async {
-    final db = await instance.database;
-    final rows = await db.query(sharedCollectionsTable);
-    final collections = List<SharedCollection>();
-    for (final row in rows) {
-      collections.add(_convertToSharedCollection(row));
-    }
-    return collections;
-  }
-
   Future<int> getLastCollectionCreationTime() async {
     final db = await instance.database;
     final rows = await db.query(
@@ -126,20 +91,6 @@ class CollectionsDB {
     }
   }
 
-  Future<int> getLastSharedCollectionCreationTime() async {
-    final db = await instance.database;
-    final rows = await db.query(
-      sharedCollectionsTable,
-      orderBy: '$columnCreationTime DESC',
-      limit: 1,
-    );
-    if (rows.isNotEmpty) {
-      return int.parse(rows[0][columnCreationTime]);
-    } else {
-      return null;
-    }
-  }
-
   Map<String, dynamic> _getRowForCollection(Collection collection) {
     var row = new Map<String, dynamic>();
     row[columnID] = collection.id;
@@ -168,26 +119,4 @@ class CollectionsDB {
       int.parse(row[columnCreationTime]),
     );
   }
-
-  Map<String, dynamic> _getRowForSharedCollection(SharedCollection collection) {
-    var row = new Map<String, dynamic>();
-    row[columnID] = collection.id;
-    row[columnOwnerID] = collection.ownerID;
-    row[columnEncryptedKey] = collection.encryptedKey;
-    row[columnName] = collection.name;
-    row[columnType] = Collection.typeToString(collection.type);
-    row[columnCreationTime] = collection.creationTime;
-    return row;
-  }
-
-  SharedCollection _convertToSharedCollection(Map<String, dynamic> row) {
-    return SharedCollection(
-      row[columnID],
-      row[columnOwnerID],
-      row[columnEncryptedKey],
-      row[columnName],
-      Collection.typeFromString(row[columnType]),
-      int.parse(row[columnCreationTime]),
-    );
-  }
 }

+ 3 - 2
lib/db/files_db.dart

@@ -290,7 +290,8 @@ class FilesDB {
     final db = await instance.database;
     return db.delete(
       table,
-      where: '$columnCollectionID =? AND ',
+      where:
+          '$columnCollectionID =? AND $columnUploadedFileID IN (${fileIDs.join(', ')})',
       whereArgs: [collectionID],
     );
   }
@@ -322,7 +323,7 @@ class FilesDB {
     if (rows.isNotEmpty) {
       return _getFileFromRow(rows[0]);
     } else {
-      throw ("No file found in collection " + collectionID.toString());
+      return null;
     }
   }
 

+ 0 - 96
lib/models/shared_collection.dart

@@ -1,96 +0,0 @@
-import 'dart:convert';
-
-import 'package:photos/models/collection.dart';
-
-class SharedCollection {
-  final int id;
-  final int ownerID;
-  final String encryptedKey;
-  final String name;
-  final CollectionType type;
-  final int creationTime;
-
-  SharedCollection(
-    this.id,
-    this.ownerID,
-    this.encryptedKey,
-    this.name,
-    this.type,
-    this.creationTime,
-  );
-
-  SharedCollection copyWith({
-    int id,
-    int ownerID,
-    String encryptedKey,
-    String name,
-    CollectionType type,
-    int creationTime,
-  }) {
-    return SharedCollection(
-      id ?? this.id,
-      ownerID ?? this.ownerID,
-      encryptedKey ?? this.encryptedKey,
-      name ?? this.name,
-      type ?? this.type,
-      creationTime ?? this.creationTime,
-    );
-  }
-
-  Map<String, dynamic> toMap() {
-    return {
-      'id': id,
-      'ownerID': ownerID,
-      'encryptedKey': encryptedKey,
-      'name': name,
-      'type': Collection.typeToString(type),
-      'creationTime': creationTime,
-    };
-  }
-
-  factory SharedCollection.fromMap(Map<String, dynamic> map) {
-    if (map == null) return null;
-
-    return SharedCollection(
-      map['id'],
-      map['ownerID'],
-      map['encryptedKey'],
-      map['name'],
-      Collection.typeFromString(map['type']),
-      map['creationTime'],
-    );
-  }
-
-  String toJson() => json.encode(toMap());
-
-  factory SharedCollection.fromJson(String source) =>
-      SharedCollection.fromMap(json.decode(source));
-
-  @override
-  String toString() {
-    return 'SharedCollection(id: $id, ownerID: $ownerID, encryptedKey: $encryptedKey, name: $name, type: $type, creationTime: $creationTime)';
-  }
-
-  @override
-  bool operator ==(Object o) {
-    if (identical(this, o)) return true;
-
-    return o is SharedCollection &&
-        o.id == id &&
-        o.ownerID == ownerID &&
-        o.encryptedKey == encryptedKey &&
-        o.name == name &&
-        o.type == type &&
-        o.creationTime == creationTime;
-  }
-
-  @override
-  int get hashCode {
-    return id.hashCode ^
-        ownerID.hashCode ^
-        encryptedKey.hashCode ^
-        name.hashCode ^
-        type.hashCode ^
-        creationTime.hashCode;
-  }
-}

+ 40 - 79
lib/services/collections_service.dart

@@ -9,11 +9,11 @@ import 'package:logging/logging.dart';
 import 'package:photos/core/configuration.dart';
 import 'package:photos/core/event_bus.dart';
 import 'package:photos/db/collections_db.dart';
+import 'package:photos/db/files_db.dart';
 import 'package:photos/events/collection_updated_event.dart';
 import 'package:photos/models/collection.dart';
 import 'package:photos/models/collection_file_item.dart';
 import 'package:photos/models/file.dart';
-import 'package:photos/models/shared_collection.dart';
 import 'package:photos/utils/crypto_util.dart';
 import 'package:photos/utils/file_util.dart';
 
@@ -23,8 +23,7 @@ class CollectionsService {
   CollectionsDB _db;
   Configuration _config;
   final _localCollections = Map<String, Collection>();
-  final _collectionIDToOwnedCollections = Map<int, Collection>();
-  final _collectionIDToSharedCollections = Map<int, SharedCollection>();
+  final _collectionIDToCollections = Map<int, Collection>();
   final _cachedKeys = Map<int, Uint8List>();
 
   CollectionsService._privateConstructor() {
@@ -38,33 +37,18 @@ class CollectionsService {
   Future<void> init() async {
     final collections = await _db.getAllCollections();
     for (final collection in collections) {
-      _cacheOwnedCollectionAttributes(collection);
-    }
-    final sharedCollections = await _db.getAllSharedCollections();
-    for (final collection in sharedCollections) {
-      _collectionIDToSharedCollections[collection.id] = collection;
+      _cacheCollectionAttributes(collection);
     }
   }
 
   Future<void> sync() async {
     final lastCollectionCreationTime =
         await _db.getLastCollectionCreationTime();
-    var collections =
-        await _getOwnedCollections(lastCollectionCreationTime ?? 0);
+    var collections = await _fetchCollections(lastCollectionCreationTime ?? 0);
     await _db.insert(collections);
     collections = await _db.getAllCollections();
     for (final collection in collections) {
-      _cacheOwnedCollectionAttributes(collection);
-    }
-
-    final lastSharedCollectionCreationTime =
-        await _db.getLastCollectionCreationTime();
-    var sharedCollections =
-        await getSharedCollections(lastSharedCollectionCreationTime ?? 0);
-    await _db.insertSharedCollections(sharedCollections);
-    sharedCollections = await _db.getAllSharedCollections();
-    for (final collection in sharedCollections) {
-      _collectionIDToSharedCollections[collection.id] = collection;
+      _cacheCollectionAttributes(collection);
     }
   }
 
@@ -72,8 +56,8 @@ class CollectionsService {
     return _localCollections[path];
   }
 
-  List<Collection> getOwnedCollections() {
-    return _collectionIDToOwnedCollections.values.toList();
+  List<Collection> getCollections() {
+    return _collectionIDToCollections.values.toList();
   }
 
   Future<List<String>> getSharees(int collectionID) {
@@ -113,14 +97,13 @@ class CollectionsService {
 
   Uint8List getCollectionKey(int collectionID) {
     if (!_cachedKeys.containsKey(collectionID)) {
+      final collection = _collectionIDToCollections[collectionID];
       var key;
-      if (_collectionIDToOwnedCollections.containsKey(collectionID)) {
-        final collection = _collectionIDToOwnedCollections[collectionID];
+      if (collection.ownerID == _config.getUserID()) {
         final encryptedKey = Sodium.base642bin(collection.encryptedKey);
         key = CryptoUtil.decryptSync(encryptedKey, _config.getKey(),
             Sodium.base642bin(collection.keyDecryptionNonce));
       } else {
-        final collection = _collectionIDToSharedCollections[collectionID];
         final encryptedKey = Sodium.base642bin(collection.encryptedKey);
         key = CryptoUtil.openSealSync(
             encryptedKey,
@@ -132,10 +115,10 @@ class CollectionsService {
     return _cachedKeys[collectionID];
   }
 
-  Future<List<Collection>> _getOwnedCollections(int sinceTime) {
+  Future<List<Collection>> _fetchCollections(int sinceTime) {
     return Dio()
         .get(
-      Configuration.instance.getHttpEndpoint() + "/collections/owned",
+      Configuration.instance.getHttpEndpoint() + "/collections/",
       queryParameters: {
         "sinceTime": sinceTime,
       },
@@ -154,30 +137,8 @@ class CollectionsService {
     });
   }
 
-  Future<List<SharedCollection>> getSharedCollections(int sinceTime) {
-    return Dio()
-        .get(
-      Configuration.instance.getHttpEndpoint() + "/collections/shared",
-      queryParameters: {
-        "sinceTime": sinceTime,
-      },
-      options:
-          Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
-    )
-        .then((response) {
-      final collections = List<SharedCollection>();
-      if (response != null) {
-        final c = response.data["collections"];
-        for (final collection in c) {
-          collections.add(SharedCollection.fromMap(collection));
-        }
-      }
-      return collections;
-    });
-  }
-
-  Collection getOwnedCollectionByID(int collectionID) {
-    return _collectionIDToOwnedCollections[collectionID];
+  Collection getCollectionByID(int collectionID) {
+    return _collectionIDToCollections[collectionID];
   }
 
   Future<Collection> createAlbum(String albumName) async {
@@ -224,29 +185,32 @@ class CollectionsService {
     params["collectionID"] = collectionID;
     for (final file in files) {
       final key = decryptFileKey(file);
+      file.collectionID = collectionID;
       final encryptedKeyData =
           CryptoUtil.encryptSync(key, getCollectionKey(collectionID));
+      file.encryptedKey = Sodium.bin2base64(encryptedKeyData.encryptedData);
+      file.keyDecryptionNonce = Sodium.bin2base64(encryptedKeyData.nonce);
       if (params["files"] == null) {
         params["files"] = [];
       }
       params["files"].add(CollectionFileItem(
-        file.uploadedFileID,
-        Sodium.bin2base64(encryptedKeyData.encryptedData),
-        Sodium.bin2base64(encryptedKeyData.nonce),
-      ).toMap());
+              file.uploadedFileID, file.encryptedKey, file.keyDecryptionNonce)
+          .toMap());
     }
     return Dio()
         .post(
-          Configuration.instance.getHttpEndpoint() + "/collections/add-files",
-          data: params,
-          options: Options(
-              headers: {"X-Auth-Token": Configuration.instance.getToken()}),
-        )
-        .then(
-            (value) => Bus.instance.fire(CollectionUpdatedEvent(collectionID)));
+      Configuration.instance.getHttpEndpoint() + "/collections/add-files",
+      data: params,
+      options:
+          Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
+    )
+        .then((value) async {
+      await FilesDB.instance.insertMultiple(files);
+      Bus.instance.fire(CollectionUpdatedEvent(collectionID));
+    });
   }
 
-  Future<void> removeFromCollection(int collectionID, List<File> files) {
+  Future<void> removeFromCollection(int collectionID, List<File> files) async {
     final params = Map<String, dynamic>();
     params["collectionID"] = collectionID;
     for (final file in files) {
@@ -255,17 +219,15 @@ class CollectionsService {
       }
       params["fileIDs"].add(file.uploadedFileID);
     }
-    return Dio()
-        .post(
-          Configuration.instance.getHttpEndpoint() +
-              "/collections/remove-files",
-          data: params,
-          options: Options(
-              headers: {"X-Auth-Token": Configuration.instance.getToken()}),
-        )
-        .then(
-            (value) => Bus.instance.fire(CollectionUpdatedEvent(collectionID)));
-    ;
+    await Dio().post(
+      Configuration.instance.getHttpEndpoint() + "/collections/remove-files",
+      data: params,
+      options:
+          Options(headers: {"X-Auth-Token": Configuration.instance.getToken()}),
+    );
+    await FilesDB.instance
+        .removeFromCollection(collectionID, params["fileIDs"]);
+    Bus.instance.fire(CollectionUpdatedEvent(collectionID));
   }
 
   Future<Collection> createAndCacheCollection(Collection collection) async {
@@ -278,12 +240,12 @@ class CollectionsService {
     )
         .then((response) {
       final collection = Collection.fromMap(response.data["collection"]);
-      _cacheOwnedCollectionAttributes(collection);
+      _cacheCollectionAttributes(collection);
       return collection;
     });
   }
 
-  void _cacheOwnedCollectionAttributes(Collection collection) {
+  void _cacheCollectionAttributes(Collection collection) {
     if (collection.attributes.encryptedPath != null) {
       var path = utf8.decode(CryptoUtil.decryptSync(
           Sodium.base642bin(collection.attributes.encryptedPath),
@@ -291,8 +253,7 @@ class CollectionsService {
           Sodium.base642bin(collection.attributes.pathDecryptionNonce)));
       _localCollections[path] = collection;
     }
-    _collectionIDToOwnedCollections[collection.id] = collection;
-    getCollectionKey(collection.id);
+    _collectionIDToCollections[collection.id] = collection;
   }
 }
 

+ 2 - 2
lib/services/favorites_service.dart

@@ -69,7 +69,7 @@ class FavoritesService {
 
   Future<Collection> getFavoritesCollection() async {
     if (!_preferences.containsKey(_favoritesCollectionIDKey)) {
-      final collections = _collectionsService.getOwnedCollections();
+      final collections = _collectionsService.getCollections();
       for (final collection in collections) {
         if (collection.type == CollectionType.favorites) {
           await _preferences.setInt(_favoritesCollectionIDKey, collection.id);
@@ -79,7 +79,7 @@ class FavoritesService {
       return null;
     }
     return _collectionsService
-        .getOwnedCollectionByID(_preferences.getInt(_favoritesCollectionIDKey));
+        .getCollectionByID(_preferences.getInt(_favoritesCollectionIDKey));
   }
 
   Future<int> _getOrCreateFavoriteCollectionID() async {

+ 2 - 2
lib/services/sync_service.dart

@@ -57,8 +57,8 @@ class SyncService {
       _logger.info("Syncing...");
       try {
         await _doSync();
-      } catch (e) {
-        throw e;
+      } catch (e, s) {
+        _logger.severe(e, s);
       } finally {
         _isSyncInProgress = false;
       }

+ 15 - 3
lib/ui/collections_gallery_widget.dart

@@ -3,6 +3,8 @@ import 'dart:async';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:fluttertoast/fluttertoast.dart';
+import 'package:logging/logging.dart';
+import 'package:photos/core/configuration.dart';
 import 'package:photos/core/event_bus.dart';
 import 'package:photos/db/files_db.dart';
 import 'package:photos/events/collection_updated_event.dart';
@@ -11,6 +13,7 @@ import 'package:photos/events/tab_changed_event.dart';
 import 'package:photos/models/collection.dart';
 import 'package:photos/models/file.dart';
 import 'package:photos/repositories/file_repository.dart';
+import 'package:photos/services/collections_service.dart';
 import 'package:photos/services/favorites_service.dart';
 import 'package:photos/models/device_folder.dart';
 import 'package:photos/ui/collection_page.dart';
@@ -29,6 +32,7 @@ class CollectionsGalleryWidget extends StatefulWidget {
 }
 
 class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget> {
+  final _logger = Logger("CollectionsGallery");
   StreamSubscription<LocalPhotosUpdatedEvent> _localFilesSubscription;
   StreamSubscription<CollectionUpdatedEvent> _collectionUpdatesSubscription;
 
@@ -120,17 +124,25 @@ class _CollectionsGalleryWidgetState extends State<CollectionsGalleryWidget> {
           .compareTo(first.thumbnail.creationTime);
     });
 
-    final collections = List<CollectionWithThumbnail>();
+    final collectionsWithThumbnail = List<CollectionWithThumbnail>();
     final favorites = FavoritesService.instance.getFavoriteFiles().toList();
     favorites.sort((first, second) {
       return second.creationTime.compareTo(first.creationTime);
     });
     if (favorites.length > 0) {
-      collections.add(CollectionWithThumbnail(
+      collectionsWithThumbnail.add(CollectionWithThumbnail(
           await FavoritesService.instance.getFavoritesCollection(),
           favorites[0]));
     }
-    return CollectionItems(folders, collections);
+    final collections = CollectionsService.instance.getCollections();
+    for (final c in collections) {
+      if (c.ownerID != Configuration.instance.getUserID()) {
+        continue;
+      }
+      collectionsWithThumbnail.add(CollectionWithThumbnail(
+          c, await FilesDB.instance.getLatestFileInCollection(c.id)));
+    }
+    return CollectionItems(folders, collectionsWithThumbnail);
   }
 
   Widget _buildFolder(BuildContext context, DeviceFolder folder) {

+ 2 - 2
lib/ui/shared_collection_page.dart

@@ -1,12 +1,12 @@
 import 'package:flutter/material.dart';
 import 'package:photos/db/files_db.dart';
 import 'package:photos/models/selected_files.dart';
-import 'package:photos/models/shared_collection.dart';
+import 'package:photos/models/collection.dart';
 import 'package:photos/ui/gallery.dart';
 import 'package:photos/ui/gallery_app_bar_widget.dart';
 
 class SharedCollectionPage extends StatefulWidget {
-  final SharedCollection collection;
+  final Collection collection;
 
   const SharedCollectionPage(this.collection, {Key key}) : super(key: key);
 

+ 12 - 19
lib/ui/shared_collections_gallery.dart

@@ -3,12 +3,12 @@ import 'dart:async';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:logging/logging.dart';
+import 'package:photos/core/configuration.dart';
 import 'package:photos/core/event_bus.dart';
 import 'package:photos/db/collections_db.dart';
 import 'package:photos/db/files_db.dart';
 import 'package:photos/events/remote_sync_event.dart';
-import 'package:photos/models/file.dart';
-import 'package:photos/models/shared_collection.dart';
+import 'package:photos/ui/collections_gallery_widget.dart';
 import 'package:photos/ui/common_elements.dart';
 import 'package:photos/ui/loading_widget.dart';
 import 'package:photos/ui/shared_collection_page.dart';
@@ -38,12 +38,14 @@ class _SharedCollectionGalleryState extends State<SharedCollectionGallery> {
 
   @override
   Widget build(BuildContext context) {
-    return FutureBuilder<List<SharedCollectionWithThumbnail>>(
-      future: CollectionsDB.instance
-          .getAllSharedCollections()
-          .then((collections) async {
-        final c = List<SharedCollectionWithThumbnail>();
+    return FutureBuilder<List<CollectionWithThumbnail>>(
+      future:
+          CollectionsDB.instance.getAllCollections().then((collections) async {
+        final c = List<CollectionWithThumbnail>();
         for (final collection in collections) {
+          if (collection.ownerID == Configuration.instance.getUserID()) {
+            continue;
+          }
           var thumbnail;
           try {
             thumbnail =
@@ -51,7 +53,7 @@ class _SharedCollectionGalleryState extends State<SharedCollectionGallery> {
           } catch (e) {
             _logger.warning(e.toString());
           }
-          c.add(SharedCollectionWithThumbnail(collection, thumbnail));
+          c.add(CollectionWithThumbnail(collection, thumbnail));
         }
         return c;
       }),
@@ -73,7 +75,7 @@ class _SharedCollectionGalleryState extends State<SharedCollectionGallery> {
   }
 
   Widget _getSharedCollectionsGallery(
-      List<SharedCollectionWithThumbnail> collections) {
+      List<CollectionWithThumbnail> collections) {
     return Container(
       margin: EdgeInsets.only(top: 24),
       child: GridView.builder(
@@ -91,9 +93,7 @@ class _SharedCollectionGalleryState extends State<SharedCollectionGallery> {
     );
   }
 
-  Widget _buildCollection(
-      BuildContext context, SharedCollectionWithThumbnail c) {
-    _logger.info("Building collection " + c.collection.toString());
+  Widget _buildCollection(BuildContext context, CollectionWithThumbnail c) {
     return GestureDetector(
       child: Column(
         children: <Widget>[
@@ -140,10 +140,3 @@ class _SharedCollectionGalleryState extends State<SharedCollectionGallery> {
     super.dispose();
   }
 }
-
-class SharedCollectionWithThumbnail {
-  final SharedCollection collection;
-  final File thumbnail;
-
-  SharedCollectionWithThumbnail(this.collection, this.thumbnail);
-}