diff --git a/src/browser/app/profile/features.inc b/src/browser/app/profile/features.inc index 78cdc5ee8b..a44636f06b 100644 --- a/src/browser/app/profile/features.inc +++ b/src/browser/app/profile/features.inc @@ -140,3 +140,6 @@ pref('zen.splitView.rearrange-hover-size', 24); // Zen Download Animations pref('zen.downloads.download-animation', true); pref('zen.downloads.download-animation-duration', 1000); // ms + +// Zen Download Notifications +pref('zen.downloads.download-notifications', true); \ No newline at end of file diff --git a/src/zen/downloads/ZenDownloadAnimation.mjs b/src/zen/downloads/ZenDownloadAnimation.mjs index 10f7c20556..cc475284b3 100644 --- a/src/zen/downloads/ZenDownloadAnimation.mjs +++ b/src/zen/downloads/ZenDownloadAnimation.mjs @@ -34,6 +34,15 @@ const list = await Downloads.getList(Downloads.ALL); list.addView({ onDownloadAdded: this.#handleNewDownload.bind(this), + onDownloadChanged: download => { + if (download.succeeded) { + this.#handleDownloadComplete(download); + } else if (download.canceled) { + this.#handleDownloadCanceled(download); + } else if (download.error) { + this.#handleDownloadFailed(download); + } + }, }); } catch (error) { console.error( @@ -57,6 +66,45 @@ this.#animateDownload(this.#lastClickPosition); } + async #handleDownloadComplete(download) { + if (!Services.prefs.getBoolPref('zen.downloads.download-notifications')) { + return; + } + const title = await document.l10n.formatValue('zen-download-complete') ?? 'Download Complete'; + const body = await document.l10n.formatValue('zen-download-complete-body', { filename: download.target.path }) ?? + `File "${download.target.path}" has finished downloading.`; + const notification = new Notification(title, { + body: body, + icon: 'chrome://browser/skin/downloads/download.svg', + }); + } + + async #handleDownloadCanceled(download) { + if (!Services.prefs.getBoolPref('zen.downloads.download-notifications')) { + return; + } + const title = await document.l10n.formatValue('zen-download-canceled') ?? 'Download Canceled'; + const body = await document.l10n.formatValue('zen-download-canceled-body', { filename: download.target.path }) ?? + `File "${download.target.path}" download was canceled.`; + const notification = new Notification(title, { + body: body, + icon: 'chrome://browser/skin/downloads/download.svg', + }); + } + + async #handleDownloadFailed(download) { + if (!Services.prefs.getBoolPref('zen.downloads.download-notifications')) { + return; + } + const title = await document.l10n.formatValue('zen-download-failed') ?? 'Download Failed'; + const body = await document.l10n.formatValue('zen-download-failed-body', { filename: download.target.path }) ?? + `Failed to download file "${download.target.path}".`; + const notification = new Notification(title, { + body: body, + icon: 'chrome://browser/skin/downloads/download.svg', + }); + } + #animateDownload(startPosition) { let animationElement = document.querySelector('zen-download-animation');