aves/lib/widgets/common/grid/sections/section_layout_builder.dart
2023-08-16 23:42:52 +02:00

105 lines
3.7 KiB
Dart

import 'package:aves/model/source/section_keys.dart';
import 'package:aves/theme/durations.dart';
import 'package:aves/widgets/common/grid/sections/list_layout.dart';
import 'package:aves/widgets/common/grid/sections/section_layout.dart';
import 'package:aves_model/aves_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:provider/provider.dart';
typedef TileBuilder<T> = Widget Function(T item, Size tileSize);
abstract class SectionLayoutBuilder<T> {
final Map<SectionKey, List<T>> sections;
final bool showHeaders;
final double Function(BuildContext context, SectionKey sectionKey) getHeaderExtent;
final Widget Function(BuildContext context, SectionKey sectionKey, double headerExtent) buildHeader;
final double scrollableWidth;
final TileLayout tileLayout;
final int columnCount;
final double spacing, horizontalPadding, tileWidth, tileHeight, bottom;
final TileBuilder<T> tileBuilder;
final Duration tileAnimationDelay;
final bool animate;
const SectionLayoutBuilder({
required this.sections,
required this.showHeaders,
required this.getHeaderExtent,
required this.buildHeader,
required this.scrollableWidth,
required this.tileLayout,
required this.columnCount,
required this.spacing,
required this.horizontalPadding,
required this.tileWidth,
required this.tileHeight,
required this.tileBuilder,
required this.tileAnimationDelay,
}) : animate = tileAnimationDelay > Duration.zero,
bottom = tileHeight - tileWidth;
SectionedListLayout<T> updateLayouts(BuildContext context);
SectionLayout buildSectionLayout({
required double headerExtent,
required SectionKey sectionKey,
required List<T> section,
required bool animate,
});
Widget buildSectionWidget({
required BuildContext context,
required List<T> section,
required int sectionGridIndex,
required int sectionChildIndex,
required (int, int) Function() itemIndexRange,
required SectionKey sectionKey,
required double headerExtent,
required List<Size> itemSizes,
required bool animate,
required Widget Function(List<Widget> children) buildGridRow,
}) {
if (sectionChildIndex == 0) {
final header = headerExtent > 0 ? buildHeader(context, sectionKey, headerExtent) : const SizedBox();
return animate ? _buildAnimation(context, sectionGridIndex, header) : header;
}
final sectionItemCount = section.length;
final itemMinMax = itemIndexRange();
final minItemIndex = itemMinMax.$1.clamp(0, sectionItemCount);
final maxItemIndex = itemMinMax.$2.clamp(0, sectionItemCount);
final childrenCount = maxItemIndex - minItemIndex;
final children = <Widget>[];
for (var i = 0; i < childrenCount; i++) {
final item = RepaintBoundary(
child: tileBuilder(section[minItemIndex + i], itemSizes[i]),
);
if (animate) {
children.add(_buildAnimation(context, sectionGridIndex + i, item));
} else {
children.add(item);
}
}
return Padding(
padding: EdgeInsets.symmetric(horizontal: horizontalPadding),
child: buildGridRow(children),
);
}
Widget _buildAnimation(BuildContext context, int index, Widget child) {
final durations = context.watch<DurationsData>();
return AnimationConfiguration.staggeredGrid(
position: index,
columnCount: tileLayout == TileLayout.mosaic ? 1 : columnCount,
duration: durations.staggeredAnimation,
delay: tileAnimationDelay,
child: SlideAnimation(
verticalOffset: 50.0,
child: FadeInAnimation(
child: child,
),
),
);
}
}