Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/app/components/DeviceVerificationSetup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import {
color,
Spinner,
} from 'folds';
import FileSaver from 'file-saver';
import to from 'await-to-js';
import { AuthDict, IAuthData, MatrixError, UIAuthCallback } from 'matrix-js-sdk';
import { saveFile } from '../utils/file-saver';
import { PasswordInput } from './password-input';
import { ContainerColor } from '../styles/ContainerColor.css';
import { copyToClipboard } from '../utils/dom';
Expand Down Expand Up @@ -238,7 +238,7 @@ function RecoveryKeyDisplay({ recoveryKey }: RecoveryKeyDisplayProps) {
const blob = new Blob([recoveryKey], {
type: 'text/plain;charset=us-ascii',
});
FileSaver.saveAs(blob, 'recovery-key.txt');
saveFile(blob, 'recovery-key.txt');
};

const safeToDisplayKey = show ? recoveryKey : recoveryKey.replace(/[^\s]/g, '*');
Expand Down
7 changes: 4 additions & 3 deletions src/app/components/Pdf-viewer/PdfViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
config,
} from 'folds';
import FocusTrap from 'focus-trap-react';
import FileSaver from 'file-saver';
import { saveFile } from '../../utils/file-saver';
import * as css from './PdfViewer.css';
import { AsyncStatus } from '../../hooks/useAsyncCallback';
import { useZoom } from '../../hooks/useZoom';
Expand Down Expand Up @@ -77,8 +77,9 @@ export const PdfViewer = as<'div', PdfViewerProps>(
}
}, [docState, pageNo, zoom]);

const handleDownload = () => {
FileSaver.saveAs(src, name);
const handleDownload = async () => {
const blob = await fetch(src).then((r) => r.blob());
await saveFile(blob, name);
};

const handleJumpSubmit: FormEventHandler<HTMLFormElement> = (evt) => {
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/image-viewer/ImageViewer.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
import React from 'react';
import FileSaver from 'file-saver';
import classNames from 'classnames';
import { Box, Chip, Header, Icon, IconButton, Icons, Text, as } from 'folds';
import { saveFile } from '../../utils/file-saver';
import * as css from './ImageViewer.css';
import { useZoom } from '../../hooks/useZoom';
import { usePan } from '../../hooks/usePan';
Expand All @@ -21,7 +21,7 @@ export const ImageViewer = as<'div', ImageViewerProps>(

const handleDownload = async () => {
const fileContent = await downloadMedia(src);
FileSaver.saveAs(fileContent, alt);
await saveFile(fileContent, alt);
};

return (
Expand Down
6 changes: 2 additions & 4 deletions src/app/components/message/FileHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
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 { saveFile } from '../../utils/file-saver';
import { mimeTypeToExt } from '../../utils/mimeTypes';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
Expand Down Expand Up @@ -33,9 +33,7 @@ export function FileDownloadButton({ filename, url, mimeType, encInfo }: FileDow
? await downloadEncryptedMedia(mediaUrl, (encBuf) => decryptFile(encBuf, mimeType, encInfo))
: await downloadMedia(mediaUrl);

const fileURL = URL.createObjectURL(fileContent);
FileSaver.saveAs(fileURL, filename);
return fileURL;
await saveFile(fileContent, filename);
}, [mx, url, useAuthentication, mimeType, encInfo, filename])
);

Expand Down
12 changes: 3 additions & 9 deletions src/app/components/message/content/FileContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import {
TooltipProvider,
as,
} from 'folds';
import FileSaver from 'file-saver';
import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
import FocusTrap from 'focus-trap-react';
import { saveFile } from '../../../utils/file-saver';
import { IFileInfo } from '../../../../types/matrix/common';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
Expand Down Expand Up @@ -261,9 +261,7 @@ export function DownloadFile({ body, mimeType, url, info, encInfo }: DownloadFil
? await downloadEncryptedMedia(mediaUrl, (encBuf) => decryptFile(encBuf, mimeType, encInfo))
: await downloadMedia(mediaUrl);

const fileURL = URL.createObjectURL(fileContent);
FileSaver.saveAs(fileURL, body);
return fileURL;
await saveFile(fileContent, body);
}, [mx, url, useAuthentication, mimeType, encInfo, body])
);

Expand All @@ -275,11 +273,7 @@ export function DownloadFile({ body, mimeType, url, info, encInfo }: DownloadFil
fill="Soft"
radii="300"
size="400"
onClick={() =>
downloadState.status === AsyncStatus.Success
? FileSaver.saveAs(downloadState.data, body)
: download()
}
onClick={() => download()}
disabled={downloadState.status === AsyncStatus.Loading}
before={
downloadState.status === AsyncStatus.Loading ? (
Expand Down
4 changes: 2 additions & 2 deletions src/app/features/settings/devices/LocalBackup.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { FormEventHandler, useCallback, useEffect, useState } from 'react';
import { Box, Button, color, Icon, Icons, Spinner, Text, toRem } from 'folds';
import FileSaver from 'file-saver';
import { saveFile } from '../../../utils/file-saver';
import { SequenceCard } from '../../../components/sequence-card';
import { SettingTile } from '../../../components/setting-tile';
import { SequenceCardStyle } from '../styles.css';
Expand Down Expand Up @@ -28,7 +28,7 @@ function ExportKeys() {
const blob = new Blob([encKeys], {
type: 'text/plain;charset=us-ascii',
});
FileSaver.saveAs(blob, 'cinny-keys.txt');
await saveFile(blob, 'cinny-keys.txt');
},
[mx]
)
Expand Down
28 changes: 28 additions & 0 deletions src/app/utils/file-saver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import FileSaver from 'file-saver';

const isTauri = typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window;

export async function saveFile(blob: Blob, fileName: string): Promise<void> {
if (!isTauri) {
FileSaver.saveAs(blob, fileName);
return;
}

const { save } = await import('@tauri-apps/plugin-dialog');
const { writeFile } = await import('@tauri-apps/plugin-fs');

const filePath = await save({
defaultPath: fileName,
filters: [{ name: 'File', extensions: [getExt(fileName)] }],
});
Comment on lines +14 to +17
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested on my Mac:

Image


if (filePath === null) return;

const buffer = await blob.arrayBuffer();
await writeFile(filePath, new Uint8Array(buffer));
}

function getExt(fileName: string): string {
const idx = fileName.lastIndexOf('.');
return idx >= 0 ? fileName.slice(idx + 1) : '*';
}
Loading