search: on this day, month filters in date filter section
This commit is contained in:
parent
76370b25b4
commit
ccc99ed59a
19 changed files with 146 additions and 70 deletions
|
@ -6,8 +6,8 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
### Added
|
||||
|
||||
- Search: `on this day` filter
|
||||
- Stats: histogram and date filters
|
||||
- Search: `on this day` and month filters in date filter section
|
||||
- Stats: histogram and contextual date filters
|
||||
- Screen saver
|
||||
|
||||
### Changed
|
||||
|
|
|
@ -417,6 +417,7 @@
|
|||
|
||||
"searchCollectionFieldHint": "Sammlung durchsuchen",
|
||||
"searchSectionRecent": "Neueste",
|
||||
"searchSectionDate": "Datum",
|
||||
"searchSectionAlbums": "Alben",
|
||||
"searchSectionCountries": "Länder",
|
||||
"searchSectionPlaces": "Orte",
|
||||
|
|
|
@ -598,6 +598,7 @@
|
|||
|
||||
"searchCollectionFieldHint": "Search collection",
|
||||
"searchSectionRecent": "Recent",
|
||||
"searchSectionDate": "Date",
|
||||
"searchSectionAlbums": "Albums",
|
||||
"searchSectionCountries": "Countries",
|
||||
"searchSectionPlaces": "Places",
|
||||
|
|
|
@ -417,6 +417,7 @@
|
|||
|
||||
"searchCollectionFieldHint": "Buscar en colección",
|
||||
"searchSectionRecent": "Reciente",
|
||||
"searchSectionDate": "Fecha",
|
||||
"searchSectionAlbums": "Álbumes",
|
||||
"searchSectionCountries": "Países",
|
||||
"searchSectionPlaces": "Lugares",
|
||||
|
|
|
@ -417,6 +417,7 @@
|
|||
|
||||
"searchCollectionFieldHint": "Recherche",
|
||||
"searchSectionRecent": "Historique",
|
||||
"searchSectionDate": "Date",
|
||||
"searchSectionAlbums": "Albums",
|
||||
"searchSectionCountries": "Pays",
|
||||
"searchSectionPlaces": "Lieux",
|
||||
|
|
|
@ -417,6 +417,7 @@
|
|||
|
||||
"searchCollectionFieldHint": "Cari koleksi",
|
||||
"searchSectionRecent": "Terkini",
|
||||
"searchSectionDate": "Tanggal",
|
||||
"searchSectionAlbums": "Album",
|
||||
"searchSectionCountries": "Negara",
|
||||
"searchSectionPlaces": "Tempat",
|
||||
|
|
|
@ -417,6 +417,7 @@
|
|||
|
||||
"searchCollectionFieldHint": "Cerca raccolta",
|
||||
"searchSectionRecent": "Recenti",
|
||||
"searchSectionDate": "Data",
|
||||
"searchSectionAlbums": "Album",
|
||||
"searchSectionCountries": "Paesi",
|
||||
"searchSectionPlaces": "Luoghi",
|
||||
|
|
|
@ -417,6 +417,7 @@
|
|||
|
||||
"searchCollectionFieldHint": "コレクションを検索",
|
||||
"searchSectionRecent": "最近",
|
||||
"searchSectionDate": "日付",
|
||||
"searchSectionAlbums": "アルバム",
|
||||
"searchSectionCountries": "国",
|
||||
"searchSectionPlaces": "場所",
|
||||
|
|
|
@ -417,6 +417,7 @@
|
|||
|
||||
"searchCollectionFieldHint": "미디어 검색",
|
||||
"searchSectionRecent": "최근 검색기록",
|
||||
"searchSectionDate": "날짜",
|
||||
"searchSectionAlbums": "앨범",
|
||||
"searchSectionCountries": "국가",
|
||||
"searchSectionPlaces": "장소",
|
||||
|
|
|
@ -417,6 +417,7 @@
|
|||
|
||||
"searchCollectionFieldHint": "Pesquisar coleção",
|
||||
"searchSectionRecent": "Recente",
|
||||
"searchSectionDate": "Data",
|
||||
"searchSectionAlbums": "Álbuns",
|
||||
"searchSectionCountries": "Países",
|
||||
"searchSectionPlaces": "Locais",
|
||||
|
|
|
@ -399,6 +399,7 @@
|
|||
|
||||
"searchCollectionFieldHint": "Поиск по коллекции",
|
||||
"searchSectionRecent": "Недавние",
|
||||
"searchSectionDate": "Дата",
|
||||
"searchSectionAlbums": "Альбомы",
|
||||
"searchSectionCountries": "Страны",
|
||||
"searchSectionPlaces": "Локации",
|
||||
|
|
|
@ -418,6 +418,7 @@
|
|||
|
||||
"searchCollectionFieldHint": "Koleksiyonu ara",
|
||||
"searchSectionRecent": "Yakın zamanda",
|
||||
"searchSectionDate": "Tarih",
|
||||
"searchSectionAlbums": "Albümler",
|
||||
"searchSectionCountries": "Ülkeler",
|
||||
"searchSectionPlaces": "Yerler",
|
||||
|
|
|
@ -417,6 +417,7 @@
|
|||
|
||||
"searchCollectionFieldHint": "搜索媒体集",
|
||||
"searchSectionRecent": "最近",
|
||||
"searchSectionDate": "日期",
|
||||
"searchSectionAlbums": "相册",
|
||||
"searchSectionCountries": "国家",
|
||||
"searchSectionPlaces": "地点",
|
||||
|
|
|
@ -7,7 +7,7 @@ import 'package:collection/collection.dart';
|
|||
import 'package:flutter/widgets.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class DateFilter extends CoveredCollectionFilter {
|
||||
class DateFilter extends CollectionFilter {
|
||||
static const type = 'date';
|
||||
|
||||
final DateLevel level;
|
||||
|
@ -69,6 +69,32 @@ class DateFilter extends CoveredCollectionFilter {
|
|||
@override
|
||||
EntryFilter get test => _test;
|
||||
|
||||
@override
|
||||
bool isCompatible(CollectionFilter other) {
|
||||
if (other is DateFilter) {
|
||||
return isCompatibleLevel(level, other.level);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool isCompatibleLevel(DateLevel a, DateLevel b) {
|
||||
switch (a) {
|
||||
case DateLevel.y:
|
||||
return {DateLevel.md, DateLevel.m, DateLevel.d}.contains(b);
|
||||
case DateLevel.ym:
|
||||
return DateLevel.d == b;
|
||||
case DateLevel.ymd:
|
||||
return false;
|
||||
case DateLevel.md:
|
||||
return DateLevel.y == b;
|
||||
case DateLevel.m:
|
||||
return {DateLevel.y, DateLevel.d}.contains(b);
|
||||
case DateLevel.d:
|
||||
return {DateLevel.y, DateLevel.ym, DateLevel.m}.contains(b);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
String get universalLabel => _effectiveDate.toIso8601String();
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ abstract class CollectionFilter extends Equatable implements Comparable<Collecti
|
|||
|
||||
EntryFilter get test;
|
||||
|
||||
bool get isUnique => true;
|
||||
bool isCompatible(CollectionFilter other) => category != other.category;
|
||||
|
||||
String get universalLabel;
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ class QueryFilter extends CollectionFilter {
|
|||
EntryFilter get test => _test;
|
||||
|
||||
@override
|
||||
bool get isUnique => false;
|
||||
bool isCompatible(CollectionFilter other) => true;
|
||||
|
||||
@override
|
||||
String get universalLabel => query;
|
||||
|
|
|
@ -38,7 +38,7 @@ class TagFilter extends CoveredCollectionFilter {
|
|||
EntryFilter get test => _test;
|
||||
|
||||
@override
|
||||
bool get isUnique => false;
|
||||
bool isCompatible(CollectionFilter other) => true;
|
||||
|
||||
@override
|
||||
String get universalLabel => tag;
|
||||
|
|
|
@ -150,9 +150,7 @@ class CollectionLens with ChangeNotifier {
|
|||
|
||||
void addFilter(CollectionFilter filter) {
|
||||
if (filters.contains(filter)) return;
|
||||
if (filter.isUnique) {
|
||||
filters.removeWhere((old) => old.category == filter.category);
|
||||
}
|
||||
filters.removeWhere((other) => !filter.isCompatible(other));
|
||||
filters.add(filter);
|
||||
_onFilterChanged();
|
||||
}
|
||||
|
|
|
@ -42,9 +42,10 @@ class CollectionSearchDelegate extends AvesSearchDelegate {
|
|||
TypeFilter.geotiff,
|
||||
TypeFilter.raw,
|
||||
MimeFilter(MimeTypes.svg),
|
||||
DateFilter.onThisDay,
|
||||
];
|
||||
|
||||
static final _monthFilters = List.generate(12, (i) => DateFilter(DateLevel.m, DateTime(1, i + 1)));
|
||||
|
||||
CollectionSearchDelegate({
|
||||
required super.searchFieldLabel,
|
||||
required this.source,
|
||||
|
@ -97,66 +98,12 @@ class CollectionSearchDelegate extends AvesSearchDelegate {
|
|||
title: context.l10n.searchSectionRecent,
|
||||
filters: history,
|
||||
),
|
||||
StreamBuilder(
|
||||
stream: source.eventBus.on<AlbumsChangedEvent>(),
|
||||
builder: (context, snapshot) {
|
||||
final filters = source.rawAlbums
|
||||
.map((album) => AlbumFilter(
|
||||
album,
|
||||
source.getAlbumDisplayName(context, album),
|
||||
))
|
||||
.where((filter) => containQuery(filter.displayName ?? filter.album))
|
||||
.toList()
|
||||
..sort();
|
||||
return _buildFilterRow(
|
||||
context: context,
|
||||
title: context.l10n.searchSectionAlbums,
|
||||
filters: filters,
|
||||
);
|
||||
}),
|
||||
StreamBuilder(
|
||||
stream: source.eventBus.on<CountriesChangedEvent>(),
|
||||
builder: (context, snapshot) {
|
||||
final filters = source.sortedCountries.where(containQuery).map((s) => LocationFilter(LocationLevel.country, s)).toList();
|
||||
return _buildFilterRow(
|
||||
context: context,
|
||||
title: context.l10n.searchSectionCountries,
|
||||
filters: filters,
|
||||
);
|
||||
}),
|
||||
StreamBuilder(
|
||||
stream: source.eventBus.on<PlacesChangedEvent>(),
|
||||
builder: (context, snapshot) {
|
||||
final filters = source.sortedPlaces.where(containQuery).map((s) => LocationFilter(LocationLevel.place, s));
|
||||
final noFilter = LocationFilter(LocationLevel.place, '');
|
||||
return _buildFilterRow(
|
||||
context: context,
|
||||
title: context.l10n.searchSectionPlaces,
|
||||
filters: [
|
||||
if (containQuery(noFilter.getLabel(context))) noFilter,
|
||||
...filters,
|
||||
],
|
||||
);
|
||||
}),
|
||||
StreamBuilder(
|
||||
stream: source.eventBus.on<TagsChangedEvent>(),
|
||||
builder: (context, snapshot) {
|
||||
final filters = source.sortedTags.where(containQuery).map(TagFilter.new);
|
||||
final noFilter = TagFilter('');
|
||||
return _buildFilterRow(
|
||||
context: context,
|
||||
title: context.l10n.searchSectionTags,
|
||||
filters: [
|
||||
if (containQuery(noFilter.getLabel(context))) noFilter,
|
||||
...filters,
|
||||
],
|
||||
);
|
||||
}),
|
||||
_buildFilterRow(
|
||||
context: context,
|
||||
title: context.l10n.searchSectionRating,
|
||||
filters: [0, 5, 4, 3, 2, 1, -1].map(RatingFilter.new).where((f) => containQuery(f.getLabel(context))).toList(),
|
||||
),
|
||||
_buildDateFilters(context, containQuery),
|
||||
_buildAlbumFilters(containQuery),
|
||||
_buildCountryFilters(containQuery),
|
||||
_buildPlaceFilters(containQuery),
|
||||
_buildTagFilters(containQuery),
|
||||
_buildRatingFilters(context, containQuery),
|
||||
],
|
||||
);
|
||||
});
|
||||
|
@ -180,6 +127,97 @@ class CollectionSearchDelegate extends AvesSearchDelegate {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildDateFilters(BuildContext context, _ContainQuery containQuery) {
|
||||
final filters = [
|
||||
DateFilter.onThisDay,
|
||||
..._monthFilters,
|
||||
].where((f) => containQuery(f.getLabel(context))).toList();
|
||||
return _buildFilterRow(
|
||||
context: context,
|
||||
title: context.l10n.searchSectionDate,
|
||||
filters: filters,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAlbumFilters(_ContainQuery containQuery) {
|
||||
return StreamBuilder(
|
||||
stream: source.eventBus.on<AlbumsChangedEvent>(),
|
||||
builder: (context, snapshot) {
|
||||
final filters = source.rawAlbums
|
||||
.map((album) => AlbumFilter(
|
||||
album,
|
||||
source.getAlbumDisplayName(context, album),
|
||||
))
|
||||
.where((filter) => containQuery(filter.displayName ?? filter.album))
|
||||
.toList()
|
||||
..sort();
|
||||
return _buildFilterRow(
|
||||
context: context,
|
||||
title: context.l10n.searchSectionAlbums,
|
||||
filters: filters,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCountryFilters(_ContainQuery containQuery) {
|
||||
return StreamBuilder(
|
||||
stream: source.eventBus.on<CountriesChangedEvent>(),
|
||||
builder: (context, snapshot) {
|
||||
final filters = source.sortedCountries.where(containQuery).map((s) => LocationFilter(LocationLevel.country, s)).toList();
|
||||
return _buildFilterRow(
|
||||
context: context,
|
||||
title: context.l10n.searchSectionCountries,
|
||||
filters: filters,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPlaceFilters(_ContainQuery containQuery) {
|
||||
return StreamBuilder(
|
||||
stream: source.eventBus.on<PlacesChangedEvent>(),
|
||||
builder: (context, snapshot) {
|
||||
final filters = source.sortedPlaces.where(containQuery).map((s) => LocationFilter(LocationLevel.place, s));
|
||||
final noFilter = LocationFilter(LocationLevel.place, '');
|
||||
return _buildFilterRow(
|
||||
context: context,
|
||||
title: context.l10n.searchSectionPlaces,
|
||||
filters: [
|
||||
if (containQuery(noFilter.getLabel(context))) noFilter,
|
||||
...filters,
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTagFilters(_ContainQuery containQuery) {
|
||||
return StreamBuilder(
|
||||
stream: source.eventBus.on<TagsChangedEvent>(),
|
||||
builder: (context, snapshot) {
|
||||
final filters = source.sortedTags.where(containQuery).map(TagFilter.new);
|
||||
final noFilter = TagFilter('');
|
||||
return _buildFilterRow(
|
||||
context: context,
|
||||
title: context.l10n.searchSectionTags,
|
||||
filters: [
|
||||
if (containQuery(noFilter.getLabel(context))) noFilter,
|
||||
...filters,
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRatingFilters(BuildContext context, _ContainQuery containQuery) {
|
||||
return _buildFilterRow(
|
||||
context: context,
|
||||
title: context.l10n.searchSectionRating,
|
||||
filters: [0, 5, 4, 3, 2, 1, -1].map(RatingFilter.new).where((f) => containQuery(f.getLabel(context))).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget buildResults(BuildContext context) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
|
@ -240,3 +278,5 @@ class CollectionSearchDelegate extends AvesSearchDelegate {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
typedef _ContainQuery = bool Function(String s);
|
||||
|
|
Loading…
Reference in a new issue