diff --git a/lib/model/collection_source.dart b/lib/model/collection_source.dart index 84d4acbaa..219fd5054 100644 --- a/lib/model/collection_source.dart +++ b/lib/model/collection_source.dart @@ -1,4 +1,5 @@ import 'package:aves/model/collection_lens.dart'; +import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_metadata.dart'; import 'package:aves/model/metadata_db.dart'; @@ -13,10 +14,10 @@ class CollectionSource { final Set _folderPaths = {}; final EventBus _eventBus = EventBus(); - List sortedAlbums = List.unmodifiable(const Iterable.empty()); - List sortedCountries = List.unmodifiable(const Iterable.empty()); - List sortedPlaces = List.unmodifiable(const Iterable.empty()); - List sortedTags = List.unmodifiable(const Iterable.empty()); + List sortedAlbums = List.unmodifiable([]); + List sortedCountries = List.unmodifiable([]); + List sortedPlaces = List.unmodifiable([]); + List sortedTags = List.unmodifiable([]); List get entries => List.unmodifiable(_rawEntries); @@ -223,6 +224,11 @@ class CollectionSource { entries.firstWhere((entry) => entry.xmpSubjects.contains(tag), orElse: () => null), ))); } + + // TODO TLAD cache counts, invalidate them on any add/remove + int count(CollectionFilter filter) { + return _rawEntries.where((entry) => filter.filter(entry)).length; + } } class AddressMetadataChangedEvent {} diff --git a/lib/widgets/common/aves_filter_chip.dart b/lib/widgets/common/aves_filter_chip.dart index c26272281..f34138795 100644 --- a/lib/widgets/common/aves_filter_chip.dart +++ b/lib/widgets/common/aves_filter_chip.dart @@ -9,6 +9,7 @@ class AvesFilterChip extends StatefulWidget { final bool removable; final bool showGenericIcon; final Decoration decoration; + final Widget details; final FilterCallback onPressed; static final BorderRadius borderRadius = BorderRadius.circular(32); @@ -24,6 +25,7 @@ class AvesFilterChip extends StatefulWidget { this.removable = false, this.showGenericIcon = true, this.decoration, + this.details, @required this.onPressed, }) : super(key: key); @@ -57,37 +59,60 @@ class _AvesFilterChipState extends State { final leading = filter.iconBuilder(context, AvesFilterChip.iconSize, showGenericIcon: widget.showGenericIcon); final trailing = widget.removable ? const Icon(AIcons.clear, size: AvesFilterChip.iconSize) : null; - Widget content = Padding( - padding: const EdgeInsets.symmetric(horizontal: AvesFilterChip.padding * 2), - child: Row( - mainAxisSize: widget.decoration != null ? MainAxisSize.max : MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (leading != null) ...[ - leading, - const SizedBox(width: AvesFilterChip.padding), - ], - Flexible( - child: Text( - filter.label, - softWrap: false, - overflow: TextOverflow.fade, - maxLines: 1, - ), - ), - if (trailing != null) ...[ - const SizedBox(width: AvesFilterChip.padding), - trailing, - ], + Widget content = Row( + mainAxisSize: widget.decoration != null ? MainAxisSize.max : MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (leading != null) ...[ + leading, + const SizedBox(width: AvesFilterChip.padding), ], - ), + Flexible( + child: Text( + filter.label, + softWrap: false, + overflow: TextOverflow.fade, + maxLines: 1, + ), + ), + if (trailing != null) ...[ + const SizedBox(width: AvesFilterChip.padding), + trailing, + ], + ], + ); + + if (widget.details != null) { + content = Column( + mainAxisSize: MainAxisSize.min, + children: [ + content, + widget.details, + ], + ); + } + + content = Padding( + padding: const EdgeInsets.symmetric(horizontal: AvesFilterChip.padding * 2, vertical: 2), + child: content, ); if (widget.decoration != null) { - content = Container( - constraints: BoxConstraints(minHeight: DefaultTextStyle.of(context).style.fontSize * 2), - color: Colors.black54, - child: content, + content = Center( + child: ColoredBox( + color: Colors.black54, + child: DefaultTextStyle( + style: Theme.of(context).textTheme.bodyText2.copyWith( + shadows: const [ + Shadow( + color: Colors.black87, + offset: Offset(0.5, 1.0), + ) + ], + ), + child: content, + ), + ), ); } diff --git a/lib/widgets/filter_grid_page.dart b/lib/widgets/filter_grid_page.dart index a7e66a6c1..99b68519b 100644 --- a/lib/widgets/filter_grid_page.dart +++ b/lib/widgets/filter_grid_page.dart @@ -1,13 +1,16 @@ import 'package:aves/model/collection_lens.dart'; import 'package:aves/model/collection_source.dart'; +import 'package:aves/model/filters/album.dart'; import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/image_entry.dart'; import 'package:aves/model/settings.dart'; +import 'package:aves/utils/android_file_utils.dart'; import 'package:aves/utils/constants.dart'; import 'package:aves/widgets/album/collection_page.dart'; import 'package:aves/widgets/app_drawer.dart'; import 'package:aves/widgets/common/aves_filter_chip.dart'; import 'package:aves/widgets/common/data_providers/media_query_data_provider.dart'; +import 'package:aves/widgets/common/icons.dart'; import 'package:aves/widgets/common/image_providers/thumbnail_provider.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -68,6 +71,8 @@ class FilterGridPage extends StatelessWidget { List get filterKeys => filterEntries.keys.toList(); + static const Color detailColor = Color(0xFFE0E0E0); + @override Widget build(BuildContext context) { return MediaQueryDataProvider( @@ -77,13 +82,14 @@ class FilterGridPage extends StatelessWidget { slivers: [ appBar, SliverPadding( - padding: EdgeInsets.all(AvesFilterChip.buttonBorderWidth), + padding: const EdgeInsets.all(AvesFilterChip.buttonBorderWidth), sliver: SliverGrid( delegate: SliverChildBuilderDelegate( (context, i) { final key = filterKeys[i]; final entry = filterEntries[key]; Decoration decoration; + // TODO TLAD add decoration for SVG if (entry != null && !entry.isSvg) { decoration = BoxDecoration( image: DecorationImage( @@ -96,10 +102,12 @@ class FilterGridPage extends StatelessWidget { borderRadius: AvesFilterChip.borderRadius, ); } + final filter = filterBuilder(key); return AvesFilterChip( - filter: filterBuilder(key), + filter: filter, showGenericIcon: false, decoration: decoration, + details: _buildDetails(filter), onPressed: onPressed, ); }, @@ -130,4 +138,25 @@ class FilterGridPage extends StatelessWidget { ), ); } + + Widget _buildDetails(CollectionFilter filter) { + final count = Text( + '${source.count(filter)}', + style: const TextStyle(color: FilterGridPage.detailColor), + ); + return filter is AlbumFilter && androidFileUtils.isOnRemovableStorage(filter.album) + ? Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon( + AIcons.removableStorage, + size: 16, + color: FilterGridPage.detailColor, + ), + const SizedBox(width: 8), + count, + ], + ) + : count; + } }