New class to store only date when time is not needed

This commit is contained in:
Ming Ming 2024-03-30 18:07:53 +08:00
parent da00a4f3ad
commit 25ef1a94f9
14 changed files with 160 additions and 47 deletions

View file

@ -1,4 +1,3 @@
import 'package:clock/clock.dart';
import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
import 'package:logging/logging.dart';
@ -14,6 +13,7 @@ import 'package:nc_photos/widget/photo_list_item.dart';
import 'package:nc_photos/widget/photo_list_util.dart';
import 'package:nc_photos/widget/selectable_item_stream_list_mixin.dart';
import 'package:np_codegen/np_codegen.dart';
import 'package:np_datetime/np_datetime.dart';
part 'photo_list_item_builder.g.dart';
@ -135,7 +135,7 @@ class _PhotoListItemBuilder {
PhotoListItemBuilderResult _fromSortedItems(
Account account, List<FileDescriptor> files) {
final today = clock.now();
final today = Date.today();
final memoryAlbumHelper = smartAlbumConfig != null
? MemoryCollectionHelper(account,
today: today, dayRange: smartAlbumConfig!.memoriesDayRange)

View file

@ -62,6 +62,7 @@ import 'package:nc_photos/widget/sliver_visualized_scale.dart';
import 'package:nc_photos/widget/viewer.dart';
import 'package:np_codegen/np_codegen.dart';
import 'package:np_common/or_null.dart';
import 'package:np_datetime/np_datetime.dart';
import 'package:np_ui/np_ui.dart';
import 'package:to_string/to_string.dart';

View file

@ -172,7 +172,7 @@ class _DateItem extends _Item {
);
}
final DateTime date;
final Date date;
}
@toString

View file

@ -376,7 +376,7 @@ _ItemTransformerResult _buildItem(_ItemTransformerArgument arg) {
final dateHelper = arg.sort == _ItemSort.dateTime
? photo_list_util.DateGroupHelper(isMonthOnly: !arg.isGroupByDay)
: null;
final today = clock.now();
final today = Date.today();
final memoryCollectionHelper = arg.sort == _ItemSort.dateTime
? photo_list_util.MemoryCollectionHelper(
arg.account,
@ -393,7 +393,7 @@ _ItemTransformerResult _buildItem(_ItemTransformerArgument arg) {
if (item == null) {
continue;
}
final localDate = file.fdDateTime.add(tzOffset);
final localDate = file.fdDateTime.add(tzOffset).toDate();
final date = dateHelper?.onFile(file, localDate: localDate);
if (date != null) {
transformed.add(_DateItem(date: date, isMonthOnly: !arg.isGroupByDay));

View file

@ -93,7 +93,7 @@ class _DateItem extends _Item {
);
}
final DateTime date;
final Date date;
final bool isMonthOnly;
}

View file

@ -55,6 +55,7 @@ import 'package:np_codegen/np_codegen.dart';
import 'package:np_collection/np_collection.dart';
import 'package:np_common/object_util.dart';
import 'package:np_common/or_null.dart';
import 'package:np_datetime/np_datetime.dart';
import 'package:to_string/to_string.dart';
import 'package:visibility_detector/visibility_detector.dart';

View file

@ -12,6 +12,7 @@ import 'package:nc_photos/mobile/android/content_uri_image_provider.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/widget/network_thumbnail.dart';
import 'package:nc_photos/widget/selectable_item_stream_list_mixin.dart';
import 'package:np_datetime/np_datetime.dart';
import 'package:to_string/to_string.dart';
part 'photo_list_item.g.dart';
@ -116,7 +117,7 @@ class PhotoListDateItem extends SelectableItem {
isMonthOnly: isMonthOnly,
);
final DateTime date;
final Date date;
final bool isMonthOnly;
}
@ -392,18 +393,18 @@ class PhotoListLabelEdit extends PhotoListLabel {
class PhotoListDate extends StatelessWidget {
const PhotoListDate({
Key? key,
super.key,
required this.date,
this.isMonthOnly = false,
}) : super(key: key);
});
@override
build(BuildContext context) {
Widget build(BuildContext context) {
final pattern =
isMonthOnly ? DateFormat.YEAR_MONTH : DateFormat.YEAR_MONTH_DAY;
final subtitle =
DateFormat(pattern, Localizations.localeOf(context).languageCode)
.format(date.toLocal());
.format(date.toUtcDateTime());
return Align(
alignment: AlignmentDirectional.centerStart,
child: Padding(
@ -416,6 +417,6 @@ class PhotoListDate extends StatelessWidget {
);
}
final DateTime date;
final Date date;
final bool isMonthOnly;
}

View file

@ -9,6 +9,7 @@ import 'package:nc_photos/entity/collection.dart';
import 'package:nc_photos/entity/collection/content_provider/memory.dart';
import 'package:nc_photos/entity/file_descriptor.dart';
import 'package:np_codegen/np_codegen.dart';
import 'package:np_datetime/np_datetime.dart';
part 'photo_list_util.g.dart';
@ -17,13 +18,13 @@ class DateGroupHelper {
required this.isMonthOnly,
}) : _tzOffset = clock.now().timeZoneOffset;
DateTime? onFile(
Date? onFile(
FileDescriptor file, {
DateTime? localDate,
Date? localDate,
}) {
// toLocal is way too slow
// final localDate = file.fdDateTime.toLocal();
localDate ??= file.fdDateTime.add(_tzOffset);
localDate ??= file.fdDateTime.add(_tzOffset).toDate();
if (localDate.year != _currentDate?.year ||
localDate.month != _currentDate?.month ||
(!isMonthOnly && localDate.day != _currentDate?.day)) {
@ -35,7 +36,7 @@ class DateGroupHelper {
}
final bool isMonthOnly;
DateTime? _currentDate;
Date? _currentDate;
final Duration _tzOffset;
}
@ -46,21 +47,21 @@ class DateGroupHelper {
class MemoryCollectionHelper {
MemoryCollectionHelper(
this.account, {
DateTime? today,
Date? today,
required int dayRange,
}) : _tzOffset = clock.now().timeZoneOffset,
// today = (today?.toLocal() ?? clock.now()).toMidnight(),
dayRange = math.max(dayRange, 0) {
this.today = (today ?? clock.now()).toUtc().add(_tzOffset).toMidnight();
this.today = today ?? Date.today();
}
void addFile(
FileDescriptor f, {
DateTime? localDate,
Date? localDate,
}) {
// too slow
// final localDate = f.fdDateTime.toLocal().toMidnight();
localDate = (localDate ?? f.fdDateTime.add(_tzOffset)).toMidnight();
localDate ??= f.fdDateTime.add(_tzOffset).toDate();
final diff = today.difference(localDate).inDays;
if (diff < 300) {
return;
@ -115,7 +116,7 @@ class MemoryCollectionHelper {
}
final Account account;
late final DateTime today;
late final Date today;
final int dayRange;
final Duration _tzOffset;
final _data = <int, _MemoryCollectionHelperItem>{};
@ -142,10 +143,14 @@ class _MemoryCollectionHelperItem {
_MemoryCollectionHelperItem(this.date, this.coverFile)
: coverDiff = getCoverDiff(date, coverFile);
static Duration getCoverDiff(DateTime date, FileDescriptor f) =>
f.fdDateTime.difference(date.copyWith(hour: 12)).abs();
static Duration getCoverDiff(Date date, FileDescriptor f) => f.fdDateTime
.add(_tzOffset)
.difference(date.toLocalDateTime().copyWith(hour: 12))
.abs();
final DateTime date;
final Date date;
FileDescriptor coverFile;
Duration coverDiff;
static final Duration _tzOffset = clock.now().timeZoneOffset;
}

View file

@ -1,6 +1,7 @@
import 'package:nc_photos/entity/collection.dart';
import 'package:nc_photos/entity/collection/content_provider/memory.dart';
import 'package:nc_photos/widget/photo_list_util.dart';
import 'package:np_datetime/np_datetime.dart';
import 'package:test/test.dart';
import '../test_util.dart' as util;
@ -52,7 +53,7 @@ void main() {
/// Expect: empty
void _sameYear() {
final account = util.buildAccount();
final today = DateTime(2021, 2, 3);
final today = Date(2021, 2, 3);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2021, 2, 3));
@ -68,7 +69,7 @@ void _sameYear() {
/// Expect: empty
void _nextYear() {
final account = util.buildAccount();
final today = DateTime(2021, 2, 3);
final today = Date(2021, 2, 3);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2022, 2, 3));
@ -83,7 +84,7 @@ void _nextYear() {
/// Expect: [2020]
void _prevYear() {
final account = util.buildAccount();
final today = DateTime(2021, 2, 3);
final today = Date(2021, 2, 3);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 3));
@ -107,7 +108,7 @@ void _prevYear() {
/// Expect: empty
void _prevYear3DaysBefore() {
final account = util.buildAccount();
final today = DateTime(2021, 2, 3);
final today = Date(2021, 2, 3);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2020, 1, 31));
@ -122,7 +123,7 @@ void _prevYear3DaysBefore() {
/// Expect: [2020]
void _prevYear2DaysBefore() {
final account = util.buildAccount();
final today = DateTime(2021, 2, 3);
final today = Date(2021, 2, 3);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 1));
@ -146,7 +147,7 @@ void _prevYear2DaysBefore() {
/// Expect: empty
void _prevYear3DaysAfter() {
final account = util.buildAccount();
final today = DateTime(2021, 2, 3);
final today = Date(2021, 2, 3);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 6));
@ -161,7 +162,7 @@ void _prevYear3DaysAfter() {
/// Expect: [2020]
void _prevYear2DaysAfter() {
final account = util.buildAccount();
final today = DateTime(2021, 2, 3);
final today = Date(2021, 2, 3);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 5));
@ -185,7 +186,7 @@ void _prevYear2DaysAfter() {
/// Expect: empty
void _onFeb29AddFeb26() {
final account = util.buildAccount();
final today = DateTime(2020, 2, 29);
final today = Date(2020, 2, 29);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2019, 2, 26));
@ -200,7 +201,7 @@ void _onFeb29AddFeb26() {
/// Expect: [2019]
void _onFeb29AddFeb27() {
final account = util.buildAccount();
final today = DateTime(2020, 2, 29);
final today = Date(2020, 2, 29);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2019, 2, 27));
@ -224,7 +225,7 @@ void _onFeb29AddFeb27() {
/// Expect: empty
void _onFeb29AddMar4() {
final account = util.buildAccount();
final today = DateTime(2020, 2, 29);
final today = Date(2020, 2, 29);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2019, 3, 4));
@ -239,7 +240,7 @@ void _onFeb29AddMar4() {
/// Expect: [2019]
void _onFeb29AddMar3() {
final account = util.buildAccount();
final today = DateTime(2020, 2, 29);
final today = Date(2020, 2, 29);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2019, 3, 3));
@ -263,7 +264,7 @@ void _onFeb29AddMar3() {
/// Expect: empty
void _onFeb29AddMar3LeapYear() {
final account = util.buildAccount();
final today = DateTime(2020, 2, 29);
final today = Date(2020, 2, 29);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2016, 3, 3));
@ -278,7 +279,7 @@ void _onFeb29AddMar3LeapYear() {
/// Expect: [2016]
void _onFeb29AddMar2LeapYear() {
final account = util.buildAccount();
final today = DateTime(2020, 2, 29);
final today = Date(2020, 2, 29);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2016, 3, 2));
@ -302,7 +303,7 @@ void _onFeb29AddMar2LeapYear() {
/// Expect: empty
void _onJan1AddDec31() {
final account = util.buildAccount();
final today = DateTime(2020, 1, 1);
final today = Date(2020, 1, 1);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2019, 12, 31));
@ -317,7 +318,7 @@ void _onJan1AddDec31() {
/// Expect: [2019]
void _onJan1AddDec31PrevYear() {
final account = util.buildAccount();
final today = DateTime(2020, 1, 1);
final today = Date(2020, 1, 1);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2018, 12, 31));
@ -341,7 +342,7 @@ void _onJan1AddDec31PrevYear() {
/// Expect: [2019]
void _onDec31AddJan1() {
final account = util.buildAccount();
final today = DateTime(2020, 12, 31);
final today = Date(2020, 12, 31);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 2);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2020, 1, 1));
@ -365,7 +366,7 @@ void _onDec31AddJan1() {
/// Expect: [2022]
void _onMay15AddMay15Range0() {
final account = util.buildAccount();
final today = DateTime(2022, 5, 15);
final today = Date(2022, 5, 15);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 0);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2021, 5, 15));
@ -389,7 +390,7 @@ void _onMay15AddMay15Range0() {
/// Expect: []
void _onMay15AddMay16Range0() {
final account = util.buildAccount();
final today = DateTime(2022, 5, 15);
final today = Date(2022, 5, 15);
final obj = MemoryCollectionHelper(account, today: today, dayRange: 0);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2021, 5, 16));
@ -404,7 +405,7 @@ void _onMay15AddMay16Range0() {
/// Expect: []
void _onMay15AddMay16RangeNegative() {
final account = util.buildAccount();
final today = DateTime(2022, 5, 15);
final today = Date(2022, 5, 15);
final obj = MemoryCollectionHelper(account, today: today, dayRange: -1);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2021, 5, 16));

View file

@ -1,3 +1,4 @@
library np_datetime;
export 'src/date.dart';
export 'src/time_range.dart';

View file

@ -0,0 +1,100 @@
import 'package:clock/clock.dart';
/// A calendar date with no timezone information
class Date implements Comparable<Date> {
factory Date(int year, [int month = 1, int day = 1]) {
final d = DateTime.utc(year, month, day);
return Date._unchecked(d.year, d.month, d.day);
}
const Date._unchecked(this.year, [this.month = 1, this.day = 1]);
/// Convert a [DateTime] object to [Date]. The data is taken from [dateTime]
/// as-is, the timezone will not be considered
static Date fromDateTime(DateTime dateTime) =>
Date._unchecked(dateTime.year, dateTime.month, dateTime.day);
static Date today() => fromDateTime(clock.now());
Date copyWith({
int? year,
int? month,
int? day,
}) {
return Date(year ?? this.year, month ?? this.month, day ?? this.day);
}
DateTime toUtcDateTime() => DateTime.utc(year, month, day);
DateTime toLocalDateTime() => DateTime(year, month, day);
@override
int compareTo(Date other) => toUtcDateTime().compareTo(other.toUtcDateTime());
@override
String toString() => "$day/$month/$year";
@override
bool operator ==(Object other) =>
other is Date &&
year == other.year &&
month == other.month &&
day == other.day;
@override
int get hashCode => Object.hash(year, month, day);
final int year;
final int month;
final int day;
}
extension DateExtension on Date {
Date add({
int? year,
int? month,
int? day,
}) {
final d = DateTime.utc(this.year + (year ?? 0), this.month + (month ?? 0),
this.day + (day ?? 0));
return Date(d.year, d.month, d.day);
}
Duration difference(Date other) =>
toUtcDateTime().difference(other.toUtcDateTime());
bool isBefore(Date other) {
if (year > other.year) {
return false;
} else if (year < other.year) {
return true;
}
if (month > other.month) {
return false;
} else if (month < other.month) {
return true;
}
return day < other.day;
}
bool isBeforeOrAt(Date other) => !isAfter(other);
bool isAfter(Date other) {
if (year < other.year) {
return false;
} else if (year > other.year) {
return true;
}
if (month < other.month) {
return false;
} else if (month > other.month) {
return true;
}
return day > other.day;
}
bool isAfterOrAt(Date other) => !isBefore(other);
}
extension DateTimeDateExtension on DateTime {
Date toDate() => Date.fromDateTime(this);
}

View file

@ -7,6 +7,9 @@ publish_to: none
environment:
sdk: '>=2.19.6 <3.0.0'
dependencies:
clock: ^1.1.1
dev_dependencies:
np_lints:
path: ../np_lints

View file

@ -148,7 +148,7 @@ class DbFilesSummary {
String toString() => _$toString();
@Format(r"{length: ${$?.length}}")
final Map<DateTime, DbFilesSummaryItem> items;
final Map<Date, DbFilesSummaryItem> items;
}
@npLog

View file

@ -45,7 +45,7 @@ class CountFileGroupsByDateResult {
required this.dateCount,
});
final Map<DateTime, int> dateCount;
final Map<Date, int> dateCount;
}
extension SqliteDbFileExtension on SqliteDb {
@ -657,8 +657,8 @@ extension SqliteDbFileExtension on SqliteDb {
..orderBy([OrderingTerm.desc(accountFiles.bestDateTime)])
..groupBy([localDate]);
final results = await query
.map((r) => MapEntry<DateTime, int>(
DateTime.parse(r.read(localDate)!),
.map((r) => MapEntry<Date, int>(
DateTime.parse(r.read(localDate)!).toDate(),
r.read(count)!,
))
.get();