From e2fbb26dce03de0664e1920aa7f037ba692aa250 Mon Sep 17 00:00:00 2001 From: laurenspriem Date: Thu, 5 Jun 2025 09:41:58 +0530 Subject: [PATCH] Reorganize --- .../lib/services/memories_cache_service.dart | 656 +++++++++--------- 1 file changed, 324 insertions(+), 332 deletions(-) diff --git a/mobile/lib/services/memories_cache_service.dart b/mobile/lib/services/memories_cache_service.dart index a4b3a3eb15..bfb8d21374 100644 --- a/mobile/lib/services/memories_cache_service.dart +++ b/mobile/lib/services/memories_cache_service.dart @@ -76,13 +76,6 @@ class MemoriesCacheService { }); } - Future _resetLastMemoriesCacheUpdateTime() async { - await _prefs.setInt( - _lastMemoriesCacheUpdateTimeKey, - DateTime.now().microsecondsSinceEpoch, - ); - } - int get lastMemoriesCacheUpdateTime { return _prefs.getInt(_lastMemoriesCacheUpdateTimeKey) ?? 0; } @@ -96,28 +89,6 @@ class MemoriesCacheService { Bus.instance.fire(MemoriesSettingChanged()); } - Future toggleOnThisDayNotifications() async { - final oldValue = localSettings.isOnThisDayNotificationsEnabled; - await localSettings.setOnThisDayNotificationsEnabled(!oldValue); - _logger.info("Turning onThisDayNotifications ${oldValue ? "off" : "on"}"); - if (oldValue) { - await _clearAllScheduledOnThisDayNotifications(); - } else { - queueUpdateCache(); - } - } - - Future toggleBirthdayNotifications() async { - final oldValue = localSettings.birthdayNotificationsEnabled; - await localSettings.setBirthdayNotificationsEnabled(!oldValue); - _logger.info("Turning birhtdayNotifications ${oldValue ? "off" : "on"}"); - if (oldValue) { - await _clearAllScheduledBirthdayNotifications(); - } else { - queueUpdateCache(); - } - } - bool get enableSmartMemories => flagService.hasGrantedMLConsent && localSettings.isMLLocalIndexingEnabled && @@ -145,11 +116,6 @@ class MemoriesCacheService { .microsecondsSinceEpoch; } - Future _getCachePath() async { - return (await getApplicationSupportDirectory()).path + - "/cache/memories_cache"; - } - Future markMemoryAsSeen(Memory memory, bool lastInList) async { memory.markSeen(); await _memoriesDB.markMemoryAsSeen( @@ -174,11 +140,130 @@ class MemoriesCacheService { unawaited(_prefs.setBool(_shouldUpdateCacheKey, true)); } - Future _cacheUpdated() async { - _shouldUpdate = false; - unawaited(_prefs.setBool(_shouldUpdateCacheKey, false)); - await _resetLastMemoriesCacheUpdateTime(); - Bus.instance.fire(MemoriesChangedEvent()); + Future> getMemories() async { + if (!showAnyMemories) { + _logger.info('Showing memories is disabled in settings, showing none'); + return []; + } + if (_cachedMemories != null && _cachedMemories!.isNotEmpty) { + return _cachedMemories!; + } + try { + if (!enableSmartMemories) { + await _calculateRegularFillers(); + return _cachedMemories!; + } + _cachedMemories = await _getMemoriesFromCache(); + if (_cachedMemories == null || _cachedMemories!.isEmpty) { + _logger.warning( + "No memories found in cache, force updating cache. Possible severe caching issue", + ); + await updateCache(forced: true); + } else { + _logger.info("Found memories in cache"); + } + if (_cachedMemories == null || _cachedMemories!.isEmpty) { + _logger + .severe("No memories found in (computed) cache, getting fillers"); + await _calculateRegularFillers(); + } + return _cachedMemories!; + } catch (e, s) { + _logger.severe("Error in getMemories", e, s); + return []; + } + } + + Future _calculateRegularFillers() async { + if (_cachedMemories == null) { + _cachedMemories = await smartMemoriesService.calcSimpleMemories(); + Bus.instance.fire(MemoriesChangedEvent()); + } + return; + } + + Future?> _getMemoriesFromCache() async { + final cache = await _readCacheFromDisk(); + if (cache == null) { + return null; + } + final result = await _fromCacheToMemories(cache); + return result; + } + + Future _readCacheFromDisk() async { + _logger.info("Reading memories cache result from disk"); + final file = File(await _getCachePath()); + if (!file.existsSync()) { + _logger.info("No memories cache found"); + return null; + } + final allFiles = Set.from( + await SearchService.instance.getAllFilesForSearch(), + ); + final allFileIdsToFile = {}; + for (final file in allFiles) { + if (file.uploadedFileID != null) { + allFileIdsToFile[file.uploadedFileID!] = file; + } + } + try { + final bytes = await file.readAsBytes(); + final jsonString = String.fromCharCodes(bytes); + final cache = + MemoriesCache.decodeFromJsonString(jsonString, allFileIdsToFile); + _logger.info("Reading memories cache result from disk done"); + return cache; + } catch (e, s) { + _logger.severe("Error reading or decoding cache file", e, s); + await file.delete(); + return null; + } + } + + Future> _fromCacheToMemories(MemoriesCache cache) async { + try { + _logger.info('Processing disk cache memories to smart memories'); + final List memories = []; + final allFiles = Set.from( + await SearchService.instance.getAllFilesForSearch(), + ); + final allFileIdsToFile = {}; + for (final file in allFiles) { + if (file.uploadedFileID != null) { + allFileIdsToFile[file.uploadedFileID!] = file; + } + } + final seenTimes = await _memoriesDB.getSeenTimes(); + + for (final ToShowMemory memory in cache.toShowMemories) { + if (memory.shouldShowNow()) { + final smartMemory = SmartMemory( + memory.fileUploadedIDs + .where((fileID) => allFileIdsToFile.containsKey(fileID)) + .map( + (fileID) => + Memory.fromFile(allFileIdsToFile[fileID]!, seenTimes), + ) + .toList(), + memory.type, + memory.title, + memory.firstTimeToShow, + memory.lastTimeToShow, + id: memory.id, + ); + if (smartMemory.memories.isNotEmpty) { + memories.add(smartMemory); + } + } + } + locationService.baseLocations = cache.baseLocations; + _logger.info('Processing of disk cache memories done'); + return memories; + } catch (e, s) { + _logger.severe("Error converting cache to memories", e, s); + return []; + } } Future updateCache({bool forced = false}) async { @@ -260,6 +345,21 @@ class MemoriesCacheService { }); } + Future _getCachePath() async { + return (await getApplicationSupportDirectory()).path + + "/cache/memories_cache"; + } + + Future _cacheUpdated() async { + _shouldUpdate = false; + unawaited(_prefs.setBool(_shouldUpdateCacheKey, false)); + await _prefs.setInt( + _lastMemoriesCacheUpdateTimeKey, + DateTime.now().microsecondsSinceEpoch, + ); + Bus.instance.fire(MemoriesChangedEvent()); + } + /// WARNING: Use for testing only, TODO: lau: remove later Future debugCacheForTesting() async { final oldCache = await _readCacheFromDisk(); @@ -267,16 +367,185 @@ class MemoriesCacheService { return newCache; } - Future _clearAllScheduledOnThisDayNotifications() async { - _logger.info('Clearing all scheduled On This Day notifications'); - await NotificationService.instance - .clearAllScheduledNotifications(containingPayload: "onThisDay"); + MemoriesCache _processOldCache(MemoriesCache? oldCache) { + final List peopleShownLogs = []; + final List clipShownLogs = []; + final List tripsShownLogs = []; + if (oldCache != null) { + final now = DateTime.now(); + for (final peopleLog in oldCache.peopleShownLogs) { + if (now.difference( + DateTime.fromMicrosecondsSinceEpoch(peopleLog.lastTimeShown), + ) < + maxShowTimeout) { + peopleShownLogs.add(peopleLog); + } + } + for (final tripsLog in oldCache.tripsShownLogs) { + if (now.difference( + DateTime.fromMicrosecondsSinceEpoch(tripsLog.lastTimeShown), + ) < + maxShowTimeout) { + tripsShownLogs.add(tripsLog); + } + } + for (final clipLog in oldCache.clipShownLogs) { + if (now.difference( + DateTime.fromMicrosecondsSinceEpoch(clipLog.lastTimeShown), + ) < + maxShowTimeout) { + clipShownLogs.add(clipLog); + } + } + for (final oldMemory in oldCache.toShowMemories) { + if (oldMemory.isOld) { + if (oldMemory.type == MemoryType.people) { + peopleShownLogs.add(PeopleShownLog.fromOldCacheMemory(oldMemory)); + } else if (oldMemory.type == MemoryType.clip) { + clipShownLogs.add(ClipShownLog.fromOldCacheMemory(oldMemory)); + } else if (oldMemory.type == MemoryType.trips) { + tripsShownLogs.add(TripsShownLog.fromOldCacheMemory(oldMemory)); + } + } + } + } + return MemoriesCache( + toShowMemories: [], + peopleShownLogs: peopleShownLogs, + clipShownLogs: clipShownLogs, + tripsShownLogs: tripsShownLogs, + baseLocations: [], + ); } - Future _clearAllScheduledBirthdayNotifications() async { - _logger.info('Clearing all scheduled birthday notifications'); - await NotificationService.instance - .clearAllScheduledNotifications(containingPayload: "birthday"); + Future clearMemoriesCache({bool fromDisk = true}) async { + if (fromDisk) { + final file = File(await _getCachePath()); + if (file.existsSync()) { + await file.delete(); + } + } + _cachedMemories = null; + } + + Future> getMemoriesForWidget({ + required bool onThisDay, + required bool pastYears, + required bool smart, + }) async { + if (!onThisDay && !pastYears && !smart) { + _logger.info( + 'No memories requested, returning empty list', + ); + return []; + } + final allMemories = await getMemories(); + if (onThisDay && pastYears && smart) { + return allMemories; + } + final filteredMemories = []; + for (final memory in allMemories) { + if (!memory.shouldShowNow()) continue; + if (memory.type == MemoryType.onThisDay) { + if (!onThisDay) continue; + } else if (memory.type == MemoryType.filler) { + if (!pastYears) continue; + } else { + if (!smart) continue; + } + filteredMemories.add(memory); + } + return filteredMemories; + } + + Future goToMemoryFromGeneratedFileID( + BuildContext context, + int generatedFileID, + ) async { + final allMemories = await getMemories(); + if (allMemories.isEmpty) return; + int memoryIdx = 0; + int fileIdx = 0; + bool found = false; + memoryLoop: + for (final memory in _cachedMemories!) { + for (final mem in memory.memories) { + if (mem.file.generatedID == generatedFileID) { + found = true; + break memoryLoop; + } + fileIdx++; + } + memoryIdx++; + fileIdx = 0; + } + if (!found) { + _logger.warning( + "Could not find memory with generatedFileID: $generatedFileID", + ); + return; + } + await routeToPage( + context, + FullScreenMemoryDataUpdater( + initialIndex: fileIdx, + memories: allMemories[memoryIdx].memories, + child: FullScreenMemory(allMemories[memoryIdx].title, fileIdx), + ), + forceCustomPageRoute: true, + ); + } + + Future goToOnThisDayMemory(BuildContext context) async { + final allMemories = await getMemories(); + if (allMemories.isEmpty) return; + int memoryIdx = 0; + bool found = false; + memoryLoop: + for (final memory in allMemories) { + if (memory.type == MemoryType.onThisDay) { + found = true; + break memoryLoop; + } + memoryIdx++; + } + if (!found) { + _logger.warning( + "Could not find onThisDay memory", + ); + return; + } + await routeToPage( + context, + FullScreenMemoryDataUpdater( + initialIndex: 0, + memories: allMemories[memoryIdx].memories, + child: FullScreenMemory(allMemories[memoryIdx].title, 0), + ), + forceCustomPageRoute: true, + ); + } + + Future toggleOnThisDayNotifications() async { + final oldValue = localSettings.isOnThisDayNotificationsEnabled; + await localSettings.setOnThisDayNotificationsEnabled(!oldValue); + _logger.info("Turning onThisDayNotifications ${oldValue ? "off" : "on"}"); + if (oldValue) { + await _clearAllScheduledOnThisDayNotifications(); + } else { + queueUpdateCache(); + } + } + + Future toggleBirthdayNotifications() async { + final oldValue = localSettings.birthdayNotificationsEnabled; + await localSettings.setBirthdayNotificationsEnabled(!oldValue); + _logger.info("Turning birhtdayNotifications ${oldValue ? "off" : "on"}"); + if (oldValue) { + await _clearAllScheduledBirthdayNotifications(); + } else { + queueUpdateCache(); + } } Future _scheduleMemoryNotifications( @@ -414,292 +683,15 @@ class MemoriesCacheService { } } - MemoriesCache _processOldCache(MemoriesCache? oldCache) { - final List peopleShownLogs = []; - final List clipShownLogs = []; - final List tripsShownLogs = []; - if (oldCache != null) { - final now = DateTime.now(); - for (final peopleLog in oldCache.peopleShownLogs) { - if (now.difference( - DateTime.fromMicrosecondsSinceEpoch(peopleLog.lastTimeShown), - ) < - maxShowTimeout) { - peopleShownLogs.add(peopleLog); - } - } - for (final tripsLog in oldCache.tripsShownLogs) { - if (now.difference( - DateTime.fromMicrosecondsSinceEpoch(tripsLog.lastTimeShown), - ) < - maxShowTimeout) { - tripsShownLogs.add(tripsLog); - } - } - for (final clipLog in oldCache.clipShownLogs) { - if (now.difference( - DateTime.fromMicrosecondsSinceEpoch(clipLog.lastTimeShown), - ) < - maxShowTimeout) { - clipShownLogs.add(clipLog); - } - } - for (final oldMemory in oldCache.toShowMemories) { - if (oldMemory.isOld) { - if (oldMemory.type == MemoryType.people) { - peopleShownLogs.add(PeopleShownLog.fromOldCacheMemory(oldMemory)); - } else if (oldMemory.type == MemoryType.clip) { - clipShownLogs.add(ClipShownLog.fromOldCacheMemory(oldMemory)); - } else if (oldMemory.type == MemoryType.trips) { - tripsShownLogs.add(TripsShownLog.fromOldCacheMemory(oldMemory)); - } - } - } - } - return MemoriesCache( - toShowMemories: [], - peopleShownLogs: peopleShownLogs, - clipShownLogs: clipShownLogs, - tripsShownLogs: tripsShownLogs, - baseLocations: [], - ); + Future _clearAllScheduledOnThisDayNotifications() async { + _logger.info('Clearing all scheduled On This Day notifications'); + await NotificationService.instance + .clearAllScheduledNotifications(containingPayload: "onThisDay"); } - Future> _fromCacheToMemories(MemoriesCache cache) async { - try { - _logger.info('Processing disk cache memories to smart memories'); - final List memories = []; - final allFiles = Set.from( - await SearchService.instance.getAllFilesForSearch(), - ); - final allFileIdsToFile = {}; - for (final file in allFiles) { - if (file.uploadedFileID != null) { - allFileIdsToFile[file.uploadedFileID!] = file; - } - } - final seenTimes = await _memoriesDB.getSeenTimes(); - - for (final ToShowMemory memory in cache.toShowMemories) { - if (memory.shouldShowNow()) { - final smartMemory = SmartMemory( - memory.fileUploadedIDs - .where((fileID) => allFileIdsToFile.containsKey(fileID)) - .map( - (fileID) => - Memory.fromFile(allFileIdsToFile[fileID]!, seenTimes), - ) - .toList(), - memory.type, - memory.title, - memory.firstTimeToShow, - memory.lastTimeToShow, - id: memory.id, - ); - if (smartMemory.memories.isNotEmpty) { - memories.add(smartMemory); - } - } - } - locationService.baseLocations = cache.baseLocations; - _logger.info('Processing of disk cache memories done'); - return memories; - } catch (e, s) { - _logger.severe("Error converting cache to memories", e, s); - return []; - } - } - - Future?> _getMemoriesFromCache() async { - final cache = await _readCacheFromDisk(); - if (cache == null) { - return null; - } - final result = await _fromCacheToMemories(cache); - return result; - } - - Future _calculateRegularFillers() async { - if (_cachedMemories == null) { - _cachedMemories = await smartMemoriesService.calcSimpleMemories(); - Bus.instance.fire(MemoriesChangedEvent()); - } - return; - } - - Future> getMemoriesForWidget({ - required bool onThisDay, - required bool pastYears, - required bool smart, - }) async { - if (!onThisDay && !pastYears && !smart) { - _logger.info( - 'No memories requested, returning empty list', - ); - return []; - } - final allMemories = await getMemories(); - if (onThisDay && pastYears && smart) { - return allMemories; - } - final filteredMemories = []; - for (final memory in allMemories) { - if (!memory.shouldShowNow()) continue; - if (memory.type == MemoryType.onThisDay) { - if (!onThisDay) continue; - } else if (memory.type == MemoryType.filler) { - if (!pastYears) continue; - } else { - if (!smart) continue; - } - filteredMemories.add(memory); - } - return filteredMemories; - } - - Future> getMemories() async { - if (!showAnyMemories) { - _logger.info('Showing memories is disabled in settings, showing none'); - return []; - } - if (_cachedMemories != null && _cachedMemories!.isNotEmpty) { - return _cachedMemories!; - } - try { - if (!enableSmartMemories) { - await _calculateRegularFillers(); - return _cachedMemories!; - } - _cachedMemories = await _getMemoriesFromCache(); - if (_cachedMemories == null || _cachedMemories!.isEmpty) { - _logger.warning( - "No memories found in cache, force updating cache. Possible severe caching issue", - ); - await updateCache(forced: true); - } else { - _logger.info("Found memories in cache"); - } - if (_cachedMemories == null || _cachedMemories!.isEmpty) { - _logger - .severe("No memories found in (computed) cache, getting fillers"); - await _calculateRegularFillers(); - } - return _cachedMemories!; - } catch (e, s) { - _logger.severe("Error in getMemories", e, s); - return []; - } - } - - Future?> getCachedMemories() async { - return _cachedMemories; - } - - Future goToMemoryFromGeneratedFileID( - BuildContext context, - int generatedFileID, - ) async { - final allMemories = await getMemories(); - if (allMemories.isEmpty) return; - int memoryIdx = 0; - int fileIdx = 0; - bool found = false; - memoryLoop: - for (final memory in _cachedMemories!) { - for (final mem in memory.memories) { - if (mem.file.generatedID == generatedFileID) { - found = true; - break memoryLoop; - } - fileIdx++; - } - memoryIdx++; - fileIdx = 0; - } - if (!found) { - _logger.warning( - "Could not find memory with generatedFileID: $generatedFileID", - ); - return; - } - await routeToPage( - context, - FullScreenMemoryDataUpdater( - initialIndex: fileIdx, - memories: allMemories[memoryIdx].memories, - child: FullScreenMemory(allMemories[memoryIdx].title, fileIdx), - ), - forceCustomPageRoute: true, - ); - } - - Future goToOnThisDayMemory(BuildContext context) async { - final allMemories = await getMemories(); - if (allMemories.isEmpty) return; - int memoryIdx = 0; - bool found = false; - memoryLoop: - for (final memory in allMemories) { - if (memory.type == MemoryType.onThisDay) { - found = true; - break memoryLoop; - } - memoryIdx++; - } - if (!found) { - _logger.warning( - "Could not find onThisDay memory", - ); - return; - } - await routeToPage( - context, - FullScreenMemoryDataUpdater( - initialIndex: 0, - memories: allMemories[memoryIdx].memories, - child: FullScreenMemory(allMemories[memoryIdx].title, 0), - ), - forceCustomPageRoute: true, - ); - } - - Future _readCacheFromDisk() async { - _logger.info("Reading memories cache result from disk"); - final file = File(await _getCachePath()); - if (!file.existsSync()) { - _logger.info("No memories cache found"); - return null; - } - final allFiles = Set.from( - await SearchService.instance.getAllFilesForSearch(), - ); - final allFileIdsToFile = {}; - for (final file in allFiles) { - if (file.uploadedFileID != null) { - allFileIdsToFile[file.uploadedFileID!] = file; - } - } - try { - final bytes = await file.readAsBytes(); - final jsonString = String.fromCharCodes(bytes); - final cache = - MemoriesCache.decodeFromJsonString(jsonString, allFileIdsToFile); - _logger.info("Reading memories cache result from disk done"); - return cache; - } catch (e, s) { - _logger.severe("Error reading or decoding cache file", e, s); - await file.delete(); - return null; - } - } - - Future clearMemoriesCache({bool fromDisk = true}) async { - if (fromDisk) { - final file = File(await _getCachePath()); - if (file.existsSync()) { - await file.delete(); - } - } - _cachedMemories = null; + Future _clearAllScheduledBirthdayNotifications() async { + _logger.info('Clearing all scheduled birthday notifications'); + await NotificationService.instance + .clearAllScheduledNotifications(containingPayload: "birthday"); } }