diff --git a/web/apps/photos/src/components/PhotoFrame.tsx b/web/apps/photos/src/components/PhotoFrame.tsx index 582af17667..4de27f64f6 100644 --- a/web/apps/photos/src/components/PhotoFrame.tsx +++ b/web/apps/photos/src/components/PhotoFrame.tsx @@ -3,24 +3,17 @@ import { isSameDay } from "@/base/date"; import { formattedDate } from "@/base/i18n-date"; import log from "@/base/log"; import type { FileInfoProps } from "@/gallery/components/FileInfo"; -import { - downloadManager, - type LivePhotoSourceURL, - type LoadedLivePhotoSourceURL, - type RenderableSourceURLs, -} from "@/gallery/services/download"; +import { FileViewer } from "@/gallery/components/viewer/FileViewer"; +import { type RenderableSourceURLs } from "@/gallery/services/download"; import type { Collection } from "@/media/collection"; import { EnteFile } from "@/media/file"; import { FileType } from "@/media/file-type"; -import { FileViewer } from "@/new/photos/components/FileViewerComponents"; import type { GalleryBarMode } from "@/new/photos/components/gallery/reducer"; import { moveToTrash, TRASH_SECTION } from "@/new/photos/services/collection"; import { styled } from "@mui/material"; -import { PhotoViewer } from "components/PhotoViewer"; import { t } from "i18next"; import { useRouter } from "next/router"; import { GalleryContext } from "pages/gallery"; -import PhotoSwipe from "photoswipe"; import { useCallback, useContext, useEffect, useMemo, useState } from "react"; import AutoSizer from "react-virtualized-auto-sizer"; import { @@ -182,10 +175,7 @@ const PhotoFrame = ({ }: PhotoFrameProps) => { const [open, setOpen] = useState(false); const [currentIndex, setCurrentIndex] = useState(0); - const [fetching, setFetching] = useState>({}); - const [thumbFetching, setThumbFetching] = useState>( - {}, - ); + const galleryContext = useContext(GalleryContext); const [rangeStart, setRangeStart] = useState(null); const [currentHover, setCurrentHover] = useState(null); @@ -200,6 +190,7 @@ const PhotoFrame = ({ ); useEffect(() => { + // TODO(PS): Audit const result = files.map((file) => ({ ...file, w: window.innerWidth, @@ -208,8 +199,6 @@ const PhotoFrame = ({ timelineDateString: fileTimelineDateString(file), })); setDisplayFiles(result); - setFetching({}); - setThumbFetching({}); }, [files]); useEffect(() => { @@ -334,28 +323,14 @@ const PhotoFrame = ({ if (file.msrc && !forceUpdate) { return false; } + // TODO(PS): Audit updateDisplayFileThumbnail(file, url); return true; }; - const handleClose = (needUpdate) => { - if (process.env.NEXT_PUBLIC_ENTE_WIP_PS5) { - throw new Error("Not implemented"); - } else { - setOpen(false); - needUpdate && onSyncWithRemote(); - setIsPhotoSwipeOpen?.(false); - } - }; - const onThumbnailClick = (index: number) => () => { setCurrentIndex(index); - if (process.env.NEXT_PUBLIC_ENTE_WIP_PS5) { - showFileViewer(); - } else { - setOpen(true); - setIsPhotoSwipeOpen?.(true); - } + showFileViewer(); }; const handleSelect = handleSelectCreator( @@ -429,135 +404,7 @@ const PhotoFrame = ({ /> ); - const getSlideData = async ( - instance: PhotoSwipe, - index: number, - item: DisplayFile, - ) => { - log.info( - `[${item.id}] getSlideData called for thumbnail: ${!!item.msrc} sourceLoaded: ${!!item.isSourceLoaded} fetching: ${!!fetching[item.id]}`, - ); - - if (!item.msrc) { - try { - if (thumbFetching[item.id]) { - log.info(`[${item.id}] thumb download already in progress`); - return; - } - log.info(`[${item.id}] doesn't have thumbnail`); - thumbFetching[item.id] = true; - // URL will always be defined (unless an error is thrown) since - // we are not passing the `cachedOnly` option. - const url = await downloadManager.renderableThumbnailURL(item)!; - updateThumbnail(instance, index, item, url, false); - } catch (e) { - log.error("getSlideData failed get msrc url failed", e); - thumbFetching[item.id] = false; - } - } - - if (item.isSourceLoaded || item.conversionFailed) { - if (item.isSourceLoaded) { - log.info(`[${item.id}] source already loaded`); - } - if (item.conversionFailed) { - log.info(`[${item.id}] conversion failed`); - } - return; - } - if (fetching[item.id]) { - log.info(`[${item.id}] file download already in progress`); - return; - } - - try { - log.info(`[${item.id}] new file src request`); - fetching[item.id] = true; - const srcURLs = await downloadManager.renderableSourceURLs(item); - if (item.metadata.fileType === FileType.livePhoto) { - const srcImgURL = srcURLs.url as LivePhotoSourceURL; - const imageURL = await srcImgURL.image(); - - const dummyImgSrcUrl: RenderableSourceURLs = { - url: imageURL, - type: "normal", - }; - updateSource(instance, index, item, dummyImgSrcUrl, false); - if (!imageURL) { - // no image url, no need to load video - return; - } - - const videoURL = await srcImgURL.video(); - const loadedLivePhotoSrcURL: RenderableSourceURLs = { - url: { video: videoURL, image: imageURL }, - type: "livePhoto", - }; - updateSource( - instance, - index, - item, - loadedLivePhotoSrcURL, - true, - ); - } else { - updateSource(instance, index, item, srcURLs, false); - } - } catch (e) { - log.error("getSlideData failed get src url failed", e); - fetching[item.id] = false; - // no-op - } - }; - - const updateThumbnail = ( - instance: PhotoSwipe, - index: number, - item: DisplayFile, - url: string, - forceUpdate?: boolean, - ) => { - try { - if (updateThumbURL(index)(item.id, url, forceUpdate)) { - log.info( - `[${item.id}] calling invalidateCurrItems for thumbnail msrc: ${!!item.msrc}`, - ); - instance.invalidateCurrItems(); - if ((instance as any).isOpen()) { - instance.updateSize(true); - } - } - } catch (e) { - log.error("updating photoswipe after msrc url update failed", e); - // ignore - } - }; - - const updateSource = ( - instance: PhotoSwipe, - index: number, - item: DisplayFile, - srcURL: RenderableSourceURLs, - overwrite: boolean, - ) => { - const file = displayFiles[index]; - // This is to prevent outdated call from updating the wrong file. - if (file.id !== item.id) { - log.info( - `Ignoring stale updateSourceURL for display file at index ${index} (file ID ${file.id}, expected ${item.id})`, - ); - throw new Error("Update URL file id mismatch"); - } - if (file.isSourceLoaded && !overwrite) return; - if (file.conversionFailed) throw new Error("File conversion failed"); - - updateDisplayFileSource(file, srcURL, enableDownload); - instance.invalidateCurrItems(); - if ((instance as any).isOpen()) { - instance.updateSize(true); - } - }; - + /* TODO(PS): const forceConvertItem = async ( instance: PhotoSwipe, index: number, @@ -582,35 +429,10 @@ const PhotoFrame = ({ // no-op } }; + */ return ( - {process.env.NEXT_PUBLIC_ENTE_WIP_PS5 && ( - - )} {({ height, width }) => ( )} - { } }; -const updateDisplayFileSource = ( - file: DisplayFile, - srcURLs: RenderableSourceURLs, - enableDownload: boolean, -) => { - const { url } = srcURLs; - const isRenderable = !!url; - file.w = window.innerWidth; - file.h = window.innerHeight; - file.isSourceLoaded = - file.metadata.fileType === FileType.livePhoto - ? srcURLs.type === "livePhoto" - : true; - file.canForceConvert = srcURLs.canForceConvert; - file.conversionFailed = !isRenderable; - file.associatedImageURL = (() => { - switch (file.metadata.fileType) { - case FileType.image: - return srcURLs.url as string; - case FileType.livePhoto: - return (srcURLs.url as LoadedLivePhotoSourceURL).image; - default: - return undefined; - } - })(); - if (!isRenderable) { - file.isSourceLoaded = true; - return; - } - - if (file.metadata.fileType === FileType.video) { - file.html = ` - - `; - } else if (file.metadata.fileType === FileType.livePhoto) { - if (srcURLs.type === "normal") { - file.html = ` -
- -
- `; - } else { - const { image: imageURL, video: videoURL } = - url as LoadedLivePhotoSourceURL; - - file.html = ` -
- - -
- `; - } - } else if (file.metadata.fileType === FileType.image) { - file.src = url as string; - } else { - log.error(`unknown file type - ${file.metadata.fileType}`); - file.src = url as string; - } -}; - /** * See: [Note: Timeline date string] */ diff --git a/web/apps/photos/src/pages/gallery.tsx b/web/apps/photos/src/pages/gallery.tsx index d4926fd54d..2e97ca2714 100644 --- a/web/apps/photos/src/pages/gallery.tsx +++ b/web/apps/photos/src/pages/gallery.tsx @@ -12,13 +12,13 @@ import { useModalVisibility } from "@/base/components/utils/modal"; import { useBaseContext } from "@/base/context"; import log from "@/base/log"; import { FullScreenDropZone } from "@/gallery/components/FullScreenDropZone"; +import { resetFileViewerDataSourceOnClose } from "@/gallery/components/viewer/data-source"; import { type Collection } from "@/media/collection"; import { mergeMetadata, type EnteFile } from "@/media/file"; import { CollectionSelector, type CollectionSelectorAttributes, } from "@/new/photos/components/CollectionSelector"; -import { resetFileViewerDataSourceOnClose } from "@/new/photos/components/FileViewerComponents-temp"; import { PlanSelector } from "@/new/photos/components/PlanSelector"; import { SearchBar, @@ -570,7 +570,6 @@ const Page: React.FC = () => { ); if (didUpdateNormalFiles || didUpdateHiddenFiles) { exportService.onLocalFilesUpdated(); - // TODO(PS): Use direct one resetFileViewerDataSourceOnClose(); } // syncWithRemote is called with the force flag set to true before diff --git a/web/packages/gallery/components/viewer/FileViewer.tsx b/web/packages/gallery/components/viewer/FileViewer.tsx index 22fbb9f494..0cddaa03d2 100644 --- a/web/packages/gallery/components/viewer/FileViewer.tsx +++ b/web/packages/gallery/components/viewer/FileViewer.tsx @@ -1,18 +1,6 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ // @ts-nocheck -// TODO(PS): WIP gallery using upstream photoswipe -// -// Needs (not committed yet): -// yarn workspace gallery add photoswipe@^5.4.4 -// mv node_modules/photoswipe packages/new/photos/components/ps5 - -if (process.env.NEXT_PUBLIC_ENTE_WIP_PS5) { - console.warn("Using WIP upstream photoswipe"); -} else { - throw new Error("Whoa"); -} - import { isDesktop } from "@/base/app"; import { SpacedRow } from "@/base/components/containers"; import { DialogCloseIconButton } from "@/base/components/mui/DialogCloseIconButton"; @@ -248,7 +236,7 @@ export type FileViewerProps = ModalVisibilityProps & { /** * A PhotoSwipe based image and video viewer. */ -const FileViewer: React.FC = ({ +export const FileViewer: React.FC = ({ open, onClose, user, @@ -870,8 +858,6 @@ const FileViewer: React.FC = ({ ); }; -export default FileViewer; - const Container = styled("div")` border: 1px solid red; diff --git a/web/packages/gallery/components/viewer/photoswipe.ts b/web/packages/gallery/components/viewer/photoswipe.ts index 9f1070c618..e7a4ede331 100644 --- a/web/packages/gallery/components/viewer/photoswipe.ts +++ b/web/packages/gallery/components/viewer/photoswipe.ts @@ -6,6 +6,7 @@ import log from "@/base/log"; import type { EnteFile } from "@/media/file"; import { FileType } from "@/media/file-type"; import { t } from "i18next"; +import PhotoSwipe from "photoswipe"; import { fileViewerDidClose, fileViewerWillOpen, @@ -18,24 +19,6 @@ import { import { type FileViewerAnnotatedFile } from "./FileViewer"; import { createPSRegisterElementIconHTML } from "./icons"; -// TODO(PS): WIP gallery using upstream photoswipe -// -// Needs (not committed yet): -// yarn workspace gallery add photoswipe@^5.4.4 -// mv node_modules/photoswipe packages/new/photos/components/ps5 - -if (process.env.NEXT_PUBLIC_ENTE_WIP_PS5) { - console.warn("Using WIP upstream photoswipe"); -} else { - throw new Error("Whoa"); -} - -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; -} - export interface FileViewerPhotoSwipeDelegate { /** * Called to obtain the latest list of files. diff --git a/web/packages/new/photos/components/FileViewerComponents-temp.ts b/web/packages/new/photos/components/FileViewerComponents-temp.ts deleted file mode 100644 index 834bc63d6c..0000000000 --- a/web/packages/new/photos/components/FileViewerComponents-temp.ts +++ /dev/null @@ -1,7 +0,0 @@ -// TODO(PS): Temporary trampoline -export const resetFileViewerDataSourceOnClose = async () => { - if (!process.env.NEXT_PUBLIC_ENTE_WIP_PS5) return; - ( - await import("@/gallery/components/viewer/data-source") - ).resetFileViewerDataSourceOnClose(); -}; diff --git a/web/packages/new/photos/components/FileViewerComponents.tsx b/web/packages/new/photos/components/FileViewerComponents.tsx index c65c74e52f..6cc139ea64 100644 --- a/web/packages/new/photos/components/FileViewerComponents.tsx +++ b/web/packages/new/photos/components/FileViewerComponents.tsx @@ -9,22 +9,6 @@ import { t } from "i18next"; import { useState } from "react"; import { aboveFileViewerContentZ } from "./utils/z-index"; -// TODO(PS) -import dynamic from "next/dynamic"; -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore -const FV5 = dynamic(() => import("@/gallery/components/viewer/FileViewer"), { - ssr: false, -}); - -const FVD = () => <>; - -export const FileViewer: React.FC = (props) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return process.env.NEXT_PUBLIC_ENTE_WIP_PS5 ? : ; -}; - type ConfirmDeleteFileDialogProps = ModalVisibilityProps & { /** * Called when the user confirms the deletion. diff --git a/web/packages/new/photos/services/sync.ts b/web/packages/new/photos/services/sync.ts index 6bd072e71e..5f215ca857 100644 --- a/web/packages/new/photos/services/sync.ts +++ b/web/packages/new/photos/services/sync.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-empty-function */ +import { resetFileViewerDataSourceOnClose } from "@/gallery/components/viewer/data-source"; import { isHiddenCollection } from "@/new/photos/services/collection"; import { getAllLatestCollections, @@ -9,7 +10,6 @@ import { isMLSupported, mlStatusSync, mlSync } from "@/new/photos/services/ml"; import { searchDataSync } from "@/new/photos/services/search"; import { syncSettings } from "@/new/photos/services/settings"; import { splitByPredicate } from "@/utils/array"; -import { resetFileViewerDataSourceOnClose } from "../components/FileViewerComponents-temp"; /** * Part 1 of {@link sync}. See TODO below for why this is split. @@ -77,9 +77,9 @@ export const syncFilesAndCollections = async () => { ); await syncTrash(allCollections, () => {}); if (didUpdateNormalFiles || didUpdateHiddenFiles) { - // TODO: + // TODO: Ok for now since we're only called by deduper, but still needs + // fixing instead of a hidden gotcha. // exportService.onLocalFilesUpdated(); - // TODO(PS): Use direct one - await resetFileViewerDataSourceOnClose(); + resetFileViewerDataSourceOnClose(); } };