rebuild performance review
This commit is contained in:
parent
64d80eb4be
commit
ff6aef1e82
4 changed files with 268 additions and 135 deletions
|
@ -32,12 +32,12 @@ import 'package:flutter/rendering.dart';
|
|||
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class ThumbnailCollection extends StatefulWidget {
|
||||
class CollectionGrid extends StatefulWidget {
|
||||
@override
|
||||
_ThumbnailCollectionState createState() => _ThumbnailCollectionState();
|
||||
_CollectionGridState createState() => _CollectionGridState();
|
||||
}
|
||||
|
||||
class _ThumbnailCollectionState extends State<ThumbnailCollection> {
|
||||
class _CollectionGridState extends State<CollectionGrid> {
|
||||
TileExtentController _tileExtentController;
|
||||
|
||||
@override
|
||||
|
@ -48,54 +48,20 @@ class _ThumbnailCollectionState extends State<ThumbnailCollection> {
|
|||
extentMin: 46,
|
||||
spacing: 0,
|
||||
);
|
||||
return SafeArea(
|
||||
bottom: false,
|
||||
child: TileExtentControllerProvider(
|
||||
return TileExtentControllerProvider(
|
||||
controller: _tileExtentController,
|
||||
child: _ThumbnailCollectionContent(),
|
||||
),
|
||||
child: _CollectionGridContent(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ThumbnailCollectionContent extends StatelessWidget {
|
||||
final ValueNotifier<double> _appBarHeightNotifier = ValueNotifier(0);
|
||||
class _CollectionGridContent extends StatelessWidget {
|
||||
final ValueNotifier<bool> _isScrollingNotifier = ValueNotifier(false);
|
||||
final GlobalKey _scrollableKey = GlobalKey(debugLabel: 'thumbnail-collection-scrollable');
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scrollController = PrimaryScrollController.of(context);
|
||||
return Consumer<CollectionLens>(
|
||||
builder: (context, collection, child) {
|
||||
final scrollView = AnimationLimiter(
|
||||
child: CollectionScrollView(
|
||||
scrollableKey: _scrollableKey,
|
||||
collection: collection,
|
||||
appBar: CollectionAppBar(
|
||||
appBarHeightNotifier: _appBarHeightNotifier,
|
||||
collection: collection,
|
||||
),
|
||||
appBarHeightNotifier: _appBarHeightNotifier,
|
||||
isScrollingNotifier: _isScrollingNotifier,
|
||||
scrollController: scrollController,
|
||||
),
|
||||
);
|
||||
|
||||
final scaler = _ThumbnailGridScaleGestureDetector(
|
||||
scrollableKey: _scrollableKey,
|
||||
appBarHeightNotifier: _appBarHeightNotifier,
|
||||
child: scrollView,
|
||||
);
|
||||
|
||||
final selector = GridSelectionGestureDetector(
|
||||
selectable: AvesApp.mode == AppMode.main,
|
||||
collection: collection,
|
||||
scrollController: scrollController,
|
||||
appBarHeightNotifier: _appBarHeightNotifier,
|
||||
child: scaler,
|
||||
);
|
||||
|
||||
final sectionedListLayoutProvider = ValueListenableBuilder<double>(
|
||||
valueListenable: context.select<TileExtentController, ValueNotifier<double>>((controller) => controller.extentNotifier),
|
||||
builder: (context, tileExtent, child) {
|
||||
|
@ -111,7 +77,11 @@ class _ThumbnailCollectionContent extends StatelessWidget {
|
|||
tileExtent: tileExtent,
|
||||
isScrollingNotifier: _isScrollingNotifier,
|
||||
),
|
||||
child: selector,
|
||||
child: _CollectionSectionedContent(
|
||||
collection: collection,
|
||||
isScrollingNotifier: _isScrollingNotifier,
|
||||
scrollController: PrimaryScrollController.of(context),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -121,12 +91,69 @@ class _ThumbnailCollectionContent extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
class _ThumbnailGridScaleGestureDetector extends StatelessWidget {
|
||||
class _CollectionSectionedContent extends StatefulWidget {
|
||||
final CollectionLens collection;
|
||||
final ValueNotifier<bool> isScrollingNotifier;
|
||||
final ScrollController scrollController;
|
||||
|
||||
const _CollectionSectionedContent({
|
||||
@required this.collection,
|
||||
@required this.isScrollingNotifier,
|
||||
@required this.scrollController,
|
||||
});
|
||||
|
||||
@override
|
||||
_CollectionSectionedContentState createState() => _CollectionSectionedContentState();
|
||||
}
|
||||
|
||||
class _CollectionSectionedContentState extends State<_CollectionSectionedContent> {
|
||||
CollectionLens get collection => widget.collection;
|
||||
|
||||
ScrollController get scrollController => widget.scrollController;
|
||||
|
||||
final ValueNotifier<double> _appBarHeightNotifier = ValueNotifier(0);
|
||||
final GlobalKey _scrollableKey = GlobalKey(debugLabel: 'thumbnail-collection-scrollable');
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scrollView = AnimationLimiter(
|
||||
child: _CollectionScrollView(
|
||||
scrollableKey: _scrollableKey,
|
||||
collection: collection,
|
||||
appBar: CollectionAppBar(
|
||||
appBarHeightNotifier: _appBarHeightNotifier,
|
||||
collection: collection,
|
||||
),
|
||||
appBarHeightNotifier: _appBarHeightNotifier,
|
||||
isScrollingNotifier: widget.isScrollingNotifier,
|
||||
scrollController: scrollController,
|
||||
),
|
||||
);
|
||||
|
||||
final scaler = _CollectionScaler(
|
||||
scrollableKey: _scrollableKey,
|
||||
appBarHeightNotifier: _appBarHeightNotifier,
|
||||
child: scrollView,
|
||||
);
|
||||
|
||||
final selector = GridSelectionGestureDetector(
|
||||
selectable: AvesApp.mode == AppMode.main,
|
||||
collection: collection,
|
||||
scrollController: scrollController,
|
||||
appBarHeightNotifier: _appBarHeightNotifier,
|
||||
child: scaler,
|
||||
);
|
||||
|
||||
return selector;
|
||||
}
|
||||
}
|
||||
|
||||
class _CollectionScaler extends StatelessWidget {
|
||||
final GlobalKey scrollableKey;
|
||||
final ValueNotifier<double> appBarHeightNotifier;
|
||||
final Widget child;
|
||||
|
||||
const _ThumbnailGridScaleGestureDetector({
|
||||
const _CollectionScaler({
|
||||
@required this.scrollableKey,
|
||||
@required this.appBarHeightNotifier,
|
||||
@required this.child,
|
||||
|
@ -166,7 +193,7 @@ class _ThumbnailGridScaleGestureDetector extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
class CollectionScrollView extends StatefulWidget {
|
||||
class _CollectionScrollView extends StatefulWidget {
|
||||
final GlobalKey scrollableKey;
|
||||
final CollectionLens collection;
|
||||
final Widget appBar;
|
||||
|
@ -174,7 +201,7 @@ class CollectionScrollView extends StatefulWidget {
|
|||
final ValueNotifier<bool> isScrollingNotifier;
|
||||
final ScrollController scrollController;
|
||||
|
||||
const CollectionScrollView({
|
||||
const _CollectionScrollView({
|
||||
@required this.scrollableKey,
|
||||
@required this.collection,
|
||||
@required this.appBar,
|
||||
|
@ -187,7 +214,7 @@ class CollectionScrollView extends StatefulWidget {
|
|||
_CollectionScrollViewState createState() => _CollectionScrollViewState();
|
||||
}
|
||||
|
||||
class _CollectionScrollViewState extends State<CollectionScrollView> {
|
||||
class _CollectionScrollViewState extends State<_CollectionScrollView> {
|
||||
Timer _scrollMonitoringTimer;
|
||||
|
||||
@override
|
||||
|
@ -197,7 +224,7 @@ class _CollectionScrollViewState extends State<CollectionScrollView> {
|
|||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant CollectionScrollView oldWidget) {
|
||||
void didUpdateWidget(covariant _CollectionScrollView oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
_unregisterWidget(oldWidget);
|
||||
_registerWidget(widget);
|
||||
|
@ -210,13 +237,13 @@ class _CollectionScrollViewState extends State<CollectionScrollView> {
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
void _registerWidget(CollectionScrollView widget) {
|
||||
void _registerWidget(_CollectionScrollView widget) {
|
||||
widget.collection.filterChangeNotifier.addListener(_scrollToTop);
|
||||
widget.collection.sortGroupChangeNotifier.addListener(_scrollToTop);
|
||||
widget.scrollController.addListener(_onScrollChange);
|
||||
}
|
||||
|
||||
void _unregisterWidget(CollectionScrollView widget) {
|
||||
void _unregisterWidget(_CollectionScrollView widget) {
|
||||
widget.collection.filterChangeNotifier.removeListener(_scrollToTop);
|
||||
widget.collection.sortGroupChangeNotifier.removeListener(_scrollToTop);
|
||||
widget.scrollController.removeListener(_onScrollChange);
|
||||
|
@ -228,27 +255,6 @@ class _CollectionScrollViewState extends State<CollectionScrollView> {
|
|||
return _buildDraggableScrollView(scrollView);
|
||||
}
|
||||
|
||||
ScrollView _buildScrollView(Widget appBar, CollectionLens collection) {
|
||||
return CustomScrollView(
|
||||
key: widget.scrollableKey,
|
||||
primary: true,
|
||||
// workaround to prevent scrolling the app bar away
|
||||
// when there is no content and we use `SliverFillRemaining`
|
||||
physics: collection.isEmpty ? NeverScrollableScrollPhysics() : SloppyScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
|
||||
cacheExtent: context.select<TileExtentController, double>((controller) => controller.effectiveExtentMax * 2),
|
||||
slivers: [
|
||||
appBar,
|
||||
collection.isEmpty
|
||||
? SliverFillRemaining(
|
||||
hasScrollBody: false,
|
||||
child: _buildEmptyCollectionPlaceholder(collection),
|
||||
)
|
||||
: SectionedListSliver<AvesEntry>(),
|
||||
BottomPaddingSliver(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDraggableScrollView(ScrollView scrollView) {
|
||||
return ValueListenableBuilder<double>(
|
||||
valueListenable: widget.appBarHeightNotifier,
|
||||
|
@ -274,6 +280,27 @@ class _CollectionScrollViewState extends State<CollectionScrollView> {
|
|||
);
|
||||
}
|
||||
|
||||
ScrollView _buildScrollView(Widget appBar, CollectionLens collection) {
|
||||
return CustomScrollView(
|
||||
key: widget.scrollableKey,
|
||||
primary: true,
|
||||
// workaround to prevent scrolling the app bar away
|
||||
// when there is no content and we use `SliverFillRemaining`
|
||||
physics: collection.isEmpty ? NeverScrollableScrollPhysics() : SloppyScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
|
||||
cacheExtent: context.select<TileExtentController, double>((controller) => controller.effectiveExtentMax * 2),
|
||||
slivers: [
|
||||
appBar,
|
||||
collection.isEmpty
|
||||
? SliverFillRemaining(
|
||||
hasScrollBody: false,
|
||||
child: _buildEmptyCollectionPlaceholder(collection),
|
||||
)
|
||||
: SectionedListSliver<AvesEntry>(),
|
||||
BottomPaddingSliver(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildEmptyCollectionPlaceholder(CollectionLens collection) {
|
||||
return ValueListenableBuilder<SourceState>(
|
||||
valueListenable: collection.source.stateNotifier,
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:aves/model/source/collection_lens.dart';
|
||||
import 'package:aves/widgets/collection/thumbnail_collection.dart';
|
||||
import 'package:aves/widgets/collection/collection_grid.dart';
|
||||
import 'package:aves/widgets/common/basic/insets.dart';
|
||||
import 'package:aves/widgets/common/behaviour/double_back_pop.dart';
|
||||
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
||||
|
@ -42,9 +42,12 @@ class _CollectionPageState extends State<CollectionPage> {
|
|||
},
|
||||
child: DoubleBackPopScope(
|
||||
child: GestureAreaProtectorStack(
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: ChangeNotifierProvider<CollectionLens>.value(
|
||||
value: collection,
|
||||
child: ThumbnailCollection(),
|
||||
child: CollectionGrid(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -58,21 +58,21 @@ class _AlbumPickPageState extends State<AlbumPickPage> {
|
|||
return StreamBuilder(
|
||||
stream: source.eventBus.on<AlbumsChangedEvent>(),
|
||||
builder: (context, snapshot) => FilterGridPage<AlbumFilter>(
|
||||
settingsRouteKey: AlbumListPage.routeName,
|
||||
appBar: appBar,
|
||||
appBarHeight: AlbumPickAppBar.preferredHeight,
|
||||
filterSections: AlbumListPage.getAlbumEntries(context, source),
|
||||
showHeaders: settings.albumGroupFactor != AlbumChipGroupFactor.none,
|
||||
queryNotifier: _queryNotifier,
|
||||
applyQuery: (filters, query) {
|
||||
if (query == null || query.isEmpty) return filters;
|
||||
query = query.toUpperCase();
|
||||
return filters.where((item) => item.filter.uniqueName.toUpperCase().contains(query)).toList();
|
||||
},
|
||||
queryNotifier: _queryNotifier,
|
||||
emptyBuilder: () => EmptyContent(
|
||||
icon: AIcons.album,
|
||||
text: context.l10n.albumEmpty,
|
||||
),
|
||||
settingsRouteKey: AlbumListPage.routeName,
|
||||
appBarHeight: AlbumPickAppBar.preferredHeight,
|
||||
onTap: (filter) => Navigator.pop<String>(context, (filter as AlbumFilter)?.album),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -29,27 +29,27 @@ import 'package:provider/provider.dart';
|
|||
typedef QueryTest<T extends CollectionFilter> = Iterable<FilterGridItem<T>> Function(Iterable<FilterGridItem<T>> filters, String query);
|
||||
|
||||
class FilterGridPage<T extends CollectionFilter> extends StatelessWidget {
|
||||
final String settingsRouteKey;
|
||||
final Widget appBar;
|
||||
final double appBarHeight;
|
||||
final Map<ChipSectionKey, List<FilterGridItem<T>>> filterSections;
|
||||
final bool showHeaders;
|
||||
final ValueNotifier<String> queryNotifier;
|
||||
final Widget Function() emptyBuilder;
|
||||
final String settingsRouteKey;
|
||||
final double appBarHeight;
|
||||
final QueryTest<T> applyQuery;
|
||||
final Widget Function() emptyBuilder;
|
||||
final FilterCallback onTap;
|
||||
final OffsetFilterCallback onLongPress;
|
||||
|
||||
const FilterGridPage({
|
||||
Key key,
|
||||
this.settingsRouteKey,
|
||||
@required this.appBar,
|
||||
this.appBarHeight = kToolbarHeight,
|
||||
@required this.filterSections,
|
||||
this.showHeaders = false,
|
||||
@required this.showHeaders,
|
||||
@required this.queryNotifier,
|
||||
this.applyQuery,
|
||||
@required this.emptyBuilder,
|
||||
this.settingsRouteKey,
|
||||
this.appBarHeight = kToolbarHeight,
|
||||
@required this.onTap,
|
||||
this.onLongPress,
|
||||
}) : super(key: key);
|
||||
|
@ -64,28 +64,21 @@ class FilterGridPage<T extends CollectionFilter> extends StatelessWidget {
|
|||
child: GestureAreaProtectorStack(
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: TileExtentControllerProvider(
|
||||
controller: TileExtentController(
|
||||
settingsRouteKey: settingsRouteKey ?? context.currentRouteName,
|
||||
columnCountDefault: 2,
|
||||
extentMin: 60,
|
||||
spacing: 8,
|
||||
),
|
||||
child: _FilterGridPageContent<T>(
|
||||
child: FilterGrid<T>(
|
||||
settingsRouteKey: settingsRouteKey,
|
||||
appBar: appBar,
|
||||
appBarHeight: appBarHeight,
|
||||
filterSections: filterSections,
|
||||
showHeaders: showHeaders,
|
||||
queryNotifier: queryNotifier,
|
||||
applyQuery: applyQuery,
|
||||
emptyBuilder: emptyBuilder,
|
||||
appBarHeight: appBarHeight,
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
drawer: AppDrawer(),
|
||||
resizeToAvoidBottomInset: false,
|
||||
),
|
||||
|
@ -93,7 +86,65 @@ class FilterGridPage<T extends CollectionFilter> extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
class _FilterGridPageContent<T extends CollectionFilter> extends StatelessWidget {
|
||||
class FilterGrid<T extends CollectionFilter> extends StatefulWidget {
|
||||
final String settingsRouteKey;
|
||||
final Widget appBar;
|
||||
final double appBarHeight;
|
||||
final Map<ChipSectionKey, List<FilterGridItem<T>>> filterSections;
|
||||
final bool showHeaders;
|
||||
final ValueNotifier<String> queryNotifier;
|
||||
final QueryTest<T> applyQuery;
|
||||
final Widget Function() emptyBuilder;
|
||||
final FilterCallback onTap;
|
||||
final OffsetFilterCallback onLongPress;
|
||||
|
||||
const FilterGrid({
|
||||
Key key,
|
||||
@required this.settingsRouteKey,
|
||||
@required this.appBar,
|
||||
@required this.appBarHeight,
|
||||
@required this.filterSections,
|
||||
@required this.showHeaders,
|
||||
@required this.queryNotifier,
|
||||
@required this.applyQuery,
|
||||
@required this.emptyBuilder,
|
||||
@required this.onTap,
|
||||
@required this.onLongPress,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_FilterGridState createState() => _FilterGridState<T>();
|
||||
}
|
||||
|
||||
class _FilterGridState<T extends CollectionFilter> extends State<FilterGrid<T>> {
|
||||
TileExtentController _tileExtentController;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_tileExtentController ??= TileExtentController(
|
||||
settingsRouteKey: widget.settingsRouteKey ?? context.currentRouteName,
|
||||
columnCountDefault: 2,
|
||||
extentMin: 60,
|
||||
spacing: 8,
|
||||
);
|
||||
return TileExtentControllerProvider(
|
||||
controller: _tileExtentController,
|
||||
child: _FilterGridContent<T>(
|
||||
appBar: widget.appBar,
|
||||
appBarHeight: widget.appBarHeight,
|
||||
filterSections: widget.filterSections,
|
||||
showHeaders: widget.showHeaders,
|
||||
queryNotifier: widget.queryNotifier,
|
||||
applyQuery: widget.applyQuery,
|
||||
emptyBuilder: widget.emptyBuilder,
|
||||
onTap: widget.onTap,
|
||||
onLongPress: widget.onLongPress,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _FilterGridContent<T extends CollectionFilter> extends StatelessWidget {
|
||||
final Widget appBar;
|
||||
final Map<ChipSectionKey, List<FilterGridItem<T>>> filterSections;
|
||||
final bool showHeaders;
|
||||
|
@ -105,15 +156,15 @@ class _FilterGridPageContent<T extends CollectionFilter> extends StatelessWidget
|
|||
|
||||
final ValueNotifier<double> _appBarHeightNotifier = ValueNotifier(0);
|
||||
|
||||
_FilterGridPageContent({
|
||||
_FilterGridContent({
|
||||
Key key,
|
||||
@required this.appBar,
|
||||
@required double appBarHeight,
|
||||
@required this.filterSections,
|
||||
@required this.showHeaders,
|
||||
@required this.queryNotifier,
|
||||
@required this.applyQuery,
|
||||
@required this.emptyBuilder,
|
||||
@required double appBarHeight,
|
||||
@required this.onTap,
|
||||
@required this.onLongPress,
|
||||
}) : super(key: key) {
|
||||
|
@ -166,7 +217,7 @@ class _FilterGridPageContent<T extends CollectionFilter> extends StatelessWidget
|
|||
),
|
||||
);
|
||||
},
|
||||
child: _SectionedContent<T>(
|
||||
child: _FilterSectionedContent<T>(
|
||||
appBar: appBar,
|
||||
appBarHeightNotifier: _appBarHeightNotifier,
|
||||
visibleFilterSections: visibleFilterSections,
|
||||
|
@ -182,14 +233,14 @@ class _FilterGridPageContent<T extends CollectionFilter> extends StatelessWidget
|
|||
}
|
||||
}
|
||||
|
||||
class _SectionedContent<T extends CollectionFilter> extends StatefulWidget {
|
||||
class _FilterSectionedContent<T extends CollectionFilter> extends StatefulWidget {
|
||||
final Widget appBar;
|
||||
final ValueNotifier<double> appBarHeightNotifier;
|
||||
final Map<ChipSectionKey, List<FilterGridItem<T>>> visibleFilterSections;
|
||||
final Widget Function() emptyBuilder;
|
||||
final ScrollController scrollController;
|
||||
|
||||
const _SectionedContent({
|
||||
const _FilterSectionedContent({
|
||||
@required this.appBar,
|
||||
@required this.appBarHeightNotifier,
|
||||
@required this.visibleFilterSections,
|
||||
|
@ -198,10 +249,10 @@ class _SectionedContent<T extends CollectionFilter> extends StatefulWidget {
|
|||
});
|
||||
|
||||
@override
|
||||
_SectionedContentState createState() => _SectionedContentState<T>();
|
||||
_FilterSectionedContentState createState() => _FilterSectionedContentState<T>();
|
||||
}
|
||||
|
||||
class _SectionedContentState<T extends CollectionFilter> extends State<_SectionedContent<T>> {
|
||||
class _FilterSectionedContentState<T extends CollectionFilter> extends State<_FilterSectionedContent<T>> {
|
||||
Widget get appBar => widget.appBar;
|
||||
|
||||
ValueNotifier<double> get appBarHeightNotifier => widget.appBarHeightNotifier;
|
||||
|
@ -220,6 +271,27 @@ class _SectionedContentState<T extends CollectionFilter> extends State<_Sectione
|
|||
WidgetsBinding.instance.addPostFrameCallback((_) => _checkInitHighlight());
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scrollView = AnimationLimiter(
|
||||
child: _FilterScrollView<T>(
|
||||
scrollableKey: _scrollableKey,
|
||||
appBar: appBar,
|
||||
appBarHeightNotifier: appBarHeightNotifier,
|
||||
emptyBuilder: emptyBuilder,
|
||||
scrollController: scrollController,
|
||||
),
|
||||
);
|
||||
|
||||
final scaler = _FilterScaler<T>(
|
||||
scrollableKey: _scrollableKey,
|
||||
appBarHeightNotifier: appBarHeightNotifier,
|
||||
child: scrollView,
|
||||
);
|
||||
|
||||
return scaler;
|
||||
}
|
||||
|
||||
Future<void> _checkInitHighlight() async {
|
||||
final highlightInfo = context.read<HighlightInfo>();
|
||||
final filter = highlightInfo.clear();
|
||||
|
@ -252,13 +324,25 @@ class _SectionedContentState<T extends CollectionFilter> extends State<_Sectione
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _FilterScaler<T extends CollectionFilter> extends StatelessWidget {
|
||||
final GlobalKey scrollableKey;
|
||||
final ValueNotifier<double> appBarHeightNotifier;
|
||||
final Widget child;
|
||||
|
||||
const _FilterScaler({
|
||||
@required this.scrollableKey,
|
||||
@required this.appBarHeightNotifier,
|
||||
@required this.child,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final pinnedFilters = settings.pinnedFilters;
|
||||
final tileSpacing = context.select<TileExtentController, double>((controller) => controller.spacing);
|
||||
return GridScaleGestureDetector<FilterGridItem<T>>(
|
||||
scrollableKey: _scrollableKey,
|
||||
scrollableKey: scrollableKey,
|
||||
appBarHeightNotifier: appBarHeightNotifier,
|
||||
gridBuilder: (center, extent, child) => CustomPaint(
|
||||
painter: GridPainter(
|
||||
|
@ -283,11 +367,31 @@ class _SectionedContentState<T extends CollectionFilter> extends State<_Sectione
|
|||
return sectionedListLayout.getTileRect(item) ?? Rect.zero;
|
||||
},
|
||||
onScaled: (item) => context.read<HighlightInfo>().set(item.filter),
|
||||
child: AnimationLimiter(
|
||||
child: _buildDraggableScrollView(_buildScrollView(context, visibleFilterSections.isEmpty)),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _FilterScrollView<T extends CollectionFilter> extends StatelessWidget {
|
||||
final GlobalKey scrollableKey;
|
||||
final Widget appBar;
|
||||
final ValueNotifier<double> appBarHeightNotifier;
|
||||
final Widget Function() emptyBuilder;
|
||||
final ScrollController scrollController;
|
||||
|
||||
const _FilterScrollView({
|
||||
@required this.scrollableKey,
|
||||
@required this.appBar,
|
||||
@required this.appBarHeightNotifier,
|
||||
@required this.emptyBuilder,
|
||||
@required this.scrollController,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scrollView = _buildScrollView(context);
|
||||
return _buildDraggableScrollView(scrollView);
|
||||
}
|
||||
|
||||
Widget _buildDraggableScrollView(ScrollView scrollView) {
|
||||
return Selector<MediaQueryData, double>(
|
||||
|
@ -310,10 +414,17 @@ class _SectionedContentState<T extends CollectionFilter> extends State<_Sectione
|
|||
);
|
||||
}
|
||||
|
||||
ScrollView _buildScrollView(BuildContext context, bool empty) {
|
||||
Widget content;
|
||||
if (empty) {
|
||||
content = SliverFillRemaining(
|
||||
ScrollView _buildScrollView(BuildContext context) {
|
||||
return CustomScrollView(
|
||||
key: scrollableKey,
|
||||
controller: scrollController,
|
||||
slivers: [
|
||||
appBar,
|
||||
Selector<SectionedListLayout<FilterGridItem<T>>, bool>(
|
||||
selector: (context, layout) => layout.sections.isEmpty,
|
||||
builder: (context, empty, child) {
|
||||
return empty
|
||||
? SliverFillRemaining(
|
||||
hasScrollBody: false,
|
||||
child: Selector<MediaQueryData, double>(
|
||||
selector: (context, mq) => mq.effectiveBottomPadding,
|
||||
|
@ -324,17 +435,9 @@ class _SectionedContentState<T extends CollectionFilter> extends State<_Sectione
|
|||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
content = SectionedListSliver<FilterGridItem<T>>();
|
||||
}
|
||||
|
||||
return CustomScrollView(
|
||||
key: _scrollableKey,
|
||||
controller: scrollController,
|
||||
slivers: [
|
||||
appBar,
|
||||
content,
|
||||
)
|
||||
: SectionedListSliver<FilterGridItem<T>>();
|
||||
}),
|
||||
BottomPaddingSliver(),
|
||||
],
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue