update memory viewer

This commit is contained in:
Mees Frensel
2026-03-16 15:46:07 +01:00
parent d1e0552b9d
commit d608fde175
4 changed files with 59 additions and 36 deletions

View File

@@ -2419,6 +2419,7 @@
"workflows": "Workflows", "workflows": "Workflows",
"workflows_help_text": "Workflows automate actions on your assets based on triggers and filters", "workflows_help_text": "Workflows automate actions on your assets based on triggers and filters",
"wrong_pin_code": "Wrong PIN code", "wrong_pin_code": "Wrong PIN code",
"x_of_total": "{x}/{total}",
"year": "Year", "year": "Year",
"years_ago": "{years, plural, one {# year} other {# years}} ago", "years_ago": "{years, plural, one {# year} other {# years}} ago",
"yes": "Yes", "yes": "Yes",

View File

@@ -188,17 +188,19 @@
src={assetFileUrl} src={assetFileUrl}
></video> ></video>
<media-settings-menu hidden anchor="auto" class="border-light-300 rounded-xl border shadow-sm w-3xs"> {#if extendedControls}
<Icon slot="checked-indicator" icon={mdiCheck} class="m-2" /> <media-settings-menu hidden anchor="auto" class="border-light-300 rounded-xl border shadow-sm w-3xs">
<media-settings-menu-item class="rounded-lg p-1 ps-2 mx-1"> <Icon slot="checked-indicator" icon={mdiCheck} class="m-2" />
{$t('playback_speed')} <media-settings-menu-item class="rounded-lg p-1 ps-2 mx-1">
<Icon slot="suffix" icon={mdiChevronRight} class="m-2" /> {$t('playback_speed')}
<media-playback-rate-menu slot="submenu" hidden rates="0.5 1 1.5 2"> <Icon slot="suffix" icon={mdiChevronRight} class="m-2" />
<Icon slot="back-icon" icon={mdiChevronLeft} class="m-2" /> <media-playback-rate-menu slot="submenu" hidden rates="0.5 1 1.5 2">
<span slot="title">{$t('playback_speed')}</span> <Icon slot="back-icon" icon={mdiChevronLeft} class="m-2" />
</media-playback-rate-menu> <span slot="title">{$t('playback_speed')}</span>
</media-settings-menu-item> </media-playback-rate-menu>
</media-settings-menu> </media-settings-menu-item>
</media-settings-menu>
{/if}
<div class="flex flex-col justify-end w-full h-32 px-4 bg-linear-to-b to-black/80"> <div class="flex flex-col justify-end w-full h-32 px-4 bg-linear-to-b to-black/80">
<media-control-bar part="bottom" class="flex w-full h-10 gap-2"> <media-control-bar part="bottom" class="flex w-full h-10 gap-2">

View File

@@ -25,7 +25,7 @@
{#if showVideo} {#if showVideo}
<div class="h-full w-full bg-pink-9000" transition:fade={{ duration: assetViewerFadeDuration }}> <div class="h-full w-full bg-pink-9000" transition:fade={{ duration: assetViewerFadeDuration }}>
<media-controller nohotkeys class="h-full w-full rounded-2xl object-contain transition-all"> <media-controller id="memory-video" nohotkeys class="h-full w-full rounded-2xl object-contain transition-all">
<!-- svelte-ignore a11y_media_has_caption --> <!-- svelte-ignore a11y_media_has_caption -->
<video <video
bind:this={videoPlayer} bind:this={videoPlayer}

View File

@@ -32,7 +32,7 @@
import { cancelMultiselect } from '$lib/utils/asset-utils'; import { cancelMultiselect } from '$lib/utils/asset-utils';
import { fromISODateTimeUTC, toTimelineAsset } from '$lib/utils/timeline-util'; import { fromISODateTimeUTC, toTimelineAsset } from '$lib/utils/timeline-util';
import { AssetMediaSize, AssetTypeEnum, getAssetInfo } from '@immich/sdk'; import { AssetMediaSize, AssetTypeEnum, getAssetInfo } from '@immich/sdk';
import { ActionButton, IconButton, toastManager } from '@immich/ui'; import { ActionButton, IconButton, Text, toastManager } from '@immich/ui';
import { import {
mdiCardsOutline, mdiCardsOutline,
mdiChevronDown, mdiChevronDown,
@@ -52,6 +52,7 @@
} from '@mdi/js'; } from '@mdi/js';
import type { NavigationTarget, Page } from '@sveltejs/kit'; import type { NavigationTarget, Page } from '@sveltejs/kit';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import 'media-chrome/media-mute-button';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
import type { Attachment } from 'svelte/attachments'; import type { Attachment } from 'svelte/attachments';
import { Tween } from 'svelte/motion'; import { Tween } from 'svelte/motion';
@@ -389,42 +390,62 @@
{/if} {/if}
{/snippet} {/snippet}
<div class="flex place-content-center place-items-center gap-2 overflow-hidden"> <div class="flex place-content-center place-items-center gap-2 dark">
<div class="w-12.5 dark"> <IconButton
<IconButton shape="round"
shape="round" variant="ghost"
variant="ghost" color="secondary"
color="secondary" aria-label={paused ? $t('play_memories') : $t('pause_memories')}
aria-label={paused ? $t('play_memories') : $t('pause_memories')} icon={paused ? mdiPlay : mdiPause}
icon={paused ? mdiPlay : mdiPause} onclick={() => handlePromiseError(handleAction('PlayPauseButtonClick', paused ? 'play' : 'pause'))}
onclick={() => handlePromiseError(handleAction('PlayPauseButtonClick', paused ? 'play' : 'pause'))} />
/>
</div>
{#each current.memory.assets as asset, index (asset.id)} {#each current.memory.assets as asset, index (asset.id)}
<a class="relative w-full py-2" href={asHref(asset)} aria-label={$t('view')}> <a class="relative grow py-2" href={asHref(asset)} aria-label={$t('view')}>
<span class="absolute start-0 h-0.5 w-full bg-gray-500"></span> <span class="absolute start-0 h-0.5 w-full bg-gray-500"></span>
<span class="absolute start-0 h-0.5 bg-white" style:width={`${toProgressPercentage(index)}%`}></span> <span class="absolute start-0 h-0.5 bg-white" style:width={`${toProgressPercentage(index)}%`}></span>
</a> </a>
{/each} {/each}
<div> <Text size="small">
<p class="text-small"> {$t('x_of_total', {
{(current.assetIndex + 1).toLocaleString($locale)}/{current.memory.assets.length.toLocaleString($locale)} values: {
</p> x: (current.assetIndex + 1).toLocaleString($locale),
</div> total: current.memory.assets.length.toLocaleString($locale),
},
})}
</Text>
{#if currentTimelineAssets.some((asset) => asset.type === AssetTypeEnum.Video)} {#if currentTimelineAssets.some((asset) => asset.type === AssetTypeEnum.Video)}
<div class="w-12.5 dark"> <media-mute-button
mediacontroller={videoPlayer ? 'memory-video' : ''}
disabled={!videoPlayer}
class="bg-transparent rounded-full focus-visible:outline-2 outline-offset-2 outline-dark"
style="--media-focus-box-shadow: none;"
>
<IconButton <IconButton
slot="off"
disabled={!videoPlayer}
tabindex={-1}
shape="round" shape="round"
variant="ghost" variant="ghost"
color="secondary" color="secondary"
aria-label={videoPlayer?.muted ? $t('unmute_memories') : $t('mute_memories')} aria-label={$t('unmute_memories')}
icon={videoPlayer?.muted ? mdiVolumeOff : mdiVolumeHigh} icon={mdiVolumeOff}
onclick={() => (videoPlayer ? (videoPlayer.muted = !videoPlayer.muted) : {})} onclick={() => {}}
/> />
</div> <IconButton
slot="high"
disabled={!videoPlayer}
tabindex={-1}
shape="round"
variant="ghost"
color="secondary"
aria-label={$t('mute_memories')}
icon={mdiVolumeHigh}
onclick={() => {}}
/>
</media-mute-button>
{/if} {/if}
</div> </div>
</ControlAppBar> </ControlAppBar>
@@ -515,7 +536,6 @@
color="secondary" color="secondary"
aria-label={isSaved ? $t('unfavorite') : $t('favorite')} aria-label={isSaved ? $t('unfavorite') : $t('favorite')}
onclick={() => handleSaveMemory()} onclick={() => handleSaveMemory()}
class="w-12 h-12"
/> />
<!-- <IconButton <!-- <IconButton
icon={mdiShareVariantOutline} icon={mdiShareVariantOutline}