mosaic fixes
This commit is contained in:
parent
ebd6f1c84c
commit
5019cc2065
10 changed files with 66 additions and 36 deletions
|
@ -141,19 +141,22 @@ class _CollectionGridContent extends StatelessWidget {
|
||||||
spacing: tileSpacing,
|
spacing: tileSpacing,
|
||||||
horizontalPadding: horizontalPadding,
|
horizontalPadding: horizontalPadding,
|
||||||
tileExtent: thumbnailExtent,
|
tileExtent: thumbnailExtent,
|
||||||
tileBuilder: (entry) => AnimatedBuilder(
|
tileBuilder: (entry, tileSize) {
|
||||||
animation: favourites,
|
final extent = tileSize.shortestSide;
|
||||||
builder: (context, child) {
|
return AnimatedBuilder(
|
||||||
return InteractiveTile(
|
animation: favourites,
|
||||||
key: ValueKey(entry.id),
|
builder: (context, child) {
|
||||||
collection: collection,
|
return InteractiveTile(
|
||||||
entry: entry,
|
key: ValueKey(entry.id),
|
||||||
thumbnailExtent: thumbnailExtent,
|
collection: collection,
|
||||||
tileLayout: tileLayout,
|
entry: entry,
|
||||||
isScrollingNotifier: _isScrollingNotifier,
|
thumbnailExtent: extent,
|
||||||
);
|
tileLayout: tileLayout,
|
||||||
},
|
isScrollingNotifier: _isScrollingNotifier,
|
||||||
),
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
tileAnimationDelay: tileAnimationDelay,
|
tileAnimationDelay: tileAnimationDelay,
|
||||||
child: child!,
|
child: child!,
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,8 +11,9 @@ import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class TransitionImage extends StatefulWidget {
|
class TransitionImage extends StatefulWidget {
|
||||||
final ImageProvider image;
|
final ImageProvider image;
|
||||||
final double? width, height;
|
|
||||||
final ValueListenable<double> animation;
|
final ValueListenable<double> animation;
|
||||||
|
final BoxFit thumbnailFit, viewerFit;
|
||||||
|
final double? width, height;
|
||||||
final bool gaplessPlayback = false;
|
final bool gaplessPlayback = false;
|
||||||
final Color? background;
|
final Color? background;
|
||||||
|
|
||||||
|
@ -20,6 +21,8 @@ class TransitionImage extends StatefulWidget {
|
||||||
super.key,
|
super.key,
|
||||||
required this.image,
|
required this.image,
|
||||||
required this.animation,
|
required this.animation,
|
||||||
|
required this.thumbnailFit,
|
||||||
|
required this.viewerFit,
|
||||||
this.width,
|
this.width,
|
||||||
this.height,
|
this.height,
|
||||||
this.background,
|
this.background,
|
||||||
|
@ -157,6 +160,8 @@ class _TransitionImageState extends State<TransitionImage> {
|
||||||
image: _imageInfo?.image,
|
image: _imageInfo?.image,
|
||||||
scale: _imageInfo?.scale ?? 1.0,
|
scale: _imageInfo?.scale ?? 1.0,
|
||||||
t: t,
|
t: t,
|
||||||
|
thumbnailFit: widget.thumbnailFit,
|
||||||
|
viewerFit: widget.viewerFit,
|
||||||
background: widget.background,
|
background: widget.background,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -166,15 +171,17 @@ class _TransitionImageState extends State<TransitionImage> {
|
||||||
|
|
||||||
class _TransitionImagePainter extends CustomPainter {
|
class _TransitionImagePainter extends CustomPainter {
|
||||||
final ui.Image? image;
|
final ui.Image? image;
|
||||||
final double scale;
|
final double scale, t;
|
||||||
final double t;
|
|
||||||
final Color? background;
|
final Color? background;
|
||||||
|
final BoxFit thumbnailFit, viewerFit;
|
||||||
|
|
||||||
const _TransitionImagePainter({
|
const _TransitionImagePainter({
|
||||||
required this.image,
|
required this.image,
|
||||||
required this.scale,
|
required this.scale,
|
||||||
required this.t,
|
required this.t,
|
||||||
this.background,
|
required this.thumbnailFit,
|
||||||
|
required this.viewerFit,
|
||||||
|
required this.background,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -190,10 +197,10 @@ class _TransitionImagePainter extends CustomPainter {
|
||||||
final inputSize = Size(image!.width.toDouble(), image!.height.toDouble());
|
final inputSize = Size(image!.width.toDouble(), image!.height.toDouble());
|
||||||
final outputSize = rect.size;
|
final outputSize = rect.size;
|
||||||
|
|
||||||
final coverSizes = applyBoxFit(BoxFit.cover, inputSize / scale, size);
|
final thumbnailSizes = applyBoxFit(thumbnailFit, inputSize / scale, size);
|
||||||
final containSizes = applyBoxFit(BoxFit.contain, inputSize / scale, size);
|
final viewerSizes = applyBoxFit(viewerFit, inputSize / scale, size);
|
||||||
final sourceSize = Size.lerp(coverSizes.source, containSizes.source, t)! * scale;
|
final sourceSize = Size.lerp(thumbnailSizes.source, viewerSizes.source, t)! * scale;
|
||||||
final destinationSize = Size.lerp(coverSizes.destination, containSizes.destination, t)!;
|
final destinationSize = Size.lerp(thumbnailSizes.destination, viewerSizes.destination, t)!;
|
||||||
|
|
||||||
final halfWidthDelta = (outputSize.width - destinationSize.width) / 2.0;
|
final halfWidthDelta = (outputSize.width - destinationSize.width) / 2.0;
|
||||||
final halfHeightDelta = (outputSize.height - destinationSize.height) / 2.0;
|
final halfHeightDelta = (outputSize.height - destinationSize.height) / 2.0;
|
||||||
|
|
|
@ -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/behaviour/eager_scale_gesture_recognizer.dart';
|
||||||
import 'package:aves/widgets/common/grid/sections/fixed/scale_overlay.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/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/grid/theme.dart';
|
||||||
import 'package:aves/widgets/common/tile_extent_controller.dart';
|
import 'package:aves/widgets/common/tile_extent_controller.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
@ -23,7 +24,7 @@ class GridScaleGestureDetector<T> extends StatefulWidget {
|
||||||
final TileLayout tileLayout;
|
final TileLayout tileLayout;
|
||||||
final double Function(double width) heightForWidth;
|
final double Function(double width) heightForWidth;
|
||||||
final Widget Function(Offset center, Size tileSize, Widget child) gridBuilder;
|
final Widget Function(Offset center, Size tileSize, Widget child) gridBuilder;
|
||||||
final Widget Function(T item, Size tileSize) scaledItemBuilder;
|
final TileBuilder<T> scaledItemBuilder;
|
||||||
final MosaicItemBuilder mosaicItemBuilder;
|
final MosaicItemBuilder mosaicItemBuilder;
|
||||||
final Object Function(T item)? highlightItem;
|
final Object Function(T item)? highlightItem;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
|
@ -11,6 +11,7 @@ import 'package:tuple/tuple.dart';
|
||||||
class FixedExtentSectionLayoutBuilder<T> extends SectionLayoutBuilder<T> {
|
class FixedExtentSectionLayoutBuilder<T> extends SectionLayoutBuilder<T> {
|
||||||
int _currentIndex = 0;
|
int _currentIndex = 0;
|
||||||
double _currentOffset = 0;
|
double _currentOffset = 0;
|
||||||
|
List<Size> _itemSizes;
|
||||||
|
|
||||||
FixedExtentSectionLayoutBuilder({
|
FixedExtentSectionLayoutBuilder({
|
||||||
required super.sections,
|
required super.sections,
|
||||||
|
@ -26,7 +27,7 @@ class FixedExtentSectionLayoutBuilder<T> extends SectionLayoutBuilder<T> {
|
||||||
required super.tileHeight,
|
required super.tileHeight,
|
||||||
required super.tileBuilder,
|
required super.tileBuilder,
|
||||||
required super.tileAnimationDelay,
|
required super.tileAnimationDelay,
|
||||||
});
|
}) : _itemSizes = List.generate(columnCount, (index) => Size(tileWidth, tileHeight));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
SectionedListLayout<T> updateLayouts(BuildContext context) {
|
SectionedListLayout<T> updateLayouts(BuildContext context) {
|
||||||
|
@ -93,6 +94,7 @@ class FixedExtentSectionLayoutBuilder<T> extends SectionLayoutBuilder<T> {
|
||||||
),
|
),
|
||||||
sectionKey: sectionKey,
|
sectionKey: sectionKey,
|
||||||
headerExtent: headerExtent,
|
headerExtent: headerExtent,
|
||||||
|
itemSizes: _itemSizes,
|
||||||
animate: animate,
|
animate: animate,
|
||||||
buildGridRow: (children) => FixedExtentGridRow(
|
buildGridRow: (children) => FixedExtentGridRow(
|
||||||
width: tileWidth,
|
width: tileWidth,
|
||||||
|
|
|
@ -113,6 +113,7 @@ class MosaicSectionLayoutBuilder<T> extends SectionLayoutBuilder<T> {
|
||||||
itemIndexRange: () => isHeader ? const Tuple2(0, 0) : Tuple2(row.firstIndex, row.lastIndex + 1),
|
itemIndexRange: () => isHeader ? const Tuple2(0, 0) : Tuple2(row.firstIndex, row.lastIndex + 1),
|
||||||
sectionKey: sectionKey,
|
sectionKey: sectionKey,
|
||||||
headerExtent: headerExtent,
|
headerExtent: headerExtent,
|
||||||
|
itemSizes: row.itemWidths.map((v) => Size(v, row.height)).toList(),
|
||||||
animate: animate,
|
animate: animate,
|
||||||
buildGridRow: (children) {
|
buildGridRow: (children) {
|
||||||
return isHeader
|
return isHeader
|
||||||
|
|
|
@ -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/fixed/section_layout_builder.dart';
|
||||||
import 'package:aves/widgets/common/grid/sections/list_layout.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/mosaic/section_layout_builder.dart';
|
||||||
|
import 'package:aves/widgets/common/grid/sections/section_layout_builder.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
@ -14,7 +15,7 @@ abstract class SectionedListLayoutProvider<T> extends StatelessWidget {
|
||||||
final TileLayout tileLayout;
|
final TileLayout tileLayout;
|
||||||
final int columnCount;
|
final int columnCount;
|
||||||
final double spacing, horizontalPadding, tileWidth, tileHeight;
|
final double spacing, horizontalPadding, tileWidth, tileHeight;
|
||||||
final Widget Function(T item) tileBuilder;
|
final TileBuilder<T> tileBuilder;
|
||||||
final Duration tileAnimationDelay;
|
final Duration tileAnimationDelay;
|
||||||
final CoverRatioResolver<T> coverRatioResolver;
|
final CoverRatioResolver<T> coverRatioResolver;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
|
@ -8,6 +8,8 @@ import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
|
typedef TileBuilder<T> = Widget Function(T item, Size tileSize);
|
||||||
|
|
||||||
abstract class SectionLayoutBuilder<T> {
|
abstract class SectionLayoutBuilder<T> {
|
||||||
final Map<SectionKey, List<T>> sections;
|
final Map<SectionKey, List<T>> sections;
|
||||||
final bool showHeaders;
|
final bool showHeaders;
|
||||||
|
@ -17,7 +19,7 @@ abstract class SectionLayoutBuilder<T> {
|
||||||
final TileLayout tileLayout;
|
final TileLayout tileLayout;
|
||||||
final int columnCount;
|
final int columnCount;
|
||||||
final double spacing, horizontalPadding, tileWidth, tileHeight, bottom;
|
final double spacing, horizontalPadding, tileWidth, tileHeight, bottom;
|
||||||
final Widget Function(T item) tileBuilder;
|
final TileBuilder<T> tileBuilder;
|
||||||
final Duration tileAnimationDelay;
|
final Duration tileAnimationDelay;
|
||||||
final bool animate;
|
final bool animate;
|
||||||
|
|
||||||
|
@ -55,6 +57,7 @@ abstract class SectionLayoutBuilder<T> {
|
||||||
required Tuple2<int, int> Function() itemIndexRange,
|
required Tuple2<int, int> Function() itemIndexRange,
|
||||||
required SectionKey sectionKey,
|
required SectionKey sectionKey,
|
||||||
required double headerExtent,
|
required double headerExtent,
|
||||||
|
required List<Size> itemSizes,
|
||||||
required bool animate,
|
required bool animate,
|
||||||
required Widget Function(List<Widget> children) buildGridRow,
|
required Widget Function(List<Widget> children) buildGridRow,
|
||||||
}) {
|
}) {
|
||||||
|
@ -67,13 +70,17 @@ abstract class SectionLayoutBuilder<T> {
|
||||||
final itemMinMax = itemIndexRange();
|
final itemMinMax = itemIndexRange();
|
||||||
final minItemIndex = itemMinMax.item1.clamp(0, sectionItemCount);
|
final minItemIndex = itemMinMax.item1.clamp(0, sectionItemCount);
|
||||||
final maxItemIndex = itemMinMax.item2.clamp(0, sectionItemCount);
|
final maxItemIndex = itemMinMax.item2.clamp(0, sectionItemCount);
|
||||||
|
final childrenCount = maxItemIndex - minItemIndex;
|
||||||
final children = <Widget>[];
|
final children = <Widget>[];
|
||||||
for (var i = minItemIndex; i < maxItemIndex; i++) {
|
for (var i = 0; i < childrenCount; i++) {
|
||||||
final itemGridIndex = sectionGridIndex + i - minItemIndex;
|
|
||||||
final item = RepaintBoundary(
|
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(
|
return Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: horizontalPadding),
|
padding: EdgeInsets.symmetric(horizontal: horizontalPadding),
|
||||||
|
|
|
@ -281,10 +281,15 @@ class OverlayIcon extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
iconChild,
|
iconChild,
|
||||||
const SizedBox(width: 2),
|
const SizedBox(width: 2),
|
||||||
Text(
|
Flexible(
|
||||||
text!,
|
child: Text(
|
||||||
// consistent with the color used for the icon next to it
|
text!,
|
||||||
style: TextStyle(color: IconTheme.of(context).color),
|
// 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,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -272,6 +272,8 @@ class _ThumbnailImageState extends State<ThumbnailImage> {
|
||||||
return TransitionImage(
|
return TransitionImage(
|
||||||
image: entry.bestCachedThumbnail,
|
image: entry.bestCachedThumbnail,
|
||||||
animation: animation,
|
animation: animation,
|
||||||
|
thumbnailFit: isMosaic ? BoxFit.contain : BoxFit.cover,
|
||||||
|
viewerFit: BoxFit.contain,
|
||||||
background: backgroundColor,
|
background: backgroundColor,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -306,11 +306,12 @@ class _FilterGridContent<T extends CollectionFilter> extends StatelessWidget {
|
||||||
horizontalPadding: horizontalPadding,
|
horizontalPadding: horizontalPadding,
|
||||||
tileWidth: thumbnailExtent,
|
tileWidth: thumbnailExtent,
|
||||||
tileHeight: tileHeight,
|
tileHeight: tileHeight,
|
||||||
tileBuilder: (gridItem) {
|
tileBuilder: (gridItem, tileSize) {
|
||||||
|
final extent = tileSize.shortestSide;
|
||||||
return InteractiveFilterTile(
|
return InteractiveFilterTile(
|
||||||
gridItem: gridItem,
|
gridItem: gridItem,
|
||||||
chipExtent: thumbnailExtent,
|
chipExtent: extent,
|
||||||
thumbnailExtent: thumbnailExtent,
|
thumbnailExtent: extent,
|
||||||
tileLayout: tileLayout,
|
tileLayout: tileLayout,
|
||||||
banner: _getFilterBanner(context, gridItem.filter),
|
banner: _getFilterBanner(context, gridItem.filter),
|
||||||
heroType: heroType,
|
heroType: heroType,
|
||||||
|
|
Loading…
Reference in a new issue