From 5019cc206506be26db0ed6c3df6252f58b78d8a1 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Sat, 1 Oct 2022 20:14:40 +0200 Subject: [PATCH] mosaic fixes --- lib/widgets/collection/collection_grid.dart | 29 ++++++++++--------- lib/widgets/common/fx/transition_image.dart | 23 ++++++++++----- lib/widgets/common/grid/scaling.dart | 3 +- .../fixed/section_layout_builder.dart | 4 ++- .../mosaic/section_layout_builder.dart | 1 + .../common/grid/sections/provider.dart | 3 +- .../grid/sections/section_layout_builder.dart | 17 +++++++---- lib/widgets/common/identity/aves_icons.dart | 13 ++++++--- lib/widgets/common/thumbnail/image.dart | 2 ++ .../filter_grids/common/filter_grid_page.dart | 7 +++-- 10 files changed, 66 insertions(+), 36 deletions(-) diff --git a/lib/widgets/collection/collection_grid.dart b/lib/widgets/collection/collection_grid.dart index 8a8dc9a46..d72303eb4 100644 --- a/lib/widgets/collection/collection_grid.dart +++ b/lib/widgets/collection/collection_grid.dart @@ -141,19 +141,22 @@ class _CollectionGridContent extends StatelessWidget { spacing: tileSpacing, horizontalPadding: horizontalPadding, tileExtent: thumbnailExtent, - tileBuilder: (entry) => AnimatedBuilder( - animation: favourites, - builder: (context, child) { - return InteractiveTile( - key: ValueKey(entry.id), - collection: collection, - entry: entry, - thumbnailExtent: thumbnailExtent, - tileLayout: tileLayout, - isScrollingNotifier: _isScrollingNotifier, - ); - }, - ), + tileBuilder: (entry, tileSize) { + final extent = tileSize.shortestSide; + return AnimatedBuilder( + animation: favourites, + builder: (context, child) { + return InteractiveTile( + key: ValueKey(entry.id), + collection: collection, + entry: entry, + thumbnailExtent: extent, + tileLayout: tileLayout, + isScrollingNotifier: _isScrollingNotifier, + ); + }, + ); + }, tileAnimationDelay: tileAnimationDelay, child: child!, ); diff --git a/lib/widgets/common/fx/transition_image.dart b/lib/widgets/common/fx/transition_image.dart index a3036e7dc..4ee1b8390 100644 --- a/lib/widgets/common/fx/transition_image.dart +++ b/lib/widgets/common/fx/transition_image.dart @@ -11,8 +11,9 @@ import 'package:flutter/material.dart'; class TransitionImage extends StatefulWidget { final ImageProvider image; - final double? width, height; final ValueListenable animation; + final BoxFit thumbnailFit, viewerFit; + final double? width, height; final bool gaplessPlayback = false; final Color? background; @@ -20,6 +21,8 @@ class TransitionImage extends StatefulWidget { super.key, required this.image, required this.animation, + required this.thumbnailFit, + required this.viewerFit, this.width, this.height, this.background, @@ -157,6 +160,8 @@ class _TransitionImageState extends State { image: _imageInfo?.image, scale: _imageInfo?.scale ?? 1.0, t: t, + thumbnailFit: widget.thumbnailFit, + viewerFit: widget.viewerFit, background: widget.background, ), ), @@ -166,15 +171,17 @@ class _TransitionImageState extends State { class _TransitionImagePainter extends CustomPainter { final ui.Image? image; - final double scale; - final double t; + final double scale, t; final Color? background; + final BoxFit thumbnailFit, viewerFit; const _TransitionImagePainter({ required this.image, required this.scale, required this.t, - this.background, + required this.thumbnailFit, + required this.viewerFit, + required this.background, }); @override @@ -190,10 +197,10 @@ class _TransitionImagePainter extends CustomPainter { final inputSize = Size(image!.width.toDouble(), image!.height.toDouble()); final outputSize = rect.size; - final coverSizes = applyBoxFit(BoxFit.cover, inputSize / scale, size); - final containSizes = applyBoxFit(BoxFit.contain, inputSize / scale, size); - final sourceSize = Size.lerp(coverSizes.source, containSizes.source, t)! * scale; - final destinationSize = Size.lerp(coverSizes.destination, containSizes.destination, t)!; + final thumbnailSizes = applyBoxFit(thumbnailFit, inputSize / scale, size); + final viewerSizes = applyBoxFit(viewerFit, inputSize / scale, size); + final sourceSize = Size.lerp(thumbnailSizes.source, viewerSizes.source, t)! * scale; + final destinationSize = Size.lerp(thumbnailSizes.destination, viewerSizes.destination, t)!; final halfWidthDelta = (outputSize.width - destinationSize.width) / 2.0; final halfHeightDelta = (outputSize.height - destinationSize.height) / 2.0; diff --git a/lib/widgets/common/grid/scaling.dart b/lib/widgets/common/grid/scaling.dart index f0e783126..cb3bb8cbc 100644 --- a/lib/widgets/common/grid/scaling.dart +++ b/lib/widgets/common/grid/scaling.dart @@ -3,6 +3,7 @@ import 'package:aves/model/source/enums/enums.dart'; import 'package:aves/widgets/common/behaviour/eager_scale_gesture_recognizer.dart'; import 'package:aves/widgets/common/grid/sections/fixed/scale_overlay.dart'; import 'package:aves/widgets/common/grid/sections/mosaic/scale_overlay.dart'; +import 'package:aves/widgets/common/grid/sections/section_layout_builder.dart'; import 'package:aves/widgets/common/grid/theme.dart'; import 'package:aves/widgets/common/tile_extent_controller.dart'; import 'package:collection/collection.dart'; @@ -23,7 +24,7 @@ class GridScaleGestureDetector extends StatefulWidget { final TileLayout tileLayout; final double Function(double width) heightForWidth; final Widget Function(Offset center, Size tileSize, Widget child) gridBuilder; - final Widget Function(T item, Size tileSize) scaledItemBuilder; + final TileBuilder scaledItemBuilder; final MosaicItemBuilder mosaicItemBuilder; final Object Function(T item)? highlightItem; final Widget child; diff --git a/lib/widgets/common/grid/sections/fixed/section_layout_builder.dart b/lib/widgets/common/grid/sections/fixed/section_layout_builder.dart index 276da0d80..316291736 100644 --- a/lib/widgets/common/grid/sections/fixed/section_layout_builder.dart +++ b/lib/widgets/common/grid/sections/fixed/section_layout_builder.dart @@ -11,6 +11,7 @@ import 'package:tuple/tuple.dart'; class FixedExtentSectionLayoutBuilder extends SectionLayoutBuilder { int _currentIndex = 0; double _currentOffset = 0; + List _itemSizes; FixedExtentSectionLayoutBuilder({ required super.sections, @@ -26,7 +27,7 @@ class FixedExtentSectionLayoutBuilder extends SectionLayoutBuilder { required super.tileHeight, required super.tileBuilder, required super.tileAnimationDelay, - }); + }) : _itemSizes = List.generate(columnCount, (index) => Size(tileWidth, tileHeight)); @override SectionedListLayout updateLayouts(BuildContext context) { @@ -93,6 +94,7 @@ class FixedExtentSectionLayoutBuilder extends SectionLayoutBuilder { ), sectionKey: sectionKey, headerExtent: headerExtent, + itemSizes: _itemSizes, animate: animate, buildGridRow: (children) => FixedExtentGridRow( width: tileWidth, 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 4490544ee..14a7b6bcb 100644 --- a/lib/widgets/common/grid/sections/mosaic/section_layout_builder.dart +++ b/lib/widgets/common/grid/sections/mosaic/section_layout_builder.dart @@ -113,6 +113,7 @@ class MosaicSectionLayoutBuilder extends SectionLayoutBuilder { itemIndexRange: () => isHeader ? const Tuple2(0, 0) : Tuple2(row.firstIndex, row.lastIndex + 1), sectionKey: sectionKey, headerExtent: headerExtent, + itemSizes: row.itemWidths.map((v) => Size(v, row.height)).toList(), animate: animate, buildGridRow: (children) { return isHeader diff --git a/lib/widgets/common/grid/sections/provider.dart b/lib/widgets/common/grid/sections/provider.dart index 47fba31c0..1cc6cf077 100644 --- a/lib/widgets/common/grid/sections/provider.dart +++ b/lib/widgets/common/grid/sections/provider.dart @@ -3,6 +3,7 @@ import 'package:aves/model/source/section_keys.dart'; import 'package:aves/widgets/common/grid/sections/fixed/section_layout_builder.dart'; import 'package:aves/widgets/common/grid/sections/list_layout.dart'; import 'package:aves/widgets/common/grid/sections/mosaic/section_layout_builder.dart'; +import 'package:aves/widgets/common/grid/sections/section_layout_builder.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:provider/provider.dart'; @@ -14,7 +15,7 @@ abstract class SectionedListLayoutProvider extends StatelessWidget { final TileLayout tileLayout; final int columnCount; final double spacing, horizontalPadding, tileWidth, tileHeight; - final Widget Function(T item) tileBuilder; + final TileBuilder tileBuilder; final Duration tileAnimationDelay; final CoverRatioResolver coverRatioResolver; final Widget child; diff --git a/lib/widgets/common/grid/sections/section_layout_builder.dart b/lib/widgets/common/grid/sections/section_layout_builder.dart index 2b86b3ff0..6b7570d8f 100644 --- a/lib/widgets/common/grid/sections/section_layout_builder.dart +++ b/lib/widgets/common/grid/sections/section_layout_builder.dart @@ -8,6 +8,8 @@ import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:provider/provider.dart'; import 'package:tuple/tuple.dart'; +typedef TileBuilder = Widget Function(T item, Size tileSize); + abstract class SectionLayoutBuilder { final Map> sections; final bool showHeaders; @@ -17,7 +19,7 @@ abstract class SectionLayoutBuilder { final TileLayout tileLayout; final int columnCount; final double spacing, horizontalPadding, tileWidth, tileHeight, bottom; - final Widget Function(T item) tileBuilder; + final TileBuilder tileBuilder; final Duration tileAnimationDelay; final bool animate; @@ -55,6 +57,7 @@ abstract class SectionLayoutBuilder { required Tuple2 Function() itemIndexRange, required SectionKey sectionKey, required double headerExtent, + required List itemSizes, required bool animate, required Widget Function(List children) buildGridRow, }) { @@ -67,13 +70,17 @@ abstract class SectionLayoutBuilder { final itemMinMax = itemIndexRange(); final minItemIndex = itemMinMax.item1.clamp(0, sectionItemCount); final maxItemIndex = itemMinMax.item2.clamp(0, sectionItemCount); + final childrenCount = maxItemIndex - minItemIndex; final children = []; - for (var i = minItemIndex; i < maxItemIndex; i++) { - final itemGridIndex = sectionGridIndex + i - minItemIndex; + for (var i = 0; i < childrenCount; i++) { final item = RepaintBoundary( - child: tileBuilder(section[i]), + child: tileBuilder(section[minItemIndex + i], itemSizes[i]), ); - children.add(animate ? _buildAnimation(context, itemGridIndex, item) : item); + if (animate) { + children.add(_buildAnimation(context, sectionGridIndex + i, item)); + } else { + children.add(item); + } } return Padding( padding: EdgeInsets.symmetric(horizontal: horizontalPadding), diff --git a/lib/widgets/common/identity/aves_icons.dart b/lib/widgets/common/identity/aves_icons.dart index 700f16469..56f89de0f 100644 --- a/lib/widgets/common/identity/aves_icons.dart +++ b/lib/widgets/common/identity/aves_icons.dart @@ -281,10 +281,15 @@ class OverlayIcon extends StatelessWidget { children: [ iconChild, const SizedBox(width: 2), - Text( - text!, - // consistent with the color used for the icon next to it - style: TextStyle(color: IconTheme.of(context).color), + Flexible( + child: Text( + text!, + // consistent with the color used for the icon next to it + style: TextStyle(color: IconTheme.of(context).color), + softWrap: false, + overflow: TextOverflow.fade, + maxLines: 1, + ), ), ], ), diff --git a/lib/widgets/common/thumbnail/image.dart b/lib/widgets/common/thumbnail/image.dart index abcc6b4c3..7d8ad61a3 100644 --- a/lib/widgets/common/thumbnail/image.dart +++ b/lib/widgets/common/thumbnail/image.dart @@ -272,6 +272,8 @@ class _ThumbnailImageState extends State { return TransitionImage( image: entry.bestCachedThumbnail, animation: animation, + thumbnailFit: isMosaic ? BoxFit.contain : BoxFit.cover, + viewerFit: BoxFit.contain, background: backgroundColor, ); }, diff --git a/lib/widgets/filter_grids/common/filter_grid_page.dart b/lib/widgets/filter_grids/common/filter_grid_page.dart index 062939671..92e3183bb 100644 --- a/lib/widgets/filter_grids/common/filter_grid_page.dart +++ b/lib/widgets/filter_grids/common/filter_grid_page.dart @@ -306,11 +306,12 @@ class _FilterGridContent extends StatelessWidget { horizontalPadding: horizontalPadding, tileWidth: thumbnailExtent, tileHeight: tileHeight, - tileBuilder: (gridItem) { + tileBuilder: (gridItem, tileSize) { + final extent = tileSize.shortestSide; return InteractiveFilterTile( gridItem: gridItem, - chipExtent: thumbnailExtent, - thumbnailExtent: thumbnailExtent, + chipExtent: extent, + thumbnailExtent: extent, tileLayout: tileLayout, banner: _getFilterBanner(context, gridItem.filter), heroType: heroType,