mirror of
https://github.com/immich-app/immich.git
synced 2025-12-17 09:13:17 +03:00
add server version check & auto sync cloud ids on compatible servers
This commit is contained in:
@@ -84,6 +84,7 @@ Future<List<_CloudIdMapping>> _fetchCloudIdMappings(Drift drift, String userId)
|
|||||||
useColumns: false,
|
useColumns: false,
|
||||||
),
|
),
|
||||||
])..where(
|
])..where(
|
||||||
|
// Only select assets that have a local cloud ID but either no remote cloud ID or a mismatched eTag
|
||||||
drift.localAssetEntity.id.isNotNull() &
|
drift.localAssetEntity.id.isNotNull() &
|
||||||
drift.localAssetEntity.iCloudId.isNotNull() &
|
drift.localAssetEntity.iCloudId.isNotNull() &
|
||||||
drift.remoteAssetEntity.ownerId.equals(userId) &
|
drift.remoteAssetEntity.ownerId.equals(userId) &
|
||||||
|
|||||||
@@ -10,4 +10,8 @@ class ServerVersion extends SemVer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ServerVersion.fromDto(ServerVersionResponseDto dto) : super(major: dto.major, minor: dto.minor, patch: dto.patch_);
|
ServerVersion.fromDto(ServerVersionResponseDto dto) : super(major: dto.major, minor: dto.minor, patch: dto.patch_);
|
||||||
|
|
||||||
|
bool isAtLeast({int major = 0, int minor = 0, int patch = 0}) {
|
||||||
|
return this >= SemVer(major: major, minor: minor, patch: patch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
|
|||||||
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/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
|
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
||||||
import 'package:immich_mobile/providers/auth.provider.dart';
|
import 'package:immich_mobile/providers/auth.provider.dart';
|
||||||
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
||||||
import 'package:immich_mobile/providers/backup/backup.provider.dart';
|
import 'package:immich_mobile/providers/backup/backup.provider.dart';
|
||||||
@@ -60,7 +61,8 @@ class SplashScreenPageState extends ConsumerState<SplashScreenPage> {
|
|||||||
(_) async {
|
(_) async {
|
||||||
try {
|
try {
|
||||||
wsProvider.connect();
|
wsProvider.connect();
|
||||||
unawaited(infoProvider.getServerInfo());
|
await infoProvider.getServerInfo();
|
||||||
|
final serverInfo = ref.read(serverInfoProvider);
|
||||||
|
|
||||||
if (Store.isBetaTimelineEnabled) {
|
if (Store.isBetaTimelineEnabled) {
|
||||||
bool syncSuccess = false;
|
bool syncSuccess = false;
|
||||||
@@ -75,6 +77,9 @@ class SplashScreenPageState extends ConsumerState<SplashScreenPage> {
|
|||||||
_resumeBackup(backupProvider);
|
_resumeBackup(backupProvider);
|
||||||
}),
|
}),
|
||||||
_resumeBackup(backupProvider),
|
_resumeBackup(backupProvider),
|
||||||
|
// Sync cloud IDs if server version is compatible
|
||||||
|
if (CurrentPlatform.isIOS && serverInfo.serverVersion.isAtLeast(major: 2, minor: 4))
|
||||||
|
backgroundManager.syncCloudIds(),
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
await backgroundManager.hashAssets();
|
await backgroundManager.hashAssets();
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ class AppLifeCycleNotifier extends StateNotifier<AppLifeCycleEnum> {
|
|||||||
|
|
||||||
final backgroundManager = _ref.read(backgroundSyncProvider);
|
final backgroundManager = _ref.read(backgroundSyncProvider);
|
||||||
final isAlbumLinkedSyncEnable = _ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.syncAlbums);
|
final isAlbumLinkedSyncEnable = _ref.read(appSettingsServiceProvider).getSetting(AppSettingsEnum.syncAlbums);
|
||||||
|
final serverInfo = _ref.read(serverInfoProvider);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
bool syncSuccess = false;
|
bool syncSuccess = false;
|
||||||
@@ -160,6 +161,9 @@ class AppLifeCycleNotifier extends StateNotifier<AppLifeCycleEnum> {
|
|||||||
_resumeBackup();
|
_resumeBackup();
|
||||||
}),
|
}),
|
||||||
_resumeBackup(),
|
_resumeBackup(),
|
||||||
|
// Sync cloud IDs if server version is compatible
|
||||||
|
if (CurrentPlatform.isIOS && serverInfo.serverVersion.isAtLeast(major: 2, minor: 4))
|
||||||
|
backgroundManager.syncCloudIds(),
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
await _safeRun(backgroundManager.hashAssets(), "hashAssets");
|
await _safeRun(backgroundManager.hashAssets(), "hashAssets");
|
||||||
|
|||||||
@@ -15,10 +15,12 @@ import 'package:immich_mobile/extensions/platform_extensions.dart';
|
|||||||
import 'package:immich_mobile/infrastructure/repositories/backup.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/backup.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
|
||||||
|
import 'package:immich_mobile/models/server_info/server_info.model.dart';
|
||||||
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
import 'package:immich_mobile/providers/app_settings.provider.dart';
|
||||||
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/storage.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/storage.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||||
import 'package:immich_mobile/repositories/asset_media.repository.dart';
|
import 'package:immich_mobile/repositories/asset_media.repository.dart';
|
||||||
import 'package:immich_mobile/repositories/upload.repository.dart';
|
import 'package:immich_mobile/repositories/upload.repository.dart';
|
||||||
import 'package:immich_mobile/services/api.service.dart';
|
import 'package:immich_mobile/services/api.service.dart';
|
||||||
@@ -35,6 +37,7 @@ final uploadServiceProvider = Provider((ref) {
|
|||||||
ref.watch(localAssetRepository),
|
ref.watch(localAssetRepository),
|
||||||
ref.watch(appSettingsServiceProvider),
|
ref.watch(appSettingsServiceProvider),
|
||||||
ref.watch(assetMediaRepositoryProvider),
|
ref.watch(assetMediaRepositoryProvider),
|
||||||
|
ref.watch(serverInfoProvider),
|
||||||
);
|
);
|
||||||
|
|
||||||
ref.onDispose(service.dispose);
|
ref.onDispose(service.dispose);
|
||||||
@@ -49,6 +52,7 @@ class UploadService {
|
|||||||
this._localAssetRepository,
|
this._localAssetRepository,
|
||||||
this._appSettingsService,
|
this._appSettingsService,
|
||||||
this._assetMediaRepository,
|
this._assetMediaRepository,
|
||||||
|
this._serverInfo,
|
||||||
) {
|
) {
|
||||||
_uploadRepository.onUploadStatus = _onUploadCallback;
|
_uploadRepository.onUploadStatus = _onUploadCallback;
|
||||||
_uploadRepository.onTaskProgress = _onTaskProgressCallback;
|
_uploadRepository.onTaskProgress = _onTaskProgressCallback;
|
||||||
@@ -60,6 +64,7 @@ class UploadService {
|
|||||||
final DriftLocalAssetRepository _localAssetRepository;
|
final DriftLocalAssetRepository _localAssetRepository;
|
||||||
final AppSettingsService _appSettingsService;
|
final AppSettingsService _appSettingsService;
|
||||||
final AssetMediaRepository _assetMediaRepository;
|
final AssetMediaRepository _assetMediaRepository;
|
||||||
|
final ServerInfo _serverInfo;
|
||||||
final Logger _logger = Logger('UploadService');
|
final Logger _logger = Logger('UploadService');
|
||||||
|
|
||||||
final StreamController<TaskStatusUpdate> _taskStatusController = StreamController<TaskStatusUpdate>.broadcast();
|
final StreamController<TaskStatusUpdate> _taskStatusController = StreamController<TaskStatusUpdate>.broadcast();
|
||||||
@@ -431,13 +436,18 @@ class UploadService {
|
|||||||
'fileModifiedAt': modifiedAt.toUtc().toIso8601String(),
|
'fileModifiedAt': modifiedAt.toUtc().toIso8601String(),
|
||||||
'isFavorite': isFavorite?.toString() ?? 'false',
|
'isFavorite': isFavorite?.toString() ?? 'false',
|
||||||
'duration': '0',
|
'duration': '0',
|
||||||
'metadata': jsonEncode([
|
|
||||||
RemoteAssetMetadataItem(
|
|
||||||
key: RemoteAssetMetadataKey.mobileApp,
|
|
||||||
value: RemoteAssetMobileAppMetadata(cloudId: cloudId, eTag: eTag),
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
if (fields != null) ...fields,
|
if (fields != null) ...fields,
|
||||||
|
// Include cloudId and eTag in metadata if available and server version supports it
|
||||||
|
if (CurrentPlatform.isIOS &&
|
||||||
|
cloudId != null &&
|
||||||
|
eTag != null &&
|
||||||
|
_serverInfo.serverVersion.isAtLeast(major: 2, minor: 4))
|
||||||
|
'metadata': jsonEncode([
|
||||||
|
RemoteAssetMetadataItem(
|
||||||
|
key: RemoteAssetMetadataKey.mobileApp,
|
||||||
|
value: RemoteAssetMobileAppMetadata(cloudId: cloudId, eTag: eTag),
|
||||||
|
),
|
||||||
|
]),
|
||||||
};
|
};
|
||||||
|
|
||||||
return UploadTask(
|
return UploadTask(
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
|||||||
import 'package:immich_mobile/providers/infrastructure/memory.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/memory.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/storage.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/storage.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/trash_sync.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/trash_sync.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||||
import 'package:immich_mobile/providers/sync_status.provider.dart';
|
import 'package:immich_mobile/providers/sync_status.provider.dart';
|
||||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
import 'package:immich_mobile/services/app_settings.service.dart';
|
||||||
import 'package:immich_mobile/widgets/settings/beta_sync_settings/entity_count_tile.dart';
|
import 'package:immich_mobile/widgets/settings/beta_sync_settings/entity_count_tile.dart';
|
||||||
@@ -25,6 +26,8 @@ class SyncStatusAndActions extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final serverInfo = ref.read(serverInfoProvider);
|
||||||
|
|
||||||
Future<void> exportDatabase() async {
|
Future<void> exportDatabase() async {
|
||||||
try {
|
try {
|
||||||
// WAL Checkpoint to ensure all changes are written to the database
|
// WAL Checkpoint to ensure all changes are written to the database
|
||||||
@@ -151,7 +154,7 @@ class SyncStatusAndActions extends HookConsumerWidget {
|
|||||||
ref.read(backgroundSyncProvider).hashAssets();
|
ref.read(backgroundSyncProvider).hashAssets();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (CurrentPlatform.isIOS)
|
if (CurrentPlatform.isIOS && serverInfo.serverVersion.isAtLeast(major: 2, minor: 4))
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
"sync_cloud_ids".t(context: context),
|
"sync_cloud_ids".t(context: context),
|
||||||
|
|||||||
Reference in New Issue
Block a user