From 31d3712dbb23241a34fc204bbd54425f2f36b5a9 Mon Sep 17 00:00:00 2001 From: Borislav Pantaleev Date: Thu, 3 Oct 2024 11:23:51 +0300 Subject: [PATCH] Better media preview/download implementation (#53) * Add download option for non image media * make view media button change the icon during the loading; update readme --- README.md | 1 + src/components/media.tsx | 75 +++++++++++++++++++++++++--------------- 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 66543e8..b10040f 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ The following changes are already implemented: * [Add `Contact support` menu item](https://github.com/etkecc/synapse-admin/pull/45) * [Provide options to delete media and redact events on user erase](https://github.com/etkecc/synapse-admin/pull/49) * [Authenticated Media support](https://github.com/etkecc/synapse-admin/pull/51) +* [Better media preview/download](https://github.com/etkecc/synapse-admin/pull/53) _the list will be updated as new changes are added_ diff --git a/src/components/media.tsx b/src/components/media.tsx index 050c6ec..d1e73f4 100644 --- a/src/components/media.tsx +++ b/src/components/media.tsx @@ -1,7 +1,6 @@ import { get } from "lodash"; import { useState } from "react"; -import Typography from "@mui/material/Typography"; import BlockIcon from "@mui/icons-material/Block"; import IconCancel from "@mui/icons-material/Cancel"; import ClearIcon from "@mui/icons-material/Clear"; @@ -9,10 +8,9 @@ import DeleteSweepIcon from "@mui/icons-material/DeleteSweep"; import FileOpenIcon from "@mui/icons-material/FileOpen"; import LockIcon from "@mui/icons-material/Lock"; import LockOpenIcon from "@mui/icons-material/LockOpen"; -import IconButton from '@mui/material/IconButton'; -import CloseIcon from '@mui/icons-material/Close'; -import ZoomInIcon from '@mui/icons-material/ZoomIn'; -import { Box, Dialog, DialogContent, DialogContentText, DialogTitle, Tooltip, Link } from "@mui/material"; +import DownloadIcon from '@mui/icons-material/Download'; +import DownloadingIcon from '@mui/icons-material/Downloading'; +import { Grid2 as Grid, Box, Dialog, DialogContent, DialogContentText, DialogTitle, Tooltip, Link } from "@mui/material"; import { alpha, useTheme } from "@mui/material/styles"; import { BooleanInput, @@ -314,17 +312,10 @@ export const QuarantineMediaButton = (props: ButtonProps) => { ); }; -export const ViewMediaButton = ({ mxcURL, label, mimetype }) => { - if (!mimetype.startsWith("image/")) { - return ( - <> - - {label} - - - ); - } +export const ViewMediaButton = ({ mxcURL, label, uploadName, mimetype }) => { const translate = useTranslate(); + const [loading, setLoading] = useState(false); + const isImage = mimetype && mimetype.startsWith("image/"); const openFileInNewTab = (blobURL: string) => { const anchorElement = document.createElement("a"); @@ -336,27 +327,54 @@ export const ViewMediaButton = ({ mxcURL, label, mimetype }) => { setTimeout(() => URL.revokeObjectURL(blobURL), 10); }; - const previewFile = async () => { + const downloadFile = async (blobURL: string) => { + console.log("downloadFile", blobURL, uploadName); + const anchorElement = document.createElement("a"); + anchorElement.href = blobURL; + anchorElement.download = uploadName; + document.body.appendChild(anchorElement); + anchorElement.click(); + document.body.removeChild(anchorElement); + setTimeout(() => URL.revokeObjectURL(blobURL), 10);; + }; + + const handleFile = async (preview: boolean) => { + setLoading(true); const response = await fetchAuthenticatedMedia(mxcURL, "original"); const blob = await response.blob(); const blobURL = URL.createObjectURL(blob); - openFileInNewTab(blobURL); + if (preview) { + openFileInNewTab(blobURL); + } else { + downloadFile(blobURL); + } + setLoading(false); }; return ( <> - + - + {isImage && ( + + )} - {label} + + {label} ); @@ -374,9 +392,10 @@ export const MediaIDField = ({ source }) => { return null; } + const uploadName = decodeURIComponent(get(record, "upload_name")?.toString()); const mxcURL = `mxc://${homeserver}/${mediaID}`; - return ; + return ; }; export const ReportMediaContent = ({ source }) => { @@ -390,5 +409,7 @@ export const ReportMediaContent = ({ source }) => { return null; } - return ; + const uploadName = decodeURIComponent(get(record, "event_json.content.body")?.toString()); + + return ; };