diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte index 00898e46e2..42c371f593 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte @@ -108,6 +108,10 @@ let sharedLink = getSharedLink(); let fullscreenElement = $state(); + let slideShowPlaying = $derived($slideshowState === SlideshowState.PlaySlideshow); + let slideShowAscending = $derived($slideshowNavigation === SlideshowNavigation.AscendingOrder); + let slideShowShuffle = $derived($slideshowNavigation === SlideshowNavigation.Shuffle); + let playOriginalVideo = $state($alwaysLoadOriginalVideo); let slideshowStartAssetId = $state(); @@ -141,12 +145,6 @@ } }; - const onAssetUpdate = (updatedAsset: AssetResponseDto) => { - if (asset.id === updatedAsset.id) { - cursor = { ...cursor, current: updatedAsset }; - } - }; - let detailPanelTransitionName = $state(); let navigationBarTransitionName = $state(); let previousButtonTransitionName = $state(); @@ -230,68 +228,65 @@ assetViewerManager.closeEditor(); }; + const completeNavigation = async (order: 'previous' | 'next') => { + preloadManager.cancelBeforeNavigation(order); + + let hasNext: boolean; + + if (slideShowPlaying && slideShowShuffle) { + let next = order === 'previous' ? slideshowHistory.previous() : slideshowHistory.next(); + if (!next) { + const asset = await onRandom?.(); + if (asset) { + slideshowHistory.queue(asset); + next = true; + } + } + hasNext = next; + } else { + const target = order === 'previous' ? previousAsset : nextAsset; + hasNext = await navigateToAsset(target); + } + + if (!slideShowPlaying) { + return; + } + + if (hasNext) { + $restartSlideshowProgress = true; + return; + } + + if ($slideshowRepeat && slideshowStartAssetId) { + await assetViewerManager.setAssetId(slideshowStartAssetId); + $restartSlideshowProgress = true; + return; + } + + await handleStopSlideshow(); + }; + const tracker = new InvocationTracker(); let navigating = $state(false); const navigateAsset = (order?: 'previous' | 'next') => { if (!order) { - if ($slideshowState === SlideshowState.PlaySlideshow) { - order = $slideshowNavigation === SlideshowNavigation.AscendingOrder ? 'previous' : 'next'; + if (slideShowPlaying) { + order = slideShowAscending ? 'previous' : 'next'; } else { return; } } - preloadManager.cancelBeforeNavigation(order); - if (tracker.isActive()) { return; } navigating = true; - const navigation = tracker.invoke(async () => { - const isShuffle = - $slideshowState === SlideshowState.PlaySlideshow && $slideshowNavigation === SlideshowNavigation.Shuffle; - - let hasNext: boolean; - - if (isShuffle) { - hasNext = order === 'previous' ? slideshowHistory.previous() : slideshowHistory.next(); - if (!hasNext) { - const asset = await onRandom?.(); - if (asset) { - slideshowHistory.queue(asset); - hasNext = true; - } - } - } else { - hasNext = - order === 'previous' ? await navigateToAsset(cursor.previousAsset) : await navigateToAsset(cursor.nextAsset); - } - - if ($slideshowState !== SlideshowState.PlaySlideshow) { - return; - } - - if (hasNext) { - $restartSlideshowProgress = true; - return; - } - - if ($slideshowRepeat && slideshowStartAssetId) { - await assetViewerManager.setAssetId(slideshowStartAssetId); - $restartSlideshowProgress = true; - return; - } - - await handleStopSlideshow(); - }, $t('error_while_navigating')); - void navigation.finally(() => (navigating = false)); + void tracker + .invoke(() => completeNavigation(order), $t('error_while_navigating')) + .finally(() => (navigating = false)); }; - /** - * Slide show mode - */ - let assetViewerHtmlElement = $state(); const slideshowHistory = new SlideshowHistory((asset) => { @@ -316,9 +311,11 @@ const handleStopSlideshow = async () => { try { - if (document.fullscreenElement) { - await document.exitFullscreen(); + if (!document.fullscreenElement) { + return; } + document.body.style.cursor = ''; + await document.exitFullscreen(); } catch (error) { handleError(error, $t('errors.unable_to_exit_fullscreen')); } finally { @@ -421,14 +418,21 @@ return; } if (lastCursor) { + previewStackedAsset = undefined; + ocrManager.showOverlay = false; preloadManager.updateAfterNavigation(lastCursor, cursor, sharedLink); - } - if (!lastCursor) { + } else { preloadManager.initializePreloads(cursor, sharedLink); } lastCursor = cursor; }); + const onAssetUpdate = (update: AssetResponseDto) => { + if (asset.id === update.id) { + cursor = { ...cursor, current: update }; + } + }; + const viewerKind = $derived.by(() => { if (previewStackedAsset) { return previewStackedAsset.type === AssetTypeEnum.Image ? 'PhotoViewer' : 'StackVideoViewer'; @@ -504,7 +508,6 @@ use:focusTrap bind:this={assetViewerHtmlElement} > - {#if $slideshowState === SlideshowState.None && !assetViewerManager.isShowEditor}
{/if} -
{#if viewerKind === 'StackVideoViewer'} {/if} - {#if stack && withStacked && !assetViewerManager.isShowEditor} + {#if stack && withStacked && $slideshowState === SlideshowState.None && !assetViewerManager.isShowEditor} {@const stackedAssets = stack.assets}
diff --git a/web/src/lib/components/asset-viewer/photo-viewer.svelte b/web/src/lib/components/asset-viewer/photo-viewer.svelte index 2ff03b1414..6ff8fb2baf 100644 --- a/web/src/lib/components/asset-viewer/photo-viewer.svelte +++ b/web/src/lib/components/asset-viewer/photo-viewer.svelte @@ -35,6 +35,9 @@ let { cursor, element = $bindable(), sharedLink, onError, onSwipe }: Props = $props(); const { slideshowState, slideshowLook } = slideshowStore; + const objectFit = $derived( + $slideshowState !== SlideshowState.None && $slideshowLook === SlideshowLook.Cover ? 'cover' : 'contain', + ); const asset = $derived(cursor.current); let visibleImageReady: boolean = $state(false); @@ -226,7 +229,7 @@ {asset} {sharedLink} {container} - objectFit={$slideshowState !== SlideshowState.None && $slideshowLook === SlideshowLook.Cover ? 'cover' : 'contain'} + {objectFit} {onUrlChange} onImageReady={() => { visibleImageReady = true; diff --git a/web/src/lib/components/asset-viewer/video-native-viewer.svelte b/web/src/lib/components/asset-viewer/video-native-viewer.svelte index 971de4051f..5a7ff6dbc4 100644 --- a/web/src/lib/components/asset-viewer/video-native-viewer.svelte +++ b/web/src/lib/components/asset-viewer/video-native-viewer.svelte @@ -58,7 +58,6 @@ }); $effect(() => { - // reactive on `assetFileUrl` changes if (assetFileUrl) { hasFocused = false; videoPlayer?.load(); diff --git a/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte b/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte index e3808506bc..d97fc88b0e 100644 --- a/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte +++ b/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte @@ -9,8 +9,8 @@ import SearchBar from '$lib/components/shared-components/search-bar/search-bar.svelte'; import SkipLink from '$lib/elements/SkipLink.svelte'; import { authManager } from '$lib/managers/auth-manager.svelte'; - import { viewTransitionManager } from '$lib/managers/ViewTransitionManager.svelte'; import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; + import { viewTransitionManager } from '$lib/managers/ViewTransitionManager.svelte'; import { Route } from '$lib/route'; import { getGlobalActions } from '$lib/services/app.service'; import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte'; @@ -37,16 +37,11 @@ let shouldShowNotificationPanel = $state(false); let innerWidth: number = $state(0); const hasUnreadNotifications = $derived(notificationManager.notifications.length > 0); - - onMount(async () => { - try { - await notificationManager.refresh(); - } catch (error) { - console.error('Failed to load notifications on mount', error); - } - }); + const { Cast } = $derived(getGlobalActions($t)); onMount(() => { + void notificationManager.refresh().catch((error) => console.error('Failed to load notifications on mount', error)); + return viewTransitionManager.on({ PrepareOldSnapshot: (types) => { if (types.includes('viewer')) { @@ -61,8 +56,6 @@ }, }); }); - - const { Cast } = $derived(getGlobalActions($t));