Skip to content

Commit

Permalink
Merge branch 'Expensify:main' into 41906-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
Rachid L authored May 29, 2024
2 parents 8c0ef9e + 6726431 commit 9a6f4d9
Show file tree
Hide file tree
Showing 235 changed files with 3,299 additions and 1,992 deletions.
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001047605
versionName "1.4.76-5"
versionCode 1001047700
versionName "1.4.77-0"
// Supported language variants must be declared here to avoid from being removed during the compilation.
// This also helps us to not include unnecessary language variants in the APK.
resConfigs "en", "es"
Expand Down
12 changes: 12 additions & 0 deletions assets/images/receipt-plus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions desktop/ELECTRON_EVENTS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ const ELECTRON_EVENTS = {
KEYBOARD_SHORTCUTS_PAGE: 'keyboard-shortcuts-page',
START_UPDATE: 'start-update',
UPDATE_DOWNLOADED: 'update-downloaded',
DOWNLOAD: 'download',
DOWNLOAD_COMPLETED: 'download-completed',
DOWNLOAD_FAILED: 'download-started',
DOWNLOAD_CANCELED: 'download-canceled',
SILENT_UPDATE: 'silent-update',
} as const;

Expand Down
11 changes: 10 additions & 1 deletion desktop/contextBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,19 @@ const WHITELIST_CHANNELS_RENDERER_TO_MAIN = [
ELECTRON_EVENTS.REQUEST_VISIBILITY,
ELECTRON_EVENTS.START_UPDATE,
ELECTRON_EVENTS.LOCALE_UPDATED,
ELECTRON_EVENTS.DOWNLOAD,
ELECTRON_EVENTS.SILENT_UPDATE,
] as const;

const WHITELIST_CHANNELS_MAIN_TO_RENDERER = [ELECTRON_EVENTS.KEYBOARD_SHORTCUTS_PAGE, ELECTRON_EVENTS.UPDATE_DOWNLOADED, ELECTRON_EVENTS.FOCUS, ELECTRON_EVENTS.BLUR] as const;
const WHITELIST_CHANNELS_MAIN_TO_RENDERER = [
ELECTRON_EVENTS.KEYBOARD_SHORTCUTS_PAGE,
ELECTRON_EVENTS.UPDATE_DOWNLOADED,
ELECTRON_EVENTS.FOCUS,
ELECTRON_EVENTS.BLUR,
ELECTRON_EVENTS.DOWNLOAD_COMPLETED,
ELECTRON_EVENTS.DOWNLOAD_FAILED,
ELECTRON_EVENTS.DOWNLOAD_CANCELED,
] as const;

const getErrorMessage = (channel: string): string => `Electron context bridge cannot be used with channel '${channel}'`;

Expand Down
116 changes: 116 additions & 0 deletions desktop/createDownloadQueue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import type {BrowserWindow} from 'electron';
import {app} from 'electron';
import * as path from 'path';
import createQueue from '@libs/Queue/Queue';
import CONST from '@src/CONST';
import ELECTRON_EVENTS from './ELECTRON_EVENTS';
import type Options from './electronDownloadManagerType';

type DownloadItem = {
// The window where the download will be initiated
win: BrowserWindow;

// The URL of the file to be downloaded
url: string;

// The options for the download, such as save path, file name, etc.
options: Options;
};

/**
* Returns the filename with extension based on the given name and MIME type.
* @param name - The name of the file.
* @param mime - The MIME type of the file.
* @returns The filename with extension.
*/
const getFilenameFromMime = (name: string, mime: string): string => {
const extensions = mime.split('/').pop();
return `${name}.${extensions}`;
};

const createDownloadQueue = () => {
const downloadItemProcessor = (item: DownloadItem): Promise<void> =>
new Promise((resolve, reject) => {
let downloadTimeout: NodeJS.Timeout;
let downloadListener: (event: Electron.Event, electronDownloadItem: Electron.DownloadItem) => void;

const timeoutFunction = () => {
item.win.webContents.session.removeListener('will-download', downloadListener);
resolve();
};

const listenerFunction = (event: Electron.Event, electronDownloadItem: Electron.DownloadItem) => {
clearTimeout(downloadTimeout);

const options = item.options;
const cleanup = () => item.win.webContents.session.removeListener('will-download', listenerFunction);
const errorMessage = `The download of ${electronDownloadItem.getFilename()} was interrupted`;

if (options.directory && !path.isAbsolute(options.directory)) {
throw new Error('The `directory` option must be an absolute path');
}

const directory = options.directory ?? app.getPath('downloads');

let filePath: string;
if (options.filename) {
filePath = path.join(directory, options.filename);
} else {
const filename = electronDownloadItem.getFilename();
const name = path.extname(filename) ? filename : getFilenameFromMime(filename, electronDownloadItem.getMimeType());

filePath = options.overwrite ? path.join(directory, name) : path.join(directory, name);
}

if (options.saveAs) {
electronDownloadItem.setSaveDialogOptions({defaultPath: filePath, ...options.dialogOptions});
} else {
electronDownloadItem.setSavePath(filePath);
}

electronDownloadItem.on('updated', (_, state) => {
if (state !== 'interrupted') {
return;
}

item.win.webContents.send(ELECTRON_EVENTS.DOWNLOAD_CANCELED, {url: item.url});
cleanup();
reject(new Error(errorMessage));
electronDownloadItem.cancel();
});

electronDownloadItem.on('done', (_, state) => {
cleanup();
if (state === 'cancelled') {
item.win.webContents.send(ELECTRON_EVENTS.DOWNLOAD_CANCELED, {url: item.url});
resolve();
} else if (state === 'interrupted') {
item.win.webContents.send(ELECTRON_EVENTS.DOWNLOAD_FAILED, {url: item.url});
reject(new Error(errorMessage));
} else if (state === 'completed') {
if (process.platform === 'darwin') {
const savePath = electronDownloadItem.getSavePath();
app.dock.downloadFinished(savePath);
}
item.win.webContents.send(ELECTRON_EVENTS.DOWNLOAD_COMPLETED, {url: item.url});
resolve();
}
});
};

downloadTimeout = setTimeout(timeoutFunction, CONST.DOWNLOADS_TIMEOUT);
downloadListener = listenerFunction;

item.win.webContents.downloadURL(item.url);
item.win.webContents.session.on('will-download', downloadListener);
});

const queue = createQueue<DownloadItem>(downloadItemProcessor);

const enqueueDownloadItem = (item: DownloadItem): void => {
queue.enqueue(item);
};
return {enqueueDownloadItem, dequeueDownloadItem: queue.dequeue};
};

export default createDownloadQueue;
49 changes: 49 additions & 0 deletions desktop/electronDownloadManagerType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type {SaveDialogOptions} from 'electron';

type Options = {
/**
Show a `Save As…` dialog instead of downloading immediately.
Note: Only use this option when strictly necessary. Downloading directly without a prompt is a much better user experience.
@default false
*/
readonly saveAs?: boolean;

/**
The directory to save the file in.
Must be an absolute path.
Default: [User's downloads directory](https://electronjs.org/docs/api/app/#appgetpathname)
*/
readonly directory?: string;

/**
Name of the saved file.
This option only makes sense for `electronDownloadManager.download()`.
Default: [`downloadItem.getFilename()`](https://electronjs.org/docs/api/download-item/#downloaditemgetfilename)
*/
readonly filename?: string;

/**
Allow downloaded files to overwrite files with the same name in the directory they are saved to.
The default behavior is to append a number to the filename.
@default false
*/
readonly overwrite?: boolean;

/**
Customize the save dialog.
If `defaultPath` is not explicity defined, a default value is assigned based on the file path.
@default {}
*/
readonly dialogOptions?: SaveDialogOptions;
};

export default Options;
11 changes: 11 additions & 0 deletions desktop/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import type PlatformSpecificUpdater from '@src/setup/platformSetup/types';
import type {Locale} from '@src/types/onyx';
import ELECTRON_EVENTS from './ELECTRON_EVENTS';

const createDownloadQueue = require('./createDownloadQueue').default;

const port = process.env.PORT ?? 8082;
const {DESKTOP_SHORTCUT_ACCELERATOR, LOCALES} = CONST;

Expand Down Expand Up @@ -613,6 +615,15 @@ const mainWindow = (): Promise<void> => {
}
});

const downloadQueue = createDownloadQueue();
ipcMain.on(ELECTRON_EVENTS.DOWNLOAD, (event, downloadData) => {
const downloadItem = {
...downloadData,
win: browserWindow,
};
downloadQueue.enqueueDownloadItem(downloadItem);
});

// Automatically check for and install the latest version in the background
ipcMain.on(ELECTRON_EVENTS.SILENT_UPDATE, () => {
if (isSilentUpdating) {
Expand Down
3 changes: 2 additions & 1 deletion docs/redirects.csv
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,5 @@ https://help.expensify.com/articles/new-expensify/expenses/Referral-Program.html
https://help.expensify.com/articles/new-expensify/workspaces/The-Free-Plan,https://help.expensify.com/new-expensify/hubs/workspaces/
https://help.expensify.com/new-expensify/hubs/expenses/Connect-a-Bank-Account,https://help.expensify.com/articles/new-expensify/expenses/Connect-a-Business-Bank-Account
https://help.expensify.com/articles/new-expensify/settings/Security,https://help.expensify.com/articles/new-expensify/settings/Encryption-and-Data-Security
https://help.expensify.com/articles/expensify-classic/workspaces/reports/Currency,https://help.expensify.com/articles/expensify-classic/workspaces/Currency
https://help.expensify.com/articles/expensify-classic/workspaces/reports/Currency,https://help.expensify.com/articles/expensify-classic/workspaces/Currency
https://help.expensify.com/articles/new-expensify/bank-accounts-and-payments/Connect-a-Bank-Account.html,https://help.expensify.com/articles/new-expensify/expenses/Connect-a-Business-Bank-Account
4 changes: 2 additions & 2 deletions ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.4.76</string>
<string>1.4.77</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
Expand All @@ -40,7 +40,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.4.76.5</string>
<string>1.4.77.0</string>
<key>FullStory</key>
<dict>
<key>OrgId</key>
Expand Down
4 changes: 2 additions & 2 deletions ios/NewExpensifyTests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.4.76</string>
<string>1.4.77</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.4.76.5</string>
<string>1.4.77.0</string>
</dict>
</plist>
4 changes: 2 additions & 2 deletions ios/NotificationServiceExtension/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundleShortVersionString</key>
<string>1.4.76</string>
<string>1.4.77</string>
<key>CFBundleVersion</key>
<string>1.4.76.5</string>
<string>1.4.77.0</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
Expand Down
38 changes: 12 additions & 26 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 9a6f4d9

Please sign in to comment.