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/configuration.dart b/lib/core/configuration.dart index d658fa81b..c87e153d9 100644 --- a/lib/core/configuration.dart +++ b/lib/core/configuration.dart @@ -46,6 +46,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; @@ -61,12 +63,15 @@ class Configuration { String _thumbnailCacheDirectory; String _volatilePassword; + final _secureStorageOptionsIOS = + IOSOptions(accessibility: IOSAccessibility.first_unlock_this_device); + Future init() async { _preferences = await SharedPreferences.getInstance(); _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() && @@ -86,10 +91,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(); } } @@ -103,7 +115,7 @@ class Configuration { } } await _preferences.clear(); - await _secureStorage.deleteAll(); + await _secureStorage.deleteAll(iOptions: _secureStorageOptionsIOS); _key = null; _cachedToken = null; _secretKey = null; @@ -197,7 +209,7 @@ class Configuration { attributes.memLimit, attributes.opsLimit, ); - var key; + Uint8List key; try { key = CryptoUtil.decryptSync(Sodium.base642bin(attributes.encryptedKey), kek, Sodium.base642bin(attributes.keyDecryptionNonce)); @@ -241,7 +253,7 @@ class Configuration { Future recover(String recoveryKey) async { final keyAttributes = getKeyAttributes(); - var masterKey; + Uint8List masterKey; try { masterKey = await CryptoUtil.decrypt( Sodium.base642bin(keyAttributes.masterKeyEncryptedWithRecoveryKey), @@ -249,7 +261,7 @@ class Configuration { Sodium.base642bin(keyAttributes.masterKeyDecryptionNonce)); } catch (e) { _logger.severe(e); - throw e; + rethrow; } await setKey(Sodium.bin2base64(masterKey)); } @@ -262,9 +274,7 @@ class Configuration { } String getToken() { - if (_cachedToken == null) { - _cachedToken = _preferences.getString(tokenKey); - } + _cachedToken ??= _preferences.getString(tokenKey); return _cachedToken; } @@ -309,7 +319,7 @@ class Configuration { if (_preferences.containsKey(foldersToBackUpKey)) { return _preferences.getStringList(foldersToBackUpKey).toSet(); } else { - return Set(); + return {}; } } @@ -342,8 +352,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() { @@ -358,18 +367,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, + ); } } @@ -477,4 +500,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); + } + } } diff --git a/lib/core/constants.dart b/lib/core/constants.dart index 647db6e30..de805ba2d 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -1,12 +1,13 @@ -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; +const int kGalleryLoadStartTime = -8000000000000000; // Wednesday, March 6, 1748 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 51bbc1063..940cff7af 100644 --- a/lib/db/files_db.dart +++ b/lib/db/files_db.dart @@ -46,28 +46,34 @@ 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)]; + static final migrationScripts = [ + ...alterDeviceFolderToAllowNULL(), + ...alterTimestampColumnTypes(), + ...addIndices(), + ]; 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); } @@ -101,13 +107,19 @@ class FilesDB { ]; } - static List addIndex() { + static List addIndices() { 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); + CREATE INDEX IF NOT EXISTS collection_id_index ON $table($columnCollectionID); + ''', + ''' + CREATE INDEX IF NOT EXISTS device_folder_index ON $table($columnDeviceFolder); + ''', + ''' + CREATE INDEX IF NOT EXISTS creation_time_index ON $table($columnCreationTime); + ''', + ''' + CREATE INDEX IF NOT EXISTS updation_time_index ON $table($columnUpdationTime); ''' ]; } @@ -128,6 +140,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 +281,7 @@ class FilesDB { collectionID, ], ); - final ids = Set(); + final ids = {}; for (final result in results) { ids.add(result[columnUploadedFileID]); } @@ -223,8 +296,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 +312,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 +329,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 +352,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 +380,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 +398,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 +413,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 +423,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 +447,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 +469,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 +481,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 +493,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 +504,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 +539,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 +552,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 +721,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 +750,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 +766,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 +786,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 +814,7 @@ class FilesDB { } Map _getRowForFile(File file) { - final row = new Map(); + final row = {}; if (file.generatedID != null) { row[columnGeneratedID] = file.generatedID; } @@ -795,7 +850,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 +894,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]; 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..2846651f2 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,14 +18,14 @@ 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 { + Future _initDatabase() async { Directory documentsDirectory = await getApplicationDocumentsDirectory(); String path = join(documentsDirectory.path, _databaseName); return await openDatabase( 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( 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/models/file.dart b/lib/models/file.dart index b21e20ac0..87aa02b03 100644 --- a/lib/models/file.dart +++ b/lib/models/file.dart @@ -134,10 +134,16 @@ class File { return localID == null && uploadedFileID != null; } + bool isCachedInAppSandbox() { return localID != null && localID.startsWith("ente-upload-cache"); } + bool hasLocation() { + return location != null && + (location.longitude != 0 || location.latitude != 0); + } + @override String toString() { return '''File(generatedId: $generatedID, uploadedFileId: $uploadedFileID, 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; } } } 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/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); } 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/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)), ), ), ]), 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 " + 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/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); 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 577f4ec55..28e292352 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,11 +185,12 @@ class _ThumbnailWidgetState extends State { } return; } + if (thumbData != null && mounted) { final imageProvider = Image.memory(thumbData).image; _cacheAndRender(imageProvider); } - ThumbnailLruCache.put(widget.file, thumbData, THUMBNAIL_SMALL_SIZE); + ThumbnailLruCache.put(widget.file, thumbData, kThumbnailSmallSize); }).catchError((e) { _logger.warning("Could not load image: ", e); _encounteredErrorLoadingThumbnail = true; 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/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; 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 7caa61a46..c341111e9 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'; @@ -63,12 +62,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); @@ -115,7 +114,7 @@ Future getThumbnailFromInAppCacheFile(ente.File file) async { var localPath = file.localID.replaceAll(RegExp(r'ente-upload-cache:'), ''); var thumbnailData = io.File(localPath).readAsBytesSync(); 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 4bac7a189..dd45ae7c8 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'; @@ -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 c3c49a111..88048a72d 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'; @@ -16,7 +16,6 @@ import 'package:photos/utils/crypto_util.dart'; import 'package:photos/utils/file_util.dart'; import 'dart:io' as io; - import 'file_uploader_util.dart'; final _logger = Logger("ThumbnailUtil"); @@ -60,7 +59,7 @@ Future getThumbnailFromServer(File file) async { } Future getThumbnailFromLocal(File file) async { - if (ThumbnailLruCache.get(file, THUMBNAIL_SMALL_SIZE) != null) { + if (ThumbnailLruCache.get(file, kThumbnailSmallSize) != null) { return ThumbnailLruCache.get(file); } final cachedThumbnail = getCachedThumbnail(file); @@ -73,7 +72,7 @@ Future getThumbnailFromLocal(File file) async { return getThumbnailFromInAppCacheFile(file) .then((data) { if (data != null) { - ThumbnailLruCache.put(file, data, THUMBNAIL_SMALL_SIZE); + ThumbnailLruCache.put(file, data, kThumbnailSmallSize); } return data; }); @@ -83,10 +82,10 @@ Future getThumbnailFromLocal(File file) async { return null; } return asset - .thumbDataWithSize(THUMBNAIL_SMALL_SIZE, THUMBNAIL_SMALL_SIZE, - quality: THUMBNAIL_QUALITY) + .thumbDataWithSize(kThumbnailSmallSize, kThumbnailSmallSize, + quality: kThumbnailQuality) .then((data) { - ThumbnailLruCache.put(file, data, THUMBNAIL_SMALL_SIZE); + ThumbnailLruCache.put(file, data, kThumbnailSmallSize); return data; }); }); @@ -146,7 +145,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);