#327 long press on section header selects all section

This commit is contained in:
Thibault Deckers 2022-09-15 22:05:19 +02:00
parent 3ee20d46bf
commit 3090439e19
10 changed files with 61 additions and 5 deletions

View file

@ -92,6 +92,7 @@ class _CollectionGridContent extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final selectable = context.select<ValueNotifier<AppMode>, bool>((v) => v.value.canSelectMedia);
final settingsRouteKey = context.read<TileExtentController>().settingsRouteKey; final settingsRouteKey = context.read<TileExtentController>().settingsRouteKey;
final tileLayout = context.select<Settings, TileLayout>((s) => s.getTileLayout(settingsRouteKey)); final tileLayout = context.select<Settings, TileLayout>((s) => s.getTileLayout(settingsRouteKey));
return Consumer<CollectionLens>( return Consumer<CollectionLens>(
@ -124,6 +125,7 @@ class _CollectionGridContent extends StatelessWidget {
} }
return SectionedEntryListLayoutProvider( return SectionedEntryListLayoutProvider(
collection: collection, collection: collection,
selectable: selectable,
scrollableWidth: scrollableWidth, scrollableWidth: scrollableWidth,
tileLayout: tileLayout, tileLayout: tileLayout,
columnCount: columnCount, columnCount: columnCount,
@ -160,6 +162,7 @@ class _CollectionGridContent extends StatelessWidget {
isScrollingNotifier: _isScrollingNotifier, isScrollingNotifier: _isScrollingNotifier,
scrollController: PrimaryScrollController.of(context)!, scrollController: PrimaryScrollController.of(context)!,
tileLayout: tileLayout, tileLayout: tileLayout,
selectable: selectable,
), ),
); );
return sectionedListLayoutProvider; return sectionedListLayoutProvider;
@ -173,12 +176,14 @@ class _CollectionSectionedContent extends StatefulWidget {
final ValueNotifier<bool> isScrollingNotifier; final ValueNotifier<bool> isScrollingNotifier;
final ScrollController scrollController; final ScrollController scrollController;
final TileLayout tileLayout; final TileLayout tileLayout;
final bool selectable;
const _CollectionSectionedContent({ const _CollectionSectionedContent({
required this.collection, required this.collection,
required this.isScrollingNotifier, required this.isScrollingNotifier,
required this.scrollController, required this.scrollController,
required this.tileLayout, required this.tileLayout,
required this.selectable,
}); });
@override @override
@ -220,7 +225,7 @@ class _CollectionSectionedContentState extends State<_CollectionSectionedContent
final selector = GridSelectionGestureDetector( final selector = GridSelectionGestureDetector(
scrollableKey: _scrollableKey, scrollableKey: _scrollableKey,
selectable: context.select<ValueNotifier<AppMode>, bool>((v) => v.value.canSelectMedia), selectable: widget.selectable,
items: collection.sortedEntries, items: collection.sortedEntries,
scrollController: scrollController, scrollController: scrollController,
appBarHeightNotifier: _appBarHeightNotifier, appBarHeightNotifier: _appBarHeightNotifier,

View file

@ -11,11 +11,13 @@ import 'package:flutter/material.dart';
class AlbumSectionHeader extends StatelessWidget { class AlbumSectionHeader extends StatelessWidget {
final String? directory, albumName; final String? directory, albumName;
final bool selectable;
const AlbumSectionHeader({ const AlbumSectionHeader({
super.key, super.key,
required this.directory, required this.directory,
required this.albumName, required this.albumName,
required this.selectable,
}); });
@override @override
@ -41,6 +43,7 @@ class AlbumSectionHeader extends StatelessWidget {
color: Color(0xFF757575), color: Color(0xFF757575),
) )
: null, : null,
selectable: selectable,
); );
} }

View file

@ -15,12 +15,14 @@ class CollectionSectionHeader extends StatelessWidget {
final CollectionLens collection; final CollectionLens collection;
final SectionKey sectionKey; final SectionKey sectionKey;
final double height; final double height;
final bool selectable;
const CollectionSectionHeader({ const CollectionSectionHeader({
super.key, super.key,
required this.collection, required this.collection,
required this.sectionKey, required this.sectionKey,
required this.height, required this.height,
required this.selectable,
}); });
@override @override
@ -41,9 +43,17 @@ class CollectionSectionHeader extends StatelessWidget {
case EntryGroupFactor.album: case EntryGroupFactor.album:
return _buildAlbumHeader(context); return _buildAlbumHeader(context);
case EntryGroupFactor.month: case EntryGroupFactor.month:
return MonthSectionHeader<AvesEntry>(key: ValueKey(sectionKey), date: (sectionKey as EntryDateSectionKey).date); return MonthSectionHeader<AvesEntry>(
key: ValueKey(sectionKey),
date: (sectionKey as EntryDateSectionKey).date,
selectable: selectable,
);
case EntryGroupFactor.day: case EntryGroupFactor.day:
return DaySectionHeader<AvesEntry>(key: ValueKey(sectionKey), date: (sectionKey as EntryDateSectionKey).date); return DaySectionHeader<AvesEntry>(
key: ValueKey(sectionKey),
date: (sectionKey as EntryDateSectionKey).date,
selectable: selectable,
);
case EntryGroupFactor.none: case EntryGroupFactor.none:
break; break;
} }
@ -51,7 +61,11 @@ class CollectionSectionHeader extends StatelessWidget {
case EntrySortFactor.name: case EntrySortFactor.name:
return _buildAlbumHeader(context); return _buildAlbumHeader(context);
case EntrySortFactor.rating: case EntrySortFactor.rating:
return RatingSectionHeader<AvesEntry>(key: ValueKey(sectionKey), rating: (sectionKey as EntryRatingSectionKey).rating); return RatingSectionHeader<AvesEntry>(
key: ValueKey(sectionKey),
rating: (sectionKey as EntryRatingSectionKey).rating,
selectable: selectable,
);
case EntrySortFactor.size: case EntrySortFactor.size:
break; break;
} }
@ -65,6 +79,7 @@ class CollectionSectionHeader extends StatelessWidget {
key: ValueKey(sectionKey), key: ValueKey(sectionKey),
directory: directory, directory: directory,
albumName: directory != null ? source.getAlbumDisplayName(context, directory) : null, albumName: directory != null ? source.getAlbumDisplayName(context, directory) : null,
selectable: selectable,
); );
} }

View file

@ -7,10 +7,12 @@ import 'package:intl/intl.dart';
class DaySectionHeader<T> extends StatelessWidget { class DaySectionHeader<T> extends StatelessWidget {
final DateTime? date; final DateTime? date;
final bool selectable;
const DaySectionHeader({ const DaySectionHeader({
super.key, super.key,
required this.date, required this.date,
required this.selectable,
}); });
// Examples (en_US): // Examples (en_US):
@ -48,16 +50,19 @@ class DaySectionHeader<T> extends StatelessWidget {
return SectionHeader<T>( return SectionHeader<T>(
sectionKey: EntryDateSectionKey(date), sectionKey: EntryDateSectionKey(date),
title: _formatDate(context, date), title: _formatDate(context, date),
selectable: selectable,
); );
} }
} }
class MonthSectionHeader<T> extends StatelessWidget { class MonthSectionHeader<T> extends StatelessWidget {
final DateTime? date; final DateTime? date;
final bool selectable;
const MonthSectionHeader({ const MonthSectionHeader({
super.key, super.key,
required this.date, required this.date,
required this.selectable,
}); });
static String _formatDate(BuildContext context, DateTime? date) { static String _formatDate(BuildContext context, DateTime? date) {
@ -74,6 +79,7 @@ class MonthSectionHeader<T> extends StatelessWidget {
return SectionHeader<T>( return SectionHeader<T>(
sectionKey: EntryDateSectionKey(date), sectionKey: EntryDateSectionKey(date),
title: _formatDate(context, date), title: _formatDate(context, date),
selectable: selectable,
); );
} }
} }

View file

@ -5,10 +5,12 @@ import 'package:flutter/material.dart';
class RatingSectionHeader<T> extends StatelessWidget { class RatingSectionHeader<T> extends StatelessWidget {
final int rating; final int rating;
final bool selectable;
const RatingSectionHeader({ const RatingSectionHeader({
super.key, super.key,
required this.rating, required this.rating,
required this.selectable,
}); });
@override @override
@ -16,6 +18,7 @@ class RatingSectionHeader<T> extends StatelessWidget {
return SectionHeader<T>( return SectionHeader<T>(
sectionKey: EntryRatingSectionKey(rating), sectionKey: EntryRatingSectionKey(rating),
title: RatingFilter.formatRating(context, rating), title: RatingFilter.formatRating(context, rating),
selectable: selectable,
); );
} }
} }

View file

@ -7,10 +7,12 @@ import 'package:flutter/material.dart';
class SectionedEntryListLayoutProvider extends SectionedListLayoutProvider<AvesEntry> { class SectionedEntryListLayoutProvider extends SectionedListLayoutProvider<AvesEntry> {
final CollectionLens collection; final CollectionLens collection;
final bool selectable;
const SectionedEntryListLayoutProvider({ const SectionedEntryListLayoutProvider({
super.key, super.key,
required this.collection, required this.collection,
required this.selectable,
required super.scrollableWidth, required super.scrollableWidth,
required super.tileLayout, required super.tileLayout,
required super.columnCount, required super.columnCount,
@ -42,6 +44,7 @@ class SectionedEntryListLayoutProvider extends SectionedListLayoutProvider<AvesE
collection: collection, collection: collection,
sectionKey: sectionKey, sectionKey: sectionKey,
height: headerExtent, height: headerExtent,
selectable: selectable,
); );
} }
} }

View file

@ -36,6 +36,17 @@ class SectionHeader<T> extends StatelessWidget {
constraints: BoxConstraints(minHeight: leadingSize.height), constraints: BoxConstraints(minHeight: leadingSize.height),
child: GestureDetector( child: GestureDetector(
onTap: selectable ? () => _toggleSectionSelection(context) : null, onTap: selectable ? () => _toggleSectionSelection(context) : null,
onLongPress: selectable
? () {
final selection = context.read<Selection<T>>();
if (selection.isSelecting) {
_toggleSectionSelection(context);
} else {
selection.select();
selection.addToSelection(_getSectionEntries(context));
}
}
: null,
child: Text.rich( child: Text.rich(
TextSpan( TextSpan(
children: [ children: [
@ -74,8 +85,10 @@ class SectionHeader<T> extends StatelessWidget {
); );
} }
List<T> _getSectionEntries(BuildContext context) => context.read<SectionedListLayout<T>>().sections[sectionKey] ?? [];
void _toggleSectionSelection(BuildContext context) { void _toggleSectionSelection(BuildContext context) {
final sectionEntries = context.read<SectionedListLayout<T>>().sections[sectionKey] ?? []; final sectionEntries = _getSectionEntries(context);
final selection = context.read<Selection<T>>(); final selection = context.read<Selection<T>>();
final isSelected = selection.isSelected(sectionEntries); final isSelected = selection.isSelected(sectionEntries);
if (isSelected) { if (isSelected) {

View file

@ -293,6 +293,7 @@ class _FilterGridContent<T extends CollectionFilter> extends StatelessWidget {
child: SectionedFilterListLayoutProvider<T>( child: SectionedFilterListLayoutProvider<T>(
sections: visibleSections, sections: visibleSections,
showHeaders: showHeaders, showHeaders: showHeaders,
selectable: selectable,
tileLayout: tileLayout, tileLayout: tileLayout,
scrollableWidth: scrollableWidth, scrollableWidth: scrollableWidth,
columnCount: columnCount, columnCount: columnCount,

View file

@ -4,10 +4,12 @@ import 'package:flutter/material.dart';
class FilterChipSectionHeader<T> extends StatelessWidget { class FilterChipSectionHeader<T> extends StatelessWidget {
final ChipSectionKey sectionKey; final ChipSectionKey sectionKey;
final bool selectable;
const FilterChipSectionHeader({ const FilterChipSectionHeader({
super.key, super.key,
required this.sectionKey, required this.sectionKey,
required this.selectable,
}); });
@override @override
@ -16,6 +18,7 @@ class FilterChipSectionHeader<T> extends StatelessWidget {
sectionKey: sectionKey, sectionKey: sectionKey,
leading: sectionKey.leading, leading: sectionKey.leading,
title: sectionKey.title, title: sectionKey.title,
selectable: selectable,
); );
} }

View file

@ -6,10 +6,13 @@ import 'package:aves/widgets/filter_grids/common/section_keys.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class SectionedFilterListLayoutProvider<T extends CollectionFilter> extends SectionedListLayoutProvider<FilterGridItem<T>> { class SectionedFilterListLayoutProvider<T extends CollectionFilter> extends SectionedListLayoutProvider<FilterGridItem<T>> {
final bool selectable;
const SectionedFilterListLayoutProvider({ const SectionedFilterListLayoutProvider({
super.key, super.key,
required this.sections, required this.sections,
required this.showHeaders, required this.showHeaders,
required this.selectable,
required super.scrollableWidth, required super.scrollableWidth,
required super.tileLayout, required super.tileLayout,
required super.columnCount, required super.columnCount,
@ -37,6 +40,7 @@ class SectionedFilterListLayoutProvider<T extends CollectionFilter> extends Sect
Widget buildHeader(BuildContext context, SectionKey sectionKey, double headerExtent) { Widget buildHeader(BuildContext context, SectionKey sectionKey, double headerExtent) {
return FilterChipSectionHeader<FilterGridItem<T>>( return FilterChipSectionHeader<FilterGridItem<T>>(
sectionKey: sectionKey as ChipSectionKey, sectionKey: sectionKey as ChipSectionKey,
selectable: selectable,
); );
} }
} }