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

Add support for persisting ignored files

Neeraj Gupta 3 éve
szülő
commit
df6eeb407b
2 módosított fájl, 127 hozzáadás és 0 törlés
  1. 119 0
      lib/db/ignore_files_db.dart
  2. 8 0
      lib/models/ignored_file.dart

+ 119 - 0
lib/db/ignore_files_db.dart

@@ -0,0 +1,119 @@
+import 'dart:io';
+import 'package:path/path.dart';
+import 'package:logging/logging.dart';
+import 'package:path_provider/path_provider.dart';
+import 'package:photos/models/ignored_file.dart';
+import 'package:sqflite/sqflite.dart';
+
+// Keeps track of local fileIDs which should be not uploaded to ente without
+// user's intervention, even if they marked the folder for backup.
+// Common cases: when a user deletes a file just from ente on current device or
+// when they delete a file from web/another device, we should not automatically
+// upload the files.
+class IgnoreFilesDB {
+  static const kIgnoreReasonTrash = "trash";
+  static const kIgnoreReasonInvalidFile = "invalidFile";
+
+  static final _databaseName = "ente.ignore_files.db";
+  static final _databaseVersion = 1;
+  static final Logger _logger = Logger("IgnoreFilesDB");
+  static final tableName = 'ignored_files';
+
+  static final columnLocalID = 'local_id';
+  static final columnDeviceFolder = 'device_folder';
+  static final columnTitle = 'title';
+  static final columnReason = 'reason';
+
+  Future _onCreate(Database db, int version) async {
+    await db.execute('''
+        CREATE TABLE $tableName (
+          $columnLocalID TEXT NOT NULL,
+          $columnTitle TEXT NOT NULL,
+          $columnDeviceFolder TEXT,
+          $columnReason TEXT DEFAULT $kIgnoreReasonTrash,
+          UNIQUE($columnLocalID, $columnDeviceFolder, $columnDeviceFolder)
+        );
+      CREATE INDEX IF NOT EXISTS local_id_index ON $tableName($columnLocalID);
+      CREATE INDEX IF NOT EXISTS device_folder_index ON $tableName($columnDeviceFolder);
+      ''');
+  }
+
+  IgnoreFilesDB._privateConstructor();
+
+  static final IgnoreFilesDB instance = IgnoreFilesDB._privateConstructor();
+
+  // only have a single app-wide reference to the database
+  static Future<Database> _dbFuture;
+
+  Future<Database> get database async {
+    // lazily instantiate the db the first time it is accessed
+    _dbFuture ??= _initDatabase();
+    return _dbFuture;
+  }
+
+  // this opens the database (and creates it if it doesn't exist)
+  Future<Database> _initDatabase() async {
+    Directory documentsDirectory = await getApplicationDocumentsDirectory();
+    String path = join(documentsDirectory.path, _databaseName);
+    return await openDatabase(
+      path,
+      version: _databaseVersion,
+      onCreate: _onCreate,
+    );
+  }
+
+  Future<void> clearTable() async {
+    final db = await instance.database;
+    await db.delete(tableName);
+  }
+
+  Future<void> insertMultiple(List<IgnoredFile> ignoredFiles) async {
+    final startTime = DateTime.now();
+    final db = await instance.database;
+    var batch = db.batch();
+    int batchCounter = 0;
+    for (IgnoredFile file in ignoredFiles) {
+      if (batchCounter == 400) {
+        await batch.commit(noResult: true);
+        batch = db.batch();
+        batchCounter = 0;
+      }
+      batch.insert(
+        tableName,
+        _getRowForIgnoredFile(file),
+        conflictAlgorithm: ConflictAlgorithm.replace,
+      );
+      batchCounter++;
+    }
+    await batch.commit(noResult: true);
+    final endTime = DateTime.now();
+    final duration = Duration(
+        microseconds:
+            endTime.microsecondsSinceEpoch - startTime.microsecondsSinceEpoch);
+    _logger.info("Batch insert of " +
+        ignoredFiles.length.toString() +
+        " took " +
+        duration.inMilliseconds.toString() +
+        "ms.");
+  }
+
+  Future<int> insert(IgnoredFile ignoredFile) async {
+    final db = await instance.database;
+    return db.insert(
+      tableName,
+      _getRowForIgnoredFile(ignoredFile),
+      conflictAlgorithm: ConflictAlgorithm.replace,
+    );
+  }
+
+  Map<String, dynamic> _getRowForIgnoredFile(IgnoredFile ignoredFile) {
+    final row = <String, dynamic>{};
+    row[columnLocalID] = ignoredFile.localID;
+    row[columnTitle] = ignoredFile.title;
+    row[columnDeviceFolder] = ignoredFile.deviceFolder;
+    if (ignoredFile.reason != null && ignoredFile.reason != "") {
+      row[columnReason] = ignoredFile.reason;
+    }
+    return row;
+  }
+}

+ 8 - 0
lib/models/ignored_file.dart

@@ -0,0 +1,8 @@
+class IgnoredFile {
+  final String localID;
+  final String deviceFolder;
+  final String title;
+  String reason;
+
+  IgnoredFile(this.localID, this.deviceFolder, this.title, this.reason);
+}