From 5236a72fb358e120e348683b209c0b0829d82c4d Mon Sep 17 00:00:00 2001 From: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> Date: Fri, 5 Sep 2025 04:15:16 +0530 Subject: [PATCH] migrate hashes from remote asset table --- .../services/background_worker.service.dart | 12 +++---- mobile/lib/domain/services/hash.service.dart | 17 ++++++++-- mobile/lib/domain/utils/background_sync.dart | 4 +-- .../lib/domain/utils/migrate_cloud_ids.dart | 2 +- .../entities/merged_asset.drift | 9 ++---- .../entities/merged_asset.drift.dart | 4 +-- .../repositories/backup.repository.dart | 12 +++---- .../repositories/local_asset.repository.dart | 31 +++++++++++++++---- .../repositories/remote_asset.repository.dart | 3 +- .../repositories/timeline.repository.dart | 9 ++---- mobile/lib/utils/migration.dart | 20 +++++------- .../domain/services/hash_service_test.dart | 17 ++++++---- 12 files changed, 78 insertions(+), 62 deletions(-) diff --git a/mobile/lib/domain/services/background_worker.service.dart b/mobile/lib/domain/services/background_worker.service.dart index 9f366ad30b..83aaccedf8 100644 --- a/mobile/lib/domain/services/background_worker.service.dart +++ b/mobile/lib/domain/services/background_worker.service.dart @@ -207,9 +207,10 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi { } Future _syncAssets({Duration? hashTimeout}) async { - final futures = >[]; - - final localSyncFuture = _ref.read(backgroundSyncProvider).syncLocal().then((_) async { + await ( + _ref.read(backgroundSyncProvider).syncLocal(), + _ref.read(backgroundSyncProvider).syncRemote(), + ).wait.whenComplete(() async { if (_isCleanedUp) { return; } @@ -226,11 +227,6 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi { return hashFuture; }); - - futures.add(localSyncFuture); - futures.add(_ref.read(backgroundSyncProvider).syncRemote()); - - await Future.wait(futures); } } diff --git a/mobile/lib/domain/services/hash.service.dart b/mobile/lib/domain/services/hash.service.dart index 8044b298d3..cadb11f7c2 100644 --- a/mobile/lib/domain/services/hash.service.dart +++ b/mobile/lib/domain/services/hash.service.dart @@ -38,6 +38,10 @@ class HashService { Future hashAssets() async { _log.info("Starting hashing of assets"); final Stopwatch stopwatch = Stopwatch()..start(); + + // Migrate hashes from cloud ID to local ID so we don't have to re-hash them + await _migrateHashes(); + // Sorted by backupSelection followed by isCloud final localAlbums = await _localAlbumRepository.getAll( sortBy: {SortLocalAlbumsBy.backupSelection, SortLocalAlbumsBy.isIosSharedAlbum}, @@ -59,6 +63,15 @@ class HashService { _log.info("Hashing took - ${stopwatch.elapsedMilliseconds}ms"); } + Future _migrateHashes() async { + final hashMappings = await _localAssetRepository.getHashMappingFromCloudId(); + if (hashMappings.isEmpty) { + return; + } + + await _localAssetRepository.updateHashes(hashMappings); + } + /// Processes a list of [LocalAsset]s, storing their hash and updating the assets in the DB /// with hash for those that were successfully hashed. Hashes are looked up in a table /// [LocalAssetHashEntity] by local id. Only missing entries are newly hashed and added to the DB. @@ -101,7 +114,7 @@ class HashService { _log.fine("Hashing ${toHash.length} files"); - final hashed = []; + final hashed = []; final hashes = await _nativeSyncApi.hashPaths(toHash.map((e) => e.path).toList()); assert( hashes.length == toHash.length, @@ -117,7 +130,7 @@ class HashService { final hash = hashes[i]; final asset = toHash[i].asset; if (hash?.length == 20) { - hashed.add(asset.copyWith(checksum: base64.encode(hash!))); + hashed.add((assetId: asset.id, checksum: base64.encode(hash!))); } else { _log.warning( "Failed to hash file for ${asset.id}: ${asset.name} created at ${asset.createdAt} from album: ${album.name}", diff --git a/mobile/lib/domain/utils/background_sync.dart b/mobile/lib/domain/utils/background_sync.dart index b33ea2a386..d81c05cbc0 100644 --- a/mobile/lib/domain/utils/background_sync.dart +++ b/mobile/lib/domain/utils/background_sync.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:immich_mobile/domain/utils/migrate_cloud_ids.dart'; +import 'package:immich_mobile/domain/utils/migrate_cloud_ids.dart' as m; import 'package:immich_mobile/domain/utils/sync_linked_album.dart'; import 'package:immich_mobile/providers/infrastructure/sync.provider.dart'; import 'package:immich_mobile/utils/isolate.dart'; @@ -195,7 +195,7 @@ class BackgroundSyncManager { onCloudIdSyncStart?.call(); - _cloudIdSyncTask = runInIsolateGentle(computation: migrateCloudIds); + _cloudIdSyncTask = runInIsolateGentle(computation: m.syncCloudIds); return _cloudIdSyncTask! .whenComplete(() { onCloudIdSyncComplete?.call(); diff --git a/mobile/lib/domain/utils/migrate_cloud_ids.dart b/mobile/lib/domain/utils/migrate_cloud_ids.dart index 5c6f2dfb28..d372e5651d 100644 --- a/mobile/lib/domain/utils/migrate_cloud_ids.dart +++ b/mobile/lib/domain/utils/migrate_cloud_ids.dart @@ -12,7 +12,7 @@ import 'package:logging/logging.dart'; // ignore: import_rule_openapi import 'package:openapi/api.dart'; -Future migrateCloudIds(ProviderContainer ref) async { +Future syncCloudIds(ProviderContainer ref) async { final db = ref.read(driftProvider); // Populate cloud IDs for local assets that don't have one yet await _populateCloudIds(db); diff --git a/mobile/lib/infrastructure/entities/merged_asset.drift b/mobile/lib/infrastructure/entities/merged_asset.drift index 63f68a6d0b..5f94497323 100644 --- a/mobile/lib/infrastructure/entities/merged_asset.drift +++ b/mobile/lib/infrastructure/entities/merged_asset.drift @@ -7,8 +7,7 @@ import 'local_album_asset.entity.dart'; mergedAsset: SELECT rae.id as remote_id, - (SELECT lae.id FROM local_asset_entity lae - WHERE lae.checksum = rae.checksum OR lae.cloud_id = rae.cloud_id LIMIT 1) as local_id, + (SELECT lae.id FROM local_asset_entity lae WHERE lae.checksum = rae.checksum LIMIT 1) as local_id, rae.name, rae."type", rae.created_at as created_at, @@ -60,8 +59,7 @@ SELECT FROM local_asset_entity lae WHERE NOT EXISTS ( - SELECT 1 FROM remote_asset_entity rae WHERE - (rae.checksum = lae.checksum OR rae.cloud_id = lae.cloud_id) AND rae.owner_id IN :user_ids + SELECT 1 FROM remote_asset_entity rae WHERE rae.checksum = lae.checksum AND rae.owner_id IN :user_ids ) AND EXISTS ( SELECT 1 FROM local_album_asset_entity laa @@ -105,8 +103,7 @@ FROM FROM local_asset_entity lae WHERE NOT EXISTS ( - SELECT 1 FROM remote_asset_entity rae - WHERE (rae.checksum = lae.checksum OR rae.cloud_id = lae.cloud_id) AND rae.owner_id IN :user_ids + SELECT 1 FROM remote_asset_entity rae WHERE rae.checksum = lae.checksum AND rae.owner_id IN :user_ids ) AND EXISTS ( SELECT 1 FROM local_album_asset_entity laa diff --git a/mobile/lib/infrastructure/entities/merged_asset.drift.dart b/mobile/lib/infrastructure/entities/merged_asset.drift.dart index 70270986ff..a241db1a64 100644 --- a/mobile/lib/infrastructure/entities/merged_asset.drift.dart +++ b/mobile/lib/infrastructure/entities/merged_asset.drift.dart @@ -29,7 +29,7 @@ class MergedAssetDrift extends i1.ModularAccessor { ); $arrayStartIndex += generatedlimit.amountOfVariables; return customSelect( - 'SELECT rae.id AS remote_id, (SELECT lae.id FROM local_asset_entity AS lae WHERE lae.checksum = rae.checksum OR lae.cloud_id = rae.cloud_id LIMIT 1) AS local_id, rae.name, rae.type, rae.created_at AS created_at, rae.updated_at, rae.width, rae.height, rae.duration_in_seconds, rae.is_favorite, rae.thumb_hash, rae.checksum, rae.owner_id, rae.live_photo_video_id, 0 AS orientation, rae.stack_id, rae.cloud_id FROM remote_asset_entity AS rae LEFT JOIN stack_entity AS se ON rae.stack_id = se.id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandeduserIds) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT NULL AS remote_id, lae.id AS local_id, lae.name, lae.type, lae.created_at AS created_at, lae.updated_at, lae.width, lae.height, lae.duration_in_seconds, lae.is_favorite, NULL AS thumb_hash, lae.checksum, NULL AS owner_id, NULL AS live_photo_video_id, lae.orientation, NULL AS stack_id, lae.cloud_id FROM local_asset_entity AS lae WHERE NOT EXISTS (SELECT 1 FROM remote_asset_entity AS rae WHERE(rae.checksum = lae.checksum OR rae.cloud_id = lae.cloud_id)AND rae.owner_id IN ($expandeduserIds)) AND EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 0) AND NOT EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 2) ORDER BY created_at DESC ${generatedlimit.sql}', + 'SELECT rae.id AS remote_id, (SELECT lae.id FROM local_asset_entity AS lae WHERE lae.checksum = rae.checksum LIMIT 1) AS local_id, rae.name, rae.type, rae.created_at AS created_at, rae.updated_at, rae.width, rae.height, rae.duration_in_seconds, rae.is_favorite, rae.thumb_hash, rae.checksum, rae.owner_id, rae.live_photo_video_id, 0 AS orientation, rae.stack_id, rae.cloud_id FROM remote_asset_entity AS rae LEFT JOIN stack_entity AS se ON rae.stack_id = se.id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandeduserIds) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT NULL AS remote_id, lae.id AS local_id, lae.name, lae.type, lae.created_at AS created_at, lae.updated_at, lae.width, lae.height, lae.duration_in_seconds, lae.is_favorite, NULL AS thumb_hash, lae.checksum, NULL AS owner_id, NULL AS live_photo_video_id, lae.orientation, NULL AS stack_id, lae.cloud_id FROM local_asset_entity AS lae WHERE NOT EXISTS (SELECT 1 FROM remote_asset_entity AS rae WHERE rae.checksum = lae.checksum AND rae.owner_id IN ($expandeduserIds)) AND EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 0) AND NOT EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 2) ORDER BY created_at DESC ${generatedlimit.sql}', variables: [ for (var $ in userIds) i0.Variable($), ...generatedlimit.introducedVariables, @@ -75,7 +75,7 @@ class MergedAssetDrift extends i1.ModularAccessor { final expandeduserIds = $expandVar($arrayStartIndex, userIds.length); $arrayStartIndex += userIds.length; return customSelect( - 'SELECT COUNT(*) AS asset_count, CASE WHEN ?1 = 0 THEN STRFTIME(\'%Y-%m-%d\', created_at, \'localtime\') WHEN ?1 = 1 THEN STRFTIME(\'%Y-%m\', created_at, \'localtime\') END AS bucket_date FROM (SELECT rae.created_at FROM remote_asset_entity AS rae LEFT JOIN stack_entity AS se ON rae.stack_id = se.id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandeduserIds) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT lae.created_at FROM local_asset_entity AS lae WHERE NOT EXISTS (SELECT 1 FROM remote_asset_entity AS rae WHERE(rae.checksum = lae.checksum OR rae.cloud_id = lae.cloud_id)AND rae.owner_id IN ($expandeduserIds)) AND EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 0) AND NOT EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 2)) GROUP BY bucket_date ORDER BY bucket_date DESC', + 'SELECT COUNT(*) AS asset_count, CASE WHEN ?1 = 0 THEN STRFTIME(\'%Y-%m-%d\', created_at, \'localtime\') WHEN ?1 = 1 THEN STRFTIME(\'%Y-%m\', created_at, \'localtime\') END AS bucket_date FROM (SELECT rae.created_at FROM remote_asset_entity AS rae LEFT JOIN stack_entity AS se ON rae.stack_id = se.id WHERE rae.deleted_at IS NULL AND rae.visibility = 0 AND rae.owner_id IN ($expandeduserIds) AND(rae.stack_id IS NULL OR rae.id = se.primary_asset_id)UNION ALL SELECT lae.created_at FROM local_asset_entity AS lae WHERE NOT EXISTS (SELECT 1 FROM remote_asset_entity AS rae WHERE rae.checksum = lae.checksum AND rae.owner_id IN ($expandeduserIds)) AND EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 0) AND NOT EXISTS (SELECT 1 FROM local_album_asset_entity AS laa INNER JOIN local_album_entity AS la ON laa.album_id = la.id WHERE laa.asset_id = lae.id AND la.backup_selection = 2)) GROUP BY bucket_date ORDER BY bucket_date DESC', variables: [ i0.Variable(groupBy), for (var $ in userIds) i0.Variable($), diff --git a/mobile/lib/infrastructure/repositories/backup.repository.dart b/mobile/lib/infrastructure/repositories/backup.repository.dart index b8998a8c40..057c7a7bf6 100644 --- a/mobile/lib/infrastructure/repositories/backup.repository.dart +++ b/mobile/lib/infrastructure/repositories/backup.repository.dart @@ -64,8 +64,7 @@ class DriftBackupRepository extends DriftDatabaseRepository { ), leftOuterJoin( _db.remoteAssetEntity, - (_db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum) | - _db.localAssetEntity.cloudId.equalsExp(_db.remoteAssetEntity.cloudId)) & + _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum) & _db.remoteAssetEntity.ownerId.equals(userId), useColumns: false, ), @@ -95,8 +94,7 @@ class DriftBackupRepository extends DriftDatabaseRepository { ), innerJoin( _db.remoteAssetEntity, - _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum) | - _db.localAssetEntity.cloudId.equalsExp(_db.remoteAssetEntity.cloudId), + _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum), useColumns: false, ), ]) @@ -118,7 +116,7 @@ class DriftBackupRepository extends DriftDatabaseRepository { final query = _db.localAssetEntity.select() ..where( (lae) => - (lae.checksum.isNotNull() | lae.cloudId.isNotNull()) & + lae.checksum.isNotNull() & existsQuery( _db.localAlbumAssetEntity.selectOnly() ..addColumns([_db.localAlbumAssetEntity.assetId]) @@ -131,9 +129,7 @@ class DriftBackupRepository extends DriftDatabaseRepository { _db.remoteAssetEntity.selectOnly() ..addColumns([_db.remoteAssetEntity.checksum]) ..where( - (_db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum) | - _db.localAssetEntity.cloudId.equalsExp(_db.remoteAssetEntity.cloudId)) & - _db.remoteAssetEntity.ownerId.equals(userId), + _db.remoteAssetEntity.checksum.equalsExp(lae.checksum) & _db.remoteAssetEntity.ownerId.equals(userId), ), ) & lae.id.isNotInQuery(_getExcludedSubquery()), diff --git a/mobile/lib/infrastructure/repositories/local_asset.repository.dart b/mobile/lib/infrastructure/repositories/local_asset.repository.dart index eba603dce8..f621dfba55 100644 --- a/mobile/lib/infrastructure/repositories/local_asset.repository.dart +++ b/mobile/lib/infrastructure/repositories/local_asset.repository.dart @@ -5,6 +5,8 @@ import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart'; import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart'; import 'package:immich_mobile/infrastructure/repositories/db.repository.dart'; +typedef LocalAssetHashMapping = ({String assetId, String checksum}); + class DriftLocalAssetRepository extends DriftDatabaseRepository { final Drift _db; const DriftLocalAssetRepository(this._db) : super(_db); @@ -13,8 +15,7 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository { final query = _db.localAssetEntity.select().addColumns([_db.remoteAssetEntity.id]).join([ leftOuterJoin( _db.remoteAssetEntity, - _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum) | - _db.localAssetEntity.cloudId.equalsExp(_db.remoteAssetEntity.cloudId), + _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum), useColumns: false, ), ])..where(_db.localAssetEntity.id.equals(id)); @@ -29,17 +30,17 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository { Stream watch(String id) => _assetSelectable(id).watchSingleOrNull(); - Future updateHashes(Iterable hashes) { + Future updateHashes(Iterable hashes) { if (hashes.isEmpty) { return Future.value(); } return _db.batch((batch) async { - for (final asset in hashes) { + for (final mapping in hashes) { batch.update( _db.localAssetEntity, - LocalAssetEntityCompanion(checksum: Value(asset.checksum)), - where: (e) => e.id.equals(asset.id), + LocalAssetEntityCompanion(checksum: Value(mapping.checksum)), + where: (e) => e.id.equals(mapping.assetId), ); } }); @@ -70,4 +71,22 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository { Future getHashedCount() { return _db.managers.localAssetEntity.filter((e) => e.checksum.isNull().not()).count(); } + + Future> getHashMappingFromCloudId() async { + final query = + _db.localAssetEntity.selectOnly().join([ + leftOuterJoin( + _db.remoteAssetEntity, + _db.localAssetEntity.cloudId.equalsExp(_db.remoteAssetEntity.cloudId), + useColumns: false, + ), + ]) + ..addColumns([_db.localAssetEntity.id, _db.remoteAssetEntity.checksum]) + ..where(_db.remoteAssetEntity.cloudId.isNotNull() & _db.localAssetEntity.checksum.isNull()); + return query + .map( + (row) => (assetId: row.read(_db.localAssetEntity.id)!, checksum: row.read(_db.remoteAssetEntity.checksum)!), + ) + .get(); + } } diff --git a/mobile/lib/infrastructure/repositories/remote_asset.repository.dart b/mobile/lib/infrastructure/repositories/remote_asset.repository.dart index 1984e6ffdc..3ed7dddfe8 100644 --- a/mobile/lib/infrastructure/repositories/remote_asset.repository.dart +++ b/mobile/lib/infrastructure/repositories/remote_asset.repository.dart @@ -34,8 +34,7 @@ class RemoteAssetRepository extends DriftDatabaseRepository { _db.remoteAssetEntity.select().addColumns([_db.localAssetEntity.id]).join([ leftOuterJoin( _db.localAssetEntity, - _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum) | - _db.localAssetEntity.cloudId.equalsExp(_db.remoteAssetEntity.cloudId), + _db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum), useColumns: false, ), ]) diff --git a/mobile/lib/infrastructure/repositories/timeline.repository.dart b/mobile/lib/infrastructure/repositories/timeline.repository.dart index fbd2cb02ef..537564ad9f 100644 --- a/mobile/lib/infrastructure/repositories/timeline.repository.dart +++ b/mobile/lib/infrastructure/repositories/timeline.repository.dart @@ -118,8 +118,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository { ), leftOuterJoin( _db.remoteAssetEntity, - _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum) | - _db.localAssetEntity.cloudId.equalsExp(_db.remoteAssetEntity.cloudId), + _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum), useColumns: false, ), ]) @@ -145,8 +144,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository { ), leftOuterJoin( _db.remoteAssetEntity, - _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum) | - _db.localAssetEntity.cloudId.equalsExp(_db.remoteAssetEntity.cloudId), + _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum), useColumns: false, ), ]) @@ -541,8 +539,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository { _db.remoteAssetEntity.select().join([ leftOuterJoin( _db.localAssetEntity, - _db.localAssetEntity.checksum.equalsExp(_db.remoteAssetEntity.checksum) | - _db.localAssetEntity.cloudId.equalsExp(_db.remoteAssetEntity.cloudId), + _db.remoteAssetEntity.checksum.equalsExp(_db.localAssetEntity.checksum), useColumns: false, ), ]) diff --git a/mobile/lib/utils/migration.dart b/mobile/lib/utils/migration.dart index cdead7c949..c6785f5bc0 100644 --- a/mobile/lib/utils/migration.dart +++ b/mobile/lib/utils/migration.dart @@ -31,7 +31,6 @@ import 'package:immich_mobile/providers/backup/backup.provider.dart'; import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/utils/diff.dart'; import 'package:isar/isar.dart'; -import 'package:logging/logging.dart'; // ignore: import_rule_photo_manager import 'package:photo_manager/photo_manager.dart'; @@ -268,21 +267,16 @@ class _DeviceAsset { const _DeviceAsset({required this.assetId, this.hash, this.dateTime}); } -Future> runNewSync(WidgetRef ref, {bool full = false}) { +Future runNewSync(WidgetRef ref, {bool full = false}) { ref.read(backupProvider.notifier).cancelBackup(); final backgroundManager = ref.read(backgroundSyncProvider); final isAlbumLinkedSyncEnable = ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.syncAlbums); - return Future.wait([ - backgroundManager.syncLocal(full: full).then((_) { - Logger("runNewSync").fine("Hashing assets after syncLocal"); - return backgroundManager.hashAssets(); - }), - backgroundManager.syncRemote().then((_) { - if (isAlbumLinkedSyncEnable) { - return backgroundManager.syncLinkedAlbum(); - } - }), - ]); + return (backgroundManager.syncLocal(full: full), backgroundManager.syncRemote()).wait.whenComplete(() async { + await backgroundManager.hashAssets(); + if (isAlbumLinkedSyncEnable) { + await backgroundManager.syncLinkedAlbum(); + } + }); } diff --git a/mobile/test/domain/services/hash_service_test.dart b/mobile/test/domain/services/hash_service_test.dart index 7969131e7f..25ab3e2cb0 100644 --- a/mobile/test/domain/services/hash_service_test.dart +++ b/mobile/test/domain/services/hash_service_test.dart @@ -3,9 +3,9 @@ import 'dart:io'; import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; -import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; import 'package:immich_mobile/domain/services/hash.service.dart'; import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart'; +import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart'; import 'package:mocktail/mocktail.dart'; import '../../fixtures/album.stub.dart'; @@ -39,6 +39,7 @@ void main() { registerFallbackValue(LocalAlbumStub.recent); registerFallbackValue(LocalAssetStub.image1); + when(() => mockAssetRepo.getHashMappingFromCloudId()).thenAnswer((_) async => []); when(() => mockAssetRepo.updateHashes(any())).thenAnswer((_) async => {}); when(() => mockStorageRepo.clearCache()).thenAnswer((_) async => {}); }); @@ -87,7 +88,8 @@ void main() { await sut.hashAssets(); verify(() => mockNativeApi.hashPaths(['image-path'])).called(1); - final captured = verify(() => mockAssetRepo.updateHashes(captureAny())).captured.first as List; + final captured = + verify(() => mockAssetRepo.updateHashes(captureAny())).captured.first as List; expect(captured.length, 1); expect(captured[0].checksum, base64.encode(hash)); }); @@ -107,7 +109,8 @@ void main() { await sut.hashAssets(); - final captured = verify(() => mockAssetRepo.updateHashes(captureAny())).captured.first as List; + final captured = + verify(() => mockAssetRepo.updateHashes(captureAny())).captured.first as List; expect(captured.length, 0); }); @@ -128,7 +131,8 @@ void main() { await sut.hashAssets(); - final captured = verify(() => mockAssetRepo.updateHashes(captureAny())).captured.first as List; + final captured = + verify(() => mockAssetRepo.updateHashes(captureAny())).captured.first as List; expect(captured.length, 0); }); @@ -224,9 +228,10 @@ void main() { await sut.hashAssets(); - final captured = verify(() => mockAssetRepo.updateHashes(captureAny())).captured.first as List; + final captured = + verify(() => mockAssetRepo.updateHashes(captureAny())).captured.first as List; expect(captured.length, 1); - expect(captured.first.id, asset1.id); + expect(captured.first.assetId, asset1.id); }); }); }