chip grid: added count and storage indicator for albums

This commit is contained in:
Thibault Deckers 2020-06-01 15:53:01 +09:00
parent 97e3fe62c0
commit b9bf51ff83
3 changed files with 93 additions and 33 deletions

View file

@ -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<String> _folderPaths = {};
final EventBus _eventBus = EventBus();
List<String> sortedAlbums = List.unmodifiable(const Iterable.empty());
List<String> sortedCountries = List.unmodifiable(const Iterable.empty());
List<String> sortedPlaces = List.unmodifiable(const Iterable.empty());
List<String> sortedTags = List.unmodifiable(const Iterable.empty());
List<String> sortedAlbums = List.unmodifiable([]);
List<String> sortedCountries = List.unmodifiable([]);
List<String> sortedPlaces = List.unmodifiable([]);
List<String> sortedTags = List.unmodifiable([]);
List<ImageEntry> 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 {}

View file

@ -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<AvesFilterChip> {
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,
),
),
);
}

View file

@ -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<String> 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;
}
}