|
|
|
@@ -3,7 +3,7 @@
|
|
|
|
|
|
|
|
|
|
import {BrowserView, ipcMain, IpcMainEvent} from 'electron';
|
|
|
|
|
|
|
|
|
|
import {CombinedConfig, MattermostTeam} from 'types/config';
|
|
|
|
|
import {MattermostTeam} from 'types/config';
|
|
|
|
|
|
|
|
|
|
import AppState from 'common/appState';
|
|
|
|
|
import {
|
|
|
|
@@ -14,7 +14,6 @@ import {
|
|
|
|
|
UPDATE_APPSTATE,
|
|
|
|
|
REQUEST_TEAMS_DROPDOWN_INFO,
|
|
|
|
|
RECEIVE_DROPDOWN_MENU_SIZE,
|
|
|
|
|
SET_ACTIVE_VIEW,
|
|
|
|
|
SERVERS_UPDATE,
|
|
|
|
|
} from 'common/communication';
|
|
|
|
|
import Config from 'common/config';
|
|
|
|
@@ -29,29 +28,41 @@ import MainWindow from '../windows/mainWindow';
|
|
|
|
|
|
|
|
|
|
const log = new Logger('TeamDropdownView');
|
|
|
|
|
|
|
|
|
|
export default class TeamDropdownView {
|
|
|
|
|
view: BrowserView;
|
|
|
|
|
bounds?: Electron.Rectangle;
|
|
|
|
|
teams: MattermostTeam[];
|
|
|
|
|
activeTeam?: string;
|
|
|
|
|
darkMode: boolean;
|
|
|
|
|
enableServerManagement?: boolean;
|
|
|
|
|
hasGPOTeams?: boolean;
|
|
|
|
|
unreads?: Map<string, boolean>;
|
|
|
|
|
mentions?: Map<string, number>;
|
|
|
|
|
expired?: Map<string, boolean>;
|
|
|
|
|
windowBounds?: Electron.Rectangle;
|
|
|
|
|
isOpen: boolean;
|
|
|
|
|
export class TeamDropdownView {
|
|
|
|
|
private view?: BrowserView;
|
|
|
|
|
private teams: MattermostTeam[];
|
|
|
|
|
private hasGPOTeams: boolean;
|
|
|
|
|
private isOpen: boolean;
|
|
|
|
|
private bounds: Electron.Rectangle;
|
|
|
|
|
|
|
|
|
|
private unreads: Map<string, boolean>;
|
|
|
|
|
private mentions: Map<string, number>;
|
|
|
|
|
private expired: Map<string, boolean>;
|
|
|
|
|
|
|
|
|
|
private windowBounds?: Electron.Rectangle;
|
|
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
|
this.teams = this.getOrderedTeams();
|
|
|
|
|
this.hasGPOTeams = this.teams.some((srv) => srv.isPredefined);
|
|
|
|
|
this.darkMode = Config.darkMode;
|
|
|
|
|
this.enableServerManagement = Config.enableServerManagement;
|
|
|
|
|
this.teams = [];
|
|
|
|
|
this.hasGPOTeams = false;
|
|
|
|
|
this.isOpen = false;
|
|
|
|
|
this.bounds = this.getBounds(0, 0);
|
|
|
|
|
|
|
|
|
|
this.windowBounds = MainWindow.getBounds();
|
|
|
|
|
this.unreads = new Map();
|
|
|
|
|
this.mentions = new Map();
|
|
|
|
|
this.expired = new Map();
|
|
|
|
|
|
|
|
|
|
ipcMain.on(OPEN_TEAMS_DROPDOWN, this.handleOpen);
|
|
|
|
|
ipcMain.on(CLOSE_TEAMS_DROPDOWN, this.handleClose);
|
|
|
|
|
ipcMain.on(RECEIVE_DROPDOWN_MENU_SIZE, this.handleReceivedMenuSize);
|
|
|
|
|
|
|
|
|
|
ipcMain.on(EMIT_CONFIGURATION, this.updateDropdown);
|
|
|
|
|
ipcMain.on(REQUEST_TEAMS_DROPDOWN_INFO, this.updateDropdown);
|
|
|
|
|
|
|
|
|
|
AppState.on(UPDATE_APPSTATE, this.updateMentions);
|
|
|
|
|
ServerManager.on(SERVERS_UPDATE, this.updateServers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init = () => {
|
|
|
|
|
const preload = getLocalPreload('desktopAPI.js');
|
|
|
|
|
this.view = new BrowserView({webPreferences: {
|
|
|
|
|
preload,
|
|
|
|
@@ -61,63 +72,12 @@ export default class TeamDropdownView {
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
transparent: true,
|
|
|
|
|
}});
|
|
|
|
|
|
|
|
|
|
this.view.webContents.loadURL(getLocalURLString('dropdown.html'));
|
|
|
|
|
|
|
|
|
|
this.setOrderedTeams();
|
|
|
|
|
this.windowBounds = MainWindow.getBounds();
|
|
|
|
|
this.updateDropdown();
|
|
|
|
|
MainWindow.get()?.addBrowserView(this.view);
|
|
|
|
|
|
|
|
|
|
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_ACTIVE_VIEW, this.updateActiveTeam);
|
|
|
|
|
AppState.on(UPDATE_APPSTATE, this.updateMentions);
|
|
|
|
|
|
|
|
|
|
ServerManager.on(SERVERS_UPDATE, this.updateServers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private getOrderedTeams = () => {
|
|
|
|
|
return ServerManager.getOrderedServers().map((team) => team.toMattermostTeam());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateServers = () => {
|
|
|
|
|
this.teams = this.getOrderedTeams();
|
|
|
|
|
this.hasGPOTeams = this.teams.some((srv) => srv.isPredefined);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateConfig = (event: IpcMainEvent, config: CombinedConfig) => {
|
|
|
|
|
log.silly('config', {config});
|
|
|
|
|
|
|
|
|
|
this.darkMode = config.darkMode;
|
|
|
|
|
this.enableServerManagement = config.enableServerManagement;
|
|
|
|
|
this.updateDropdown();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateActiveTeam = (event: IpcMainEvent, serverId: string) => {
|
|
|
|
|
log.silly('updateActiveTeam', {serverId});
|
|
|
|
|
|
|
|
|
|
this.activeTeam = serverId;
|
|
|
|
|
this.updateDropdown();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private reduceNotifications = <T>(items: Map<string, T>, modifier: (base?: T, value?: T) => T) => {
|
|
|
|
|
return [...items.keys()].reduce((map, key) => {
|
|
|
|
|
const view = ServerManager.getTab(key);
|
|
|
|
|
if (!view) {
|
|
|
|
|
return map;
|
|
|
|
|
}
|
|
|
|
|
map.set(view.server.id, modifier(map.get(view.server.id), items.get(key)));
|
|
|
|
|
return map;
|
|
|
|
|
}, new Map());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateMentions = (expired: Map<string, boolean>, mentions: Map<string, number>, unreads: Map<string, boolean>) => {
|
|
|
|
|
log.silly('updateMentions', {expired, mentions, unreads});
|
|
|
|
|
|
|
|
|
|
this.unreads = this.reduceNotifications(unreads, (base, value) => base || value || false);
|
|
|
|
|
this.mentions = this.reduceNotifications(mentions, (base, value) => (base ?? 0) + (value ?? 0));
|
|
|
|
|
this.expired = this.reduceNotifications(expired, (base, value) => base || value || false);
|
|
|
|
|
this.updateDropdown();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateWindowBounds = () => {
|
|
|
|
@@ -125,16 +85,16 @@ export default class TeamDropdownView {
|
|
|
|
|
this.updateDropdown();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateDropdown = () => {
|
|
|
|
|
private updateDropdown = () => {
|
|
|
|
|
log.silly('updateDropdown');
|
|
|
|
|
|
|
|
|
|
this.view.webContents.send(
|
|
|
|
|
this.view?.webContents.send(
|
|
|
|
|
UPDATE_TEAMS_DROPDOWN,
|
|
|
|
|
this.teams,
|
|
|
|
|
this.darkMode,
|
|
|
|
|
Config.darkMode,
|
|
|
|
|
this.windowBounds,
|
|
|
|
|
this.activeTeam,
|
|
|
|
|
this.enableServerManagement,
|
|
|
|
|
ServerManager.hasServers() ? ServerManager.getCurrentServer().id : undefined,
|
|
|
|
|
Config.enableServerManagement,
|
|
|
|
|
this.hasGPOTeams,
|
|
|
|
|
this.expired,
|
|
|
|
|
this.mentions,
|
|
|
|
@@ -142,12 +102,33 @@ export default class TeamDropdownView {
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleOpen = () => {
|
|
|
|
|
private updateServers = () => {
|
|
|
|
|
this.setOrderedTeams();
|
|
|
|
|
this.updateDropdown();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private updateMentions = (expired: Map<string, boolean>, mentions: Map<string, number>, unreads: Map<string, boolean>) => {
|
|
|
|
|
log.silly('updateMentions', {expired, mentions, unreads});
|
|
|
|
|
|
|
|
|
|
this.unreads = this.reduceNotifications(this.unreads, unreads, (base, value) => base || value || false);
|
|
|
|
|
this.mentions = this.reduceNotifications(this.mentions, mentions, (base, value) => (base ?? 0) + (value ?? 0));
|
|
|
|
|
this.expired = this.reduceNotifications(this.expired, expired, (base, value) => base || value || false);
|
|
|
|
|
this.updateDropdown();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Menu open/close/size handlers
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
private handleOpen = () => {
|
|
|
|
|
log.debug('handleOpen');
|
|
|
|
|
|
|
|
|
|
if (!this.bounds) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!this.view) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.view.setBounds(this.bounds);
|
|
|
|
|
MainWindow.get()?.setTopBrowserView(this.view);
|
|
|
|
|
this.view.webContents.focus();
|
|
|
|
@@ -155,24 +136,28 @@ export default class TeamDropdownView {
|
|
|
|
|
this.isOpen = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleClose = () => {
|
|
|
|
|
private handleClose = () => {
|
|
|
|
|
log.debug('handleClose');
|
|
|
|
|
|
|
|
|
|
this.view.setBounds(this.getBounds(0, 0));
|
|
|
|
|
this.view?.setBounds(this.getBounds(0, 0));
|
|
|
|
|
WindowManager.sendToRenderer(CLOSE_TEAMS_DROPDOWN);
|
|
|
|
|
this.isOpen = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleReceivedMenuSize = (event: IpcMainEvent, width: number, height: number) => {
|
|
|
|
|
private handleReceivedMenuSize = (event: IpcMainEvent, width: number, height: number) => {
|
|
|
|
|
log.silly('handleReceivedMenuSize', {width, height});
|
|
|
|
|
|
|
|
|
|
this.bounds = this.getBounds(width, height);
|
|
|
|
|
if (this.isOpen) {
|
|
|
|
|
this.view.setBounds(this.bounds);
|
|
|
|
|
this.view?.setBounds(this.bounds);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getBounds = (width: number, height: number) => {
|
|
|
|
|
/**
|
|
|
|
|
* Helpers
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
private 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,
|
|
|
|
@@ -181,11 +166,22 @@ export default class TeamDropdownView {
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
private reduceNotifications = <T>(inputMap: Map<string, T>, items: Map<string, T>, modifier: (base?: T, value?: T) => T) => {
|
|
|
|
|
return [...items.keys()].reduce((map, key) => {
|
|
|
|
|
const view = ServerManager.getTab(key);
|
|
|
|
|
if (!view) {
|
|
|
|
|
return map;
|
|
|
|
|
}
|
|
|
|
|
map.set(view.server.id, modifier(map.get(view.server.id), items.get(key)));
|
|
|
|
|
return map;
|
|
|
|
|
}, inputMap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private setOrderedTeams = () => {
|
|
|
|
|
this.teams = ServerManager.getOrderedServers().map((team) => team.toMattermostTeam());
|
|
|
|
|
this.hasGPOTeams = this.teams.some((srv) => srv.isPredefined);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const teamDropdownView = new TeamDropdownView();
|
|
|
|
|
export default teamDropdownView;
|
|
|
|
|