Add support for uploading & reading image from app cache

This commit is contained in:
Neeraj Gupta 2021-07-22 11:41:32 +05:30
parent 9e2c555dbc
commit 9adf41fd2e
4 changed files with 98 additions and 24 deletions

View file

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

View file

@ -24,8 +24,11 @@ class MediaUploadData {
}
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 {
@ -93,3 +96,32 @@ Future<void> _decorateEnteFileData(ente.File file, AssetEntity asset) async {
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;
}

View file

@ -20,6 +20,7 @@ import 'package:photos/services/collections_service.dart';
import 'package:photos/utils/thumbnail_util.dart';
import 'crypto_util.dart';
import 'file_uploader_util.dart';
final _logger = Logger("FileUtil");
@ -36,7 +37,7 @@ Future<io.File> getFile(ente.File file) async {
} else {
final cachedFile = FileLruCache.get(file);
if (cachedFile == null) {
final diskFile = await (await file.getAsset()).file;
final diskFile = await _getLocalDiskFile(file);
FileLruCache.put(file, 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) {
if (file.isRemoteFile()) {
getThumbnailFromServer(file);
} 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";
try {
fileExtension = extension(file.title).substring(1).toLowerCase();
} catch(e) {
} catch (e) {
_logger.severe("Could not capture file extension");
}
var outputFile = decryptedFile;
if ((fileExtension=="unknown" && file.fileType == FileType.image) ||
if ((fileExtension == "unknown" && file.fileType == FileType.image) ||
(io.Platform.isAndroid && fileExtension == "heic")) {
outputFile = await FlutterImageCompress.compressAndGetFile(
decryptedFilePath,
@ -156,6 +151,11 @@ Future<io.File> _downloadAndDecrypt(
maxAge: Duration(days: 365),
fileExtension: fileExtension,
);
_logger.info("File Put in cacheManager " +
file.uploadedFileID.toString() +
" " +
cachedFile.uri.toString());
outputFile.deleteSync();
fileDownloadsInProgress.remove(file.uploadedFileID);
return cachedFile;

View file

@ -17,6 +17,8 @@ import 'package:photos/utils/file_util.dart';
import 'dart:io' as io;
import 'file_uploader_util.dart';
final _logger = Logger("ThumbnailUtil");
final _map = LinkedHashMap<int, FileDownloadItem>();
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) {
if (_map.containsKey(file.uploadedFileID)) {
final item = _map[file.uploadedFileID];
@ -132,5 +168,6 @@ Future<void> _downloadAndDecryptThumbnail(FileDownloadItem item) async {
io.File getCachedThumbnail(File file) {
final thumbnailCacheDirectory =
Configuration.instance.getThumbnailCacheDirectory();
return io.File(thumbnailCacheDirectory + "/" + file.uploadedFileID.toString());
}
return io.File(
thumbnailCacheDirectory + "/" + file.uploadedFileID.toString());
}