diff --git a/web/src/lib/components/asset-viewer/AssetViewer.svelte b/web/src/lib/components/asset-viewer/AssetViewer.svelte index f63b919633..9606077d52 100644 --- a/web/src/lib/components/asset-viewer/AssetViewer.svelte +++ b/web/src/lib/components/asset-viewer/AssetViewer.svelte @@ -499,11 +499,9 @@ {album} {person} {stack} - showSlideshow={true} preAction={handlePreAction} onAction={handleAction} {onUndoDelete} - onPlaySlideshow={() => ($slideshowState = SlideshowState.PlaySlideshow)} onClose={onClose ? () => onClose(stack?.primaryAssetId ?? asset.id) : undefined} {onRemoveFromAlbum} {playOriginalVideo} diff --git a/web/src/lib/components/asset-viewer/AssetViewerNavBar.svelte b/web/src/lib/components/asset-viewer/AssetViewerNavBar.svelte index 75504765e2..d6d90aca8a 100644 --- a/web/src/lib/components/asset-viewer/AssetViewerNavBar.svelte +++ b/web/src/lib/components/asset-viewer/AssetViewerNavBar.svelte @@ -9,7 +9,6 @@ import RatingAction from '$lib/components/asset-viewer/actions/RatingAction.svelte'; import RemoveAssetFromStack from '$lib/components/asset-viewer/actions/RemoveAssetFromStack.svelte'; import RestoreAction from '$lib/components/asset-viewer/actions/RestoreAction.svelte'; - import SetAlbumCoverAction from '$lib/components/asset-viewer/actions/SetAlbumCoverAction.svelte'; import SetFeaturedPhotoAction from '$lib/components/asset-viewer/actions/SetPersonFeaturedAction.svelte'; import SetProfilePictureAction from '$lib/components/asset-viewer/actions/SetProfilePictureAction.svelte'; import SetStackPrimaryAsset from '$lib/components/asset-viewer/actions/SetStackPrimaryAsset.svelte'; @@ -24,6 +23,7 @@ import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import { languageManager } from '$lib/managers/language-manager.svelte'; import { Route } from '$lib/route'; + import { getAlbumAssetActions } from '$lib/services/album.service'; import { getGlobalActions } from '$lib/services/app.service'; import { getAssetActions } from '$lib/services/asset.service'; import { getSharedLink, withoutIcons } from '$lib/utils'; @@ -38,15 +38,7 @@ type StackResponseDto, } from '@immich/sdk'; import { ActionButton, CommandPaletteDefaultProvider, Tooltip, type ActionItem } from '@immich/ui'; - import { - mdiArrowLeft, - mdiArrowRight, - mdiCompare, - mdiDotsVertical, - mdiImageSearch, - mdiPresentationPlay, - mdiVideoOutline, - } from '@mdi/js'; + import { mdiArrowLeft, mdiArrowRight, mdiCompare, mdiDotsVertical, mdiImageSearch, mdiVideoOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; interface Props { @@ -54,11 +46,9 @@ album?: AlbumResponseDto | null; person?: PersonResponseDto | null; stack?: StackResponseDto | null; - showSlideshow?: boolean; preAction: PreAction; onAction: OnAction; onUndoDelete?: OnUndoDelete; - onPlaySlideshow: () => void; onClose?: () => void; onRemoveFromAlbum?: (assetIds: string[]) => void; playOriginalVideo: boolean; @@ -70,11 +60,9 @@ album = null, person = null, stack = null, - showSlideshow = false, preAction, onAction, onUndoDelete = undefined, - onPlaySlideshow, onClose, onRemoveFromAlbum, playOriginalVideo = false, @@ -147,9 +135,7 @@ {#if !sharedLink} - {#if showSlideshow && !isLocked} - - {/if} + @@ -177,7 +163,8 @@ {/if} {/if} {#if album} - + {@const { SetCover } = getAlbumAssetActions($t, album, asset)} + {/if} {#if person} diff --git a/web/src/lib/components/asset-viewer/actions/SetAlbumCoverAction.svelte b/web/src/lib/components/asset-viewer/actions/SetAlbumCoverAction.svelte deleted file mode 100644 index b4d3d19fb5..0000000000 --- a/web/src/lib/components/asset-viewer/actions/SetAlbumCoverAction.svelte +++ /dev/null @@ -1,33 +0,0 @@ - - - diff --git a/web/src/lib/services/album.service.ts b/web/src/lib/services/album.service.ts index 8cd46bd13d..09796d440a 100644 --- a/web/src/lib/services/album.service.ts +++ b/web/src/lib/services/album.service.ts @@ -10,12 +10,13 @@ import { updateAlbumUser, type AlbumResponseDto, type AlbumsAddAssetsResponseDto, + type AssetResponseDto, type BulkIdResponseDto, type UpdateAlbumDto, type UserResponseDto, } from '@immich/sdk'; import { modalManager, toastManager, type ActionItem } from '@immich/ui'; -import { mdiLink, mdiPlus, mdiPlusBoxOutline, mdiShareVariantOutline, mdiUpload } from '@mdi/js'; +import { mdiImageOutline, mdiLink, mdiPlus, mdiPlusBoxOutline, mdiShareVariantOutline, mdiUpload } from '@mdi/js'; import { type MessageFormatter } from 'svelte-i18n'; import { goto } from '$app/navigation'; import { authManager } from '$lib/managers/auth-manager.svelte'; @@ -68,6 +69,16 @@ export const getAlbumActions = ($t: MessageFormatter, album: AlbumResponseDto) = return { Share, AddUsers, CreateSharedLink }; }; +export const getAlbumAssetActions = ($t: MessageFormatter, album: AlbumResponseDto, asset: AssetResponseDto) => { + const SetCover: ActionItem = { + title: $t('set_as_album_cover'), + icon: mdiImageOutline, + onAction: () => handleUpdateThumbnail(album, asset.id), + }; + + return { SetCover }; +}; + export const getAlbumAssetsActions = ($t: MessageFormatter, album: AlbumResponseDto, assets: TimelineAsset[]) => { const AddAssets: ActionItem = { title: $t('add_assets'), @@ -206,6 +217,23 @@ export const handleRemoveUserFromAlbum = async (album: AlbumResponseDto, albumUs } }; +const handleUpdateThumbnail = async (album: AlbumResponseDto, assetId: string) => { + const $t = await getFormatter(); + + try { + const response = await updateAlbumInfo({ + id: album.id, + updateAlbumDto: { + albumThumbnailAssetId: assetId, + }, + }); + eventManager.emit('AlbumUpdate', response); + toastManager.primary($t('album_cover_updated')); + } catch (error) { + handleError(error, $t('errors.unable_to_update_album_cover')); + } +}; + export const handleUpdateAlbum = async ({ id }: { id: string }, dto: UpdateAlbumDto) => { const $t = await getFormatter(); diff --git a/web/src/lib/services/asset.service.ts b/web/src/lib/services/asset.service.ts index 8804c23ec2..3e629b413f 100644 --- a/web/src/lib/services/asset.service.ts +++ b/web/src/lib/services/asset.service.ts @@ -28,6 +28,7 @@ import { mdiMotionPauseOutline, mdiMotionPlayOutline, mdiPlus, + mdiPresentationPlay, mdiShareVariantOutline, mdiTagPlusOutline, mdiTune, @@ -41,6 +42,7 @@ import { eventManager } from '$lib/managers/event-manager.svelte'; import AssetAddToAlbumModal from '$lib/modals/AssetAddToAlbumModal.svelte'; import AssetTagModal from '$lib/modals/AssetTagModal.svelte'; import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte'; +import { SlideshowState, slideshowStore } from '$lib/stores/slideshow.store'; import { getAssetMediaUrl, getSharedLink, sleep } from '$lib/utils'; import { downloadUrl } from '$lib/utils'; import { handleError } from '$lib/utils/handle-error'; @@ -140,6 +142,13 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) = }, }; + const PlaySlideshow: ActionItem = { + title: $t('slideshow'), + icon: mdiPresentationPlay, + $if: () => asset.visibility !== AssetVisibility.Locked, + onAction: () => slideshowStore.slideshowState.set(SlideshowState.PlaySlideshow), + }; + const Favorite: ActionItem = { title: $t('to_favorite'), icon: mdiHeartOutline, @@ -269,6 +278,7 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) = Unfavorite, PlayMotionPhoto, StopMotionPhoto, + PlaySlideshow, AddToAlbum, ZoomIn, ZoomOut,