feat: favorite albums

This commit is contained in:
Alex Tran
2026-03-29 05:05:44 +00:00
parent b09ebb11e9
commit 6876eb2f05
43 changed files with 1421 additions and 29 deletions
+4
View File
@@ -95,6 +95,7 @@ Class | Method | HTTP request | Description
*AlbumsApi* | [**removeUserFromAlbum**](doc//AlbumsApi.md#removeuserfromalbum) | **DELETE** /albums/{id}/user/{userId} | Remove user from album
*AlbumsApi* | [**updateAlbumInfo**](doc//AlbumsApi.md#updatealbuminfo) | **PATCH** /albums/{id} | Update an album
*AlbumsApi* | [**updateAlbumUser**](doc//AlbumsApi.md#updatealbumuser) | **PUT** /albums/{id}/user/{userId} | Update user role
*AlbumsApi* | [**updateAlbumUserMetadata**](doc//AlbumsApi.md#updatealbumusermetadata) | **PATCH** /albums/{id}/user-metadata | Update album user metadata
*AssetsApi* | [**checkBulkUpload**](doc//AssetsApi.md#checkbulkupload) | **POST** /assets/bulk-upload-check | Check bulk upload
*AssetsApi* | [**checkExistingAssets**](doc//AssetsApi.md#checkexistingassets) | **POST** /assets/exist | Check existing assets
*AssetsApi* | [**copyAsset**](doc//AssetsApi.md#copyasset) | **PUT** /assets/copy | Copy asset
@@ -576,6 +577,8 @@ Class | Method | HTTP request | Description
- [SyncAlbumToAssetDeleteV1](doc//SyncAlbumToAssetDeleteV1.md)
- [SyncAlbumToAssetV1](doc//SyncAlbumToAssetV1.md)
- [SyncAlbumUserDeleteV1](doc//SyncAlbumUserDeleteV1.md)
- [SyncAlbumUserMetadataDeleteV1](doc//SyncAlbumUserMetadataDeleteV1.md)
- [SyncAlbumUserMetadataV1](doc//SyncAlbumUserMetadataV1.md)
- [SyncAlbumUserV1](doc//SyncAlbumUserV1.md)
- [SyncAlbumV1](doc//SyncAlbumV1.md)
- [SyncAssetDeleteV1](doc//SyncAssetDeleteV1.md)
@@ -656,6 +659,7 @@ Class | Method | HTTP request | Description
- [TrashResponseDto](doc//TrashResponseDto.md)
- [UpdateAlbumDto](doc//UpdateAlbumDto.md)
- [UpdateAlbumUserDto](doc//UpdateAlbumUserDto.md)
- [UpdateAlbumUserMetadataDto](doc//UpdateAlbumUserMetadataDto.md)
- [UpdateAssetDto](doc//UpdateAssetDto.md)
- [UpdateLibraryDto](doc//UpdateLibraryDto.md)
- [UsageByUserDto](doc//UsageByUserDto.md)
+3
View File
@@ -314,6 +314,8 @@ part 'model/sync_album_delete_v1.dart';
part 'model/sync_album_to_asset_delete_v1.dart';
part 'model/sync_album_to_asset_v1.dart';
part 'model/sync_album_user_delete_v1.dart';
part 'model/sync_album_user_metadata_delete_v1.dart';
part 'model/sync_album_user_metadata_v1.dart';
part 'model/sync_album_user_v1.dart';
part 'model/sync_album_v1.dart';
part 'model/sync_asset_delete_v1.dart';
@@ -394,6 +396,7 @@ part 'model/transcode_policy.dart';
part 'model/trash_response_dto.dart';
part 'model/update_album_dto.dart';
part 'model/update_album_user_dto.dart';
part 'model/update_album_user_metadata_dto.dart';
part 'model/update_asset_dto.dart';
part 'model/update_library_dto.dart';
part 'model/usage_by_user_dto.dart';
+61
View File
@@ -771,4 +771,65 @@ class AlbumsApi {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
}
/// Update album user metadata
///
/// Update metadata for the authenticated user on a specific album.
///
/// Note: This method returns the HTTP [Response].
///
/// Parameters:
///
/// * [String] id (required):
///
/// * [UpdateAlbumUserMetadataDto] updateAlbumUserMetadataDto (required):
Future<Response> updateAlbumUserMetadataWithHttpInfo(String id, UpdateAlbumUserMetadataDto updateAlbumUserMetadataDto,) async {
// ignore: prefer_const_declarations
final apiPath = r'/albums/{id}/user-metadata'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
Object? postBody = updateAlbumUserMetadataDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
apiPath,
'PATCH',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Update album user metadata
///
/// Update metadata for the authenticated user on a specific album.
///
/// Parameters:
///
/// * [String] id (required):
///
/// * [UpdateAlbumUserMetadataDto] updateAlbumUserMetadataDto (required):
Future<AlbumResponseDto?> updateAlbumUserMetadata(String id, UpdateAlbumUserMetadataDto updateAlbumUserMetadataDto,) async {
final response = await updateAlbumUserMetadataWithHttpInfo(id, updateAlbumUserMetadataDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'AlbumResponseDto',) as AlbumResponseDto;
}
return null;
}
}
+6
View File
@@ -674,6 +674,10 @@ class ApiClient {
return SyncAlbumToAssetV1.fromJson(value);
case 'SyncAlbumUserDeleteV1':
return SyncAlbumUserDeleteV1.fromJson(value);
case 'SyncAlbumUserMetadataDeleteV1':
return SyncAlbumUserMetadataDeleteV1.fromJson(value);
case 'SyncAlbumUserMetadataV1':
return SyncAlbumUserMetadataV1.fromJson(value);
case 'SyncAlbumUserV1':
return SyncAlbumUserV1.fromJson(value);
case 'SyncAlbumV1':
@@ -834,6 +838,8 @@ class ApiClient {
return UpdateAlbumDto.fromJson(value);
case 'UpdateAlbumUserDto':
return UpdateAlbumUserDto.fromJson(value);
case 'UpdateAlbumUserMetadataDto':
return UpdateAlbumUserMetadataDto.fromJson(value);
case 'UpdateAssetDto':
return UpdateAssetDto.fromJson(value);
case 'UpdateLibraryDto':
+10 -1
View File
@@ -25,6 +25,7 @@ class AlbumResponseDto {
required this.hasSharedLink,
required this.id,
required this.isActivityEnabled,
required this.isFavorite,
this.lastModifiedAssetTimestamp,
this.order,
required this.owner,
@@ -73,6 +74,9 @@ class AlbumResponseDto {
/// Activity feed enabled
bool isActivityEnabled;
/// Is favorite
bool isFavorite;
/// Last modified asset timestamp
///
/// Please note: This property should have been non-nullable! Since the specification file
@@ -125,6 +129,7 @@ class AlbumResponseDto {
other.hasSharedLink == hasSharedLink &&
other.id == id &&
other.isActivityEnabled == isActivityEnabled &&
other.isFavorite == isFavorite &&
other.lastModifiedAssetTimestamp == lastModifiedAssetTimestamp &&
other.order == order &&
other.owner == owner &&
@@ -148,6 +153,7 @@ class AlbumResponseDto {
(hasSharedLink.hashCode) +
(id.hashCode) +
(isActivityEnabled.hashCode) +
(isFavorite.hashCode) +
(lastModifiedAssetTimestamp == null ? 0 : lastModifiedAssetTimestamp!.hashCode) +
(order == null ? 0 : order!.hashCode) +
(owner.hashCode) +
@@ -157,7 +163,7 @@ class AlbumResponseDto {
(updatedAt.hashCode);
@override
String toString() => 'AlbumResponseDto[albumName=$albumName, albumThumbnailAssetId=$albumThumbnailAssetId, albumUsers=$albumUsers, assetCount=$assetCount, assets=$assets, contributorCounts=$contributorCounts, createdAt=$createdAt, description=$description, endDate=$endDate, hasSharedLink=$hasSharedLink, id=$id, isActivityEnabled=$isActivityEnabled, lastModifiedAssetTimestamp=$lastModifiedAssetTimestamp, order=$order, owner=$owner, ownerId=$ownerId, shared=$shared, startDate=$startDate, updatedAt=$updatedAt]';
String toString() => 'AlbumResponseDto[albumName=$albumName, albumThumbnailAssetId=$albumThumbnailAssetId, albumUsers=$albumUsers, assetCount=$assetCount, assets=$assets, contributorCounts=$contributorCounts, createdAt=$createdAt, description=$description, endDate=$endDate, hasSharedLink=$hasSharedLink, id=$id, isActivityEnabled=$isActivityEnabled, isFavorite=$isFavorite, lastModifiedAssetTimestamp=$lastModifiedAssetTimestamp, order=$order, owner=$owner, ownerId=$ownerId, shared=$shared, startDate=$startDate, updatedAt=$updatedAt]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
@@ -181,6 +187,7 @@ class AlbumResponseDto {
json[r'hasSharedLink'] = this.hasSharedLink;
json[r'id'] = this.id;
json[r'isActivityEnabled'] = this.isActivityEnabled;
json[r'isFavorite'] = this.isFavorite;
if (this.lastModifiedAssetTimestamp != null) {
json[r'lastModifiedAssetTimestamp'] = this.lastModifiedAssetTimestamp!.toUtc().toIso8601String();
} else {
@@ -224,6 +231,7 @@ class AlbumResponseDto {
hasSharedLink: mapValueOfType<bool>(json, r'hasSharedLink')!,
id: mapValueOfType<String>(json, r'id')!,
isActivityEnabled: mapValueOfType<bool>(json, r'isActivityEnabled')!,
isFavorite: mapValueOfType<bool>(json, r'isFavorite')!,
lastModifiedAssetTimestamp: mapDateTime(json, r'lastModifiedAssetTimestamp', r''),
order: AssetOrder.fromJson(json[r'order']),
owner: UserResponseDto.fromJson(json[r'owner'])!,
@@ -288,6 +296,7 @@ class AlbumResponseDto {
'hasSharedLink',
'id',
'isActivityEnabled',
'isFavorite',
'owner',
'ownerId',
'shared',
@@ -0,0 +1,109 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class SyncAlbumUserMetadataDeleteV1 {
/// Returns a new [SyncAlbumUserMetadataDeleteV1] instance.
SyncAlbumUserMetadataDeleteV1({
required this.albumId,
required this.userId,
});
/// Album ID
String albumId;
/// User ID
String userId;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncAlbumUserMetadataDeleteV1 &&
other.albumId == albumId &&
other.userId == userId;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(albumId.hashCode) +
(userId.hashCode);
@override
String toString() => 'SyncAlbumUserMetadataDeleteV1[albumId=$albumId, userId=$userId]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'albumId'] = this.albumId;
json[r'userId'] = this.userId;
return json;
}
/// Returns a new [SyncAlbumUserMetadataDeleteV1] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncAlbumUserMetadataDeleteV1? fromJson(dynamic value) {
upgradeDto(value, "SyncAlbumUserMetadataDeleteV1");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncAlbumUserMetadataDeleteV1(
albumId: mapValueOfType<String>(json, r'albumId')!,
userId: mapValueOfType<String>(json, r'userId')!,
);
}
return null;
}
static List<SyncAlbumUserMetadataDeleteV1> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAlbumUserMetadataDeleteV1>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAlbumUserMetadataDeleteV1.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncAlbumUserMetadataDeleteV1> mapFromJson(dynamic json) {
final map = <String, SyncAlbumUserMetadataDeleteV1>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncAlbumUserMetadataDeleteV1.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncAlbumUserMetadataDeleteV1-objects as value to a dart map
static Map<String, List<SyncAlbumUserMetadataDeleteV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncAlbumUserMetadataDeleteV1>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncAlbumUserMetadataDeleteV1.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'albumId',
'userId',
};
}
+118
View File
@@ -0,0 +1,118 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class SyncAlbumUserMetadataV1 {
/// Returns a new [SyncAlbumUserMetadataV1] instance.
SyncAlbumUserMetadataV1({
required this.albumId,
required this.isFavorite,
required this.userId,
});
/// Album ID
String albumId;
/// Is favorite
bool isFavorite;
/// User ID
String userId;
@override
bool operator ==(Object other) => identical(this, other) || other is SyncAlbumUserMetadataV1 &&
other.albumId == albumId &&
other.isFavorite == isFavorite &&
other.userId == userId;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(albumId.hashCode) +
(isFavorite.hashCode) +
(userId.hashCode);
@override
String toString() => 'SyncAlbumUserMetadataV1[albumId=$albumId, isFavorite=$isFavorite, userId=$userId]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'albumId'] = this.albumId;
json[r'isFavorite'] = this.isFavorite;
json[r'userId'] = this.userId;
return json;
}
/// Returns a new [SyncAlbumUserMetadataV1] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SyncAlbumUserMetadataV1? fromJson(dynamic value) {
upgradeDto(value, "SyncAlbumUserMetadataV1");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SyncAlbumUserMetadataV1(
albumId: mapValueOfType<String>(json, r'albumId')!,
isFavorite: mapValueOfType<bool>(json, r'isFavorite')!,
userId: mapValueOfType<String>(json, r'userId')!,
);
}
return null;
}
static List<SyncAlbumUserMetadataV1> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SyncAlbumUserMetadataV1>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SyncAlbumUserMetadataV1.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SyncAlbumUserMetadataV1> mapFromJson(dynamic json) {
final map = <String, SyncAlbumUserMetadataV1>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SyncAlbumUserMetadataV1.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SyncAlbumUserMetadataV1-objects as value to a dart map
static Map<String, List<SyncAlbumUserMetadataV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SyncAlbumUserMetadataV1>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SyncAlbumUserMetadataV1.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'albumId',
'isFavorite',
'userId',
};
}
+6
View File
@@ -48,6 +48,8 @@ class SyncEntityType {
static const albumUserV1 = SyncEntityType._(r'AlbumUserV1');
static const albumUserBackfillV1 = SyncEntityType._(r'AlbumUserBackfillV1');
static const albumUserDeleteV1 = SyncEntityType._(r'AlbumUserDeleteV1');
static const albumUserMetadataV1 = SyncEntityType._(r'AlbumUserMetadataV1');
static const albumUserMetadataDeleteV1 = SyncEntityType._(r'AlbumUserMetadataDeleteV1');
static const albumAssetCreateV1 = SyncEntityType._(r'AlbumAssetCreateV1');
static const albumAssetUpdateV1 = SyncEntityType._(r'AlbumAssetUpdateV1');
static const albumAssetBackfillV1 = SyncEntityType._(r'AlbumAssetBackfillV1');
@@ -101,6 +103,8 @@ class SyncEntityType {
albumUserV1,
albumUserBackfillV1,
albumUserDeleteV1,
albumUserMetadataV1,
albumUserMetadataDeleteV1,
albumAssetCreateV1,
albumAssetUpdateV1,
albumAssetBackfillV1,
@@ -189,6 +193,8 @@ class SyncEntityTypeTypeTransformer {
case r'AlbumUserV1': return SyncEntityType.albumUserV1;
case r'AlbumUserBackfillV1': return SyncEntityType.albumUserBackfillV1;
case r'AlbumUserDeleteV1': return SyncEntityType.albumUserDeleteV1;
case r'AlbumUserMetadataV1': return SyncEntityType.albumUserMetadataV1;
case r'AlbumUserMetadataDeleteV1': return SyncEntityType.albumUserMetadataDeleteV1;
case r'AlbumAssetCreateV1': return SyncEntityType.albumAssetCreateV1;
case r'AlbumAssetUpdateV1': return SyncEntityType.albumAssetUpdateV1;
case r'AlbumAssetBackfillV1': return SyncEntityType.albumAssetBackfillV1;
+3
View File
@@ -25,6 +25,7 @@ class SyncRequestType {
static const albumsV1 = SyncRequestType._(r'AlbumsV1');
static const albumUsersV1 = SyncRequestType._(r'AlbumUsersV1');
static const albumUserMetadataV1 = SyncRequestType._(r'AlbumUserMetadataV1');
static const albumToAssetsV1 = SyncRequestType._(r'AlbumToAssetsV1');
static const albumAssetsV1 = SyncRequestType._(r'AlbumAssetsV1');
static const albumAssetExifsV1 = SyncRequestType._(r'AlbumAssetExifsV1');
@@ -50,6 +51,7 @@ class SyncRequestType {
static const values = <SyncRequestType>[
albumsV1,
albumUsersV1,
albumUserMetadataV1,
albumToAssetsV1,
albumAssetsV1,
albumAssetExifsV1,
@@ -110,6 +112,7 @@ class SyncRequestTypeTypeTransformer {
switch (data) {
case r'AlbumsV1': return SyncRequestType.albumsV1;
case r'AlbumUsersV1': return SyncRequestType.albumUsersV1;
case r'AlbumUserMetadataV1': return SyncRequestType.albumUserMetadataV1;
case r'AlbumToAssetsV1': return SyncRequestType.albumToAssetsV1;
case r'AlbumAssetsV1': return SyncRequestType.albumAssetsV1;
case r'AlbumAssetExifsV1': return SyncRequestType.albumAssetExifsV1;
@@ -0,0 +1,100 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class UpdateAlbumUserMetadataDto {
/// Returns a new [UpdateAlbumUserMetadataDto] instance.
UpdateAlbumUserMetadataDto({
required this.isFavorite,
});
/// Favorite status
bool isFavorite;
@override
bool operator ==(Object other) => identical(this, other) || other is UpdateAlbumUserMetadataDto &&
other.isFavorite == isFavorite;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(isFavorite.hashCode);
@override
String toString() => 'UpdateAlbumUserMetadataDto[isFavorite=$isFavorite]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'isFavorite'] = this.isFavorite;
return json;
}
/// Returns a new [UpdateAlbumUserMetadataDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static UpdateAlbumUserMetadataDto? fromJson(dynamic value) {
upgradeDto(value, "UpdateAlbumUserMetadataDto");
if (value is Map) {
final json = value.cast<String, dynamic>();
return UpdateAlbumUserMetadataDto(
isFavorite: mapValueOfType<bool>(json, r'isFavorite')!,
);
}
return null;
}
static List<UpdateAlbumUserMetadataDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <UpdateAlbumUserMetadataDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = UpdateAlbumUserMetadataDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, UpdateAlbumUserMetadataDto> mapFromJson(dynamic json) {
final map = <String, UpdateAlbumUserMetadataDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = UpdateAlbumUserMetadataDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of UpdateAlbumUserMetadataDto-objects as value to a dart map
static Map<String, List<UpdateAlbumUserMetadataDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<UpdateAlbumUserMetadataDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = UpdateAlbumUserMetadataDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'isFavorite',
};
}