diff --git a/app/lib/l10n/app_en.arb b/app/lib/l10n/app_en.arb index 6784ae48..fc09f379 100644 --- a/app/lib/l10n/app_en.arb +++ b/app/lib/l10n/app_en.arb @@ -371,6 +371,19 @@ "@settingsPhotosPageTitle": { "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", "settingsViewerDescription": "Customize the image/video viewer", "settingsViewerPageTitle": "Viewer settings", @@ -1401,7 +1414,6 @@ "@collectionPlacesLabel": { "description": "Browse photos grouped by place" }, - "errorUnauthenticated": "Unauthenticated access. Please sign-in again if the problem continues", "@errorUnauthenticated": { "description": "Error message when server responds with HTTP401" diff --git a/app/lib/l10n/untranslated-messages.txt b/app/lib/l10n/untranslated-messages.txt index a72b6dcf..6b0aad57 100644 --- a/app/lib/l10n/untranslated-messages.txt +++ b/app/lib/l10n/untranslated-messages.txt @@ -17,6 +17,8 @@ "settingsServerAppSectionTitle", "settingsPhotosDescription", "settingsPhotosPageTitle", + "settingsMemoriesRangeTitle", + "settingsMemoriesRangeValueText", "settingsMapProviderTitle", "settingsAlbumTitle", "settingsAlbumDescription", @@ -170,6 +172,8 @@ "settingsServerAppSectionTitle", "settingsPhotosDescription", "settingsPhotosPageTitle", + "settingsMemoriesRangeTitle", + "settingsMemoriesRangeValueText", "settingsMapProviderTitle", "settingsAlbumTitle", "settingsAlbumDescription", @@ -327,6 +331,8 @@ "settingsAccountLabelDescription", "settingsPhotosDescription", "settingsPhotosPageTitle", + "settingsMemoriesRangeTitle", + "settingsMemoriesRangeValueText", "settingsDoubleTapExitTitle", "enhanceStyleTransferStyleDialogTitle", "doubleTapExitNotification", @@ -370,6 +376,8 @@ "settingsLanguageOptionSystemDefaultLabel", "settingsPhotosDescription", "settingsPhotosPageTitle", + "settingsMemoriesRangeTitle", + "settingsMemoriesRangeValueText", "rootPickerSkipConfirmationDialogContent2", "showAllButtonLabel", "gpsPlaceText", @@ -381,6 +389,8 @@ "fi": [ "settingsPhotosDescription", "settingsPhotosPageTitle", + "settingsMemoriesRangeTitle", + "settingsMemoriesRangeValueText", "gpsPlaceText", "gpsPlaceAboutDialogTitle", "gpsPlaceAboutDialogContent", @@ -396,6 +406,8 @@ "settingsAccountLabelDescription", "settingsPhotosDescription", "settingsPhotosPageTitle", + "settingsMemoriesRangeTitle", + "settingsMemoriesRangeValueText", "settingsPhotoEnhancementTitle", "settingsPhotoEnhancementPageTitle", "settingsEnhanceMaxResolutionTitle", @@ -467,6 +479,8 @@ "settingsAccountLabelDescription", "settingsPhotosDescription", "settingsPhotosPageTitle", + "settingsMemoriesRangeTitle", + "settingsMemoriesRangeValueText", "settingsPhotoEnhancementTitle", "settingsPhotoEnhancementPageTitle", "settingsEnhanceMaxResolutionTitle", @@ -556,6 +570,8 @@ "settingsAccountLabelDescription", "settingsPhotosDescription", "settingsPhotosPageTitle", + "settingsMemoriesRangeTitle", + "settingsMemoriesRangeValueText", "settingsPhotoEnhancementTitle", "settingsPhotoEnhancementPageTitle", "settingsEnhanceMaxResolutionTitle", @@ -624,6 +640,8 @@ "settingsAccountLabelDescription", "settingsPhotosDescription", "settingsPhotosPageTitle", + "settingsMemoriesRangeTitle", + "settingsMemoriesRangeValueText", "settingsPhotoEnhancementTitle", "settingsPhotoEnhancementPageTitle", "settingsEnhanceMaxResolutionTitle", @@ -692,6 +710,8 @@ "settingsAccountLabelDescription", "settingsPhotosDescription", "settingsPhotosPageTitle", + "settingsMemoriesRangeTitle", + "settingsMemoriesRangeValueText", "settingsPhotoEnhancementTitle", "settingsPhotoEnhancementPageTitle", "settingsEnhanceMaxResolutionTitle", @@ -760,6 +780,8 @@ "settingsAccountLabelDescription", "settingsPhotosDescription", "settingsPhotosPageTitle", + "settingsMemoriesRangeTitle", + "settingsMemoriesRangeValueText", "settingsPhotoEnhancementTitle", "settingsPhotoEnhancementPageTitle", "settingsEnhanceMaxResolutionTitle", diff --git a/app/lib/pref.dart b/app/lib/pref.dart index 7eac20fa..14cfe451 100644 --- a/app/lib/pref.dart +++ b/app/lib/pref.dart @@ -244,6 +244,11 @@ class Pref { Future setDoubleTapExit(bool value) => _set(PrefKey.doubleTapExit, value, (key, value) => provider.setBool(key, value)); + int? getMemoriesRange() => provider.getInt(PrefKey.memoriesRange); + int getMemoriesRangeOr([int def = 2]) => getMemoriesRange() ?? def; + Future setMemoriesRange(int value) => _set(PrefKey.memoriesRange, + value, (key, value) => provider.setInt(key, value)); + Future _set(PrefKey key, T value, Future Function(PrefKey key, T value) setFn) async { if (await setFn(key, value)) { @@ -555,6 +560,7 @@ enum PrefKey { isPhotosTabSortByName, shouldProcessExifWifiOnly, doubleTapExit, + memoriesRange, // account pref isEnableFaceRecognitionApp, @@ -624,6 +630,8 @@ extension on PrefKey { return "shouldProcessExifWifiOnly"; case PrefKey.doubleTapExit: return "doubleTapExit"; + case PrefKey.memoriesRange: + return "memoriesRange"; // account pref case PrefKey.isEnableFaceRecognitionApp: diff --git a/app/lib/use_case/populate_album.dart b/app/lib/use_case/populate_album.dart index a4a651a7..e8707b1a 100644 --- a/app/lib/use_case/populate_album.dart +++ b/app/lib/use_case/populate_album.dart @@ -80,8 +80,9 @@ class PopulateAlbum { assert(album.provider is AlbumMemoryProvider); final provider = album.provider as AlbumMemoryProvider; final date = DateTime(provider.year, provider.month, provider.day); - final from = date.subtract(const Duration(days: 2)); - final to = date.add(const Duration(days: 3)); + final dayRange = _c.pref.getMemoriesRangeOr(); + final from = date.subtract(Duration(days: dayRange)); + final to = date.add(Duration(days: dayRange + 1)); final files = await FileSqliteDbDataSource(_c).listByDate( account, from.millisecondsSinceEpoch, to.millisecondsSinceEpoch); return files diff --git a/app/lib/widget/builder/photo_list_item_builder.dart b/app/lib/widget/builder/photo_list_item_builder.dart index b50ca7c9..a7b03bc0 100644 --- a/app/lib/widget/builder/photo_list_item_builder.dart +++ b/app/lib/widget/builder/photo_list_item_builder.dart @@ -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/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 { const PhotoListItemBuilderArguments( this.account, @@ -22,7 +26,7 @@ class PhotoListItemBuilderArguments { this.isArchived = false, required this.sorter, this.grouper, - this.shouldBuildSmartAlbums = false, + this.smartAlbumConfig, this.shouldShowFavoriteBadge = false, required this.locale, }); @@ -32,7 +36,7 @@ class PhotoListItemBuilderArguments { final bool isArchived; final PhotoListItemSorter? sorter; final PhotoListItemGrouper? grouper; - final bool shouldBuildSmartAlbums; + final PhotoListItemSmartAlbumConfig? smartAlbumConfig; final bool shouldShowFavoriteBadge; /// Locale is needed to get localized string @@ -73,6 +77,12 @@ class PhotoListFileDateGrouper implements PhotoListItemGrouper { final DateGroupHelper helper; } +class PhotoListItemSmartAlbumConfig { + const PhotoListItemSmartAlbumConfig(this.memoriesDayRange); + + final int memoriesDayRange; +} + int photoListFileDateTimeSorter(File a, File b) => compareFileDateTimeDescending(a, b); @@ -86,7 +96,7 @@ PhotoListItemBuilderResult buildPhotoListItem( isArchived: arg.isArchived, sorter: arg.sorter, grouper: arg.grouper, - shouldBuildSmartAlbums: arg.shouldBuildSmartAlbums, + smartAlbumConfig: arg.smartAlbumConfig, shouldShowFavoriteBadge: arg.shouldShowFavoriteBadge, locale: arg.locale, )(arg.account, arg.files); @@ -97,7 +107,7 @@ class _PhotoListItemBuilder { required this.isArchived, required this.sorter, required this.grouper, - required this.shouldBuildSmartAlbums, + required this.smartAlbumConfig, required this.shouldShowFavoriteBadge, required this.locale, }); @@ -123,8 +133,10 @@ class _PhotoListItemBuilder { PhotoListItemBuilderResult _fromSortedItems( Account account, List files) { final today = DateTime.now(); - final memoryAlbumHelper = - shouldBuildSmartAlbums ? MemoryAlbumHelper(today) : null; + final memoryAlbumHelper = smartAlbumConfig != null + ? MemoryAlbumHelper( + today: today, dayRange: smartAlbumConfig!.memoriesDayRange) + : null; final listItems = []; for (int i = 0; i < files.length; ++i) { final f = files[i]; @@ -173,7 +185,7 @@ class _PhotoListItemBuilder { final bool isArchived; final PhotoListItemSorter? sorter; final PhotoListItemGrouper? grouper; - final bool shouldBuildSmartAlbums; + final PhotoListItemSmartAlbumConfig? smartAlbumConfig; final bool shouldShowFavoriteBadge; final Locale locale; diff --git a/app/lib/widget/home_photos.dart b/app/lib/widget/home_photos.dart index 2c92426e..56550ace 100644 --- a/app/lib/widget/home_photos.dart +++ b/app/lib/widget/home_photos.dart @@ -509,6 +509,11 @@ class _HomePhotosState extends State _log.info("[_onPrefUpdated] Update view after changing sort option"); _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 /// Transform a File list to grid items void _transformItems(List files, {bool isSorted = false}) { _log.info("[_transformItems] Queue ${files.length} items"); + final c = KiwiContainer().resolve(); final PhotoListItemSorter? sorter; final PhotoListItemGrouper? grouper; if (Pref().isPhotosTabSortByNameOr()) { @@ -564,7 +570,8 @@ class _HomePhotosState extends State files, sorter: sorter, grouper: grouper, - shouldBuildSmartAlbums: true, + smartAlbumConfig: + PhotoListItemSmartAlbumConfig(c.pref.getMemoriesRangeOr()), shouldShowFavoriteBadge: true, locale: language_util.getSelectedLocale() ?? PlatformDispatcher.instance.locale, diff --git a/app/lib/widget/photo_list_util.dart b/app/lib/widget/photo_list_util.dart index 5c71b530..9f715e33 100644 --- a/app/lib/widget/photo_list_util.dart +++ b/app/lib/widget/photo_list_util.dart @@ -1,3 +1,5 @@ +import 'dart:math' as math; + import 'package:collection/collection.dart'; import 'package:logging/logging.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 class MemoryAlbumHelper { - MemoryAlbumHelper([DateTime? today]) - : today = (today?.toLocal() ?? DateTime.now()).toMidnight(); + MemoryAlbumHelper({ + DateTime? today, + required int dayRange, + }) : today = (today?.toLocal() ?? DateTime.now()).toMidnight(), + dayRange = math.max(dayRange, 0); void addFile(File f) { final date = f.bestDateTime.toLocal().toMidnight(); @@ -43,7 +48,7 @@ class MemoryAlbumHelper { } for (final dy in [0, -1, 1]) { if (today.copyWith(year: date.year + dy).difference(date).abs().inDays <= - 2) { + dayRange) { _log.fine( "[addFile] Add file (${f.bestDateTime}) to ${date.year + dy}"); _addFileToYear(f, date.year + dy); @@ -85,6 +90,7 @@ class MemoryAlbumHelper { } final DateTime today; + final int dayRange; final _data = {}; static final _log = Logger("widget.photo_list_util.MemoryAlbumHelper"); diff --git a/app/lib/widget/settings.dart b/app/lib/widget/settings.dart index aee44a83..e9c97ec6 100644 --- a/app/lib/widget/settings.dart +++ b/app/lib/widget/settings.dart @@ -814,6 +814,7 @@ class _PhotosSettingsState extends State<_PhotosSettings> { @override initState() { super.initState(); + _memoriesRange = Pref().getMemoriesRangeOr(); final settings = AccountPref.of(widget.account); _isEnableMemoryAlbum = settings.isEnableMemoryAlbumOr(true); @@ -848,6 +849,14 @@ class _PhotosSettingsState extends State<_PhotosSettings> { ? null : _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 _onMemoriesRangeTap(BuildContext context) async { + var memoriesRange = _memoriesRange; + final result = await showDialog( + context: context, + builder: (_) => AppTheme( + child: AlertDialog( + content: _MemoriesRangeSlider( + initialRange: _memoriesRange, + onChanged: (value) { + memoriesRange = value; + }, + ), + contentPadding: const EdgeInsets.fromLTRB(24, 20, 24, 0), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(true); + }, + child: Text(L10n.global().applyButtonLabel), + ), + ], + ), + ), + ); + if (result != true || memoriesRange == _memoriesRange) { + return; + } + + unawaited(_setMemoriesRange(memoriesRange)); + } + Future _onEnableMemoryAlbumChanged(bool value) async { _log.info("[_onEnableMemoryAlbumChanged] New value: $value"); final oldValue = _isEnableMemoryAlbum; @@ -873,11 +913,80 @@ class _PhotosSettingsState extends State<_PhotosSettings> { } } + Future _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 int _memoriesRange; 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? 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 { @override createState() => _ViewerSettingsState(); diff --git a/app/test/widget/photo_list_util_test.dart b/app/test/widget/photo_list_util_test.dart index 7b11e7e7..2210851e 100644 --- a/app/test/widget/photo_list_util_test.dart +++ b/app/test/widget/photo_list_util_test.dart @@ -38,6 +38,13 @@ void main() { group("on dec 31", () { 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 void _sameYear() { final today = DateTime(2021, 2, 3); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2021, 2, 3)); obj.addFile(file); @@ -63,7 +70,7 @@ void _sameYear() { /// Expect: empty void _nextYear() { final today = DateTime(2021, 2, 3); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2022, 2, 3)); obj.addFile(file); @@ -77,7 +84,7 @@ void _nextYear() { /// Expect: [2020] void _prevYear() { final today = DateTime(2021, 2, 3); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 3)); obj.addFile(file); @@ -106,7 +113,7 @@ void _prevYear() { /// Expect: empty void _prevYear3DaysBefore() { final today = DateTime(2021, 2, 3); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2020, 1, 31)); obj.addFile(file); @@ -120,7 +127,7 @@ void _prevYear3DaysBefore() { /// Expect: [2020] void _prevYear2DaysBefore() { final today = DateTime(2021, 2, 3); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 1)); obj.addFile(file); @@ -149,7 +156,7 @@ void _prevYear2DaysBefore() { /// Expect: empty void _prevYear3DaysAfter() { final today = DateTime(2021, 2, 3); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 6)); obj.addFile(file); @@ -163,7 +170,7 @@ void _prevYear3DaysAfter() { /// Expect: [2020] void _prevYear2DaysAfter() { final today = DateTime(2021, 2, 3); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2020, 2, 5)); obj.addFile(file); @@ -192,7 +199,7 @@ void _prevYear2DaysAfter() { /// Expect: empty void _onFeb29AddFeb26() { final today = DateTime(2020, 2, 29); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2019, 2, 26)); obj.addFile(file); @@ -206,7 +213,7 @@ void _onFeb29AddFeb26() { /// Expect: [2019] void _onFeb29AddFeb27() { final today = DateTime(2020, 2, 29); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2019, 2, 27)); obj.addFile(file); @@ -235,7 +242,7 @@ void _onFeb29AddFeb27() { /// Expect: empty void _onFeb29AddMar4() { final today = DateTime(2020, 2, 29); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2019, 3, 4)); obj.addFile(file); @@ -249,7 +256,7 @@ void _onFeb29AddMar4() { /// Expect: [2019] void _onFeb29AddMar3() { final today = DateTime(2020, 2, 29); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2019, 3, 3)); obj.addFile(file); @@ -278,7 +285,7 @@ void _onFeb29AddMar3() { /// Expect: empty void _onFeb29AddMar3LeapYear() { final today = DateTime(2020, 2, 29); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2016, 3, 3)); obj.addFile(file); @@ -292,7 +299,7 @@ void _onFeb29AddMar3LeapYear() { /// Expect: [2016] void _onFeb29AddMar2LeapYear() { final today = DateTime(2020, 2, 29); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2016, 3, 2)); obj.addFile(file); @@ -321,7 +328,7 @@ void _onFeb29AddMar2LeapYear() { /// Expect: empty void _onJan1AddDec31() { final today = DateTime(2020, 1, 1); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2019, 12, 31)); obj.addFile(file); @@ -335,7 +342,7 @@ void _onJan1AddDec31() { /// Expect: [2019] void _onJan1AddDec31PrevYear() { final today = DateTime(2020, 1, 1); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2018, 12, 31)); obj.addFile(file); @@ -364,7 +371,7 @@ void _onJan1AddDec31PrevYear() { /// Expect: [2019] void _onDec31AddJan1() { final today = DateTime(2020, 12, 31); - final obj = MemoryAlbumHelper(today); + final obj = MemoryAlbumHelper(today: today, dayRange: 2); final file = util.buildJpegFile( path: "", fileId: 0, lastModified: DateTime.utc(2020, 1, 1)); 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";