feat: fix discriminated type parsing

This commit is contained in:
bwees
2026-01-20 10:23:43 -06:00
parent 61a9d5cbc7
commit 5bbd7df137
7 changed files with 116 additions and 17 deletions

View File

@@ -4,6 +4,7 @@ import 'package:immich_mobile/domain/models/exif.model.dart';
import 'package:immich_mobile/extensions/platform_extensions.dart';
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/remote_asset.repository.dart';
import 'package:openapi/api.dart';
typedef _AssetVideoDimension = ({double? width, double? height, bool isFlipped});
@@ -116,4 +117,12 @@ class AssetService {
Future<List<LocalAlbum>> getSourceAlbums(String localAssetId, {BackupSelection? backupSelection}) {
return _localAssetRepository.getSourceAlbums(localAssetId, backupSelection: backupSelection);
}
Future<AssetEditsDto?> getAssetEdits(String assetId) {
return _remoteAssetRepository.getAssetEdits(assetId);
}
Future<AssetEditsDto?> editAsset(String assetId, AssetEditActionListDto edits) {
return _remoteAssetRepository.editAsset(assetId, edits);
}
}

View File

@@ -9,11 +9,13 @@ import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.
import 'package:immich_mobile/infrastructure/entities/stack.entity.drift.dart';
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
import 'package:maplibre_gl/maplibre_gl.dart';
import 'package:openapi/api.dart' hide AssetVisibility;
class RemoteAssetRepository extends DriftDatabaseRepository {
final Drift _db;
final AssetsApi _api;
const RemoteAssetRepository(this._db) : super(_db);
const RemoteAssetRepository(this._db, this._api) : super(_db);
/// For testing purposes
Future<List<RemoteAsset>> getSome(String userId) {
@@ -258,4 +260,12 @@ class RemoteAssetRepository extends DriftDatabaseRepository {
Future<int> getCount() {
return _db.managers.remoteAssetEntity.count();
}
Future<AssetEditsDto?> getAssetEdits(String assetId) async {
return _api.getAssetEdits(assetId);
}
Future<AssetEditsDto?> editAsset(String assetId, AssetEditActionListDto edits) {
return _api.editAsset(assetId, edits);
}
}

View File

@@ -11,6 +11,7 @@ import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/providers/background_sync.provider.dart';
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
import 'package:immich_mobile/repositories/file_media.repository.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/services/foreground_upload.service.dart';
@@ -91,6 +92,8 @@ class DriftEditImagePage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final edits = ref.read(assetServiceProvider).getAssetEdits(asset.remoteId!);
return Scaffold(
appBar: AppBar(
title: Text("edit".tr()),
@@ -139,6 +142,12 @@ class DriftEditImagePage extends ConsumerWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
FutureBuilder(
future: edits,
builder: (ctx, data) {
return Text(data.hasData ? data.data?.edits.length.toString() ?? "" : "...");
},
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[

View File

@@ -3,6 +3,7 @@ import 'package:immich_mobile/domain/services/asset.service.dart';
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/remote_asset.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/trashed_local_asset.repository.dart';
import 'package:immich_mobile/providers/api.provider.dart';
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';
@@ -11,7 +12,7 @@ final localAssetRepository = Provider<DriftLocalAssetRepository>(
);
final remoteAssetRepositoryProvider = Provider<RemoteAssetRepository>(
(ref) => RemoteAssetRepository(ref.watch(driftProvider)),
(ref) => RemoteAssetRepository(ref.watch(driftProvider), ref.watch(apiServiceProvider).assetsApi),
);
final trashedLocalAssetRepository = Provider<DriftTrashedLocalAssetRepository>(

View File

@@ -19,26 +19,26 @@ class AssetEditActionListDtoEditsInner {
AssetEditAction action;
MirrorParameters parameters;
/// Union type: can be MirrorParameters, RotateParameters, or CropParameters
Object parameters;
@override
bool operator ==(Object other) => identical(this, other) || other is AssetEditActionListDtoEditsInner &&
other.action == action &&
other.parameters == parameters;
bool operator ==(Object other) =>
identical(this, other) ||
other is AssetEditActionListDtoEditsInner && other.action == action && other.parameters == parameters;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(action.hashCode) +
(parameters.hashCode);
// ignore: unnecessary_parenthesis
(action.hashCode) + (parameters.hashCode);
@override
String toString() => 'AssetEditActionListDtoEditsInner[action=$action, parameters=$parameters]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'action'] = this.action;
json[r'parameters'] = this.parameters;
json[r'action'] = this.action;
json[r'parameters'] = this.parameters;
return json;
}
@@ -50,15 +50,35 @@ class AssetEditActionListDtoEditsInner {
if (value is Map) {
final json = value.cast<String, dynamic>();
final action = AssetEditAction.fromJson(json[r'action'])!;
final parametersJson = json[r'parameters'];
// Deserialize parameters based on action type
Object parameters = {};
switch (action) {
case AssetEditAction.crop:
parameters = CropParameters.fromJson(parametersJson)!;
break;
case AssetEditAction.rotate:
parameters = RotateParameters.fromJson(parametersJson)!;
break;
case AssetEditAction.mirror:
parameters = MirrorParameters.fromJson(parametersJson)!;
break;
}
return AssetEditActionListDtoEditsInner(
action: AssetEditAction.fromJson(json[r'action'])!,
parameters: MirrorParameters.fromJson(json[r'parameters'])!,
action: action,
parameters: parameters,
);
}
return null;
}
static List<AssetEditActionListDtoEditsInner> listFromJson(dynamic json, {bool growable = false,}) {
static List<AssetEditActionListDtoEditsInner> listFromJson(
dynamic json, {
bool growable = false,
}) {
final result = <AssetEditActionListDtoEditsInner>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
@@ -86,13 +106,19 @@ class AssetEditActionListDtoEditsInner {
}
// maps a json object with a list of AssetEditActionListDtoEditsInner-objects as value to a dart map
static Map<String, List<AssetEditActionListDtoEditsInner>> mapListFromJson(dynamic json, {bool growable = false,}) {
static Map<String, List<AssetEditActionListDtoEditsInner>> mapListFromJson(
dynamic json, {
bool growable = false,
}) {
final map = <String, List<AssetEditActionListDtoEditsInner>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = AssetEditActionListDtoEditsInner.listFromJson(entry.value, growable: growable,);
map[entry.key] = AssetEditActionListDtoEditsInner.listFromJson(
entry.value,
growable: growable,
);
}
}
return map;
@@ -104,4 +130,3 @@ class AssetEditActionListDtoEditsInner {
'parameters',
};
}

View File

@@ -21,6 +21,7 @@ function dart {
patch --no-backup-if-mismatch -u ../mobile/openapi/lib/api_client.dart <./patch/api_client.dart.patch
patch --no-backup-if-mismatch -u ../mobile/openapi/lib/api.dart <./patch/api.dart.patch
patch --no-backup-if-mismatch -u ../mobile/openapi/pubspec.yaml <./patch/pubspec_immich_mobile.yaml.patch
patch --no-backup-if-mismatch -u ../mobile/openapi/lib/model/asset_edit_action_list_dto_edits_inner.dart <./patch/asset_edit_action_list_dto_edits_inner.dart.patch
# Don't include analysis_options.yaml for the generated openapi files
# so that language servers can properly exclude the mobile/openapi directory
rm ../mobile/openapi/analysis_options.yaml

View File

@@ -0,0 +1,44 @@
@@ -19,7 +19,8 @@
AssetEditAction action;
- MirrorParameters parameters;
+ /// Union type: can be MirrorParameters, RotateParameters, or CropParameters
+ Object parameters;
@override
bool operator ==(Object other) => identical(this, other) || other is AssetEditActionListDtoEditsInner &&
@@ -50,9 +51,26 @@
if (value is Map) {
final json = value.cast<String, dynamic>();
+ final action = AssetEditAction.fromJson(json[r'action'])!;
+ final parametersJson = json[r'parameters'];
+
+ // Deserialize parameters based on action type
+ Object parameters = {};
+ switch (action) {
+ case AssetEditAction.crop:
+ parameters = CropParameters.fromJson(parametersJson)!;
+ break;
+ case AssetEditAction.rotate:
+ parameters = RotateParameters.fromJson(parametersJson)!;
+ break;
+ case AssetEditAction.mirror:
+ parameters = MirrorParameters.fromJson(parametersJson)!;
+ break;
+ }
+
return AssetEditActionListDtoEditsInner(
- action: AssetEditAction.fromJson(json[r'action'])!,
- parameters: MirrorParameters.fromJson(json[r'parameters'])!,
+ action: action,
+ parameters: parameters,
);
}
return null;
@@ -104,4 +122,3 @@
'parameters',
};
}
-