Refactor
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import "package:flutter/foundation.dart";
|
||||
|
||||
const int thumbnailSmallSize = 256;
|
||||
const int thumbnailQuality = 50;
|
||||
const int thumbnailLargeSize = 512;
|
||||
const int compressedThumbnailResolution = 1080;
|
||||
const int thumbnailDataLimit = 100 * 1024;
|
||||
// thumbnailSmallSize Thumbnail sizes in pixels 256px
|
||||
const int thumbnailSmall256 = 256;
|
||||
// thumbnailMediumSize Thumbnail sizes in pixels 512px
|
||||
const int thumbnailLarge512 = 512; // 512px
|
||||
const int compressThumb1080 = 1080;
|
||||
const int thumbnailDataMaxSize = 100 * 1024;
|
||||
const String sentryDSN =
|
||||
"https://2235e5c99219488ea93da34b9ac1cb68@sentry.ente.io/4";
|
||||
const String sentryDebugDSN =
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import "package:photos/utils/standalone/task_queue.dart";
|
||||
|
||||
class LocalThumbnailService {
|
||||
final thumbnailQueue = TaskQueue<String>(
|
||||
maxConcurrentTasks: 15,
|
||||
taskTimeout: const Duration(minutes: 1),
|
||||
maxQueueSize: 100, // Limit the queue to 50 pending tasks
|
||||
);
|
||||
}
|
||||
49
mobile/lib/image/thumnail/upload_thumb.dart
Normal file
49
mobile/lib/image/thumnail/upload_thumb.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
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/utils/file_util.dart";
|
||||
|
||||
Logger _logger = Logger("UploadThumbnailService");
|
||||
const kMaximumThumbnailCompressionAttempts = 2;
|
||||
Future<Uint8List?> getThumbnailForUpload(
|
||||
AssetEntity asset,
|
||||
) async {
|
||||
try {
|
||||
Uint8List? thumbnailData = await asset.thumbnailDataWithSize(
|
||||
const ThumbnailSize(thumbnailLarge512, thumbnailLarge512),
|
||||
quality: thumbnailQuality,
|
||||
);
|
||||
if (thumbnailData == null) {
|
||||
// allow videos to be uploaded without thumbnails
|
||||
if (asset.type == AssetType.video) {
|
||||
return null;
|
||||
}
|
||||
throw InvalidFileError(
|
||||
"no thumbnail : ${asset.type.name} ${asset.id}",
|
||||
InvalidReason.thumbnailMissing,
|
||||
);
|
||||
}
|
||||
int compressionAttempts = 0;
|
||||
while (thumbnailData!.length > thumbnailDataMaxSize &&
|
||||
compressionAttempts < kMaximumThumbnailCompressionAttempts) {
|
||||
_logger.info("Thumbnail size " + thumbnailData.length.toString());
|
||||
thumbnailData = await compressThumbnail(thumbnailData);
|
||||
_logger
|
||||
.info("Compressed thumbnail size " + thumbnailData.length.toString());
|
||||
compressionAttempts++;
|
||||
}
|
||||
return thumbnailData;
|
||||
} catch (e) {
|
||||
final String errMessage =
|
||||
"thumbErr id: ${asset.id} type: ${asset.type.name}, name: ${await asset.titleAsync}";
|
||||
_logger.warning(errMessage, e);
|
||||
// allow videos to be uploaded without thumbnails
|
||||
if (asset.type == AssetType.video) {
|
||||
return null;
|
||||
}
|
||||
throw InvalidFileError(errMessage, InvalidReason.thumbnailMissing);
|
||||
}
|
||||
}
|
||||
47
mobile/lib/services/local/asset_entity.service.dart
Normal file
47
mobile/lib/services/local/asset_entity.service.dart
Normal file
@@ -0,0 +1,47 @@
|
||||
import "dart:async";
|
||||
import "dart:io";
|
||||
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photo_manager/photo_manager.dart";
|
||||
import "package:photos/core/errors.dart";
|
||||
|
||||
class AssetEntityService {
|
||||
static final Logger _logger = Logger("AssetEntityService");
|
||||
static Future<AssetEntity> fromIDWithRetry(String localID) async {
|
||||
final asset = await AssetEntity.fromId(localID)
|
||||
.timeout(const Duration(seconds: 3))
|
||||
.catchError((e) async {
|
||||
if (e is TimeoutException) {
|
||||
_logger.info("Asset fetch timed out for id $localID ");
|
||||
return await AssetEntity.fromId(localID);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
if (asset == null) {
|
||||
throw InvalidFileError("asset null", InvalidReason.assetDeleted);
|
||||
}
|
||||
return asset;
|
||||
}
|
||||
|
||||
static Future<File> sourceFromAsset(AssetEntity asset) async {
|
||||
final sourceFile = await asset.originFile
|
||||
.timeout(const Duration(seconds: 15))
|
||||
.catchError((e) async {
|
||||
if (e is TimeoutException) {
|
||||
_logger.info("Origin file fetch timed out for ${asset.id}");
|
||||
return await asset.originFile;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
if (sourceFile == null || !sourceFile.existsSync()) {
|
||||
throw InvalidFileError(
|
||||
"id: ${asset.id}",
|
||||
InvalidReason.sourceFileMissing,
|
||||
);
|
||||
}
|
||||
return sourceFile;
|
||||
}
|
||||
}
|
||||
@@ -6,12 +6,12 @@ import "package:ente_crypto/ente_crypto.dart";
|
||||
import "package:exif_reader/exif_reader.dart";
|
||||
import "package:logging/logging.dart";
|
||||
import "package:motion_photos/motion_photos.dart";
|
||||
import "package:photos/core/errors.dart";
|
||||
import "package:photos/extensions/stop_watch.dart";
|
||||
import "package:photos/models/ffmpeg/ffprobe_props.dart";
|
||||
import "package:photos/models/file/file.dart";
|
||||
import "package:photos/models/local/local_metadata.dart";
|
||||
import "package:photos/models/location/location.dart";
|
||||
import "package:photos/services/local/asset_entity.service.dart";
|
||||
import "package:photos/utils/exif_util.dart";
|
||||
import "package:wechat_assets_picker/wechat_assets_picker.dart";
|
||||
|
||||
@@ -21,8 +21,8 @@ class LocalMetadataService {
|
||||
static Future<DroidMetadata?> getMetadata(String id) async {
|
||||
try {
|
||||
final TimeLogger t = TimeLogger(context: "getDroidMetadata");
|
||||
final AssetEntity asset = await fromIDWithRetry(id);
|
||||
final sourceFile = await sourceFromAsset(asset);
|
||||
final AssetEntity asset = await AssetEntityService.fromIDWithRetry(id);
|
||||
final sourceFile = await AssetEntityService.sourceFromAsset(asset);
|
||||
final latLng = await asset.latlngAsync();
|
||||
Location location =
|
||||
Location(latitude: latLng.latitude, longitude: latLng.longitude);
|
||||
@@ -89,41 +89,4 @@ class LocalMetadataService {
|
||||
taskName: "motionVideoIndex",
|
||||
);
|
||||
}
|
||||
|
||||
static Future<AssetEntity> fromIDWithRetry(String localID) async {
|
||||
final asset = await AssetEntity.fromId(localID)
|
||||
.timeout(const Duration(seconds: 3))
|
||||
.catchError((e) async {
|
||||
if (e is TimeoutException) {
|
||||
_logger.info("Asset fetch timed out for id $localID ");
|
||||
return await AssetEntity.fromId(localID);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
if (asset == null) {
|
||||
throw InvalidFileError("", InvalidReason.assetDeleted);
|
||||
}
|
||||
return asset;
|
||||
}
|
||||
|
||||
static Future<File> sourceFromAsset(AssetEntity asset) async {
|
||||
final sourceFile = await asset.originFile
|
||||
.timeout(const Duration(seconds: 15))
|
||||
.catchError((e) async {
|
||||
if (e is TimeoutException) {
|
||||
_logger.info("Origin file fetch timed out for ${asset.id}");
|
||||
return await asset.originFile;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
if (sourceFile == null || !sourceFile.existsSync()) {
|
||||
throw InvalidFileError(
|
||||
"id: ${asset.id}",
|
||||
InvalidReason.sourceFileMissing,
|
||||
);
|
||||
}
|
||||
return sourceFile;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ class _BackDrop extends StatelessWidget {
|
||||
backDropImage,
|
||||
shouldShowSyncStatus: false,
|
||||
shouldShowFavoriteIcon: false,
|
||||
thumbnailSize: thumbnailLargeSize,
|
||||
thumbnailSize: thumbnailLarge512,
|
||||
),
|
||||
BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 12, sigmaY: 12),
|
||||
@@ -388,7 +388,7 @@ class _CustomImage extends StatelessWidget {
|
||||
file,
|
||||
shouldShowSyncStatus: false,
|
||||
shouldShowFavoriteIcon: false,
|
||||
thumbnailSize: thumbnailLargeSize,
|
||||
thumbnailSize: thumbnailLarge512,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -53,7 +53,7 @@ class ThumbnailWidget extends StatefulWidget {
|
||||
this.shouldShowOwnerAvatar = false,
|
||||
this.diskLoadDeferDuration,
|
||||
this.serverLoadDeferDuration,
|
||||
this.thumbnailSize = thumbnailSmallSize,
|
||||
this.thumbnailSize = thumbnailSmall256,
|
||||
this.shouldShowFavoriteIcon = true,
|
||||
this.shouldShowVideoDuration = false,
|
||||
this.shouldShowVideoOverlayIcon = true,
|
||||
@@ -250,7 +250,7 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
|
||||
!_isLoadingRemoteThumbnail) {
|
||||
_isLoadingRemoteThumbnail = true;
|
||||
final cachedThumbnail =
|
||||
enteImageCache.getThumb(widget.file, thumbnailLargeSize);
|
||||
enteImageCache.getThumb(widget.file, thumbnailLarge512);
|
||||
if (cachedThumbnail != null) {
|
||||
_imageProvider = Image.memory(cachedThumbnail).image;
|
||||
_hasLoadedThumbnail = true;
|
||||
|
||||
@@ -258,7 +258,7 @@ class _ZoomableImageState extends State<ZoomableImage> {
|
||||
void _loadNetworkImage() {
|
||||
if (!_loadedSmallThumbnail && !_loadedFinalImage) {
|
||||
final cachedThumbnail =
|
||||
enteImageCache.getThumb(_photo, thumbnailLargeSize);
|
||||
enteImageCache.getThumb(_photo, thumbnailLarge512);
|
||||
if (cachedThumbnail != null) {
|
||||
_imageProvider = Image.memory(cachedThumbnail).image;
|
||||
_loadedSmallThumbnail = true;
|
||||
@@ -300,7 +300,7 @@ class _ZoomableImageState extends State<ZoomableImage> {
|
||||
!_loadedLargeThumbnail &&
|
||||
!_loadedFinalImage) {
|
||||
final cachedThumbnail =
|
||||
enteImageCache.getThumb(_photo, thumbnailSmallSize);
|
||||
enteImageCache.getThumb(_photo, thumbnailSmall256);
|
||||
if (cachedThumbnail != null) {
|
||||
_imageProvider = Image.memory(cachedThumbnail).image;
|
||||
_loadedSmallThumbnail = true;
|
||||
@@ -311,7 +311,7 @@ class _ZoomableImageState extends State<ZoomableImage> {
|
||||
!_loadedLargeThumbnail &&
|
||||
!_loadedFinalImage) {
|
||||
_loadingLargeThumbnail = true;
|
||||
getThumbnailFromLocal(_photo, size: thumbnailLargeSize, quality: 100)
|
||||
getThumbnailFromLocal(_photo, size: thumbnailLarge512, quality: 100)
|
||||
.then((cachedThumbnail) {
|
||||
if (cachedThumbnail != null) {
|
||||
_onLargeThumbnailLoaded(Image.memory(cachedThumbnail).image, context);
|
||||
|
||||
@@ -52,8 +52,8 @@ class GalleryFileWidget extends StatelessWidget {
|
||||
shouldShowLivePhotoOverlay: true,
|
||||
key: Key(heroTag),
|
||||
thumbnailSize: photoGridSize < photoGridSizeDefault
|
||||
? thumbnailLargeSize
|
||||
: thumbnailSmallSize,
|
||||
? thumbnailLarge512
|
||||
: thumbnailSmall256,
|
||||
shouldShowOwnerAvatar: !isFileSelected,
|
||||
shouldShowVideoDuration: true,
|
||||
);
|
||||
|
||||
@@ -17,12 +17,14 @@ import 'package:photo_manager/photo_manager.dart';
|
||||
import 'package:photos/core/configuration.dart';
|
||||
import 'package:photos/core/constants.dart';
|
||||
import 'package:photos/core/errors.dart';
|
||||
import "package:photos/image/thumnail/upload_thumb.dart";
|
||||
import "package:photos/models/api/metadata.dart";
|
||||
import "package:photos/models/ffmpeg/ffprobe_props.dart";
|
||||
import "package:photos/models/file/extensions/file_props.dart";
|
||||
import 'package:photos/models/file/file.dart';
|
||||
import 'package:photos/models/file/file_type.dart';
|
||||
import "package:photos/models/location/location.dart";
|
||||
import "package:photos/services/local/asset_entity.service.dart";
|
||||
import "package:photos/services/local/local_import.dart";
|
||||
import "package:photos/utils/exif_util.dart";
|
||||
import 'package:photos/utils/file_util.dart';
|
||||
@@ -30,7 +32,6 @@ import "package:uuid/uuid.dart";
|
||||
import 'package:video_thumbnail/video_thumbnail.dart';
|
||||
|
||||
final _logger = Logger("FileUtil");
|
||||
const kMaximumThumbnailCompressionAttempts = 2;
|
||||
|
||||
class MediaUploadData {
|
||||
final File? sourceFile;
|
||||
@@ -95,39 +96,12 @@ Future<MediaUploadData> _getMediaUploadDataFromAssetFile(
|
||||
Map<String, IfdTag>? exifData;
|
||||
|
||||
// The timeouts are to safeguard against https://github.com/CaiJingLong/flutter_photo_manager/issues/467
|
||||
final asset = await file.getAsset
|
||||
.timeout(const Duration(seconds: 3))
|
||||
.catchError((e) async {
|
||||
if (e is TimeoutException) {
|
||||
_logger.info("Asset fetch timed out for " + file.toString());
|
||||
return await file.getAsset;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
if (asset == null) {
|
||||
throw InvalidFileError("", InvalidReason.assetDeleted);
|
||||
}
|
||||
final asset = await AssetEntityService.fromIDWithRetry(file.lAsset!.id);
|
||||
_assertFileType(asset, file);
|
||||
if (Platform.isIOS) {
|
||||
trackOriginFetchForUploadOrML.put(file.localID!, true);
|
||||
}
|
||||
sourceFile = await asset.originFile
|
||||
.timeout(const Duration(seconds: 15))
|
||||
.catchError((e) async {
|
||||
if (e is TimeoutException) {
|
||||
_logger.info("Origin file fetch timed out for " + file.tag);
|
||||
return await asset.originFile;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
if (sourceFile == null || !sourceFile.existsSync()) {
|
||||
throw InvalidFileError(
|
||||
"id: ${file.localID}",
|
||||
InvalidReason.sourceFileMissing,
|
||||
);
|
||||
trackOriginFetchForUploadOrML.put(file.lAsset!.id, true);
|
||||
}
|
||||
sourceFile = await AssetEntityService.sourceFromAsset(asset);
|
||||
if (parseExif) {
|
||||
exifData = await tryExifFromFile(sourceFile);
|
||||
}
|
||||
@@ -143,10 +117,10 @@ Future<MediaUploadData> _getMediaUploadDataFromAssetFile(
|
||||
_logger.severe(errMsg);
|
||||
throw InvalidFileError(errMsg, InvalidReason.livePhotoVideoMissing);
|
||||
}
|
||||
final String livePhotoVideoHash =
|
||||
final String videoHash =
|
||||
CryptoUtil.bin2base64(await CryptoUtil.getHash(videoUrl));
|
||||
// imgHash:vidHash
|
||||
fileHash = '$fileHash$kLivePhotoHashSeparator$livePhotoVideoHash';
|
||||
fileHash = '$fileHash$kLivePhotoHashSeparator$videoHash';
|
||||
final tempPath = Configuration.instance.getTempDirectory();
|
||||
// .elp -> ente live photo
|
||||
final uniqueId = const Uuid().v4().toString();
|
||||
@@ -166,7 +140,7 @@ Future<MediaUploadData> _getMediaUploadDataFromAssetFile(
|
||||
zipHash = CryptoUtil.bin2base64(await CryptoUtil.getHash(sourceFile));
|
||||
}
|
||||
|
||||
thumbnailData = await _getThumbnailForUpload(asset, file);
|
||||
thumbnailData = await getThumbnailForUpload(asset);
|
||||
isDeleted = !(await asset.exists);
|
||||
int? h, w;
|
||||
if (asset.width != 0 && asset.height != 0) {
|
||||
@@ -202,24 +176,25 @@ Future<int?> motionVideoIndex(Map<String, dynamic> args) async {
|
||||
return (await MotionPhotos(path).getMotionVideoIndex())?.start;
|
||||
}
|
||||
|
||||
Future<void> _computeZip(Map<String, dynamic> args) async {
|
||||
final String zipPath = args['zipPath'];
|
||||
final String imagePath = args['imagePath'];
|
||||
final String videoPath = args['videoPath'];
|
||||
final encoder = ZipFileEncoder();
|
||||
encoder.create(zipPath);
|
||||
await encoder.addFile(File(imagePath), "image" + extension(imagePath));
|
||||
await encoder.addFile(File(videoPath), "video" + extension(videoPath));
|
||||
await encoder.close();
|
||||
}
|
||||
|
||||
Future<void> zip({
|
||||
required String zipPath,
|
||||
required String imagePath,
|
||||
required String videoPath,
|
||||
}) {
|
||||
return Computer.shared().compute(
|
||||
_computeZip,
|
||||
(Map<String, dynamic> args) async {
|
||||
final encoder = ZipFileEncoder();
|
||||
encoder.create(args['zipPath']);
|
||||
await encoder.addFile(
|
||||
File(args['imagePath']),
|
||||
"image${extension(args['imagePath'])}",
|
||||
);
|
||||
await encoder.addFile(
|
||||
File(args['videoPath']),
|
||||
"video${extension(args['videoPath'])}",
|
||||
);
|
||||
await encoder.close();
|
||||
},
|
||||
param: {
|
||||
'zipPath': zipPath,
|
||||
'imagePath': imagePath,
|
||||
@@ -229,47 +204,6 @@ Future<void> zip({
|
||||
);
|
||||
}
|
||||
|
||||
Future<Uint8List?> _getThumbnailForUpload(
|
||||
AssetEntity asset,
|
||||
EnteFile file,
|
||||
) async {
|
||||
try {
|
||||
Uint8List? thumbnailData = await asset.thumbnailDataWithSize(
|
||||
const ThumbnailSize(thumbnailLargeSize, thumbnailLargeSize),
|
||||
quality: thumbnailQuality,
|
||||
);
|
||||
if (thumbnailData == null) {
|
||||
// allow videos to be uploaded without thumbnails
|
||||
if (asset.type == AssetType.video) {
|
||||
return null;
|
||||
}
|
||||
throw InvalidFileError(
|
||||
"no thumbnail : ${file.fileType} ${file.tag}",
|
||||
InvalidReason.thumbnailMissing,
|
||||
);
|
||||
}
|
||||
int compressionAttempts = 0;
|
||||
while (thumbnailData!.length > thumbnailDataLimit &&
|
||||
compressionAttempts < kMaximumThumbnailCompressionAttempts) {
|
||||
_logger.info("Thumbnail size " + thumbnailData.length.toString());
|
||||
thumbnailData = await compressThumbnail(thumbnailData);
|
||||
_logger
|
||||
.info("Compressed thumbnail size " + thumbnailData.length.toString());
|
||||
compressionAttempts++;
|
||||
}
|
||||
return thumbnailData;
|
||||
} catch (e) {
|
||||
final String errMessage =
|
||||
"thumbErr for ${file.fileType}, ${extension(file.displayName)} ${file.tag}";
|
||||
_logger.warning(errMessage, e);
|
||||
// allow videos to be uploaded without thumbnails
|
||||
if (asset.type == AssetType.video) {
|
||||
return null;
|
||||
}
|
||||
throw InvalidFileError(errMessage, InvalidReason.thumbnailMissing);
|
||||
}
|
||||
}
|
||||
|
||||
// check if the assetType is still the same. This can happen for livePhotos
|
||||
// if the user turns off the video using native photos app
|
||||
void _assertFileType(AssetEntity asset, EnteFile file) {
|
||||
@@ -443,7 +377,7 @@ Future<Uint8List?> getThumbnailFromInAppCacheFile(EnteFile file) async {
|
||||
video: localFile.path,
|
||||
imageFormat: ImageFormat.JPEG,
|
||||
thumbnailPath: (await getTemporaryDirectory()).path,
|
||||
maxWidth: thumbnailLargeSize,
|
||||
maxWidth: thumbnailLarge512,
|
||||
quality: 80,
|
||||
);
|
||||
localFile = File(thumbnailFilePath!);
|
||||
@@ -454,7 +388,7 @@ Future<Uint8List?> getThumbnailFromInAppCacheFile(EnteFile file) async {
|
||||
}
|
||||
var thumbnailData = await localFile.readAsBytes();
|
||||
int compressionAttempts = 0;
|
||||
while (thumbnailData.length > thumbnailDataLimit &&
|
||||
while (thumbnailData.length > thumbnailDataMaxSize &&
|
||||
compressionAttempts < kMaximumThumbnailCompressionAttempts) {
|
||||
_logger.info("Thumbnail size " + thumbnailData.length.toString());
|
||||
thumbnailData = await compressThumbnail(thumbnailData);
|
||||
|
||||
@@ -342,8 +342,8 @@ String getExtension(String nameOrPath) {
|
||||
Future<Uint8List> compressThumbnail(Uint8List thumbnail) {
|
||||
return FlutterImageCompress.compressWithList(
|
||||
thumbnail,
|
||||
minHeight: compressedThumbnailResolution,
|
||||
minWidth: compressedThumbnailResolution,
|
||||
minHeight: compressThumb1080,
|
||||
minWidth: compressThumb1080,
|
||||
quality: 25,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ Future<Uint8List?> getThumbnail(EnteFile file) async {
|
||||
} else {
|
||||
return getThumbnailFromLocal(
|
||||
file,
|
||||
size: thumbnailLargeSize,
|
||||
size: thumbnailLarge512,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ Future<Uint8List> getThumbnailFromServer(EnteFile file) async {
|
||||
final cachedThumbnail = cachedThumbnailPath(file);
|
||||
if (await cachedThumbnail.exists()) {
|
||||
final data = await cachedThumbnail.readAsBytes();
|
||||
enteImageCache.putThumb(file, data, thumbnailLargeSize);
|
||||
enteImageCache.putThumb(file, data, thumbnailLarge512);
|
||||
return data;
|
||||
}
|
||||
// Check if there's already in flight request for fetching thumbnail from the
|
||||
@@ -95,7 +95,7 @@ Future<Uint8List> getThumbnailFromServer(EnteFile file) async {
|
||||
|
||||
Future<Uint8List?> getThumbnailFromLocal(
|
||||
EnteFile file, {
|
||||
int size = thumbnailSmallSize,
|
||||
int size = thumbnailSmall256,
|
||||
int quality = thumbnailQuality,
|
||||
}) async {
|
||||
final lruCachedThumbnail = enteImageCache.getThumb(file, size);
|
||||
@@ -116,7 +116,8 @@ Future<Uint8List?> getThumbnailFromLocal(
|
||||
return null;
|
||||
}
|
||||
return asset
|
||||
.thumbnailDataWithSize(ThumbnailSize(size, size), quality: quality, format: ThumbnailFormat.jpeg)
|
||||
.thumbnailDataWithSize(ThumbnailSize(size, size),
|
||||
quality: quality, format: ThumbnailFormat.jpeg)
|
||||
.then((data) {
|
||||
enteImageCache.putThumb(file, data, size);
|
||||
return data;
|
||||
@@ -207,10 +208,10 @@ Future<void> _downloadAndDecryptThumbnail(FileDownloadItem item) async {
|
||||
return;
|
||||
}
|
||||
final thumbnailSize = data.length;
|
||||
if (thumbnailSize > thumbnailDataLimit) {
|
||||
if (thumbnailSize > thumbnailDataMaxSize) {
|
||||
data = await compressThumbnail(data);
|
||||
}
|
||||
enteImageCache.putThumb(item.file, data, thumbnailLargeSize);
|
||||
enteImageCache.putThumb(item.file, data, thumbnailLarge512);
|
||||
final cachedThumbnail = cachedThumbnailPath(item.file);
|
||||
if (await cachedThumbnail.exists()) {
|
||||
await cachedThumbnail.delete();
|
||||
|
||||
Reference in New Issue
Block a user