Explorar el Código

Merge branch 'master' into edit-time

Neeraj Gupta hace 3 años
padre
commit
96932f22d7

+ 38 - 17
lib/db/ignored_files_db.dart

@@ -1,6 +1,7 @@
 import 'dart:io';
-import 'package:path/path.dart';
+
 import 'package:logging/logging.dart';
+import 'package:path/path.dart';
 import 'package:path_provider/path_provider.dart';
 import 'package:photos/models/ignored_file.dart';
 import 'package:sqflite/sqflite.dart';
@@ -17,6 +18,7 @@ class IgnoredFilesDB {
 
   static final columnLocalID = 'local_id';
   static final columnTitle = 'title';
+  static final columnDeviceFolder = 'device_folder';
   static final columnReason = 'reason';
 
   Future _onCreate(Database db, int version) async {
@@ -24,10 +26,12 @@ class IgnoredFilesDB {
         CREATE TABLE $tableName (
           $columnLocalID TEXT NOT NULL,
           $columnTitle TEXT NOT NULL,
+          $columnDeviceFolder TEXT NOT NULL,
           $columnReason TEXT DEFAULT $kIgnoreReasonTrash,
-          UNIQUE($columnLocalID, $columnTitle)
+          UNIQUE($columnLocalID, $columnTitle, $columnDeviceFolder)
         );
       CREATE INDEX IF NOT EXISTS local_id_index ON $tableName($columnLocalID);
+      CREATE INDEX IF NOT EXISTS device_folder_index ON $tableName($columnDeviceFolder);
       ''');
   }
 
@@ -83,11 +87,8 @@ class IgnoredFilesDB {
     final duration = Duration(
         microseconds:
             endTime.microsecondsSinceEpoch - startTime.microsecondsSinceEpoch);
-    _logger.info("Batch insert of " +
-        ignoredFiles.length.toString() +
-        " took " +
-        duration.inMilliseconds.toString() +
-        "ms.");
+    _logger.info("Batch insert of ${ignoredFiles.length} "
+        "took ${duration.inMilliseconds} ms.");
   }
 
   Future<int> insert(IgnoredFile ignoredFile) async {
@@ -99,26 +100,45 @@ class IgnoredFilesDB {
     );
   }
 
-  // return map of localID to set of titles associated with the given localIDs
-  // Note: localIDs can easily clash across devices for Android, so we should
-  // always compare both localID & title in Android before ignoring the file for upload.
-  // iOS: localID is usually UUID and the title in localDB may be missing (before upload) as the
-  // photo manager library doesn't always fetch the title by default.
-  Future<Map<String, Set<String>>> getIgnoredFiles() async {
-    final db = await instance.database;
-    final rows = await db.query(tableName);
+  // returns a  map of device folder to set of title/filenames which exist
+  // in the particular device folder.
+  Future<Map<String, Set<String>>> getFilenamesForDeviceFolders(
+      Set<String> folders) async {
     final result = <String, Set<String>>{};
+    final db = await instance.database;
+
+    if (folders.isEmpty) {
+      return result;
+    }
+    String inParam = "";
+    for (final folder in folders) {
+      inParam += "'" + folder.replaceAll("'", "''") + "',";
+    }
+    inParam = inParam.substring(0, inParam.length - 1);
+    final rows =
+        await db.query(tableName, where: '$columnDeviceFolder IN ($inParam)');
     for (final row in rows) {
       final ignoredFile = _getIgnoredFileFromRow(row);
       result
-          .putIfAbsent(ignoredFile.localID, () => <String>{})
+          .putIfAbsent(ignoredFile.deviceFolder, () => <String>{})
           .add(ignoredFile.title);
     }
     return result;
   }
 
+  Future<Set<String>> getAllLocalIDs() async {
+    final db = await instance.database;
+    final rows = await db.query(tableName);
+    final result = <String>{};
+    for (final row in rows) {
+      result.add(row[columnLocalID]);
+    }
+    return result;
+  }
+
   IgnoredFile _getIgnoredFileFromRow(Map<String, dynamic> row) {
-    return IgnoredFile(row[columnLocalID], row[columnTitle], row[columnReason]);
+    return IgnoredFile(row[columnLocalID], row[columnTitle],
+        row[columnDeviceFolder], row[columnReason]);
   }
 
   Map<String, dynamic> _getRowForIgnoredFile(IgnoredFile ignoredFile) {
@@ -127,6 +147,7 @@ class IgnoredFilesDB {
     final row = <String, dynamic>{};
     row[columnLocalID] = ignoredFile.localID;
     row[columnTitle] = ignoredFile.title;
+    row[columnDeviceFolder] = ignoredFile.deviceFolder;
     row[columnReason] = ignoredFile.reason;
     return row;
   }

+ 8 - 4
lib/models/ignored_file.dart

@@ -6,19 +6,23 @@ const kIgnoreReasonInvalidFile = "invalidFile";
 class IgnoredFile {
   final String localID;
   final String title;
+  final String deviceFolder;
   String reason;
 
-  IgnoredFile(this.localID, this.title, this.reason);
+  IgnoredFile(this.localID, this.title, this.deviceFolder, this.reason);
 
   factory IgnoredFile.fromTrashItem(TrashFile trashFile) {
     if (trashFile == null) return null;
     if (trashFile.localID == null ||
-        trashFile.title == null ||
         trashFile.localID.isEmpty ||
-        trashFile.title.isEmpty) {
+        trashFile.title == null ||
+        trashFile.title.isEmpty ||
+        trashFile.deviceFolder == null ||
+        trashFile.deviceFolder.isEmpty) {
       return null;
     }
 
-    return IgnoredFile(trashFile.localID, trashFile.title, kIgnoreReasonTrash);
+    return IgnoredFile(trashFile.localID, trashFile.title,
+        trashFile.deviceFolder, kIgnoreReasonTrash);
   }
 }

+ 2 - 1
lib/services/collections_service.dart

@@ -153,7 +153,8 @@ class CollectionsService {
   List<Collection> getActiveCollections() {
     return _collectionIDToCollections.values
         .toList()
-        .where((element) => !element.isDeleted);
+        .where((element) => !element.isDeleted)
+        .toList();
   }
 
   Future<List<User>> getSharees(int collectionID) {

+ 29 - 20
lib/services/remote_sync_service.dart

@@ -66,8 +66,9 @@ class RemoteSyncService {
     // this is to ensure that we don't pause upload due to any error during
     // the trash sync. Impact: We may end up re-uploading a file which was
     // recently trashed.
-    await TrashSyncService.instance.syncTrash()
-    .onError((e, s) => _logger.severe('trash sync failed', e, s));
+    await TrashSyncService.instance
+        .syncTrash()
+        .onError((e, s) => _logger.severe('trash sync failed', e, s));
     bool hasUploadedFiles = await _uploadDiff();
     if (hasUploadedFiles) {
       sync(silently: true);
@@ -126,21 +127,24 @@ class RemoteSyncService {
     }
   }
 
+  // This method checks for deviceFolder + title for Android.
+  // For iOS, we rely on localIDs as they are uuid as title or deviceFolder (aka
+  // album name) can be missing due to various reasons.
   bool _shouldIgnoreFileUpload(
-      Map<String, Set<String>> ignoredFilesMap, File file) {
+    File file, {
+    Map<String, Set<String>> ignoredFilesMap,
+    Set<String> ignoredLocalIDs,
+  }) {
     if (file.localID == null || file.localID.isEmpty) {
       return false;
     }
-    if (!ignoredFilesMap.containsKey(file.localID)) {
-      return false;
-    }
-    // only compare title in Android because title may be missing in IOS
-    // and iOS anyways use uuid for localIDs of file, so collision should be
-    // rare.
-    if (Platform.isAndroid) {
-      return ignoredFilesMap[file.localID].contains(file.title ?? '');
+    if (Platform.isIOS) {
+      return ignoredLocalIDs.contains(file.localID);
     }
-    return true;
+    // For android, check if there's any ignored file with same device folder
+    // and title.
+    return ignoredFilesMap.containsKey(file.deviceFolder) &&
+        ignoredFilesMap[file.deviceFolder].contains(file.title);
   }
 
   Future<bool> _uploadDiff() async {
@@ -158,10 +162,17 @@ class RemoteSyncService {
           .removeWhere((element) => element.fileType == FileType.video);
     }
     if (filesToBeUploaded.isNotEmpty) {
-      final ignoredFilesMap = await IgnoredFilesDB.instance.getIgnoredFiles();
       final int prevCount = filesToBeUploaded.length;
-      filesToBeUploaded.removeWhere(
-          (file) => _shouldIgnoreFileUpload(ignoredFilesMap, file));
+      if (Platform.isAndroid) {
+        final ignoredFilesMap = await IgnoredFilesDB.instance
+            .getFilenamesForDeviceFolders(foldersToBackUp);
+        filesToBeUploaded.removeWhere((file) =>
+            _shouldIgnoreFileUpload(file, ignoredFilesMap: ignoredFilesMap));
+      } else {
+        final ignoredLocalIDs = await IgnoredFilesDB.instance.getAllLocalIDs();
+        filesToBeUploaded.removeWhere((file) =>
+            _shouldIgnoreFileUpload(file, ignoredLocalIDs: ignoredLocalIDs));
+      }
       if (prevCount != filesToBeUploaded.length) {
         _logger.info((prevCount - filesToBeUploaded.length).toString() +
             " files were ignored for upload");
@@ -240,12 +251,10 @@ class RemoteSyncService {
     if (_completedUploads > toBeUploadedInThisSession ||
         _completedUploads < 0 ||
         toBeUploadedInThisSession < 0) {
-      _logger.severe(
+      _logger.info(
           "Incorrect sync status",
-          InvalidSyncStatusError("Tried to report " +
-              _completedUploads.toString() +
-              " as uploaded out of " +
-              toBeUploadedInThisSession.toString()));
+          InvalidSyncStatusError("Tried to report $_completedUploads as "
+              "uploaded out of $toBeUploadedInThisSession"));
       return;
     }
     Bus.instance.fire(SyncStatusUpdate(SyncStatus.in_progress,

+ 13 - 10
lib/ui/common/dialogs.dart

@@ -1,10 +1,7 @@
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 
-enum DialogUserChoice {
-  firstChoice,
-  secondChoice
-}
+enum DialogUserChoice { firstChoice, secondChoice }
 
 enum ActionType {
   confirm,
@@ -20,19 +17,25 @@ Future<T> showChoiceDialog<T>(
   ActionType actionType = ActionType.confirm,
 }) {
   AlertDialog alert = AlertDialog(
-    title: Text(title,
+    title: Text(
+      title,
       style: TextStyle(
-        color:
-            actionType == ActionType.critical ? Colors.red : Colors.white,
+        color: actionType == ActionType.critical ? Colors.red : Colors.white,
+      ),
+    ),
+    content: Text(
+      content,
+      style: TextStyle(
+        height: 1.4,
       ),
     ),
-    content: Text(content),
     actions: [
       TextButton(
         child: Text(
           firstAction,
           style: TextStyle(
-            color: actionType == ActionType.critical ? Colors.red : Colors.white,
+            color:
+                actionType == ActionType.critical ? Colors.red : Colors.white,
           ),
         ),
         onPressed: () {
@@ -62,4 +65,4 @@ Future<T> showChoiceDialog<T>(
     },
     barrierColor: Colors.black87,
   );
-}
+}

+ 3 - 1
lib/ui/detail_page.dart

@@ -201,7 +201,9 @@ class _DetailPageState extends State<DetailPage> {
           limit: kLoadLimit,
           asc: true);
       setState(() {
-        final files = result.files.reversed.toList();
+        // Returned result could be a subtype of File
+        // ignore: unnecessary_cast
+        final files = result.files.reversed.map((e) => e as File).toList();
         if (!result.hasMore) {
           _hasLoadedTillStart = true;
         }

+ 22 - 12
lib/ui/fading_app_bar.dart

@@ -264,7 +264,7 @@ class FadingAppBarState extends State<FadingAppBar> {
 
   void _showDeleteSheet(File file) {
     final List<Widget> actions = [];
-    if (file.uploadedFileID == null) {
+    if (file.uploadedFileID == null || file.localID == null) {
       actions.add(CupertinoActionSheetAction(
         child: Text("everywhere"),
         isDestructiveAction: true,
@@ -274,17 +274,27 @@ class FadingAppBarState extends State<FadingAppBar> {
         },
       ));
     } else {
-      if (file.localID != null) {
-        actions.add(CupertinoActionSheetAction(
-          child: Text("on this device"),
-          isDestructiveAction: true,
-          onPressed: () async {
-            await deleteFilesOnDeviceOnly(context, [file]);
-            showToast("file deleted from device");
-            Navigator.of(context, rootNavigator: true).pop();
-          },
-        ));
-      }
+      // uploaded file which is present locally too
+      actions.add(CupertinoActionSheetAction(
+        child: Text("device"),
+        isDestructiveAction: true,
+        onPressed: () async {
+          await deleteFilesOnDeviceOnly(context, [file]);
+          showToast("file deleted from device");
+          Navigator.of(context, rootNavigator: true).pop();
+        },
+      ));
+
+      actions.add(CupertinoActionSheetAction(
+        child: Text("ente"),
+        isDestructiveAction: true,
+        onPressed: () async {
+          await deleteFilesFromRemoteOnly(context, [file]);
+          showToast("moved to trash");
+          Navigator.of(context, rootNavigator: true).pop();
+        },
+      ));
+
       actions.add(CupertinoActionSheetAction(
         child: Text("everywhere"),
         isDestructiveAction: true,

+ 19 - 15
lib/ui/gallery_app_bar_widget.dart

@@ -93,6 +93,8 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
                   _appBarTitle,
                   style: TextStyle(
                     color: Colors.white.withOpacity(0.80),
+                    fontWeight: FontWeight.bold,
+                    fontSize: 16,
                   ),
                 ),
                 onPressed: () => _renameAlbum(context),
@@ -192,7 +194,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
         },
       ));
     }
-    if(widget.type == GalleryAppBarType.trash) {
+    if (widget.type == GalleryAppBarType.trash) {
       actions.add(
         Tooltip(
           message: "empty trash",
@@ -416,18 +418,20 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
         },
       ),
     ));
-    actions.add(Tooltip(
-      message: "delete permanently",
-      child: IconButton(
-        icon: Icon(Icons.delete_forever_outlined),
-        onPressed: () async {
-          if (await deleteFromTrash(
-              context, widget.selectedFiles.files.toList())) {
-            _clearSelectedFiles();
-          }
-        },
+    actions.add(
+      Tooltip(
+        message: "delete permanently",
+        child: IconButton(
+          icon: Icon(Icons.delete_forever_outlined),
+          onPressed: () async {
+            if (await deleteFromTrash(
+                context, widget.selectedFiles.files.toList())) {
+              _clearSelectedFiles();
+            }
+          },
+        ),
       ),
-    ));
+    );
   }
 
   Future<void> _handleVisibilityChangeRequest(
@@ -502,7 +506,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
     final actions = <Widget>[];
     if (containsUploadedFile && containsLocalFile) {
       actions.add(CupertinoActionSheetAction(
-        child: Text("this device"),
+        child: Text("device"),
         isDestructiveAction: true,
         onPressed: () async {
           Navigator.of(context, rootNavigator: true).pop();
@@ -520,7 +524,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
           await deleteFilesFromRemoteOnly(
               context, widget.selectedFiles.files.toList());
           _clearSelectedFiles();
-          showToast("deleted files are moved to trash");
+          showToast("moved to trash");
         },
       ));
       actions.add(CupertinoActionSheetAction(
@@ -535,7 +539,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
       ));
     } else {
       actions.add(CupertinoActionSheetAction(
-        child: Text("delete forever"),
+        child: Text("delete"),
         isDestructiveAction: true,
         onPressed: () async {
           Navigator.of(context, rootNavigator: true).pop();

+ 44 - 43
lib/ui/trash_page.dart

@@ -1,5 +1,3 @@
-import 'dart:io';
-
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:photos/core/event_bus.dart';
@@ -16,40 +14,41 @@ class TrashPage extends StatelessWidget {
   final GalleryAppBarType appBarType;
   final _selectedFiles = SelectedFiles();
 
-  TrashPage(
-      {this.tagPrefix = "trash_page",
-      this.appBarType = GalleryAppBarType.trash,
-      Key key})
-      : super(key: key);
+  TrashPage({
+    this.tagPrefix = "trash_page",
+    this.appBarType = GalleryAppBarType.trash,
+    Key key,
+  }) : super(key: key);
 
   @override
   Widget build(Object context) {
     final gallery = Gallery(
-        asyncLoader: (creationStartTime, creationEndTime, {limit, asc}) {
-          return TrashDB.instance.getTrashedFiles(
-              creationStartTime, creationEndTime,
-              limit: limit, asc: asc);
-        },
-        reloadEvent: Bus.instance.on<FilesUpdatedEvent>().where(
+      asyncLoader: (creationStartTime, creationEndTime, {limit, asc}) {
+        return TrashDB.instance.getTrashedFiles(
+            creationStartTime, creationEndTime,
+            limit: limit, asc: asc);
+      },
+      reloadEvent: Bus.instance.on<FilesUpdatedEvent>().where(
+            (event) =>
+                event.updatedFiles.firstWhere(
+                    (element) => element.uploadedFileID != null,
+                    orElse: () => null) !=
+                null,
+          ),
+      forceReloadEvents: [
+        Bus.instance.on<FilesUpdatedEvent>().where(
               (event) =>
                   event.updatedFiles.firstWhere(
                       (element) => element.uploadedFileID != null,
                       orElse: () => null) !=
                   null,
             ),
-        forceReloadEvents: [
-          Bus.instance.on<FilesUpdatedEvent>().where(
-                (event) =>
-                    event.updatedFiles.firstWhere(
-                        (element) => element.uploadedFileID != null,
-                        orElse: () => null) !=
-                    null,
-              ),
-        ],
-        tagPrefix: tagPrefix,
-        selectedFiles: _selectedFiles,
-        initialFiles: null,
-        footer: _footerWidget());
+      ],
+      tagPrefix: tagPrefix,
+      selectedFiles: _selectedFiles,
+      header: _headerWidget(),
+      initialFiles: null,
+    );
 
     return Scaffold(
       appBar: PreferredSize(
@@ -64,24 +63,26 @@ class TrashPage extends StatelessWidget {
     );
   }
 
-  Widget _footerWidget() {
+  Widget _headerWidget() {
     return FutureBuilder<FileLoadResult>(
-        future: TrashDB.instance
-            .getTrashedFiles(0, DateTime.now().microsecondsSinceEpoch),
-        builder: (context, snapshot) {
-          if (snapshot.hasData && snapshot.data.files.isNotEmpty) {
-            return Padding(
-              padding: EdgeInsets.all(15),
-              child: Text(
-                'memories shows the number the days after which they will be permanently deleted.',
-                style: TextStyle(
-                  fontSize: 16,
-                ),
+      future: TrashDB.instance
+          .getTrashedFiles(0, DateTime.now().microsecondsSinceEpoch),
+      builder: (context, snapshot) {
+        if (snapshot.hasData && snapshot.data.files.isNotEmpty) {
+          return Padding(
+            padding: EdgeInsets.all(16),
+            child: Text(
+              'items show the number the days remaining before permanent deletion',
+              style: TextStyle(
+                fontSize: 16,
+                color: Colors.white.withOpacity(0.6),
               ),
-            );
-          } else {
-            return Container();
-          }
-        });
+            ),
+          );
+        } else {
+          return Container();
+        }
+      },
+    );
   }
 }

+ 20 - 19
lib/utils/delete_file_util.dart

@@ -16,7 +16,6 @@ import 'package:photos/events/collection_updated_event.dart';
 import 'package:photos/events/files_updated_event.dart';
 import 'package:photos/events/local_photos_updated_event.dart';
 import 'package:photos/models/file.dart';
-import 'package:photos/models/trash_file.dart';
 import 'package:photos/models/trash_item_request.dart';
 import 'package:photos/services/remote_sync_service.dart';
 import 'package:photos/services/sync_service.dart';
@@ -68,7 +67,8 @@ Future<void> deleteFilesFromEverywhere(
           alreadyDeletedIDs.contains(file.localID)) {
         deletedFiles.add(file);
         if (file.uploadedFileID != null) {
-          uploadedFilesToBeTrashed.add(TrashRequest(file.uploadedFileID, file.collectionID));
+          uploadedFilesToBeTrashed
+              .add(TrashRequest(file.uploadedFileID, file.collectionID));
           updatedCollectionIDs.add(file.collectionID);
         } else {
           await FilesDB.instance.deleteLocalFile(file);
@@ -77,16 +77,19 @@ Future<void> deleteFilesFromEverywhere(
     } else {
       updatedCollectionIDs.add(file.collectionID);
       deletedFiles.add(file);
-      uploadedFilesToBeTrashed.add(TrashRequest(file.uploadedFileID, file.collectionID));
+      uploadedFilesToBeTrashed
+          .add(TrashRequest(file.uploadedFileID, file.collectionID));
     }
   }
   if (uploadedFilesToBeTrashed.isNotEmpty) {
     try {
-      final fileIDs = uploadedFilesToBeTrashed.map((item) => item.fileID).toList();
-      await TrashSyncService.instance.trashFilesOnServer(uploadedFilesToBeTrashed);
+      final fileIDs =
+          uploadedFilesToBeTrashed.map((item) => item.fileID).toList();
+      await TrashSyncService.instance
+          .trashFilesOnServer(uploadedFilesToBeTrashed);
       // await SyncService.instance
       //     .deleteFilesOnServer(fileIDs);
-       await FilesDB.instance.deleteMultipleUploadedFiles(fileIDs);
+      await FilesDB.instance.deleteMultipleUploadedFiles(fileIDs);
     } catch (e) {
       _logger.severe(e);
       await dialog.hide();
@@ -108,7 +111,7 @@ Future<void> deleteFilesFromEverywhere(
         .fire(LocalPhotosUpdatedEvent(deletedFiles, type: EventType.deleted));
   }
   await dialog.hide();
-  showToast("deleted from everywhere");
+  showToast("moved to trash");
   if (uploadedFilesToBeTrashed.isNotEmpty) {
     RemoteSyncService.instance.sync(silently: true);
   }
@@ -117,7 +120,7 @@ Future<void> deleteFilesFromEverywhere(
 Future<void> deleteFilesFromRemoteOnly(
     BuildContext context, List<File> files) async {
   files.removeWhere((element) => element.uploadedFileID == null);
-  if(files.isEmpty) {
+  if (files.isEmpty) {
     showToast("selected files are not on ente");
     return;
   }
@@ -149,8 +152,7 @@ Future<void> deleteFilesFromRemoteOnly(
       type: EventType.deleted,
     ));
   }
-  Bus.instance
-        .fire(LocalPhotosUpdatedEvent(files, type: EventType.deleted));
+  Bus.instance.fire(LocalPhotosUpdatedEvent(files, type: EventType.deleted));
   SyncService.instance.sync();
   await dialog.hide();
   RemoteSyncService.instance.sync(silently: true);
@@ -201,10 +203,9 @@ Future<void> deleteFilesOnDeviceOnly(
   await dialog.hide();
 }
 
-Future<bool> deleteFromTrash(
-    BuildContext context, List<File> files) async {
-  final result = await showChoiceDialog(context, "delete permanently?",
-      "the files will be permanently removed from your ente account",
+Future<bool> deleteFromTrash(BuildContext context, List<File> files) async {
+  final result = await showChoiceDialog(
+      context, "delete permanently?", "this action cannot be undone",
       firstAction: "delete", actionType: ActionType.critical);
   if (result != DialogUserChoice.firstChoice) {
     return false;
@@ -225,11 +226,10 @@ Future<bool> deleteFromTrash(
   }
 }
 
-
 Future<bool> emptyTrash(BuildContext context) async {
   final result = await showChoiceDialog(context, "empty trash?",
-      "all files will be permanently removed from your ente account",
-      firstAction: "yes", actionType: ActionType.critical);
+      "these files will be permanently removed from your ente account",
+      firstAction: "empty", actionType: ActionType.critical);
   if (result != DialogUserChoice.firstChoice) {
     return false;
   }
@@ -237,9 +237,10 @@ Future<bool> emptyTrash(BuildContext context) async {
   await dialog.show();
   try {
     await TrashSyncService.instance.emptyTrash();
-    showToast("done");
+    showToast("trash emptied");
     await dialog.hide();
-    Bus.instance.fire(FilesUpdatedEvent((List<File>.empty()), type: EventType.deleted));
+    Bus.instance
+        .fire(FilesUpdatedEvent((List<File>.empty()), type: EventType.deleted));
     return true;
   } catch (e, s) {
     _logger.info("failed empty trash", e, s);

+ 2 - 2
lib/utils/file_uploader.dart

@@ -248,7 +248,7 @@ class FileUploader {
     }
     final fileOnDisk = await FilesDB.instance.getFile(file.generatedID);
     final wasAlreadyUploaded = fileOnDisk.uploadedFileID != null &&
-        fileOnDisk.updationTime != null &&
+        fileOnDisk.updationTime != -1 &&
         fileOnDisk.collectionID == collectionID;
     if (wasAlreadyUploaded) {
       return fileOnDisk;
@@ -293,7 +293,7 @@ class FileUploader {
       }
       Uint8List key;
       bool isUpdatedFile =
-          file.uploadedFileID != null && file.updationTime == null;
+          file.uploadedFileID != null && file.updationTime == -1;
       if (isUpdatedFile) {
         _logger.info("File was updated " + file.toString());
         key = decryptFileKey(file);