Set day range of memory albums

This commit is contained in:
Ming Ming 2022-09-05 12:49:26 +08:00
parent 3040cd123e
commit e320b6b741
9 changed files with 271 additions and 30 deletions

View file

@ -371,6 +371,19 @@
"@settingsPhotosPageTitle": { "@settingsPhotosPageTitle": {
"description": "Dedicated page for settings related to the Photos tab" "description": "Dedicated page for settings related to the Photos tab"
}, },
"settingsMemoriesRangeTitle": "Memories range",
"@settingsMemoriesRangeTitle": {
"description": "How many adjacent days to be inclded in memories for a particular year"
},
"settingsMemoriesRangeValueText": "{range, plural, =1{+-{range} day} other{+-{range} days}}",
"@settingsMemoriesRangeValueText": {
"description": "How many adjacent days to be inclded in memories for a particular year, could be 0",
"placeholders": {
"range": {
"example": "1"
}
}
},
"settingsViewerTitle": "Viewer", "settingsViewerTitle": "Viewer",
"settingsViewerDescription": "Customize the image/video viewer", "settingsViewerDescription": "Customize the image/video viewer",
"settingsViewerPageTitle": "Viewer settings", "settingsViewerPageTitle": "Viewer settings",
@ -1401,7 +1414,6 @@
"@collectionPlacesLabel": { "@collectionPlacesLabel": {
"description": "Browse photos grouped by place" "description": "Browse photos grouped by place"
}, },
"errorUnauthenticated": "Unauthenticated access. Please sign-in again if the problem continues", "errorUnauthenticated": "Unauthenticated access. Please sign-in again if the problem continues",
"@errorUnauthenticated": { "@errorUnauthenticated": {
"description": "Error message when server responds with HTTP401" "description": "Error message when server responds with HTTP401"

View file

@ -17,6 +17,8 @@
"settingsServerAppSectionTitle", "settingsServerAppSectionTitle",
"settingsPhotosDescription", "settingsPhotosDescription",
"settingsPhotosPageTitle", "settingsPhotosPageTitle",
"settingsMemoriesRangeTitle",
"settingsMemoriesRangeValueText",
"settingsMapProviderTitle", "settingsMapProviderTitle",
"settingsAlbumTitle", "settingsAlbumTitle",
"settingsAlbumDescription", "settingsAlbumDescription",
@ -170,6 +172,8 @@
"settingsServerAppSectionTitle", "settingsServerAppSectionTitle",
"settingsPhotosDescription", "settingsPhotosDescription",
"settingsPhotosPageTitle", "settingsPhotosPageTitle",
"settingsMemoriesRangeTitle",
"settingsMemoriesRangeValueText",
"settingsMapProviderTitle", "settingsMapProviderTitle",
"settingsAlbumTitle", "settingsAlbumTitle",
"settingsAlbumDescription", "settingsAlbumDescription",
@ -327,6 +331,8 @@
"settingsAccountLabelDescription", "settingsAccountLabelDescription",
"settingsPhotosDescription", "settingsPhotosDescription",
"settingsPhotosPageTitle", "settingsPhotosPageTitle",
"settingsMemoriesRangeTitle",
"settingsMemoriesRangeValueText",
"settingsDoubleTapExitTitle", "settingsDoubleTapExitTitle",
"enhanceStyleTransferStyleDialogTitle", "enhanceStyleTransferStyleDialogTitle",
"doubleTapExitNotification", "doubleTapExitNotification",
@ -370,6 +376,8 @@
"settingsLanguageOptionSystemDefaultLabel", "settingsLanguageOptionSystemDefaultLabel",
"settingsPhotosDescription", "settingsPhotosDescription",
"settingsPhotosPageTitle", "settingsPhotosPageTitle",
"settingsMemoriesRangeTitle",
"settingsMemoriesRangeValueText",
"rootPickerSkipConfirmationDialogContent2", "rootPickerSkipConfirmationDialogContent2",
"showAllButtonLabel", "showAllButtonLabel",
"gpsPlaceText", "gpsPlaceText",
@ -381,6 +389,8 @@
"fi": [ "fi": [
"settingsPhotosDescription", "settingsPhotosDescription",
"settingsPhotosPageTitle", "settingsPhotosPageTitle",
"settingsMemoriesRangeTitle",
"settingsMemoriesRangeValueText",
"gpsPlaceText", "gpsPlaceText",
"gpsPlaceAboutDialogTitle", "gpsPlaceAboutDialogTitle",
"gpsPlaceAboutDialogContent", "gpsPlaceAboutDialogContent",
@ -396,6 +406,8 @@
"settingsAccountLabelDescription", "settingsAccountLabelDescription",
"settingsPhotosDescription", "settingsPhotosDescription",
"settingsPhotosPageTitle", "settingsPhotosPageTitle",
"settingsMemoriesRangeTitle",
"settingsMemoriesRangeValueText",
"settingsPhotoEnhancementTitle", "settingsPhotoEnhancementTitle",
"settingsPhotoEnhancementPageTitle", "settingsPhotoEnhancementPageTitle",
"settingsEnhanceMaxResolutionTitle", "settingsEnhanceMaxResolutionTitle",
@ -467,6 +479,8 @@
"settingsAccountLabelDescription", "settingsAccountLabelDescription",
"settingsPhotosDescription", "settingsPhotosDescription",
"settingsPhotosPageTitle", "settingsPhotosPageTitle",
"settingsMemoriesRangeTitle",
"settingsMemoriesRangeValueText",
"settingsPhotoEnhancementTitle", "settingsPhotoEnhancementTitle",
"settingsPhotoEnhancementPageTitle", "settingsPhotoEnhancementPageTitle",
"settingsEnhanceMaxResolutionTitle", "settingsEnhanceMaxResolutionTitle",
@ -556,6 +570,8 @@
"settingsAccountLabelDescription", "settingsAccountLabelDescription",
"settingsPhotosDescription", "settingsPhotosDescription",
"settingsPhotosPageTitle", "settingsPhotosPageTitle",
"settingsMemoriesRangeTitle",
"settingsMemoriesRangeValueText",
"settingsPhotoEnhancementTitle", "settingsPhotoEnhancementTitle",
"settingsPhotoEnhancementPageTitle", "settingsPhotoEnhancementPageTitle",
"settingsEnhanceMaxResolutionTitle", "settingsEnhanceMaxResolutionTitle",
@ -624,6 +640,8 @@
"settingsAccountLabelDescription", "settingsAccountLabelDescription",
"settingsPhotosDescription", "settingsPhotosDescription",
"settingsPhotosPageTitle", "settingsPhotosPageTitle",
"settingsMemoriesRangeTitle",
"settingsMemoriesRangeValueText",
"settingsPhotoEnhancementTitle", "settingsPhotoEnhancementTitle",
"settingsPhotoEnhancementPageTitle", "settingsPhotoEnhancementPageTitle",
"settingsEnhanceMaxResolutionTitle", "settingsEnhanceMaxResolutionTitle",
@ -692,6 +710,8 @@
"settingsAccountLabelDescription", "settingsAccountLabelDescription",
"settingsPhotosDescription", "settingsPhotosDescription",
"settingsPhotosPageTitle", "settingsPhotosPageTitle",
"settingsMemoriesRangeTitle",
"settingsMemoriesRangeValueText",
"settingsPhotoEnhancementTitle", "settingsPhotoEnhancementTitle",
"settingsPhotoEnhancementPageTitle", "settingsPhotoEnhancementPageTitle",
"settingsEnhanceMaxResolutionTitle", "settingsEnhanceMaxResolutionTitle",
@ -760,6 +780,8 @@
"settingsAccountLabelDescription", "settingsAccountLabelDescription",
"settingsPhotosDescription", "settingsPhotosDescription",
"settingsPhotosPageTitle", "settingsPhotosPageTitle",
"settingsMemoriesRangeTitle",
"settingsMemoriesRangeValueText",
"settingsPhotoEnhancementTitle", "settingsPhotoEnhancementTitle",
"settingsPhotoEnhancementPageTitle", "settingsPhotoEnhancementPageTitle",
"settingsEnhanceMaxResolutionTitle", "settingsEnhanceMaxResolutionTitle",

View file

@ -244,6 +244,11 @@ class Pref {
Future<bool> setDoubleTapExit(bool value) => _set<bool>(PrefKey.doubleTapExit, Future<bool> setDoubleTapExit(bool value) => _set<bool>(PrefKey.doubleTapExit,
value, (key, value) => provider.setBool(key, value)); value, (key, value) => provider.setBool(key, value));
int? getMemoriesRange() => provider.getInt(PrefKey.memoriesRange);
int getMemoriesRangeOr([int def = 2]) => getMemoriesRange() ?? def;
Future<bool> setMemoriesRange(int value) => _set<int>(PrefKey.memoriesRange,
value, (key, value) => provider.setInt(key, value));
Future<bool> _set<T>(PrefKey key, T value, Future<bool> _set<T>(PrefKey key, T value,
Future<bool> Function(PrefKey key, T value) setFn) async { Future<bool> Function(PrefKey key, T value) setFn) async {
if (await setFn(key, value)) { if (await setFn(key, value)) {
@ -555,6 +560,7 @@ enum PrefKey {
isPhotosTabSortByName, isPhotosTabSortByName,
shouldProcessExifWifiOnly, shouldProcessExifWifiOnly,
doubleTapExit, doubleTapExit,
memoriesRange,
// account pref // account pref
isEnableFaceRecognitionApp, isEnableFaceRecognitionApp,
@ -624,6 +630,8 @@ extension on PrefKey {
return "shouldProcessExifWifiOnly"; return "shouldProcessExifWifiOnly";
case PrefKey.doubleTapExit: case PrefKey.doubleTapExit:
return "doubleTapExit"; return "doubleTapExit";
case PrefKey.memoriesRange:
return "memoriesRange";
// account pref // account pref
case PrefKey.isEnableFaceRecognitionApp: case PrefKey.isEnableFaceRecognitionApp:

View file

@ -80,8 +80,9 @@ class PopulateAlbum {
assert(album.provider is AlbumMemoryProvider); assert(album.provider is AlbumMemoryProvider);
final provider = album.provider as AlbumMemoryProvider; final provider = album.provider as AlbumMemoryProvider;
final date = DateTime(provider.year, provider.month, provider.day); final date = DateTime(provider.year, provider.month, provider.day);
final from = date.subtract(const Duration(days: 2)); final dayRange = _c.pref.getMemoriesRangeOr();
final to = date.add(const Duration(days: 3)); final from = date.subtract(Duration(days: dayRange));
final to = date.add(Duration(days: dayRange + 1));
final files = await FileSqliteDbDataSource(_c).listByDate( final files = await FileSqliteDbDataSource(_c).listByDate(
account, from.millisecondsSinceEpoch, to.millisecondsSinceEpoch); account, from.millisecondsSinceEpoch, to.millisecondsSinceEpoch);
return files return files

View file

@ -15,6 +15,10 @@ import 'package:nc_photos/widget/photo_list_item.dart';
import 'package:nc_photos/widget/photo_list_util.dart'; import 'package:nc_photos/widget/photo_list_util.dart';
import 'package:nc_photos/widget/selectable_item_stream_list_mixin.dart'; import 'package:nc_photos/widget/selectable_item_stream_list_mixin.dart';
/// Arguments to the photo list item builder
///
/// If [smartAlbumConfig] != null, the builder will also build smart albums in
/// the process
class PhotoListItemBuilderArguments { class PhotoListItemBuilderArguments {
const PhotoListItemBuilderArguments( const PhotoListItemBuilderArguments(
this.account, this.account,
@ -22,7 +26,7 @@ class PhotoListItemBuilderArguments {
this.isArchived = false, this.isArchived = false,
required this.sorter, required this.sorter,
this.grouper, this.grouper,
this.shouldBuildSmartAlbums = false, this.smartAlbumConfig,
this.shouldShowFavoriteBadge = false, this.shouldShowFavoriteBadge = false,
required this.locale, required this.locale,
}); });
@ -32,7 +36,7 @@ class PhotoListItemBuilderArguments {
final bool isArchived; final bool isArchived;
final PhotoListItemSorter? sorter; final PhotoListItemSorter? sorter;
final PhotoListItemGrouper? grouper; final PhotoListItemGrouper? grouper;
final bool shouldBuildSmartAlbums; final PhotoListItemSmartAlbumConfig? smartAlbumConfig;
final bool shouldShowFavoriteBadge; final bool shouldShowFavoriteBadge;
/// Locale is needed to get localized string /// Locale is needed to get localized string
@ -73,6 +77,12 @@ class PhotoListFileDateGrouper implements PhotoListItemGrouper {
final DateGroupHelper helper; final DateGroupHelper helper;
} }
class PhotoListItemSmartAlbumConfig {
const PhotoListItemSmartAlbumConfig(this.memoriesDayRange);
final int memoriesDayRange;
}
int photoListFileDateTimeSorter(File a, File b) => int photoListFileDateTimeSorter(File a, File b) =>
compareFileDateTimeDescending(a, b); compareFileDateTimeDescending(a, b);
@ -86,7 +96,7 @@ PhotoListItemBuilderResult buildPhotoListItem(
isArchived: arg.isArchived, isArchived: arg.isArchived,
sorter: arg.sorter, sorter: arg.sorter,
grouper: arg.grouper, grouper: arg.grouper,
shouldBuildSmartAlbums: arg.shouldBuildSmartAlbums, smartAlbumConfig: arg.smartAlbumConfig,
shouldShowFavoriteBadge: arg.shouldShowFavoriteBadge, shouldShowFavoriteBadge: arg.shouldShowFavoriteBadge,
locale: arg.locale, locale: arg.locale,
)(arg.account, arg.files); )(arg.account, arg.files);
@ -97,7 +107,7 @@ class _PhotoListItemBuilder {
required this.isArchived, required this.isArchived,
required this.sorter, required this.sorter,
required this.grouper, required this.grouper,
required this.shouldBuildSmartAlbums, required this.smartAlbumConfig,
required this.shouldShowFavoriteBadge, required this.shouldShowFavoriteBadge,
required this.locale, required this.locale,
}); });
@ -123,8 +133,10 @@ class _PhotoListItemBuilder {
PhotoListItemBuilderResult _fromSortedItems( PhotoListItemBuilderResult _fromSortedItems(
Account account, List<File> files) { Account account, List<File> files) {
final today = DateTime.now(); final today = DateTime.now();
final memoryAlbumHelper = final memoryAlbumHelper = smartAlbumConfig != null
shouldBuildSmartAlbums ? MemoryAlbumHelper(today) : null; ? MemoryAlbumHelper(
today: today, dayRange: smartAlbumConfig!.memoriesDayRange)
: null;
final listItems = <SelectableItem>[]; final listItems = <SelectableItem>[];
for (int i = 0; i < files.length; ++i) { for (int i = 0; i < files.length; ++i) {
final f = files[i]; final f = files[i];
@ -173,7 +185,7 @@ class _PhotoListItemBuilder {
final bool isArchived; final bool isArchived;
final PhotoListItemSorter? sorter; final PhotoListItemSorter? sorter;
final PhotoListItemGrouper? grouper; final PhotoListItemGrouper? grouper;
final bool shouldBuildSmartAlbums; final PhotoListItemSmartAlbumConfig? smartAlbumConfig;
final bool shouldShowFavoriteBadge; final bool shouldShowFavoriteBadge;
final Locale locale; final Locale locale;

View file

@ -509,6 +509,11 @@ class _HomePhotosState extends State<HomePhotos>
_log.info("[_onPrefUpdated] Update view after changing sort option"); _log.info("[_onPrefUpdated] Update view after changing sort option");
_transformItems(_bloc.state.files); _transformItems(_bloc.state.files);
} }
} else if (ev.key == PrefKey.memoriesRange) {
if (_bloc.state is! ScanAccountDirBlocInit) {
_log.info("[_onPrefUpdated] Update view after changing memories");
_transformItems(_bloc.state.files);
}
} }
} }
@ -548,6 +553,7 @@ class _HomePhotosState extends State<HomePhotos>
/// Transform a File list to grid items /// Transform a File list to grid items
void _transformItems(List<File> files, {bool isSorted = false}) { void _transformItems(List<File> files, {bool isSorted = false}) {
_log.info("[_transformItems] Queue ${files.length} items"); _log.info("[_transformItems] Queue ${files.length} items");
final c = KiwiContainer().resolve<DiContainer>();
final PhotoListItemSorter? sorter; final PhotoListItemSorter? sorter;
final PhotoListItemGrouper? grouper; final PhotoListItemGrouper? grouper;
if (Pref().isPhotosTabSortByNameOr()) { if (Pref().isPhotosTabSortByNameOr()) {
@ -564,7 +570,8 @@ class _HomePhotosState extends State<HomePhotos>
files, files,
sorter: sorter, sorter: sorter,
grouper: grouper, grouper: grouper,
shouldBuildSmartAlbums: true, smartAlbumConfig:
PhotoListItemSmartAlbumConfig(c.pref.getMemoriesRangeOr()),
shouldShowFavoriteBadge: true, shouldShowFavoriteBadge: true,
locale: language_util.getSelectedLocale() ?? locale: language_util.getSelectedLocale() ??
PlatformDispatcher.instance.locale, PlatformDispatcher.instance.locale,

View file

@ -1,3 +1,5 @@
import 'dart:math' as math;
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:nc_photos/date_time_extension.dart'; import 'package:nc_photos/date_time_extension.dart';
@ -32,8 +34,11 @@ class DateGroupHelper {
/// ///
/// Feb 29 is treated as Mar 1 on non leap years /// Feb 29 is treated as Mar 1 on non leap years
class MemoryAlbumHelper { class MemoryAlbumHelper {
MemoryAlbumHelper([DateTime? today]) MemoryAlbumHelper({
: today = (today?.toLocal() ?? DateTime.now()).toMidnight(); DateTime? today,
required int dayRange,
}) : today = (today?.toLocal() ?? DateTime.now()).toMidnight(),
dayRange = math.max(dayRange, 0);
void addFile(File f) { void addFile(File f) {
final date = f.bestDateTime.toLocal().toMidnight(); final date = f.bestDateTime.toLocal().toMidnight();
@ -43,7 +48,7 @@ class MemoryAlbumHelper {
} }
for (final dy in [0, -1, 1]) { for (final dy in [0, -1, 1]) {
if (today.copyWith(year: date.year + dy).difference(date).abs().inDays <= if (today.copyWith(year: date.year + dy).difference(date).abs().inDays <=
2) { dayRange) {
_log.fine( _log.fine(
"[addFile] Add file (${f.bestDateTime}) to ${date.year + dy}"); "[addFile] Add file (${f.bestDateTime}) to ${date.year + dy}");
_addFileToYear(f, date.year + dy); _addFileToYear(f, date.year + dy);
@ -85,6 +90,7 @@ class MemoryAlbumHelper {
} }
final DateTime today; final DateTime today;
final int dayRange;
final _data = <int, _MemoryAlbumHelperItem>{}; final _data = <int, _MemoryAlbumHelperItem>{};
static final _log = Logger("widget.photo_list_util.MemoryAlbumHelper"); static final _log = Logger("widget.photo_list_util.MemoryAlbumHelper");

View file

@ -814,6 +814,7 @@ class _PhotosSettingsState extends State<_PhotosSettings> {
@override @override
initState() { initState() {
super.initState(); super.initState();
_memoriesRange = Pref().getMemoriesRangeOr();
final settings = AccountPref.of(widget.account); final settings = AccountPref.of(widget.account);
_isEnableMemoryAlbum = settings.isEnableMemoryAlbumOr(true); _isEnableMemoryAlbum = settings.isEnableMemoryAlbumOr(true);
@ -848,6 +849,14 @@ class _PhotosSettingsState extends State<_PhotosSettings> {
? null ? null
: _onEnableMemoryAlbumChanged, : _onEnableMemoryAlbumChanged,
), ),
ListTile(
title: Text(L10n.global().settingsMemoriesRangeTitle),
subtitle: Text(L10n.global()
.settingsMemoriesRangeValueText(_memoriesRange)),
onTap: () => _onMemoriesRangeTap(context),
enabled:
!Pref().isPhotosTabSortByNameOr() && _isEnableMemoryAlbum,
),
], ],
), ),
), ),
@ -855,6 +864,37 @@ class _PhotosSettingsState extends State<_PhotosSettings> {
); );
} }
Future<void> _onMemoriesRangeTap(BuildContext context) async {
var memoriesRange = _memoriesRange;
final result = await showDialog<bool>(
context: context,
builder: (_) => AppTheme(
child: AlertDialog(
content: _MemoriesRangeSlider(
initialRange: _memoriesRange,
onChanged: (value) {
memoriesRange = value;
},
),
contentPadding: const EdgeInsets.fromLTRB(24, 20, 24, 0),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: Text(L10n.global().applyButtonLabel),
),
],
),
),
);
if (result != true || memoriesRange == _memoriesRange) {
return;
}
unawaited(_setMemoriesRange(memoriesRange));
}
Future<void> _onEnableMemoryAlbumChanged(bool value) async { Future<void> _onEnableMemoryAlbumChanged(bool value) async {
_log.info("[_onEnableMemoryAlbumChanged] New value: $value"); _log.info("[_onEnableMemoryAlbumChanged] New value: $value");
final oldValue = _isEnableMemoryAlbum; final oldValue = _isEnableMemoryAlbum;
@ -873,11 +913,80 @@ class _PhotosSettingsState extends State<_PhotosSettings> {
} }
} }
Future<void> _setMemoriesRange(int value) async {
_log.info("[_setMemoriesRange] New value: $value");
final oldValue = _memoriesRange;
setState(() {
_memoriesRange = value;
});
if (!await Pref().setMemoriesRange(value)) {
_log.severe("[_setMemoriesRange] Failed writing pref");
SnackBarManager().showSnackBar(SnackBar(
content: Text(L10n.global().writePreferenceFailureNotification),
duration: k.snackBarDurationNormal,
));
setState(() {
_memoriesRange = oldValue;
});
}
}
late bool _isEnableMemoryAlbum; late bool _isEnableMemoryAlbum;
late int _memoriesRange;
static final _log = Logger("widget.settings._PhotosSettingsState"); static final _log = Logger("widget.settings._PhotosSettingsState");
} }
class _MemoriesRangeSlider extends StatefulWidget {
const _MemoriesRangeSlider({
Key? key,
required this.initialRange,
this.onChanged,
}) : super(key: key);
@override
createState() => _MemoriesRangeSliderState();
final int initialRange;
final ValueChanged<int>? onChanged;
}
class _MemoriesRangeSliderState extends State<_MemoriesRangeSlider> {
@override
initState() {
super.initState();
_memoriesRange = widget.initialRange;
}
@override
build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Align(
alignment: Alignment.center,
child: Text(
L10n.global().settingsMemoriesRangeValueText(_memoriesRange)),
),
StatefulSlider(
initialValue: _memoriesRange.toDouble(),
min: 0,
max: 4,
divisions: 4,
onChangeEnd: (value) async {
setState(() {
_memoriesRange = value.toInt();
});
widget.onChanged?.call(_memoriesRange);
},
),
],
);
}
late int _memoriesRange;
}
class _ViewerSettings extends StatefulWidget { class _ViewerSettings extends StatefulWidget {
@override @override
createState() => _ViewerSettingsState(); createState() => _ViewerSettingsState();

View file

@ -38,6 +38,13 @@ void main() {
group("on dec 31", () { group("on dec 31", () {
test("+jan 1", _onDec31AddJan1); test("+jan 1", _onDec31AddJan1);
}); });
group("on may 15, range=0", () {
test("+may 16", _onMay15AddMay16Range0);
test("+may 15", _onMay15AddMay15Range0);
});
group("on may 15, range<0", () {
test("+may 16", _onMay15AddMay16RangeNegative);
});
}); });
} }
@ -48,7 +55,7 @@ void main() {
/// Expect: empty /// Expect: empty
void _sameYear() { void _sameYear() {
final today = DateTime(2021, 2, 3); final today = DateTime(2021, 2, 3);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2021, 2, 3)); path: "", fileId: 0, lastModified: DateTime.utc(2021, 2, 3));
obj.addFile(file); obj.addFile(file);
@ -63,7 +70,7 @@ void _sameYear() {
/// Expect: empty /// Expect: empty
void _nextYear() { void _nextYear() {
final today = DateTime(2021, 2, 3); final today = DateTime(2021, 2, 3);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2022, 2, 3)); path: "", fileId: 0, lastModified: DateTime.utc(2022, 2, 3));
obj.addFile(file); obj.addFile(file);
@ -77,7 +84,7 @@ void _nextYear() {
/// Expect: [2020] /// Expect: [2020]
void _prevYear() { void _prevYear() {
final today = DateTime(2021, 2, 3); final today = DateTime(2021, 2, 3);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 3)); path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 3));
obj.addFile(file); obj.addFile(file);
@ -106,7 +113,7 @@ void _prevYear() {
/// Expect: empty /// Expect: empty
void _prevYear3DaysBefore() { void _prevYear3DaysBefore() {
final today = DateTime(2021, 2, 3); final today = DateTime(2021, 2, 3);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2020, 1, 31)); path: "", fileId: 0, lastModified: DateTime.utc(2020, 1, 31));
obj.addFile(file); obj.addFile(file);
@ -120,7 +127,7 @@ void _prevYear3DaysBefore() {
/// Expect: [2020] /// Expect: [2020]
void _prevYear2DaysBefore() { void _prevYear2DaysBefore() {
final today = DateTime(2021, 2, 3); final today = DateTime(2021, 2, 3);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 1)); path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 1));
obj.addFile(file); obj.addFile(file);
@ -149,7 +156,7 @@ void _prevYear2DaysBefore() {
/// Expect: empty /// Expect: empty
void _prevYear3DaysAfter() { void _prevYear3DaysAfter() {
final today = DateTime(2021, 2, 3); final today = DateTime(2021, 2, 3);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 6)); path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 6));
obj.addFile(file); obj.addFile(file);
@ -163,7 +170,7 @@ void _prevYear3DaysAfter() {
/// Expect: [2020] /// Expect: [2020]
void _prevYear2DaysAfter() { void _prevYear2DaysAfter() {
final today = DateTime(2021, 2, 3); final today = DateTime(2021, 2, 3);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 5)); path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 5));
obj.addFile(file); obj.addFile(file);
@ -192,7 +199,7 @@ void _prevYear2DaysAfter() {
/// Expect: empty /// Expect: empty
void _onFeb29AddFeb26() { void _onFeb29AddFeb26() {
final today = DateTime(2020, 2, 29); final today = DateTime(2020, 2, 29);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2019, 2, 26)); path: "", fileId: 0, lastModified: DateTime.utc(2019, 2, 26));
obj.addFile(file); obj.addFile(file);
@ -206,7 +213,7 @@ void _onFeb29AddFeb26() {
/// Expect: [2019] /// Expect: [2019]
void _onFeb29AddFeb27() { void _onFeb29AddFeb27() {
final today = DateTime(2020, 2, 29); final today = DateTime(2020, 2, 29);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2019, 2, 27)); path: "", fileId: 0, lastModified: DateTime.utc(2019, 2, 27));
obj.addFile(file); obj.addFile(file);
@ -235,7 +242,7 @@ void _onFeb29AddFeb27() {
/// Expect: empty /// Expect: empty
void _onFeb29AddMar4() { void _onFeb29AddMar4() {
final today = DateTime(2020, 2, 29); final today = DateTime(2020, 2, 29);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2019, 3, 4)); path: "", fileId: 0, lastModified: DateTime.utc(2019, 3, 4));
obj.addFile(file); obj.addFile(file);
@ -249,7 +256,7 @@ void _onFeb29AddMar4() {
/// Expect: [2019] /// Expect: [2019]
void _onFeb29AddMar3() { void _onFeb29AddMar3() {
final today = DateTime(2020, 2, 29); final today = DateTime(2020, 2, 29);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2019, 3, 3)); path: "", fileId: 0, lastModified: DateTime.utc(2019, 3, 3));
obj.addFile(file); obj.addFile(file);
@ -278,7 +285,7 @@ void _onFeb29AddMar3() {
/// Expect: empty /// Expect: empty
void _onFeb29AddMar3LeapYear() { void _onFeb29AddMar3LeapYear() {
final today = DateTime(2020, 2, 29); final today = DateTime(2020, 2, 29);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2016, 3, 3)); path: "", fileId: 0, lastModified: DateTime.utc(2016, 3, 3));
obj.addFile(file); obj.addFile(file);
@ -292,7 +299,7 @@ void _onFeb29AddMar3LeapYear() {
/// Expect: [2016] /// Expect: [2016]
void _onFeb29AddMar2LeapYear() { void _onFeb29AddMar2LeapYear() {
final today = DateTime(2020, 2, 29); final today = DateTime(2020, 2, 29);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2016, 3, 2)); path: "", fileId: 0, lastModified: DateTime.utc(2016, 3, 2));
obj.addFile(file); obj.addFile(file);
@ -321,7 +328,7 @@ void _onFeb29AddMar2LeapYear() {
/// Expect: empty /// Expect: empty
void _onJan1AddDec31() { void _onJan1AddDec31() {
final today = DateTime(2020, 1, 1); final today = DateTime(2020, 1, 1);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2019, 12, 31)); path: "", fileId: 0, lastModified: DateTime.utc(2019, 12, 31));
obj.addFile(file); obj.addFile(file);
@ -335,7 +342,7 @@ void _onJan1AddDec31() {
/// Expect: [2019] /// Expect: [2019]
void _onJan1AddDec31PrevYear() { void _onJan1AddDec31PrevYear() {
final today = DateTime(2020, 1, 1); final today = DateTime(2020, 1, 1);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2018, 12, 31)); path: "", fileId: 0, lastModified: DateTime.utc(2018, 12, 31));
obj.addFile(file); obj.addFile(file);
@ -364,7 +371,7 @@ void _onJan1AddDec31PrevYear() {
/// Expect: [2019] /// Expect: [2019]
void _onDec31AddJan1() { void _onDec31AddJan1() {
final today = DateTime(2020, 12, 31); final today = DateTime(2020, 12, 31);
final obj = MemoryAlbumHelper(today); final obj = MemoryAlbumHelper(today: today, dayRange: 2);
final file = util.buildJpegFile( final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2020, 1, 1)); path: "", fileId: 0, lastModified: DateTime.utc(2020, 1, 1));
obj.addFile(file); obj.addFile(file);
@ -386,4 +393,61 @@ void _onDec31AddJan1() {
); );
} }
/// Add a file with 0 day offset when range = 0
///
/// Today: 2022-05-15
/// File: 2021-05-15
/// Expect: [2022]
void _onMay15AddMay15Range0() {
final today = DateTime(2022, 5, 15);
final obj = MemoryAlbumHelper(today: today, dayRange: 0);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2021, 5, 15));
obj.addFile(file);
expect(
obj
.build(_nameBuilder)
.map((a) => a.copyWith(lastUpdated: OrNull(DateTime(2021))))
.toList(),
[
Album(
name: "2021",
provider:
AlbumMemoryProvider(year: 2021, month: today.month, day: today.day),
coverProvider: AlbumManualCoverProvider(coverFile: file),
sortProvider: const AlbumTimeSortProvider(isAscending: false),
lastUpdated: DateTime(2021),
),
],
);
}
/// Add a file with 1 day offset when range = 0
///
/// Today: 2022-05-15
/// File: 2021-05-16
/// Expect: []
void _onMay15AddMay16Range0() {
final today = DateTime(2022, 5, 15);
final obj = MemoryAlbumHelper(today: today, dayRange: 0);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2021, 5, 16));
obj.addFile(file);
expect(obj.build(_nameBuilder), []);
}
/// Make sure the builder won't throw when range < 0
///
/// Today: 2022-05-15
/// File: 2021-05-16
/// Expect: []
void _onMay15AddMay16RangeNegative() {
final today = DateTime(2022, 5, 15);
final obj = MemoryAlbumHelper(today: today, dayRange: -1);
final file = util.buildJpegFile(
path: "", fileId: 0, lastModified: DateTime.utc(2021, 5, 16));
obj.addFile(file);
expect(obj.build(_nameBuilder), []);
}
String _nameBuilder(int year) => "$year"; String _nameBuilder(int year) => "$year";