[MM-36421] Replace server tabs with dropdown menu (#1647)

* WIP

* WIP

* PoC for dropdown - logic stuff

* Most of the logic for the dropdown

* Working dropdown menu to pick servers

* Mentions, unreads and expired working. Many styles are working.

* Some more styles

* Dark mode and other stuff

* Some cleanup

* Generate build

* PR feedback

* More PR feedback
This commit is contained in:
Devin Binnie
2021-07-07 18:49:48 -04:00
committed by GitHub
parent 4130c2c37d
commit 880af87ddf
32 changed files with 1792 additions and 117 deletions

View File

@@ -73,19 +73,17 @@ export class MattermostView extends EventEmitter {
this.window = win;
const preload = getLocalPreload('preload.js');
this.options = {
webPreferences: {
contextIsolation: process.env.NODE_ENV !== 'test',
preload,
additionalArguments: [
`version=${app.getVersion()}`,
`appName=${app.name}`,
],
enableRemoteModule: process.env.NODE_ENV === 'test',
nodeIntegration: process.env.NODE_ENV === 'test',
...options.webPreferences,
},
...options,
this.options = Object.assign({}, options);
this.options.webPreferences = {
contextIsolation: process.env.NODE_ENV !== 'test',
preload,
additionalArguments: [
`version=${app.getVersion()}`,
`appName=${app.name}`,
],
enableRemoteModule: process.env.NODE_ENV === 'test',
nodeIntegration: process.env.NODE_ENV === 'test',
...options.webPreferences,
};
this.isVisible = false;
this.view = new BrowserView(this.options);

View File

@@ -0,0 +1,114 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {BrowserView, BrowserWindow, ipcMain, IpcMainEvent} from 'electron';
import {CombinedConfig, Team} from 'types/config';
import {
CLOSE_TEAMS_DROPDOWN,
EMIT_CONFIGURATION,
OPEN_TEAMS_DROPDOWN,
UPDATE_TEAMS_DROPDOWN,
UPDATE_DROPDOWN_MENTIONS,
REQUEST_TEAMS_DROPDOWN_INFO,
RECEIVE_DROPDOWN_MENU_SIZE,
SET_SERVER_KEY,
} from 'common/communication';
import * as AppState from '../appState';
import {TAB_BAR_HEIGHT, THREE_DOT_MENU_WIDTH, THREE_DOT_MENU_WIDTH_MAC, MENU_SHADOW_WIDTH} from 'common/utils/constants';
import {getLocalPreload, getLocalURLString} from 'main/utils';
import * as WindowManager from '../windows/windowManager';
export default class TeamDropdownView {
view: BrowserView;
bounds?: Electron.Rectangle;
teams: Team[];
activeTeam?: string;
darkMode: boolean;
unreads?: Map<string, boolean>;
mentions?: Map<string, number>;
expired?: Map<string, boolean>;
window: BrowserWindow;
constructor(window: BrowserWindow, teams: Team[], darkMode: boolean) {
this.teams = teams;
this.window = window;
this.darkMode = darkMode;
const preload = getLocalPreload('dropdown.js');
this.view = new BrowserView({webPreferences: {
contextIsolation: process.env.NODE_ENV !== 'test',
preload,
nodeIntegration: process.env.NODE_ENV === 'test',
enableRemoteModule: process.env.NODE_ENV === 'test',
}});
this.view.webContents.loadURL(getLocalURLString('dropdown.html'));
ipcMain.on(OPEN_TEAMS_DROPDOWN, this.handleOpen);
ipcMain.on(CLOSE_TEAMS_DROPDOWN, this.handleClose);
ipcMain.on(EMIT_CONFIGURATION, this.updateConfig);
ipcMain.on(REQUEST_TEAMS_DROPDOWN_INFO, this.updateDropdown);
ipcMain.on(RECEIVE_DROPDOWN_MENU_SIZE, this.handleReceivedMenuSize);
ipcMain.on(SET_SERVER_KEY, this.updateActiveTeam);
AppState.on(UPDATE_DROPDOWN_MENTIONS, this.updateMentions);
}
updateConfig = (event: IpcMainEvent, config: CombinedConfig) => {
this.teams = config.teams;
this.darkMode = config.darkMode;
this.updateDropdown();
}
updateActiveTeam = (event: IpcMainEvent, name: string) => {
this.activeTeam = name;
this.updateDropdown();
}
updateMentions = (expired: Map<string, boolean>, mentions: Map<string, number>, unreads: Map<string, boolean>) => {
this.unreads = unreads;
this.mentions = mentions;
this.expired = expired;
this.updateDropdown();
}
updateDropdown = () => {
this.view.webContents.send(UPDATE_TEAMS_DROPDOWN, this.teams, this.activeTeam, this.darkMode, this.expired, this.mentions, this.unreads);
}
handleOpen = () => {
this.window.addBrowserView(this.view);
const bounds = this.view.getBounds();
this.view.setBounds(this.getBounds(bounds.width, bounds.height));
this.window.setTopBrowserView(this.view);
this.view.webContents.focus();
WindowManager.sendToRenderer(OPEN_TEAMS_DROPDOWN);
}
handleClose = () => {
this.window.removeBrowserView(this.view);
WindowManager.sendToRenderer(CLOSE_TEAMS_DROPDOWN);
}
handleReceivedMenuSize = (event: IpcMainEvent, width: number, height: number) => {
const bounds = this.getBounds(width, height);
this.view.setBounds(bounds);
}
getBounds = (width: number, height: number) => {
return {
x: (process.platform === 'darwin' ? THREE_DOT_MENU_WIDTH_MAC : THREE_DOT_MENU_WIDTH) - MENU_SHADOW_WIDTH,
y: TAB_BAR_HEIGHT - MENU_SHADOW_WIDTH,
width,
height,
};
}
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();
}
}

View File

@@ -1,7 +1,7 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import log from 'electron-log';
import {BrowserView, BrowserWindow, dialog} from 'electron';
import {BrowserView, BrowserWindow, dialog, ipcMain} from 'electron';
import {BrowserViewConstructorOptions} from 'electron/main';
import {CombinedConfig, Team} from 'types/config';
@@ -131,6 +131,7 @@ export class ViewManager {
return;
}
newView.window.webContents.send(SET_SERVER_KEY, serverInfo.order);
ipcMain.emit(SET_SERVER_KEY, true, name);
if (newView.isReady()) {
// if view is not ready, the renderer will have something to display instead.
newView.show();