
* Migrate intl_provider to contextBridge * Migrate modalPreload to contextBridge * Migrate loadingScreenPreload to contextBridge * Migrate downloadDropdown preloads to contextBridge * Migrate server dropdown preload to contextBridge * Migrate urlView preload to contextBridge * Merge all desktop API scripts into one * Remove unused communication channel constants
222 lines
7.5 KiB
TypeScript
222 lines
7.5 KiB
TypeScript
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
import {BrowserView, BrowserWindow, ipcMain, IpcMainEvent} from 'electron';
|
|
|
|
import log from 'electron-log';
|
|
|
|
import {CombinedConfig} from 'types/config';
|
|
import {CoordinatesToJsonType, DownloadedItem, DownloadsMenuOpenEventPayload} from 'types/downloads';
|
|
|
|
import {
|
|
CLOSE_DOWNLOADS_DROPDOWN_MENU,
|
|
DOWNLOADS_DROPDOWN_MENU_CANCEL_DOWNLOAD,
|
|
DOWNLOADS_DROPDOWN_MENU_CLEAR_FILE,
|
|
DOWNLOADS_DROPDOWN_MENU_OPEN_FILE,
|
|
DOWNLOADS_DROPDOWN_MENU_SHOW_FILE_IN_FOLDER,
|
|
EMIT_CONFIGURATION,
|
|
OPEN_DOWNLOADS_DROPDOWN_MENU,
|
|
REQUEST_DOWNLOADS_DROPDOWN_MENU_INFO,
|
|
TOGGLE_DOWNLOADS_DROPDOWN_MENU,
|
|
UPDATE_DOWNLOADS_DROPDOWN_MENU,
|
|
UPDATE_DOWNLOADS_DROPDOWN_MENU_ITEM,
|
|
} from 'common/communication';
|
|
import {
|
|
DOWNLOADS_DROPDOWN_FULL_WIDTH,
|
|
DOWNLOADS_DROPDOWN_MENU_FULL_HEIGHT,
|
|
DOWNLOADS_DROPDOWN_MENU_FULL_WIDTH,
|
|
TAB_BAR_HEIGHT,
|
|
} from 'common/utils/constants';
|
|
import {getLocalPreload, getLocalURLString} from 'main/utils';
|
|
|
|
import WindowManager from '../windows/windowManager';
|
|
import downloadsManager from 'main/downloadsManager';
|
|
|
|
export default class DownloadsDropdownMenuView {
|
|
open: boolean;
|
|
view: BrowserView;
|
|
bounds?: Electron.Rectangle;
|
|
item?: DownloadedItem;
|
|
coordinates?: CoordinatesToJsonType;
|
|
darkMode: boolean;
|
|
window: BrowserWindow;
|
|
windowBounds: Electron.Rectangle;
|
|
|
|
constructor(window: BrowserWindow, darkMode: boolean) {
|
|
this.open = false;
|
|
this.item = undefined;
|
|
this.coordinates = undefined;
|
|
this.window = window;
|
|
this.darkMode = darkMode;
|
|
|
|
this.windowBounds = this.window.getContentBounds();
|
|
this.bounds = this.getBounds(DOWNLOADS_DROPDOWN_MENU_FULL_WIDTH, DOWNLOADS_DROPDOWN_MENU_FULL_HEIGHT);
|
|
|
|
const preload = getLocalPreload('desktopAPI.js');
|
|
this.view = new BrowserView({webPreferences: {
|
|
preload,
|
|
|
|
// Workaround for this issue: https://github.com/electron/electron/issues/30993
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore
|
|
transparent: true,
|
|
}});
|
|
|
|
this.view.webContents.loadURL(getLocalURLString('downloadsDropdownMenu.html'));
|
|
this.window.addBrowserView(this.view);
|
|
|
|
ipcMain.on(OPEN_DOWNLOADS_DROPDOWN_MENU, this.handleOpen);
|
|
ipcMain.on(CLOSE_DOWNLOADS_DROPDOWN_MENU, this.handleClose);
|
|
ipcMain.on(TOGGLE_DOWNLOADS_DROPDOWN_MENU, this.handleToggle);
|
|
ipcMain.on(EMIT_CONFIGURATION, this.updateConfig);
|
|
ipcMain.on(REQUEST_DOWNLOADS_DROPDOWN_MENU_INFO, this.updateDownloadsDropdownMenu);
|
|
ipcMain.on(DOWNLOADS_DROPDOWN_MENU_OPEN_FILE, this.openFile);
|
|
ipcMain.on(DOWNLOADS_DROPDOWN_MENU_SHOW_FILE_IN_FOLDER, this.showFileInFolder);
|
|
ipcMain.on(DOWNLOADS_DROPDOWN_MENU_CANCEL_DOWNLOAD, this.cancelDownload);
|
|
ipcMain.on(DOWNLOADS_DROPDOWN_MENU_CLEAR_FILE, this.clearFile);
|
|
ipcMain.on(UPDATE_DOWNLOADS_DROPDOWN_MENU, this.updateItem);
|
|
}
|
|
|
|
updateItem = (event: IpcMainEvent, item: DownloadedItem) => {
|
|
log.debug('DownloadsDropdownMenuView.updateItem', {item});
|
|
|
|
this.item = item;
|
|
|
|
this.updateDownloadsDropdownMenu();
|
|
}
|
|
|
|
updateConfig = (event: IpcMainEvent, config: CombinedConfig) => {
|
|
log.debug('DownloadsDropdownMenuView.updateConfig');
|
|
|
|
this.darkMode = config.darkMode;
|
|
this.updateDownloadsDropdownMenu();
|
|
}
|
|
|
|
/**
|
|
* This is called every time the "window" is resized so that we can position
|
|
* the downloads dropdown at the correct position
|
|
*/
|
|
updateWindowBounds = () => {
|
|
log.debug('DownloadsDropdownMenuView.updateWindowBounds');
|
|
|
|
this.windowBounds = this.window.getContentBounds();
|
|
this.updateDownloadsDropdownMenu();
|
|
this.repositionDownloadsDropdownMenu();
|
|
}
|
|
|
|
updateDownloadsDropdownMenu = () => {
|
|
log.debug('DownloadsDropdownMenuView.updateDownloadsDropdownMenu');
|
|
|
|
this.view.webContents.send(
|
|
UPDATE_DOWNLOADS_DROPDOWN_MENU,
|
|
this.item,
|
|
this.darkMode,
|
|
);
|
|
ipcMain.emit(UPDATE_DOWNLOADS_DROPDOWN_MENU_ITEM, true, this.item);
|
|
this.repositionDownloadsDropdownMenu();
|
|
}
|
|
|
|
handleOpen = (event: IpcMainEvent, payload: DownloadsMenuOpenEventPayload = {} as DownloadsMenuOpenEventPayload) => {
|
|
log.debug('DownloadsDropdownMenuView.handleOpen', {bounds: this.bounds, payload});
|
|
|
|
if (!this.bounds) {
|
|
return;
|
|
}
|
|
|
|
const {item, coordinates} = payload;
|
|
|
|
log.debug('DownloadsDropdownMenuView.handleOpen', {item, coordinates});
|
|
|
|
this.open = true;
|
|
this.coordinates = coordinates;
|
|
this.item = item;
|
|
this.bounds = this.getBounds(DOWNLOADS_DROPDOWN_MENU_FULL_WIDTH, DOWNLOADS_DROPDOWN_MENU_FULL_HEIGHT);
|
|
this.view.setBounds(this.bounds);
|
|
this.window.setTopBrowserView(this.view);
|
|
this.view.webContents.focus();
|
|
this.updateDownloadsDropdownMenu();
|
|
}
|
|
|
|
handleClose = () => {
|
|
log.debug('DownloadsDropdownMenuView.handleClose');
|
|
|
|
this.open = false;
|
|
this.item = undefined;
|
|
ipcMain.emit(UPDATE_DOWNLOADS_DROPDOWN_MENU_ITEM);
|
|
this.view.setBounds(this.getBounds(0, 0));
|
|
WindowManager.sendToRenderer(CLOSE_DOWNLOADS_DROPDOWN_MENU);
|
|
}
|
|
|
|
handleToggle = (event: IpcMainEvent, payload: DownloadsMenuOpenEventPayload) => {
|
|
if (this.open) {
|
|
if (this.item?.location === payload.item.location) {
|
|
// clicking 3-dot in the same item
|
|
this.handleClose();
|
|
} else {
|
|
// clicking 3-dot in a different item
|
|
this.handleClose();
|
|
this.handleOpen(event, payload);
|
|
}
|
|
} else {
|
|
this.handleOpen(event, payload);
|
|
}
|
|
}
|
|
|
|
openFile = () => {
|
|
downloadsManager.openFile(this.item);
|
|
this.handleClose();
|
|
}
|
|
|
|
showFileInFolder = (e: IpcMainEvent, item: DownloadedItem) => {
|
|
downloadsManager.showFileInFolder(item);
|
|
this.handleClose();
|
|
}
|
|
|
|
clearFile = () => {
|
|
downloadsManager.clearFile(this.item);
|
|
this.handleClose();
|
|
}
|
|
|
|
cancelDownload = () => {
|
|
downloadsManager.cancelDownload(this.item);
|
|
this.handleClose();
|
|
}
|
|
|
|
getBounds = (width: number, height: number) => {
|
|
// MUST return integers
|
|
return {
|
|
x: this.getX(),
|
|
y: this.getY(),
|
|
width: Math.round(width),
|
|
height: Math.round(height),
|
|
};
|
|
}
|
|
|
|
getX = () => {
|
|
const result = (this.windowBounds.width - DOWNLOADS_DROPDOWN_FULL_WIDTH - DOWNLOADS_DROPDOWN_MENU_FULL_WIDTH) + (this.coordinates?.x || 0) + (this.coordinates?.width || 0);
|
|
if (result <= DOWNLOADS_DROPDOWN_MENU_FULL_WIDTH) {
|
|
return 0;
|
|
}
|
|
return Math.round(result);
|
|
}
|
|
|
|
getY = () => {
|
|
const result = TAB_BAR_HEIGHT + (this.coordinates?.y || 0) + (this.coordinates?.height || 0);
|
|
return Math.round(result);
|
|
}
|
|
|
|
repositionDownloadsDropdownMenu = () => {
|
|
this.bounds = this.getBounds(DOWNLOADS_DROPDOWN_MENU_FULL_WIDTH, DOWNLOADS_DROPDOWN_MENU_FULL_HEIGHT);
|
|
if (this.open) {
|
|
this.view.setBounds(this.bounds);
|
|
}
|
|
}
|
|
|
|
destroy = () => {
|
|
// workaround to eliminate zombie processes
|
|
// https://github.com/mattermost/desktop/pull/1519
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore
|
|
this.view.webContents.destroy();
|
|
}
|
|
}
|