diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a6a7d4d0..59699a7dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Changed + +- mosaic layout: clamp ratio to 32/9 + ## [v1.9.6] - 2023-09-25 ### Fixed diff --git a/lib/widgets/common/grid/sections/mosaic/section_layout_builder.dart b/lib/widgets/common/grid/sections/mosaic/section_layout_builder.dart index 4be25c6e6..26701c59d 100644 --- a/lib/widgets/common/grid/sections/mosaic/section_layout_builder.dart +++ b/lib/widgets/common/grid/sections/mosaic/section_layout_builder.dart @@ -19,7 +19,9 @@ class MosaicSectionLayoutBuilder extends SectionLayoutBuilder { late double rowHeightMax; final CoverRatioResolver coverRatioResolver; - static const heightMaxFactor = 2.4; + static const double heightMaxFactor = 2.4; + static const double minThumbnailAspectRatio = 9 / 32; + static const double maxThumbnailAspectRatio = 32 / 9; MosaicSectionLayoutBuilder({ required super.sections, @@ -76,7 +78,7 @@ class MosaicSectionLayoutBuilder extends SectionLayoutBuilder { targetExtent: tileWidth, spacing: spacing, bottom: bottom, - coverRatioResolver: coverRatioResolver, + coverRatioResolver: (item) => coverRatioResolver(item).clamp(minThumbnailAspectRatio, maxThumbnailAspectRatio), ); final rowCount = rows.length; final sectionChildCount = 1 + rowCount; diff --git a/lib/widgets/common/thumbnail/decorated.dart b/lib/widgets/common/thumbnail/decorated.dart index e55912e26..6a1616d25 100644 --- a/lib/widgets/common/thumbnail/decorated.dart +++ b/lib/widgets/common/thumbnail/decorated.dart @@ -1,6 +1,7 @@ import 'package:aves/model/entry/entry.dart'; import 'package:aves/widgets/common/fx/borders.dart'; import 'package:aves/widgets/common/grid/overlay.dart'; +import 'package:aves/widgets/common/grid/sections/mosaic/section_layout_builder.dart'; import 'package:aves/widgets/common/thumbnail/image.dart'; import 'package:aves/widgets/common/thumbnail/notifications.dart'; import 'package:aves/widgets/common/thumbnail/overlay.dart'; @@ -30,8 +31,17 @@ class DecoratedThumbnail extends StatelessWidget { @override Widget build(BuildContext context) { - final thumbnailWidth = isMosaic ? tileExtent * entry.displayAspectRatio : tileExtent; - final thumbnailHeight = tileExtent; + final double thumbnailHeight = tileExtent; + final double thumbnailWidth; + if (isMosaic) { + thumbnailWidth = thumbnailHeight * + entry.displayAspectRatio.clamp( + MosaicSectionLayoutBuilder.minThumbnailAspectRatio, + MosaicSectionLayoutBuilder.maxThumbnailAspectRatio, + ); + } else { + thumbnailWidth = tileExtent; + } Widget child = ThumbnailImage( entry: entry, diff --git a/lib/widgets/common/thumbnail/image.dart b/lib/widgets/common/thumbnail/image.dart index 794979ef8..d2e06f994 100644 --- a/lib/widgets/common/thumbnail/image.dart +++ b/lib/widgets/common/thumbnail/image.dart @@ -11,6 +11,7 @@ import 'package:aves/services/common/services.dart'; import 'package:aves/widgets/common/basic/insets.dart'; import 'package:aves/widgets/common/fx/checkered_decoration.dart'; import 'package:aves/widgets/common/fx/transition_image.dart'; +import 'package:aves/widgets/common/grid/sections/mosaic/section_layout_builder.dart'; import 'package:aves/widgets/common/providers/media_query_data_provider.dart'; import 'package:aves/widgets/common/thumbnail/error.dart'; import 'package:aves_model/aves_model.dart'; @@ -197,16 +198,20 @@ class _ThumbnailImageState extends State { // use `RawImage` instead of `Image`, using `ImageInfo` to check dimensions // and have more control when chaining image providers - final thumbnailWidth = isMosaic ? extent * entry.displayAspectRatio : extent; final thumbnailHeight = extent; + final double thumbnailWidth; + if (isMosaic) { + thumbnailWidth = thumbnailHeight * + entry.displayAspectRatio.clamp( + MosaicSectionLayoutBuilder.minThumbnailAspectRatio, + MosaicSectionLayoutBuilder.maxThumbnailAspectRatio, + ); + } else { + thumbnailWidth = extent; + } final canHaveAlpha = entry.canHaveAlpha; - final fit = widget.fit ?? - (entry.isSvg - ? BoxFit.contain - : isMosaic - ? BoxFit.contain - : BoxFit.cover); + final fit = widget.fit ?? (entry.isSvg ? BoxFit.contain : BoxFit.cover); final imageInfo = _lastImageInfo; Widget image = imageInfo == null ? Container( @@ -266,7 +271,7 @@ class _ThumbnailImageState extends State { Widget child = TransitionImage( image: entry.bestCachedThumbnail, animation: animation, - thumbnailFit: isMosaic ? BoxFit.contain : BoxFit.cover, + thumbnailFit: BoxFit.cover, viewerFit: BoxFit.contain, background: backgroundColor, );