#312 filter pages: size displayed in list view details, sort by size

This commit is contained in:
Thibault Deckers 2022-09-05 19:07:35 +02:00
parent 39f7eda873
commit e56875e9ad
28 changed files with 169 additions and 138 deletions

View file

@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
### Added ### Added
- Collection / Info: edit title via IPTC / XMP - Collection / Info: edit title via IPTC / XMP
- Albums / Countries / Tags: size displayed in list view details, sort by size
- Greek translation (thanks Emmanouil Papavergis) - Greek translation (thanks Emmanouil Papavergis)
### Changed ### Changed

View file

@ -337,11 +337,6 @@
"collectionSearchTitlesHintText": "Titel suchen", "collectionSearchTitlesHintText": "Titel suchen",
"collectionSortDate": "Nach Datum",
"collectionSortSize": "Nach Größe",
"collectionSortName": "Nach Album & Dateiname",
"collectionSortRating": "Nach Bewertung",
"collectionGroupAlbum": "Nach Album", "collectionGroupAlbum": "Nach Album",
"collectionGroupMonth": "Nach Monat", "collectionGroupMonth": "Nach Monat",
"collectionGroupDay": "Nach Tag", "collectionGroupDay": "Nach Tag",
@ -385,9 +380,12 @@
"drawerCountryPage": "Länder", "drawerCountryPage": "Länder",
"drawerTagPage": "Tags", "drawerTagPage": "Tags",
"chipSortDate": "Nach Datum", "sortByDate": "Nach Datum",
"chipSortName": "Nach Name", "sortByName": "Nach Name",
"chipSortCount": "Nach Anzahl", "sortByItemCount": "Nach Anzahl",
"sortBySize": "Nach Größe",
"sortByAlbumFileName": "Nach Album & Dateiname",
"sortByRating": "Nach Bewertung",
"albumGroupTier": "Nach Ebene", "albumGroupTier": "Nach Ebene",
"albumGroupVolume": "Nach Speichervolumen", "albumGroupVolume": "Nach Speichervolumen",

View file

@ -337,11 +337,6 @@
"collectionSearchTitlesHintText": "Αναζήτηση τίτλων", "collectionSearchTitlesHintText": "Αναζήτηση τίτλων",
"collectionSortDate": "Ανά ημερομηνία.",
"collectionSortSize": "Ανά μέγεθος",
"collectionSortName": "Ανά άλμπουμ και όνομα αρχείου",
"collectionSortRating": "Ανά βαθμολογία",
"collectionGroupAlbum": "Ανά άλμπουμ", "collectionGroupAlbum": "Ανά άλμπουμ",
"collectionGroupMonth": "Ανά μήνα", "collectionGroupMonth": "Ανά μήνα",
"collectionGroupDay": "Ανά ημέρα", "collectionGroupDay": "Ανά ημέρα",
@ -385,9 +380,12 @@
"drawerCountryPage": "Χώρες", "drawerCountryPage": "Χώρες",
"drawerTagPage": "Ετικέτες", "drawerTagPage": "Ετικέτες",
"chipSortDate": "Ανά ημερομηνία", "sortByDate": "Ανά ημερομηνία",
"chipSortName": "Ανά όνομα", "sortByName": "Ανά όνομα",
"chipSortCount": "Ανά μέτρηση στοιχείων", "sortByItemCount": "Ανά μέτρηση στοιχείων",
"sortBySize": "Ανά μέγεθος",
"sortByAlbumFileName": "Ανά άλμπουμ και όνομα αρχείου",
"sortByRating": "Ανά βαθμολογία",
"albumGroupTier": "Ανά βαθμίδα", "albumGroupTier": "Ανά βαθμίδα",
"albumGroupVolume": "Ανά αποθηκευτική μονάδα", "albumGroupVolume": "Ανά αποθηκευτική μονάδα",

View file

@ -468,11 +468,6 @@
"collectionSearchTitlesHintText": "Search titles", "collectionSearchTitlesHintText": "Search titles",
"collectionSortDate": "By date",
"collectionSortSize": "By size",
"collectionSortName": "By album & file name",
"collectionSortRating": "By rating",
"collectionGroupAlbum": "By album", "collectionGroupAlbum": "By album",
"collectionGroupMonth": "By month", "collectionGroupMonth": "By month",
"collectionGroupDay": "By day", "collectionGroupDay": "By day",
@ -566,9 +561,12 @@
"drawerCountryPage": "Countries", "drawerCountryPage": "Countries",
"drawerTagPage": "Tags", "drawerTagPage": "Tags",
"chipSortDate": "By date", "sortByDate": "By date",
"chipSortName": "By name", "sortByName": "By name",
"chipSortCount": "By item count", "sortByItemCount": "By item count",
"sortBySize": "By size",
"sortByAlbumFileName": "By album & file name",
"sortByRating": "By rating",
"albumGroupTier": "By tier", "albumGroupTier": "By tier",
"albumGroupVolume": "By storage volume", "albumGroupVolume": "By storage volume",

View file

@ -336,11 +336,6 @@
"collectionSearchTitlesHintText": "Buscar títulos", "collectionSearchTitlesHintText": "Buscar títulos",
"collectionSortDate": "Por fecha",
"collectionSortSize": "Por tamaño",
"collectionSortName": "Por nombre de álbum y archivo",
"collectionSortRating": "Por clasificación",
"collectionGroupAlbum": "Por álbum", "collectionGroupAlbum": "Por álbum",
"collectionGroupMonth": "Por mes", "collectionGroupMonth": "Por mes",
"collectionGroupDay": "Por día", "collectionGroupDay": "Por día",
@ -384,9 +379,12 @@
"drawerCountryPage": "Países", "drawerCountryPage": "Países",
"drawerTagPage": "Etiquetas", "drawerTagPage": "Etiquetas",
"chipSortDate": "Por fecha", "sortByDate": "Por fecha",
"chipSortName": "Por nombre", "sortByName": "Por nombre",
"chipSortCount": "Por número de elementos", "sortByItemCount": "Por número de elementos",
"sortBySize": "Por tamaño",
"sortByAlbumFileName": "Por nombre de álbum y archivo",
"sortByRating": "Por clasificación",
"albumGroupTier": "Por nivel", "albumGroupTier": "Por nivel",
"albumGroupVolume": "Por volumen de almacenamiento", "albumGroupVolume": "Por volumen de almacenamiento",

View file

@ -338,11 +338,6 @@
"collectionSearchTitlesHintText": "Recherche de titres", "collectionSearchTitlesHintText": "Recherche de titres",
"collectionSortDate": "par date",
"collectionSortSize": "par taille",
"collectionSortName": "alphabétique",
"collectionSortRating": "par notation",
"collectionGroupAlbum": "par album", "collectionGroupAlbum": "par album",
"collectionGroupMonth": "par mois", "collectionGroupMonth": "par mois",
"collectionGroupDay": "par jour", "collectionGroupDay": "par jour",
@ -386,9 +381,12 @@
"drawerCountryPage": "Pays", "drawerCountryPage": "Pays",
"drawerTagPage": "Libellés", "drawerTagPage": "Libellés",
"chipSortDate": "par date", "sortByDate": "par date",
"chipSortName": "alphabétique", "sortByName": "alphabétique",
"chipSortCount": "par nombre déléments", "sortByItemCount": "par nombre déléments",
"sortBySize": "par taille",
"sortByAlbumFileName": "alphabétique",
"sortByRating": "par notation",
"albumGroupTier": "par importance", "albumGroupTier": "par importance",
"albumGroupVolume": "par volume de stockage", "albumGroupVolume": "par volume de stockage",

View file

@ -336,11 +336,6 @@
"collectionSearchTitlesHintText": "Cari judul", "collectionSearchTitlesHintText": "Cari judul",
"collectionSortDate": "Lewat tanggal",
"collectionSortSize": "Lewat ukuran",
"collectionSortName": "Lewat nama album & file",
"collectionSortRating": "Lewat nilai",
"collectionGroupAlbum": "Lewat album", "collectionGroupAlbum": "Lewat album",
"collectionGroupMonth": "Lewat bulan", "collectionGroupMonth": "Lewat bulan",
"collectionGroupDay": "Lewat hari", "collectionGroupDay": "Lewat hari",
@ -384,9 +379,12 @@
"drawerCountryPage": "Negara", "drawerCountryPage": "Negara",
"drawerTagPage": "Label", "drawerTagPage": "Label",
"chipSortDate": "Lewat tanggal", "sortByDate": "Lewat tanggal",
"chipSortName": "Lewat nama", "sortByName": "Lewat nama",
"chipSortCount": "Lewat jumlah benda", "sortByItemCount": "Lewat jumlah benda",
"sortBySize": "Lewat ukuran",
"sortByAlbumFileName": "Lewat nama album & file",
"sortByRating": "Lewat nilai",
"albumGroupTier": "Lewat tingkat", "albumGroupTier": "Lewat tingkat",
"albumGroupVolume": "Lewat volume penyimpanan", "albumGroupVolume": "Lewat volume penyimpanan",

View file

@ -337,11 +337,6 @@
"collectionSearchTitlesHintText": "Cerca titoli", "collectionSearchTitlesHintText": "Cerca titoli",
"collectionSortDate": "Per data",
"collectionSortSize": "Per dimensione",
"collectionSortName": "Per album e nome del file",
"collectionSortRating": "Per valutazione",
"collectionGroupAlbum": "Per album", "collectionGroupAlbum": "Per album",
"collectionGroupMonth": "Per mese", "collectionGroupMonth": "Per mese",
"collectionGroupDay": "Per giorno", "collectionGroupDay": "Per giorno",
@ -385,9 +380,12 @@
"drawerCountryPage": "Paesi", "drawerCountryPage": "Paesi",
"drawerTagPage": "Etichette", "drawerTagPage": "Etichette",
"chipSortDate": "Per data", "sortByDate": "Per data",
"chipSortName": "Per nome", "sortByName": "Per nome",
"chipSortCount": "Per numero di elementi", "sortByItemCount": "Per numero di elementi",
"sortBySize": "Per dimensione",
"sortByAlbumFileName": "Per album e nome del file",
"sortByRating": "Per valutazione",
"albumGroupTier": "Per importanza", "albumGroupTier": "Per importanza",
"albumGroupVolume": "Per volume di archiviazione", "albumGroupVolume": "Per volume di archiviazione",

View file

@ -336,11 +336,6 @@
"collectionSearchTitlesHintText": "タイトルを検索", "collectionSearchTitlesHintText": "タイトルを検索",
"collectionSortDate": "日付",
"collectionSortSize": "サイズ",
"collectionSortName": "アルバムとファイル名",
"collectionSortRating": "評価",
"collectionGroupAlbum": "アルバム別", "collectionGroupAlbum": "アルバム別",
"collectionGroupMonth": "月別", "collectionGroupMonth": "月別",
"collectionGroupDay": "日別", "collectionGroupDay": "日別",
@ -384,9 +379,12 @@
"drawerCountryPage": "国", "drawerCountryPage": "国",
"drawerTagPage": "タグ", "drawerTagPage": "タグ",
"chipSortDate": "日付", "sortByDate": "日付",
"chipSortName": "名前", "sortByName": "名前",
"chipSortCount": "アイテム件数", "sortByItemCount": "アイテム件数",
"sortBySize": "サイズ",
"sortByAlbumFileName": "アルバムとファイル名",
"sortByRating": "評価",
"albumGroupTier": "階層別", "albumGroupTier": "階層別",
"albumGroupVolume": "ストレージ ボリューム別", "albumGroupVolume": "ストレージ ボリューム別",

View file

@ -338,11 +338,6 @@
"collectionSearchTitlesHintText": "제목 검색", "collectionSearchTitlesHintText": "제목 검색",
"collectionSortDate": "날짜",
"collectionSortSize": "크기",
"collectionSortName": "이름",
"collectionSortRating": "별점",
"collectionGroupAlbum": "앨범별로", "collectionGroupAlbum": "앨범별로",
"collectionGroupMonth": "월별로", "collectionGroupMonth": "월별로",
"collectionGroupDay": "날짜별로", "collectionGroupDay": "날짜별로",
@ -386,9 +381,12 @@
"drawerCountryPage": "국가", "drawerCountryPage": "국가",
"drawerTagPage": "태그", "drawerTagPage": "태그",
"chipSortDate": "날짜", "sortByDate": "날짜",
"chipSortName": "이름", "sortByName": "이름",
"chipSortCount": "항목수", "sortByItemCount": "항목수",
"sortBySize": "크기",
"sortByAlbumFileName": "이름",
"sortByRating": "별점",
"albumGroupTier": "단계별로", "albumGroupTier": "단계별로",
"albumGroupVolume": "저장공간별로", "albumGroupVolume": "저장공간별로",

View file

@ -337,11 +337,6 @@
"collectionSearchTitlesHintText": "Zoek op titel", "collectionSearchTitlesHintText": "Zoek op titel",
"collectionSortDate": "Op datum",
"collectionSortSize": "Op grootte",
"collectionSortName": "Op album- en bestandsnaam",
"collectionSortRating": "Op rating",
"collectionGroupAlbum": "Op Albumnaam", "collectionGroupAlbum": "Op Albumnaam",
"collectionGroupMonth": "Op maand", "collectionGroupMonth": "Op maand",
"collectionGroupDay": "Op dag", "collectionGroupDay": "Op dag",
@ -385,9 +380,12 @@
"drawerCountryPage": "Landen", "drawerCountryPage": "Landen",
"drawerTagPage": "Labels", "drawerTagPage": "Labels",
"chipSortDate": "Op datum", "sortByDate": "Op datum",
"chipSortName": "Op naam", "sortByName": "Op naam",
"chipSortCount": "Op aantal items", "sortByItemCount": "Op aantal items",
"sortBySize": "Op grootte",
"sortByAlbumFileName": "Op album- en bestandsnaam",
"sortByRating": "Op rating",
"albumGroupTier": "Op rang", "albumGroupTier": "Op rang",
"albumGroupVolume": "Op opslagvolume", "albumGroupVolume": "Op opslagvolume",

View file

@ -337,11 +337,6 @@
"collectionSearchTitlesHintText": "Pesquisar títulos", "collectionSearchTitlesHintText": "Pesquisar títulos",
"collectionSortDate": "Por data",
"collectionSortSize": "Por tamanho",
"collectionSortName": "Por álbum e nome de arquivo",
"collectionSortRating": "Por classificação",
"collectionGroupAlbum": "Por álbum", "collectionGroupAlbum": "Por álbum",
"collectionGroupMonth": "Por mês", "collectionGroupMonth": "Por mês",
"collectionGroupDay": "Por dia", "collectionGroupDay": "Por dia",
@ -385,9 +380,12 @@
"drawerCountryPage": "Países", "drawerCountryPage": "Países",
"drawerTagPage": "Etiquetas", "drawerTagPage": "Etiquetas",
"chipSortDate": "Por data", "sortByDate": "Por data",
"chipSortName": "Por nome", "sortByName": "Por nome",
"chipSortCount": "Por contagem de itens", "sortByItemCount": "Por contagem de itens",
"sortBySize": "Por tamanho",
"sortByAlbumFileName": "Por álbum e nome de arquivo",
"sortByRating": "Por classificação",
"albumGroupTier": "Por nível", "albumGroupTier": "Por nível",
"albumGroupVolume": "Por volume de armazenamento", "albumGroupVolume": "Por volume de armazenamento",

View file

@ -335,11 +335,6 @@
"collectionSearchTitlesHintText": "Поиск заголовков", "collectionSearchTitlesHintText": "Поиск заголовков",
"collectionSortDate": "По дате",
"collectionSortSize": "По размеру",
"collectionSortName": "По имени альбома и файла",
"collectionSortRating": "По рейтингу",
"collectionGroupAlbum": "По альбому", "collectionGroupAlbum": "По альбому",
"collectionGroupMonth": "По месяцу", "collectionGroupMonth": "По месяцу",
"collectionGroupDay": "По дню", "collectionGroupDay": "По дню",
@ -383,9 +378,12 @@
"drawerCountryPage": "Страны", "drawerCountryPage": "Страны",
"drawerTagPage": "Теги", "drawerTagPage": "Теги",
"chipSortDate": "По дате", "sortByDate": "По дате",
"chipSortName": "По названию", "sortByName": "По названию",
"chipSortCount": "По количеству объектов", "sortByItemCount": "По количеству объектов",
"sortBySize": "По размеру",
"sortByAlbumFileName": "По имени альбома и файла",
"sortByRating": "По рейтингу",
"albumGroupTier": "По уровню", "albumGroupTier": "По уровню",
"albumGroupVolume": "По накопителю", "albumGroupVolume": "По накопителю",

View file

@ -323,11 +323,6 @@
"collectionSearchTitlesHintText": "Başlıkları ara", "collectionSearchTitlesHintText": "Başlıkları ara",
"collectionSortDate": "Tarihe göre",
"collectionSortSize": "Boyuta göre",
"collectionSortName": "Albüm ve dosya adına göre",
"collectionSortRating": "Derecelendirmeye göre",
"collectionGroupAlbum": "Albüme göre", "collectionGroupAlbum": "Albüme göre",
"collectionGroupMonth": "Aya göre", "collectionGroupMonth": "Aya göre",
"collectionGroupDay": "Güne göre", "collectionGroupDay": "Güne göre",
@ -380,9 +375,12 @@
"drawerCountryPage": "Ülkeler", "drawerCountryPage": "Ülkeler",
"drawerTagPage": "Etiketler", "drawerTagPage": "Etiketler",
"chipSortDate": "Tarihe göre", "sortByDate": "Tarihe göre",
"chipSortName": "Adına göre", "sortByName": "Adına göre",
"chipSortCount": "Öğe sayısına göre", "sortByItemCount": "Öğe sayısına göre",
"sortBySize": "Boyuta göre",
"sortByAlbumFileName": "Albüm ve dosya adına göre",
"sortByRating": "Derecelendirmeye göre",
"albumGroupTier": "Kademeye göre", "albumGroupTier": "Kademeye göre",
"albumGroupVolume": "Depolama hacmine göre", "albumGroupVolume": "Depolama hacmine göre",

View file

@ -337,11 +337,6 @@
"collectionSearchTitlesHintText": "搜索标题", "collectionSearchTitlesHintText": "搜索标题",
"collectionSortDate": "按日期",
"collectionSortSize": "按大小",
"collectionSortName": "按相册和文件名",
"collectionSortRating": "按评分",
"collectionGroupAlbum": "按相册", "collectionGroupAlbum": "按相册",
"collectionGroupMonth": "按月份", "collectionGroupMonth": "按月份",
"collectionGroupDay": "按天", "collectionGroupDay": "按天",
@ -385,9 +380,12 @@
"drawerCountryPage": "国家", "drawerCountryPage": "国家",
"drawerTagPage": "标签", "drawerTagPage": "标签",
"chipSortDate": "按日期", "sortByDate": "按日期",
"chipSortName": "按名称", "sortByName": "按名称",
"chipSortCount": "按数量", "sortByItemCount": "按数量",
"sortBySize": "按大小",
"sortByAlbumFileName": "按相册和文件名",
"sortByRating": "按评分",
"albumGroupTier": "按层级", "albumGroupTier": "按层级",
"albumGroupVolume": "按存储卷", "albumGroupVolume": "按存储卷",

View file

@ -4,6 +4,7 @@ import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_source.dart'; import 'package:aves/model/source/collection_source.dart';
import 'package:aves/services/common/services.dart'; import 'package:aves/services/common/services.dart';
import 'package:aves/utils/android_file_utils.dart'; import 'package:aves/utils/android_file_utils.dart';
import 'package:aves/utils/collection_utils.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
@ -95,7 +96,7 @@ mixin AlbumMixin on SourceBase {
// filter summary // filter summary
// by directory // by directory
final Map<String, int> _filterEntryCountMap = {}; final Map<String, int> _filterEntryCountMap = {}, _filterSizeMap = {};
final Map<String, AvesEntry?> _filterRecentEntryMap = {}; final Map<String, AvesEntry?> _filterRecentEntryMap = {};
void invalidateAlbumFilterSummary({ void invalidateAlbumFilterSummary({
@ -103,10 +104,11 @@ mixin AlbumMixin on SourceBase {
Set<String?>? directories, Set<String?>? directories,
bool notify = true, bool notify = true,
}) { }) {
if (_filterEntryCountMap.isEmpty && _filterRecentEntryMap.isEmpty) return; if (_filterEntryCountMap.isEmpty && _filterSizeMap.isEmpty && _filterRecentEntryMap.isEmpty) return;
if (entries == null && directories == null) { if (entries == null && directories == null) {
_filterEntryCountMap.clear(); _filterEntryCountMap.clear();
_filterSizeMap.clear();
_filterRecentEntryMap.clear(); _filterRecentEntryMap.clear();
} else { } else {
directories ??= {}; directories ??= {};
@ -115,6 +117,7 @@ mixin AlbumMixin on SourceBase {
} }
directories.forEach((directory) { directories.forEach((directory) {
_filterEntryCountMap.remove(directory); _filterEntryCountMap.remove(directory);
_filterSizeMap.remove(directory);
_filterRecentEntryMap.remove(directory); _filterRecentEntryMap.remove(directory);
}); });
} }
@ -127,6 +130,10 @@ mixin AlbumMixin on SourceBase {
return _filterEntryCountMap.putIfAbsent(filter.album, () => visibleEntries.where(filter.test).length); return _filterEntryCountMap.putIfAbsent(filter.album, () => visibleEntries.where(filter.test).length);
} }
int albumSize(AlbumFilter filter) {
return _filterSizeMap.putIfAbsent(filter.album, () => visibleEntries.where(filter.test).map((v) => v.sizeBytes).sum);
}
AvesEntry? albumRecentEntry(AlbumFilter filter) { AvesEntry? albumRecentEntry(AlbumFilter filter) {
return _filterRecentEntryMap.putIfAbsent(filter.album, () => sortedEntriesByDate.firstWhereOrNull(filter.test)); return _filterRecentEntryMap.putIfAbsent(filter.album, () => sortedEntriesByDate.firstWhereOrNull(filter.test));
} }

View file

@ -458,6 +458,13 @@ abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagM
return 0; return 0;
} }
int size(CollectionFilter filter) {
if (filter is AlbumFilter) return albumSize(filter);
if (filter is LocationFilter) return countrySize(filter);
if (filter is TagFilter) return tagSize(filter);
return 0;
}
AvesEntry? recentEntry(CollectionFilter filter) { AvesEntry? recentEntry(CollectionFilter filter) {
if (filter is AlbumFilter) return albumRecentEntry(filter); if (filter is AlbumFilter) return albumRecentEntry(filter);
if (filter is LocationFilter) return countryRecentEntry(filter); if (filter is LocationFilter) return countryRecentEntry(filter);

View file

@ -1,6 +1,6 @@
enum SourceState { loading, cataloguing, locatingCountries, locatingPlaces, ready } enum SourceState { loading, cataloguing, locatingCountries, locatingPlaces, ready }
enum ChipSortFactor { date, name, count } enum ChipSortFactor { date, name, count, size }
enum AlbumChipGroupFactor { none, importance, volume } enum AlbumChipGroupFactor { none, importance, volume }

View file

@ -9,6 +9,7 @@ import 'package:aves/model/source/analysis_controller.dart';
import 'package:aves/model/source/collection_source.dart'; import 'package:aves/model/source/collection_source.dart';
import 'package:aves/model/source/enums.dart'; import 'package:aves/model/source/enums.dart';
import 'package:aves/services/common/services.dart'; import 'package:aves/services/common/services.dart';
import 'package:aves/utils/collection_utils.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
@ -180,7 +181,7 @@ mixin LocationMixin on SourceBase {
// filter summary // filter summary
// by country code // by country code
final Map<String, int> _filterEntryCountMap = {}; final Map<String, int> _filterEntryCountMap = {}, _filterSizeMap = {};
final Map<String, AvesEntry?> _filterRecentEntryMap = {}; final Map<String, AvesEntry?> _filterRecentEntryMap = {};
void invalidateCountryFilterSummary({ void invalidateCountryFilterSummary({
@ -188,10 +189,11 @@ mixin LocationMixin on SourceBase {
Set<String>? countryCodes, Set<String>? countryCodes,
bool notify = true, bool notify = true,
}) { }) {
if (_filterEntryCountMap.isEmpty && _filterRecentEntryMap.isEmpty) return; if (_filterEntryCountMap.isEmpty && _filterSizeMap.isEmpty && _filterRecentEntryMap.isEmpty) return;
if (entries == null && countryCodes == null) { if (entries == null && countryCodes == null) {
_filterEntryCountMap.clear(); _filterEntryCountMap.clear();
_filterSizeMap.clear();
_filterRecentEntryMap.clear(); _filterRecentEntryMap.clear();
} else { } else {
countryCodes ??= {}; countryCodes ??= {};
@ -200,6 +202,7 @@ mixin LocationMixin on SourceBase {
} }
countryCodes.forEach((countryCode) { countryCodes.forEach((countryCode) {
_filterEntryCountMap.remove(countryCode); _filterEntryCountMap.remove(countryCode);
_filterSizeMap.remove(countryCode);
_filterRecentEntryMap.remove(countryCode); _filterRecentEntryMap.remove(countryCode);
}); });
} }
@ -214,6 +217,12 @@ mixin LocationMixin on SourceBase {
return _filterEntryCountMap.putIfAbsent(countryCode, () => visibleEntries.where(filter.test).length); return _filterEntryCountMap.putIfAbsent(countryCode, () => visibleEntries.where(filter.test).length);
} }
int countrySize(LocationFilter filter) {
final countryCode = filter.countryCode;
if (countryCode == null) return 0;
return _filterSizeMap.putIfAbsent(countryCode, () => visibleEntries.where(filter.test).map((v) => v.sizeBytes).sum);
}
AvesEntry? countryRecentEntry(LocationFilter filter) { AvesEntry? countryRecentEntry(LocationFilter filter) {
final countryCode = filter.countryCode; final countryCode = filter.countryCode;
if (countryCode == null) return null; if (countryCode == null) return null;

View file

@ -5,6 +5,7 @@ import 'package:aves/model/source/analysis_controller.dart';
import 'package:aves/model/source/collection_source.dart'; import 'package:aves/model/source/collection_source.dart';
import 'package:aves/model/source/enums.dart'; import 'package:aves/model/source/enums.dart';
import 'package:aves/services/common/services.dart'; import 'package:aves/services/common/services.dart';
import 'package:aves/utils/collection_utils.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -75,7 +76,7 @@ mixin TagMixin on SourceBase {
// filter summary // filter summary
// by tag // by tag
final Map<String, int> _filterEntryCountMap = {}; final Map<String, int> _filterEntryCountMap = {}, _filterSizeMap = {};
final Map<String, AvesEntry?> _filterRecentEntryMap = {}; final Map<String, AvesEntry?> _filterRecentEntryMap = {};
void invalidateTagFilterSummary({ void invalidateTagFilterSummary({
@ -83,10 +84,11 @@ mixin TagMixin on SourceBase {
Set<String>? tags, Set<String>? tags,
bool notify = true, bool notify = true,
}) { }) {
if (_filterEntryCountMap.isEmpty && _filterRecentEntryMap.isEmpty) return; if (_filterEntryCountMap.isEmpty && _filterSizeMap.isEmpty && _filterRecentEntryMap.isEmpty) return;
if (entries == null && tags == null) { if (entries == null && tags == null) {
_filterEntryCountMap.clear(); _filterEntryCountMap.clear();
_filterSizeMap.clear();
_filterRecentEntryMap.clear(); _filterRecentEntryMap.clear();
} else { } else {
tags ??= {}; tags ??= {};
@ -95,6 +97,7 @@ mixin TagMixin on SourceBase {
} }
tags.forEach((tag) { tags.forEach((tag) {
_filterEntryCountMap.remove(tag); _filterEntryCountMap.remove(tag);
_filterSizeMap.remove(tag);
_filterRecentEntryMap.remove(tag); _filterRecentEntryMap.remove(tag);
}); });
} }
@ -107,6 +110,10 @@ mixin TagMixin on SourceBase {
return _filterEntryCountMap.putIfAbsent(filter.tag, () => visibleEntries.where(filter.test).length); return _filterEntryCountMap.putIfAbsent(filter.tag, () => visibleEntries.where(filter.test).length);
} }
int tagSize(TagFilter filter) {
return _filterSizeMap.putIfAbsent(filter.tag, () => visibleEntries.where(filter.test).map((v) => v.sizeBytes).sum);
}
AvesEntry? tagRecentEntry(TagFilter filter) { AvesEntry? tagRecentEntry(TagFilter filter) {
return _filterRecentEntryMap.putIfAbsent(filter.tag, () => sortedEntriesByDate.firstWhereOrNull(filter.test)); return _filterRecentEntryMap.putIfAbsent(filter.tag, () => sortedEntriesByDate.firstWhereOrNull(filter.test));
} }

View file

@ -13,3 +13,7 @@ extension ExtraMapNullableKeyValue<K extends Object, V> on Map<K?, V?> {
Map<K?, V> whereNotNullValue() => <K?, V>{for (var kv in entries.where((kv) => kv.value != null)) kv.key: kv.value as V}; Map<K?, V> whereNotNullValue() => <K?, V>{for (var kv in entries.where((kv) => kv.value != null)) kv.key: kv.value as V};
} }
extension ExtraNumIterable on Iterable<int?> {
int get sum => fold(0, (prev, v) => prev + (v ?? 0));
}

View file

@ -518,10 +518,10 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
return TileViewDialog<EntrySortFactor, EntryGroupFactor, TileLayout>( return TileViewDialog<EntrySortFactor, EntryGroupFactor, TileLayout>(
initialValue: initialValue, initialValue: initialValue,
sortOptions: { sortOptions: {
EntrySortFactor.date: l10n.collectionSortDate, EntrySortFactor.date: l10n.sortByDate,
EntrySortFactor.size: l10n.collectionSortSize, EntrySortFactor.size: l10n.sortBySize,
EntrySortFactor.name: l10n.collectionSortName, EntrySortFactor.name: l10n.sortByAlbumFileName,
EntrySortFactor.rating: l10n.collectionSortRating, EntrySortFactor.rating: l10n.sortByRating,
}, },
groupOptions: { groupOptions: {
EntryGroupFactor.album: l10n.collectionGroupAlbum, EntryGroupFactor.album: l10n.collectionGroupAlbum,

View file

@ -137,14 +137,15 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
return TileViewDialog<ChipSortFactor, AlbumChipGroupFactor, TileLayout>( return TileViewDialog<ChipSortFactor, AlbumChipGroupFactor, TileLayout>(
initialValue: initialValue, initialValue: initialValue,
sortOptions: { sortOptions: {
ChipSortFactor.date: context.l10n.chipSortDate, ChipSortFactor.date: l10n.sortByDate,
ChipSortFactor.name: context.l10n.chipSortName, ChipSortFactor.name: l10n.sortByName,
ChipSortFactor.count: context.l10n.chipSortCount, ChipSortFactor.count: l10n.sortByItemCount,
ChipSortFactor.size: l10n.sortBySize,
}, },
groupOptions: { groupOptions: {
AlbumChipGroupFactor.importance: context.l10n.albumGroupTier, AlbumChipGroupFactor.importance: l10n.albumGroupTier,
AlbumChipGroupFactor.volume: context.l10n.albumGroupVolume, AlbumChipGroupFactor.volume: l10n.albumGroupVolume,
AlbumChipGroupFactor.none: context.l10n.albumGroupNone, AlbumChipGroupFactor.none: l10n.albumGroupNone,
}, },
layoutOptions: { layoutOptions: {
TileLayout.grid: l10n.tileLayoutGrid, TileLayout.grid: l10n.tileLayoutGrid,

View file

@ -206,9 +206,10 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
return TileViewDialog<ChipSortFactor, void, TileLayout>( return TileViewDialog<ChipSortFactor, void, TileLayout>(
initialValue: initialValue, initialValue: initialValue,
sortOptions: { sortOptions: {
ChipSortFactor.date: context.l10n.chipSortDate, ChipSortFactor.date: l10n.sortByDate,
ChipSortFactor.name: context.l10n.chipSortName, ChipSortFactor.name: l10n.sortByName,
ChipSortFactor.count: context.l10n.chipSortCount, ChipSortFactor.count: l10n.sortByItemCount,
ChipSortFactor.size: l10n.sortBySize,
}, },
layoutOptions: { layoutOptions: {
TileLayout.grid: l10n.tileLayoutGrid, TileLayout.grid: l10n.tileLayoutGrid,

View file

@ -1,6 +1,7 @@
import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/filters/filters.dart';
import 'package:aves/model/source/collection_source.dart'; import 'package:aves/model/source/collection_source.dart';
import 'package:aves/model/source/enums.dart'; import 'package:aves/model/source/enums.dart';
import 'package:aves/utils/file_utils.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/grid/draggable_thumb_label.dart'; import 'package:aves/widgets/common/grid/draggable_thumb_label.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -22,10 +23,6 @@ class FilterDraggableThumbLabel<T extends CollectionFilter> extends StatelessWid
offsetY: offsetY, offsetY: offsetY,
lineBuilder: (context, filterGridItem) { lineBuilder: (context, filterGridItem) {
switch (sortFactor) { switch (sortFactor) {
case ChipSortFactor.count:
return [
context.l10n.itemCount(context.read<CollectionSource>().count(filterGridItem.filter)),
];
case ChipSortFactor.date: case ChipSortFactor.date:
return [ return [
DraggableThumbLabel.formatMonthThumbLabel(context, filterGridItem.entry?.bestDate), DraggableThumbLabel.formatMonthThumbLabel(context, filterGridItem.entry?.bestDate),
@ -34,6 +31,15 @@ class FilterDraggableThumbLabel<T extends CollectionFilter> extends StatelessWid
return [ return [
filterGridItem.filter.getLabel(context), filterGridItem.filter.getLabel(context),
]; ];
case ChipSortFactor.count:
return [
context.l10n.itemCount(context.read<CollectionSource>().count(filterGridItem.filter)),
];
case ChipSortFactor.size:
final locale = context.l10n.localeName;
return [
formatFileSize(locale, context.read<CollectionSource>().size(filterGridItem.filter)),
];
} }
}, },
); );

View file

@ -47,6 +47,11 @@ class FilterNavigationPage<T extends CollectionFilter, CSAD extends ChipSetActio
return c != 0 ? c : a.key.compareTo(b.key); return c != 0 ? c : a.key.compareTo(b.key);
} }
static int compareFiltersBySize(MapEntry<CollectionFilter, num> a, MapEntry<CollectionFilter, num> b) {
final c = b.value.compareTo(a.value);
return c != 0 ? c : a.key.compareTo(b.key);
}
static int compareFiltersByName(FilterGridItem<CollectionFilter> a, FilterGridItem<CollectionFilter> b) { static int compareFiltersByName(FilterGridItem<CollectionFilter> a, FilterGridItem<CollectionFilter> b) {
return a.filter.compareTo(b.filter); return a.filter.compareTo(b.filter);
} }
@ -75,6 +80,12 @@ class FilterNavigationPage<T extends CollectionFilter, CSAD extends ChipSetActio
filters = filtersWithCount.map((kv) => kv.key).toSet(); filters = filtersWithCount.map((kv) => kv.key).toSet();
allMapEntries = toGridItem(source, filters); allMapEntries = toGridItem(source, filters);
break; break;
case ChipSortFactor.size:
final filtersWithSize = List.of(filters.map((filter) => MapEntry(filter, source.size(filter))));
filtersWithSize.sort(compareFiltersBySize);
filters = filtersWithSize.map((kv) => kv.key).toSet();
allMapEntries = toGridItem(source, filters);
break;
} }
return allMapEntries; return allMapEntries;
} }

View file

@ -6,6 +6,7 @@ import 'package:aves/theme/format.dart';
import 'package:aves/theme/icons.dart'; import 'package:aves/theme/icons.dart';
import 'package:aves/utils/android_file_utils.dart'; import 'package:aves/utils/android_file_utils.dart';
import 'package:aves/utils/constants.dart'; import 'package:aves/utils/constants.dart';
import 'package:aves/utils/file_utils.dart';
import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/fx/borders.dart'; import 'package:aves/widgets/common/fx/borders.dart';
import 'package:aves/widgets/filter_grids/common/list_details_theme.dart'; import 'package:aves/widgets/filter_grids/common/list_details_theme.dart';
@ -140,6 +141,10 @@ class FilterListDetails<T extends CollectionFilter> extends StatelessWidget {
child: Center(child: leading ?? const SizedBox()), child: Center(child: leading ?? const SizedBox()),
); );
final l10n = context.l10n;
final locale = l10n.localeName;
final source = context.read<CollectionSource>();
return IconTheme.merge( return IconTheme.merge(
data: detailsTheme.captionIconTheme, data: detailsTheme.captionIconTheme,
child: Row( child: Row(
@ -147,7 +152,7 @@ class FilterListDetails<T extends CollectionFilter> extends StatelessWidget {
leading, leading,
const SizedBox(width: 8), const SizedBox(width: 8),
Text( Text(
context.l10n.itemCount(context.read<CollectionSource>().count(filter)), '${l10n.itemCount(source.count(filter))}${formatFileSize(locale, source.size(filter))}',
style: detailsTheme.captionStyle, style: detailsTheme.captionStyle,
strutStyle: Constants.overflowStrutStyle, strutStyle: Constants.overflowStrutStyle,
softWrap: false, softWrap: false,

View file

@ -48,7 +48,7 @@ class _MimeDonutState extends State<MimeDonut> with AutomaticKeepAliveClientMixi
final locale = l10n.localeName; final locale = l10n.localeName;
final numberFormat = NumberFormat.decimalPattern(locale); final numberFormat = NumberFormat.decimalPattern(locale);
final sum = byMimeTypes.values.fold<int>(0, (prev, v) => prev + v); final sum = byMimeTypes.values.sum;
final colors = context.watch<AvesColorsData>(); final colors = context.watch<AvesColorsData>();
final seriesData = byMimeTypes.entries.map((kv) { final seriesData = byMimeTypes.entries.map((kv) {