mirror of
https://github.com/immich-app/immich.git
synced 2026-01-26 03:14:39 -08:00
Compare commits
1 Commits
feat/mobil
...
fix/foregr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ccc05feeb |
@@ -1,6 +1,5 @@
|
|||||||
import 'dart:async';
|
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/domain/utils/sync_linked_album.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/sync.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/sync.provider.dart';
|
||||||
import 'package:immich_mobile/utils/isolate.dart';
|
import 'package:immich_mobile/utils/isolate.dart';
|
||||||
@@ -23,13 +22,8 @@ class BackgroundSyncManager {
|
|||||||
final SyncCallback? onHashingComplete;
|
final SyncCallback? onHashingComplete;
|
||||||
final SyncErrorCallback? onHashingError;
|
final SyncErrorCallback? onHashingError;
|
||||||
|
|
||||||
final SyncCallback? onCloudIdSyncStart;
|
|
||||||
final SyncCallback? onCloudIdSyncComplete;
|
|
||||||
final SyncErrorCallback? onCloudIdSyncError;
|
|
||||||
|
|
||||||
Cancelable<bool?>? _syncTask;
|
Cancelable<bool?>? _syncTask;
|
||||||
Cancelable<void>? _syncWebsocketTask;
|
Cancelable<void>? _syncWebsocketTask;
|
||||||
Cancelable<void>? _cloudIdSyncTask;
|
|
||||||
Cancelable<void>? _deviceAlbumSyncTask;
|
Cancelable<void>? _deviceAlbumSyncTask;
|
||||||
Cancelable<void>? _linkedAlbumSyncTask;
|
Cancelable<void>? _linkedAlbumSyncTask;
|
||||||
Cancelable<void>? _hashTask;
|
Cancelable<void>? _hashTask;
|
||||||
@@ -44,9 +38,6 @@ class BackgroundSyncManager {
|
|||||||
this.onHashingStart,
|
this.onHashingStart,
|
||||||
this.onHashingComplete,
|
this.onHashingComplete,
|
||||||
this.onHashingError,
|
this.onHashingError,
|
||||||
this.onCloudIdSyncStart,
|
|
||||||
this.onCloudIdSyncComplete,
|
|
||||||
this.onCloudIdSyncError,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<void> cancel() async {
|
Future<void> cancel() async {
|
||||||
@@ -64,12 +55,6 @@ class BackgroundSyncManager {
|
|||||||
_syncWebsocketTask?.cancel();
|
_syncWebsocketTask?.cancel();
|
||||||
_syncWebsocketTask = null;
|
_syncWebsocketTask = null;
|
||||||
|
|
||||||
if (_cloudIdSyncTask != null) {
|
|
||||||
futures.add(_cloudIdSyncTask!.future);
|
|
||||||
}
|
|
||||||
_cloudIdSyncTask?.cancel();
|
|
||||||
_cloudIdSyncTask = null;
|
|
||||||
|
|
||||||
if (_linkedAlbumSyncTask != null) {
|
if (_linkedAlbumSyncTask != null) {
|
||||||
futures.add(_linkedAlbumSyncTask!.future);
|
futures.add(_linkedAlbumSyncTask!.future);
|
||||||
}
|
}
|
||||||
@@ -216,25 +201,6 @@ class BackgroundSyncManager {
|
|||||||
_linkedAlbumSyncTask = null;
|
_linkedAlbumSyncTask = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> 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<void> _handleWsAssetUploadReadyV1Batch(List<dynamic> batchData) => runInIsolateGentle(
|
Cancelable<void> _handleWsAssetUploadReadyV1Batch(List<dynamic> batchData) => runInIsolateGentle(
|
||||||
|
|||||||
@@ -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/platform/native_sync_api.g.dart';
|
||||||
import 'package:immich_mobile/providers/api.provider.dart';
|
import 'package:immich_mobile/providers/api.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/db.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/server_info.provider.dart';
|
||||||
import 'package:immich_mobile/providers/user.provider.dart';
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
// ignore: import_rule_openapi
|
// ignore: import_rule_openapi
|
||||||
import 'package:openapi/api.dart' hide AssetVisibility;
|
import 'package:openapi/api.dart' hide AssetVisibility;
|
||||||
|
|
||||||
Future<void> syncCloudIds(ProviderContainer ref) async {
|
Future<void> syncCloudIds(Ref ref) async {
|
||||||
if (!CurrentPlatform.isIOS) {
|
if (!CurrentPlatform.isIOS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -35,14 +34,6 @@ Future<void> syncCloudIds(ProviderContainer ref) async {
|
|||||||
}
|
}
|
||||||
final canBulkUpdateMetadata = serverInfo.serverVersion.isAtLeast(major: 2, minor: 5);
|
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
|
// 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);
|
final currentUser = ref.read(currentUserProvider);
|
||||||
if (currentUser == null) {
|
if (currentUser == null) {
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ class SplashScreenPageState extends ConsumerState<SplashScreenPage> {
|
|||||||
_resumeBackup(backupProvider);
|
_resumeBackup(backupProvider);
|
||||||
}),
|
}),
|
||||||
_resumeBackup(backupProvider),
|
_resumeBackup(backupProvider),
|
||||||
backgroundManager.syncCloudIds(),
|
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
await backgroundManager.hashAssets();
|
await backgroundManager.hashAssets();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'dart:async';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/domain/services/log.service.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/entities/store.entity.dart';
|
||||||
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
||||||
import 'package:immich_mobile/models/backup/backup_state.model.dart';
|
import 'package:immich_mobile/models/backup/backup_state.model.dart';
|
||||||
@@ -156,11 +157,11 @@ class AppLifeCycleNotifier extends StateNotifier<AppLifeCycleEnum> {
|
|||||||
]);
|
]);
|
||||||
if (syncSuccess) {
|
if (syncSuccess) {
|
||||||
await Future.wait([
|
await Future.wait([
|
||||||
|
_safeRun(syncCloudIds(_ref), "syncCloudIds"),
|
||||||
_safeRun(backgroundManager.hashAssets(), "hashAssets").then((_) {
|
_safeRun(backgroundManager.hashAssets(), "hashAssets").then((_) {
|
||||||
_resumeBackup();
|
_resumeBackup();
|
||||||
}),
|
}),
|
||||||
_resumeBackup(),
|
_resumeBackup(),
|
||||||
_safeRun(backgroundManager.syncCloudIds(), "syncCloudIds"),
|
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
await _safeRun(backgroundManager.hashAssets(), "hashAssets");
|
await _safeRun(backgroundManager.hashAssets(), "hashAssets");
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter_udid/flutter_udid.dart';
|
import 'package:flutter_udid/flutter_udid.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/user.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/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/entities/store.entity.dart';
|
||||||
import 'package:immich_mobile/models/auth/auth_state.model.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/models/auth/login_response.model.dart';
|
||||||
import 'package:immich_mobile/providers/api.provider.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/providers/infrastructure/user.provider.dart';
|
||||||
import 'package:immich_mobile/services/api.service.dart';
|
import 'package:immich_mobile/services/api.service.dart';
|
||||||
import 'package:immich_mobile/services/auth.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/foreground_upload.service.dart';
|
||||||
import 'package:immich_mobile/services/secure_storage.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/services/widget.service.dart';
|
||||||
import 'package:immich_mobile/utils/debug_print.dart';
|
import 'package:immich_mobile/utils/debug_print.dart';
|
||||||
import 'package:immich_mobile/utils/hash.dart';
|
import 'package:immich_mobile/utils/hash.dart';
|
||||||
@@ -172,6 +176,15 @@ class AuthNotifier extends StateNotifier<AuthState> {
|
|||||||
isAdmin: user.isAdmin,
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,9 +28,6 @@ final backgroundSyncProvider = Provider<BackgroundSyncManager>((ref) {
|
|||||||
onHashingStart: syncStatusNotifier.startHashJob,
|
onHashingStart: syncStatusNotifier.startHashJob,
|
||||||
onHashingComplete: syncStatusNotifier.completeHashJob,
|
onHashingComplete: syncStatusNotifier.completeHashJob,
|
||||||
onHashingError: syncStatusNotifier.errorHashJob,
|
onHashingError: syncStatusNotifier.errorHashJob,
|
||||||
onCloudIdSyncStart: syncStatusNotifier.startCloudIdSync,
|
|
||||||
onCloudIdSyncComplete: syncStatusNotifier.completeCloudIdSync,
|
|
||||||
onCloudIdSyncError: syncStatusNotifier.errorCloudIdSync,
|
|
||||||
);
|
);
|
||||||
ref.onDispose(manager.cancel);
|
ref.onDispose(manager.cancel);
|
||||||
return manager;
|
return manager;
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ class SyncStatusState {
|
|||||||
final SyncStatus remoteSyncStatus;
|
final SyncStatus remoteSyncStatus;
|
||||||
final SyncStatus localSyncStatus;
|
final SyncStatus localSyncStatus;
|
||||||
final SyncStatus hashJobStatus;
|
final SyncStatus hashJobStatus;
|
||||||
final SyncStatus cloudIdSyncStatus;
|
|
||||||
|
|
||||||
final String? errorMessage;
|
final String? errorMessage;
|
||||||
|
|
||||||
@@ -29,7 +28,6 @@ class SyncStatusState {
|
|||||||
this.remoteSyncStatus = SyncStatus.idle,
|
this.remoteSyncStatus = SyncStatus.idle,
|
||||||
this.localSyncStatus = SyncStatus.idle,
|
this.localSyncStatus = SyncStatus.idle,
|
||||||
this.hashJobStatus = SyncStatus.idle,
|
this.hashJobStatus = SyncStatus.idle,
|
||||||
this.cloudIdSyncStatus = SyncStatus.idle,
|
|
||||||
this.errorMessage,
|
this.errorMessage,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -37,14 +35,12 @@ class SyncStatusState {
|
|||||||
SyncStatus? remoteSyncStatus,
|
SyncStatus? remoteSyncStatus,
|
||||||
SyncStatus? localSyncStatus,
|
SyncStatus? localSyncStatus,
|
||||||
SyncStatus? hashJobStatus,
|
SyncStatus? hashJobStatus,
|
||||||
SyncStatus? cloudIdSyncStatus,
|
|
||||||
String? errorMessage,
|
String? errorMessage,
|
||||||
}) {
|
}) {
|
||||||
return SyncStatusState(
|
return SyncStatusState(
|
||||||
remoteSyncStatus: remoteSyncStatus ?? this.remoteSyncStatus,
|
remoteSyncStatus: remoteSyncStatus ?? this.remoteSyncStatus,
|
||||||
localSyncStatus: localSyncStatus ?? this.localSyncStatus,
|
localSyncStatus: localSyncStatus ?? this.localSyncStatus,
|
||||||
hashJobStatus: hashJobStatus ?? this.hashJobStatus,
|
hashJobStatus: hashJobStatus ?? this.hashJobStatus,
|
||||||
cloudIdSyncStatus: cloudIdSyncStatus ?? this.cloudIdSyncStatus,
|
|
||||||
errorMessage: errorMessage ?? this.errorMessage,
|
errorMessage: errorMessage ?? this.errorMessage,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -52,7 +48,6 @@ class SyncStatusState {
|
|||||||
bool get isRemoteSyncing => remoteSyncStatus == SyncStatus.syncing;
|
bool get isRemoteSyncing => remoteSyncStatus == SyncStatus.syncing;
|
||||||
bool get isLocalSyncing => localSyncStatus == SyncStatus.syncing;
|
bool get isLocalSyncing => localSyncStatus == SyncStatus.syncing;
|
||||||
bool get isHashing => hashJobStatus == SyncStatus.syncing;
|
bool get isHashing => hashJobStatus == SyncStatus.syncing;
|
||||||
bool get isCloudIdSyncing => cloudIdSyncStatus == SyncStatus.syncing;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
@@ -61,12 +56,11 @@ class SyncStatusState {
|
|||||||
other.remoteSyncStatus == remoteSyncStatus &&
|
other.remoteSyncStatus == remoteSyncStatus &&
|
||||||
other.localSyncStatus == localSyncStatus &&
|
other.localSyncStatus == localSyncStatus &&
|
||||||
other.hashJobStatus == hashJobStatus &&
|
other.hashJobStatus == hashJobStatus &&
|
||||||
other.cloudIdSyncStatus == cloudIdSyncStatus &&
|
|
||||||
other.errorMessage == errorMessage;
|
other.errorMessage == errorMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(remoteSyncStatus, localSyncStatus, hashJobStatus, cloudIdSyncStatus, errorMessage);
|
int get hashCode => Object.hash(remoteSyncStatus, localSyncStatus, hashJobStatus, errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
class SyncStatusNotifier extends Notifier<SyncStatusState> {
|
class SyncStatusNotifier extends Notifier<SyncStatusState> {
|
||||||
@@ -77,7 +71,6 @@ class SyncStatusNotifier extends Notifier<SyncStatusState> {
|
|||||||
remoteSyncStatus: SyncStatus.idle,
|
remoteSyncStatus: SyncStatus.idle,
|
||||||
localSyncStatus: SyncStatus.idle,
|
localSyncStatus: SyncStatus.idle,
|
||||||
hashJobStatus: SyncStatus.idle,
|
hashJobStatus: SyncStatus.idle,
|
||||||
cloudIdSyncStatus: SyncStatus.idle,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,18 +109,6 @@ class SyncStatusNotifier extends Notifier<SyncStatusState> {
|
|||||||
void startHashJob() => setHashJobStatus(SyncStatus.syncing);
|
void startHashJob() => setHashJobStatus(SyncStatus.syncing);
|
||||||
void completeHashJob() => setHashJobStatus(SyncStatus.success);
|
void completeHashJob() => setHashJobStatus(SyncStatus.success);
|
||||||
void errorHashJob(String error) => setHashJobStatus(SyncStatus.error, error);
|
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, SyncStatusState>(SyncStatusNotifier.new);
|
final syncStatusProvider = NotifierProvider<SyncStatusNotifier, SyncStatusState>(SyncStatusNotifier.new);
|
||||||
|
|||||||
Reference in New Issue
Block a user