#684 stats: added total size

This commit is contained in:
Thibault Deckers 2023-07-12 23:00:20 +02:00
parent 157d2b2738
commit 7e51f7f5c8

View file

@ -13,6 +13,7 @@ import 'package:aves/model/source/collection_source.dart';
import 'package:aves/theme/durations.dart'; import 'package:aves/theme/durations.dart';
import 'package:aves/theme/icons.dart'; import 'package:aves/theme/icons.dart';
import 'package:aves/theme/styles.dart'; import 'package:aves/theme/styles.dart';
import 'package:aves/utils/file_utils.dart';
import 'package:aves/widgets/collection/collection_page.dart'; import 'package:aves/widgets/collection/collection_page.dart';
import 'package:aves/widgets/common/action_mixins/feedback.dart'; import 'package:aves/widgets/common/action_mixins/feedback.dart';
import 'package:aves/widgets/common/action_mixins/vault_aware.dart'; import 'package:aves/widgets/common/action_mixins/vault_aware.dart';
@ -58,6 +59,7 @@ class _StatsPageState extends State<StatsPage> with FeedbackMixin, VaultAwareMix
final Map<String, int> _entryCountPerTag = {}, _entryCountPerAlbum = {}; final Map<String, int> _entryCountPerTag = {}, _entryCountPerAlbum = {};
final Map<int, int> _entryCountPerRating = Map.fromEntries(List.generate(7, (i) => MapEntry(5 - i, 0))); final Map<int, int> _entryCountPerRating = Map.fromEntries(List.generate(7, (i) => MapEntry(5 - i, 0)));
late final ValueNotifier<bool> _isPageAnimatingNotifier; late final ValueNotifier<bool> _isPageAnimatingNotifier;
int _totalSizeBytes = 0;
Set<AvesEntry> get entries => widget.entries; Set<AvesEntry> get entries => widget.entries;
@ -72,6 +74,8 @@ class _StatsPageState extends State<StatsPage> with FeedbackMixin, VaultAwareMix
}); });
entries.forEach((entry) { entries.forEach((entry) {
_totalSizeBytes += entry.sizeBytes ?? 0;
if (entry.hasAddress) { if (entry.hasAddress) {
final address = entry.addressDetails!; final address = entry.addressDetails!;
var country = address.countryName; var country = address.countryName;
@ -123,7 +127,6 @@ class _StatsPageState extends State<StatsPage> with FeedbackMixin, VaultAwareMix
text: l10n.collectionEmptyImages, text: l10n.collectionEmptyImages,
); );
} else { } else {
final theme = Theme.of(context);
final chartAnimationDuration = context.read<DurationsData>().chartTransition; final chartAnimationDuration = context.read<DurationsData>().chartTransition;
final byMimeTypes = groupBy<AvesEntry, String>(entries, (entry) => entry.mimeType).map<String, int>((k, v) => MapEntry(k, v.length)); final byMimeTypes = groupBy<AvesEntry, String>(entries, (entry) => entry.mimeType).map<String, int>((k, v) => MapEntry(k, v.length));
@ -148,48 +151,21 @@ class _StatsPageState extends State<StatsPage> with FeedbackMixin, VaultAwareMix
], ],
); );
final catalogued = entries.where((entry) => entry.isCatalogued); final showRatings = _entryCountPerRating.entries.any((kv) => kv.key != 0 && kv.value > 0);
final withGps = catalogued.where((entry) => entry.hasGps); final source = widget.source;
final withGpsCount = withGps.length; final sizeIndicator = Padding(
final withGpsPercent = withGpsCount / entries.length; padding: const EdgeInsets.symmetric(horizontal: 16),
final textScaleFactor = MediaQuery.textScaleFactorOf(context); child: Row(
final lineHeight = 16 * textScaleFactor; mainAxisSize: MainAxisSize.min,
final barRadius = Radius.circular(lineHeight / 2);
final locationIndicator = Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [ children: [
Row( const Icon(AIcons.size),
mainAxisSize: MainAxisSize.min, const SizedBox(width: 16),
children: [ Expanded(
const Icon(AIcons.location), child: Text(formatFileSize(l10n.localeName, _totalSizeBytes)),
Expanded(
child: LinearPercentIndicator(
percent: withGpsPercent,
lineHeight: lineHeight,
backgroundColor: theme.colorScheme.onPrimary.withOpacity(.1),
progressColor: theme.colorScheme.secondary,
animation: context.select<Settings, bool>((v) => v.accessibilityAnimations.animate),
isRTL: context.isRtl,
barRadius: barRadius,
center: LinearPercentIndicatorText(percent: withGpsPercent),
padding: EdgeInsets.symmetric(horizontal: lineHeight),
),
),
// end padding to match leading, so that inside label is aligned with outside label below
const SizedBox(width: 24),
],
),
const SizedBox(height: 8),
Text(
l10n.statsWithGps(withGpsCount),
textAlign: TextAlign.center,
), ),
], ],
), ),
); );
final showRatings = _entryCountPerRating.entries.any((kv) => kv.key != 0 && kv.value > 0);
final source = widget.source;
child = NotificationListener<ReverseFilterNotification>( child = NotificationListener<ReverseFilterNotification>(
onNotification: (notification) { onNotification: (notification) {
_onFilterSelection(context, notification.reversedFilter); _onFilterSelection(context, notification.reversedFilter);
@ -214,7 +190,10 @@ class _StatsPageState extends State<StatsPage> with FeedbackMixin, VaultAwareMix
animationDuration: chartAnimationDuration, animationDuration: chartAnimationDuration,
onFilterSelection: (filter) => _onFilterSelection(context, filter), onFilterSelection: (filter) => _onFilterSelection(context, filter),
), ),
locationIndicator, const SizedBox(height: 16),
sizeIndicator,
const SizedBox(height: 16),
_LocationIndicator(entries: entries),
..._buildFilterSection<String>(context, l10n.statsTopCountriesSectionTitle, _entryCountPerCountry, (v) => LocationFilter(LocationLevel.country, v)), ..._buildFilterSection<String>(context, l10n.statsTopCountriesSectionTitle, _entryCountPerCountry, (v) => LocationFilter(LocationLevel.country, v)),
..._buildFilterSection<String>(context, l10n.statsTopStatesSectionTitle, _entryCountPerState, (v) => LocationFilter(LocationLevel.state, v)), ..._buildFilterSection<String>(context, l10n.statsTopStatesSectionTitle, _entryCountPerState, (v) => LocationFilter(LocationLevel.state, v)),
..._buildFilterSection<String>(context, l10n.statsTopPlacesSectionTitle, _entryCountPerPlace, (v) => LocationFilter(LocationLevel.place, v)), ..._buildFilterSection<String>(context, l10n.statsTopPlacesSectionTitle, _entryCountPerPlace, (v) => LocationFilter(LocationLevel.place, v)),
@ -418,3 +397,54 @@ class StatsTopPage extends StatelessWidget {
); );
} }
} }
class _LocationIndicator extends StatelessWidget {
final Set<AvesEntry> entries;
const _LocationIndicator({required this.entries});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final catalogued = entries.where((entry) => entry.isCatalogued);
final withGps = catalogued.where((entry) => entry.hasGps);
final withGpsCount = withGps.length;
final withGpsPercent = withGpsCount / entries.length;
final textScaleFactor = MediaQuery.textScaleFactorOf(context);
final lineHeight = 16 * textScaleFactor;
final barRadius = Radius.circular(lineHeight / 2);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(AIcons.location),
Expanded(
child: LinearPercentIndicator(
percent: withGpsPercent,
lineHeight: lineHeight,
backgroundColor: theme.colorScheme.onPrimary.withOpacity(.1),
progressColor: theme.colorScheme.secondary,
animation: context.select<Settings, bool>((v) => v.accessibilityAnimations.animate),
isRTL: context.isRtl,
barRadius: barRadius,
center: LinearPercentIndicatorText(percent: withGpsPercent),
padding: EdgeInsets.symmetric(horizontal: lineHeight),
),
),
// end padding to match leading, so that inside label is aligned with outside label below
const SizedBox(width: 24),
],
),
const SizedBox(height: 8),
Text(
context.l10n.statsWithGps(withGpsCount),
textAlign: TextAlign.center,
),
],
),
);
}
}