diff --git a/mobile/lib/app.dart b/mobile/lib/app.dart index 55491085c4..c0f1b0950c 100644 --- a/mobile/lib/app.dart +++ b/mobile/lib/app.dart @@ -75,7 +75,7 @@ class _EnteAppState extends State with WidgetsBindingObserver { (event) async { _changeCallbackDebouncer.run( () async => - unawaited(PeopleHomeWidgetService.instance.peopleChanged()), + unawaited(PeopleHomeWidgetService.instance.checkPeopleChanged()), ); }, ); diff --git a/mobile/lib/db/entities_db.dart b/mobile/lib/db/entities_db.dart index 3cd9d47639..d4becaf744 100644 --- a/mobile/lib/db/entities_db.dart +++ b/mobile/lib/db/entities_db.dart @@ -99,4 +99,19 @@ extension EntitiesDB on FilesDB { } return LocalEntityData.fromJson(maps.first); } + + Future getPreHashForEntities( + EntityType type, + List ids, + ) async { + final db = await sqliteAsyncDB; + final maps = await db.get( + 'SELECT GROUP_CONCAT(id || \':\' || updatedAt, \',\') FROM entities WHERE type = ? AND id IN (${List.filled(ids.length, '?').join(',')})', + [type.name, ...ids], + ); + if (maps.isEmpty) { + return null; + } + return maps.values.first as String?; + } } diff --git a/mobile/lib/services/album_home_widget_service.dart b/mobile/lib/services/album_home_widget_service.dart index 4bf8864940..2a5d422d14 100644 --- a/mobile/lib/services/album_home_widget_service.dart +++ b/mobile/lib/services/album_home_widget_service.dart @@ -110,6 +110,7 @@ class AlbumHomeWidgetService { await _setTotalAlbums(null); await updateAlbumsStatus(WidgetStatus.syncedEmpty); _hasSyncedAlbums = false; + await setAlbumsLastHash(""); await _refreshWidget(message: "AlbumsHomeWidget cleared & updated"); } @@ -183,7 +184,7 @@ class AlbumHomeWidgetService { for (final albumId in albumIds) { final collection = CollectionsService.instance.getCollectionByID(albumId); if (collection != null) { - updationTimestamps += "${collection.updationTime.toString()}_"; + updationTimestamps += "$albumId:${collection.updationTime.toString()}_"; } } @@ -386,6 +387,7 @@ class AlbumHomeWidgetService { } Future _loadAndRenderAlbums() async { + final selectedAlbumIds = await _getEffectiveSelectedAlbumIds(); final albumsWithFiles = await _getAlbumsWithFiles(); if (albumsWithFiles.isEmpty) { @@ -465,7 +467,6 @@ class AlbumHomeWidgetService { } // Update the hash to track changes - final selectedAlbumIds = await _getEffectiveSelectedAlbumIds(); final hash = _calculateHash(selectedAlbumIds); await setAlbumsLastHash(hash); diff --git a/mobile/lib/services/entity_service.dart b/mobile/lib/services/entity_service.dart index 2986a33ef5..9226eafe7f 100644 --- a/mobile/lib/services/entity_service.dart +++ b/mobile/lib/services/entity_service.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:math'; +import "package:crypto/crypto.dart"; import "package:ente_crypto/ente_crypto.dart"; import 'package:flutter/foundation.dart'; import 'package:logging/logging.dart'; @@ -219,4 +220,22 @@ class EntityService { rethrow; } } + + Future getPreHashForEntities( + EntityType type, + List ids, + ) async { + return await _db.getPreHashForEntities(type, ids); + } + + Future getHashForIds(List personIds) async { + final preHash = await getPreHashForEntities(EntityType.cgroup, personIds); + + if (preHash == null) { + return ""; + } + + final hash = md5.convert(utf8.encode(preHash)).toString().substring(0, 10); + return hash; + } } diff --git a/mobile/lib/services/machine_learning/face_ml/person/person_service.dart b/mobile/lib/services/machine_learning/face_ml/person/person_service.dart index 7c96a67dea..dd1283b9ac 100644 --- a/mobile/lib/services/machine_learning/face_ml/person/person_service.dart +++ b/mobile/lib/services/machine_learning/face_ml/person/person_service.dart @@ -75,7 +75,10 @@ class PersonService { final entities = await entityService.getEntities(EntityType.cgroup); return entities .map( - (e) => PersonEntity(e.id, PersonData.fromJson(json.decode(e.data))), + (e) => PersonEntity( + e.id, + PersonData.fromJson(json.decode(e.data)), + ), ) .toList(); } @@ -85,7 +88,10 @@ class PersonService { if (e == null) { return null; } - return PersonEntity(e.id, PersonData.fromJson(json.decode(e.data))); + return PersonEntity( + e.id, + PersonData.fromJson(json.decode(e.data)), + ); }); } @@ -93,8 +99,10 @@ class PersonService { final entities = await entityService.getEntities(EntityType.cgroup); final Map map = {}; for (var e in entities) { - final person = - PersonEntity(e.id, PersonData.fromJson(json.decode(e.data))); + final person = PersonEntity( + e.id, + PersonData.fromJson(json.decode(e.data)), + ); map[person.remoteID] = person; } return map; diff --git a/mobile/lib/services/people_home_widget_service.dart b/mobile/lib/services/people_home_widget_service.dart index d9f618f6fc..a44a70159b 100644 --- a/mobile/lib/services/people_home_widget_service.dart +++ b/mobile/lib/services/people_home_widget_service.dart @@ -23,6 +23,7 @@ import 'package:synchronized/synchronized.dart'; class PeopleHomeWidgetService { // Constants static const String SELECTED_PEOPLE_KEY = "selectedPeopleHW"; + static const String PEOPLE_LAST_HASH_KEY = "peopleLastHash"; static const String ANDROID_CLASS_NAME = "EntePeopleWidgetProvider"; static const String IOS_CLASS_NAME = "EntePeopleWidget"; static const String PEOPLE_STATUS_KEY = "peopleStatusKey.widget"; @@ -39,6 +40,7 @@ class PeopleHomeWidgetService { final Logger _logger = Logger((PeopleHomeWidgetService).toString()); late final SharedPreferences _prefs; final _peopleForceRefreshLock = Lock(); + final _lock2 = Lock(); bool _hasSyncedPeople = false; // Initialization @@ -69,6 +71,14 @@ class PeopleHomeWidgetService { await updatePeopleChanged(true); } + String? getPeopleLastHash() { + return _prefs.getString(PEOPLE_LAST_HASH_KEY); + } + + Future setPeopleLastHash(String hash) async { + await _prefs.setString(PEOPLE_LAST_HASH_KEY, hash); + } + Future countHomeWidgets() async { return await HomeWidgetService.instance.countHomeWidgets( ANDROID_CLASS_NAME, @@ -112,6 +122,7 @@ class PeopleHomeWidgetService { await _setTotalPeople(null); _hasSyncedPeople = false; await updatePeopleStatus(WidgetStatus.syncedEmpty); + await setPeopleLastHash(""); await _refreshWidget(message: "PeopleHomeWidget cleared & updated"); } @@ -147,20 +158,22 @@ class PeopleHomeWidgetService { await HomeWidgetService.instance.initHomeWidget(); } - Future peopleChanged() async { - await updatePeopleChanged(true); + Future checkPeopleChanged() async { + final havePeopleChanged = await _lock2.synchronized(() async { + final peopleIds = await _getEffectiveSelectedPeopleIds(); + final currentHash = await _calculateHash(peopleIds); + final lastHash = getPeopleLastHash(); + if (peopleIds.isEmpty || currentHash == lastHash) { + return false; + } + return true; + }); - final cachedMemories = await _getPeople(); - final currentTotal = cachedMemories.length; - final existingTotal = await _getTotalPeople() ?? 0; - - if (existingTotal == currentTotal && existingTotal == 0) { - await updatePeopleChanged(false); - _logger.info("People empty, no update needed"); + await updatePeopleChanged(havePeopleChanged); + if (!havePeopleChanged) { + _logger.info("No changes detected in people, skipping update"); return; } - - _logger.info("People changed, updating widget"); await initHomeWidget(true); } @@ -219,6 +232,10 @@ class PeopleHomeWidgetService { await updatePeopleChanged(false); } + Future _calculateHash(List peopleIds) async { + return await entityService.getHashForIds(peopleIds); + } + Future _hasAnyBlockers() async { // Check if first import is completed final hasCompletedFirstImport = @@ -363,6 +380,7 @@ class PeopleHomeWidgetService { } Future _loadAndRenderPeople() async { + final peopleIds = await _getEffectiveSelectedPeopleIds(); final peopleWithFiles = await _getPeople(); if (peopleWithFiles.isEmpty) { @@ -448,6 +466,9 @@ class PeopleHomeWidgetService { await updatePeopleStatus(WidgetStatus.syncedAll); } + final hash = await _calculateHash(peopleIds); + await setPeopleLastHash(hash); + await _refreshWidget( message: "Switched to next people set, total: $renderedCount", ); diff --git a/mobile/lib/ui/settings/widgets/people_widget_settings.dart b/mobile/lib/ui/settings/widgets/people_widget_settings.dart index 564aa736e5..a0d0abbaaa 100644 --- a/mobile/lib/ui/settings/widgets/people_widget_settings.dart +++ b/mobile/lib/ui/settings/widgets/people_widget_settings.dart @@ -72,7 +72,7 @@ class _PeopleWidgetSettingsState extends State { ); Navigator.pop(context); await PeopleHomeWidgetService.instance - .peopleChanged(); + .checkPeopleChanged(); }, ); },