From 4736ec7e0a01a5bb045b9f1e0e5c571db78c0e6a Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 12 Feb 2025 08:31:40 +0530 Subject: [PATCH 01/26] Workbench --- web/apps/photos/src/pages/_app.tsx | 4 ++-- web/apps/photos/src/styles/global.css | 3 ++- web/packages/new/photos/components/FileViewerPhotoSwipe.ts | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/web/apps/photos/src/pages/_app.tsx b/web/apps/photos/src/pages/_app.tsx index 98bbec1235..62800fc6fe 100644 --- a/web/apps/photos/src/pages/_app.tsx +++ b/web/apps/photos/src/pages/_app.tsx @@ -50,9 +50,9 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import { resumeExportsIfNeeded } from "services/export"; import { photosLogout } from "services/logout"; -import "photoswipe/dist/photoswipe.css"; +// import "photoswipe/dist/photoswipe.css"; // TODO(PS): Note, auto hide only works with the new CSS. -// import "../../../../packages/new/photos/components/ps5/dist/photoswipe.css"; +import "../../../../packages/new/photos/components/ps5/dist/photoswipe.css"; import "styles/global.css"; diff --git a/web/apps/photos/src/styles/global.css b/web/apps/photos/src/styles/global.css index d480d0dc6b..a83e359b88 100644 --- a/web/apps/photos/src/styles/global.css +++ b/web/apps/photos/src/styles/global.css @@ -12,7 +12,7 @@ body { flex-direction: column; height: 100%; } - +@media DISABLED { .pswp__button--custom { width: 48px; height: 48px; @@ -114,3 +114,4 @@ body { .pswp__caption--empty { display: none; } +} diff --git a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts index 658e837672..8f0218f3ad 100644 --- a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts +++ b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts @@ -26,7 +26,7 @@ if (process.env.NEXT_PUBLIC_ENTE_WIP_PS5) { let PhotoSwipe; if (process.env.NEXT_PUBLIC_ENTE_WIP_PS5) { // TODO(PS): Comment me before merging into main. - // PhotoSwipe = require("./ps5/dist/photoswipe.esm.js").default; + PhotoSwipe = require("./ps5/dist/photoswipe.esm.js").default; } // TODO(PS): //import { type SlideData } from "./ps5/dist/types/slide/" From d4ddc0f91995ffbbca9558cfd7164bfd06d06677 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 12 Feb 2025 08:59:26 +0530 Subject: [PATCH 02/26] The dimensions are necessary the CSS was masking the issue --- .../photos/components/FileViewerPhotoSwipe.ts | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts index 8f0218f3ad..8569a07f2f 100644 --- a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts +++ b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts @@ -202,22 +202,21 @@ export class FileViewerPhotoSwipe { pswp.addFilter("itemData", (_, index) => { const file = files[index]; + // We might not have anything to show immediately, though in most + // cases a cached renderable thumbnail URL will be available + // shortly. + // + // Meanwhile, + // + // 1. Return empty slide data; PhotoSwipe will not show anything in + // the image area but will otherwise render UI controls properly. + // + // 2. Insert empty data so that we don't enqueue multiple updates. + let itemData: SlideData | undefined; if (file) { itemData = this.itemDataByFileID.get(file.id); if (!itemData) { - // We don't have anything to show immediately, though in - // most cases a cached renderable thumbnail URL will be - // available shortly. - // - // Meanwhile, - // - // 1. Return empty slide data; PhotoSwipe will not show - // anything in the image area but will otherwise render - // the surrounding UI properly. - // - // 2. Insert empty data so that we don't enqueue multiple - // updates. itemData = {}; this.itemDataByFileID.set(file.id, itemData); this.enqueueUpdates(index, file); @@ -351,11 +350,18 @@ export class FileViewerPhotoSwipe { }; const thumbnailURL = await downloadManager.renderableThumbnailURL(file); - // We don't have the dimensions of the thumbnail. We could try to deduce - // something from the file's aspect ratio etc, but that's not needed: - // PhotoSwipe already correctly (for our purposes) handles just a source - // URL being present. - update({ src: thumbnailURL }); + const thumbnailURLWithDimensions = await new Promise((resolve) => { + let image = new Image(); + image.onload = () => { + resolve({ + src: thumbnailURL, + width: image.naturalWidth, + height: image.naturalHeight, + }); + }; + image.src = thumbnailURL; + }); + update(thumbnailURLWithDimensions); switch (file.metadata.fileType) { case FileType.image: { From 6ef3c01030218d12e84a6494aac1e7d87cee53ee Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 12 Feb 2025 11:07:18 +0530 Subject: [PATCH 03/26] Fix --- web/packages/new/photos/components/FileViewerPhotoSwipe.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts index 8569a07f2f..fdb9cf3a70 100644 --- a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts +++ b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts @@ -266,7 +266,7 @@ export class FileViewerPhotoSwipe { // The user did some action within the file viewer to close it. // // Clear intervals. - clearIntervals(); + this.clearAutoHideIntervalIfNeeded(); // Let our parent know that we have been closed. onClose(); }); From 57881f34c3e1077bd6851e5f84b9124783b450a9 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 12 Feb 2025 14:55:21 +0530 Subject: [PATCH 04/26] Image dims --- .../photos/components/FileViewerPhotoSwipe.ts | 48 +++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts index fdb9cf3a70..b3363b04ea 100644 --- a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts +++ b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts @@ -350,28 +350,13 @@ export class FileViewerPhotoSwipe { }; const thumbnailURL = await downloadManager.renderableThumbnailURL(file); - const thumbnailURLWithDimensions = await new Promise((resolve) => { - let image = new Image(); - image.onload = () => { - resolve({ - src: thumbnailURL, - width: image.naturalWidth, - height: image.naturalHeight, - }); - }; - image.src = thumbnailURL; - }); - update(thumbnailURLWithDimensions); + update(await augmentedWithDimensions(thumbnailURL)); switch (file.metadata.fileType) { case FileType.image: { const sourceURLs = await downloadManager.renderableSourceURLs(file); - update({ - src: sourceURLs.url, - width: file.pubMagicMetadata?.data?.w, - height: file.pubMagicMetadata?.data?.h, - }); + update(await augmentedWithDimensions(sourceURLs.url)); break; } @@ -389,18 +374,13 @@ export class FileViewerPhotoSwipe { const livePhotoSourceURLs = sourceURLs.url as LivePhotoSourceURL; const imageURL = await livePhotoSourceURLs.image(); - update({ - src: imageURL, - width: file.pubMagicMetadata?.data?.w, - height: file.pubMagicMetadata?.data?.h, - }); + const imageData = await augmentedWithDimensions(imageURL); + update(imageData); const videoURL = await livePhotoSourceURLs.video(); console.log(videoURL); // update({ html: livePhotoVideoHTML(videoURL) }); update({ - src: imageURL, - width: file.pubMagicMetadata?.data?.w, - height: file.pubMagicMetadata?.data?.h, + ...imageData, videoURL, }); break; @@ -421,3 +401,21 @@ const livePhotoVideoHTML = (videoURL: string) => ` `; + +/** + * Take a image URL, determine its dimensions using browser APIs, and return the URL + * and its dimensions in a form that can directly be passed to PhotoSwipe as + * {@link SlideData}. + */ +const augmentedWithDimensions = (imageURL: string): Promise => + new Promise((resolve) => { + let image = new Image(); + image.onload = () => { + resolve({ + src: imageURL, + width: image.naturalWidth, + height: image.naturalHeight, + }); + }; + image.src = imageURL; + }); From bdb30d64f032ff9dedda6888349a2e7f1637a16f Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 12 Feb 2025 15:11:27 +0530 Subject: [PATCH 05/26] Note diversion that didn't work --- .../new/photos/components/FileViewerPhotoSwipe.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts index b3363b04ea..b39dfdbe51 100644 --- a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts +++ b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts @@ -161,8 +161,14 @@ export class FileViewerPhotoSwipe { // The default imageClickAction is "zoom-or-close". When the image // is small and cannot be zoomed into further (which is common when // just the thumbnail has been loaded), this causes PhotoSwipe to - // close. Disable this behaviour. - clickToCloseNonZoomable: false, + // close. + // + // This can be disabled by setting `clickToCloseNonZoomable` to + // false, but we also want to disable zooming into the thumbnails + // (it's not useful, and further, the user's zoom will be lost when + // the full res is loaded). Setting `imageClickAction` to "zoom" + // achieves both these ends. + imageClickAction: "zoom", // The default `bgClickAction` is "close", but it is not always // apparent where the background is and where the controls are, // since everything is black, and so accidentally closing PhotoSwipe From 17e59de59c5f6dbba3e7e142bd521cc366b7f413 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 12 Feb 2025 15:11:42 +0530 Subject: [PATCH 06/26] Revert "Note diversion that didn't work" This reverts commit 0791a8f659e7aad48ff69c53f07c7894db663345. --- .../new/photos/components/FileViewerPhotoSwipe.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts index b39dfdbe51..b3363b04ea 100644 --- a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts +++ b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts @@ -161,14 +161,8 @@ export class FileViewerPhotoSwipe { // The default imageClickAction is "zoom-or-close". When the image // is small and cannot be zoomed into further (which is common when // just the thumbnail has been loaded), this causes PhotoSwipe to - // close. - // - // This can be disabled by setting `clickToCloseNonZoomable` to - // false, but we also want to disable zooming into the thumbnails - // (it's not useful, and further, the user's zoom will be lost when - // the full res is loaded). Setting `imageClickAction` to "zoom" - // achieves both these ends. - imageClickAction: "zoom", + // close. Disable this behaviour. + clickToCloseNonZoomable: false, // The default `bgClickAction` is "close", but it is not always // apparent where the background is and where the controls are, // since everything is black, and so accidentally closing PhotoSwipe From 0883fe1d05c5c86f9d85f8d771dcd1d9c78512d2 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 12 Feb 2025 15:44:00 +0530 Subject: [PATCH 07/26] Take 2 disable thumb zoom --- web/packages/new/photos/components/FileViewerPhotoSwipe.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts index b3363b04ea..8f0b464351 100644 --- a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts +++ b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts @@ -232,6 +232,10 @@ export class FileViewerPhotoSwipe { return itemData ?? {}; }); + pswp.addFilter("isContentZoomable", (originalResult, content) => { + return content.data.isContentZoomable ?? originalResult; + }); + pswp.addFilter("preventPointerEvent", (originalResult) => { // There was a pointer event. We don't care which one, we just use // this as a hook to show UI again (if needed) and update our last @@ -350,7 +354,8 @@ export class FileViewerPhotoSwipe { }; const thumbnailURL = await downloadManager.renderableThumbnailURL(file); - update(await augmentedWithDimensions(thumbnailURL)); + const thumbnailData = await augmentedWithDimensions(thumbnailURL); + update({ ...thumbnailData, isContentZoomable: false }); switch (file.metadata.fileType) { case FileType.image: { From aa27191ddcc7c9a544f74da1678129c02408b71e Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 12 Feb 2025 15:55:46 +0530 Subject: [PATCH 08/26] CSS for vids --- web/apps/photos/src/styles/global.css | 9 +++++++++ .../new/photos/components/FileViewerPhotoSwipe.ts | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/web/apps/photos/src/styles/global.css b/web/apps/photos/src/styles/global.css index a83e359b88..77583e306f 100644 --- a/web/apps/photos/src/styles/global.css +++ b/web/apps/photos/src/styles/global.css @@ -115,3 +115,12 @@ body { display: none; } } + +/* + Make the controllable video elements we render as custom PhotoSwipe content + take up the entire container. + */ +.pswp-ente video[controls] { + width: 100%; + height: 100%; +} diff --git a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts index 8f0b464351..278259509e 100644 --- a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts +++ b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts @@ -189,7 +189,7 @@ export class FileViewerPhotoSwipe { index: initialIndex, // TODO(PS): padding option? for handling custom title bar. // TODO(PS): will we need this? - mainClass: "our-extra-pswp-main-class", + mainClass: "pswp-ente", }); // Provide data about slides to PhotoSwipe via callbacks From 18ee3b19f7b44aaaa14b12aaf853dbaaafaa2130 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 12 Feb 2025 16:05:07 +0530 Subject: [PATCH 09/26] Set --- web/packages/new/photos/components/FileViewerPhotoSwipe.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts index 278259509e..496b0db7f8 100644 --- a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts +++ b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts @@ -158,6 +158,10 @@ export class FileViewerPhotoSwipe { const pswp = new PhotoSwipe({ // Opaque background. bgOpacity: 1, + // The default, "zoom", cannot be used since we're not animating + // from a thumbnail, so effectively "fade" is in effect anyway. Set + // it still, just for and explicitness and documentation. + showHideAnimationType: "fade", // The default imageClickAction is "zoom-or-close". When the image // is small and cannot be zoomed into further (which is common when // just the thumbnail has been loaded), this causes PhotoSwipe to From 981c74d3f17bbde6e02825856b84ef1501698c01 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 12 Feb 2025 16:16:57 +0530 Subject: [PATCH 10/26] Don't auto load vids Ref: https://github.com/dimsemenov/photoswipe-video-plugin/blob/5e32d6589df53df2887900bcd55267d72aee57a6/dist/photoswipe-video-plugin.esm.js#L77 --- web/packages/new/photos/components/FileViewerPhotoSwipe.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts index 496b0db7f8..99909ae55e 100644 --- a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts +++ b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts @@ -248,6 +248,13 @@ export class FileViewerPhotoSwipe { return originalResult; }); + pswp.on("appendHeavy", (e) => { + // Do not append video elements on nearby slides. + if (e.slide.content.type == "html" && !e.slide.isActive) { + e.preventDefault(); + } + }); + pswp.on("contentLoad", (e) => { console.log("contentLoad", e); if (e.content.data.videoURL) { From 6e774d675832d735f6618e0ac82cd38dc0ace9d0 Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 12 Feb 2025 17:10:26 +0530 Subject: [PATCH 11/26] Pause on changing video slide --- .../photos/components/FileViewerPhotoSwipe.ts | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts index 99909ae55e..8440837a6e 100644 --- a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts +++ b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts @@ -236,8 +236,8 @@ export class FileViewerPhotoSwipe { return itemData ?? {}; }); - pswp.addFilter("isContentZoomable", (originalResult, content) => { - return content.data.isContentZoomable ?? originalResult; + pswp.addFilter("isContentZoomable", (isZoomable, content) => { + return content.data.isContentZoomable ?? isZoomable; }); pswp.addFilter("preventPointerEvent", (originalResult) => { @@ -248,15 +248,11 @@ export class FileViewerPhotoSwipe { return originalResult; }); - pswp.on("appendHeavy", (e) => { - // Do not append video elements on nearby slides. - if (e.slide.content.type == "html" && !e.slide.isActive) { - e.preventDefault(); - } - }); - pswp.on("contentLoad", (e) => { console.log("contentLoad", e); + // if (content.type == "video") { + // content. + // } if (e.content.data.videoURL) { const holderEl = e.content.slide.holderElement; const vid = document.createElement("h1"); @@ -277,9 +273,14 @@ export class FileViewerPhotoSwipe { } }); + pswp.on("contentDeactivate", (e) => { + // Pause the video tag (if any) for a slide when we move away from it. + const video = e.content?.element?.getElementsByTagName("video")[0]; + video?.pause(); + }); + + // The user did some action within the file viewer to close it. pswp.on("close", () => { - // The user did some action within the file viewer to close it. - // // Clear intervals. this.clearAutoHideIntervalIfNeeded(); // Let our parent know that we have been closed. From 8df58319442d977f6f14ff5a341f3f9ef3cf614f Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Wed, 12 Feb 2025 17:53:53 +0530 Subject: [PATCH 12/26] Some overlay --- .../photos/components/FileViewerPhotoSwipe.ts | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts index 8440837a6e..e1f44f5342 100644 --- a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts +++ b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts @@ -248,28 +248,36 @@ export class FileViewerPhotoSwipe { return originalResult; }); - pswp.on("contentLoad", (e) => { - console.log("contentLoad", e); - // if (content.type == "video") { - // content. - // } - if (e.content.data.videoURL) { - const holderEl = e.content.slide.holderElement; - const vid = document.createElement("h1"); - vid.innerText = "Test 1"; - holderEl.appendChild(vid); - } - }); pswp.on("contentAppend", (e) => { const containerEl = e.content.slide.container; - console.log("contentAppend", containerEl); if (e.content.data.videoURL) { - const vid = document.createElement("div"); - vid.innerHTML = livePhotoVideoHTML(e.content.data.videoURL); + const img = e.content.element; + console.log( + img, + img.width, + img.height, + containerEl.width, + containerEl.height, + ); + + const vidT = document.createElement("template"); + vidT.innerHTML = livePhotoVideoHTML( + e.content.data.videoURL, + ).trim(); + const vid = vidT.content.firstChild; // vid.innerText = "Test 2"; + containerEl.style = "position: relative"; containerEl.appendChild(vid); + // vid.style = `position: absolute; width: ${img.width}px; height: ${img.height}px; top: 0, left: 0, z-index: 1; pointer-events: none;`; + // console.log(vid.style); + // vid.style = `position: absolute; width: 200px; height: 200px; + // top: 0, left: 0, z-index: 1; pointer-events: none;`; vid.style = - "position: absolute; left: 0; right: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none;"; + //img.style + + `width: 200px; height: 100px; ` + + `; position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;`; + // vid.style.width = img.width + "px"; + // vid.style.height = img.height + "px"; } }); @@ -394,12 +402,7 @@ export class FileViewerPhotoSwipe { const imageData = await augmentedWithDimensions(imageURL); update(imageData); const videoURL = await livePhotoSourceURLs.video(); - console.log(videoURL); - // update({ html: livePhotoVideoHTML(videoURL) }); - update({ - ...imageData, - videoURL, - }); + update({ ...imageData, videoURL }); break; } } From 8218bfba04423cd302a6efc7f79c1a2e6ce35a2b Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 13 Feb 2025 07:59:06 +0530 Subject: [PATCH 13/26] Try and alternative event to resize --- .../photos/components/FileViewerPhotoSwipe.ts | 71 +++++++++++-------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts index e1f44f5342..614ccca693 100644 --- a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts +++ b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts @@ -249,36 +249,38 @@ export class FileViewerPhotoSwipe { }); pswp.on("contentAppend", (e) => { - const containerEl = e.content.slide.container; - if (e.content.data.videoURL) { - const img = e.content.element; - console.log( - img, - img.width, - img.height, - containerEl.width, - containerEl.height, - ); + const videoURL = e.content.data.livePhotoVideoURL; + if (!videoURL) return; - const vidT = document.createElement("template"); - vidT.innerHTML = livePhotoVideoHTML( - e.content.data.videoURL, - ).trim(); - const vid = vidT.content.firstChild; - // vid.innerText = "Test 2"; - containerEl.style = "position: relative"; - containerEl.appendChild(vid); - // vid.style = `position: absolute; width: ${img.width}px; height: ${img.height}px; top: 0, left: 0, z-index: 1; pointer-events: none;`; - // console.log(vid.style); - // vid.style = `position: absolute; width: 200px; height: 200px; - // top: 0, left: 0, z-index: 1; pointer-events: none;`; - vid.style = - //img.style + - `width: 200px; height: 100px; ` + - `; position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;`; - // vid.style.width = img.width + "px"; - // vid.style.height = img.height + "px"; + // This slide is displaying a live photo. Append a video element + // into the mix. + + const img = e.content.element; + const video = createElementFromHTMLString( + livePhotoVideoHTML(videoURL), + ); + const containerEl = e.content.slide.container; + containerEl.style = "position: relative"; + containerEl.appendChild(video); + video.style = + `width: 200px; height: 100px; ` + + `position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;`; + }); + + pswp.on("imageSizeChange", ({ content, width, height }) => { + if (!content.data.livePhotoVideoURL) return; + + // This slide is displaying a live photo. Modify the size of the + // video element to match that of the image. + + const video = content?.element?.getElementsByTagName("video")[0]; + if (!video) { + assertionFailed(); + return; } + + video.style.width = `${width}px`; + video.style.height = `${height}px`; }); pswp.on("contentDeactivate", (e) => { @@ -401,8 +403,8 @@ export class FileViewerPhotoSwipe { const imageURL = await livePhotoSourceURLs.image(); const imageData = await augmentedWithDimensions(imageURL); update(imageData); - const videoURL = await livePhotoSourceURLs.video(); - update({ ...imageData, videoURL }); + const livePhotoVideoURL = await livePhotoSourceURLs.video(); + update({ ...imageData, livePhotoVideoURL }); break; } } @@ -422,6 +424,14 @@ const livePhotoVideoHTML = (videoURL: string) => ` `; +const createElementFromHTMLString = (htmlString: string) => { + const template = document.createElement("template"); + // Excess whitespace causes excess DOM nodes, causing our firstChild to not + // be what we wanted them to be. + template.innerHTML = htmlString.trim(); + return vidT.content.firstChild; +}; + /** * Take a image URL, determine its dimensions using browser APIs, and return the URL * and its dimensions in a form that can directly be passed to PhotoSwipe as @@ -437,5 +447,6 @@ const augmentedWithDimensions = (imageURL: string): Promise => height: image.naturalHeight, }); }; + // TODO(PS): Handle imageElement.onerror image.src = imageURL; }); From e06b20a56629204c6be7b460a59249174f3e948a Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 13 Feb 2025 08:09:25 +0530 Subject: [PATCH 14/26] Fix --- .../photos/components/FileViewerPhotoSwipe.ts | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts index 614ccca693..5365977f0d 100644 --- a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts +++ b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts @@ -262,20 +262,36 @@ export class FileViewerPhotoSwipe { const containerEl = e.content.slide.container; containerEl.style = "position: relative"; containerEl.appendChild(video); - video.style = - `width: 200px; height: 100px; ` + - `position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;`; + video.style = `position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;`; + + video.style.width = img.style.width; + video.style.height = img.style.height; + + console.log( + "contentAppend", + e.content, + e.content.slide.container, + video, + img.style.width, + img.style.height, + ); }); pswp.on("imageSizeChange", ({ content, width, height }) => { if (!content.data.livePhotoVideoURL) return; - // This slide is displaying a live photo. Modify the size of the // video element to match that of the image. - const video = content?.element?.getElementsByTagName("video")[0]; + const video = + content.slide.container.getElementsByTagName("video")[0]; + console.log( + "imageSizeChange", + content, + content.slide.container, + video, + ); + if (!video) { - assertionFailed(); return; } @@ -429,7 +445,7 @@ const createElementFromHTMLString = (htmlString: string) => { // Excess whitespace causes excess DOM nodes, causing our firstChild to not // be what we wanted them to be. template.innerHTML = htmlString.trim(); - return vidT.content.firstChild; + return template.content.firstChild; }; /** From b823a8d6a121c29e345b193c95091bc9633d752e Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 13 Feb 2025 08:17:12 +0530 Subject: [PATCH 15/26] Cleanup --- .../photos/components/FileViewerPhotoSwipe.ts | 80 ++++++++----------- 1 file changed, 35 insertions(+), 45 deletions(-) diff --git a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts index 5365977f0d..24e1ddb98a 100644 --- a/web/packages/new/photos/components/FileViewerPhotoSwipe.ts +++ b/web/packages/new/photos/components/FileViewerPhotoSwipe.ts @@ -227,7 +227,7 @@ export class FileViewerPhotoSwipe { } } - log.debug(() => ["[ps]", { itemData, index, file, itemData }]); + log.debug(() => ["[viewer]", { index, itemData, file }]); if (!file) assertionFailed(); if (this.lastActivityDate != "already-hidden") @@ -242,8 +242,8 @@ export class FileViewerPhotoSwipe { pswp.addFilter("preventPointerEvent", (originalResult) => { // There was a pointer event. We don't care which one, we just use - // this as a hook to show UI again (if needed) and update our last - // activity date. + // this as a hook to show the UI again (if needed), and update our + // last activity date. this.onPointerActivity(); return originalResult; }); @@ -252,46 +252,36 @@ export class FileViewerPhotoSwipe { const videoURL = e.content.data.livePhotoVideoURL; if (!videoURL) return; - // This slide is displaying a live photo. Append a video element - // into the mix. + // This slide is displaying a live photo. Append a video element to + // show its video part. const img = e.content.element; const video = createElementFromHTMLString( livePhotoVideoHTML(videoURL), ); - const containerEl = e.content.slide.container; - containerEl.style = "position: relative"; - containerEl.appendChild(video); - video.style = `position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;`; + const container = e.content.slide.container; + container.style = "position: relative"; + container.appendChild(video); + // Set z-index to 1 to keep it on top, and set pointer-events to + // none to pass the clicks through. + video.style = + "position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;"; + // Size it to the underlying image. video.style.width = img.style.width; video.style.height = img.style.height; - - console.log( - "contentAppend", - e.content, - e.content.slide.container, - video, - img.style.width, - img.style.height, - ); }); pswp.on("imageSizeChange", ({ content, width, height }) => { if (!content.data.livePhotoVideoURL) return; - // This slide is displaying a live photo. Modify the size of the + + // This slide is displaying a live photo. Resize the size of the // video element to match that of the image. const video = content.slide.container.getElementsByTagName("video")[0]; - console.log( - "imageSizeChange", - content, - content.slide.container, - video, - ); - if (!video) { + // We might have been called before "contentAppend". return; } @@ -427,6 +417,25 @@ export class FileViewerPhotoSwipe { } } +/** + * Take a image URL, determine its dimensions using browser APIs, and return the URL + * and its dimensions in a form that can directly be passed to PhotoSwipe as + * {@link SlideData}. + */ +const augmentedWithDimensions = (imageURL: string): Promise => + new Promise((resolve) => { + let image = new Image(); + image.onload = () => { + resolve({ + src: imageURL, + width: image.naturalWidth, + height: image.naturalHeight, + }); + }; + // TODO(PS): Handle imageElement.onerror + image.src = imageURL; + }); + const videoHTML = (url: string, disableDownload: boolean) => `