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
2 changed files with 52 additions and 36 deletions

View File

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

View File

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