diff --git a/app/main/handle-external-link.ts b/app/main/handle-external-link.ts index 0a75a0cbd..f3a013c88 100644 --- a/app/main/handle-external-link.ts +++ b/app/main/handle-external-link.ts @@ -1,5 +1,6 @@ import {shell} from "electron/common"; import type { + BrowserWindow, HandlerDetails, SaveDialogOptions, WebContents, @@ -20,18 +21,21 @@ function isUploadsUrl(server: string, url: URL): boolean { function downloadFile({ contents, url, + win, downloadPath, completed, failed, }: { contents: WebContents; url: string; + win: BrowserWindow; downloadPath: string; completed(filePath: string, fileName: string): Promise; failed(state: string): void; }) { contents.downloadURL(url); contents.session.once("will-download", async (_event: Event, item) => { + const totalFileSize = item.getTotalBytes(); if (ConfigUtil.getConfigItem("promptDownload", false)) { const showDialogOptions: SaveDialogOptions = { defaultPath: path.join(downloadPath, item.getFilename()), @@ -59,6 +63,11 @@ function downloadFile({ item.setSavePath(setFilePath); } + let currProgress = 0; + const progressInterval = setInterval(() => { + win.setProgressBar(currProgress / totalFileSize); + }, 1000); + const updatedListener = (_event: Event, state: string): void => { switch (state) { case "interrupted": { @@ -67,15 +76,18 @@ function downloadFile({ "Download interrupted, cancelling and fallback to dialog download.", ); item.cancel(); + win.setProgressBar(-1); break; } case "progressing": { if (item.isPaused()) { item.cancel(); + win.setProgressBar(-1); + break; } - // This event can also be used to show progress in percentage in future. + currProgress = item.getReceivedBytes(); break; } @@ -89,11 +101,16 @@ function downloadFile({ item.once("done", async (_event: Event, state) => { if (state === "completed") { await completed(item.getSavePath(), path.basename(item.getSavePath())); + win.setProgressBar(1); } else { + win.setProgressBar(-1); + clearInterval(progressInterval); console.log("Download failed state:", state); + failed(state); } + clearInterval(progressInterval); // To stop item for listening to updated events of this file item.removeListener("updated", updatedListener); }); @@ -104,6 +121,7 @@ export default function handleExternalLink( contents: WebContents, details: HandlerDetails, mainContents: WebContents, + win: BrowserWindow, ): void { let url: URL; try { @@ -121,6 +139,7 @@ export default function handleExternalLink( downloadFile({ contents, url: url.href, + win, downloadPath, async completed(filePath: string, fileName: string) { const downloadNotification = new Notification({ @@ -128,12 +147,16 @@ export default function handleExternalLink( body: `Click to show ${fileName} in folder`, silent: true, // We'll play our own sound - ding.ogg }); + shell.showItemInFolder(filePath); downloadNotification.on("click", () => { // Reveal file in download folder shell.showItemInFolder(filePath); }); downloadNotification.show(); - + setTimeout(() => { + downloadNotification.close(); + win.setProgressBar(-1); + }, 3000); // Play sound to indicate download complete if (!ConfigUtil.getConfigItem("silent", false)) { send(mainContents, "play-ding-sound"); diff --git a/app/main/index.ts b/app/main/index.ts index 523258fac..5e0aacf6c 100644 --- a/app/main/index.ts +++ b/app/main/index.ts @@ -179,7 +179,7 @@ function createMainWindow(): BrowserWindow { app.on("web-contents-created", (_event: Event, contents: WebContents) => { contents.setWindowOpenHandler((details) => { - handleExternalLink(contents, details, page); + handleExternalLink(contents, details, page, mainWindow); return {action: "deny"}; }); }); diff --git a/app/renderer/js/main.ts b/app/renderer/js/main.ts index 2830fbac6..5e2d84b15 100644 --- a/app/renderer/js/main.ts +++ b/app/renderer/js/main.ts @@ -191,7 +191,7 @@ export class ServerManagerView { }, downloadsPath: `${app.getPath("downloads")}`, quitOnClose: false, - promptDownload: false, + promptDownload: true, }; // Platform specific settings