mirror of
https://github.com/immich-app/immich
synced 2026-08-15 13:03:57 +00:00
refactor: server capabilities (#30663)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
parent
447cc40a50
commit
652ef8a427
7 changed files with 41 additions and 31 deletions
23
mobile/lib/domain/models/server_capability.model.dart
Normal file
23
mobile/lib/domain/models/server_capability.model.dart
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import 'package:immich_mobile/utils/semver.dart';
|
||||
|
||||
enum ServerCapability {
|
||||
// Feature Support
|
||||
cloudIdMetadata(SemVer(major: 2, minor: 4, patch: 0)),
|
||||
bulkCloudIdMetadata(SemVer(major: 2, minor: 5, patch: 0)),
|
||||
assetEdits(SemVer(major: 2, minor: 6, patch: 0)),
|
||||
assetFacesV2(SemVer(major: 2, minor: 6, patch: 0)),
|
||||
syncV2(SemVer(major: 3, minor: 0, patch: 0)),
|
||||
assetOcr(SemVer(major: 3, minor: 0, patch: 0)),
|
||||
|
||||
// Migrations
|
||||
assetPayloadChange20260128(SemVer(major: 2, minor: 5, patch: 0)),
|
||||
assetPayloadChange20260597(SemVer(major: 2, minor: 7, patch: 6));
|
||||
|
||||
const ServerCapability(this.minVersion);
|
||||
|
||||
final SemVer minVersion;
|
||||
}
|
||||
|
||||
extension ServerCapabilitySupport on SemVer {
|
||||
bool supports(ServerCapability capability) => this >= capability.minVersion;
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import 'dart:async';
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/domain/models/server_capability.model.dart';
|
||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||
import 'package:immich_mobile/domain/models/sync_event.model.dart';
|
||||
import 'package:immich_mobile/entities/store.entity.dart';
|
||||
|
|
@ -122,7 +123,7 @@ class SyncStreamService {
|
|||
}
|
||||
|
||||
if (!migrations.contains(SyncMigrationTask.v20260128_ResetAssetV1.name) &&
|
||||
semVer >= const SemVer(major: 2, minor: 5, patch: 0)) {
|
||||
semVer.supports(.assetPayloadChange20260128)) {
|
||||
_logger.info("Running pre-sync task: v20260128_ResetAssetV1");
|
||||
await _syncApiRepository.deleteSyncAck([
|
||||
SyncEntityType.assetV1,
|
||||
|
|
@ -139,7 +140,7 @@ class SyncStreamService {
|
|||
}
|
||||
|
||||
if (!migrations.contains(SyncMigrationTask.v20260597_ResetAssetV1AssetV2.name) &&
|
||||
semVer > const SemVer(major: 2, minor: 7, patch: 5)) {
|
||||
semVer.supports(.assetPayloadChange20260597)) {
|
||||
_logger.info("Running pre-sync task: v20260597_ResetAssetV1AssetV2");
|
||||
await _syncApiRepository.deleteSyncAck([SyncEntityType.assetV1, SyncEntityType.assetV2]);
|
||||
migrations.add(SyncMigrationTask.v20260597_ResetAssetV1AssetV2.name);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||
import 'package:immich_mobile/constants/constants.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/asset_metadata.model.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/domain/models/server_capability.model.dart';
|
||||
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
|
|
@ -31,12 +32,12 @@ Future<void> syncCloudIds(ProviderContainer ref) async {
|
|||
await _populateCloudIds(db);
|
||||
|
||||
final serverInfo = await ref.read(serverInfoProvider.notifier).getServerInfo();
|
||||
final canUpdateMetadata = serverInfo.serverVersion.isAtLeast(major: 2, minor: 4);
|
||||
final canUpdateMetadata = serverInfo.serverVersion.supports(.cloudIdMetadata);
|
||||
if (!canUpdateMetadata) {
|
||||
logger.fine('Server version does not support asset metadata updates. Skipping cloudId migration.');
|
||||
return;
|
||||
}
|
||||
final canBulkUpdateMetadata = serverInfo.serverVersion.isAtLeast(major: 2, minor: 5);
|
||||
final canBulkUpdateMetadata = serverInfo.serverVersion.supports(.bulkCloudIdMetadata);
|
||||
|
||||
// Wait for remote sync to complete, so we have up-to-date asset metadata entries
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'dart:convert';
|
|||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:immich_mobile/constants/constants.dart';
|
||||
import 'package:immich_mobile/domain/models/server_capability.model.dart';
|
||||
import 'package:immich_mobile/domain/models/sync_event.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/network.repository.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
|
|
@ -44,25 +45,16 @@ class SyncApiRepository {
|
|||
types: [
|
||||
SyncRequestType.authUsersV1,
|
||||
SyncRequestType.usersV1,
|
||||
serverVersion >= const SemVer(major: 3, minor: 0, patch: 0)
|
||||
? SyncRequestType.assetsV2
|
||||
: SyncRequestType.assetsV1,
|
||||
serverVersion.supports(.syncV2) ? SyncRequestType.assetsV2 : SyncRequestType.assetsV1,
|
||||
SyncRequestType.assetExifsV1,
|
||||
if (serverVersion >= const SemVer(major: 2, minor: 6, patch: 0)) SyncRequestType.assetEditsV1,
|
||||
if (serverVersion.supports(.assetEdits)) SyncRequestType.assetEditsV1,
|
||||
SyncRequestType.assetMetadataV1,
|
||||
SyncRequestType.partnersV1,
|
||||
serverVersion >= const SemVer(major: 3, minor: 0, patch: 0)
|
||||
? SyncRequestType.partnerAssetsV2
|
||||
: SyncRequestType.partnerAssetsV1,
|
||||
serverVersion.supports(.syncV2) ? SyncRequestType.partnerAssetsV2 : SyncRequestType.partnerAssetsV1,
|
||||
SyncRequestType.partnerAssetExifsV1,
|
||||
if (serverVersion < const SemVer(major: 3, minor: 0, patch: 0))
|
||||
SyncRequestType.albumsV1
|
||||
else
|
||||
SyncRequestType.albumsV2,
|
||||
serverVersion.supports(.syncV2) ? SyncRequestType.albumsV2 : SyncRequestType.albumsV1,
|
||||
SyncRequestType.albumUsersV1,
|
||||
serverVersion >= const SemVer(major: 3, minor: 0, patch: 0)
|
||||
? SyncRequestType.albumAssetsV2
|
||||
: SyncRequestType.albumAssetsV1,
|
||||
serverVersion.supports(.syncV2) ? SyncRequestType.albumAssetsV2 : SyncRequestType.albumAssetsV1,
|
||||
SyncRequestType.albumAssetExifsV1,
|
||||
SyncRequestType.albumToAssetsV1,
|
||||
SyncRequestType.memoriesV1,
|
||||
|
|
@ -71,10 +63,8 @@ class SyncApiRepository {
|
|||
SyncRequestType.partnerStacksV1,
|
||||
SyncRequestType.userMetadataV1,
|
||||
SyncRequestType.peopleV1,
|
||||
serverVersion >= const SemVer(major: 2, minor: 6, patch: 0)
|
||||
? SyncRequestType.assetFacesV2
|
||||
: SyncRequestType.assetFacesV1,
|
||||
if (serverVersion >= const SemVer(major: 3, minor: 0, patch: 0)) SyncRequestType.assetOcrV1,
|
||||
serverVersion.supports(.assetFacesV2) ? SyncRequestType.assetFacesV2 : SyncRequestType.assetFacesV1,
|
||||
if (serverVersion.supports(.assetOcr)) SyncRequestType.assetOcrV1,
|
||||
],
|
||||
).toJson(),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -6,8 +6,4 @@ class ServerVersion extends SemVer {
|
|||
|
||||
ServerVersion.fromDto(ServerVersionResponseDto dto)
|
||||
: super(major: dto.major, minor: dto.minor, patch: dto.patch_, prerelease: dto.prerelease);
|
||||
|
||||
bool isAtLeast({int major = 0, int minor = 0, int patch = 0, int? prerelease}) {
|
||||
return this >= SemVer(major: major, minor: minor, patch: patch, prerelease: prerelease);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||
import 'package:immich_mobile/constants/enums.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/domain/models/asset_edit.model.dart';
|
||||
import 'package:immich_mobile/domain/models/server_capability.model.dart';
|
||||
import 'package:immich_mobile/generated/translations.g.dart';
|
||||
import 'package:immich_mobile/presentation/actions/action.dart';
|
||||
import 'package:immich_mobile/presentation/pages/edit/editor.provider.dart';
|
||||
|
|
@ -16,12 +17,9 @@ import 'package:immich_mobile/providers/server_info.provider.dart';
|
|||
import 'package:immich_mobile/providers/websocket.provider.dart';
|
||||
import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/utils/error_handler.dart';
|
||||
import 'package:immich_mobile/utils/semver.dart';
|
||||
|
||||
const _minimumServerVersion = SemVer(major: 2, minor: 6, patch: 0);
|
||||
|
||||
final _stateProvider = Provider.family.autoDispose<RemoteAsset?, ActionSource>((ref, source) {
|
||||
final isSupported = ref.watch(serverInfoProvider.select((state) => state.serverVersion >= _minimumServerVersion));
|
||||
final isSupported = ref.watch(serverInfoProvider.select((state) => state.serverVersion.supports(.assetEdits)));
|
||||
if (!isSupported) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'dart:io';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/server_capability.model.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
||||
import 'package:immich_mobile/generated/translations.g.dart';
|
||||
|
|
@ -150,7 +151,7 @@ class SyncStatusAndActions extends HookConsumerWidget {
|
|||
unawaited(ref.read(backgroundSyncProvider).syncRemote());
|
||||
},
|
||||
),
|
||||
if (CurrentPlatform.isIOS && serverVersion.isAtLeast(major: 2, minor: 5))
|
||||
if (CurrentPlatform.isIOS && serverVersion.supports(.cloudIdMetadata))
|
||||
SettingListTile(
|
||||
title: 'Sync Cloud Ids',
|
||||
leading: const Icon(Icons.cloud_circle_rounded),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue