feat(mobile): add album asset sync (#19522)

* feat(mobile): add album asset sync

* add SyncAlbumToAssetDeleteV1 to openapi-spec

* update delete queries to use where in statements

* clear remote album when clear remote data

* fix: bad merge

* fix: bad merge

* fix: _SyncAckV1 return type

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: wuzihao051119 <wuzihao051119@outlook.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
shenlong
2025-06-26 19:20:39 +05:30
committed by GitHub
parent 24a4cba953
commit ea3a14ed25
39 changed files with 3059 additions and 100 deletions
@@ -2,8 +2,8 @@ import 'dart:async';
import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/models/local_album.model.dart';
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
import 'package:immich_mobile/platform/native_sync_api.g.dart';
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
@@ -76,11 +76,76 @@ class SyncStreamService {
case SyncEntityType.assetExifV1:
return _syncStreamRepository.updateAssetsExifV1(data.cast());
case SyncEntityType.partnerAssetV1:
return _syncStreamRepository.updatePartnerAssetsV1(data.cast());
return _syncStreamRepository.updateAssetsV1(
data.cast(),
debugLabel: 'partner',
);
case SyncEntityType.partnerAssetBackfillV1:
return _syncStreamRepository.updateAssetsV1(
data.cast(),
debugLabel: 'partner backfill',
);
case SyncEntityType.partnerAssetDeleteV1:
return _syncStreamRepository.deletePartnerAssetsV1(data.cast());
return _syncStreamRepository.deleteAssetsV1(
data.cast(),
debugLabel: "partner",
);
case SyncEntityType.partnerAssetExifV1:
return _syncStreamRepository.updatePartnerAssetsExifV1(data.cast());
return _syncStreamRepository.updateAssetsExifV1(
data.cast(),
debugLabel: 'partner',
);
case SyncEntityType.partnerAssetExifBackfillV1:
return _syncStreamRepository.updateAssetsExifV1(
data.cast(),
debugLabel: 'partner backfill',
);
case SyncEntityType.albumV1:
return _syncStreamRepository.updateAlbumsV1(data.cast());
case SyncEntityType.albumDeleteV1:
return _syncStreamRepository.deleteAlbumsV1(data.cast());
case SyncEntityType.albumUserV1:
return _syncStreamRepository.updateAlbumUsersV1(data.cast());
case SyncEntityType.albumUserBackfillV1:
return _syncStreamRepository.updateAlbumUsersV1(
data.cast(),
debugLabel: 'backfill',
);
case SyncEntityType.albumUserDeleteV1:
return _syncStreamRepository.deleteAlbumUsersV1(data.cast());
case SyncEntityType.albumAssetV1:
return _syncStreamRepository.updateAssetsV1(
data.cast(),
debugLabel: 'album',
);
case SyncEntityType.albumAssetBackfillV1:
return _syncStreamRepository.updateAssetsV1(
data.cast(),
debugLabel: 'album backfill',
);
case SyncEntityType.albumAssetExifV1:
return _syncStreamRepository.updateAssetsExifV1(
data.cast(),
debugLabel: 'album',
);
case SyncEntityType.albumAssetExifBackfillV1:
return _syncStreamRepository.updateAssetsExifV1(
data.cast(),
debugLabel: 'album backfill',
);
case SyncEntityType.albumToAssetV1:
return _syncStreamRepository.updateAlbumToAssetsV1(data.cast());
case SyncEntityType.albumToAssetBackfillV1:
return _syncStreamRepository.updateAlbumToAssetsV1(
data.cast(),
debugLabel: 'backfill',
);
case SyncEntityType.albumToAssetDeleteV1:
return _syncStreamRepository.deleteAlbumToAssetsV1(data.cast());
// No-op. SyncAckV1 entities are checkpoints in the sync stream
// to acknowledge that the client has processed all the backfill events
case SyncEntityType.syncAckV1:
return;
default:
_logger.warning("Unknown sync data type: $type");
}
@@ -45,6 +45,13 @@ class TimelineFactory {
bucketSource: () =>
_timelineRepository.watchLocalBucket(albumId, groupBy: groupBy),
);
TimelineService remoteAlbum({required String albumId}) => TimelineService(
assetSource: (offset, count) => _timelineRepository
.getRemoteBucketAssets(albumId, offset: offset, count: count),
bucketSource: () =>
_timelineRepository.watchRemoteBucket(albumId, groupBy: groupBy),
);
}
class TimelineService {