stats: fixed histogram when crossing DST boundaries

This commit is contained in:
Thibault Deckers 2024-04-21 19:35:53 +02:00
parent 94eccbd2f1
commit 2bb52143cd
5 changed files with 15 additions and 6 deletions

View file

@ -10,6 +10,7 @@ import 'package:aves/ref/unicode.dart';
import 'package:aves/services/common/services.dart';
import 'package:aves/theme/text.dart';
import 'package:aves/utils/android_file_utils.dart';
import 'package:aves/utils/time_utils.dart';
extension ExtraAvesEntryProps on AvesEntry {
bool get isValid => !isMissingAtPath && sizeBytes != 0 && width > 0 && height > 0;
@ -85,7 +86,7 @@ extension ExtraAvesEntryProps on AvesEntry {
int? get trashDaysLeft {
final dateMillis = trashDetails?.dateMillis;
if (dateMillis == null) return null;
return DateTime.fromMillisecondsSinceEpoch(dateMillis).add(TrashMixin.binKeepDuration).difference(DateTime.now()).inDays;
return DateTime.fromMillisecondsSinceEpoch(dateMillis).add(TrashMixin.binKeepDuration).difference(DateTime.now()).inHumanDays;
}
// storage

View file

@ -26,6 +26,12 @@ extension ExtraDateTime on DateTime {
DateTime addDays(int days) => DateTime(year, month, day + days, hour, minute, second, millisecond, microsecond);
}
extension ExtraDuration on Duration {
// using `Duration.inDays` may yield surprising results when crossing DST boundaries
// because a day will not have 24 hours, so we use the following approximation instead
int get inHumanDays => (inMicroseconds / Duration.microsecondsPerDay).round();
}
final epoch = DateTime.fromMillisecondsSinceEpoch(0, isUtc: true);
// Overflowing timestamps that are supposed to be in milliseconds

View file

@ -14,6 +14,7 @@ import 'package:aves/model/source/section_keys.dart';
import 'package:aves/ref/mime_types.dart';
import 'package:aves/theme/durations.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/utils/time_utils.dart';
import 'package:aves/widgets/collection/app_bar.dart';
import 'package:aves/widgets/collection/draggable_thumb_label.dart';
import 'package:aves/widgets/collection/grid/list_details_theme.dart';
@ -673,7 +674,7 @@ class _CollectionScrollViewState extends State<_CollectionScrollView> with Widge
final oldest = lastKey.date;
if (newest != null && oldest != null) {
final locale = context.l10n.localeName;
final dateFormat = (newest.difference(oldest).inDays).abs() > 365 ? DateFormat.y(locale) : DateFormat.MMM(locale);
final dateFormat = (newest.difference(oldest).inHumanDays).abs() > 365 ? DateFormat.y(locale) : DateFormat.MMM(locale);
String? lastLabel;
sectionLayouts.forEach((section) {
final date = (section.sectionKey as EntryDateSectionKey).date;

View file

@ -34,7 +34,7 @@ class TimeAxisSpec {
first = first.date;
last = last.date;
final rangeDays = last.difference(first).inDays;
final rangeDays = last.difference(first).inHumanDays;
final delta = max(1, (rangeDays / 5).ceil());
List<charts.TickSpec<DateTime>> ticks = [];

View file

@ -5,6 +5,7 @@ import 'package:aves/model/entry/entry.dart';
import 'package:aves/model/entry/sort.dart';
import 'package:aves/model/filters/date.dart';
import 'package:aves/theme/durations.dart';
import 'package:aves/utils/time_utils.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/fx/transitions.dart';
import 'package:aves/widgets/common/identity/aves_filter_chip.dart';
@ -56,7 +57,7 @@ class _HistogramState extends State<Histogram> with AutomaticKeepAliveClientMixi
var firstDate = entriesByDateDescending.lastWhereOrNull((entry) => entry.bestDate != null)?.bestDate;
if (lastDate != null && firstDate != null) {
final rangeDays = lastDate.difference(firstDate).inDays;
final rangeDays = lastDate.difference(firstDate).inHumanDays;
if (rangeDays > 1) {
if (rangeDays <= 31) {
_level = DateLevel.ymd;
@ -113,10 +114,10 @@ class _HistogramState extends State<Histogram> with AutomaticKeepAliveClientMixi
late DateTime Function(DateTime date) incrementDate;
switch (level) {
case DateLevel.ymd:
xCount = xRange.inDays;
xCount = xRange.inHumanDays;
incrementDate = (date) => DateTime(date.year, date.month, date.day + 1);
case DateLevel.ym:
xCount = (xRange.inDays / 30.5).round();
xCount = (xRange.inHumanDays / 30.5).round();
incrementDate = (date) => DateTime(date.year, date.month + 1);
default:
xCount = lastDate.year - firstDate.year;