diff --git a/e2e/src/web/specs/photo-viewer.e2e-spec.ts b/e2e/src/web/specs/photo-viewer.e2e-spec.ts index c8a9b42b2a..3f9bb4237a 100644 --- a/e2e/src/web/specs/photo-viewer.e2e-spec.ts +++ b/e2e/src/web/specs/photo-viewer.e2e-spec.ts @@ -3,7 +3,7 @@ import { Page, expect, test } from '@playwright/test'; import { utils } from 'src/utils'; function imageLocator(page: Page) { - return page.getByAltText('Image taken on').locator('visible=true'); + return page.getByAltText('Image taken').locator('visible=true'); } test.describe('Photo Viewer', () => { let admin: LoginResponseDto; diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte index 19b9bd3555..471efab967 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte @@ -10,6 +10,7 @@ import { activityManager } from '$lib/managers/activity-manager.svelte'; import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { authManager } from '$lib/managers/auth-manager.svelte'; + import { eventManager } from '$lib/managers/event-manager.svelte'; import { preloadManager } from '$lib/managers/PreloadManager.svelte'; import { closeEditorCofirm } from '$lib/stores/asset-editor.store'; import { assetViewingStore } from '$lib/stores/asset-viewing.store'; @@ -52,8 +53,6 @@ import SlideshowBar from './slideshow-bar.svelte'; import VideoViewer from './video-wrapper-viewer.svelte'; - type HasAsset = boolean; - export type AssetCursor = { current: AssetResponseDto; nextAsset?: AssetResponseDto; @@ -71,9 +70,8 @@ onAction?: OnAction; onUndoDelete?: OnUndoDelete; onClose?: (asset: AssetResponseDto) => void; - onNext: () => Promise; - onPrevious: () => Promise; - onRandom: () => Promise<{ id: string } | undefined>; + onNavigateToAsset?: (asset: AssetResponseDto | undefined | null) => Promise; + onRandom?: () => Promise<{ id: string } | undefined>; copyImage?: () => Promise; } @@ -88,8 +86,7 @@ onAction, onUndoDelete, onClose, - onNext, - onPrevious, + onNavigateToAsset, onRandom, copyImage = $bindable(), }: Props = $props(); @@ -106,6 +103,8 @@ const stackSelectedThumbnailSize = 65; let asset = $derived(cursor.current); + let nextAsset = $derived(cursor.nextAsset); + let previousAsset = $derived(cursor.previousAsset); let appearsInAlbums: AlbumResponseDto[] = $state([]); let sharedLink = getSharedLink(); let previewStackedAsset: AssetResponseDto | undefined = $state(); @@ -229,14 +228,19 @@ if ($slideshowState === SlideshowState.PlaySlideshow && $slideshowNavigation === SlideshowNavigation.Shuffle) { hasNext = order === 'previous' ? slideshowHistory.previous() : slideshowHistory.next(); if (!hasNext) { - const asset = await onRandom(); + const asset = await onRandom?.(); if (asset) { slideshowHistory.queue(asset); hasNext = true; } } + } else if (onNavigateToAsset) { + hasNext = + order === 'previous' + ? await onNavigateToAsset(cursor.previousAsset) + : await onNavigateToAsset(cursor.nextAsset); } else { - hasNext = order === 'previous' ? await onPrevious() : await onNext(); + hasNext = false; } if ($slideshowState === SlideshowState.PlaySlideshow) { @@ -383,7 +387,6 @@ await ocrManager.getAssetOcr(asset.id); } }; - $effect(() => { // eslint-disable-next-line @typescript-eslint/no-unused-expressions asset; @@ -391,6 +394,34 @@ preloadManager.preload(cursor.nextAsset); preloadManager.preload(cursor.previousAsset); }); + + $effect(() => { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions + asset.id; + if (viewerKind !== 'PhotoViewer' && viewerKind !== 'ImagePanaramaViewer') { + eventManager.emit('AssetViewerFree'); + } + }); + + const viewerKind = $derived.by(() => { + if (previewStackedAsset) { + return asset.type === AssetTypeEnum.Image ? 'StackPhotoViewer' : 'StackVideoViewer'; + } + if (asset.type === AssetTypeEnum.Image) { + if (assetViewerManager.isPlayingMotionPhoto && asset.livePhotoVideoId) { + return 'LiveVideoViewer'; + } else if ( + asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR || + (asset.originalPath && asset.originalPath.toLowerCase().endsWith('.insp')) + ) { + return 'ImagePanaramaViewer'; + } else if (isShowEditor && selectedEditType === 'crop') { + return 'CropArea'; + } + return 'PhotoViewer'; + } + return 'VideoViewer'; + }); @@ -427,7 +458,7 @@ {/if} {#if $slideshowState != SlideshowState.None} -
+
{/if} - {#if $slideshowState === SlideshowState.None && showNavigation && !isShowEditor} -
+ {#if $slideshowState === SlideshowState.None && showNavigation && !isShowEditor && previousAsset} +
navigateAsset('previous')} />
{/if}
- {#if previewStackedAsset} - {#key previewStackedAsset.id} - {#if previewStackedAsset.type === AssetTypeEnum.Image} - navigateAsset('previous')} - onNextAsset={() => navigateAsset('next')} - haveFadeTransition={false} - {sharedLink} - /> - {:else} - navigateAsset('previous')} - onNextAsset={() => navigateAsset('next')} - onClose={closeViewer} - onVideoEnded={() => navigateAsset()} - onVideoStarted={handleVideoStarted} - {playOriginalVideo} - /> - {/if} - {/key} - {:else} - {#key asset.id} - {#if asset.type === AssetTypeEnum.Image} - {#if assetViewerManager.isPlayingMotionPhoto && asset.livePhotoVideoId} - navigateAsset('previous')} - onNextAsset={() => navigateAsset('next')} - onVideoEnded={() => (assetViewerManager.isPlayingMotionPhoto = false)} - {playOriginalVideo} - /> - {:else if asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR || (asset.originalPath && asset.originalPath - .toLowerCase() - .endsWith('.insp'))} - - {:else if isShowEditor && selectedEditType === 'crop'} - - {:else} - navigateAsset('previous')} - onNextAsset={() => navigateAsset('next')} - {sharedLink} - haveFadeTransition={$slideshowState !== SlideshowState.None && $slideshowTransition} - /> - {/if} - {:else} - navigateAsset('previous')} - onNextAsset={() => navigateAsset('next')} - onClose={closeViewer} - onVideoEnded={() => navigateAsset()} - onVideoStarted={handleVideoStarted} - {playOriginalVideo} - /> - {/if} + {#if viewerKind === 'StackPhotoViewer'} + navigateAsset('previous')} + onNextAsset={() => navigateAsset('next')} + haveFadeTransition={false} + {sharedLink} + /> + {:else if viewerKind === 'StackVideoViewer'} + navigateAsset('previous')} + onNextAsset={() => navigateAsset('next')} + onClose={closeViewer} + onVideoEnded={() => navigateAsset()} + onVideoStarted={handleVideoStarted} + {playOriginalVideo} + /> + {:else if viewerKind === 'LiveVideoViewer'} + navigateAsset('previous')} + onNextAsset={() => navigateAsset('next')} + onVideoEnded={() => (assetViewerManager.isPlayingMotionPhoto = false)} + {playOriginalVideo} + /> + {:else if viewerKind === 'ImagePanaramaViewer'} + + {:else if viewerKind === 'CropArea'} + + {:else if viewerKind === 'PhotoViewer'} + navigateAsset('previous')} + onNextAsset={() => navigateAsset('next')} + {sharedLink} + haveFadeTransition={$slideshowState !== SlideshowState.None && $slideshowTransition} + onFree={() => eventManager.emit('AssetViewerFree')} + /> + {:else if viewerKind === 'VideoViewer'} + navigateAsset('previous')} + onNextAsset={() => navigateAsset('next')} + onClose={closeViewer} + onVideoEnded={() => navigateAsset()} + onVideoStarted={handleVideoStarted} + {playOriginalVideo} + /> + {/if} - {#if $slideshowState === SlideshowState.None && isShared && ((album && album.isActivityEnabled) || activityManager.commentCount > 0) && !activityManager.isLoading} -
- -
- {/if} + {#if $slideshowState === SlideshowState.None && isShared && ((album && album.isActivityEnabled) || activityManager.commentCount > 0) && !activityManager.isLoading} +
+ +
+ {/if} - {#if $slideshowState === SlideshowState.None && asset.type === AssetTypeEnum.Image && !isShowEditor && ocrManager.hasOcrData} -
- -
- {/if} - {/key} + {#if $slideshowState === SlideshowState.None && asset.type === AssetTypeEnum.Image && !isShowEditor && ocrManager.hasOcrData} +
+ +
{/if}
- {#if $slideshowState === SlideshowState.None && showNavigation && !isShowEditor} + {#if $slideshowState === SlideshowState.None && showNavigation && !isShowEditor && nextAsset}
navigateAsset('next')} />
diff --git a/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte b/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte index 2e5d0d85c5..399c4fb7de 100644 --- a/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte +++ b/web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte @@ -1,5 +1,6 @@