Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add tray icon resolutions #1676

Merged
merged 14 commits into from Aug 17, 2018
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added electron/img/tray-icon/tray/tray.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added electron/img/tray-icon/tray/tray@1.25x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added electron/img/tray-icon/tray/tray@1.33x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added electron/img/tray-icon/tray/tray@1.4x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added electron/img/tray-icon/tray/tray@1.5x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added electron/img/tray-icon/tray/tray@1.8x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added electron/img/tray-icon/tray/tray@2.5x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added electron/img/tray-icon/tray/tray@2x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added electron/img/tray-icon/tray/tray@3x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added electron/img/tray-icon/tray/tray@4x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added electron/img/tray-icon/tray/tray@5x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed electron/img/tray.badge.ico
Binary file not shown.
Binary file removed electron/img/tray.badge.png
Binary file not shown.
Binary file removed electron/img/tray.ico
Binary file not shown.
Binary file removed electron/img/tray.png
Binary file not shown.
81 changes: 81 additions & 0 deletions electron/js/menu/TrayHandler.js
@@ -0,0 +1,81 @@
const {app, Menu, nativeImage, Tray} = require('electron');
const config = require('./../config');
const lifecycle = require('./../lifecycle');
const locale = require('./../../locale/locale');
const path = require('path');
const windowManager = require('./../window-manager');

function buildTrayMenu() {
const contextMenu = Menu.buildFromTemplate([
{
click: () => windowManager.showPrimaryWindow(),
label: locale.getText('trayOpen'),
},
{
click: async () => await lifecycle.quit(),
label: locale.getText('trayQuit'),
},
]);

this.trayIcon.on('click', () => windowManager.showPrimaryWindow());
this.trayIcon.setContextMenu(contextMenu);
this.trayIcon.setToolTip(config.NAME);
}

function flashApplicationWindow(win, count) {
if (win.isFocused() || !count) {
win.flashFrame(false);
} else if (count > this.lastUnreadCount) {
win.flashFrame(true);
}
}

function updateBadgeCount(count) {
app.setBadgeCount(count);
this.lastUnreadCount = count;
}

function updateIcons(win, count) {
if (this.icons) {
const trayImage = count ? this.icons.trayWithBadge : this.icons.tray;
this.trayIcon.setImage(trayImage);

const overlayImage = count ? this.icons.badge : null;
win.setOverlayIcon(overlayImage, locale.getText('unreadMessages'));
}
}

class TrayHandler {
constructor() {
this.lastUnreadCount = 0;
}

initTray(trayIcon = new Tray(nativeImage.createEmpty())) {
const IMAGE_ROOT = path.join(app.getAppPath(), 'img');

const iconPaths = {
badge: path.join(IMAGE_ROOT, 'taskbar.overlay.png'),
tray: path.join(IMAGE_ROOT, 'tray-icon', 'tray', 'tray.png'),
trayWithBadge: path.join(IMAGE_ROOT, 'tray-icon', 'tray-with-badge', 'tray.badge.png'),
};

this.icons = {
badge: nativeImage.createFromPath(iconPaths.badge),
tray: nativeImage.createFromPath(iconPaths.tray),
trayWithBadge: nativeImage.createFromPath(iconPaths.trayWithBadge),
};

this.trayIcon = trayIcon;
this.trayIcon.setImage(this.icons.tray);

buildTrayMenu.call(this);
}

showUnreadCount(win, count) {
updateIcons.call(this, win, count);
flashApplicationWindow.call(this, win, count);
updateBadgeCount.call(this, count);
}
}

module.exports = TrayHandler;
81 changes: 0 additions & 81 deletions electron/js/menu/TrayIconHandler.js

This file was deleted.

11 changes: 7 additions & 4 deletions electron/main.js
Expand Up @@ -54,7 +54,7 @@ const locale = require('./locale/locale');
const systemMenu = require('./js/menu/system');
const util = require('./js/util');
const windowManager = require('./js/window-manager');
const TrayIconHandler = require('./js/menu/TrayIconHandler');
const TrayHandler = require('./js/menu/TrayHandler');
const EVENT_TYPE = require('./js/lib/eventType');

// Config
Expand All @@ -80,7 +80,7 @@ const bindIpcEvents = () => {
});

ipcMain.on(EVENT_TYPE.UI.BADGE_COUNT, (event, count) => {
tray.updateBadgeIcon(main, count);
tray.showUnreadCount(main, count);
});

ipcMain.on(EVENT_TYPE.GOOGLE_OAUTH.REQUEST, event => {
Expand Down Expand Up @@ -213,7 +213,7 @@ const showMainWindow = () => {
main.on('focus', () => main.flashFrame(false));
main.on('maximize', () => saveFullScreenState());
main.on('move', () => saveWindowBoundsState());
main.on('page-title-updated', () => tray.updateBadgeIcon(main));
main.on('page-title-updated', () => tray.showUnreadCount(main));
main.on('resize', () => saveWindowBoundsState());
main.on('unmaximize', () => saveFullScreenState());

Expand Down Expand Up @@ -259,7 +259,10 @@ const handleAppEvents = () => {
appMenu.on(EVENT_TYPE.ABOUT.SHOW, () => about.showWindow());

Menu.setApplicationMenu(appMenu);
tray = new TrayIconHandler(environment.platform);
tray = new TrayHandler();
if (!environment.platform.IS_MAC_OS) {
tray.initTray();
}
showMainWindow();
});
};
Expand Down
50 changes: 20 additions & 30 deletions tests/main/TrayIconHandlerTest.js → tests/main/TrayHandlerTest.js
Expand Up @@ -23,7 +23,7 @@ const {app} = require('electron');
const assert = require('assert');
const path = require('path');
const sinon = require('sinon');
const TrayIconHandler = require('../../electron/js/menu/TrayIconHandler');
const TrayHandler = require('../../electron/js/menu/TrayHandler');
const {BrowserWindow} = require('electron');

describe('TrayIconHandler', () => {
Expand All @@ -34,35 +34,22 @@ describe('TrayIconHandler', () => {
setToolTip: () => {},
};

describe('"constructor"', () => {
it('creates native images for all tray icons on instantiation', () => {
const tray = new TrayIconHandler({IS_MAC_OS: false, IS_WINDOWS: true}, TrayMock);
describe('initTray', () => {
it('creates native images for all tray icons and sets a default tray icon', () => {
const tray = new TrayHandler();
tray.initTray(TrayMock);
assert.equal(Object.keys(tray.icons).length, 3);
assert.equal(tray.icons.badge.constructor.name, 'NativeImage');
assert.equal(tray.icons.tray.constructor.name, 'NativeImage');
assert.equal(tray.icons.trayWithBadge.constructor.name, 'NativeImage');
});

it('creates a tray icon on Linux', () => {
const tray = new TrayIconHandler({IS_LINUX: true}, TrayMock);
sinon.assert.match(tray.appIcon, sinon.match.defined);
});

it('creates a tray icon on Window', () => {
const tray = new TrayIconHandler({IS_WINDOWS: true}, TrayMock);
sinon.assert.match(tray.appIcon, sinon.match.defined);
});

it('does not create a tray icon on macOS', () => {
const tray = new TrayIconHandler({IS_MAC_OS: true}, TrayMock);
sinon.assert.match(tray.appIcon, sinon.match.typeOf('undefined'));
sinon.assert.match(tray.trayIcon, sinon.match.defined);
});
});

describe('"updateBadgeIcon"', () => {
describe('"Mac"', () => {
describe('showUnreadCount', () => {
describe('without tray icon initialization', () => {
it('updates the badge counter and stops flashing the app frame when app is in focus while receiving new messages', done => {
const tray = new TrayIconHandler({IS_MAC: true}, TrayMock);
const tray = new TrayHandler();
const appWindow = new BrowserWindow();

sinon.spy(app, 'setBadgeCount');
Expand All @@ -72,7 +59,7 @@ describe('TrayIconHandler', () => {
appWindow.webContents.on('dom-ready', () => {
assert.equal(appWindow.isFocused(), true);
assert.equal(appWindow.flashFrame.callCount, 0);
tray.updateBadgeIcon(appWindow, 1);
tray.showUnreadCount(appWindow, 1);
assert.ok(app.setBadgeCount.getCall(0).calledWith(1));
assert.ok(appWindow.flashFrame.getCall(0).calledWith(false));
assert.equal(tray.lastUnreadCount, 1);
Expand All @@ -83,9 +70,10 @@ describe('TrayIconHandler', () => {
});
});

describe('"Windows"', () => {
describe('with tray icon initialization', () => {
it('updates the badge counter and stops flashing the app frame when app is in focus while receiving new messages', done => {
const tray = new TrayIconHandler({IS_WINDOWS: true}, TrayMock);
const tray = new TrayHandler();
tray.initTray(TrayMock);
const appWindow = new BrowserWindow();

sinon.spy(appWindow, 'flashFrame');
Expand All @@ -94,7 +82,7 @@ describe('TrayIconHandler', () => {
appWindow.webContents.on('dom-ready', () => {
assert.equal(appWindow.isFocused(), true);
assert.equal(appWindow.flashFrame.callCount, 0);
tray.updateBadgeIcon(appWindow, 10);
tray.showUnreadCount(appWindow, 10);
assert.ok(appWindow.flashFrame.getCall(0).calledWith(false));
assert.equal(tray.lastUnreadCount, 10);
appWindow.flashFrame.restore();
Expand All @@ -103,7 +91,8 @@ describe('TrayIconHandler', () => {
});

it('flashes the app frame when app is not in focus and you receive new messages', done => {
const tray = new TrayIconHandler({IS_WINDOWS: true}, TrayMock);
const tray = new TrayHandler();
tray.initTray(TrayMock);

const appWindow = new BrowserWindow({
show: false,
Expand All @@ -115,7 +104,7 @@ describe('TrayIconHandler', () => {
appWindow.loadURL(`file://${path.join(__dirname, '..', 'fixtures', 'badge.html')}`);
appWindow.webContents.on('dom-ready', () => {
assert.equal(appWindow.isFocused(), false);
tray.updateBadgeIcon(appWindow, 2);
tray.showUnreadCount(appWindow, 2);
assert.ok(appWindow.flashFrame.getCall(0).calledWith(true));
appWindow.flashFrame.restore();
done();
Expand All @@ -124,7 +113,8 @@ describe('TrayIconHandler', () => {
});

it('does change the flash state if the window has already been flashed', done => {
const tray = new TrayIconHandler({IS_WINDOWS: true}, TrayMock);
const tray = new TrayHandler();
tray.initTray(TrayMock);
tray.lastUnreadCount = 5;

const appWindow = new BrowserWindow({
Expand All @@ -137,7 +127,7 @@ describe('TrayIconHandler', () => {
appWindow.loadURL(`file://${path.join(__dirname, '..', 'fixtures', 'badge.html')}`);
appWindow.webContents.on('dom-ready', () => {
assert.equal(appWindow.isFocused(), false);
tray.updateBadgeIcon(appWindow, 2);
tray.showUnreadCount(appWindow, 2);
assert.equal(appWindow.flashFrame.callCount, 0);
appWindow.flashFrame.restore();
done();
Expand Down