Skip to content

Commit

Permalink
Merge pull request #900 from RocketChat/fix/tray
Browse files Browse the repository at this point in the history
[FIX] Tray icon module
  • Loading branch information
tassoevan authored Oct 2, 2018
2 parents 576f917 + 9408025 commit 993054f
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 240 deletions.
3 changes: 2 additions & 1 deletion src/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ import certificate from './background/certificate';
import { addServer, createMainWindow, getMainWindow } from './background/mainWindow';
import menus from './background/menus';
import './background/screenshare';
import tray from './background/tray';

import i18n from './i18n/index.js';
import env from './env';

export { default as showAboutDialog } from './background/aboutDialog';
export { default as remoteServers } from './background/servers';
export { certificate, menus };
export { certificate, menus, tray };

process.env.GOOGLE_API_KEY = 'AIzaSyADqUh_c1Qhji3Cp1NE43YrcpuPkmhXD-c';

Expand Down
14 changes: 11 additions & 3 deletions src/background/mainWindow.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import windowStateKeeper from './windowState';
import env from '../env';

let mainWindow = null;
let hideOnClose = true;

const mainWindowOptions = {
width: 1000,
Expand All @@ -32,7 +33,6 @@ const attachWindowStateHandling = (mainWindow) => {
});

app.on('before-quit', () => {
mainWindowState.saveState(mainWindow);
mainWindowState.saveState.flush();
mainWindow = null;
});
Expand All @@ -49,11 +49,11 @@ const attachWindowStateHandling = (mainWindow) => {
event.preventDefault();
if (mainWindow.isFullScreen()) {
mainWindow.once('leave-full-screen', () => {
mainWindow.hide();
(process.platform === 'darwin' && hideOnClose) ? mainWindow.hide() : mainWindow.destroy();
});
mainWindow.setFullScreen(false);
} else {
mainWindow.hide();
(process.platform === 'darwin' && hideOnClose) ? mainWindow.hide() : mainWindow.destroy();
}
mainWindowState.saveState(mainWindow);
});
Expand All @@ -65,6 +65,14 @@ const attachWindowStateHandling = (mainWindow) => {
mainWindow.on('move', () => {
mainWindowState.saveState(mainWindow);
});

mainWindow.on('tray-created', () => {
hideOnClose = true;
});

mainWindow.on('tray-destroyed', () => {
hideOnClose = false;
});
};

const attachIpcMessageHandling = (mainWindow) => {
Expand Down
3 changes: 2 additions & 1 deletion src/background/menus.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,6 @@ class Menus extends EventEmitter {
constructor() {
super();
this.state = {};
this.on('update', this.update.bind(this));
}

setState(partialState) {
Expand All @@ -325,6 +324,8 @@ class Menus extends EventEmitter {
mainWindow.setAutoHideMenuBar(!showMenuBar);
mainWindow.setMenuBarVisibility(!!showMenuBar);
}

this.emit('update');
}
}

Expand Down
140 changes: 140 additions & 0 deletions src/background/tray.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { app, systemPreferences, Menu, Tray as TrayIcon } from 'electron';
import { EventEmitter } from 'events';
import path from 'path';
import i18n from '../i18n/index.js';

const getTrayIconFileNameSuffix = ({ badge: { title, count, showAlert } }) => {
if (title === '•') {
return 'dot';
} else if (count > 9) {
return '9plus';
} else if (count > 0) {
return String(count);
} else if (showAlert) {
return 'alert';
} else {
return 'Template';
}
};

const getTrayIconPath = (state) => {
const iconDir = {
win32: 'windows',
linux: 'linux',
darwin: 'osx',
}[process.platform];
const fileName = `icon-tray-${ getTrayIconFileNameSuffix(state) }.${ process.platform === 'win32' ? 'ico' : 'png' }`;
return path.join(__dirname, 'public', 'images', iconDir, fileName);
};

const getTrayIconTitle = ({ badge: { title, count, showAlert }, status, showUserStatus }) => {
// TODO: remove status icon from title, since ANSI codes disable title color's adaptiveness
const isDarkMode = systemPreferences.getUserDefault('AppleInterfaceStyle', 'string') === 'Dark';

const statusAnsiColor = {
online: '32',
away: '33',
busy: '31',
offline: isDarkMode ? '37' : '0',
}[status];

const badgeTitleAnsiColor = isDarkMode ? '37' : '0';

const hasMentions = showAlert && count > 0;
const statusBulletString = showUserStatus ? `\u001B[${ statusAnsiColor }m•\u001B[0m` : null;
const badgeTitleString = hasMentions ? `\u001B[${ badgeTitleAnsiColor }m${ title }\u001B[0m` : null;

return [statusBulletString, badgeTitleString].filter(Boolean).join(' ');
};

const createContextMenuTemplate = ({ isMainWindowVisible }, events) => ([
{
label: !isMainWindowVisible ? i18n.__('Show') : i18n.__('Hide'),
click: () => events.emit('set-main-window-visibility', !isMainWindowVisible),
},
{
label: i18n.__('Quit'),
click: () => events.emit('quit'),
},
]);

class Tray extends EventEmitter {
constructor() {
super();

this.state = {
badge: {
title: '',
count: 0,
showAlert: false,
},
status: 'online',
isMainWindowVisible: true,
showIcon: true,
showUserStatus: true,
};

this.trayIcon = null;
}

setState(partialState) {
this.state = {
...this.state,
...partialState,
};
this.update();
}

createTrayIcon() {
this.trayIcon = new TrayIcon(getTrayIconPath(this.state));
this.trayIcon.setToolTip(app.getName());

this.trayIcon.on('click', () => this.emit('set-main-window-visibility', !this.state.isMainWindowVisible));
this.trayIcon.on('right-click', (event, bounds) => this.trayIcon.popUpContextMenu(undefined, bounds));

this.emit('created');
}

destroyTrayIcon() {
if (!this.trayIcon) {
return;
}

this.trayIcon.destroy();
this.emit('destroyed');
this.trayIcon = null;
}

destroy() {
this.destroyTrayIcon();
this.removeAllListeners();
}

update() {
const { showIcon } = this.state;

if (this.trayIcon && !showIcon) {
this.destroyTrayIcon();
} else if (!this.trayIcon && showIcon) {
this.createTrayIcon();
}

if (!this.trayIcon) {
this.emit('update');
return;
}

if (process.platform === 'darwin') {
this.trayIcon.setTitle(getTrayIconTitle(this.state));
}

this.trayIcon.setImage(getTrayIconPath(this.state));

const template = createContextMenuTemplate(this.state, this);
const menu = Menu.buildFromTemplate(template);
this.trayIcon.setContextMenu(menu);
this.emit('update');
}
}

export default new Tray();
67 changes: 58 additions & 9 deletions src/scripts/events.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { remote, ipcRenderer } from 'electron';
import servers from './servers';
import sidebar from './sidebar';
import tray from './tray';
import webview from './webview';

const { app, getCurrentWindow, shell } = remote;
const { certificate, menus, showAboutDialog } = remote.require('./background');
const { certificate, menus, showAboutDialog, tray } = remote.require('./background');

export default () => {
menus.on('quit', () => app.quit());
Expand Down Expand Up @@ -56,11 +55,9 @@ export default () => {

menus.on('reload-app', () => {
const mainWindow = getCurrentWindow();
if (mainWindow.destroyTray) {
mainWindow.destroyTray();
}
mainWindow.removeAllListeners();
menus.removeAllListeners();
tray.destroy();
mainWindow.reload();
});

Expand All @@ -80,17 +77,26 @@ export default () => {
showMenuBar: localStorage.getItem('autohideMenu') !== 'true',
showServerList: localStorage.getItem('sidebar-closed') !== 'true',
});

tray.setState({
showIcon: localStorage.getItem('hideTray') !== 'true',
showUserStatus: (localStorage.getItem('showUserStatusInTray') || 'true') === 'true',
});
};

menus.on('toggle', (property) => {
switch (property) {
case 'showTrayIcon': {
tray.toggle();
const previousValue = localStorage.getItem('hideTray') !== 'true';
const newValue = !previousValue;
localStorage.setItem('hideTray', JSON.stringify(!newValue));
break;
}

case 'showUserStatusInTray': {
tray.toggleStatus();
const previousValue = (localStorage.getItem('showUserStatusInTray') || 'true') === 'true';
const newValue = !previousValue;
localStorage.setItem('showUserStatusInTray', JSON.stringify(newValue));
break;
}

Expand Down Expand Up @@ -141,11 +147,49 @@ export default () => {
sidebar.on('hosts-sorted', updateServers);


sidebar.on('badge-setted', function() {
sidebar.on('badge-setted', () => {
const badge = sidebar.getGlobalBadge();
tray.showTrayAlert(badge);
const hasMentions = badge.showAlert && badge.count > 0;
const mainWindow = getCurrentWindow();

tray.setState({ badge });

if (!mainWindow.isFocused()) {
mainWindow.flashFrame(hasMentions);
}

if (process.platform === 'win32') {
if (hasMentions) {
mainWindow.webContents.send('render-taskbar-icon', badge.count);
} else {
mainWindow.setOverlayIcon(null, '');
}
}

if (process.platform === 'darwin') {
app.dock.setBadge(badge.title);
}

if (process.platform === 'linux') {
app.setBadgeCount(badge.count);
}
});


const updateWindowState = () =>
tray.setState({ isMainWindowVisible: getCurrentWindow().isVisible() || getCurrentWindow().isMinimized() });
getCurrentWindow().on('hide', updateWindowState);
getCurrentWindow().on('show', updateWindowState);
getCurrentWindow().on('minimize', updateWindowState);
getCurrentWindow().on('restore', updateWindowState);

tray.on('created', () => getCurrentWindow().emit('tray-created'));
tray.on('destroyed', () => getCurrentWindow().emit('tray-destroyed'));
tray.on('set-main-window-visibility', (visible) =>
(visible ? getCurrentWindow().show() : getCurrentWindow().hide()));
tray.on('quit', () => app.quit());


webview.on('ipc-message-unread-changed', (hostUrl, [count]) => {
if (typeof count === 'number' && localStorage.getItem('showWindowOnUnreadChanged') === 'true') {
const mainWindow = remote.getCurrentWindow();
Expand All @@ -157,6 +201,10 @@ export default () => {
}
});

webview.on('ipc-message-user-status-manually-set', (hostUrl, [status]) => {
tray.setState({ status });
});

ipcRenderer.on('render-taskbar-icon', (event, messageCount) => {
// Create a canvas from unread messages
function createOverlayIcon(messageCount) {
Expand Down Expand Up @@ -186,5 +234,6 @@ export default () => {
servers.restoreActive();
updatePreferences();
updateServers();
updateWindowState();

};
Loading

0 comments on commit 993054f

Please sign in to comment.