From 41a06743c2b6a9e45dc2d967fccc5dca80dd1d4b Mon Sep 17 00:00:00 2001 From: CJPeckover Date: Mon, 21 Jul 2025 13:27:42 -0400 Subject: [PATCH 01/31] Multi add to album picker: - update modal for multi select - Update add-to-album and add-to-album-action to work with new array return from AlbumPickerModal - Add asset-utils.addAssetsToAlbums (incomplete) --- .../actions/add-to-album-action.svelte | 16 ++- .../asset-viewer/album-list-item.svelte | 116 +++++++++++++++++- web/src/lib/components/elements/icon.svelte | 7 ++ .../photos-page/actions/add-to-album.svelte | 16 ++- .../album-selection/album-selection-utils.ts | 4 + web/src/lib/modals/AlbumPickerModal.svelte | 60 +++++++-- web/src/lib/utils/asset-utils.ts | 11 ++ 7 files changed, 210 insertions(+), 20 deletions(-) diff --git a/web/src/lib/components/asset-viewer/actions/add-to-album-action.svelte b/web/src/lib/components/asset-viewer/actions/add-to-album-action.svelte index 8fe765ab2db08..048f5b725d32e 100644 --- a/web/src/lib/components/asset-viewer/actions/add-to-album-action.svelte +++ b/web/src/lib/components/asset-viewer/actions/add-to-album-action.svelte @@ -5,7 +5,7 @@ import { AssetAction } from '$lib/constants'; import { modalManager } from '$lib/managers/modal-manager.svelte'; import AlbumPickerModal from '$lib/modals/AlbumPickerModal.svelte'; - import { addAssetsToAlbum } from '$lib/utils/asset-utils'; + import { addAssetsToAlbum, addAssetsToAlbums } from '$lib/utils/asset-utils'; import { toTimelineAsset } from '$lib/utils/timeline-util'; import type { AssetResponseDto } from '@immich/sdk'; import { mdiImageAlbum, mdiShareVariantOutline } from '@mdi/js'; @@ -20,14 +20,20 @@ let { asset, onAction, shared = false }: Props = $props(); const onClick = async () => { - const album = await modalManager.show(AlbumPickerModal, { shared }); + const albums = await modalManager.show(AlbumPickerModal, { shared }); - if (!album) { + if (!albums || albums.length === 0) { return; } - await addAssetsToAlbum(album.id, [asset.id]); - onAction({ type: AssetAction.ADD_TO_ALBUM, asset: toTimelineAsset(asset), album }); + if (albums.length === 1) { + const album = albums[0]; + await addAssetsToAlbum(album.id, [asset.id]); + onAction({ type: AssetAction.ADD_TO_ALBUM, asset: toTimelineAsset(asset), album }); + } else { + await addAssetsToAlbums(albums.map(a=>a.id), [asset.id]); + onAction({type: AssetAction.ADD_TO_ALBUM, asset: toTimelineAsset(asset), album: albums[0]}); + } }; diff --git a/web/src/lib/components/asset-viewer/album-list-item.svelte b/web/src/lib/components/asset-viewer/album-list-item.svelte index 7751bd09d822a..0f64535f56312 100644 --- a/web/src/lib/components/asset-viewer/album-list-item.svelte +++ b/web/src/lib/components/asset-viewer/album-list-item.svelte @@ -1,19 +1,32 @@ + + From 383da33123602bbe1d880c8cc601c89de36cdb75 Mon Sep 17 00:00:00 2001 From: CJPeckover Date: Sun, 27 Jul 2025 01:21:58 -0400 Subject: [PATCH 23/31] open-api --- mobile/openapi/README.md | 1 + mobile/openapi/lib/api.dart | 1 + mobile/openapi/lib/api_client.dart | 2 ++ mobile/openapi/lib/api_helper.dart | 3 +++ 4 files changed, 7 insertions(+) diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index 2ed572ca84fc8..cc5b3b188d5ac 100644 --- a/mobile/openapi/README.md +++ b/mobile/openapi/README.md @@ -561,6 +561,7 @@ Class | Method | HTTP request | Description - [UserAdminUpdateDto](doc//UserAdminUpdateDto.md) - [UserAvatarColor](doc//UserAvatarColor.md) - [UserLicense](doc//UserLicense.md) + - [UserMetadataKey](doc//UserMetadataKey.md) - [UserPreferencesResponseDto](doc//UserPreferencesResponseDto.md) - [UserPreferencesUpdateDto](doc//UserPreferencesUpdateDto.md) - [UserResponseDto](doc//UserResponseDto.md) diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart index 0cd4cbab6d35a..305479e87e373 100644 --- a/mobile/openapi/lib/api.dart +++ b/mobile/openapi/lib/api.dart @@ -341,6 +341,7 @@ part 'model/user_admin_response_dto.dart'; part 'model/user_admin_update_dto.dart'; part 'model/user_avatar_color.dart'; part 'model/user_license.dart'; +part 'model/user_metadata_key.dart'; part 'model/user_preferences_response_dto.dart'; part 'model/user_preferences_update_dto.dart'; part 'model/user_response_dto.dart'; diff --git a/mobile/openapi/lib/api_client.dart b/mobile/openapi/lib/api_client.dart index 9683569dfbf1a..3f31d4ed90f6d 100644 --- a/mobile/openapi/lib/api_client.dart +++ b/mobile/openapi/lib/api_client.dart @@ -738,6 +738,8 @@ class ApiClient { return UserAvatarColorTypeTransformer().decode(value); case 'UserLicense': return UserLicense.fromJson(value); + case 'UserMetadataKey': + return UserMetadataKeyTypeTransformer().decode(value); case 'UserPreferencesResponseDto': return UserPreferencesResponseDto.fromJson(value); case 'UserPreferencesUpdateDto': diff --git a/mobile/openapi/lib/api_helper.dart b/mobile/openapi/lib/api_helper.dart index fa32d284a1aa3..4adb62768b889 100644 --- a/mobile/openapi/lib/api_helper.dart +++ b/mobile/openapi/lib/api_helper.dart @@ -154,6 +154,9 @@ String parameterToString(dynamic value) { if (value is UserAvatarColor) { return UserAvatarColorTypeTransformer().encode(value).toString(); } + if (value is UserMetadataKey) { + return UserMetadataKeyTypeTransformer().encode(value).toString(); + } if (value is UserStatus) { return UserStatusTypeTransformer().encode(value).toString(); } From dff2db6741b105924f8f92a74af2badc2c93e47d Mon Sep 17 00:00:00 2001 From: CJPeckover Date: Wed, 30 Jul 2025 00:29:11 -0400 Subject: [PATCH 24/31] - Cleanup multi-select button to match Thumbnail --- .../asset-viewer/album-list-item.svelte | 39 ++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/web/src/lib/components/asset-viewer/album-list-item.svelte b/web/src/lib/components/asset-viewer/album-list-item.svelte index 35db4322555ca..882d6891a4114 100644 --- a/web/src/lib/components/asset-viewer/album-list-item.svelte +++ b/web/src/lib/components/asset-viewer/album-list-item.svelte @@ -5,6 +5,7 @@ import { normalizeSearchString } from '$lib/utils/string-utils.js'; import { type AlbumResponseDto } from '@immich/sdk'; import { IconButton } from '@immich/ui'; + import Icon from '$lib/components/elements/icon.svelte'; import { mdiCheckCircle } from '@mdi/js'; import { t } from 'svelte-i18n'; import type { Action } from 'svelte/action'; @@ -119,28 +120,22 @@
{#if mouseOver || multiSelected}
- {#if multiSelected} - - {:else} - - {/if} +
{/if} -
- {/if} +
+ + {#if mouseOver || multiSelected} + + {/if}
diff --git a/web/src/lib/components/shared-components/album-selection/new-album-list-item.svelte b/web/src/lib/components/shared-components/album-selection/new-album-list-item.svelte index d8be0e2a30d13..a1adc3ef4f9c0 100644 --- a/web/src/lib/components/shared-components/album-selection/new-album-list-item.svelte +++ b/web/src/lib/components/shared-components/album-selection/new-album-list-item.svelte @@ -1,9 +1,9 @@