import { Badge, Box, Icon, IconButton, Icons, Spinner, Text, as, toRem } from 'folds'; import React, { ReactNode, useCallback } from 'react'; import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment'; import FileSaver from 'file-saver'; import { mimeTypeToExt } from '../../utils/mimeTypes'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { useMediaAuthentication } from '../../hooks/useMediaAuthentication'; import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback'; import { decryptFile, downloadEncryptedMedia, downloadMedia, mxcUrlToHttp, } from '../../utils/matrix'; const badgeStyles = { maxWidth: toRem(100) }; type FileDownloadButtonProps = { filename: string; url: string; mimeType: string; encInfo?: EncryptedAttachmentInfo; }; export function FileDownloadButton({ filename, url, mimeType, encInfo }: FileDownloadButtonProps) { const mx = useMatrixClient(); const useAuthentication = useMediaAuthentication(); const [downloadState, download] = useAsyncCallback( useCallback(async () => { const mediaUrl = mxcUrlToHttp(mx, url, useAuthentication) ?? url; const fileContent = encInfo ? await downloadEncryptedMedia(mediaUrl, (encBuf) => decryptFile(encBuf, mimeType, encInfo)) : await downloadMedia(mediaUrl); const fileURL = URL.createObjectURL(fileContent); FileSaver.saveAs(fileURL, filename); return fileURL; }, [mx, url, useAuthentication, mimeType, encInfo, filename]) ); const downloading = downloadState.status === AsyncStatus.Loading; const hasError = downloadState.status === AsyncStatus.Error; return ( {downloading ? ( ) : ( )} ); } export type FileHeaderProps = { body: string; mimeType: string; after?: ReactNode; }; export const FileHeader = as<'div', FileHeaderProps>(({ body, mimeType, after, ...props }, ref) => ( {mimeTypeToExt(mimeType)} {body} {after} ));