diff --git a/packages/smooth_app/lib/generic_lib/widgets/images/smooth_image.dart b/packages/smooth_app/lib/generic_lib/widgets/images/smooth_image.dart index 3e8a6be7cf1..95e24525693 100644 --- a/packages/smooth_app/lib/generic_lib/widgets/images/smooth_image.dart +++ b/packages/smooth_app/lib/generic_lib/widgets/images/smooth_image.dart @@ -18,7 +18,16 @@ class SmoothImage extends StatelessWidget { this.fit = BoxFit.cover, this.rounded = true, this.heroTag, - }); + this.cacheWidth, + this.cacheHeight, + }) : assert( + cacheWidth == null || imageProvider is NetworkImage, + 'cacheWidth requires a NetworkImage', + ), + assert( + cacheHeight == null || imageProvider is NetworkImage, + 'cacheHeight requires a NetworkImage', + ); final ImageProvider? imageProvider; final double? height; @@ -28,17 +37,28 @@ class SmoothImage extends StatelessWidget { final BoxFit fit; final String? heroTag; final bool rounded; + final int? cacheWidth; + final int? cacheHeight; @override Widget build(BuildContext context) { - Widget child = imageProvider == null - ? const PictureNotFound() - : Image( - image: imageProvider!, - fit: fit, - loadingBuilder: _loadingBuilder, - errorBuilder: _errorBuilder, - ); + Widget child = switch (imageProvider) { + NetworkImage(url: final String url) => Image.network( + url, + fit: fit, + loadingBuilder: _loadingBuilder, + errorBuilder: _errorBuilder, + cacheWidth: cacheWidth, + cacheHeight: cacheHeight, + ), + ImageProvider() => Image( + image: imageProvider!, + fit: fit, + loadingBuilder: _loadingBuilder, + errorBuilder: _errorBuilder, + ), + _ => const PictureNotFound(), + }; if (heroTag != null) { child = Hero(tag: heroTag!, child: child); diff --git a/packages/smooth_app/lib/pages/image/product_image_gallery_other_view.dart b/packages/smooth_app/lib/pages/image/product_image_gallery_other_view.dart index 3f40df632f7..3936ac36b1a 100644 --- a/packages/smooth_app/lib/pages/image/product_image_gallery_other_view.dart +++ b/packages/smooth_app/lib/pages/image/product_image_gallery_other_view.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:openfoodfacts/openfoodfacts.dart'; @@ -108,6 +109,8 @@ class _RawGridGallery extends StatelessWidget { @override Widget build(BuildContext context) { final double squareSize = _getSquareSize(context); + final ImageSize? imageSize = _computeImageSize(squareSize); + return SliverGrid( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: _columns, @@ -137,6 +140,7 @@ class _RawGridGallery extends StatelessWidget { productImage: productImage, barcode: product.barcode!, squareSize: squareSize, + imageSize: imageSize, ), ), ); @@ -146,4 +150,12 @@ class _RawGridGallery extends StatelessWidget { ), ); } + + ImageSize? _computeImageSize(double squareSize) => [ + ImageSize.THUMB, + ImageSize.SMALL, + ImageSize.DISPLAY + ].firstWhereOrNull( + (ImageSize element) => squareSize <= int.parse(element.number), + ); } diff --git a/packages/smooth_app/lib/pages/image/product_image_widget.dart b/packages/smooth_app/lib/pages/image/product_image_widget.dart index c1448413b52..50dd84ded55 100644 --- a/packages/smooth_app/lib/pages/image/product_image_widget.dart +++ b/packages/smooth_app/lib/pages/image/product_image_widget.dart @@ -11,43 +11,20 @@ import 'package:smooth_app/resources/app_icons.dart'; import 'package:smooth_app/themes/smooth_theme_colors.dart'; /// Displays a product image thumbnail with the upload date on top. -class ProductImageWidget extends StatefulWidget { +class ProductImageWidget extends StatelessWidget { const ProductImageWidget({ required this.productImage, required this.barcode, required this.squareSize, + this.imageSize, }); final ProductImage productImage; final String barcode; final double squareSize; - @override - State createState() => _ProductImageWidgetState(); -} - -class _ProductImageWidgetState extends State { - @override - void initState() { - super.initState(); - _loadImagePalette(); - } - - Future _loadImagePalette() async { - final ColorScheme palette = await ColorScheme.fromImageProvider( - provider: NetworkImage(widget.productImage.getUrl( - widget.barcode, - uriHelper: ProductQuery.uriProductHelper, - ))); - - setState(() { - backgroundColor = palette.primaryContainer; - darkBackground = backgroundColor!.computeLuminance() < 0.5; - }); - } - - Color? backgroundColor; - bool? darkBackground; + /// Allows to fetch the optimized version of the image + final ImageSize? imageSize; @override Widget build(BuildContext context) { @@ -57,20 +34,21 @@ class _ProductImageWidgetState extends State { final DateFormat dateFormat = DateFormat.yMd(ProductQuery.getLanguage().offTag); - darkBackground = darkBackground ?? true; - final Widget image = SmoothImage( - width: widget.squareSize, - height: widget.squareSize, + cacheHeight: + (squareSize * MediaQuery.devicePixelRatioOf(context)).toInt(), + width: squareSize, + height: squareSize, imageProvider: NetworkImage( - widget.productImage.getUrl( - widget.barcode, + productImage.getUrl( + barcode, uriHelper: ProductQuery.uriProductHelper, + imageSize: imageSize, ), ), rounded: false, ); - final DateTime? uploaded = widget.productImage.uploaded; + final DateTime? uploaded = productImage.uploaded; if (uploaded == null) { return image; } @@ -85,7 +63,7 @@ class _ProductImageWidgetState extends State { button: true, child: SmoothCard( padding: EdgeInsets.zero, - color: backgroundColor ?? colors.primaryBlack, + color: colors.primaryBlack, borderRadius: ANGULAR_BORDER_RADIUS, margin: EdgeInsets.zero, child: ClipRRect( @@ -108,11 +86,7 @@ class _ProductImageWidgetState extends State { child: AutoSizeText( date, maxLines: 1, - style: TextStyle( - color: darkBackground! - ? Colors.white - : colors.primaryDark, - ), + style: const TextStyle(color: Colors.white), ), ), if (expired)