fix(web): let slideshow videos play (#19601) (#24914)

Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>
This commit is contained in:
Keanu Czirjak 2025-12-29 18:03:55 +00:00 committed by GitHub
parent 369a30e227
commit e87bfa548a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 52 additions and 36 deletions

View file

@ -451,6 +451,7 @@
<div class="absolute w-full flex"> <div class="absolute w-full flex">
<SlideshowBar <SlideshowBar
{isFullScreen} {isFullScreen}
assetType={previewStackedAsset?.type ?? asset.type}
onSetToFullScreen={() => assetViewerHtmlElement?.requestFullscreen?.()} onSetToFullScreen={() => assetViewerHtmlElement?.requestFullscreen?.()}
onPrevious={() => navigateAsset('previous')} onPrevious={() => navigateAsset('previous')}
onNext={() => navigateAsset('next')} onNext={() => navigateAsset('next')}

View file

@ -1,9 +1,10 @@
<script lang="ts"> <script lang="ts">
import { shortcuts } from '$lib/actions/shortcut'; import { shortcuts, type ShortcutOptions } from '$lib/actions/shortcut';
import ProgressBar from '$lib/components/shared-components/progress-bar/progress-bar.svelte'; import ProgressBar from '$lib/components/shared-components/progress-bar/progress-bar.svelte';
import { ProgressBarStatus } from '$lib/constants'; import { ProgressBarStatus } from '$lib/constants';
import SlideshowSettingsModal from '$lib/modals/SlideshowSettingsModal.svelte'; import SlideshowSettingsModal from '$lib/modals/SlideshowSettingsModal.svelte';
import { SlideshowNavigation, slideshowStore } from '$lib/stores/slideshow.store'; import { SlideshowNavigation, slideshowStore } from '$lib/stores/slideshow.store';
import { AssetTypeEnum } from '@immich/sdk';
import { IconButton, modalManager } from '@immich/ui'; import { IconButton, modalManager } from '@immich/ui';
import { mdiChevronLeft, mdiChevronRight, mdiClose, mdiCog, mdiFullscreen, mdiPause, mdiPlay } from '@mdi/js'; import { mdiChevronLeft, mdiChevronRight, mdiClose, mdiCog, mdiFullscreen, mdiPause, mdiPlay } from '@mdi/js';
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
@ -13,6 +14,7 @@
interface Props { interface Props {
isFullScreen: boolean; isFullScreen: boolean;
assetType: AssetTypeEnum;
onNext?: () => void; onNext?: () => void;
onPrevious?: () => void; onPrevious?: () => void;
onClose?: () => void; onClose?: () => void;
@ -21,6 +23,7 @@
let { let {
isFullScreen, isFullScreen,
assetType,
onNext = () => {}, onNext = () => {},
onPrevious = () => {}, onPrevious = () => {},
onClose = () => {}, onClose = () => {},
@ -35,6 +38,7 @@
let showControls = $state(true); let showControls = $state(true);
let timer: NodeJS.Timeout; let timer: NodeJS.Timeout;
let isOverControls = $state(false); let isOverControls = $state(false);
const isVideoSlide = $derived(assetType === AssetTypeEnum.Video);
let unsubscribeRestart: () => void; let unsubscribeRestart: () => void;
let unsubscribeStop: () => void; let unsubscribeStop: () => void;
@ -132,15 +136,17 @@
{ onswipedown: showControlBar }, { onswipedown: showControlBar },
true, true,
); );
</script>
<svelte:document const shortcutBindings = $derived.by((): ShortcutOptions[] => {
onmousemove={showControlBar} const bindings: ShortcutOptions[] = [
use:shortcuts={[
{ shortcut: { key: 'Escape' }, onShortcut: onClose }, { shortcut: { key: 'Escape' }, onShortcut: onClose },
{ shortcut: { key: 'ArrowLeft' }, onShortcut: onPrevious }, { shortcut: { key: 'ArrowLeft' }, onShortcut: onPrevious },
{ shortcut: { key: 'ArrowRight' }, onShortcut: onNext }, { shortcut: { key: 'ArrowRight' }, onShortcut: onNext },
{ ];
// For videos, allow the native HTML5 element to handle space for play/pause
if (!isVideoSlide) {
bindings.push({
shortcut: { key: ' ' }, shortcut: { key: ' ' },
onShortcut: () => { onShortcut: () => {
if (progressBarStatus === ProgressBarStatus.Paused) { if (progressBarStatus === ProgressBarStatus.Paused) {
@ -150,9 +156,14 @@
} }
}, },
preventDefault: true, preventDefault: true,
}, });
]} }
/>
return bindings;
});
</script>
<svelte:document onmousemove={showControlBar} use:shortcuts={shortcutBindings} />
{/* @ts-expect-error https://github.com/Rezi/svelte-gestures/issues/38#issuecomment-3315953573 */ null} {/* @ts-expect-error https://github.com/Rezi/svelte-gestures/issues/38#issuecomment-3315953573 */ null}
<svelte:body {@attach swipe} {onswipe} {onswipedown} /> <svelte:body {@attach swipe} {onswipe} {onswipedown} />
@ -174,6 +185,7 @@
aria-label={$t('exit_slideshow')} aria-label={$t('exit_slideshow')}
/> />
{#if !isVideoSlide}
<IconButton <IconButton
variant="ghost" variant="ghost"
shape="round" shape="round"
@ -182,6 +194,7 @@
onclick={() => (progressBarStatus === ProgressBarStatus.Paused ? progressBar?.play() : progressBar?.pause())} onclick={() => (progressBarStatus === ProgressBarStatus.Paused ? progressBar?.play() : progressBar?.pause())}
aria-label={progressBarStatus === ProgressBarStatus.Paused ? $t('play') : $t('pause')} aria-label={progressBarStatus === ProgressBarStatus.Paused ? $t('play') : $t('pause')}
/> />
{/if}
<IconButton <IconButton
variant="ghost" variant="ghost"
shape="round" shape="round"
@ -219,6 +232,7 @@
</div> </div>
{/if} {/if}
{#if !isVideoSlide}
<ProgressBar <ProgressBar
autoplay={$slideshowAutoplay} autoplay={$slideshowAutoplay}
hidden={!$showProgressBar} hidden={!$showProgressBar}
@ -227,3 +241,4 @@
bind:status={progressBarStatus} bind:status={progressBarStatus}
onDone={handleDone} onDone={handleDone}
/> />
{/if}