瀏覽代碼

Merge branch 'main' into fix_null_safety_suggestion

Neeraj Gupta 2 年之前
父節點
當前提交
aec3e379a8

+ 1 - 1
lib/core/cache/thumbnail_cache.dart → lib/core/cache/thumbnail_in_memory_cache.dart

@@ -4,7 +4,7 @@ import 'package:photos/core/cache/lru_map.dart';
 import 'package:photos/core/constants.dart';
 import 'package:photos/core/constants.dart';
 import 'package:photos/models/ente_file.dart';
 import 'package:photos/models/ente_file.dart';
 
 
-class ThumbnailLruCache {
+class ThumbnailInMemoryLruCache {
   static final LRUMap<String, Uint8List?> _map = LRUMap(1000);
   static final LRUMap<String, Uint8List?> _map = LRUMap(1000);
 
 
   static Uint8List? get(EnteFile enteFile, [int? size]) {
   static Uint8List? get(EnteFile enteFile, [int? size]) {

+ 8 - 8
lib/core/configuration.dart

@@ -13,7 +13,6 @@ import 'package:photos/core/errors.dart';
 import 'package:photos/core/event_bus.dart';
 import 'package:photos/core/event_bus.dart';
 import 'package:photos/db/collections_db.dart';
 import 'package:photos/db/collections_db.dart';
 import 'package:photos/db/files_db.dart';
 import 'package:photos/db/files_db.dart';
-import 'package:photos/db/ignored_files_db.dart';
 import 'package:photos/db/memories_db.dart';
 import 'package:photos/db/memories_db.dart';
 import 'package:photos/db/public_keys_db.dart';
 import 'package:photos/db/public_keys_db.dart';
 import 'package:photos/db/trash_db.dart';
 import 'package:photos/db/trash_db.dart';
@@ -26,6 +25,7 @@ import 'package:photos/models/private_key_attributes.dart';
 import 'package:photos/services/billing_service.dart';
 import 'package:photos/services/billing_service.dart';
 import 'package:photos/services/collections_service.dart';
 import 'package:photos/services/collections_service.dart';
 import 'package:photos/services/favorites_service.dart';
 import 'package:photos/services/favorites_service.dart';
+import 'package:photos/services/ignored_files_service.dart';
 import 'package:photos/services/memories_service.dart';
 import 'package:photos/services/memories_service.dart';
 import 'package:photos/services/search_service.dart';
 import 'package:photos/services/search_service.dart';
 import 'package:photos/services/sync_service.dart';
 import 'package:photos/services/sync_service.dart';
@@ -160,7 +160,7 @@ class Configuration {
     await MemoriesDB.instance.clearTable();
     await MemoriesDB.instance.clearTable();
     await PublicKeysDB.instance.clearTable();
     await PublicKeysDB.instance.clearTable();
     await UploadLocksDB.instance.clearTable();
     await UploadLocksDB.instance.clearTable();
-    await IgnoredFilesDB.instance.clearTable();
+    await IgnoredFilesService.instance.reset();
     await TrashDB.instance.clearTable();
     await TrashDB.instance.clearTable();
     if (!autoLogout) {
     if (!autoLogout) {
       CollectionsService.instance.clearCache();
       CollectionsService.instance.clearCache();
@@ -273,8 +273,8 @@ class Configuration {
     final kek = await CryptoUtil.deriveKey(
     final kek = await CryptoUtil.deriveKey(
       utf8.encode(password) as Uint8List,
       utf8.encode(password) as Uint8List,
       Sodium.base642bin(attributes.kekSalt),
       Sodium.base642bin(attributes.kekSalt),
-      attributes.memLimit,
-      attributes.opsLimit,
+      attributes.memLimit!,
+      attributes.opsLimit!,
     ).onError((e, s) {
     ).onError((e, s) {
       _logger.severe('deriveKey failed', e, s);
       _logger.severe('deriveKey failed', e, s);
       throw KeyDerivationError();
       throw KeyDerivationError();
@@ -318,8 +318,8 @@ class Configuration {
     final kek = await CryptoUtil.deriveKey(
     final kek = await CryptoUtil.deriveKey(
       utf8.encode(password) as Uint8List,
       utf8.encode(password) as Uint8List,
       Sodium.base642bin(attributes.kekSalt),
       Sodium.base642bin(attributes.kekSalt),
-      attributes.memLimit,
-      attributes.opsLimit,
+      attributes.memLimit!,
+      attributes.opsLimit!,
     ).onError((e, s) {
     ).onError((e, s) {
       _logger.severe('deriveKey failed', e, s);
       _logger.severe('deriveKey failed', e, s);
       throw KeyDerivationError();
       throw KeyDerivationError();
@@ -374,9 +374,9 @@ class Configuration {
     Uint8List masterKey;
     Uint8List masterKey;
     try {
     try {
       masterKey = await CryptoUtil.decrypt(
       masterKey = await CryptoUtil.decrypt(
-        Sodium.base642bin(attributes!.masterKeyEncryptedWithRecoveryKey),
+        Sodium.base642bin(attributes!.masterKeyEncryptedWithRecoveryKey!),
         Sodium.hex2bin(recoveryKey),
         Sodium.hex2bin(recoveryKey),
-        Sodium.base642bin(attributes.masterKeyDecryptionNonce),
+        Sodium.base642bin(attributes.masterKeyDecryptionNonce!),
       );
       );
     } catch (e) {
     } catch (e) {
       _logger.severe(e);
       _logger.severe(e);

+ 14 - 4
lib/models/key_attributes.dart

@@ -7,10 +7,20 @@ class KeyAttributes {
   final String publicKey;
   final String publicKey;
   final String encryptedSecretKey;
   final String encryptedSecretKey;
   final String secretKeyDecryptionNonce;
   final String secretKeyDecryptionNonce;
-  final int memLimit;
-  final int opsLimit;
-  final String masterKeyEncryptedWithRecoveryKey;
-  final String masterKeyDecryptionNonce;
+
+  // Note: For users who signed in before we started storing memLimit and
+  // optsLimit, these fields will be null. To update these values, they need to
+  // either log in again or client needs to fetch these values from server.
+  // (internal monologue: Hopefully, the mem/ops limit used to generate the
+  // key is same as it's stored on the server)
+  // https://github.com/ente-io/photos-app/commit/8cb7f885b343f2c796e4cc9ce1f7d70c9a13a003#diff-02f19d9ee0a60ee9674372d2c780da5d5284128dc9ea65dec6cdcddfc559ebb3
+  final int? memLimit;
+  final int? opsLimit;
+  // The recovery key attributes can be null for old users who haven't generated
+  // their recovery keys yet.
+  // https://github.com/ente-io/photos-app/commit/d7acc95855c62ecdf2a29c4102e648105e17bd8c#diff-02f19d9ee0a60ee9674372d2c780da5d5284128dc9ea65dec6cdcddfc559ebb3
+  final String? masterKeyEncryptedWithRecoveryKey;
+  final String? masterKeyDecryptionNonce;
   final String? recoveryKeyEncryptedWithMasterKey;
   final String? recoveryKeyEncryptedWithMasterKey;
   final String? recoveryKeyDecryptionNonce;
   final String? recoveryKeyDecryptionNonce;
 
 

+ 4 - 4
lib/services/user_service.dart

@@ -397,8 +397,8 @@ class UserService {
         kekSalt: keyAttributes.kekSalt,
         kekSalt: keyAttributes.kekSalt,
         encryptedKey: keyAttributes.encryptedKey,
         encryptedKey: keyAttributes.encryptedKey,
         keyDecryptionNonce: keyAttributes.keyDecryptionNonce,
         keyDecryptionNonce: keyAttributes.keyDecryptionNonce,
-        memLimit: keyAttributes.memLimit,
-        opsLimit: keyAttributes.opsLimit,
+        memLimit: keyAttributes.memLimit!,
+        opsLimit: keyAttributes.opsLimit!,
       );
       );
       await _enteDio.put(
       await _enteDio.put(
         "/users/keys",
         "/users/keys",
@@ -414,8 +414,8 @@ class UserService {
   Future<void> setRecoveryKey(KeyAttributes keyAttributes) async {
   Future<void> setRecoveryKey(KeyAttributes keyAttributes) async {
     try {
     try {
       final setRecoveryKeyRequest = SetRecoveryKeyRequest(
       final setRecoveryKeyRequest = SetRecoveryKeyRequest(
-        keyAttributes.masterKeyEncryptedWithRecoveryKey,
-        keyAttributes.masterKeyDecryptionNonce,
+        keyAttributes.masterKeyEncryptedWithRecoveryKey!,
+        keyAttributes.masterKeyDecryptionNonce!,
         keyAttributes.recoveryKeyEncryptedWithMasterKey!,
         keyAttributes.recoveryKeyEncryptedWithMasterKey!,
         keyAttributes.recoveryKeyDecryptionNonce!,
         keyAttributes.recoveryKeyDecryptionNonce!,
       );
       );

+ 5 - 4
lib/ui/viewer/file/thumbnail_widget.dart

@@ -1,7 +1,7 @@
 import 'package:flutter/foundation.dart';
 import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 import 'package:logging/logging.dart';
 import 'package:logging/logging.dart';
-import 'package:photos/core/cache/thumbnail_cache.dart';
+import 'package:photos/core/cache/thumbnail_in_memory_cache.dart';
 import 'package:photos/core/configuration.dart';
 import 'package:photos/core/configuration.dart';
 import 'package:photos/core/constants.dart';
 import 'package:photos/core/constants.dart';
 import 'package:photos/core/errors.dart';
 import 'package:photos/core/errors.dart';
@@ -187,7 +187,7 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
         !_isLoadingLocalThumbnail) {
         !_isLoadingLocalThumbnail) {
       _isLoadingLocalThumbnail = true;
       _isLoadingLocalThumbnail = true;
       final cachedSmallThumbnail =
       final cachedSmallThumbnail =
-          ThumbnailLruCache.get(widget.file!, thumbnailSmallSize);
+          ThumbnailInMemoryLruCache.get(widget.file!, thumbnailSmallSize);
       if (cachedSmallThumbnail != null) {
       if (cachedSmallThumbnail != null) {
         _imageProvider = Image.memory(cachedSmallThumbnail).image;
         _imageProvider = Image.memory(cachedSmallThumbnail).image;
         _hasLoadedThumbnail = true;
         _hasLoadedThumbnail = true;
@@ -240,7 +240,8 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
         final imageProvider = Image.memory(thumbData).image;
         final imageProvider = Image.memory(thumbData).image;
         _cacheAndRender(imageProvider);
         _cacheAndRender(imageProvider);
       }
       }
-      ThumbnailLruCache.put(widget.file!, thumbData, thumbnailSmallSize);
+      ThumbnailInMemoryLruCache.put(
+          widget.file!, thumbData, thumbnailSmallSize);
     }).catchError((e) {
     }).catchError((e) {
       _logger.warning("Could not load image: ", e);
       _logger.warning("Could not load image: ", e);
       _errorLoadingLocalThumbnail = true;
       _errorLoadingLocalThumbnail = true;
@@ -252,7 +253,7 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
         !_errorLoadingRemoteThumbnail &&
         !_errorLoadingRemoteThumbnail &&
         !_isLoadingRemoteThumbnail) {
         !_isLoadingRemoteThumbnail) {
       _isLoadingRemoteThumbnail = true;
       _isLoadingRemoteThumbnail = true;
-      final cachedThumbnail = ThumbnailLruCache.get(widget.file!);
+      final cachedThumbnail = ThumbnailInMemoryLruCache.get(widget.file!);
       if (cachedThumbnail != null) {
       if (cachedThumbnail != null) {
         _imageProvider = Image.memory(cachedThumbnail).image;
         _imageProvider = Image.memory(cachedThumbnail).image;
         _hasLoadedThumbnail = true;
         _hasLoadedThumbnail = true;

+ 4 - 3
lib/ui/viewer/file/zoomable_image.dart

@@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:flutter/widgets.dart';
 import 'package:logging/logging.dart';
 import 'package:logging/logging.dart';
 import 'package:photo_view/photo_view.dart';
 import 'package:photo_view/photo_view.dart';
-import 'package:photos/core/cache/thumbnail_cache.dart';
+import 'package:photos/core/cache/thumbnail_in_memory_cache.dart';
 import 'package:photos/core/constants.dart';
 import 'package:photos/core/constants.dart';
 import 'package:photos/core/event_bus.dart';
 import 'package:photos/core/event_bus.dart';
 import 'package:photos/db/files_db.dart';
 import 'package:photos/db/files_db.dart';
@@ -102,7 +102,7 @@ class _ZoomableImageState extends State<ZoomableImage>
 
 
   void _loadNetworkImage() {
   void _loadNetworkImage() {
     if (!_loadedSmallThumbnail && !_loadedFinalImage) {
     if (!_loadedSmallThumbnail && !_loadedFinalImage) {
-      final cachedThumbnail = ThumbnailLruCache.get(_photo);
+      final cachedThumbnail = ThumbnailInMemoryLruCache.get(_photo!);
       if (cachedThumbnail != null) {
       if (cachedThumbnail != null) {
         _imageProvider = Image.memory(cachedThumbnail).image;
         _imageProvider = Image.memory(cachedThumbnail).image;
         _loadedSmallThumbnail = true;
         _loadedSmallThumbnail = true;
@@ -141,7 +141,8 @@ class _ZoomableImageState extends State<ZoomableImage>
     if (!_loadedSmallThumbnail &&
     if (!_loadedSmallThumbnail &&
         !_loadedLargeThumbnail &&
         !_loadedLargeThumbnail &&
         !_loadedFinalImage) {
         !_loadedFinalImage) {
-      final cachedThumbnail = ThumbnailLruCache.get(_photo, thumbnailSmallSize);
+      final cachedThumbnail =
+          ThumbnailInMemoryLruCache.get(_photo!, thumbnailSmallSize);
       if (cachedThumbnail != null) {
       if (cachedThumbnail != null) {
         _imageProvider = Image.memory(cachedThumbnail).image;
         _imageProvider = Image.memory(cachedThumbnail).image;
         _loadedSmallThumbnail = true;
         _loadedSmallThumbnail = true;

+ 2 - 2
lib/utils/file_util.dart

@@ -12,7 +12,7 @@ import 'package:logging/logging.dart';
 import 'package:motionphoto/motionphoto.dart';
 import 'package:motionphoto/motionphoto.dart';
 import 'package:path/path.dart';
 import 'package:path/path.dart';
 import 'package:photos/core/cache/image_cache.dart';
 import 'package:photos/core/cache/image_cache.dart';
-import 'package:photos/core/cache/thumbnail_cache.dart';
+import 'package:photos/core/cache/thumbnail_in_memory_cache.dart';
 import 'package:photos/core/cache/video_cache_manager.dart';
 import 'package:photos/core/cache/video_cache_manager.dart';
 import 'package:photos/core/configuration.dart';
 import 'package:photos/core/configuration.dart';
 import 'package:photos/core/constants.dart';
 import 'package:photos/core/constants.dart';
@@ -337,7 +337,7 @@ Future<void> clearCache(ente.File file) async {
   if (cachedThumbnail.existsSync()) {
   if (cachedThumbnail.existsSync()) {
     await cachedThumbnail.delete();
     await cachedThumbnail.delete();
   }
   }
-  ThumbnailLruCache.clearCache(file);
+  ThumbnailInMemoryLruCache.clearCache(file);
 }
 }
 
 
 class _LivePhoto {
 class _LivePhoto {

+ 29 - 27
lib/utils/thumbnail_util.dart

@@ -7,7 +7,7 @@ import 'package:dio/dio.dart';
 import 'package:flutter_sodium/flutter_sodium.dart';
 import 'package:flutter_sodium/flutter_sodium.dart';
 import 'package:logging/logging.dart';
 import 'package:logging/logging.dart';
 import 'package:photo_manager/photo_manager.dart';
 import 'package:photo_manager/photo_manager.dart';
-import 'package:photos/core/cache/thumbnail_cache.dart';
+import 'package:photos/core/cache/thumbnail_in_memory_cache.dart';
 import 'package:photos/core/configuration.dart';
 import 'package:photos/core/configuration.dart';
 import 'package:photos/core/constants.dart';
 import 'package:photos/core/constants.dart';
 import 'package:photos/core/errors.dart';
 import 'package:photos/core/errors.dart';
@@ -19,8 +19,8 @@ import 'package:photos/utils/file_uploader_util.dart';
 import 'package:photos/utils/file_util.dart';
 import 'package:photos/utils/file_util.dart';
 
 
 final _logger = Logger("ThumbnailUtil");
 final _logger = Logger("ThumbnailUtil");
-final _map = <int, FileDownloadItem>{};
-final _queue = Queue<int>();
+final _uploadIDToDownloadItem = <int, FileDownloadItem>{};
+final _downloadQueue = Queue<int>();
 const int kMaximumConcurrentDownloads = 500;
 const int kMaximumConcurrentDownloads = 500;
 
 
 class FileDownloadItem {
 class FileDownloadItem {
@@ -36,25 +36,27 @@ Future<Uint8List> getThumbnailFromServer(File file) async {
   final cachedThumbnail = cachedThumbnailPath(file);
   final cachedThumbnail = cachedThumbnailPath(file);
   if (await cachedThumbnail.exists()) {
   if (await cachedThumbnail.exists()) {
     final data = await cachedThumbnail.readAsBytes();
     final data = await cachedThumbnail.readAsBytes();
-    ThumbnailLruCache.put(file, data);
+    ThumbnailInMemoryLruCache.put(file, data);
     return data;
     return data;
   }
   }
-  if (!_map.containsKey(file.uploadedFileID)) {
-    if (_queue.length > kMaximumConcurrentDownloads) {
-      final id = _queue.removeFirst();
-      final item = _map.remove(id)!;
+  // Check if there's already in flight request for fetching thumbnail from the
+  // server
+  if (!_uploadIDToDownloadItem.containsKey(file.uploadedFileID)) {
+    final item =
+        FileDownloadItem(file, Completer<Uint8List>(), CancelToken(), 1);
+    _uploadIDToDownloadItem[file.uploadedFileID!] = item;
+    if (_downloadQueue.length > kMaximumConcurrentDownloads) {
+      final id = _downloadQueue.removeFirst();
+      final FileDownloadItem item = _uploadIDToDownloadItem.remove(id)!;
       item.cancelToken.cancel();
       item.cancelToken.cancel();
       item.completer.completeError(RequestCancelledError());
       item.completer.completeError(RequestCancelledError());
     }
     }
-    final item =
-        FileDownloadItem(file, Completer<Uint8List>(), CancelToken(), 1);
-    _map[file.uploadedFileID!] = item;
-    _queue.add(file.uploadedFileID!);
+    _downloadQueue.add(file.uploadedFileID!);
     _downloadItem(item);
     _downloadItem(item);
     return item.completer.future;
     return item.completer.future;
   } else {
   } else {
-    _map[file.uploadedFileID]!.counter++;
-    return _map[file.uploadedFileID]!.completer.future;
+    _uploadIDToDownloadItem[file.uploadedFileID]!.counter++;
+    return _uploadIDToDownloadItem[file.uploadedFileID]!.completer.future;
   }
   }
 }
 }
 
 
@@ -63,21 +65,21 @@ Future<Uint8List?> getThumbnailFromLocal(
   int size = thumbnailSmallSize,
   int size = thumbnailSmallSize,
   int quality = thumbnailQuality,
   int quality = thumbnailQuality,
 }) async {
 }) async {
-  final lruCachedThumbnail = ThumbnailLruCache.get(file, size);
+  final lruCachedThumbnail = ThumbnailInMemoryLruCache.get(file, size);
   if (lruCachedThumbnail != null) {
   if (lruCachedThumbnail != null) {
     return lruCachedThumbnail;
     return lruCachedThumbnail;
   }
   }
   final cachedThumbnail = cachedThumbnailPath(file);
   final cachedThumbnail = cachedThumbnailPath(file);
   if ((await cachedThumbnail.exists())) {
   if ((await cachedThumbnail.exists())) {
     final data = await cachedThumbnail.readAsBytes();
     final data = await cachedThumbnail.readAsBytes();
-    ThumbnailLruCache.put(file, data);
+    ThumbnailInMemoryLruCache.put(file, data);
     return data;
     return data;
   }
   }
   if (file.isSharedMediaToAppSandbox) {
   if (file.isSharedMediaToAppSandbox) {
     //todo:neeraj support specifying size/quality
     //todo:neeraj support specifying size/quality
     return getThumbnailFromInAppCacheFile(file).then((data) {
     return getThumbnailFromInAppCacheFile(file).then((data) {
       if (data != null) {
       if (data != null) {
-        ThumbnailLruCache.put(file, data, size);
+        ThumbnailInMemoryLruCache.put(file, data, size);
       }
       }
       return data;
       return data;
     });
     });
@@ -89,7 +91,7 @@ Future<Uint8List?> getThumbnailFromLocal(
       return asset
       return asset
           .thumbnailDataWithSize(ThumbnailSize(size, size), quality: quality)
           .thumbnailDataWithSize(ThumbnailSize(size, size), quality: quality)
           .then((data) {
           .then((data) {
-        ThumbnailLruCache.put(file, data, size);
+        ThumbnailInMemoryLruCache.put(file, data, size);
         return data;
         return data;
       });
       });
     });
     });
@@ -97,13 +99,13 @@ Future<Uint8List?> getThumbnailFromLocal(
 }
 }
 
 
 void removePendingGetThumbnailRequestIfAny(File file) {
 void removePendingGetThumbnailRequestIfAny(File file) {
-  if (_map.containsKey(file.uploadedFileID)) {
-    final item = _map[file.uploadedFileID]!;
+  if (_uploadIDToDownloadItem.containsKey(file.uploadedFileID)) {
+    final item = _uploadIDToDownloadItem[file.uploadedFileID]!;
     item.counter--;
     item.counter--;
     if (item.counter <= 0) {
     if (item.counter <= 0) {
-      _map.remove(file.uploadedFileID);
+      _uploadIDToDownloadItem.remove(file.uploadedFileID);
       item.cancelToken.cancel();
       item.cancelToken.cancel();
-      _queue.removeWhere((element) => element == file.uploadedFileID);
+      _downloadQueue.removeWhere((element) => element == file.uploadedFileID);
     }
     }
   }
   }
 }
 }
@@ -119,8 +121,8 @@ void _downloadItem(FileDownloadItem item) async {
     );
     );
     item.completer.completeError(e);
     item.completer.completeError(e);
   }
   }
-  _queue.removeWhere((element) => element == item.file.uploadedFileID);
-  _map.remove(item.file.uploadedFileID);
+  _downloadQueue.removeWhere((element) => element == item.file.uploadedFileID);
+  _uploadIDToDownloadItem.remove(item.file.uploadedFileID);
 }
 }
 
 
 Future<void> _downloadAndDecryptThumbnail(FileDownloadItem item) async {
 Future<void> _downloadAndDecryptThumbnail(FileDownloadItem item) async {
@@ -142,7 +144,7 @@ Future<void> _downloadAndDecryptThumbnail(FileDownloadItem item) async {
     }
     }
     rethrow;
     rethrow;
   }
   }
-  if (!_map.containsKey(file.uploadedFileID)) {
+  if (!_uploadIDToDownloadItem.containsKey(file.uploadedFileID)) {
     return;
     return;
   }
   }
   final thumbnailDecryptionKey = decryptFileKey(file);
   final thumbnailDecryptionKey = decryptFileKey(file);
@@ -155,14 +157,14 @@ Future<void> _downloadAndDecryptThumbnail(FileDownloadItem item) async {
   if (thumbnailSize > thumbnailDataLimit) {
   if (thumbnailSize > thumbnailDataLimit) {
     data = await compressThumbnail(data);
     data = await compressThumbnail(data);
   }
   }
-  ThumbnailLruCache.put(item.file, data);
+  ThumbnailInMemoryLruCache.put(item.file, data);
   final cachedThumbnail = cachedThumbnailPath(item.file);
   final cachedThumbnail = cachedThumbnailPath(item.file);
   if (await cachedThumbnail.exists()) {
   if (await cachedThumbnail.exists()) {
     await cachedThumbnail.delete();
     await cachedThumbnail.delete();
   }
   }
   // data is already cached in-memory, no need to await on dist write
   // data is already cached in-memory, no need to await on dist write
   unawaited(cachedThumbnail.writeAsBytes(data));
   unawaited(cachedThumbnail.writeAsBytes(data));
-  if (_map.containsKey(file.uploadedFileID)) {
+  if (_uploadIDToDownloadItem.containsKey(file.uploadedFileID)) {
     try {
     try {
       item.completer.complete(data);
       item.completer.complete(data);
     } catch (e) {
     } catch (e) {

+ 4 - 1
lib/utils/validator_util.dart

@@ -25,7 +25,10 @@ void validatePreVerificationStateCheck(
     "secretKeyDecryptionNonce",
     "secretKeyDecryptionNonce",
   );
   );
   nullOrEmptyArgCheck(keyAttr.publicKey, "publicKey");
   nullOrEmptyArgCheck(keyAttr.publicKey, "publicKey");
-  if (keyAttr.memLimit <= 0 || keyAttr.opsLimit <= 0) {
+  if (keyAttr.memLimit == null || keyAttr.opsLimit == null) {
+    throw ArgumentError("Key mem/OpsLimit can not be null");
+  }
+  if (keyAttr.memLimit! <= 0 || keyAttr.opsLimit! <= 0) {
     throw ArgumentError("Key mem/OpsLimit can not be <0");
     throw ArgumentError("Key mem/OpsLimit can not be <0");
   }
   }
   // check password encoding issues
   // check password encoding issues