From 28c19b891633b0e8e907c697aa6ebbaca37aa91e Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Mon, 3 Mar 2025 16:18:39 +0530 Subject: [PATCH] [mob][photos] filler memories --- mobile/lib/models/filler_memory.dart | 19 +++++ .../lib/services/smart_memories_service.dart | 75 ++++++++++++++++--- .../lib/ui/home/memories/memories_widget.dart | 11 ++- 3 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 mobile/lib/models/filler_memory.dart diff --git a/mobile/lib/models/filler_memory.dart b/mobile/lib/models/filler_memory.dart new file mode 100644 index 0000000000..8cfcbea49d --- /dev/null +++ b/mobile/lib/models/filler_memory.dart @@ -0,0 +1,19 @@ +import "package:photos/models/memory.dart"; +import "package:photos/models/smart_memory.dart"; + +class FillerMemory extends SmartMemory { + FillerMemory( + List memories, + String title, + int firstDateToShow, + int lastDateToShow, { + int? firstCreationTime, + int? lastCreationTime, + }) : super( + memories, + MemoryType.filler, + title, + firstDateToShow, + lastDateToShow, + ); +} diff --git a/mobile/lib/services/smart_memories_service.dart b/mobile/lib/services/smart_memories_service.dart index 88179d4fcb..ff1e0a94f3 100644 --- a/mobile/lib/services/smart_memories_service.dart +++ b/mobile/lib/services/smart_memories_service.dart @@ -13,6 +13,7 @@ import "package:photos/l10n/l10n.dart"; import "package:photos/models/base_location.dart"; import "package:photos/models/file/extensions/file_props.dart"; import "package:photos/models/file/file.dart"; +import "package:photos/models/filler_memory.dart"; import "package:photos/models/local_entity_data.dart"; import "package:photos/models/location/location.dart"; import "package:photos/models/location_tag/location_tag.dart"; @@ -49,6 +50,8 @@ class SmartMemoriesService { static const _clipSimilarImageThreshold = 0.75; static const _clipActivityQueryThreshold = 0.25; + static const yearsBefore = 30; + SmartMemoriesService(); Future init() async { @@ -99,11 +102,9 @@ class SmartMemoriesService { memories.addAll(timeMemories); _logger.finest("All files length: ${allFiles.length}"); - // // Filler memories TODO: lau: add filler results - // final fillerMemories = await _getFillerResults(limit); - // _deductUsedMemories(allFiles, fillerMemories); - // memories.addAll(fillerMemories); - // _logger.finest("All files length: ${allFiles.length}"); + // Filler memories + final fillerMemories = await _getFillerResults(allFiles, now); + memories.addAll(fillerMemories); return memories; } catch (e, s) { _logger.severe("Error calculating smart memories", e, s); @@ -394,9 +395,8 @@ class SmartMemoriesService { spotlightMem.copyWith( title: secondTitle, firstDateToShow: thisBirthday.microsecondsSinceEpoch, - lastDateToShow: thisBirthday - .add(kDayItself) - .microsecondsSinceEpoch, + lastDateToShow: + thisBirthday.add(kDayItself).microsecondsSinceEpoch, ), ); } @@ -407,9 +407,8 @@ class SmartMemoriesService { firstDateToShow: thisBirthday .subtract(const Duration(days: 6)) .microsecondsSinceEpoch, - lastDateToShow: thisBirthday - .add(kDayItself) - .microsecondsSinceEpoch, + lastDateToShow: + thisBirthday.add(kDayItself).microsecondsSinceEpoch, ), ); } @@ -1121,6 +1120,60 @@ class SmartMemoriesService { return memoryResult; } + Future> _getFillerResults( + Iterable allFiles, + DateTime currentTime, + ) async { + final List memoryResults = []; + if (allFiles.isEmpty) return []; + final nowInMicroseconds = currentTime.microsecondsSinceEpoch; + final windowEnd = + currentTime.add(kMemoriesUpdateFrequency).microsecondsSinceEpoch; + final currentYear = currentTime.year; + final cutOffTime = currentTime.subtract(const Duration(days: 365)); + final timeTillYearEnd = DateTime(currentYear + 1).difference(currentTime); + final bool almostYearEnd = timeTillYearEnd < kMemoriesUpdateFrequency; + + final Map> yearsAgoToMemories = {}; + for (final file in allFiles) { + if (file.creationTime == null || + file.creationTime! > cutOffTime.microsecondsSinceEpoch) { + continue; + } + final fileDate = DateTime.fromMicrosecondsSinceEpoch(file.creationTime!); + final fileTimeInYear = fileDate.copyWith(year: currentYear); + final diff = fileTimeInYear.difference(currentTime); + if (!diff.isNegative && diff < kMemoriesUpdateFrequency) { + final yearsAgo = currentYear - fileDate.year; + yearsAgoToMemories + .putIfAbsent(yearsAgo, () => []) + .add(Memory.fromFile(file, _seenTimes)); + } else if (almostYearEnd) { + final altDiff = fileDate.copyWith(year: currentYear + 1).difference( + currentTime, + ); + if (!altDiff.isNegative && altDiff < kMemoriesUpdateFrequency) { + final yearsAgo = currentYear - fileDate.year + 1; + yearsAgoToMemories + .putIfAbsent(yearsAgo, () => []) + .add(Memory.fromFile(file, _seenTimes)); + } + } + } + for (var yearAgo = 1; yearAgo <= yearsBefore; yearAgo++) { + final memories = yearsAgoToMemories[yearAgo]; + if (memories == null) continue; + final fillerMemory = FillerMemory( + memories, + "TEST", + nowInMicroseconds, + windowEnd, + ); + memoryResults.add(fillerMemory); + } + return memoryResults; + } + /// TODO: lau: replace this by just taking next 7 days int _getWeekNumber(DateTime date) { // Get day of year (1-366) diff --git a/mobile/lib/ui/home/memories/memories_widget.dart b/mobile/lib/ui/home/memories/memories_widget.dart index 002a899245..de4f9fbbc8 100644 --- a/mobile/lib/ui/home/memories/memories_widget.dart +++ b/mobile/lib/ui/home/memories/memories_widget.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import "package:flutter_animate/flutter_animate.dart"; import "package:photos/core/event_bus.dart"; import "package:photos/events/memories_setting_changed.dart"; +import "package:photos/models/filler_memory.dart"; import 'package:photos/models/memory.dart'; import "package:photos/models/smart_memory.dart"; import "package:photos/service_locator.dart"; @@ -128,8 +129,14 @@ class _MemoriesWidgetState extends State { } Widget _buildSmartMemories(List memories) { - final collatedMemories = - memories.map((e) => (e.memories, e.title)).toList(); + final List<(List, String?)> collatedMemories = []; + for (final memory in memories) { + if (memory is FillerMemory) { + collatedMemories.add((memory.memories, null)); + } else { + collatedMemories.add((memory.memories, memory.title)); + } + } return SizedBox( height: _maxHeight + MemoryCoverWidget.outerStrokeWidth * 2,