diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 8e04b259b..bbc9cefe0 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -16,7 +16,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
- DA6BE5E826B3BC8600656280 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
+ DA6BE5E826B3BC8600656280 /* (null) in Resources */ = {isa = PBXBuildFile; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -213,7 +213,7 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
- DA6BE5E826B3BC8600656280 /* BuildFile in Resources */,
+ DA6BE5E826B3BC8600656280 /* (null) in Resources */,
277218A0270F596900FFE3CC /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -497,10 +497,7 @@
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- );
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
@@ -633,6 +630,7 @@
STRIP_STYLE = "non-global";
STRIP_SWIFT_SYMBOLS = NO;
SUPPORTED_PLATFORMS = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
@@ -656,10 +654,7 @@
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- );
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
@@ -693,10 +688,7 @@
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- );
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 92cb0a5a0..11fd2fa2e 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -60,6 +60,8 @@
NSAllowsArbitraryLoadsInWebContent
+ ITSAppUsesNonExemptEncryption
+
NSFaceIDUsageDescription
Please allow ente to lock itself with FaceID or TouchID
NSPhotoLibraryUsageDescription
diff --git a/lib/core/cache/image_cache.dart b/lib/core/cache/image_cache.dart
index 98386efd3..2370cf9a2 100644
--- a/lib/core/cache/image_cache.dart
+++ b/lib/core/cache/image_cache.dart
@@ -1,5 +1,3 @@
-// @dart=2.9
-
import 'dart:io' as io;
import 'package:photos/core/cache/lru_map.dart';
@@ -7,11 +5,11 @@ import 'package:photos/core/cache/lru_map.dart';
class FileLruCache {
static final LRUMap _map = LRUMap(25);
- static io.File get(String key) {
+ static io.File? get(String key) {
return _map.get(key);
}
- static void put(String key, io.File imageData) {
- _map.put(key, imageData);
+ static void put(String key, io.File value) {
+ _map.put(key, value);
}
}
diff --git a/lib/core/cache/lru_map.dart b/lib/core/cache/lru_map.dart
index 69d790077..9e28c84c0 100644
--- a/lib/core/cache/lru_map.dart
+++ b/lib/core/cache/lru_map.dart
@@ -1,5 +1,3 @@
-// @dart=2.9
-
import 'dart:collection';
typedef EvictionHandler = Function(K key, V value);
@@ -7,12 +5,12 @@ typedef EvictionHandler = Function(K key, V value);
class LRUMap {
final LinkedHashMap _map = LinkedHashMap();
final int _maxSize;
- final EvictionHandler _handler;
+ final EvictionHandler? _handler;
LRUMap(this._maxSize, [this._handler]);
- V get(K key) {
- final V value = _map.remove(key);
+ V? get(K key) {
+ final V? value = _map.remove(key);
if (value != null) {
_map[key] = value;
}
@@ -24,9 +22,9 @@ class LRUMap {
_map[key] = value;
if (_map.length > _maxSize) {
final K evictedKey = _map.keys.first;
- final V evictedValue = _map.remove(evictedKey);
+ final V? evictedValue = _map.remove(evictedKey);
if (_handler != null) {
- _handler(evictedKey, evictedValue);
+ _handler!(evictedKey, evictedValue);
}
}
}
diff --git a/lib/core/cache/thumbnail_cache.dart b/lib/core/cache/thumbnail_cache.dart
index 4af10f215..08a05fda9 100644
--- a/lib/core/cache/thumbnail_cache.dart
+++ b/lib/core/cache/thumbnail_cache.dart
@@ -1,5 +1,3 @@
-// @dart=2.9
-
import 'dart:typed_data';
import 'package:photos/core/cache/lru_map.dart';
@@ -7,35 +5,35 @@ import 'package:photos/core/constants.dart';
import 'package:photos/models/ente_file.dart';
class ThumbnailLruCache {
- static final LRUMap _map = LRUMap(1000);
+ static final LRUMap _map = LRUMap(1000);
- static Uint8List get(EnteFile enteFile, [int size]) {
+ static Uint8List? get(EnteFile enteFile, [int? size]) {
return _map.get(
enteFile.cacheKey() +
"_" +
- (size != null ? size.toString() : kThumbnailLargeSize.toString()),
+ (size != null ? size.toString() : thumbnailLargeSize.toString()),
);
}
static void put(
EnteFile enteFile,
- Uint8List imageData, [
- int size,
+ Uint8List? imageData, [
+ int? size,
]) {
_map.put(
enteFile.cacheKey() +
"_" +
- (size != null ? size.toString() : kThumbnailLargeSize.toString()),
+ (size != null ? size.toString() : thumbnailLargeSize.toString()),
imageData,
);
}
static void clearCache(EnteFile enteFile) {
_map.remove(
- enteFile.cacheKey() + "_" + kThumbnailLargeSize.toString(),
+ enteFile.cacheKey() + "_" + thumbnailLargeSize.toString(),
);
_map.remove(
- enteFile.cacheKey() + "_" + kThumbnailSmallSize.toString(),
+ enteFile.cacheKey() + "_" + thumbnailSmallSize.toString(),
);
}
}
diff --git a/lib/core/cache/video_cache_manager.dart b/lib/core/cache/video_cache_manager.dart
index 601682eda..ada01c080 100644
--- a/lib/core/cache/video_cache_manager.dart
+++ b/lib/core/cache/video_cache_manager.dart
@@ -1,5 +1,3 @@
-
-
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
class VideoCacheManager {
diff --git a/lib/core/configuration.dart b/lib/core/configuration.dart
index b604029fb..f4afbcac1 100644
--- a/lib/core/configuration.dart
+++ b/lib/core/configuration.dart
@@ -1,5 +1,3 @@
-// @dart=2.9
-
import 'dart:convert';
import 'dart:io' as io;
import 'dart:typed_data';
@@ -10,14 +8,19 @@ import 'package:flutter_sodium/flutter_sodium.dart';
import 'package:logging/logging.dart';
import 'package:path_provider/path_provider.dart';
import 'package:photos/core/constants.dart';
+// ignore: import_of_legacy_library_into_null_safe
import 'package:photos/core/error-reporting/super_logging.dart';
import 'package:photos/core/errors.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/db/collections_db.dart';
+// ignore: import_of_legacy_library_into_null_safe
import 'package:photos/db/files_db.dart';
+// ignore: import_of_legacy_library_into_null_safe
import 'package:photos/db/ignored_files_db.dart';
+// ignore: import_of_legacy_library_into_null_safe
import 'package:photos/db/memories_db.dart';
import 'package:photos/db/public_keys_db.dart';
+// ignore: import_of_legacy_library_into_null_safe
import 'package:photos/db/trash_db.dart';
import 'package:photos/db/upload_locks_db.dart';
import 'package:photos/events/signed_in_event.dart';
@@ -25,11 +28,17 @@ import 'package:photos/events/user_logged_out_event.dart';
import 'package:photos/models/key_attributes.dart';
import 'package:photos/models/key_gen_result.dart';
import 'package:photos/models/private_key_attributes.dart';
+// ignore: import_of_legacy_library_into_null_safe
import 'package:photos/services/billing_service.dart';
+// ignore: import_of_legacy_library_into_null_safe
import 'package:photos/services/collections_service.dart';
+// ignore: import_of_legacy_library_into_null_safe
import 'package:photos/services/favorites_service.dart';
+// ignore: import_of_legacy_library_into_null_safe
import 'package:photos/services/memories_service.dart';
+// ignore: import_of_legacy_library_into_null_safe
import 'package:photos/services/search_service.dart';
+// ignore: import_of_legacy_library_into_null_safe
import 'package:photos/services/sync_service.dart';
import 'package:photos/utils/crypto_util.dart';
import 'package:photos/utils/validator_util.dart';
@@ -57,8 +66,8 @@ class Configuration {
static const keyShouldKeepDeviceAwake = "should_keep_device_awake";
static const keyShouldHideFromRecents = "should_hide_from_recents";
static const keyShouldShowLockScreen = "should_show_lock_screen";
- static const keyHasSkippedBackupFolderSelection =
- "has_skipped_backup_folder_selection";
+ static const keyHasSelectedAnyBackupFolder =
+ "has_selected_any_folder_for_backup";
static const lastTempFolderClearTimeKey = "last_temp_folder_clear_time";
static const nameKey = "name";
static const secretKeyKey = "secret_key";
@@ -75,21 +84,21 @@ class Configuration {
static final _logger = Logger("Configuration");
- String _cachedToken;
- String _documentsDirectory;
- String _key;
- SharedPreferences _preferences;
- String _secretKey;
- FlutterSecureStorage _secureStorage;
- String _tempDirectory;
- String _thumbnailCacheDirectory;
+ String? _cachedToken;
+ late String _documentsDirectory;
+ String? _key;
+ late SharedPreferences _preferences;
+ String? _secretKey;
+ late FlutterSecureStorage _secureStorage;
+ late String _tempDirectory;
+ late String _thumbnailCacheDirectory;
// 6th July 22: Remove this after 3 months. Hopefully, active users
// will migrate to newer version of the app, where shared media is stored
// on appSupport directory which OS won't clean up automatically
- String _sharedTempMediaDirectory;
+ late String _sharedTempMediaDirectory;
- String _sharedDocumentsMediaDirectory;
- String _volatilePassword;
+ late String _sharedDocumentsMediaDirectory;
+ String? _volatilePassword;
final _secureStorageOptionsIOS =
const IOSOptions(accessibility: IOSAccessibility.first_unlock);
@@ -133,12 +142,15 @@ class Configuration {
key: secretKeyKey,
iOptions: _secureStorageOptionsIOS,
);
+ if (_key == null) {
+ await logout(autoLogout: true);
+ }
await _migrateSecurityStorageToFirstUnlock();
}
SuperLogging.setUserID(await _getOrCreateAnonymousUserID());
}
- Future logout() async {
+ Future logout({bool autoLogout = false}) async {
if (SyncService.instance.isSyncInProgress()) {
SyncService.instance.stopSync();
try {
@@ -161,12 +173,24 @@ class Configuration {
await UploadLocksDB.instance.clearTable();
await IgnoredFilesDB.instance.clearTable();
await TrashDB.instance.clearTable();
- CollectionsService.instance.clearCache();
- FavoritesService.instance.clearCache();
- MemoriesService.instance.clearCache();
- BillingService.instance.clearCache();
- SearchService.instance.clearCache();
- Bus.instance.fire(UserLoggedOutEvent());
+ if (!autoLogout) {
+ CollectionsService.instance.clearCache();
+ FavoritesService.instance.clearCache();
+ MemoriesService.instance.clearCache();
+ BillingService.instance.clearCache();
+ SearchService.instance.clearCache();
+ Bus.instance.fire(UserLoggedOutEvent());
+ } else {
+ _preferences.setBool("auto_logout", true);
+ }
+ }
+
+ bool showAutoLogoutDialog() {
+ return _preferences.containsKey("auto_logout");
+ }
+
+ Future clearAutoLogoutFlag() {
+ return _preferences.remove("auto_logout");
}
Future generateKey(String password) async {
@@ -183,8 +207,10 @@ class Configuration {
// Derive a key from the password that will be used to encrypt and
// decrypt the master key
final kekSalt = CryptoUtil.getSaltToDeriveKey();
- final derivedKeyResult =
- await CryptoUtil.deriveSensitiveKey(utf8.encode(password), kekSalt);
+ final derivedKeyResult = await CryptoUtil.deriveSensitiveKey(
+ utf8.encode(password) as Uint8List,
+ kekSalt,
+ );
// Encrypt the key with this derived key
final encryptedKeyData =
@@ -197,17 +223,17 @@ class Configuration {
final attributes = KeyAttributes(
Sodium.bin2base64(kekSalt),
- Sodium.bin2base64(encryptedKeyData.encryptedData),
- Sodium.bin2base64(encryptedKeyData.nonce),
+ Sodium.bin2base64(encryptedKeyData.encryptedData!),
+ Sodium.bin2base64(encryptedKeyData.nonce!),
Sodium.bin2base64(keyPair.pk),
- Sodium.bin2base64(encryptedSecretKeyData.encryptedData),
- Sodium.bin2base64(encryptedSecretKeyData.nonce),
+ Sodium.bin2base64(encryptedSecretKeyData.encryptedData!),
+ Sodium.bin2base64(encryptedSecretKeyData.nonce!),
derivedKeyResult.memLimit,
derivedKeyResult.opsLimit,
- Sodium.bin2base64(encryptedMasterKey.encryptedData),
- Sodium.bin2base64(encryptedMasterKey.nonce),
- Sodium.bin2base64(encryptedRecoveryKey.encryptedData),
- Sodium.bin2base64(encryptedRecoveryKey.nonce),
+ Sodium.bin2base64(encryptedMasterKey.encryptedData!),
+ Sodium.bin2base64(encryptedMasterKey.nonce!),
+ Sodium.bin2base64(encryptedRecoveryKey.encryptedData!),
+ Sodium.bin2base64(encryptedRecoveryKey.nonce!),
);
final privateAttributes = PrivateKeyAttributes(
Sodium.bin2base64(masterKey),
@@ -224,19 +250,21 @@ class Configuration {
// Derive a key from the password that will be used to encrypt and
// decrypt the master key
final kekSalt = CryptoUtil.getSaltToDeriveKey();
- final derivedKeyResult =
- await CryptoUtil.deriveSensitiveKey(utf8.encode(password), kekSalt);
+ final derivedKeyResult = await CryptoUtil.deriveSensitiveKey(
+ utf8.encode(password) as Uint8List,
+ kekSalt,
+ );
// Encrypt the key with this derived key
final encryptedKeyData =
- CryptoUtil.encryptSync(masterKey, derivedKeyResult.key);
+ CryptoUtil.encryptSync(masterKey!, derivedKeyResult.key);
final existingAttributes = getKeyAttributes();
- return existingAttributes.copyWith(
+ return existingAttributes!.copyWith(
kekSalt: Sodium.bin2base64(kekSalt),
- encryptedKey: Sodium.bin2base64(encryptedKeyData.encryptedData),
- keyDecryptionNonce: Sodium.bin2base64(encryptedKeyData.nonce),
+ encryptedKey: Sodium.bin2base64(encryptedKeyData.encryptedData!),
+ keyDecryptionNonce: Sodium.bin2base64(encryptedKeyData.nonce!),
memLimit: derivedKeyResult.memLimit,
opsLimit: derivedKeyResult.opsLimit,
);
@@ -254,7 +282,7 @@ class Configuration {
);
_logger.info('state validation done');
final kek = await CryptoUtil.deriveKey(
- utf8.encode(password),
+ utf8.encode(password) as Uint8List,
Sodium.base642bin(attributes.kekSalt),
attributes.memLimit,
attributes.opsLimit,
@@ -285,7 +313,7 @@ class Configuration {
_logger.info("secret-key done");
await setSecretKey(Sodium.bin2base64(secretKey));
final token = CryptoUtil.openSealSync(
- Sodium.base642bin(getEncryptedToken()),
+ Sodium.base642bin(getEncryptedToken()!),
Sodium.base642bin(attributes.publicKey),
secretKey,
);
@@ -296,7 +324,7 @@ class Configuration {
}
Future createNewRecoveryKey() async {
- final masterKey = getKey();
+ final masterKey = getKey()!;
final existingAttributes = getKeyAttributes();
// Create a recovery key
@@ -306,22 +334,23 @@ class Configuration {
final encryptedMasterKey = CryptoUtil.encryptSync(masterKey, recoveryKey);
final encryptedRecoveryKey = CryptoUtil.encryptSync(recoveryKey, masterKey);
- return existingAttributes.copyWith(
+ return existingAttributes!.copyWith(
masterKeyEncryptedWithRecoveryKey:
- Sodium.bin2base64(encryptedMasterKey.encryptedData),
- masterKeyDecryptionNonce: Sodium.bin2base64(encryptedMasterKey.nonce),
+ Sodium.bin2base64(encryptedMasterKey.encryptedData!),
+ masterKeyDecryptionNonce: Sodium.bin2base64(encryptedMasterKey.nonce!),
recoveryKeyEncryptedWithMasterKey:
- Sodium.bin2base64(encryptedRecoveryKey.encryptedData),
- recoveryKeyDecryptionNonce: Sodium.bin2base64(encryptedRecoveryKey.nonce),
+ Sodium.bin2base64(encryptedRecoveryKey.encryptedData!),
+ recoveryKeyDecryptionNonce:
+ Sodium.bin2base64(encryptedRecoveryKey.nonce!),
);
}
Future recover(String recoveryKey) async {
// check if user has entered mnemonic code
if (recoveryKey.contains(' ')) {
- if (recoveryKey.split(' ').length != kMnemonicKeyWordCount) {
+ if (recoveryKey.split(' ').length != mnemonicKeyWordCount) {
throw AssertionError(
- 'recovery code should have $kMnemonicKeyWordCount words',
+ 'recovery code should have $mnemonicKeyWordCount words',
);
}
recoveryKey = bip39.mnemonicToEntropy(recoveryKey);
@@ -330,7 +359,7 @@ class Configuration {
Uint8List masterKey;
try {
masterKey = await CryptoUtil.decrypt(
- Sodium.base642bin(attributes.masterKeyEncryptedWithRecoveryKey),
+ Sodium.base642bin(attributes!.masterKeyEncryptedWithRecoveryKey),
Sodium.hex2bin(recoveryKey),
Sodium.base642bin(attributes.masterKeyDecryptionNonce),
);
@@ -346,7 +375,7 @@ class Configuration {
);
await setSecretKey(Sodium.bin2base64(secretKey));
final token = CryptoUtil.openSealSync(
- Sodium.base642bin(getEncryptedToken()),
+ Sodium.base642bin(getEncryptedToken()!),
Sodium.base642bin(attributes.publicKey),
secretKey,
);
@@ -359,7 +388,7 @@ class Configuration {
return endpoint;
}
- String getToken() {
+ String? getToken() {
_cachedToken ??= _preferences.getString(tokenKey);
return _cachedToken;
}
@@ -374,11 +403,11 @@ class Configuration {
await _preferences.setString(encryptedTokenKey, encryptedToken);
}
- String getEncryptedToken() {
+ String? getEncryptedToken() {
return _preferences.getString(encryptedTokenKey);
}
- String getEmail() {
+ String? getEmail() {
return _preferences.getString(emailKey);
}
@@ -386,7 +415,7 @@ class Configuration {
await _preferences.setString(emailKey, email);
}
- String getName() {
+ String? getName() {
return _preferences.getString(nameKey);
}
@@ -394,7 +423,7 @@ class Configuration {
await _preferences.setString(nameKey, name);
}
- int getUserID() {
+ int? getUserID() {
return _preferences.getInt(userIDKey);
}
@@ -404,33 +433,17 @@ class Configuration {
Set getPathsToBackUp() {
if (_preferences.containsKey(foldersToBackUpKey)) {
- return _preferences.getStringList(foldersToBackUpKey).toSet();
+ return _preferences.getStringList(foldersToBackUpKey)!.toSet();
} else {
return {};
}
}
- Future setPathsToBackUp(Set newPaths) async {
- await _preferences.setStringList(foldersToBackUpKey, newPaths.toList());
- final allFolders = (await FilesDB.instance.getLatestLocalFiles())
- .map((file) => file.deviceFolder)
- .toList();
- await _setSelectAllFoldersForBackup(newPaths.length == allFolders.length);
- SyncService.instance.onFoldersSet(newPaths);
- SyncService.instance.sync();
- }
-
- Future addPathToFoldersToBeBackedUp(String path) async {
- final currentPaths = getPathsToBackUp();
- currentPaths.add(path);
- return setPathsToBackUp(currentPaths);
- }
-
Future setKeyAttributes(KeyAttributes attributes) async {
- await _preferences.setString(keyAttributesKey, attributes?.toJson());
+ await _preferences.setString(keyAttributesKey, attributes.toJson());
}
- KeyAttributes getKeyAttributes() {
+ KeyAttributes? getKeyAttributes() {
final jsonValue = _preferences.getString(keyAttributesKey);
if (jsonValue == null) {
return null;
@@ -439,7 +452,7 @@ class Configuration {
}
}
- Future setKey(String key) async {
+ Future setKey(String? key) async {
_key = key;
if (key == null) {
await _secureStorage.delete(
@@ -455,7 +468,7 @@ class Configuration {
}
}
- Future setSecretKey(String secretKey) async {
+ Future setSecretKey(String? secretKey) async {
_secretKey = secretKey;
if (secretKey == null) {
await _secureStorage.delete(
@@ -471,16 +484,16 @@ class Configuration {
}
}
- Uint8List getKey() {
- return _key == null ? null : Sodium.base642bin(_key);
+ Uint8List? getKey() {
+ return _key == null ? null : Sodium.base642bin(_key!);
}
- Uint8List getSecretKey() {
- return _secretKey == null ? null : Sodium.base642bin(_secretKey);
+ Uint8List? getSecretKey() {
+ return _secretKey == null ? null : Sodium.base642bin(_secretKey!);
}
Uint8List getRecoveryKey() {
- final keyAttributes = getKeyAttributes();
+ final keyAttributes = getKeyAttributes()!;
return CryptoUtil.decryptSync(
Sodium.base642bin(keyAttributes.recoveryKeyEncryptedWithMasterKey),
getKey(),
@@ -488,10 +501,6 @@ class Configuration {
);
}
- String getDocumentsDirectory() {
- return _documentsDirectory;
- }
-
// Caution: This directory is cleared on app start
String getTempDirectory() {
return _tempDirectory;
@@ -515,7 +524,7 @@ class Configuration {
bool shouldBackupOverMobileData() {
if (_preferences.containsKey(keyShouldBackupOverMobileData)) {
- return _preferences.getBool(keyShouldBackupOverMobileData);
+ return _preferences.getBool(keyShouldBackupOverMobileData)!;
} else {
return false;
}
@@ -530,14 +539,15 @@ class Configuration {
bool shouldBackupVideos() {
if (_preferences.containsKey(keyShouldBackupVideos)) {
- return _preferences.getBool(keyShouldBackupVideos);
+ return _preferences.getBool(keyShouldBackupVideos)!;
} else {
return true;
}
}
bool shouldKeepDeviceAwake() {
- return _preferences.get(keyShouldKeepDeviceAwake) ?? false;
+ final keepAwake = _preferences.get(keyShouldKeepDeviceAwake);
+ return keepAwake == null ? false : keepAwake as bool;
}
Future setShouldKeepDeviceAwake(bool value) async {
@@ -556,7 +566,7 @@ class Configuration {
bool shouldShowLockScreen() {
if (_preferences.containsKey(keyShouldShowLockScreen)) {
- return _preferences.getBool(keyShouldShowLockScreen);
+ return _preferences.getBool(keyShouldShowLockScreen)!;
} else {
return false;
}
@@ -567,11 +577,7 @@ class Configuration {
}
bool shouldHideFromRecents() {
- if (_preferences.containsKey(keyShouldHideFromRecents)) {
- return _preferences.getBool(keyShouldHideFromRecents);
- } else {
- return false;
- }
+ return _preferences.getBool(keyShouldHideFromRecents) ?? false;
}
Future setShouldHideFromRecents(bool value) {
@@ -582,23 +588,23 @@ class Configuration {
_volatilePassword = volatilePassword;
}
- String getVolatilePassword() {
+ String? getVolatilePassword() {
return _volatilePassword;
}
- Future skipBackupFolderSelection() async {
- await _preferences.setBool(keyHasSkippedBackupFolderSelection, true);
+ Future setHasSelectedAnyBackupFolder(bool val) async {
+ await _preferences.setBool(keyHasSelectedAnyBackupFolder, val);
}
- bool hasSkippedBackupFolderSelection() {
- return _preferences.getBool(keyHasSkippedBackupFolderSelection) ?? false;
+ bool hasSelectedAnyBackupFolder() {
+ return _preferences.getBool(keyHasSelectedAnyBackupFolder) ?? false;
}
bool hasSelectedAllFoldersForBackup() {
return _preferences.getBool(hasSelectedAllFoldersForBackupKey) ?? false;
}
- Future _setSelectAllFoldersForBackup(bool value) async {
+ Future setSelectAllFoldersForBackup(bool value) async {
await _preferences.setBool(hasSelectedAllFoldersForBackupKey, value);
}
@@ -630,6 +636,6 @@ class Configuration {
//ignore: prefer_const_constructors
await _preferences.setString(anonymousUserIDKey, Uuid().v4());
}
- return _preferences.getString(anonymousUserIDKey);
+ return _preferences.getString(anonymousUserIDKey)!;
}
}
diff --git a/lib/core/constants.dart b/lib/core/constants.dart
index e028840a9..a51250130 100644
--- a/lib/core/constants.dart
+++ b/lib/core/constants.dart
@@ -1,48 +1,43 @@
-// @dart = 2.7
-
-const int kThumbnailSmallSize = 256;
-const int kThumbnailQuality = 50;
-const int kThumbnailLargeSize = 512;
-const int kCompressedThumbnailResolution = 1080;
-const int kThumbnailDataLimit = 100 * 1024;
-const String kSentryDSN =
+const int thumbnailSmallSize = 256;
+const int thumbnailQuality = 50;
+const int thumbnailLargeSize = 512;
+const int compressedThumbnailResolution = 1080;
+const int thumbnailDataLimit = 100 * 1024;
+const String sentryDSN =
"https://2235e5c99219488ea93da34b9ac1cb68@sentry.ente.io/4";
-const String kSentryDebugDSN =
+const String sentryDebugDSN =
"https://ca5e686dd7f149d9bf94e620564cceba@sentry.ente.io/3";
-const String kSentryTunnel = "https://sentry-reporter.ente.io";
-const String kRoadmapURL = "https://roadmap.ente.io";
-const int kMicroSecondsInDay = 86400000000;
-const int kAndroid11SDKINT = 30;
-const int kGalleryLoadStartTime = -8000000000000000; // Wednesday, March 6, 1748
-const int kGalleryLoadEndTime = 9223372036854775807; // 2^63 -1
+const String sentryTunnel = "https://sentry-reporter.ente.io";
+const String roadmapURL = "https://roadmap.ente.io";
+const int microSecondsInDay = 86400000000;
+const int android11SDKINT = 30;
+const int galleryLoadStartTime = -8000000000000000; // Wednesday, March 6, 1748
+const int galleryLoadEndTime = 9223372036854775807; // 2^63 -1
// used to identify which ente file are available in app cache
// todo: 6Jun22: delete old media identifier after 3 months
-const String kOldSharedMediaIdentifier = 'ente-shared://';
-const String kSharedMediaIdentifier = 'ente-shared-media://';
+const String oldSharedMediaIdentifier = 'ente-shared://';
+const String sharedMediaIdentifier = 'ente-shared-media://';
-const int kMaxLivePhotoToastCount = 2;
-const String kLivePhotoToastCounterKey = "show_live_photo_toast";
+const int maxLivePhotoToastCount = 2;
+const String livePhotoToastCounterKey = "show_live_photo_toast";
-const kThumbnailDiskLoadDeferDuration = Duration(milliseconds: 40);
-const kThumbnailServerLoadDeferDuration = Duration(milliseconds: 80);
+const thumbnailDiskLoadDeferDuration = Duration(milliseconds: 40);
+const thumbnailServerLoadDeferDuration = Duration(milliseconds: 80);
// 256 bit key maps to 24 words
// https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki#Generating_the_mnemonic
-const kMnemonicKeyWordCount = 24;
+const mnemonicKeyWordCount = 24;
// https://stackoverflow.com/a/61162219
-const kDragSensitivity = 8;
+const dragSensitivity = 8;
-const kSupportEmail = 'support@ente.io';
+const supportEmail = 'support@ente.io';
// Default values for various feature flags
class FFDefault {
static const bool enableStripe = true;
- static const bool disableUrlSharing = false;
static const bool disableCFWorker = false;
- static const bool enableMissingLocationMigration = false;
- static const bool enableSearch = false;
}
const kDefaultProductionEndpoint = 'https://api.ente.io';
diff --git a/lib/core/error-reporting/super_logging.dart b/lib/core/error-reporting/super_logging.dart
index cee59567f..10125cf73 100644
--- a/lib/core/error-reporting/super_logging.dart
+++ b/lib/core/error-reporting/super_logging.dart
@@ -209,7 +209,7 @@ class SuperLogging {
}
static void setUserID(String userID) async {
- if (config.sentryDsn != null) {
+ if (config?.sentryDsn != null) {
Sentry.configureScope((scope) => scope.user = SentryUser(id: userID));
$.info("setting sentry user ID to: $userID");
}
diff --git a/lib/core/errors.dart b/lib/core/errors.dart
index 3f3630382..f4f1bbde2 100644
--- a/lib/core/errors.dart
+++ b/lib/core/errors.dart
@@ -1,5 +1,3 @@
-// @dart=2.9
-
class InvalidFileError extends ArgumentError {
InvalidFileError(String message) : super(message);
}
diff --git a/lib/core/network.dart b/lib/core/network.dart
index aef529db3..bc2d82a1a 100644
--- a/lib/core/network.dart
+++ b/lib/core/network.dart
@@ -1,5 +1,3 @@
-// @dart=2.9
-
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:fk_user_agent/fk_user_agent.dart';
@@ -9,7 +7,7 @@ import 'package:uuid/uuid.dart';
int kConnectTimeout = 15000;
class Network {
- Dio _dio;
+ late Dio _dio;
Future init() async {
await FkUserAgent.init();
diff --git a/lib/data/holidays.dart b/lib/data/holidays.dart
index 831da3f1c..c8ed8f8b0 100644
--- a/lib/data/holidays.dart
+++ b/lib/data/holidays.dart
@@ -1,22 +1,26 @@
-// @dart=2.9
+class HolidayData {
+ final String name;
+ final int month;
+ final int day;
-import 'package:photos/models/search/holiday_search_result.dart';
+ const HolidayData(this.name, {required this.month, required this.day});
+}
const List allHolidays = [
- HolidayData('New Year', 1, 1),
- HolidayData('Epiphany', 1, 6),
- HolidayData('Pongal', 1, 14),
- HolidayData('Makar Sankranthi', 1, 14),
- HolidayData('Valentine\'s Day', 2, 14),
- HolidayData('Nowruz', 3, 21),
- HolidayData('Walpurgis Night', 4, 30),
- HolidayData('Vappu', 4, 30),
- HolidayData('May Day', 5, 1),
- HolidayData('Midsummer\'s Eve', 6, 24),
- HolidayData('Midsummer Day', 6, 25),
- HolidayData('Christmas Eve', 12, 24),
- HolidayData('Halloween', 10, 31),
- HolidayData('Christmas', 12, 25),
- HolidayData('Boxing Day', 12, 26),
- HolidayData('New Year\'s Eve', 12, 31),
+ HolidayData('New Year', month: 1, day: 1),
+ HolidayData('Epiphany', month: 1, day: 6),
+ HolidayData('Pongal', month: 1, day: 14),
+ HolidayData('Makar Sankranthi', month: 1, day: 14),
+ HolidayData('Valentine\'s Day', month: 2, day: 14),
+ HolidayData('Nowruz', month: 3, day: 21),
+ HolidayData('Walpurgis Night', month: 4, day: 30),
+ HolidayData('Vappu', month: 4, day: 30),
+ HolidayData('May Day', month: 5, day: 1),
+ HolidayData('Midsummer\'s Eve', month: 6, day: 24),
+ HolidayData('Midsummer Day', month: 6, day: 25),
+ HolidayData('Christmas Eve', month: 12, day: 24),
+ HolidayData('Halloween', month: 10, day: 31),
+ HolidayData('Christmas', month: 12, day: 25),
+ HolidayData('Boxing Day', month: 12, day: 26),
+ HolidayData('New Year\'s Eve', month: 12, day: 31),
];
diff --git a/lib/data/months.dart b/lib/data/months.dart
index d1eab1e96..530a869c1 100644
--- a/lib/data/months.dart
+++ b/lib/data/months.dart
@@ -1,7 +1,3 @@
-// @dart=2.9
-
-import 'package:photos/models/search/month_search_result.dart';
-
List allMonths = [
MonthData('January', 1),
MonthData('February', 2),
@@ -16,3 +12,10 @@ List allMonths = [
MonthData('November', 11),
MonthData('December', 12),
];
+
+class MonthData {
+ final String name;
+ final int monthNumber;
+
+ MonthData(this.name, this.monthNumber);
+}
diff --git a/lib/data/years.dart b/lib/data/years.dart
index b7acc3fb5..2b2e04d91 100644
--- a/lib/data/years.dart
+++ b/lib/data/years.dart
@@ -1,5 +1,3 @@
-// @dart=2.9
-
import 'package:photos/utils/date_time_util.dart';
class YearsData {
diff --git a/lib/db/collections_db.dart b/lib/db/collections_db.dart
index 275a6f3fd..9fc9c2000 100644
--- a/lib/db/collections_db.dart
+++ b/lib/db/collections_db.dart
@@ -1,5 +1,3 @@
-// @dart=2.9
-
import 'dart:convert';
import 'dart:io';
@@ -54,15 +52,16 @@ class CollectionsDB {
static final CollectionsDB instance = CollectionsDB._privateConstructor();
- static Future _dbFuture;
+ static Future? _dbFuture;
Future get database async {
_dbFuture ??= _initDatabase();
- return _dbFuture;
+ return _dbFuture!;
}
Future _initDatabase() async {
- final Directory documentsDirectory = await getApplicationDocumentsDirectory();
+ final Directory documentsDirectory =
+ await getApplicationDocumentsDirectory();
final String path = join(documentsDirectory.path, _databaseName);
return await openDatabaseWithMigration(path, dbConfig);
}
@@ -180,20 +179,6 @@ class CollectionsDB {
return collections;
}
- Future getLastCollectionUpdationTime() async {
- final db = await instance.database;
- final rows = await db.query(
- table,
- orderBy: '$columnUpdationTime DESC',
- limit: 1,
- );
- if (rows.isNotEmpty) {
- return int.parse(rows[0][columnUpdationTime]);
- } else {
- return null;
- }
- }
-
Future deleteCollection(int collectionID) async {
final db = await instance.database;
return db.delete(
@@ -206,7 +191,7 @@ class CollectionsDB {
Map _getRowForCollection(Collection collection) {
final row = {};
row[columnID] = collection.id;
- row[columnOwner] = collection.owner.toJson();
+ row[columnOwner] = collection.owner!.toJson();
row[columnEncryptedKey] = collection.encryptedKey;
row[columnKeyDecryptionNonce] = collection.keyDecryptionNonce;
row[columnName] = collection.name;
@@ -217,16 +202,16 @@ class CollectionsDB {
row[columnPathDecryptionNonce] = collection.attributes.pathDecryptionNonce;
row[columnVersion] = collection.attributes.version;
row[columnSharees] =
- json.encode(collection.sharees?.map((x) => x?.toMap())?.toList());
+ json.encode(collection.sharees?.map((x) => x?.toMap()).toList());
row[columnPublicURLs] =
- json.encode(collection.publicURLs?.map((x) => x?.toMap())?.toList());
+ json.encode(collection.publicURLs?.map((x) => x?.toMap()).toList());
row[columnUpdationTime] = collection.updationTime;
- if (collection.isDeleted ?? false) {
+ if (collection.isDeleted) {
row[columnIsDeleted] = _sqlBoolTrue;
} else {
row[columnIsDeleted] = _sqlBoolFalse;
}
- row[columnMMdVersion] = collection.mMdVersion ?? 0;
+ row[columnMMdVersion] = collection.mMdVersion;
row[columnMMdEncodedJson] = collection.mMdEncodedJson ?? '{}';
return row;
}
diff --git a/lib/db/device_files_db.dart b/lib/db/device_files_db.dart
new file mode 100644
index 000000000..d23343db7
--- /dev/null
+++ b/lib/db/device_files_db.dart
@@ -0,0 +1,376 @@
+// @dart = 2.9
+import 'package:flutter/foundation.dart';
+import 'package:logging/logging.dart';
+import 'package:photo_manager/photo_manager.dart';
+import 'package:photos/db/files_db.dart';
+import 'package:photos/models/device_collection.dart';
+import 'package:photos/models/file.dart';
+import 'package:photos/models/file_load_result.dart';
+import 'package:photos/models/upload_strategy.dart';
+import 'package:photos/services/local/local_sync_util.dart';
+import 'package:sqflite/sqlite_api.dart';
+import 'package:tuple/tuple.dart';
+
+extension DeviceFiles on FilesDB {
+ static final Logger _logger = Logger("DeviceFilesDB");
+ static const _sqlBoolTrue = 1;
+ static const _sqlBoolFalse = 0;
+
+ Future insertPathIDToLocalIDMapping(
+ Map> mappingToAdd, {
+ ConflictAlgorithm conflictAlgorithm = ConflictAlgorithm.ignore,
+ }) async {
+ debugPrint("Inserting missing PathIDToLocalIDMapping");
+ final db = await database;
+ var batch = db.batch();
+ int batchCounter = 0;
+ for (MapEntry e in mappingToAdd.entries) {
+ final String pathID = e.key;
+ for (String localID in e.value) {
+ if (batchCounter == 400) {
+ await batch.commit(noResult: true);
+ batch = db.batch();
+ batchCounter = 0;
+ }
+ batch.insert(
+ "device_files",
+ {
+ "id": localID,
+ "path_id": pathID,
+ },
+ conflictAlgorithm: conflictAlgorithm,
+ );
+ batchCounter++;
+ }
+ }
+ await batch.commit(noResult: true);
+ }
+
+ Future deletePathIDToLocalIDMapping(
+ Map> mappingsToRemove,
+ ) async {
+ debugPrint("removing PathIDToLocalIDMapping");
+ final db = await database;
+ var batch = db.batch();
+ int batchCounter = 0;
+ for (MapEntry e in mappingsToRemove.entries) {
+ final String pathID = e.key;
+ for (String localID in e.value) {
+ if (batchCounter == 400) {
+ await batch.commit(noResult: true);
+ batch = db.batch();
+ batchCounter = 0;
+ }
+ batch.delete(
+ "device_files",
+ where: 'id = ? AND path_id = ?',
+ whereArgs: [localID, pathID],
+ );
+ batchCounter++;
+ }
+ }
+ await batch.commit(noResult: true);
+ }
+
+ Future