From 5ccc05feeba92427a0eadcc98e79a91f7fe57075 Mon Sep 17 00:00:00 2001 From: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> Date: Thu, 22 Jan 2026 20:37:44 +0530 Subject: [PATCH] fix: foreground cloud sync --- mobile/lib/domain/utils/background_sync.dart | 34 ------------------- .../lib/domain/utils/migrate_cloud_ids.dart | 11 +----- .../lib/pages/common/splash_screen.page.dart | 1 - .../providers/app_life_cycle.provider.dart | 3 +- mobile/lib/providers/auth.provider.dart | 15 +++++++- .../providers/background_sync.provider.dart | 3 -- .../lib/providers/sync_status.provider.dart | 21 +----------- 7 files changed, 18 insertions(+), 70 deletions(-) diff --git a/mobile/lib/domain/utils/background_sync.dart b/mobile/lib/domain/utils/background_sync.dart index 6840bae595..9650007095 100644 --- a/mobile/lib/domain/utils/background_sync.dart +++ b/mobile/lib/domain/utils/background_sync.dart @@ -1,6 +1,5 @@ import 'dart:async'; -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'; @@ -23,13 +22,8 @@ class BackgroundSyncManager { final SyncCallback? onHashingComplete; final SyncErrorCallback? onHashingError; - final SyncCallback? onCloudIdSyncStart; - final SyncCallback? onCloudIdSyncComplete; - final SyncErrorCallback? onCloudIdSyncError; - Cancelable? _syncTask; Cancelable? _syncWebsocketTask; - Cancelable? _cloudIdSyncTask; Cancelable? _deviceAlbumSyncTask; Cancelable? _linkedAlbumSyncTask; Cancelable? _hashTask; @@ -44,9 +38,6 @@ class BackgroundSyncManager { this.onHashingStart, this.onHashingComplete, this.onHashingError, - this.onCloudIdSyncStart, - this.onCloudIdSyncComplete, - this.onCloudIdSyncError, }); Future cancel() async { @@ -64,12 +55,6 @@ class BackgroundSyncManager { _syncWebsocketTask?.cancel(); _syncWebsocketTask = null; - if (_cloudIdSyncTask != null) { - futures.add(_cloudIdSyncTask!.future); - } - _cloudIdSyncTask?.cancel(); - _cloudIdSyncTask = null; - if (_linkedAlbumSyncTask != null) { futures.add(_linkedAlbumSyncTask!.future); } @@ -216,25 +201,6 @@ class BackgroundSyncManager { _linkedAlbumSyncTask = null; }); } - - Future syncCloudIds() { - if (_cloudIdSyncTask != null) { - return _cloudIdSyncTask!.future; - } - - onCloudIdSyncStart?.call(); - - _cloudIdSyncTask = runInIsolateGentle(computation: m.syncCloudIds); - return _cloudIdSyncTask! - .whenComplete(() { - onCloudIdSyncComplete?.call(); - _cloudIdSyncTask = null; - }) - .catchError((error) { - onCloudIdSyncError?.call(error.toString()); - _cloudIdSyncTask = null; - }); - } } Cancelable _handleWsAssetUploadReadyV1Batch(List batchData) => runInIsolateGentle( diff --git a/mobile/lib/domain/utils/migrate_cloud_ids.dart b/mobile/lib/domain/utils/migrate_cloud_ids.dart index 6ff78823c2..c546a575d9 100644 --- a/mobile/lib/domain/utils/migrate_cloud_ids.dart +++ b/mobile/lib/domain/utils/migrate_cloud_ids.dart @@ -10,14 +10,13 @@ import 'package:immich_mobile/infrastructure/repositories/local_album.repository import 'package:immich_mobile/platform/native_sync_api.g.dart'; import 'package:immich_mobile/providers/api.provider.dart'; import 'package:immich_mobile/providers/infrastructure/db.provider.dart'; -import 'package:immich_mobile/providers/infrastructure/sync.provider.dart'; import 'package:immich_mobile/providers/server_info.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; import 'package:logging/logging.dart'; // ignore: import_rule_openapi import 'package:openapi/api.dart' hide AssetVisibility; -Future syncCloudIds(ProviderContainer ref) async { +Future syncCloudIds(Ref ref) async { if (!CurrentPlatform.isIOS) { return; } @@ -35,14 +34,6 @@ Future syncCloudIds(ProviderContainer ref) async { } final canBulkUpdateMetadata = serverInfo.serverVersion.isAtLeast(major: 2, minor: 5); - // Wait for remote sync to complete, so we have up-to-date asset metadata entries - try { - await ref.read(syncStreamServiceProvider).sync(); - } catch (e, s) { - logger.fine('Failed to complete remote sync before cloudId migration.', e, s); - return; - } - // Fetch the mapping for backed up assets that have a cloud ID locally but do not have a cloud ID on the server final currentUser = ref.read(currentUserProvider); if (currentUser == null) { diff --git a/mobile/lib/pages/common/splash_screen.page.dart b/mobile/lib/pages/common/splash_screen.page.dart index bc407f5b79..a820385170 100644 --- a/mobile/lib/pages/common/splash_screen.page.dart +++ b/mobile/lib/pages/common/splash_screen.page.dart @@ -75,7 +75,6 @@ class SplashScreenPageState extends ConsumerState { _resumeBackup(backupProvider); }), _resumeBackup(backupProvider), - backgroundManager.syncCloudIds(), ]); } else { await backgroundManager.hashAssets(); diff --git a/mobile/lib/providers/app_life_cycle.provider.dart b/mobile/lib/providers/app_life_cycle.provider.dart index a6e8503d99..6ea4dfcf7b 100644 --- a/mobile/lib/providers/app_life_cycle.provider.dart +++ b/mobile/lib/providers/app_life_cycle.provider.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/domain/services/log.service.dart'; +import 'package:immich_mobile/domain/utils/migrate_cloud_ids.dart'; import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/extensions/platform_extensions.dart'; import 'package:immich_mobile/models/backup/backup_state.model.dart'; @@ -156,11 +157,11 @@ class AppLifeCycleNotifier extends StateNotifier { ]); if (syncSuccess) { await Future.wait([ + _safeRun(syncCloudIds(_ref), "syncCloudIds"), _safeRun(backgroundManager.hashAssets(), "hashAssets").then((_) { _resumeBackup(); }), _resumeBackup(), - _safeRun(backgroundManager.syncCloudIds(), "syncCloudIds"), ]); } else { await _safeRun(backgroundManager.hashAssets(), "hashAssets"); diff --git a/mobile/lib/providers/auth.provider.dart b/mobile/lib/providers/auth.provider.dart index 49dc10240b..595dc3378d 100644 --- a/mobile/lib/providers/auth.provider.dart +++ b/mobile/lib/providers/auth.provider.dart @@ -1,19 +1,23 @@ +import 'dart:async'; + import 'package:flutter_udid/flutter_udid.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/constants.dart'; import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/domain/models/user.model.dart'; import 'package:immich_mobile/domain/services/user.service.dart'; +import 'package:immich_mobile/domain/utils/migrate_cloud_ids.dart'; import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/models/auth/auth_state.model.dart'; import 'package:immich_mobile/models/auth/login_response.model.dart'; import 'package:immich_mobile/providers/api.provider.dart'; +import 'package:immich_mobile/providers/background_sync.provider.dart'; import 'package:immich_mobile/providers/infrastructure/user.provider.dart'; import 'package:immich_mobile/services/api.service.dart'; import 'package:immich_mobile/services/auth.service.dart'; +import 'package:immich_mobile/services/background_upload.service.dart'; import 'package:immich_mobile/services/foreground_upload.service.dart'; import 'package:immich_mobile/services/secure_storage.service.dart'; -import 'package:immich_mobile/services/background_upload.service.dart'; import 'package:immich_mobile/services/widget.service.dart'; import 'package:immich_mobile/utils/debug_print.dart'; import 'package:immich_mobile/utils/hash.dart'; @@ -172,6 +176,15 @@ class AuthNotifier extends StateNotifier { isAdmin: user.isAdmin, ); + // TODO: Temporarily run cloud Id sync here until we have a better place to do it + unawaited( + _ref.read(backgroundSyncProvider).syncRemote().then((success) { + if (success) { + return syncCloudIds(_ref); + } + }), + ); + return true; } diff --git a/mobile/lib/providers/background_sync.provider.dart b/mobile/lib/providers/background_sync.provider.dart index 37b3145eb4..5d6a2f0f4d 100644 --- a/mobile/lib/providers/background_sync.provider.dart +++ b/mobile/lib/providers/background_sync.provider.dart @@ -28,9 +28,6 @@ final backgroundSyncProvider = Provider((ref) { onHashingStart: syncStatusNotifier.startHashJob, onHashingComplete: syncStatusNotifier.completeHashJob, onHashingError: syncStatusNotifier.errorHashJob, - onCloudIdSyncStart: syncStatusNotifier.startCloudIdSync, - onCloudIdSyncComplete: syncStatusNotifier.completeCloudIdSync, - onCloudIdSyncError: syncStatusNotifier.errorCloudIdSync, ); ref.onDispose(manager.cancel); return manager; diff --git a/mobile/lib/providers/sync_status.provider.dart b/mobile/lib/providers/sync_status.provider.dart index 203184fc87..8e24bbf4d0 100644 --- a/mobile/lib/providers/sync_status.provider.dart +++ b/mobile/lib/providers/sync_status.provider.dart @@ -21,7 +21,6 @@ class SyncStatusState { final SyncStatus remoteSyncStatus; final SyncStatus localSyncStatus; final SyncStatus hashJobStatus; - final SyncStatus cloudIdSyncStatus; final String? errorMessage; @@ -29,7 +28,6 @@ class SyncStatusState { this.remoteSyncStatus = SyncStatus.idle, this.localSyncStatus = SyncStatus.idle, this.hashJobStatus = SyncStatus.idle, - this.cloudIdSyncStatus = SyncStatus.idle, this.errorMessage, }); @@ -37,14 +35,12 @@ class SyncStatusState { SyncStatus? remoteSyncStatus, SyncStatus? localSyncStatus, SyncStatus? hashJobStatus, - SyncStatus? cloudIdSyncStatus, String? errorMessage, }) { return SyncStatusState( remoteSyncStatus: remoteSyncStatus ?? this.remoteSyncStatus, localSyncStatus: localSyncStatus ?? this.localSyncStatus, hashJobStatus: hashJobStatus ?? this.hashJobStatus, - cloudIdSyncStatus: cloudIdSyncStatus ?? this.cloudIdSyncStatus, errorMessage: errorMessage ?? this.errorMessage, ); } @@ -52,7 +48,6 @@ class SyncStatusState { bool get isRemoteSyncing => remoteSyncStatus == SyncStatus.syncing; bool get isLocalSyncing => localSyncStatus == SyncStatus.syncing; bool get isHashing => hashJobStatus == SyncStatus.syncing; - bool get isCloudIdSyncing => cloudIdSyncStatus == SyncStatus.syncing; @override bool operator ==(Object other) { @@ -61,12 +56,11 @@ class SyncStatusState { other.remoteSyncStatus == remoteSyncStatus && other.localSyncStatus == localSyncStatus && other.hashJobStatus == hashJobStatus && - other.cloudIdSyncStatus == cloudIdSyncStatus && other.errorMessage == errorMessage; } @override - int get hashCode => Object.hash(remoteSyncStatus, localSyncStatus, hashJobStatus, cloudIdSyncStatus, errorMessage); + int get hashCode => Object.hash(remoteSyncStatus, localSyncStatus, hashJobStatus, errorMessage); } class SyncStatusNotifier extends Notifier { @@ -77,7 +71,6 @@ class SyncStatusNotifier extends Notifier { remoteSyncStatus: SyncStatus.idle, localSyncStatus: SyncStatus.idle, hashJobStatus: SyncStatus.idle, - cloudIdSyncStatus: SyncStatus.idle, ); } @@ -116,18 +109,6 @@ class SyncStatusNotifier extends Notifier { void startHashJob() => setHashJobStatus(SyncStatus.syncing); void completeHashJob() => setHashJobStatus(SyncStatus.success); void errorHashJob(String error) => setHashJobStatus(SyncStatus.error, error); - - /// - /// Cloud ID Sync Job - /// - - void setCloudIdSyncStatus(SyncStatus status, [String? errorMessage]) { - state = state.copyWith(cloudIdSyncStatus: status, errorMessage: status == SyncStatus.error ? errorMessage : null); - } - - void startCloudIdSync() => setCloudIdSyncStatus(SyncStatus.syncing); - void completeCloudIdSync() => setCloudIdSyncStatus(SyncStatus.success); - void errorCloudIdSync(String error) => setCloudIdSyncStatus(SyncStatus.error, error); } final syncStatusProvider = NotifierProvider(SyncStatusNotifier.new);