immich/mobile/pigeon/native_sync_api.dart
Luis Nachtigall d6c724b13b
feat(mobile): add playbackStyle to native sync API (#26541)
* feat(mobile): add playbackStyle to native sync API

Adds a `playbackStyle` field to `PlatformAsset` in the pigeon sync API so
native platforms can communicate the asset's playback style (image, video,
animated, livePhoto) to Flutter during sync.

- Add `playbackStyleValue` computed property to `PHAsset` extension (iOS)
- Populate `playbackStyle` in `toPlatformAsset()` and the full-sync path
- Update generated Dart/Kotlin/Swift files

* fix(tests): add playbackStyle to local asset test cases

* fix(tests): update playbackStyle to use integer values in local sync tests

* feat(mobile): extend playbackStyle enum to include videoLooping

* Update PHAssetExtensions.swift

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(playback): simplify playbackStyleValue implementation by removing iOS version check

* feat(android): implement proper playbackStyle detection

* add PlatformAssetPlaybackStyle enum

* linting

---------

Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-28 03:08:51 +00:00

148 lines
3.4 KiB
Dart

import 'package:pigeon/pigeon.dart';
@ConfigurePigeon(
PigeonOptions(
dartOut: 'lib/platform/native_sync_api.g.dart',
swiftOut: 'ios/Runner/Sync/Messages.g.swift',
swiftOptions: SwiftOptions(),
kotlinOut: 'android/app/src/main/kotlin/app/alextran/immich/sync/Messages.g.kt',
kotlinOptions: KotlinOptions(package: 'app.alextran.immich.sync'),
dartOptions: DartOptions(),
dartPackageName: 'immich_mobile',
),
)
enum PlatformAssetPlaybackStyle {
unknown,
image,
video,
imageAnimated,
livePhoto,
videoLooping,
}
class PlatformAsset {
final String id;
final String name;
// Follows AssetType enum from base_asset.model.dart
final int type;
// Seconds since epoch
final int? createdAt;
final int? updatedAt;
final int? width;
final int? height;
final int durationInSeconds;
final int orientation;
final bool isFavorite;
final int? adjustmentTime;
final double? latitude;
final double? longitude;
final PlatformAssetPlaybackStyle playbackStyle;
const PlatformAsset({
required this.id,
required this.name,
required this.type,
this.createdAt,
this.updatedAt,
this.width,
this.height,
this.durationInSeconds = 0,
this.orientation = 0,
this.isFavorite = false,
this.adjustmentTime,
this.latitude,
this.longitude,
this.playbackStyle = PlatformAssetPlaybackStyle.unknown,
});
}
class PlatformAlbum {
final String id;
final String name;
// Seconds since epoch
final int? updatedAt;
final bool isCloud;
final int assetCount;
const PlatformAlbum({
required this.id,
required this.name,
this.updatedAt,
this.isCloud = false,
this.assetCount = 0,
});
}
class SyncDelta {
final bool hasChanges;
final List<PlatformAsset> updates;
final List<String> deletes;
// Asset -> Album mapping
final Map<String, List<String>> assetAlbums;
const SyncDelta({
this.hasChanges = false,
this.updates = const [],
this.deletes = const [],
this.assetAlbums = const {},
});
}
class HashResult {
final String assetId;
final String? error;
final String? hash;
const HashResult({required this.assetId, this.error, this.hash});
}
class CloudIdResult {
final String assetId;
final String? error;
final String? cloudId;
const CloudIdResult({required this.assetId, this.error, this.cloudId});
}
@HostApi()
abstract class NativeSyncApi {
bool shouldFullSync();
@TaskQueue(type: TaskQueueType.serialBackgroundThread)
SyncDelta getMediaChanges();
void checkpointSync();
void clearSyncCheckpoint();
@TaskQueue(type: TaskQueueType.serialBackgroundThread)
List<String> getAssetIdsForAlbum(String albumId);
@TaskQueue(type: TaskQueueType.serialBackgroundThread)
List<PlatformAlbum> getAlbums();
@TaskQueue(type: TaskQueueType.serialBackgroundThread)
int getAssetsCountSince(String albumId, int timestamp);
@TaskQueue(type: TaskQueueType.serialBackgroundThread)
List<PlatformAsset> getAssetsForAlbum(String albumId, {int? updatedTimeCond});
@async
@TaskQueue(type: TaskQueueType.serialBackgroundThread)
List<HashResult> hashAssets(List<String> assetIds, {bool allowNetworkAccess = false});
void cancelHashing();
@TaskQueue(type: TaskQueueType.serialBackgroundThread)
Map<String, List<PlatformAsset>> getTrashedAssets();
@TaskQueue(type: TaskQueueType.serialBackgroundThread)
List<CloudIdResult> getCloudIdForAssetIds(List<String> assetIds);
}