From 0803ef4da67a4e2951cae4757fd2e9565e5b7f9a Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 27 Feb 2025 15:55:38 +0530 Subject: [PATCH] Btn --- web/packages/base/components/utils/theme.ts | 3 +- .../gallery/components/viewer/FileViewer.tsx | 29 ++++++++++++-- .../gallery/components/viewer/icons.tsx | 2 + .../gallery/components/viewer/photoswipe.ts | 40 ++++++++++++++++++- 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/web/packages/base/components/utils/theme.ts b/web/packages/base/components/utils/theme.ts index 080e5eef74..04c38e9859 100644 --- a/web/packages/base/components/utils/theme.ts +++ b/web/packages/base/components/utils/theme.ts @@ -546,7 +546,8 @@ const components: Components = { // This is required to prevent console errors about aria-hiding a // focused button when the dialog is closed. // - // https://github.com/mui/material-ui/issues/43106#issuecomment-2314809028 + // - https://github.com/mui/material-ui/issues/43106#issuecomment-2314809028 + // - https://issues.chromium.org/issues/392121909 closeAfterTransition: false, }, styleOverrides: { diff --git a/web/packages/gallery/components/viewer/FileViewer.tsx b/web/packages/gallery/components/viewer/FileViewer.tsx index c802121102..23ead0d31f 100644 --- a/web/packages/gallery/components/viewer/FileViewer.tsx +++ b/web/packages/gallery/components/viewer/FileViewer.tsx @@ -13,7 +13,9 @@ if (process.env.NEXT_PUBLIC_ENTE_WIP_PS5) { throw new Error("Whoa"); } +import { isDesktop } from "@/base/app"; import { type ModalVisibilityProps } from "@/base/components/utils/modal"; +import { lowercaseExtension } from "@/base/file-name"; import type { LocalUser } from "@/base/local-user"; import log from "@/base/log"; import { @@ -21,7 +23,9 @@ import { type FileInfoExif, type FileInfoProps, } from "@/gallery/components/FileInfo"; +import { FileType } from "@/media/file-type"; import type { EnteFile } from "@/media/file.js"; +import { isHEICExtension, needsJPEGConversion } from "@/media/formats"; import { ImageEditorOverlay } from "@/new/photos/components/ImageEditorOverlay"; import { Button, styled } from "@mui/material"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; @@ -145,7 +149,8 @@ const FileViewer: React.FC = ({ (file: EnteFile) => { const fileID = file.id; const isOwnFile = file.ownerID == user?.id; - return { fileID, isOwnFile }; + const isEditableImage = fileIsEditableImage(file); + return { fileID, isOwnFile, isEditableImage }; }, [user], ); @@ -227,7 +232,7 @@ const FileViewer: React.FC = ({ onClose: handleClose, onAnnotate: handleAnnotate, onViewInfo: handleViewInfo, - onEditImage: handleEditImage + onEditImage: handleEditImage, }); pswpRef.current = pswp; @@ -289,6 +294,8 @@ const FileViewer: React.FC = ({ ); }; +export default FileViewer; + const Container = styled("div")` border: 1px solid red; @@ -298,4 +305,20 @@ const Container = styled("div")` } `; -export default FileViewer; +const fileIsEditableImage = (file: EnteFile) => { + // Only images are editable. + if (file.metadata.fileType !== FileType.image) return false; + + const extension = lowercaseExtension(file.metadata.title); + // Assume it is editable; + let isRenderable = true; + if (extension && needsJPEGConversion(extension)) { + // See if the file is on the whitelist of extensions that we know + // will not be directly renderable. + if (!isDesktop) { + // On the web, we only support HEIC conversion. + isRenderable = isHEICExtension(extension); + } + } + return isRenderable; +}; diff --git a/web/packages/gallery/components/viewer/icons.tsx b/web/packages/gallery/components/viewer/icons.tsx index 5b8201f459..d3739be83d 100644 --- a/web/packages/gallery/components/viewer/icons.tsx +++ b/web/packages/gallery/components/viewer/icons.tsx @@ -21,6 +21,8 @@ const paths = { info: ' void; /** * Called when the user activates the edit action on an image. + * + * If this callback is not provided, then the edit button is never shown. If + * this callback is provided, then the visibility of the edit button is + * determined by the {@link isEditableImage} property of + * {@link FileViewerFileAnnotation} for the file. */ - onEditImage: (annotatedFile: FileViewerAnnotatedFile) => void; + onEditImage?: (annotatedFile: FileViewerAnnotatedFile) => void; } & Pick; /** @@ -69,6 +75,13 @@ export interface FileViewerFileAnnotation { * `true` if this file is owned by the logged in user (if any). */ isOwnFile: boolean; + /** + * `true` if this is an image which can be edited. + * + * The edit button is shown when this is true. See also the + * {@link onEditImage} option for {@link FileViewerPhotoSwipe} constructor. + */ + isEditableImage: boolean; } /** @@ -147,6 +160,7 @@ export class FileViewerPhotoSwipe { onClose, onAnnotate, onViewInfo, + onEditImage, }: FileViewerPhotoSwipeOptions) { this.files = files; this.opts = { disableDownload }; @@ -405,11 +419,33 @@ export class FileViewerPhotoSwipe { pswp.ui.registerElement({ name: "info", title: t("info"), - order: 15, + order: 16, isButton: true, html: createPSRegisterElementIconHTML("info"), onClick: withCurrentAnnotatedFile(onViewInfo), }); + + if (onEditImage) { + pswp.ui.registerElement({ + name: "edit", + // TODO(PS): + // title: t("edit_image"), + title: pt("Edit image"), + order: 15, + isButton: true, + html: createPSRegisterElementIconHTML("edit"), + onClick: withCurrentAnnotatedFile(onEditImage), + onInit: (buttonElement, pswp) => { + pswp.on("change", () => { + const { annotation } = currentAnnotatedFile(); + buttonElement.classList.toggle( + "pswp--ui-visible", + annotation.isEditableImage, + ); + }); + }, + }); + } }); // Modify the default UI elements.