From d600d6e3b72e869eeadfcf0d96903635c8576a0a Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Wed, 21 Jul 2021 20:06:42 +0530 Subject: [PATCH 01/14] Fix linter suggestions --- lib/services/collections_service.dart | 43 ++++++++++++--------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/lib/services/collections_service.dart b/lib/services/collections_service.dart index a2adb9ad7..54761b661 100644 --- a/lib/services/collections_service.dart +++ b/lib/services/collections_service.dart @@ -35,9 +35,9 @@ class CollectionsService { SharedPreferences _prefs; Future> _cachedLatestFiles; final _dio = Network.instance.getDio(); - final _localCollections = Map(); - final _collectionIDToCollections = Map(); - final _cachedKeys = Map(); + final _localCollections = {}; + final _collectionIDToCollections = {}; + final _cachedKeys = {}; CollectionsService._privateConstructor() { _db = CollectionsDB.instance; @@ -72,7 +72,7 @@ class CollectionsService { // Might not have synced the collection fully final fetchedCollections = await _fetchCollections(lastCollectionUpdationTime ?? 0); - final updatedCollections = List(); + final updatedCollections = []; int maxUpdationTime = lastCollectionUpdationTime; for (final collection in fetchedCollections) { if (collection.isDeleted) { @@ -100,7 +100,7 @@ class CollectionsService { return collections; } - Future clearCache() { + void clearCache() { _localCollections.clear(); _collectionIDToCollections.clear(); _cachedKeys.clear(); @@ -108,7 +108,7 @@ class CollectionsService { Future> getCollectionsToBeSynced() async { final collections = await _db.getAllCollections(); - final updatedCollections = List(); + final updatedCollections = []; for (final c in collections) { if (c.updationTime > getCollectionSyncTime(c.id)) { updatedCollections.add(c); @@ -118,18 +118,13 @@ class CollectionsService { } int getCollectionSyncTime(int collectionID) { - var syncTime = - _prefs.getInt(_collectionSyncTimeKeyPrefix + collectionID.toString()); - if (syncTime == null) { - syncTime = 0; - } - return syncTime; + return _prefs + .getInt(_collectionSyncTimeKeyPrefix + collectionID.toString()) ?? + 0; } Future> getLatestCollectionFiles() { - if (_cachedLatestFiles == null) { - _cachedLatestFiles = _filesDB.getLatestCollectionFiles(); - } + _cachedLatestFiles ??= _filesDB.getLatestCollectionFiles(); return _cachedLatestFiles; } @@ -161,7 +156,7 @@ class CollectionsService { ) .then((response) { _logger.info(response.toString()); - final sharees = List(); + final sharees = []; for (final user in response.data["sharees"]) { sharees.add(User.fromMap(user)); } @@ -187,7 +182,7 @@ class CollectionsService { if (e.response.statusCode == 402) { throw SharingNotPermittedForFreeAccountsError(); } - throw e; + rethrow; } RemoteSyncService.instance.sync(silently: true); } @@ -209,7 +204,7 @@ class CollectionsService { _db.insert([_collectionIDToCollections[collectionID]]); } catch (e) { _logger.severe(e); - throw e; + rethrow; } RemoteSyncService.instance.sync(silently: true); } @@ -257,7 +252,7 @@ class CollectionsService { if (e is DioError && e.response?.statusCode == 401) { throw UnauthorizedError(); } - throw e; + rethrow; } } @@ -313,7 +308,7 @@ class CollectionsService { } Future addToCollection(int collectionID, List files) { - final params = Map(); + final params = {}; params["collectionID"] = collectionID; for (final file in files) { final key = decryptFileKey(file); @@ -344,11 +339,11 @@ class CollectionsService { } Future removeFromCollection(int collectionID, List files) async { - final params = Map(); + final params = {}; params["collectionID"] = collectionID; for (final file in files) { if (params["fileIDs"] == null) { - params["fileIDs"] = List(); + params["fileIDs"] = []; } params["fileIDs"].add(file.uploadedFileID); } @@ -401,7 +396,7 @@ class CollectionsService { Collection _getCollectionWithDecryptedName(Collection collection) { if (collection.encryptedName != null && collection.encryptedName.isNotEmpty) { - var name; + String name; try { final result = CryptoUtil.decryptSync( Sodium.base642bin(collection.encryptedName), @@ -429,7 +424,7 @@ class CollectionsService { if (attempt < kMaximumWriteAttempts) { return _updateDB(collections, attempt: attempt++); } else { - throw e; + rethrow; } } } From b23dbe172806dc649818364c79c5076d324dad8a Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 22 Jul 2021 00:47:04 +0530 Subject: [PATCH 02/14] Remove debug endpoint --- lib/core/configuration.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/core/configuration.dart b/lib/core/configuration.dart index d658fa81b..68ace9aeb 100644 --- a/lib/core/configuration.dart +++ b/lib/core/configuration.dart @@ -2,7 +2,6 @@ import 'dart:convert'; import 'dart:io' as io; import 'dart:typed_data'; -import 'package:flutter/foundation.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_sodium/flutter_sodium.dart'; import 'package:logging/logging.dart'; @@ -255,9 +254,9 @@ class Configuration { } String getHttpEndpoint() { - if (kDebugMode) { - return "http://192.168.1.123:8080"; - } + // if (kDebugMode) { + // return "http://192.168.1.123:8080"; + // } return "https://api.ente.io"; } From 1d9e67c6c6b7ea855ab0436305af1986e605c33d Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 22 Jul 2021 00:48:29 +0530 Subject: [PATCH 03/14] Fix linter suggestions --- lib/core/configuration.dart | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/core/configuration.dart b/lib/core/configuration.dart index 68ace9aeb..8cb456950 100644 --- a/lib/core/configuration.dart +++ b/lib/core/configuration.dart @@ -65,7 +65,7 @@ class Configuration { _secureStorage = FlutterSecureStorage(); _documentsDirectory = (await getApplicationDocumentsDirectory()).path; _tempDirectory = _documentsDirectory + "/temp/"; - final tempDirectory = new io.Directory(_tempDirectory); + final tempDirectory = io.Directory(_tempDirectory); try { final currentTime = DateTime.now().microsecondsSinceEpoch; if (tempDirectory.existsSync() && @@ -196,7 +196,7 @@ class Configuration { attributes.memLimit, attributes.opsLimit, ); - var key; + Uint8List key; try { key = CryptoUtil.decryptSync(Sodium.base642bin(attributes.encryptedKey), kek, Sodium.base642bin(attributes.keyDecryptionNonce)); @@ -240,7 +240,7 @@ class Configuration { Future recover(String recoveryKey) async { final keyAttributes = getKeyAttributes(); - var masterKey; + Uint8List masterKey; try { masterKey = await CryptoUtil.decrypt( Sodium.base642bin(keyAttributes.masterKeyEncryptedWithRecoveryKey), @@ -248,7 +248,7 @@ class Configuration { Sodium.base642bin(keyAttributes.masterKeyDecryptionNonce)); } catch (e) { _logger.severe(e); - throw e; + rethrow; } await setKey(Sodium.bin2base64(masterKey)); } @@ -261,9 +261,7 @@ class Configuration { } String getToken() { - if (_cachedToken == null) { - _cachedToken = _preferences.getString(tokenKey); - } + _cachedToken ??= _preferences.getString(tokenKey); return _cachedToken; } @@ -308,7 +306,7 @@ class Configuration { if (_preferences.containsKey(foldersToBackUpKey)) { return _preferences.getStringList(foldersToBackUpKey).toSet(); } else { - return Set(); + return {}; } } @@ -341,8 +339,7 @@ class Configuration { } Future setKeyAttributes(KeyAttributes attributes) async { - await _preferences.setString( - keyAttributesKey, attributes == null ? null : attributes.toJson()); + await _preferences.setString(keyAttributesKey, attributes?.toJson()); } KeyAttributes getKeyAttributes() { From 54278ac89f3e3641430857dd4c6d4f1d88889345 Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 22 Jul 2021 01:25:24 +0530 Subject: [PATCH 04/14] Alter timestamp column types --- lib/db/files_db.dart | 166 ++++++++++++++++++++++++++++--------------- 1 file changed, 110 insertions(+), 56 deletions(-) diff --git a/lib/db/files_db.dart b/lib/db/files_db.dart index 51bbc1063..2cc23a1d4 100644 --- a/lib/db/files_db.dart +++ b/lib/db/files_db.dart @@ -46,28 +46,35 @@ class FilesDB { static final columnThumbnailDecryptionHeader = 'thumbnail_decryption_header'; static final columnMetadataDecryptionHeader = 'metadata_decryption_header'; - static final intitialScript = [...createTable(table), ...addIndex()]; - static final migrationScripts = [...alterDeviceFolderToAllowNULL()]; + static final initializationScript = [...createTable(table), ...addIndex()]; + static final migrationScripts = [ + ...alterDeviceFolderToAllowNULL(), + ...alterTimestampColumnTypes(), + ]; final dbConfig = MigrationConfig( - initializationScript: intitialScript, migrationScripts: migrationScripts); + initializationScript: initializationScript, + migrationScripts: migrationScripts); // make this a singleton class FilesDB._privateConstructor(); static final FilesDB instance = FilesDB._privateConstructor(); // only have a single app-wide reference to the database static Database _database; + static Future _dbFuture; + Future get database async { if (_database != null) return _database; // lazily instantiate the db the first time it is accessed - _database = await _initDatabase(); - return _database; + _dbFuture ??= _initDatabase(); + return _dbFuture; } // this opens the database (and creates it if it doesn't exist) - _initDatabase() async { + Future _initDatabase() async { Directory documentsDirectory = await getApplicationDocumentsDirectory(); String path = join(documentsDirectory.path, _databaseName); + _logger.info("DB path " + path); return await openDatabaseWithMigration(path, dbConfig); } @@ -105,8 +112,14 @@ class FilesDB { return [ ''' 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); ''' ]; @@ -128,6 +141,67 @@ class FilesDB { ]; } + static List alterTimestampColumnTypes() { + return [ + ''' + DROP TABLE IF EXISTS $tempTable; + ''', + ''' + CREATE TABLE $tempTable ( + $columnGeneratedID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + $columnLocalID TEXT, + $columnUploadedFileID INTEGER DEFAULT -1, + $columnOwnerID INTEGER, + $columnCollectionID INTEGER DEFAULT -1, + $columnTitle TEXT NOT NULL, + $columnDeviceFolder TEXT, + $columnLatitude REAL, + $columnLongitude REAL, + $columnFileType INTEGER, + $columnModificationTime INTEGER NOT NULL, + $columnEncryptedKey TEXT, + $columnKeyDecryptionNonce TEXT, + $columnFileDecryptionHeader TEXT, + $columnThumbnailDecryptionHeader TEXT, + $columnMetadataDecryptionHeader TEXT, + $columnCreationTime INTEGER NOT NULL, + $columnUpdationTime INTEGER, + UNIQUE($columnLocalID, $columnUploadedFileID, $columnCollectionID) + ); + ''', + ''' + INSERT INTO $tempTable + SELECT + $columnGeneratedID, + $columnLocalID, + $columnUploadedFileID, + $columnOwnerID, + $columnCollectionID, + $columnTitle, + $columnDeviceFolder, + $columnLatitude, + $columnLongitude, + $columnFileType, + CAST($columnModificationTime AS INTEGER), + $columnEncryptedKey, + $columnKeyDecryptionNonce, + $columnFileDecryptionHeader, + $columnThumbnailDecryptionHeader, + $columnMetadataDecryptionHeader, + CAST($columnCreationTime AS INTEGER), + CAST($columnUpdationTime AS INTEGER) + FROM $table; + ''', + ''' + DROP TABLE $table; + ''', + ''' + ALTER TABLE $tempTable + RENAME TO $table; + ''', + ]; + } + Future clearTable() async { final db = await instance.database; await db.delete(table); @@ -208,7 +282,7 @@ class FilesDB { collectionID, ], ); - final ids = Set(); + final ids = {}; for (final result in results) { ids.add(result[columnUploadedFileID]); } @@ -223,8 +297,8 @@ class FilesDB { where: '$columnLocalID IS NOT NULL AND ($columnUploadedFileID IS NOT NULL AND $columnUploadedFileID IS NOT -1)', ); - final localIDs = Set(); - final uploadedIDs = Set(); + final localIDs = {}; + final uploadedIDs = {}; for (final result in results) { localIDs.add(result[columnLocalID]); uploadedIDs.add(result[columnUploadedFileID]); @@ -239,7 +313,7 @@ class FilesDB { final results = await db.query( table, where: - '$columnCreationTime >= ? AND $columnCreationTime <= ? AND $columnIsDeleted = 0 AND ($columnCollectionID IS NOT NULL AND $columnCollectionID IS NOT -1)', + '$columnCreationTime >= ? AND $columnCreationTime <= ? AND ($columnCollectionID IS NOT NULL AND $columnCollectionID IS NOT -1)', whereArgs: [startTime, endTime], orderBy: '$columnCreationTime ' + order + ', $columnModificationTime ' + order, @@ -256,7 +330,7 @@ class FilesDB { final results = await db.query( table, where: - '$columnCreationTime >= ? AND $columnCreationTime <= ? AND $columnIsDeleted = 0 AND ($columnLocalID IS NOT NULL OR ($columnCollectionID IS NOT NULL AND $columnCollectionID IS NOT -1))', + '$columnCreationTime >= ? AND $columnCreationTime <= ? AND ($columnLocalID IS NOT NULL OR ($columnCollectionID IS NOT NULL AND $columnCollectionID IS NOT -1))', whereArgs: [startTime, endTime], orderBy: '$columnCreationTime ' + order + ', $columnModificationTime ' + order, @@ -279,13 +353,13 @@ class FilesDB { final results = await db.query( table, where: - '$columnCreationTime >= ? AND $columnCreationTime <= ? AND $columnIsDeleted = 0 AND (($columnLocalID IS NOT NULL AND $columnDeviceFolder IN ($inParam)) OR ($columnCollectionID IS NOT NULL AND $columnCollectionID IS NOT -1))', + '$columnCreationTime >= ? AND $columnCreationTime <= ? AND (($columnLocalID IS NOT NULL AND $columnDeviceFolder IN ($inParam)) OR ($columnCollectionID IS NOT NULL AND $columnCollectionID IS NOT -1))', whereArgs: [startTime, endTime], orderBy: '$columnCreationTime ' + order + ', $columnModificationTime ' + order, limit: limit, ); - final uploadedFileIDs = Set(); + final uploadedFileIDs = {}; final files = _convertToFiles(results); final List deduplicatedFiles = []; for (final file in files) { @@ -307,7 +381,7 @@ class FilesDB { final results = await db.query( table, where: - '$columnCollectionID = ? AND $columnCreationTime >= ? AND $columnCreationTime <= ? AND $columnIsDeleted = 0', + '$columnCollectionID = ? AND $columnCreationTime >= ? AND $columnCreationTime <= ?', whereArgs: [collectionID, startTime, endTime], orderBy: '$columnCreationTime ' + order + ', $columnModificationTime ' + order, @@ -325,11 +399,11 @@ class FilesDB { final results = await db.query( table, where: - '$columnDeviceFolder = ? AND $columnCreationTime >= ? AND $columnCreationTime <= ? AND $columnLocalID IS NOT NULL AND $columnIsDeleted = 0', + '$columnDeviceFolder = ? AND $columnCreationTime >= ? AND $columnCreationTime <= ? AND $columnLocalID IS NOT NULL', whereArgs: [path, startTime, endTime], orderBy: '$columnCreationTime ' + order + ', $columnModificationTime ' + order, - groupBy: '$columnLocalID', + groupBy: columnLocalID, limit: limit, ); final files = _convertToFiles(results); @@ -340,8 +414,7 @@ class FilesDB { final db = await instance.database; final results = await db.query( table, - where: - '$columnLocalID IS NOT NULL AND $columnFileType = 1 AND $columnIsDeleted = 0', + where: '$columnLocalID IS NOT NULL AND $columnFileType = 1', orderBy: '$columnCreationTime DESC', ); return _convertToFiles(results); @@ -351,11 +424,10 @@ class FilesDB { final db = await instance.database; final results = await db.query( table, - where: - '$columnLocalID IS NOT NULL AND $columnDeviceFolder = ? AND $columnIsDeleted = 0', + where: '$columnLocalID IS NOT NULL AND $columnDeviceFolder = ?', whereArgs: [path], orderBy: '$columnCreationTime DESC', - groupBy: '$columnLocalID', + groupBy: columnLocalID, ); return _convertToFiles(results); } @@ -376,28 +448,12 @@ class FilesDB { } final results = await db.query( table, - where: whereClause + " AND $columnIsDeleted = 0", + where: whereClause, orderBy: '$columnCreationTime ASC', ); return _convertToFiles(results); } - Future> getDeletedFileIDs() async { - final db = await instance.database; - final rows = await db.query( - table, - columns: [columnUploadedFileID], - distinct: true, - where: '$columnIsDeleted = 1', - orderBy: '$columnCreationTime DESC', - ); - final result = List(); - for (final row in rows) { - result.add(row[columnUploadedFileID]); - } - return result; - } - Future> getFilesToBeUploadedWithinFolders( Set folders) async { if (folders.isEmpty) { @@ -414,7 +470,7 @@ class FilesDB { where: '($columnUploadedFileID IS NULL OR $columnUploadedFileID IS -1) AND $columnDeviceFolder IN ($inParam)', orderBy: '$columnCreationTime DESC', - groupBy: '$columnLocalID', + groupBy: columnLocalID, ); return _convertToFiles(results); } @@ -426,7 +482,7 @@ class FilesDB { where: '($columnUploadedFileID IS NULL OR $columnUploadedFileID IS -1) AND $columnLocalID IS NOT NULL', orderBy: '$columnCreationTime DESC', - groupBy: '$columnLocalID', + groupBy: columnLocalID, ); return _convertToFiles(results); } @@ -438,7 +494,7 @@ class FilesDB { where: '($columnCollectionID IS NOT NULL AND $columnCollectionID IS NOT -1) AND ($columnUploadedFileID IS NULL OR $columnUploadedFileID IS -1)', orderBy: '$columnCreationTime DESC', - groupBy: '$columnLocalID', + groupBy: columnLocalID, ); return _convertToFiles(results); } @@ -449,11 +505,11 @@ class FilesDB { table, columns: [columnUploadedFileID], where: - '($columnLocalID IS NOT NULL AND ($columnUploadedFileID IS NOT NULL AND $columnUploadedFileID IS NOT -1) AND $columnUpdationTime IS NULL AND $columnIsDeleted = 0)', + '($columnLocalID IS NOT NULL AND ($columnUploadedFileID IS NOT NULL AND $columnUploadedFileID IS NOT -1) AND $columnUpdationTime IS NULL)', orderBy: '$columnCreationTime DESC', distinct: true, ); - final uploadedFileIDs = List(); + final uploadedFileIDs = []; for (final row in rows) { uploadedFileIDs.add(row[columnUploadedFileID]); } @@ -484,7 +540,7 @@ class FilesDB { distinct: true, where: '$columnLocalID IS NOT NULL', ); - final result = Set(); + final result = {}; for (final row in rows) { result.add(row[columnLocalID]); } @@ -497,7 +553,7 @@ class FilesDB { table, columns: [columnUploadedFileID], where: - '($columnLocalID IS NOT NULL AND ($columnUploadedFileID IS NOT NULL AND $columnUploadedFileID IS NOT -1) AND $columnUpdationTime IS NOT NULL AND $columnIsDeleted = 0)', + '($columnLocalID IS NOT NULL AND ($columnUploadedFileID IS NOT NULL AND $columnUploadedFileID IS NOT -1) AND $columnUpdationTime IS NOT NULL)', distinct: true, ); return rows.length; @@ -666,7 +722,7 @@ class FilesDB { '''); final files = _convertToFiles(rows); // TODO: Do this de-duplication within the SQL Query - final folderMap = Map(); + final folderMap = {}; for (final file in files) { if (folderMap.containsKey(file.deviceFolder)) { if (folderMap[file.deviceFolder].updationTime < file.updationTime) { @@ -695,7 +751,7 @@ class FilesDB { '''); final files = _convertToFiles(rows); // TODO: Do this de-duplication within the SQL Query - final collectionMap = Map(); + final collectionMap = {}; for (final file in files) { if (collectionMap.containsKey(file.collectionID)) { if (collectionMap[file.collectionID].updationTime < file.updationTime) { @@ -711,7 +767,7 @@ class FilesDB { final db = await instance.database; final rows = await db.query( table, - where: '$columnCollectionID = ? AND $columnIsDeleted = 0', + where: '$columnCollectionID = ?', whereArgs: [collectionID], orderBy: '$columnUpdationTime DESC', limit: 1, @@ -731,7 +787,7 @@ class FilesDB { WHERE $columnLocalID IS NOT NULL GROUP BY $columnDeviceFolder '''); - final result = Map(); + final result = {}; for (final row in rows) { result[row[columnDeviceFolder]] = row["count"]; } @@ -759,7 +815,7 @@ class FilesDB { } Map _getRowForFile(File file) { - final row = new Map(); + final row = {}; if (file.generatedID != null) { row[columnGeneratedID] = file.generatedID; } @@ -795,7 +851,7 @@ class FilesDB { } Map _getRowForFileWithoutCollection(File file) { - final row = new Map(); + final row = {}; row[columnLocalID] = file.localID; row[columnUploadedFileID] = file.uploadedFileID ?? -1; row[columnOwnerID] = file.ownerID; @@ -839,11 +895,9 @@ class FilesDB { file.location = Location(row[columnLatitude], row[columnLongitude]); } file.fileType = getFileType(row[columnFileType]); - file.creationTime = int.parse(row[columnCreationTime]); - file.modificationTime = int.parse(row[columnModificationTime]); - file.updationTime = row[columnUpdationTime] == null - ? -1 - : int.parse(row[columnUpdationTime]); + file.creationTime = row[columnCreationTime]; + file.modificationTime = row[columnModificationTime]; + file.updationTime = row[columnUpdationTime] ?? -1; file.encryptedKey = row[columnEncryptedKey]; file.keyDecryptionNonce = row[columnKeyDecryptionNonce]; file.fileDecryptionHeader = row[columnFileDecryptionHeader]; From c6ce7f2850262dacb51754a738be151d953ecefb Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 22 Jul 2021 01:51:31 +0530 Subject: [PATCH 05/14] Add indices --- lib/db/files_db.dart | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/db/files_db.dart b/lib/db/files_db.dart index 2cc23a1d4..61a81b386 100644 --- a/lib/db/files_db.dart +++ b/lib/db/files_db.dart @@ -46,10 +46,11 @@ class FilesDB { static final columnThumbnailDecryptionHeader = 'thumbnail_decryption_header'; static final columnMetadataDecryptionHeader = 'metadata_decryption_header'; - static final initializationScript = [...createTable(table), ...addIndex()]; + static final initializationScript = [...createTable(table)]; static final migrationScripts = [ ...alterDeviceFolderToAllowNULL(), ...alterTimestampColumnTypes(), + ...addIndices(), ]; final dbConfig = MigrationConfig( @@ -108,19 +109,19 @@ class FilesDB { ]; } - static List addIndex() { + static List addIndices() { return [ ''' - CREATE INDEX collection_id_index ON $table($columnCollectionID); + CREATE INDEX IF NOT EXISTS collection_id_index ON $table($columnCollectionID); ''', ''' - CREATE INDEX device_folder_index ON $table($columnDeviceFolder); + CREATE INDEX IF NOT EXISTS device_folder_index ON $table($columnDeviceFolder); ''', ''' - CREATE INDEX creation_time_index ON $table($columnCreationTime); + CREATE INDEX IF NOT EXISTS creation_time_index ON $table($columnCreationTime); ''', ''' - CREATE INDEX updation_time_index ON $table($columnUpdationTime); + CREATE INDEX IF NOT EXISTS updation_time_index ON $table($columnUpdationTime); ''' ]; } From 2747810cb311b45b1ccb68aac487b43896f586f0 Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 22 Jul 2021 02:04:53 +0530 Subject: [PATCH 06/14] Ensure that DB inits occur only once --- lib/db/collections_db.dart | 10 +++++----- lib/db/files_db.dart | 2 -- lib/db/memories_db.dart | 11 +++++------ lib/db/public_keys_db.dart | 10 +++++----- lib/db/upload_locks_db.dart | 11 +++++------ 5 files changed, 20 insertions(+), 24 deletions(-) diff --git a/lib/db/collections_db.dart b/lib/db/collections_db.dart index fc92c87b0..53eef19f7 100644 --- a/lib/db/collections_db.dart +++ b/lib/db/collections_db.dart @@ -39,14 +39,14 @@ class CollectionsDB { CollectionsDB._privateConstructor(); static final CollectionsDB instance = CollectionsDB._privateConstructor(); - static Database _database; + static Future _dbFuture; + Future get database async { - if (_database != null) return _database; - _database = await _initDatabase(); - return _database; + _dbFuture ??= _initDatabase(); + return _dbFuture; } - _initDatabase() async { + Future _initDatabase() async { Directory documentsDirectory = await getApplicationDocumentsDirectory(); String path = join(documentsDirectory.path, _databaseName); return await openDatabaseWithMigration(path, dbConfig); diff --git a/lib/db/files_db.dart b/lib/db/files_db.dart index 61a81b386..940cff7af 100644 --- a/lib/db/files_db.dart +++ b/lib/db/files_db.dart @@ -61,11 +61,9 @@ class FilesDB { static final FilesDB instance = FilesDB._privateConstructor(); // only have a single app-wide reference to the database - static Database _database; static Future _dbFuture; Future get database async { - if (_database != null) return _database; // lazily instantiate the db the first time it is accessed _dbFuture ??= _initDatabase(); return _dbFuture; diff --git a/lib/db/memories_db.dart b/lib/db/memories_db.dart index b89fdd0e5..81eeba805 100644 --- a/lib/db/memories_db.dart +++ b/lib/db/memories_db.dart @@ -2,9 +2,9 @@ import 'dart:async'; import 'dart:io'; import 'package:path/path.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:photos/models/memory.dart'; import 'package:sqflite/sqflite.dart'; -import 'package:path_provider/path_provider.dart'; class MemoriesDB { static final _databaseName = "ente.memories.db"; @@ -18,14 +18,13 @@ class MemoriesDB { MemoriesDB._privateConstructor(); static final MemoriesDB instance = MemoriesDB._privateConstructor(); - static Database _database; + static Future _dbFuture; Future get database async { - if (_database != null) return _database; - _database = await _initDatabase(); - return _database; + _dbFuture ??= _initDatabase(); + return _dbFuture; } - _initDatabase() async { + Future _initDatabase() async { Directory documentsDirectory = await getApplicationDocumentsDirectory(); String path = join(documentsDirectory.path, _databaseName); return await openDatabase( diff --git a/lib/db/public_keys_db.dart b/lib/db/public_keys_db.dart index 6cd048c56..03501bab2 100644 --- a/lib/db/public_keys_db.dart +++ b/lib/db/public_keys_db.dart @@ -2,9 +2,9 @@ import 'dart:async'; import 'dart:io'; import 'package:path/path.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:photos/models/public_key.dart'; import 'package:sqflite/sqflite.dart'; -import 'package:path_provider/path_provider.dart'; class PublicKeysDB { static final _databaseName = "ente.public_keys.db"; @@ -18,11 +18,11 @@ class PublicKeysDB { PublicKeysDB._privateConstructor(); static final PublicKeysDB instance = PublicKeysDB._privateConstructor(); - static Database _database; + static Future _dbFuture; + Future get database async { - if (_database != null) return _database; - _database = await _initDatabase(); - return _database; + _dbFuture ??= _initDatabase(); + return _dbFuture; } _initDatabase() async { diff --git a/lib/db/upload_locks_db.dart b/lib/db/upload_locks_db.dart index 7ab9baffa..117aa7b16 100644 --- a/lib/db/upload_locks_db.dart +++ b/lib/db/upload_locks_db.dart @@ -2,8 +2,8 @@ import 'dart:async'; import 'dart:io'; import 'package:path/path.dart'; -import 'package:sqflite/sqflite.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:sqflite/sqflite.dart'; class UploadLocksDB { static const _databaseName = "ente.upload_locks.db"; @@ -17,14 +17,13 @@ class UploadLocksDB { UploadLocksDB._privateConstructor(); static final UploadLocksDB instance = UploadLocksDB._privateConstructor(); - static Database _database; + static Future _dbFuture; Future get database async { - if (_database != null) return _database; - _database = await _initDatabase(); - return _database; + _dbFuture ??= _initDatabase(); + return _dbFuture; } - _initDatabase() async { + Future _initDatabase() async { Directory documentsDirectory = await getApplicationDocumentsDirectory(); String path = join(documentsDirectory.path, _databaseName); return await openDatabase( From 9f8c409f3d993c773de76230f4cc47989a35105c Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 22 Jul 2021 02:17:43 +0530 Subject: [PATCH 07/14] Fix lint warnings --- lib/core/cache/thumbnail_cache.dart | 4 ++-- lib/core/constants.dart | 20 ++++++++-------- lib/main.dart | 6 ++--- lib/services/memories_service.dart | 2 +- lib/services/sync_service.dart | 2 +- lib/services/update_service.dart | 2 +- .../huge_listview/lazy_loading_gallery.dart | 2 +- lib/ui/settings/support_section_widget.dart | 2 +- lib/ui/thumbnail_widget.dart | 14 +++++------ lib/ui/zoomable_image.dart | 12 +++++----- lib/utils/delete_file_util.dart | 2 +- lib/utils/file_uploader_util.dart | 11 ++++----- lib/utils/file_util.dart | 24 +++++++++---------- lib/utils/thumbnail_util.dart | 11 ++++----- 14 files changed, 56 insertions(+), 58 deletions(-) diff --git a/lib/core/cache/thumbnail_cache.dart b/lib/core/cache/thumbnail_cache.dart index b9979d8ef..e9aaec52d 100644 --- a/lib/core/cache/thumbnail_cache.dart +++ b/lib/core/cache/thumbnail_cache.dart @@ -10,7 +10,7 @@ class ThumbnailLruCache { static Uint8List get(File photo, [int size]) { return _map.get(photo.generatedID.toString() + "_" + - (size != null ? size.toString() : THUMBNAIL_LARGE_SIZE.toString())); + (size != null ? size.toString() : kThumbnailLargeSize.toString())); } static void put( @@ -21,7 +21,7 @@ class ThumbnailLruCache { _map.put( photo.generatedID.toString() + "_" + - (size != null ? size.toString() : THUMBNAIL_LARGE_SIZE.toString()), + (size != null ? size.toString() : kThumbnailLargeSize.toString()), imageData); } } diff --git a/lib/core/constants.dart b/lib/core/constants.dart index 647db6e30..d1c90f81c 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -1,12 +1,12 @@ -const int THUMBNAIL_SMALL_SIZE = 256; -const int THUMBNAIL_QUALITY = 50; -const int THUMBNAIL_LARGE_SIZE = 512; -const int COMPRESSED_THUMBNAIL_RESOLUTION = 1080; -const int THUMBNAIL_DATA_LIMIT = 100 * 1024; -const String SENTRY_DSN = +const int kThumbnailSmallSize = 256; +const int kThumbnailQuality = 50; +const int kThumbnailLargeSize = 512; +const int kCompressedThumbnailResolution = 1080; +const int kThumbnailDataLimit = 100 * 1024; +const String kSentryDSN = "https://93b8ea6f54f442dc8408ebccdff6fe7a@errors.ente.io/2"; -const String SENTRY_DEBUG_DSN = +const String kSentryDebugDSN = "https://b31c8af8384a4ce980509b8f592a67eb@errors.ente.io/3"; -const String ROADMAP_URL = "https://roadmap.ente.io"; -const int MICRO_SECONDS_IN_DAY = 86400000000; -const int ANDROID_11_SDK_INT = 30; \ No newline at end of file +const String kRoadmapURL = "https://roadmap.ente.io"; +const int kMicroSecondsInDay = 86400000000; +const int kAndroid11SDKINT = 30; diff --git a/lib/main.dart b/lib/main.dart index 225148909..08e2c3807 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,9 +5,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:in_app_purchase/in_app_purchase.dart'; +import 'package:logging/logging.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:photos/core/constants.dart'; import 'package:photos/core/configuration.dart'; +import 'package:photos/core/constants.dart'; import 'package:photos/core/network.dart'; import 'package:photos/db/upload_locks_db.dart'; import 'package:photos/services/billing_service.dart'; @@ -25,7 +26,6 @@ import 'package:photos/utils/crypto_util.dart'; import 'package:photos/utils/file_uploader.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:super_logging/super_logging.dart'; -import 'package:logging/logging.dart'; final _logger = Logger("main"); @@ -166,7 +166,7 @@ Future _runWithLogs(Function() function, {String prefix = ""}) async { body: function, logDirPath: (await getTemporaryDirectory()).path + "/logs", maxLogFiles: 5, - sentryDsn: kDebugMode ? SENTRY_DEBUG_DSN : SENTRY_DSN, + sentryDsn: kDebugMode ? kSentryDebugDSN : kSentryDSN, enableInDebugMode: true, prefix: prefix, )); diff --git a/lib/services/memories_service.dart b/lib/services/memories_service.dart index 5aea9e85e..0758849c1 100644 --- a/lib/services/memories_service.dart +++ b/lib/services/memories_service.dart @@ -27,7 +27,7 @@ class MemoriesService extends ChangeNotifier { _cachedMemories = null; }); await _memoriesDB.clearMemoriesSeenBeforeTime( - DateTime.now().microsecondsSinceEpoch - (7 * MICRO_SECONDS_IN_DAY)); + DateTime.now().microsecondsSinceEpoch - (7 * kMicroSecondsInDay)); } void clearCache() { diff --git a/lib/services/sync_service.dart b/lib/services/sync_service.dart index e36183363..98c1794db 100644 --- a/lib/services/sync_service.dart +++ b/lib/services/sync_service.dart @@ -231,7 +231,7 @@ class SyncService { final lastNotificationShownTime = _prefs.getInt(kLastStorageLimitExceededNotificationPushTime) ?? 0; final now = DateTime.now().microsecondsSinceEpoch; - if ((now - lastNotificationShownTime) > MICRO_SECONDS_IN_DAY) { + if ((now - lastNotificationShownTime) > kMicroSecondsInDay) { await _prefs.setInt(kLastStorageLimitExceededNotificationPushTime, now); NotificationService.instance.showNotification( "storage limit exceeded", "sorry, we had to pause your backups"); diff --git a/lib/services/update_service.dart b/lib/services/update_service.dart index da8907f5d..ebef330d0 100644 --- a/lib/services/update_service.dart +++ b/lib/services/update_service.dart @@ -51,7 +51,7 @@ class UpdateService { _prefs.getInt(kUpdateAvailableShownTimeKey) ?? 0; final now = DateTime.now().microsecondsSinceEpoch; final hasBeen3DaysSinceLastNotification = - (now - lastNotificationShownTime) > (3 * MICRO_SECONDS_IN_DAY); + (now - lastNotificationShownTime) > (3 * kMicroSecondsInDay); if (shouldUpdate && hasBeen3DaysSinceLastNotification && _latestVersion.shouldNotify) { diff --git a/lib/ui/huge_listview/lazy_loading_gallery.dart b/lib/ui/huge_listview/lazy_loading_gallery.dart index 0e45dcd76..217ff5506 100644 --- a/lib/ui/huge_listview/lazy_loading_gallery.dart +++ b/lib/ui/huge_listview/lazy_loading_gallery.dart @@ -99,7 +99,7 @@ class _LazyLoadingGalleryState extends State { DateTime(galleryDate.year, galleryDate.month, galleryDate.day); final result = await widget.asyncLoader( dayStartTime.microsecondsSinceEpoch, - dayStartTime.microsecondsSinceEpoch + MICRO_SECONDS_IN_DAY - 1); + dayStartTime.microsecondsSinceEpoch + kMicroSecondsInDay - 1); if (result.files.isEmpty) { // All files on this day were deleted, let gallery trigger the reload } else { diff --git a/lib/ui/settings/support_section_widget.dart b/lib/ui/settings/support_section_widget.dart index 358cb864b..f9cbb13f8 100644 --- a/lib/ui/settings/support_section_widget.dart +++ b/lib/ui/settings/support_section_widget.dart @@ -72,7 +72,7 @@ class SupportSectionWidget extends StatelessWidget { final isLoggedIn = Configuration.instance.getToken() != null; final url = isLoggedIn ? endpoint + "?token=" + Configuration.instance.getToken() - : ROADMAP_URL; + : kRoadmapURL; return WebPage("roadmap", url); }, ), diff --git a/lib/ui/thumbnail_widget.dart b/lib/ui/thumbnail_widget.dart index 07a524535..5ce446497 100644 --- a/lib/ui/thumbnail_widget.dart +++ b/lib/ui/thumbnail_widget.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:logging/logging.dart'; import 'package:photos/core/cache/thumbnail_cache.dart'; +import 'package:photos/core/constants.dart'; import 'package:photos/core/errors.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/models/file.dart'; -import 'package:logging/logging.dart'; -import 'package:photos/core/constants.dart'; import 'package:photos/models/file_type.dart'; import 'package:photos/ui/common_elements.dart'; import 'package:photos/utils/thumbnail_util.dart'; @@ -152,7 +152,7 @@ class _ThumbnailWidgetState extends State { !_isLoadingThumbnail) { _isLoadingThumbnail = true; final cachedSmallThumbnail = - ThumbnailLruCache.get(widget.file, THUMBNAIL_SMALL_SIZE); + ThumbnailLruCache.get(widget.file, kThumbnailSmallSize); if (cachedSmallThumbnail != null) { _imageProvider = Image.memory(cachedSmallThumbnail).image; _hasLoadedThumbnail = true; @@ -185,16 +185,16 @@ class _ThumbnailWidgetState extends State { } asset .thumbDataWithSize( - THUMBNAIL_SMALL_SIZE, - THUMBNAIL_SMALL_SIZE, - quality: THUMBNAIL_QUALITY, + kThumbnailSmallSize, + kThumbnailSmallSize, + quality: kThumbnailQuality, ) .then((data) { if (data != null && mounted) { final imageProvider = Image.memory(data).image; _cacheAndRender(imageProvider); } - ThumbnailLruCache.put(widget.file, data, THUMBNAIL_SMALL_SIZE); + ThumbnailLruCache.put(widget.file, data, kThumbnailSmallSize); }); }).catchError((e) { _logger.warning("Could not load image: ", e); diff --git a/lib/ui/zoomable_image.dart b/lib/ui/zoomable_image.dart index 9be8c643c..66ea2cc09 100644 --- a/lib/ui/zoomable_image.dart +++ b/lib/ui/zoomable_image.dart @@ -2,15 +2,15 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:logging/logging.dart'; +import 'package:photo_view/photo_view.dart'; import 'package:photos/core/cache/image_cache.dart'; import 'package:photos/core/cache/thumbnail_cache.dart'; +import 'package:photos/core/constants.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/models/file.dart'; import 'package:photos/ui/loading_widget.dart'; -import 'package:photo_view/photo_view.dart'; -import 'package:photos/core/constants.dart'; import 'package:photos/utils/file_util.dart'; import 'package:photos/utils/thumbnail_util.dart'; @@ -119,7 +119,7 @@ class _ZoomableImageState extends State !_loadedLargeThumbnail && !_loadedFinalImage) { final cachedThumbnail = - ThumbnailLruCache.get(_photo, THUMBNAIL_SMALL_SIZE); + ThumbnailLruCache.get(_photo, kThumbnailSmallSize); if (cachedThumbnail != null) { _imageProvider = Image.memory(cachedThumbnail).image; _loadedSmallThumbnail = true; @@ -131,7 +131,7 @@ class _ZoomableImageState extends State !_loadedFinalImage) { _loadingLargeThumbnail = true; final cachedThumbnail = - ThumbnailLruCache.get(_photo, THUMBNAIL_LARGE_SIZE); + ThumbnailLruCache.get(_photo, kThumbnailLargeSize); if (cachedThumbnail != null) { _onLargeThumbnailLoaded(Image.memory(cachedThumbnail).image, context); } else { @@ -141,14 +141,14 @@ class _ZoomableImageState extends State return; } asset - .thumbDataWithSize(THUMBNAIL_LARGE_SIZE, THUMBNAIL_LARGE_SIZE) + .thumbDataWithSize(kThumbnailLargeSize, kThumbnailLargeSize) .then((data) { if (data == null) { // Deleted file return; } _onLargeThumbnailLoaded(Image.memory(data).image, context); - ThumbnailLruCache.put(_photo, data, THUMBNAIL_LARGE_SIZE); + ThumbnailLruCache.put(_photo, data, kThumbnailLargeSize); }); }); } diff --git a/lib/utils/delete_file_util.dart b/lib/utils/delete_file_util.dart index fcbfada3a..abfeb5dc9 100644 --- a/lib/utils/delete_file_util.dart +++ b/lib/utils/delete_file_util.dart @@ -147,7 +147,7 @@ Future deleteLocalFiles( final List deletedIDs = []; if (Platform.isAndroid) { final androidInfo = await DeviceInfoPlugin().androidInfo; - if (androidInfo.version.sdkInt < ANDROID_11_SDK_INT) { + if (androidInfo.version.sdkInt < kAndroid11SDKINT) { deletedIDs.addAll(await _deleteLocalFilesInBatches(context, localIDs)); } else { deletedIDs.addAll(await _deleteLocalFilesInOneShot(context, localIDs)); diff --git a/lib/utils/file_uploader_util.dart b/lib/utils/file_uploader_util.dart index 3940eeb81..0794179df 100644 --- a/lib/utils/file_uploader_util.dart +++ b/lib/utils/file_uploader_util.dart @@ -1,14 +1,13 @@ import 'dart:async'; import 'dart:io' as io; - import 'dart:typed_data'; import 'package:logging/logging.dart'; import 'package:photo_manager/photo_manager.dart'; import 'package:photos/core/constants.dart'; import 'package:photos/core/errors.dart'; -import 'package:photos/models/location.dart'; import 'package:photos/models/file.dart' as ente; +import 'package:photos/models/location.dart'; import 'file_util.dart'; @@ -60,12 +59,12 @@ Future _getMediaUploadDataFromAssetFile(ente.File file) async { throw InvalidFileError(); } thumbnailData = await asset.thumbDataWithSize( - THUMBNAIL_SMALL_SIZE, - THUMBNAIL_SMALL_SIZE, - quality: THUMBNAIL_QUALITY, + kThumbnailSmallSize, + kThumbnailSmallSize, + quality: kThumbnailQuality, ); int compressionAttempts = 0; - while (thumbnailData.length > THUMBNAIL_DATA_LIMIT && + while (thumbnailData.length > kThumbnailDataLimit && compressionAttempts < kMaximumThumbnailCompressionAttempts) { _logger.info("Thumbnail size " + thumbnailData.length.toString()); thumbnailData = await compressThumbnail(thumbnailData); diff --git a/lib/utils/file_util.dart b/lib/utils/file_util.dart index bb9e69de0..fa3a35124 100644 --- a/lib/utils/file_util.dart +++ b/lib/utils/file_util.dart @@ -2,12 +2,12 @@ import 'dart:async'; import 'dart:io' as io; import 'dart:typed_data'; -import 'package:flutter_sodium/flutter_sodium.dart'; -import 'package:logging/logging.dart'; -import 'package:path/path.dart'; import 'package:dio/dio.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_image_compress/flutter_image_compress.dart'; +import 'package:flutter_sodium/flutter_sodium.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart'; import 'package:photos/core/cache/image_cache.dart'; import 'package:photos/core/cache/thumbnail_cache.dart'; import 'package:photos/core/cache/video_cache_manager.dart'; @@ -48,19 +48,19 @@ void preloadThumbnail(ente.File file) { if (file.isRemoteFile()) { getThumbnailFromServer(file); } else { - if (ThumbnailLruCache.get(file, THUMBNAIL_SMALL_SIZE) != null) { + if (ThumbnailLruCache.get(file, kThumbnailSmallSize) != null) { return; } file.getAsset().then((asset) { if (asset != null) { asset .thumbDataWithSize( - THUMBNAIL_SMALL_SIZE, - THUMBNAIL_SMALL_SIZE, - quality: THUMBNAIL_QUALITY, + kThumbnailSmallSize, + kThumbnailSmallSize, + quality: kThumbnailQuality, ) .then((data) { - ThumbnailLruCache.put(file, data, THUMBNAIL_SMALL_SIZE); + ThumbnailLruCache.put(file, data, kThumbnailSmallSize); }); } }); @@ -136,11 +136,11 @@ Future _downloadAndDecrypt( var fileExtension = "unknown"; try { fileExtension = extension(file.title).substring(1).toLowerCase(); - } catch(e) { + } catch (e) { _logger.severe("Could not capture file extension"); } var outputFile = decryptedFile; - if ((fileExtension=="unknown" && file.fileType == FileType.image) || + if ((fileExtension == "unknown" && file.fileType == FileType.image) || (io.Platform.isAndroid && fileExtension == "heic")) { outputFile = await FlutterImageCompress.compressAndGetFile( decryptedFilePath, @@ -175,8 +175,8 @@ Uint8List decryptFileKey(ente.File file) { Future compressThumbnail(Uint8List thumbnail) { return FlutterImageCompress.compressWithList( thumbnail, - minHeight: COMPRESSED_THUMBNAIL_RESOLUTION, - minWidth: COMPRESSED_THUMBNAIL_RESOLUTION, + minHeight: kCompressedThumbnailResolution, + minWidth: kCompressedThumbnailResolution, quality: 25, ); } diff --git a/lib/utils/thumbnail_util.dart b/lib/utils/thumbnail_util.dart index 32e69a2c9..6561e2b4e 100644 --- a/lib/utils/thumbnail_util.dart +++ b/lib/utils/thumbnail_util.dart @@ -1,6 +1,6 @@ import 'dart:async'; import 'dart:collection'; - +import 'dart:io' as io; import 'dart:typed_data'; import 'package:dio/dio.dart'; @@ -15,8 +15,6 @@ import 'package:photos/models/file.dart'; import 'package:photos/utils/crypto_util.dart'; import 'package:photos/utils/file_util.dart'; -import 'dart:io' as io; - final _logger = Logger("ThumbnailUtil"); final _map = LinkedHashMap(); final _queue = Queue(); @@ -110,7 +108,7 @@ Future _downloadAndDecryptThumbnail(FileDownloadItem item) async { Sodium.base642bin(file.thumbnailDecryptionHeader), ); final thumbnailSize = data.length; - if (thumbnailSize > THUMBNAIL_DATA_LIMIT) { + if (thumbnailSize > kThumbnailDataLimit) { data = await compressThumbnail(data); } ThumbnailLruCache.put(item.file, data); @@ -132,5 +130,6 @@ Future _downloadAndDecryptThumbnail(FileDownloadItem item) async { io.File getCachedThumbnail(File file) { final thumbnailCacheDirectory = Configuration.instance.getThumbnailCacheDirectory(); - return io.File(thumbnailCacheDirectory + "/" + file.uploadedFileID.toString()); -} \ No newline at end of file + return io.File( + thumbnailCacheDirectory + "/" + file.uploadedFileID.toString()); +} From 6606ecdc91a25346a0d4f831f94921181c326f9a Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 22 Jul 2021 02:23:51 +0530 Subject: [PATCH 08/14] =?UTF-8?q?Load=20images=20from=20the=2018th=20centu?= =?UTF-8?q?ry=20too=20=F0=9F=A4=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/constants.dart | 1 + lib/ui/detail_page.dart | 3 ++- lib/ui/gallery.dart | 6 ++++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/core/constants.dart b/lib/core/constants.dart index d1c90f81c..de805ba2d 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -10,3 +10,4 @@ const String kSentryDebugDSN = const String kRoadmapURL = "https://roadmap.ente.io"; const int kMicroSecondsInDay = 86400000000; const int kAndroid11SDKINT = 30; +const int kGalleryLoadStartTime = -8000000000000000; // Wednesday, March 6, 1748 diff --git a/lib/ui/detail_page.dart b/lib/ui/detail_page.dart index b6c01004e..84f0eb9cf 100644 --- a/lib/ui/detail_page.dart +++ b/lib/ui/detail_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:logging/logging.dart'; +import 'package:photos/core/constants.dart'; import 'package:photos/models/file.dart'; import 'package:photos/models/file_type.dart'; import 'package:photos/ui/fading_app_bar.dart'; @@ -208,7 +209,7 @@ class _DetailPageState extends State { } if (_selectedIndex == _files.length - 1 && !_hasLoadedTillEnd) { final result = await widget.config.asyncLoader( - 0, _files[_selectedIndex].creationTime - 1, + kGalleryLoadStartTime, _files[_selectedIndex].creationTime - 1, limit: kLoadLimit); setState(() { if (!result.hasMore) { diff --git a/lib/ui/gallery.dart b/lib/ui/gallery.dart index eb3b8d270..e0d6534ed 100644 --- a/lib/ui/gallery.dart +++ b/lib/ui/gallery.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; +import 'package:photos/core/constants.dart'; import 'package:photos/core/event_bus.dart'; import 'package:photos/events/event.dart'; import 'package:photos/events/files_updated_event.dart'; @@ -100,8 +101,9 @@ class _GalleryState extends State { Future _loadFiles({int limit}) async { _logger.info("Loading files"); final startTime = DateTime.now().microsecondsSinceEpoch; - final result = await widget - .asyncLoader(0, DateTime.now().microsecondsSinceEpoch, limit: limit); + final result = await widget.asyncLoader( + kGalleryLoadStartTime, DateTime.now().microsecondsSinceEpoch, + limit: limit); final endTime = DateTime.now().microsecondsSinceEpoch; final duration = Duration(microseconds: endTime - startTime); _logger.info("Time taken to load " + From 197e807dc347f46dbc55a05b5f20ac3df2dbe811 Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 22 Jul 2021 02:28:07 +0530 Subject: [PATCH 09/14] Fix lint warnings --- lib/services/remote_sync_service.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/services/remote_sync_service.dart b/lib/services/remote_sync_service.dart index 6b5359781..cc7f118a9 100644 --- a/lib/services/remote_sync_service.dart +++ b/lib/services/remote_sync_service.dart @@ -79,7 +79,7 @@ class RemoteSyncService { Future _uploadDiff() async { final foldersToBackUp = Configuration.instance.getPathsToBackUp(); - var filesToBeUploaded; + List filesToBeUploaded; if (LocalSyncService.instance.hasGrantedLimitedPermissions() && foldersToBackUp.isEmpty) { filesToBeUploaded = await _db.getAllLocalFiles(); @@ -149,7 +149,7 @@ class RemoteSyncService { } on UserCancelledUploadError { // Do nothing } catch (e) { - throw e; + rethrow; } return _completedUploads > 0; } @@ -223,7 +223,7 @@ class RemoteSyncService { } } await _db.insertMultiple(toBeInserted); - if (toBeInserted.length > 0) { + if (toBeInserted.isNotEmpty) { await _collectionsService.setCollectionSyncTime( collectionID, toBeInserted[toBeInserted.length - 1].updationTime); } From 199e3a58cc196ed0f89cd55313c7a0ee0bd8f629 Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 22 Jul 2021 11:49:34 +0530 Subject: [PATCH 10/14] Fix lint warnings --- lib/ui/blurred_file_backdrop.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ui/blurred_file_backdrop.dart b/lib/ui/blurred_file_backdrop.dart index e407de29e..e664028bf 100644 --- a/lib/ui/blurred_file_backdrop.dart +++ b/lib/ui/blurred_file_backdrop.dart @@ -22,9 +22,9 @@ class BlurredFileBackdrop extends StatelessWidget { key: Key("memory_backdrop" + file.tag()), ), BackdropFilter( - filter: new ImageFilter.blur(sigmaX: 64.0, sigmaY: 64.0), - child: new Container( - decoration: new BoxDecoration(color: Colors.white.withOpacity(0.0)), + filter: ImageFilter.blur(sigmaX: 64.0, sigmaY: 64.0), + child: Container( + decoration: BoxDecoration(color: Colors.white.withOpacity(0.0)), ), ), ]), From e7dd26c69e589f141cffde5aac193e1c9df223a5 Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 22 Jul 2021 12:21:59 +0530 Subject: [PATCH 11/14] Fix lint warnings --- lib/utils/crypto_util.dart | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/utils/crypto_util.dart b/lib/utils/crypto_util.dart index 5ffd9a09e..bba711fbb 100644 --- a/lib/utils/crypto_util.dart +++ b/lib/utils/crypto_util.dart @@ -1,6 +1,6 @@ +import 'dart:io' as io; import 'dart:typed_data'; -import 'dart:io' as io; import 'package:computer/computer.dart'; import 'package:flutter_sodium/flutter_sodium.dart'; import 'package:logging/logging.dart'; @@ -109,15 +109,15 @@ void chachaDecryptFile(Map args) { } Uint8List chachaDecryptData(Map args) { - final pullState = - Sodium.cryptoSecretstreamXchacha20poly1305InitPull(args["header"], args["key"]); - final pullResult = - Sodium.cryptoSecretstreamXchacha20poly1305Pull(pullState, args["source"], null); + final pullState = Sodium.cryptoSecretstreamXchacha20poly1305InitPull( + args["header"], args["key"]); + final pullResult = Sodium.cryptoSecretstreamXchacha20poly1305Pull( + pullState, args["source"], null); return pullResult.m; } class CryptoUtil { - static Computer _computer = Computer(); + static final Computer _computer = Computer(); static init() { _computer.turnOn(workersCount: 4); @@ -127,7 +127,7 @@ class CryptoUtil { static EncryptionResult encryptSync(Uint8List source, Uint8List key) { final nonce = Sodium.randombytesBuf(Sodium.cryptoSecretboxNoncebytes); - final args = Map(); + final args = {}; args["source"] = source; args["nonce"] = nonce; args["key"] = key; @@ -141,7 +141,7 @@ class CryptoUtil { Uint8List key, Uint8List nonce, ) async { - final args = Map(); + final args = {}; args["cipher"] = cipher; args["nonce"] = nonce; args["key"] = key; @@ -153,7 +153,7 @@ class CryptoUtil { Uint8List key, Uint8List nonce, ) { - final args = Map(); + final args = {}; args["cipher"] = cipher; args["nonce"] = nonce; args["key"] = key; @@ -162,7 +162,7 @@ class CryptoUtil { static Future encryptChaCha( Uint8List source, Uint8List key) async { - final args = Map(); + final args = {}; args["source"] = source; args["key"] = key; return _computer.compute(chachaEncryptData, param: args); @@ -170,7 +170,7 @@ class CryptoUtil { static Future decryptChaCha( Uint8List source, Uint8List key, Uint8List header) async { - final args = Map(); + final args = {}; args["source"] = source; args["key"] = key; args["header"] = header; @@ -182,7 +182,7 @@ class CryptoUtil { String destinationFilePath, { Uint8List key, }) { - final args = Map(); + final args = {}; args["sourceFilePath"] = sourceFilePath; args["destinationFilePath"] = destinationFilePath; args["key"] = key; @@ -195,7 +195,7 @@ class CryptoUtil { Uint8List header, Uint8List key, ) { - final args = Map(); + final args = {}; args["sourceFilePath"] = sourceFilePath; args["destinationFilePath"] = destinationFilePath; args["header"] = header; From 19202c37fae9e0e982db51271cc8c6061f07e7e6 Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 22 Jul 2021 12:36:45 +0530 Subject: [PATCH 12/14] Migrate secure storage to wait for first unlock --- lib/core/configuration.dart | 63 ++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/lib/core/configuration.dart b/lib/core/configuration.dart index 8cb456950..3f25a10ea 100644 --- a/lib/core/configuration.dart +++ b/lib/core/configuration.dart @@ -45,6 +45,8 @@ class Configuration { static const tokenKey = "token"; static const encryptedTokenKey = "encrypted_token"; static const userIDKey = "user_id"; + static const hasMigratedSecureStorageToFirstUnlockKey = + "has_migrated_secure_storage_to_first_unlock"; final kTempFolderDeletionTimeBuffer = Duration(days: 1).inMicroseconds; @@ -60,6 +62,9 @@ class Configuration { String _thumbnailCacheDirectory; String _volatilePassword; + final _secureStorageOptionsIOS = + IOSOptions(accessibility: IOSAccessibility.first_unlock); + Future init() async { _preferences = await SharedPreferences.getInstance(); _secureStorage = FlutterSecureStorage(); @@ -85,10 +90,17 @@ class Configuration { (await getTemporaryDirectory()).path + "/thumbnail-cache"; io.Directory(_thumbnailCacheDirectory).createSync(recursive: true); if (!_preferences.containsKey(tokenKey)) { - await _secureStorage.deleteAll(); + await _secureStorage.deleteAll(iOptions: _secureStorageOptionsIOS); } else { - _key = await _secureStorage.read(key: keyKey); - _secretKey = await _secureStorage.read(key: secretKeyKey); + _key = await _secureStorage.read( + key: keyKey, + iOptions: _secureStorageOptionsIOS, + ); + _secretKey = await _secureStorage.read( + key: secretKeyKey, + iOptions: _secureStorageOptionsIOS, + ); + await _migrateSecurityStorageToFirstUnlock(); } } @@ -102,7 +114,7 @@ class Configuration { } } await _preferences.clear(); - await _secureStorage.deleteAll(); + await _secureStorage.deleteAll(iOptions: _secureStorageOptionsIOS); _key = null; _cachedToken = null; _secretKey = null; @@ -354,18 +366,32 @@ class Configuration { Future setKey(String key) async { _key = key; if (key == null) { - await _secureStorage.delete(key: keyKey); + await _secureStorage.delete( + key: keyKey, + iOptions: _secureStorageOptionsIOS, + ); } else { - await _secureStorage.write(key: keyKey, value: key); + await _secureStorage.write( + key: keyKey, + value: key, + iOptions: _secureStorageOptionsIOS, + ); } } Future setSecretKey(String secretKey) async { _secretKey = secretKey; if (secretKey == null) { - await _secureStorage.delete(key: secretKeyKey); + await _secureStorage.delete( + key: secretKeyKey, + iOptions: _secureStorageOptionsIOS, + ); } else { - await _secureStorage.write(key: secretKeyKey, value: secretKey); + await _secureStorage.write( + key: secretKeyKey, + value: secretKey, + iOptions: _secureStorageOptionsIOS, + ); } } @@ -473,4 +499,25 @@ class Configuration { bool hasSkippedBackupFolderSelection() { return _preferences.getBool(keyHasSkippedBackupFolderSelection) ?? false; } + + Future _migrateSecurityStorageToFirstUnlock() async { + final hasMigratedSecureStorageToFirstUnlock = + _preferences.getBool(hasMigratedSecureStorageToFirstUnlockKey) ?? false; + if (!hasMigratedSecureStorageToFirstUnlock && + _key != null && + _secretKey != null) { + await _secureStorage.write( + key: keyKey, + value: _key, + iOptions: _secureStorageOptionsIOS, + ); + await _secureStorage.write( + key: secretKeyKey, + value: _secretKey, + iOptions: _secureStorageOptionsIOS, + ); + await _preferences.setBool( + hasMigratedSecureStorageToFirstUnlockKey, true); + } + } } From b404029029e3065f7ccba5fe4dfabcb0031dbf27 Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Thu, 22 Jul 2021 12:37:43 +0530 Subject: [PATCH 13/14] Prevent secure storage value migrations --- lib/core/configuration.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/configuration.dart b/lib/core/configuration.dart index 3f25a10ea..417ea0508 100644 --- a/lib/core/configuration.dart +++ b/lib/core/configuration.dart @@ -63,7 +63,7 @@ class Configuration { String _volatilePassword; final _secureStorageOptionsIOS = - IOSOptions(accessibility: IOSAccessibility.first_unlock); + IOSOptions(accessibility: IOSAccessibility.first_unlock_this_device); Future init() async { _preferences = await SharedPreferences.getInstance(); From a0b3010348c8a3613e9ff5944df9e1fd1b1935c7 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta Date: Thu, 22 Jul 2021 12:55:30 +0530 Subject: [PATCH 14/14] Fix crash in imageEdit for remote files --- lib/models/file.dart | 5 +++++ lib/ui/image_editor_page.dart | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/models/file.dart b/lib/models/file.dart index 73b7b2096..4b74d5e81 100644 --- a/lib/models/file.dart +++ b/lib/models/file.dart @@ -133,6 +133,11 @@ class File { return localID == null && uploadedFileID != null; } + bool hasLocation() { + return location != null && + (location.longitude != 0 || location.latitude != 0); + } + @override String toString() { return '''File(generatedId: $generatedID, uploadedFileId: $uploadedFileID, diff --git a/lib/ui/image_editor_page.dart b/lib/ui/image_editor_page.dart index 3296548ea..4cb312e98 100644 --- a/lib/ui/image_editor_page.dart +++ b/lib/ui/image_editor_page.dart @@ -319,8 +319,7 @@ class _ImageEditorPageState extends State { newFile.creationTime = widget.originalFile.creationTime; newFile.collectionID = widget.originalFile.collectionID; newFile.location = widget.originalFile.location; - if (newFile.location == null || - (newFile.location.latitude == 0 && newFile.location.longitude == 0)) { + if (!newFile.hasLocation() && widget.originalFile.localID != null) { final latLong = await (await widget.originalFile.getAsset()).latlngAsync(); newFile.location = Location(latLong.latitude, latLong.longitude);