fix(web): wait for image to load before playing memories. (#19757)
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Docker / pre-job (push) Waiting to run
Docker / Re-Tag ML () (push) Blocked by required conditions
Docker / Re-Tag ML (-armnn) (push) Blocked by required conditions
Docker / Re-Tag ML (-cuda) (push) Blocked by required conditions
Docker / Re-Tag ML (-openvino) (push) Blocked by required conditions
Docker / Re-Tag ML (-rknn) (push) Blocked by required conditions
Docker / Re-Tag ML (-rocm) (push) Blocked by required conditions
Docker / Re-Tag Server () (push) Blocked by required conditions
Docker / Build and Push ML (armnn, linux/arm64, -armnn) (push) Blocked by required conditions
Docker / Build and Push ML (cpu, ) (push) Blocked by required conditions
Docker / Build and Push ML (cuda, linux/amd64, -cuda) (push) Blocked by required conditions
Docker / Build and Push ML (openvino, linux/amd64, -openvino) (push) Blocked by required conditions
Docker / Build and Push ML (rknn, linux/arm64, -rknn) (push) Blocked by required conditions
Docker / Build and Push ML (rocm, linux/amd64, {"linux/amd64": "mich"}, -rocm) (push) Blocked by required conditions
Docker / Build and Push Server (push) Blocked by required conditions
Docker / Docker Build & Push Server Success (push) Blocked by required conditions
Docker / Docker Build & Push ML Success (push) Blocked by required conditions
Docs build / pre-job (push) Waiting to run
Docs build / Docs Build (push) Blocked by required conditions
Static Code Analysis / pre-job (push) Waiting to run
Static Code Analysis / Run Dart Code Analysis (push) Blocked by required conditions
Static Code Analysis / zizmor (push) Waiting to run
Test / pre-job (push) Waiting to run
Test / Test & Lint Server (push) Blocked by required conditions
Test / Unit Test CLI (push) Blocked by required conditions
Test / Unit Test CLI (Windows) (push) Blocked by required conditions
Test / Lint Web (push) Blocked by required conditions
Test / Test Web (push) Blocked by required conditions
Test / Test i18n (push) Blocked by required conditions
Test / End-to-End Lint (push) Blocked by required conditions
Test / Medium Tests (Server) (push) Blocked by required conditions
Test / End-to-End Tests (Server & CLI) (ubuntu-24.04-arm) (push) Blocked by required conditions
Test / End-to-End Tests (Server & CLI) (ubuntu-latest) (push) Blocked by required conditions
Test / End-to-End Tests (Web) (ubuntu-24.04-arm) (push) Blocked by required conditions
Test / End-to-End Tests (Web) (ubuntu-latest) (push) Blocked by required conditions
Test / End-to-End Tests Success (push) Blocked by required conditions
Test / Unit Test Mobile (push) Blocked by required conditions
Test / Unit Test ML (push) Blocked by required conditions
Test / .github Files Formatting (push) Blocked by required conditions
Test / ShellCheck (push) Waiting to run
Test / OpenAPI Clients (push) Waiting to run
Test / SQL Schema Checks (push) Waiting to run

This commit is contained in:
Dag Stuan
2025-08-31 15:50:33 +02:00
committed by GitHub
parent 03dafba522
commit fd2b7a344c
2 changed files with 28 additions and 10 deletions

View File

@@ -10,26 +10,28 @@
interface Props { interface Props {
asset: TimelineAsset; asset: TimelineAsset;
onImageLoad: () => void;
} }
const { asset }: Props = $props(); const { asset, onImageLoad }: Props = $props();
let assetFileUrl: string = $state(''); let assetFileUrl: string = $state('');
let imageLoaded: boolean = $state(false); let imageLoaded: boolean = $state(false);
let loader = $state<HTMLImageElement>(); let loader = $state<HTMLImageElement>();
const onload = () => { const onLoadCallback = () => {
imageLoaded = true; imageLoaded = true;
assetFileUrl = imageLoaderUrl; assetFileUrl = imageLoaderUrl;
onImageLoad();
}; };
onMount(() => { onMount(() => {
if (loader?.complete) { if (loader?.complete) {
onload(); onLoadCallback();
} }
loader?.addEventListener('load', onload); loader?.addEventListener('load', onLoadCallback);
return () => { return () => {
loader?.removeEventListener('load', onload); loader?.removeEventListener('load', onLoadCallback);
}; };
}); });

View File

@@ -84,6 +84,7 @@
let progressBarController: Tween<number> | undefined = $state(undefined); let progressBarController: Tween<number> | undefined = $state(undefined);
let videoPlayer: HTMLVideoElement | undefined = $state(); let videoPlayer: HTMLVideoElement | undefined = $state();
const asHref = (asset: { id: string }) => `?${QueryParameter.ID}=${asset.id}`; const asHref = (asset: { id: string }) => `?${QueryParameter.ID}=${asset.id}`;
const handleNavigate = async (asset?: { id: string }) => { const handleNavigate = async (asset?: { id: string }) => {
if ($isViewing) { if ($isViewing) {
return asset; return asset;
@@ -95,6 +96,7 @@
await goto(asHref(asset)); await goto(asHref(asset));
}; };
const setProgressDuration = (asset: TimelineAsset) => { const setProgressDuration = (asset: TimelineAsset) => {
if (asset.isVideo) { if (asset.isVideo) {
const timeParts = asset.duration!.split(':').map(Number); const timeParts = asset.duration!.split(':').map(Number);
@@ -108,6 +110,7 @@
}); });
} }
}; };
const handleNextAsset = () => handleNavigate(current?.next?.asset); const handleNextAsset = () => handleNavigate(current?.next?.asset);
const handlePreviousAsset = () => handleNavigate(current?.previous?.asset); const handlePreviousAsset = () => handleNavigate(current?.previous?.asset);
const handleNextMemory = () => handleNavigate(current?.nextMemory?.assets[0]); const handleNextMemory = () => handleNavigate(current?.nextMemory?.assets[0]);
@@ -115,6 +118,7 @@
const handleEscape = async () => goto(AppRoute.PHOTOS); const handleEscape = async () => goto(AppRoute.PHOTOS);
const handleSelectAll = () => const handleSelectAll = () =>
assetInteraction.selectAssets(current?.memory.assets.map((a) => toTimelineAsset(a)) || []); assetInteraction.selectAssets(current?.memory.assets.map((a) => toTimelineAsset(a)) || []);
const handleAction = async (callingContext: string, action: 'reset' | 'pause' | 'play') => { const handleAction = async (callingContext: string, action: 'reset' | 'pause' | 'play') => {
// leaving these log statements here as comments. Very useful to figure out what's going on during dev! // leaving these log statements here as comments. Very useful to figure out what's going on during dev!
// console.log(`handleAction[${callingContext}] called with: ${action}`); // console.log(`handleAction[${callingContext}] called with: ${action}`);
@@ -154,6 +158,7 @@
} }
} }
}; };
const handleProgress = async (progress: number) => { const handleProgress = async (progress: number) => {
if (!progressBarController) { if (!progressBarController) {
return; return;
@@ -184,6 +189,7 @@
memoryStore.hideAssetsFromMemory(ids); memoryStore.hideAssetsFromMemory(ids);
init(page); init(page);
}; };
const handleDeleteMemoryAsset = async () => { const handleDeleteMemoryAsset = async () => {
if (!current) { if (!current) {
return; return;
@@ -192,6 +198,7 @@
await memoryStore.deleteAssetFromMemory(current.asset.id); await memoryStore.deleteAssetFromMemory(current.asset.id);
init(page); init(page);
}; };
const handleDeleteMemory = async () => { const handleDeleteMemory = async () => {
if (!current) { if (!current) {
return; return;
@@ -201,6 +208,7 @@
notificationController.show({ message: $t('removed_memory'), type: NotificationType.Info }); notificationController.show({ message: $t('removed_memory'), type: NotificationType.Info });
init(page); init(page);
}; };
const handleSaveMemory = async () => { const handleSaveMemory = async () => {
if (!current) { if (!current) {
return; return;
@@ -214,10 +222,12 @@
}); });
init(page); init(page);
}; };
const handleGalleryScrollsIntoView = () => { const handleGalleryScrollsIntoView = () => {
galleryInView = true; galleryInView = true;
handlePromiseError(handleAction('galleryInView', 'pause')); handlePromiseError(handleAction('galleryInView', 'pause'));
}; };
const handleGalleryScrollsOutOfView = () => { const handleGalleryScrollsOutOfView = () => {
galleryInView = false; galleryInView = false;
// only call play after the first page load. When page first loads the gallery will not be visible // only call play after the first page load. When page first loads the gallery will not be visible
@@ -246,16 +256,22 @@
playerInitialized = false; playerInitialized = false;
}; };
const resetAndPlay = () => {
handlePromiseError(handleAction('resetAndPlay', 'reset'));
handlePromiseError(handleAction('resetAndPlay', 'play'));
};
const initPlayer = () => { const initPlayer = () => {
const isVideoAssetButPlayerHasNotLoadedYet = current && current.asset.isVideo && !videoPlayer; const isVideo = current && current.asset.isVideo;
const isVideoAssetButPlayerHasNotLoadedYet = isVideo && !videoPlayer;
if (playerInitialized || isVideoAssetButPlayerHasNotLoadedYet) { if (playerInitialized || isVideoAssetButPlayerHasNotLoadedYet) {
return; return;
} }
if ($isViewing) { if ($isViewing) {
handlePromiseError(handleAction('initPlayer[AssetViewOpen]', 'pause')); handlePromiseError(handleAction('initPlayer[AssetViewOpen]', 'pause'));
} else { } else if (isVideo) {
handlePromiseError(handleAction('initPlayer[AssetViewClosed]', 'reset')); // Image assets will start playing when the image is loaded. Only autostart video assets.
handlePromiseError(handleAction('initPlayer[AssetViewClosed]', 'play')); resetAndPlay();
} }
playerInitialized = true; playerInitialized = true;
}; };
@@ -474,7 +490,7 @@
videoViewerVolume={$videoViewerVolume} videoViewerVolume={$videoViewerVolume}
/> />
{:else} {:else}
<MemoryPhotoViewer asset={current.asset} /> <MemoryPhotoViewer asset={current.asset} onImageLoad={resetAndPlay} />
{/if} {/if}
{/key} {/key}