Skip to content

Commit

Permalink
Better media preview/download implementation (#53)
Browse files Browse the repository at this point in the history
* Add download option for non image media

* make view media button change the icon during the loading; update readme
  • Loading branch information
beastafk authored Oct 3, 2024
1 parent a15dad4 commit 31d3712
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 27 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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_

Expand Down
75 changes: 48 additions & 27 deletions src/components/media.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
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";
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,
Expand Down Expand Up @@ -314,17 +312,10 @@ export const QuarantineMediaButton = (props: ButtonProps) => {
);
};

export const ViewMediaButton = ({ mxcURL, label, mimetype }) => {
if (!mimetype.startsWith("image/")) {
return (
<>
<Box style={{ whiteSpace: "pre" }}>
{label}
</Box>
</>
);
}
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");
Expand All @@ -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 (
<>
<Box style={{ whiteSpace: "pre" }}>
<Box display="flex" alignItems="center">
<Tooltip title={translate("resources.users_media.action.open")}>
<span>
<Button
onClick={() => previewFile()}
style={{ minWidth: 0, paddingLeft: 0, paddingRight: 0 }}
>
<FileOpenIcon />
</Button>
{isImage && (
<Button
disabled={loading}
onClick={() => handleFile(true)}
style={{ minWidth: 0, padding: 0, marginRight: 8 }}
>
{loading ? <DownloadingIcon /> : <FileOpenIcon />}
</Button>
)}
</span>
</Tooltip>
{label}
<Button
disabled={loading}
onClick={() => handleFile(false)}
style={{ minWidth: 0, padding: 0, marginRight: 8 }}
>
{loading ? <DownloadingIcon /> : <DownloadIcon />}
</Button>
<span>{label}</span>
</Box>
</>
);
Expand All @@ -374,9 +392,10 @@ export const MediaIDField = ({ source }) => {
return null;
}

const uploadName = decodeURIComponent(get(record, "upload_name")?.toString());
const mxcURL = `mxc://${homeserver}/${mediaID}`;

return <ViewMediaButton mxcURL={mxcURL} label={mediaID} mimetype={record.media_type}/>;
return <ViewMediaButton mxcURL={mxcURL} label={mediaID} uploadName={uploadName} mimetype={record.media_type}/>;
};

export const ReportMediaContent = ({ source }) => {
Expand All @@ -390,5 +409,7 @@ export const ReportMediaContent = ({ source }) => {
return null;
}

return <ViewMediaButton mxcURL={mxcURL} label={mxcURL} mimetype={record.media_type}/>;
const uploadName = decodeURIComponent(get(record, "event_json.content.body")?.toString());

return <ViewMediaButton mxcURL={mxcURL} label={mxcURL} uploadName={uploadName} mimetype={record.media_type}/>;
};

0 comments on commit 31d3712

Please sign in to comment.