diff --git a/.gitignore b/.gitignore index b22a5648..067d0e08 100644 --- a/.gitignore +++ b/.gitignore @@ -124,6 +124,10 @@ app.*.map.json !**/ios/**/default.pbxuser !**/ios/**/default.perspectivev3 !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +example/.flutter-plugins-dependencies +flutter_cache_manager/example/ios/Flutter/.last_build_id + +flutter_cache_manager/coverage/ !/dev/ci/**/Gemfile.lock !.vscode/settings.json !.vscode/tasks.json @@ -138,4 +142,4 @@ app.*.map.json *.g.dart # Injection generated files -injectable.config.dart \ No newline at end of file +injectable.config.dart diff --git a/flutter_cache_manager/README.md b/flutter_cache_manager/README.md index 8ea4e19e..fac7d22e 100644 --- a/flutter_cache_manager/README.md +++ b/flutter_cache_manager/README.md @@ -56,6 +56,9 @@ The image from the url is resized within the specifications, and the resized ima always tries to keep the existing aspect ratios. The original image is also cached and used to resize the image if you call this method with other height/width parameters. +And also there's a `getFileFromCache` method that returns a resized image from the cache only without downloading it. +`getFileFromCache` only retrieves from cache and returns no image when the image is not in the cache. + ## Other implementations When your files are stored on Firebase Storage you can use [flutter_cache_manager_firebase](https://pub.dev/packages/flutter_cache_manager_firebase). diff --git a/flutter_cache_manager/lib/src/cache_managers/image_cache_manager.dart b/flutter_cache_manager/lib/src/cache_managers/image_cache_manager.dart index 614d7d9d..f6c65dd7 100644 --- a/flutter_cache_manager/lib/src/cache_managers/image_cache_manager.dart +++ b/flutter_cache_manager/lib/src/cache_managers/image_cache_manager.dart @@ -7,7 +7,41 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; const supportedFileNames = ['jpg', 'jpeg', 'png', 'tga', 'cur', 'ico']; + mixin ImageCacheManager on BaseCacheManager { + /// Get the image from the cache and resize if needed + /// Specify [ignoreMemCache] to force a re-read from the database + Future getImageFileFromCache( + String key, { + int? maxHeight, + int? maxWidth, + bool ignoreMemCache = false, + }) async { + final fromCache = + await getFileFromCache(key, ignoreMemCache: ignoreMemCache); + if ((maxHeight == null && maxWidth == null) || fromCache == null) { + return fromCache; + } + + var resizedKey = 'resized'; + if (maxWidth != null) resizedKey += '_w$maxWidth'; + if (maxHeight != null) resizedKey += '_h$maxHeight'; + resizedKey += '_$key'; + + final fromCacheResized = + await getFileFromCache(resizedKey, ignoreMemCache: ignoreMemCache); + if (fromCacheResized != null) { + return fromCacheResized; + } + final resizedFile = await _resizeImageFile( + fromCache, + resizedKey, + maxWidth, + maxHeight, + ); + return resizedFile; + } + /// Returns a resized image file to fit within maxHeight and maxWidth. It /// tries to keep the aspect ratio. It stores the resized image by adding /// the size to the key or url. For example when resizing diff --git a/flutter_cache_manager/test/image_cache_manager_test.dart b/flutter_cache_manager/test/image_cache_manager_test.dart index f3701d5d..0076a70d 100644 --- a/flutter_cache_manager/test/image_cache_manager_test.dart +++ b/flutter_cache_manager/test/image_cache_manager_test.dart @@ -125,6 +125,59 @@ void main() { expect(progress, isNotEmpty); }); }); + group('Test resized image getting from cache', () { + test('Image should be fetched from cache without resizing', () async { + var config = await setupConfig(cacheKey: fileName); + var cacheManager = TestCacheManager(config); + var result = await cacheManager.getImageFileFromCache( + fileName, + ) as FileInfo?; + + await verifySize(result?.file.readAsBytesSync(), 120, 120); + config.verifyNoDownloadCall(); + }); + + test('Image should be fetched from cache with resizing', () async { + var config = await setupConfig(cacheKey: fileName); + var cacheManager = TestCacheManager(config); + var result = await cacheManager.getImageFileFromCache( + fileName, + maxHeight: 100, + maxWidth: 80, + ) as FileInfo?; + + await verifySize(result?.file.readAsBytesSync(), 80, 80); + config.verifyNoDownloadCall(); + }); + + test('Resized image should be fetched from cache', () async { + var config = await setupConfig(cacheKey: fileName); + config.returnsCacheObject(fileUrl, fileName, validTill, + key: 'resized_w100_h80_$fileName'); + var cacheManager = TestCacheManager(config); + var result = await cacheManager.getImageFileFromCache( + fileName, + maxWidth: 100, + maxHeight: 80, + ) as FileInfo?; + + expect(result, isNotNull); + config.verifyNoDownloadCall(); + }); + + test('If no image is in cache null should be returned', () async { + var config = await setupConfig(cacheKey: ''); + var cacheManager = TestCacheManager(config); + var result = await cacheManager.getImageFileFromCache( + fileUrl, + maxWidth: 100, + maxHeight: 80, + ) as FileInfo?; + + expect(result, isNull); + config.verifyNoDownloadCall(); + }); + }); } Future setupCacheManager() async { @@ -140,10 +193,15 @@ Future setupConfig({String? cacheKey}) async { } Future verifySize( - Uint8List image, + Uint8List? image, int expectedWidth, int expectedHeight, ) async { + expect(image, isNotNull); + if (image == null) { + return; + } + var codec = await instantiateImageCodec(image); var frame = await codec.getNextFrame(); var height = frame.image.height;