浏览代码

Add support for uploading & reading image from app cache

Neeraj Gupta 4 年之前
父节点
当前提交
9adf41fd2e
共有 4 个文件被更改,包括 98 次插入24 次删除
  1. 6 1
      lib/models/file.dart
  2. 34 2
      lib/utils/file_uploader_util.dart
  3. 19 19
      lib/utils/file_util.dart
  4. 39 2
      lib/utils/thumbnail_util.dart

+ 6 - 1
lib/models/file.dart

@@ -82,7 +82,7 @@ class File {
 
 
   Map<String, dynamic> getMetadata() {
   Map<String, dynamic> getMetadata() {
     final metadata = Map<String, dynamic>();
     final metadata = Map<String, dynamic>();
-    metadata["localID"] = localID;
+    metadata["localID"] = isCachedInAppSandbox() ? null : localID;
     metadata["title"] = title;
     metadata["title"] = title;
     metadata["deviceFolder"] = deviceFolder;
     metadata["deviceFolder"] = deviceFolder;
     metadata["creationTime"] = creationTime;
     metadata["creationTime"] = creationTime;
@@ -129,10 +129,15 @@ class File {
     }
     }
   }
   }
 
 
+  // returns true if the file isn't available in the user's gallery
   bool isRemoteFile() {
   bool isRemoteFile() {
     return localID == null && uploadedFileID != null;
     return localID == null && uploadedFileID != null;
   }
   }
 
 
+  bool isCachedInAppSandbox() {
+    return localID != null && localID.startsWith("ente-upload-cache");
+  }
+
   @override
   @override
   String toString() {
   String toString() {
     return '''File(generatedId: $generatedID, uploadedFileId: $uploadedFileID, 
     return '''File(generatedId: $generatedID, uploadedFileId: $uploadedFileID, 

+ 34 - 2
lib/utils/file_uploader_util.dart

@@ -24,8 +24,11 @@ class MediaUploadData {
 }
 }
 
 
 Future<MediaUploadData> getUploadDataFromEnteFile(ente.File file) async {
 Future<MediaUploadData> getUploadDataFromEnteFile(ente.File file) async {
-  // todo: add local to get data from either Asset/photoManager or app cache
-  return await _getMediaUploadDataFromAssetFile(file);
+  if (file.isCachedInAppSandbox()) {
+    return await _getMediaUploadDataFromAppCache(file);
+  } else {
+    return await _getMediaUploadDataFromAssetFile(file);
+  }
 }
 }
 
 
 Future<MediaUploadData> _getMediaUploadDataFromAssetFile(ente.File file) async {
 Future<MediaUploadData> _getMediaUploadDataFromAssetFile(ente.File file) async {
@@ -93,3 +96,32 @@ Future<void> _decorateEnteFileData(ente.File file, AssetEntity asset) async {
     file.title = await asset.titleAsync;
     file.title = await asset.titleAsync;
   }
   }
 }
 }
+
+Future<MediaUploadData> _getMediaUploadDataFromAppCache(ente.File file) async {
+  io.File sourceFile;
+  Uint8List thumbnailData;
+  bool isDeleted = false;
+  var localPath = file.localID.replaceAll(RegExp(r'ente-upload-cache:'), '');
+  sourceFile = io.File(localPath);
+  if (!sourceFile.existsSync()) {
+    _logger.warning("File doesn't exist in app sandbox");
+    throw InvalidFileError();
+  }
+  thumbnailData = await getThumbnailFromInAppCacheFile(file);
+  return MediaUploadData(sourceFile, thumbnailData, isDeleted);
+}
+
+Future<Uint8List> 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 &&
+      compressionAttempts < kMaximumThumbnailCompressionAttempts) {
+    _logger.info("Thumbnail size " + thumbnailData.length.toString());
+    thumbnailData = await compressThumbnail(thumbnailData);
+    _logger
+        .info("Compressed thumbnail size " + thumbnailData.length.toString());
+    compressionAttempts++;
+  }
+  return thumbnailData;
+}

+ 19 - 19
lib/utils/file_util.dart

@@ -20,6 +20,7 @@ import 'package:photos/services/collections_service.dart';
 import 'package:photos/utils/thumbnail_util.dart';
 import 'package:photos/utils/thumbnail_util.dart';
 
 
 import 'crypto_util.dart';
 import 'crypto_util.dart';
+import 'file_uploader_util.dart';
 
 
 final _logger = Logger("FileUtil");
 final _logger = Logger("FileUtil");
 
 
@@ -36,7 +37,7 @@ Future<io.File> getFile(ente.File file) async {
   } else {
   } else {
     final cachedFile = FileLruCache.get(file);
     final cachedFile = FileLruCache.get(file);
     if (cachedFile == null) {
     if (cachedFile == null) {
-      final diskFile = await (await file.getAsset()).file;
+      final diskFile = await _getLocalDiskFile(file);
       FileLruCache.put(file, diskFile);
       FileLruCache.put(file, diskFile);
       return diskFile;
       return diskFile;
     }
     }
@@ -44,26 +45,20 @@ Future<io.File> getFile(ente.File file) async {
   }
   }
 }
 }
 
 
+Future<io.File> _getLocalDiskFile(ente.File file) async {
+  if (file.isCachedInAppSandbox()) {
+    var localPath = file.localID.replaceAll(RegExp(r'ente-upload-cache:'), '');
+    return io.File(localPath);
+  } else {
+    return await (await file.getAsset()).file;
+  }
+}
+
 void preloadThumbnail(ente.File file) {
 void preloadThumbnail(ente.File file) {
   if (file.isRemoteFile()) {
   if (file.isRemoteFile()) {
     getThumbnailFromServer(file);
     getThumbnailFromServer(file);
   } else {
   } else {
-    if (ThumbnailLruCache.get(file, THUMBNAIL_SMALL_SIZE) != null) {
-      return;
-    }
-    file.getAsset().then((asset) {
-      if (asset != null) {
-        asset
-            .thumbDataWithSize(
-          THUMBNAIL_SMALL_SIZE,
-          THUMBNAIL_SMALL_SIZE,
-          quality: THUMBNAIL_QUALITY,
-        )
-            .then((data) {
-          ThumbnailLruCache.put(file, data, THUMBNAIL_SMALL_SIZE);
-        });
-      }
-    });
+    getThumbnailFromLocal(file);
   }
   }
 }
 }
 
 
@@ -136,11 +131,11 @@ Future<io.File> _downloadAndDecrypt(
     var fileExtension = "unknown";
     var fileExtension = "unknown";
     try {
     try {
       fileExtension = extension(file.title).substring(1).toLowerCase();
       fileExtension = extension(file.title).substring(1).toLowerCase();
-    } catch(e) {
+    } catch (e) {
       _logger.severe("Could not capture file extension");
       _logger.severe("Could not capture file extension");
     }
     }
     var outputFile = decryptedFile;
     var outputFile = decryptedFile;
-    if ((fileExtension=="unknown" && file.fileType == FileType.image) || 
+    if ((fileExtension == "unknown" && file.fileType == FileType.image) ||
         (io.Platform.isAndroid && fileExtension == "heic")) {
         (io.Platform.isAndroid && fileExtension == "heic")) {
       outputFile = await FlutterImageCompress.compressAndGetFile(
       outputFile = await FlutterImageCompress.compressAndGetFile(
         decryptedFilePath,
         decryptedFilePath,
@@ -156,6 +151,11 @@ Future<io.File> _downloadAndDecrypt(
       maxAge: Duration(days: 365),
       maxAge: Duration(days: 365),
       fileExtension: fileExtension,
       fileExtension: fileExtension,
     );
     );
+    _logger.info("File Put in cacheManager " +
+        file.uploadedFileID.toString() +
+        "  " +
+        cachedFile.uri.toString());
+
     outputFile.deleteSync();
     outputFile.deleteSync();
     fileDownloadsInProgress.remove(file.uploadedFileID);
     fileDownloadsInProgress.remove(file.uploadedFileID);
     return cachedFile;
     return cachedFile;

+ 39 - 2
lib/utils/thumbnail_util.dart

@@ -17,6 +17,8 @@ import 'package:photos/utils/file_util.dart';
 
 
 import 'dart:io' as io;
 import 'dart:io' as io;
 
 
+import 'file_uploader_util.dart';
+
 final _logger = Logger("ThumbnailUtil");
 final _logger = Logger("ThumbnailUtil");
 final _map = LinkedHashMap<int, FileDownloadItem>();
 final _map = LinkedHashMap<int, FileDownloadItem>();
 final _queue = Queue<int>();
 final _queue = Queue<int>();
@@ -57,6 +59,40 @@ Future<Uint8List> getThumbnailFromServer(File file) async {
   }
   }
 }
 }
 
 
+Future<Uint8List> getThumbnailFromLocal(File file) async {
+  if (ThumbnailLruCache.get(file, THUMBNAIL_SMALL_SIZE) != null) {
+    return ThumbnailLruCache.get(file);
+  }
+  final cachedThumbnail = getCachedThumbnail(file);
+  if (cachedThumbnail.existsSync()) {
+    final data = cachedThumbnail.readAsBytesSync();
+    ThumbnailLruCache.put(file, data);
+    return data;
+  }
+  if (file.isCachedInAppSandbox()) {
+    return getThumbnailFromInAppCacheFile(file)
+        .then((data) {
+      if (data != null) {
+        ThumbnailLruCache.put(file, data, THUMBNAIL_SMALL_SIZE);
+      }
+      return data;
+    });
+  } else {
+    return file.getAsset().then((asset) async {
+      if (asset == null || !(await asset.exists)) {
+        return null;
+      }
+      return asset
+          .thumbDataWithSize(THUMBNAIL_SMALL_SIZE, THUMBNAIL_SMALL_SIZE,
+              quality: THUMBNAIL_QUALITY)
+          .then((data) {
+        ThumbnailLruCache.put(file, data, THUMBNAIL_SMALL_SIZE);
+        return data;
+      });
+    });
+  }
+}
+
 void removePendingGetThumbnailRequestIfAny(File file) {
 void removePendingGetThumbnailRequestIfAny(File file) {
   if (_map.containsKey(file.uploadedFileID)) {
   if (_map.containsKey(file.uploadedFileID)) {
     final item = _map[file.uploadedFileID];
     final item = _map[file.uploadedFileID];
@@ -132,5 +168,6 @@ Future<void> _downloadAndDecryptThumbnail(FileDownloadItem item) async {
 io.File getCachedThumbnail(File file) {
 io.File getCachedThumbnail(File file) {
   final thumbnailCacheDirectory =
   final thumbnailCacheDirectory =
       Configuration.instance.getThumbnailCacheDirectory();
       Configuration.instance.getThumbnailCacheDirectory();
-  return io.File(thumbnailCacheDirectory + "/" + file.uploadedFileID.toString());
-}
+  return io.File(
+      thumbnailCacheDirectory + "/" + file.uploadedFileID.toString());
+}