This commit is contained in:
Manav Rathi 2024-10-11 12:32:38 +05:30
parent b92e9e366b
commit 06f19b26d2
No known key found for this signature in database
5 changed files with 53 additions and 28 deletions

View File

@ -11,13 +11,13 @@ import { photosDialogZIndex } from "@/new/photos/components/z-index";
import downloadManager from "@/new/photos/services/download";
import { AppContext } from "@/new/photos/types/context";
import { EnteFile } from "@/new/photos/types/file";
import { downloadAndRevokeObjectURL } from "@/new/photos/utils/web";
import { ensure } from "@/utils/ensure";
import {
CenteredFlex,
HorizontalFlex,
} from "@ente/shared/components/Container";
import { EnteMenuItem } from "@ente/shared/components/Menu/EnteMenuItem";
import { downloadUsingAnchor } from "@ente/shared/utils";
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import CloseIcon from "@mui/icons-material/Close";
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
@ -462,8 +462,7 @@ const ImageEditorOverlay = (props: IProps) => {
if (!canvasRef.current) return;
const f = await getEditedFile();
// Revokes the URL after downloading.
downloadUsingAnchor(URL.createObjectURL(f), f.name);
downloadAndRevokeObjectURL(URL.createObjectURL(f), f.name);
};
const saveCopyToEnte = async () => {

View File

@ -19,10 +19,10 @@ import { detectFileTypeInfo } from "@/new/photos/utils/detect-type";
import { mergeMetadata } from "@/new/photos/utils/file";
import { safeFileName } from "@/new/photos/utils/native-fs";
import { writeStream } from "@/new/photos/utils/native-stream";
import { downloadAndRevokeObjectURL } from "@/new/photos/utils/web";
import { withTimeout } from "@/utils/promise";
import { LS_KEYS, getData } from "@ente/shared/storage/localStorage";
import type { User } from "@ente/shared/user/types";
import { downloadUsingAnchor } from "@ente/shared/utils";
import { t } from "i18next";
import {
addMultipleToFavorites,
@ -70,8 +70,8 @@ export async function downloadFile(file: EnteFile) {
const tempVideoURL = URL.createObjectURL(
new Blob([videoData], { type: videoType.mimeType }),
);
downloadUsingAnchor(tempImageURL, imageFileName);
downloadUsingAnchor(tempVideoURL, videoFileName);
downloadAndRevokeObjectURL(tempImageURL, imageFileName);
downloadAndRevokeObjectURL(tempVideoURL, videoFileName);
} else {
const fileType = await detectFileTypeInfo(
new File([fileBlob], file.metadata.title),
@ -81,7 +81,7 @@ export async function downloadFile(file: EnteFile) {
).blob();
fileBlob = new Blob([fileBlob], { type: fileType.mimeType });
const tempURL = URL.createObjectURL(fileBlob);
downloadUsingAnchor(tempURL, file.metadata.title);
downloadAndRevokeObjectURL(tempURL, file.metadata.title);
}
} catch (e) {
log.error("failed to download file", e);

View File

@ -12,7 +12,6 @@ import { ensure } from "@/utils/ensure";
import CodeBlock from "@ente/shared/components/CodeBlock";
import DialogTitleWithCloseButton from "@ente/shared/components/DialogBox/TitleWithCloseButton";
import { getRecoveryKey } from "@ente/shared/crypto/helpers";
import { downloadAsFile } from "@ente/shared/utils";
import {
Box,
Button,
@ -25,6 +24,7 @@ import {
import * as bip39 from "bip39";
import { t } from "i18next";
import { useEffect, useState } from "react";
import { downloadString } from "../utils/web";
// mobile client library only supports english.
bip39.setDefaultWordlist("english");
@ -62,7 +62,7 @@ export const RecoveryKey: React.FC<ModalVisibilityProps> = ({
}, [open]);
function onSaveClick() {
downloadAsFile(RECOVERY_KEY_FILE_NAME, ensure(recoveryKey));
downloadRecoveryKeyMnemonic(ensure(recoveryKey));
onClose();
}
@ -111,3 +111,6 @@ const DashedBorderWrapper = styled(Box)(({ theme }) => ({
const getRecoveryKeyMnemonic = async () =>
bip39.entropyToMnemonic(await getRecoveryKey());
const downloadRecoveryKeyMnemonic = (key: string) =>
downloadString(key, RECOVERY_KEY_FILE_NAME);

View File

@ -21,3 +21,45 @@ export const initiateEmail = (email: string) => {
a.rel = "noopener";
a.click();
};
/**
* Download the asset at the given {@link url} to a file on the user's download
* folder by appending a temporary <a> element to the DOM.
*
* @param url The URL that we want to download. See also
* {@link downloadAndRevokeObjectURL} and {@link downloadString}.
*
* @param fileName The name of downloaded file.
*/
export const downloadURL = (url: string, fileName: string) => {
const a = document.createElement("a");
a.style.display = "none";
a.href = url;
a.download = fileName;
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(url);
a.remove();
};
/**
* A variant of {@link downloadURL} that also revokes the provided
* {@link objectURL} after initiating the download.
*/
export const downloadAndRevokeObjectURL = (url: string, fileName: string) => {
downloadURL(url, fileName);
URL.revokeObjectURL(url);
};
/**
* Save the given string {@link s} as a file in the user's download folder.
*
* @param s The string to save.
*
* @param fileName The name of the file that gets saved.
*/
export const downloadString = (s: string, fileName: string) => {
const file = new Blob([s], { type: "text/plain" });
const fileURL = URL.createObjectURL(file);
downloadAndRevokeObjectURL(fileURL, fileName);
};

View File

@ -1,25 +1,6 @@
import { ensure } from "@/utils/ensure";
import { wait } from "@/utils/promise";
export function downloadAsFile(filename: string, content: string) {
const file = new Blob([content], {
type: "text/plain",
});
const fileURL = URL.createObjectURL(file);
downloadUsingAnchor(fileURL, filename);
}
export function downloadUsingAnchor(link: string, name: string) {
const a = document.createElement("a");
a.style.display = "none";
a.href = link;
a.download = name;
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(link);
a.remove();
}
export async function retryAsyncFunction<T>(
request: (abort?: () => void) => Promise<T>,
waitTimeBeforeNextTry?: number[],