Skip to content

Commit

Permalink
Remove unused functionalities / types
Browse files Browse the repository at this point in the history
  • Loading branch information
wildan-m committed Feb 27, 2024
1 parent b902719 commit 1200701
Show file tree
Hide file tree
Showing 4 changed files with 8 additions and 198 deletions.
155 changes: 6 additions & 149 deletions src/libs/downloadQueue/electronDownloadManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
* We decided to replicate the functionality of the `electron-dl` package for easier maintenance.
* More context: https://github.com/Expensify/App/issues/35189#issuecomment-1959681109
*/
import type {BrowserView, DownloadItem, Event, Session, WebContents} from 'electron';
import {app, BrowserWindow, dialog, shell} from 'electron';
import type {BrowserView, BrowserWindow, DownloadItem, Event, Session} from 'electron';
import {app, shell} from 'electron';
import * as path from 'path';
import type {Options} from './electronDownloadManagerType';

Expand All @@ -27,79 +27,17 @@ const getFilenameFromMime = (name: string, mime: string): string => {
return `${name}.${extensions}`;
};

/**
* Returns the major version number of Electron.
* @returns The major version number of Electron.
*/
const majorElectronVersion = (): number => {
const version = process.versions.electron.split('.');
return Number.parseInt(version[0], 10);
};

/**
* Retrieves the parent BrowserWindow associated with the given WebContents.
* @param webContents The WebContents object to find the parent BrowserWindow for.
* @returns The parent BrowserWindow if found, otherwise undefined.
*/
const getWindowFromBrowserView = (webContents: WebContents): BrowserWindow | undefined => {
for (const currentWindow of BrowserWindow.getAllWindows()) {
for (const currentBrowserView of currentWindow.getBrowserViews()) {
if (currentBrowserView.webContents.id === webContents.id) {
return currentWindow;
}
}
}
};

/**
* Retrieves the Electron BrowserWindow associated with the given WebContents.
* @param webContents The WebContents object to retrieve the BrowserWindow from.
* @returns The associated BrowserWindow, or undefined if not found.
*/
const getWindowFromWebContents = (webContents: WebContents): BrowserWindow | undefined | null => {
let electronWindow: BrowserWindow | undefined | null;
const webContentsType = webContents.getType();
switch (webContentsType) {
case 'webview':
electronWindow = BrowserWindow.fromWebContents(webContents.hostWebContents);
break;
case 'browserView':
electronWindow = getWindowFromBrowserView(webContents);
break;
default:
electronWindow = BrowserWindow.fromWebContents(webContents);
break;
}

return electronWindow;
};

/**
* Registers a listener for download events in Electron session.
*
* @param session - The Electron session to register the listener on.
* @param prevOptions - The previous options for the download manager.
* @param options - The previous options for the download manager.
* @param callback - The callback function to be called when a download event occurs.
*/
const registerListener = (session: Session, prevOptions: Options, callback: (error: Error | null, item?: DownloadItem) => void = () => {}): void => {
const registerListener = (session: Session, options: Options, callback: (error: Error | null, item?: DownloadItem) => void = () => {}): void => {
const downloadItems = new Set<DownloadItem>();
let receivedBytes = 0;
let completedBytes = 0;
let totalBytes = 0;
const activeDownloadItems = (): number => downloadItems.size;
const progressDownloadItems = (): number => receivedBytes / totalBytes;

const options = {
showBadge: true,
showProgressBar: true,
...prevOptions,
};

const listener = (event: Event, item: DownloadItem, webContents: WebContents): void => {
const listener = (event: Event, item: DownloadItem): void => {
downloadItems.add(item);
totalBytes += item.getTotalBytes();

const electronWindow = majorElectronVersion() >= 12 ? BrowserWindow.fromWebContents(webContents) : getWindowFromWebContents(webContents);

if (options.directory && !path.isAbsolute(options.directory)) {
throw new Error('The `directory` option must be an absolute path');
Expand All @@ -123,55 +61,9 @@ const registerListener = (session: Session, prevOptions: Options, callback: (err
item.setSavePath(filePath);
}

item.on('updated', () => {
receivedBytes = completedBytes;
for (const downloadItem of downloadItems) {
receivedBytes += downloadItem.getReceivedBytes();
}

if (options.showBadge && ['darwin', 'linux'].includes(process.platform)) {
app.badgeCount = activeDownloadItems();
}

if (!electronWindow?.isDestroyed() && options.showProgressBar) {
electronWindow?.setProgressBar(progressDownloadItems());
}

if (typeof options.onProgress === 'function') {
const itemTransferredBytes = item.getReceivedBytes();
const itemTotalBytes = item.getTotalBytes();

options.onProgress({
percent: itemTotalBytes ? itemTransferredBytes / itemTotalBytes : 0,
transferredBytes: itemTransferredBytes,
totalBytes: itemTotalBytes,
});
}

if (typeof options.onTotalProgress === 'function') {
options.onTotalProgress({
percent: progressDownloadItems(),
transferredBytes: receivedBytes,
totalBytes,
});
}
});

item.on('done', (doneEvent: Event, state: string) => {
completedBytes += item.getTotalBytes();
downloadItems.delete(item);

if (options.showBadge && ['darwin', 'linux'].includes(process.platform)) {
app.badgeCount = activeDownloadItems();
}

if (!electronWindow?.isDestroyed() && !activeDownloadItems()) {
electronWindow?.setProgressBar(-1);
receivedBytes = 0;
completedBytes = 0;
totalBytes = 0;
}

if (options.unregisterWhenDone) {
session.removeListener('will-download', listener);
}
Expand Down Expand Up @@ -209,45 +101,11 @@ const registerListener = (session: Session, prevOptions: Options, callback: (err
callback(null, item);
}
});

if (typeof options.onStarted === 'function') {
options.onStarted(item);
}
};

session.on('will-download', listener);
};

/**
Register the helper for all windows.
@example
```
import {app, BrowserWindow} from 'electron';
import electronDownloadManager = require('./electronDownloadManager');
electronDownloadManager();
let win;
(async () => {
await app.whenReady();
win = new BrowserWindow();
})();
```
*/
export default (options: Options = {}): void => {
app.on('session-created', (session: Session) => {
registerListener(session, options, (error: Error | null) => {
if (!error || error instanceof CancelError) {
return;
}

const errorTitle = options.errorMessage ?? 'Download Error';
dialog.showErrorBox(errorTitle, error.message);
});
});
};

/**
This can be useful if you need download functionality in a reusable module.
Expand Down Expand Up @@ -289,5 +147,4 @@ const download = (electronWindow: BrowserWindow | BrowserView, url: string, prev
});
};

export {download};
export type {CancelError, Options};
export default download;
46 changes: 1 addition & 45 deletions src/libs/downloadQueue/electronDownloadManagerType.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
import type {DownloadItem, SaveDialogOptions} from 'electron';

type Progress = {
// The percentage of the download that has been completed
percent: number;

// The number of bytes that have been downloaded so far
transferredBytes: number;

// The total number of bytes in the file being downloaded
totalBytes: number;
};

type File = {
// The name of the file being downloaded
filename: string;
Expand Down Expand Up @@ -72,25 +61,6 @@ type Options = {
*/
readonly errorMessage?: string;

/**
Optional callback that receives the [download item](https://electronjs.org/docs/api/download-item).
You can use this for advanced handling such as canceling the item like `item.cancel()`.
*/
readonly onStarted?: (item: DownloadItem) => void;

/**
Optional callback that receives an object containing information about the progress of the current download item.
*/
readonly onProgress?: (progress: Progress) => void;

/**
Optional callback that receives an object containing information about the combined progress of all download items done within any registered window.
Each time a new download is started, the next callback will include it. The progress percentage could therefore become smaller again.
This callback provides the same data that is used for the progress bar on the app icon.
*/
readonly onTotalProgress?: (progress: Progress) => void;

/**
Optional callback that receives the [download item](https://electronjs.org/docs/api/download-item) for which the download has been cancelled.
*/
Expand All @@ -108,20 +78,6 @@ type Options = {
*/
readonly openFolderWhenDone?: boolean;

/**
Show a file count badge on the macOS/Linux dock/taskbar icon when a download is in progress.
@default true
*/
readonly showBadge?: boolean;

/**
Show a progress bar on the dock/taskbar icon when a download is in progress.
@default true
*/
readonly showProgressBar?: boolean;

/**
Allow downloaded files to overwrite files with the same name in the directory they are saved to.
Expand All @@ -144,4 +100,4 @@ type Options = {
readonly unregisterWhenDone?: boolean;
};

export type {Options, File, Progress};
export type {Options, File};
2 changes: 1 addition & 1 deletion src/libs/downloadQueue/index.desktop.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {BrowserWindow} from 'electron';
import {download as electronDownload} from './electronDownloadManager';
import electronDownload from './electronDownloadManager';
import type {Options} from './electronDownloadManagerType';

type DownloadItem = {
Expand Down
3 changes: 0 additions & 3 deletions src/libs/fileDownload/index.desktop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ const fileDownload: FileDownload = (url, fileName) => {
const options: Options = {
filename: fileName,
saveAs: true,
// showing badge and progress bar only supported on macos and linux, better to disable it
showBadge: false,
showProgressBar: false,
};
window.electron.send(ELECTRON_EVENTS.DOWNLOAD, {url, options});

Expand Down

0 comments on commit 1200701

Please sign in to comment.