Files
immich/mobile/pigeon/native_sync_api.dart
T
Santo Shakil 2d9183ab44 feat(mobile): stack original + edited photo on ios
Detect an iOS edit, upload the unedited original, and stack the edited
version on top of it. Reverting in Photos flips the stack cover back to
the original and keeps the edits. Adds an optional stackParentId field to
the asset upload on the server.
2026-05-23 03:47:26 +06:00

167 lines
4.3 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 durationMs;
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.durationMs = 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});
}
class BaseResource {
final String path;
final String sha1;
final int sizeBytes;
final String mimeType;
const BaseResource({required this.path, required this.sha1, required this.sizeBytes, required this.mimeType});
}
// Whether an iOS asset currently carries a user edit, as opposed to a
// capture-time Photographic Style or a reverted edit. `unknown` means the
// adjustment data couldn't be read (e.g. the asset is offloaded to iCloud and
// network wasn't allowed), so callers must not treat it as "not edited".
enum EditState { notEdited, edited, unknown }
@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();
@async
bool restoreFromTrashById(String mediaId, int type);
@TaskQueue(type: TaskQueueType.serialBackgroundThread)
List<CloudIdResult> getCloudIdForAssetIds(List<String> assetIds);
@async
@TaskQueue(type: TaskQueueType.serialBackgroundThread)
BaseResource? getBaseResource(String assetId, {bool allowNetworkAccess = false});
@async
@TaskQueue(type: TaskQueueType.serialBackgroundThread)
EditState getEditState(String assetId, {bool allowNetworkAccess = false});
}