#327 long press on section header selects all section
This commit is contained in:
parent
3ee20d46bf
commit
3090439e19
10 changed files with 61 additions and 5 deletions
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue