grid padding
This commit is contained in:
parent
3a81d6c655
commit
5a5e8d6728
7 changed files with 69 additions and 35 deletions
|
@ -70,6 +70,7 @@ class _CollectionGridState extends State<CollectionGrid> {
|
|||
extentMin: CollectionGrid.extentMin,
|
||||
extentMax: CollectionGrid.extentMax,
|
||||
spacing: CollectionGrid.spacing,
|
||||
horizontalPadding: 2,
|
||||
);
|
||||
return TileExtentControllerProvider(
|
||||
controller: _tileExtentController!,
|
||||
|
@ -90,12 +91,13 @@ class _CollectionGridContent extends StatelessWidget {
|
|||
final sectionedListLayoutProvider = ValueListenableBuilder<double>(
|
||||
valueListenable: context.select<TileExtentController, ValueNotifier<double>>((controller) => controller.extentNotifier),
|
||||
builder: (context, thumbnailExtent, child) {
|
||||
return Selector<TileExtentController, Tuple3<double, int, double>>(
|
||||
selector: (context, c) => Tuple3(c.viewportSize.width, c.columnCount, c.spacing),
|
||||
return Selector<TileExtentController, Tuple4<double, int, double, double>>(
|
||||
selector: (context, c) => Tuple4(c.viewportSize.width, c.columnCount, c.spacing, c.horizontalPadding),
|
||||
builder: (context, c, child) {
|
||||
final scrollableWidth = c.item1;
|
||||
final columnCount = c.item2;
|
||||
final tileSpacing = c.item3;
|
||||
final horizontalPadding = c.item4;
|
||||
return GridTheme(
|
||||
extent: thumbnailExtent,
|
||||
child: EntryListDetailsTheme(
|
||||
|
@ -117,6 +119,7 @@ class _CollectionGridContent extends StatelessWidget {
|
|||
tileLayout: tileLayout,
|
||||
columnCount: columnCount,
|
||||
spacing: tileSpacing,
|
||||
horizontalPadding: horizontalPadding,
|
||||
tileExtent: thumbnailExtent,
|
||||
tileBuilder: (entry) => AnimatedBuilder(
|
||||
animation: favourites,
|
||||
|
@ -242,7 +245,9 @@ class _CollectionScaler extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final tileSpacing = context.select<TileExtentController, double>((controller) => controller.spacing);
|
||||
final metrics = context.select<TileExtentController, Tuple2<double, double>>((v) => Tuple2(v.spacing, v.horizontalPadding));
|
||||
final tileSpacing = metrics.item1;
|
||||
final horizontalPadding = metrics.item2;
|
||||
return GridScaleGestureDetector<AvesEntry>(
|
||||
scrollableKey: scrollableKey,
|
||||
tileLayout: tileLayout,
|
||||
|
@ -253,6 +258,7 @@ class _CollectionScaler extends StatelessWidget {
|
|||
tileCenter: center,
|
||||
tileSize: tileSize,
|
||||
spacing: tileSpacing,
|
||||
horizontalPadding: horizontalPadding,
|
||||
borderWidth: DecoratedThumbnail.borderWidth,
|
||||
borderRadius: Radius.zero,
|
||||
color: DecoratedThumbnail.borderColor,
|
||||
|
|
|
@ -16,6 +16,7 @@ class SectionedEntryListLayoutProvider extends SectionedListLayoutProvider<AvesE
|
|||
required TileLayout tileLayout,
|
||||
required int columnCount,
|
||||
required double spacing,
|
||||
required double horizontalPadding,
|
||||
required double tileExtent,
|
||||
required Widget Function(AvesEntry entry) tileBuilder,
|
||||
required Duration tileAnimationDelay,
|
||||
|
@ -26,6 +27,7 @@ class SectionedEntryListLayoutProvider extends SectionedListLayoutProvider<AvesE
|
|||
tileLayout: tileLayout,
|
||||
columnCount: columnCount,
|
||||
spacing: spacing,
|
||||
horizontalPadding: horizontalPadding,
|
||||
tileWidth: tileExtent,
|
||||
tileHeight: tileExtent,
|
||||
tileBuilder: tileBuilder,
|
||||
|
|
|
@ -108,19 +108,26 @@ class _GridScaleGestureDetectorState<T> extends State<GridScaleGestureDetector<T
|
|||
_startSize = renderMetaData.size;
|
||||
_scaledSizeNotifier = ValueNotifier(_startSize!);
|
||||
|
||||
// not the same as `MediaQuery.size.width`, because of screen insets/padding
|
||||
final gridWidth = scrollableBox.size.width;
|
||||
// not the same as `MediaQuery` metrics, because of screen insets/padding
|
||||
final scrollViewWidth = scrollableBox.size.width;
|
||||
final scrollViewXMin = scrollableBox.localToGlobal(Offset.zero).dx;
|
||||
final scrollViewXMax = scrollableBox.localToGlobal(Offset(scrollViewWidth, 0)).dx;
|
||||
|
||||
final horizontalPadding = tileExtentController.horizontalPadding;
|
||||
final xMin = scrollViewXMin + horizontalPadding;
|
||||
final xMax = scrollViewXMax - horizontalPadding;
|
||||
|
||||
_extentMin = tileExtentController.effectiveExtentMin;
|
||||
_extentMax = tileExtentController.effectiveExtentMax;
|
||||
|
||||
final halfSize = _startSize! / 2;
|
||||
final tileCenter = renderMetaData.localToGlobal(Offset(halfSize.width, halfSize.height));
|
||||
final tileLayout = widget.tileLayout;
|
||||
_overlayEntry = OverlayEntry(
|
||||
builder: (context) => _ScaleOverlay(
|
||||
builder: (scaledTileSize) {
|
||||
late final double themeExtent;
|
||||
switch (widget.tileLayout) {
|
||||
switch (tileLayout) {
|
||||
case TileLayout.grid:
|
||||
themeExtent = scaledTileSize.width;
|
||||
break;
|
||||
|
@ -136,9 +143,10 @@ class _GridScaleGestureDetectorState<T> extends State<GridScaleGestureDetector<T
|
|||
),
|
||||
);
|
||||
},
|
||||
tileLayout: widget.tileLayout,
|
||||
tileLayout: tileLayout,
|
||||
center: tileCenter,
|
||||
viewportWidth: gridWidth,
|
||||
xMin: xMin,
|
||||
xMax: xMax,
|
||||
gridBuilder: widget.gridBuilder,
|
||||
scaledSizeNotifier: _scaledSizeNotifier!,
|
||||
),
|
||||
|
@ -220,7 +228,7 @@ class _ScaleOverlay extends StatefulWidget {
|
|||
final Widget Function(Size scaledTileSize) builder;
|
||||
final TileLayout tileLayout;
|
||||
final Offset center;
|
||||
final double viewportWidth;
|
||||
final double xMin, xMax;
|
||||
final ValueNotifier<Size> scaledSizeNotifier;
|
||||
final Widget Function(Offset center, Size tileSize, Widget child) gridBuilder;
|
||||
|
||||
|
@ -229,7 +237,8 @@ class _ScaleOverlay extends StatefulWidget {
|
|||
required this.builder,
|
||||
required this.tileLayout,
|
||||
required this.center,
|
||||
required this.viewportWidth,
|
||||
required this.xMin,
|
||||
required this.xMax,
|
||||
required this.scaledSizeNotifier,
|
||||
required this.gridBuilder,
|
||||
}) : super(key: key);
|
||||
|
@ -243,7 +252,9 @@ class _ScaleOverlayState extends State<_ScaleOverlay> {
|
|||
|
||||
Offset get center => widget.center;
|
||||
|
||||
double get gridWidth => widget.viewportWidth;
|
||||
double get xMin => widget.xMin;
|
||||
|
||||
double get xMax => widget.xMax;
|
||||
|
||||
// `Color(0x00FFFFFF)` is different from `Color(0x00000000)` (or `Colors.transparent`)
|
||||
// when used in gradients or lerping to it
|
||||
|
@ -269,8 +280,6 @@ class _ScaleOverlayState extends State<_ScaleOverlay> {
|
|||
final width = scaledSize.width;
|
||||
final height = scaledSize.height;
|
||||
// keep scaled thumbnail within the screen
|
||||
final xMin = context.select<MediaQueryData, double>((mq) => mq.padding.left);
|
||||
final xMax = xMin + gridWidth;
|
||||
var dx = .0;
|
||||
if (center.dx - width / 2 < xMin) {
|
||||
dx = xMin - (center.dx - width / 2);
|
||||
|
@ -309,7 +318,7 @@ class _ScaleOverlayState extends State<_ScaleOverlay> {
|
|||
gradientCenter = center;
|
||||
break;
|
||||
case TileLayout.list:
|
||||
gradientCenter = Offset(context.isRtl ? gridWidth : 0, center.dy);
|
||||
gradientCenter = Offset(context.isRtl ? xMax : xMin, center.dy);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -351,7 +360,7 @@ class GridPainter extends CustomPainter {
|
|||
final TileLayout tileLayout;
|
||||
final Offset tileCenter;
|
||||
final Size tileSize;
|
||||
final double spacing, borderWidth;
|
||||
final double spacing, horizontalPadding, borderWidth;
|
||||
final Radius borderRadius;
|
||||
final Color color;
|
||||
final TextDirection textDirection;
|
||||
|
@ -361,6 +370,7 @@ class GridPainter extends CustomPainter {
|
|||
required this.tileCenter,
|
||||
required this.tileSize,
|
||||
required this.spacing,
|
||||
required this.horizontalPadding,
|
||||
required this.borderWidth,
|
||||
required this.borderRadius,
|
||||
required this.color,
|
||||
|
@ -394,7 +404,7 @@ class GridPainter extends CustomPainter {
|
|||
case TileLayout.list:
|
||||
chipSize = Size.square(tileSize.shortestSide);
|
||||
final chipCenterToEdge = chipSize.width / 2;
|
||||
chipCenter = Offset(textDirection == TextDirection.rtl ? size.width - chipCenterToEdge : chipCenterToEdge, tileCenter.dy);
|
||||
chipCenter = Offset(textDirection == TextDirection.rtl ? size.width - (chipCenterToEdge + horizontalPadding) : chipCenterToEdge + horizontalPadding, tileCenter.dy);
|
||||
deltaColumn = 0;
|
||||
strokeShader = ui.Gradient.linear(
|
||||
tileCenter - Offset(0, chipSize.shortestSide * 3),
|
||||
|
|
|
@ -15,7 +15,7 @@ abstract class SectionedListLayoutProvider<T> extends StatelessWidget {
|
|||
final double scrollableWidth;
|
||||
final TileLayout tileLayout;
|
||||
final int columnCount;
|
||||
final double spacing, tileWidth, tileHeight;
|
||||
final double spacing, horizontalPadding, tileWidth, tileHeight;
|
||||
final Widget Function(T item) tileBuilder;
|
||||
final Duration tileAnimationDelay;
|
||||
final Widget child;
|
||||
|
@ -26,6 +26,7 @@ abstract class SectionedListLayoutProvider<T> extends StatelessWidget {
|
|||
required this.tileLayout,
|
||||
required int columnCount,
|
||||
required this.spacing,
|
||||
required this.horizontalPadding,
|
||||
required double tileWidth,
|
||||
required this.tileHeight,
|
||||
required this.tileBuilder,
|
||||
|
@ -33,7 +34,7 @@ abstract class SectionedListLayoutProvider<T> extends StatelessWidget {
|
|||
required this.child,
|
||||
}) : assert(scrollableWidth != 0),
|
||||
columnCount = tileLayout == TileLayout.list ? 1 : columnCount,
|
||||
tileWidth = tileLayout == TileLayout.list ? scrollableWidth : tileWidth,
|
||||
tileWidth = tileLayout == TileLayout.list ? scrollableWidth - (horizontalPadding * 2) : tileWidth,
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
|
@ -98,6 +99,7 @@ abstract class SectionedListLayoutProvider<T> extends StatelessWidget {
|
|||
tileWidth: tileWidth,
|
||||
tileHeight: tileHeight,
|
||||
spacing: spacing,
|
||||
horizontalPadding: horizontalPadding,
|
||||
sectionLayouts: sectionLayouts,
|
||||
);
|
||||
}
|
||||
|
@ -129,12 +131,15 @@ abstract class SectionedListLayoutProvider<T> extends StatelessWidget {
|
|||
);
|
||||
children.add(animate ? _buildAnimation(context, itemGridIndex, item) : item);
|
||||
}
|
||||
return _GridRow(
|
||||
width: tileWidth,
|
||||
height: tileHeight,
|
||||
spacing: spacing,
|
||||
textDirection: Directionality.of(context),
|
||||
children: children,
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: horizontalPadding),
|
||||
child: _GridRow(
|
||||
width: tileWidth,
|
||||
height: tileHeight,
|
||||
spacing: spacing,
|
||||
textDirection: Directionality.of(context),
|
||||
children: children,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -168,6 +173,7 @@ abstract class SectionedListLayoutProvider<T> extends StatelessWidget {
|
|||
properties.add(DoubleProperty('scrollableWidth', scrollableWidth));
|
||||
properties.add(IntProperty('columnCount', columnCount));
|
||||
properties.add(DoubleProperty('spacing', spacing));
|
||||
properties.add(DoubleProperty('horizontalPadding', horizontalPadding));
|
||||
properties.add(DoubleProperty('tileWidth', tileWidth));
|
||||
properties.add(DoubleProperty('tileHeight', tileHeight));
|
||||
properties.add(DiagnosticsProperty<bool>('showHeaders', showHeaders));
|
||||
|
@ -178,7 +184,7 @@ class SectionedListLayout<T> {
|
|||
final Map<SectionKey, List<T>> sections;
|
||||
final bool showHeaders;
|
||||
final int columnCount;
|
||||
final double tileWidth, tileHeight, spacing;
|
||||
final double tileWidth, tileHeight, spacing, horizontalPadding;
|
||||
final List<SectionLayout> sectionLayouts;
|
||||
|
||||
const SectionedListLayout({
|
||||
|
@ -188,6 +194,7 @@ class SectionedListLayout<T> {
|
|||
required this.tileWidth,
|
||||
required this.tileHeight,
|
||||
required this.spacing,
|
||||
required this.horizontalPadding,
|
||||
required this.sectionLayouts,
|
||||
});
|
||||
|
||||
|
@ -205,7 +212,7 @@ class SectionedListLayout<T> {
|
|||
final row = (sectionItemIndex / columnCount).floor();
|
||||
final listIndex = sectionLayout.firstIndex + 1 + row;
|
||||
|
||||
final left = tileWidth * column + spacing * (column - 1);
|
||||
final left = horizontalPadding + tileWidth * column + spacing * (column - 1);
|
||||
final top = sectionLayout.indexToLayoutOffset(listIndex);
|
||||
return Rect.fromLTWH(left, top, tileWidth, tileHeight);
|
||||
}
|
||||
|
@ -225,7 +232,7 @@ class SectionedListLayout<T> {
|
|||
if (dy < 0) return null;
|
||||
|
||||
final row = dy ~/ (tileHeight + spacing);
|
||||
final column = position.dx ~/ (tileWidth + spacing);
|
||||
final column = max(0, position.dx - horizontalPadding) ~/ (tileWidth + spacing);
|
||||
final index = row * columnCount + column;
|
||||
if (index >= section.length) return null;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import 'package:flutter/widgets.dart';
|
|||
class TileExtentController {
|
||||
final String settingsRouteKey;
|
||||
final int columnCountMin, columnCountDefault;
|
||||
final double spacing, extentMin, extentMax;
|
||||
final double extentMin, extentMax, spacing, horizontalPadding;
|
||||
final ValueNotifier<double> extentNotifier = ValueNotifier(0);
|
||||
|
||||
late double userPreferredExtent;
|
||||
|
@ -22,6 +22,7 @@ class TileExtentController {
|
|||
required this.extentMin,
|
||||
required this.extentMax,
|
||||
required this.spacing,
|
||||
required this.horizontalPadding,
|
||||
}) {
|
||||
userPreferredExtent = settings.getTileExtent(settingsRouteKey);
|
||||
settings.addListener(_onSettingsChanged);
|
||||
|
@ -68,11 +69,11 @@ class TileExtentController {
|
|||
return newExtent;
|
||||
}
|
||||
|
||||
double _extentMax() => min(extentMax, (viewportSize.shortestSide - spacing * (columnCountMin - 1)) / columnCountMin);
|
||||
double _extentMax() => min(extentMax, (viewportSize.shortestSide - (horizontalPadding * 2) - spacing * (columnCountMin - 1)) / columnCountMin);
|
||||
|
||||
double _columnCountForExtent(double extent) => (viewportSize.width + spacing) / (extent + spacing);
|
||||
double _columnCountForExtent(double extent) => (viewportSize.width - (horizontalPadding * 2) + spacing) / (extent + spacing);
|
||||
|
||||
double _extentForColumnCount(int columnCount) => (viewportSize.width - spacing * (columnCount - 1)) / columnCount;
|
||||
double _extentForColumnCount(int columnCount) => (viewportSize.width - (horizontalPadding * 2) - spacing * (columnCount - 1)) / columnCount;
|
||||
|
||||
int _effectiveColumnCountMin() => _columnCountForExtent(_extentMax()).ceil();
|
||||
|
||||
|
@ -94,7 +95,7 @@ class TileExtentController {
|
|||
|
||||
Duration getTileAnimationDelay(Duration pageTarget) {
|
||||
final extent = extentNotifier.value;
|
||||
final columnCount = ((viewportSize.width + spacing) / (extent + spacing)).round();
|
||||
final columnCount = ((viewportSize.width - (horizontalPadding * 2) + spacing) / (extent + spacing)).round();
|
||||
final rowCount = (viewportSize.height + spacing) ~/ (extent + spacing);
|
||||
return pageTarget ~/ (columnCount + rowCount) * timeDilation;
|
||||
}
|
||||
|
|
|
@ -164,6 +164,7 @@ class _FilterGridState<T extends CollectionFilter> extends State<FilterGrid<T>>
|
|||
extentMin: 60,
|
||||
extentMax: 300,
|
||||
spacing: 8,
|
||||
horizontalPadding: 2,
|
||||
);
|
||||
return TileExtentControllerProvider(
|
||||
controller: _tileExtentController!,
|
||||
|
@ -237,12 +238,13 @@ class _FilterGridContent<T extends CollectionFilter> extends StatelessWidget {
|
|||
final sectionedListLayoutProvider = ValueListenableBuilder<double>(
|
||||
valueListenable: context.select<TileExtentController, ValueNotifier<double>>((controller) => controller.extentNotifier),
|
||||
builder: (context, thumbnailExtent, child) {
|
||||
return Selector<TileExtentController, Tuple3<double, int, double>>(
|
||||
selector: (context, c) => Tuple3(c.viewportSize.width, c.columnCount, c.spacing),
|
||||
return Selector<TileExtentController, Tuple4<double, int, double, double>>(
|
||||
selector: (context, c) => Tuple4(c.viewportSize.width, c.columnCount, c.spacing, c.horizontalPadding),
|
||||
builder: (context, c, child) {
|
||||
final scrollableWidth = c.item1;
|
||||
final columnCount = c.item2;
|
||||
final tileSpacing = c.item3;
|
||||
final horizontalPadding = c.item4;
|
||||
// do not listen for animation delay change
|
||||
final target = context.read<DurationsData>().staggeredAnimationPageTarget;
|
||||
final tileAnimationDelay = context.read<TileExtentController>().getTileAnimationDelay(target);
|
||||
|
@ -265,6 +267,7 @@ class _FilterGridContent<T extends CollectionFilter> extends StatelessWidget {
|
|||
scrollableWidth: scrollableWidth,
|
||||
columnCount: columnCount,
|
||||
spacing: tileSpacing,
|
||||
horizontalPadding: horizontalPadding,
|
||||
tileWidth: thumbnailExtent,
|
||||
tileHeight: tileHeight,
|
||||
tileBuilder: (gridItem) {
|
||||
|
@ -430,8 +433,10 @@ class _FilterScaler<T extends CollectionFilter> extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final tileSpacing = context.select<TileExtentController, double>((controller) => controller.spacing);
|
||||
final textScaleFactor = context.select<MediaQueryData, double>((mq) => mq.textScaleFactor);
|
||||
final metrics = context.select<TileExtentController, Tuple2<double, double>>((v) => Tuple2(v.spacing, v.horizontalPadding));
|
||||
final tileSpacing = metrics.item1;
|
||||
final horizontalPadding = metrics.item2;
|
||||
return GridScaleGestureDetector<FilterGridItem<T>>(
|
||||
scrollableKey: scrollableKey,
|
||||
tileLayout: tileLayout,
|
||||
|
@ -442,6 +447,7 @@ class _FilterScaler<T extends CollectionFilter> extends StatelessWidget {
|
|||
tileCenter: center,
|
||||
tileSize: tileSize,
|
||||
spacing: tileSpacing,
|
||||
horizontalPadding: horizontalPadding,
|
||||
borderWidth: AvesFilterChip.outlineWidth,
|
||||
borderRadius: CoveredFilterChip.radius(tileSize.shortestSide),
|
||||
color: Colors.grey.shade700,
|
||||
|
|
|
@ -15,6 +15,7 @@ class SectionedFilterListLayoutProvider<T extends CollectionFilter> extends Sect
|
|||
required TileLayout tileLayout,
|
||||
required int columnCount,
|
||||
required double spacing,
|
||||
required double horizontalPadding,
|
||||
required double tileWidth,
|
||||
required double tileHeight,
|
||||
required Widget Function(FilterGridItem<T> gridItem) tileBuilder,
|
||||
|
@ -26,6 +27,7 @@ class SectionedFilterListLayoutProvider<T extends CollectionFilter> extends Sect
|
|||
tileLayout: tileLayout,
|
||||
columnCount: columnCount,
|
||||
spacing: spacing,
|
||||
horizontalPadding: horizontalPadding,
|
||||
tileWidth: tileWidth,
|
||||
tileHeight: tileHeight,
|
||||
tileBuilder: tileBuilder,
|
||||
|
|
Loading…
Reference in a new issue