Skip to content
This repository was archived by the owner on Mar 7, 2018. It is now read-only.

Commit 534426c

Browse files
committed
Merge pull request #81 from teetrinkers/trayicon
Show a tray icon if enabled in the config.
2 parents 61a999b + 0b34619 commit 534426c

18 files changed

+209
-4
lines changed

README.md

+14-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ An application for [Mattermost](http://mattermost.org) for OS X, Windows, and Li
1111
First, clone down this project, and then from within that directory in your favorite terminal run:
1212

1313
```
14-
> npm install
14+
> npm install
1515
// installs packages....
1616
> npm link
1717
// creates a local symlink
@@ -23,7 +23,7 @@ you have your `config.json` setup as noted in the steps below.
2323

2424
Matterfront can connect to multiple teams. For now, the names and urls or your teams are pulled from a json file in your home directory.
2525

26-
Create a text file at `~/.matterfront/state.json`. (Where `~` is your home directory). Make it look like this:
26+
Create a text file at `~/.matterfront/config.json`. (Where `~` is your home directory). Make it look like this:
2727

2828
```json
2929
{
@@ -66,6 +66,18 @@ These values can also be specified via the developer command-line like this:
6666
electron . --chrome-args:remote-debugging-port=2929 --chrome-args:no-proxy-server
6767
```
6868

69+
## Enabling the tray icon
70+
71+
Matterfront can show an icon in the tray, which is the notification area on Windows, or menu bar on OS X. To enable the tray icon, set the option `showTrayIcon` in your `config.json`, like this:
72+
73+
```json
74+
{
75+
"showTrayIcon": true
76+
}
77+
```
78+
79+
If the tray icon is enabled, Matterfront will not quit when the window is closed. Quit the process using the corresponding menu item of the tray icon.
80+
6981
## Running in Developer Mode
7082

7183
To launch the app from source without building a distribution:

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@
5050
"less-loader": "~2.2.2",
5151
"lodash.once": "~3.0.1",
5252
"mocha": "~2.3.4",
53+
"proxyquire": "^1.7.3",
5354
"razz": "~1.1.1",
55+
"sinon": "^1.17.2",
56+
"sinon-chai": "^2.8.0",
5457
"style-loader": "~0.13.0",
5558
"watch": "~0.16.0",
5659
"webpack": "^1.12.9",

resources/tray-mention.png

1.73 KB
Loading

resources/[email protected]

2.64 KB
Loading

resources/[email protected]

4.71 KB
Loading

resources/tray-unread.png

1.74 KB
Loading

resources/[email protected]

2.63 KB
Loading

resources/[email protected]

4.7 KB
Loading

resources/tray.png

1.6 KB
Loading

resources/[email protected]

2.25 KB
Loading

resources/[email protected]

3.65 KB
Loading

src/browser/mattermost-observer.js

+3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ var notifyHost = function() {
2929
var unreadCount = getUnreadCount();
3030

3131
ipc.sendToHost('mention', mentionCount);
32+
ipc.send('mention', mentionCount);
33+
3234
ipc.sendToHost('unread', unreadCount);
35+
ipc.send('unread', unreadCount);
3336
};
3437

3538
var getUnreadCount = function(){

src/main.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ var chromeArgs = require('./chrome-args.js');
55
var menu = require('./menu.js');
66
var settings = require('./settings.js');
77
var teams = require("./teams.js");
8+
var tray = require("./tray.js");
89

910
settings.load();
1011
chromeArgs.apply(settings);
@@ -56,7 +57,11 @@ app.on('ready', function() {
5657
}
5758
settings.saveState();
5859

59-
if (process.platform != 'darwin') { return; }
60+
// Quit when the window is closed if not on OS X or if the tray icon is disabled.
61+
if (process.platform != 'darwin' && !tray.isEnabled()) {
62+
return;
63+
}
64+
6065
if (quitting) { return; }
6166

6267
e.preventDefault();
@@ -72,4 +77,10 @@ app.on('ready', function() {
7277
});
7378

7479
menu.load();
80+
81+
// Show a system tray/menu bar icon if enabled in the settings.
82+
if (settings.get('showTrayIcon') === true) {
83+
tray.enable(mainWindow);
84+
}
85+
7586
});

src/settings.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ var defaults = {
2525
width: 1024,
2626
height: 600
2727
},
28-
"chrome-args": {}
28+
"chrome-args": {},
29+
"showTrayIcon": false
2930
};
3031

3132
settings.load = function(homedir){

src/tray.js

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
var electron = require('electron');
2+
var Menu = electron.Menu;
3+
var MenuItem = electron.MenuItem;
4+
var Tray = electron.Tray;
5+
var nativeImage = electron.nativeImage;
6+
var ipc = electron.ipcMain;
7+
var app = electron.app;
8+
var path = require('path');
9+
10+
var defaultIcon = nativeImage.createFromPath(
11+
path.join(__dirname, '../resources/tray.png'));
12+
var unreadMessagesIcon = nativeImage.createFromPath(
13+
path.join(__dirname, '../resources/tray-unread.png'));
14+
var mentionsIcon = nativeImage.createFromPath(
15+
path.join(__dirname, '../resources/tray-mention.png'));
16+
17+
var tray;
18+
var mainWindow;
19+
20+
var unreadCount = 0;
21+
var mentionsCount = 0;
22+
23+
// Returns true if the tray icon is enabled.
24+
function isEnabled() {
25+
return tray != undefined;
26+
}
27+
28+
function createMenu() {
29+
var menu = new Menu();
30+
31+
menu.append(new MenuItem({
32+
label: 'Show',
33+
click: function(item) {
34+
mainWindow.restore();
35+
mainWindow.show();
36+
}
37+
}));
38+
menu.append(new MenuItem({
39+
label: 'Quit',
40+
click: function(item) {
41+
app.quit();
42+
}
43+
}));
44+
45+
return menu;
46+
}
47+
48+
function updateIcon() {
49+
if (mentionsCount > 0) {
50+
tray.setImage(mentionsIcon);
51+
} else if (unreadCount > 0) {
52+
tray.setImage(unreadMessagesIcon);
53+
} else {
54+
tray.setImage(defaultIcon);
55+
}
56+
}
57+
58+
function handleUnreadChange(event, arg) {
59+
if (arg !== unreadCount) {
60+
unreadCount = arg;
61+
updateIcon();
62+
}
63+
}
64+
65+
function handleMentionsChange(event, arg) {
66+
if (arg !== mentionsCount) {
67+
mentionsCount = arg;
68+
updateIcon();
69+
}
70+
}
71+
72+
// Shows the tray icon.
73+
function enable(mainBrowserWindow) {
74+
mainWindow = mainBrowserWindow;
75+
76+
tray = new Tray(defaultIcon);
77+
tray.setToolTip(app.getName());
78+
79+
var tray_menu = createMenu();
80+
tray.setContextMenu(tray_menu);
81+
82+
tray.on('click', function() {
83+
mainBrowserWindow.restore();
84+
mainBrowserWindow.show();
85+
});
86+
87+
ipc.on('mention', handleMentionsChange);
88+
ipc.on('unread', handleUnreadChange);
89+
}
90+
91+
92+
module.exports = {
93+
enable: enable,
94+
isEnabled: isEnabled
95+
};

test/common.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
var chai = require("chai");
22
var chaiJq = require("chai-jq");
33
chai.use(chaiJq);
4+
var sinonChai = require("sinon-chai");
5+
chai.use(sinonChai);
46

57
global.expect = chai.expect;
68

test/electron-stub.js

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Returns a partial stub of the electron api.
3+
*/
4+
function create() {
5+
return {
6+
app: {
7+
getName: function() {}
8+
},
9+
10+
ipcMain: {
11+
on: function() {}
12+
},
13+
14+
nativeImage : {
15+
'createFromPath': function() {
16+
return {};
17+
}
18+
},
19+
20+
Tray: function() {
21+
var Tray = function() {};
22+
Tray.prototype.setToolTip = function() {};
23+
Tray.prototype.setContextMenu = function() {};
24+
Tray.prototype.on = function() {};
25+
return Tray;
26+
}(),
27+
28+
Menu: function() {
29+
var Menu = function() {};
30+
Menu.prototype.append = function() {};
31+
return Menu;
32+
}(),
33+
34+
MenuItem: function() {}
35+
}
36+
}
37+
38+
module.exports = {
39+
create: create
40+
};

test/tray-spec.js

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
var sinon = require("sinon");
2+
var proxyquire = require("proxyquire").noPreserveCache().noCallThru();
3+
var electronStub = require("./electron-stub.js");
4+
5+
describe('tray', function() {
6+
7+
var electron;
8+
var trayModule;
9+
10+
beforeEach(function() {
11+
electron = electronStub.create();
12+
electron.Tray = sinon.spy(electron.Tray);
13+
});
14+
15+
it('is initially disabled', function() {
16+
trayModule = proxyquire('../src/tray.js', {electron: electron});
17+
expect(electron.Tray).to.not.have.been.called;
18+
expect(trayModule.isEnabled()).to.be.false;
19+
});
20+
21+
it('creates a tray icon on enable()', function() {
22+
trayModule = proxyquire('../src/tray.js', {electron: electron});
23+
trayModule.enable({});
24+
expect(electron.Tray).to.have.been.calledOnce;
25+
expect(trayModule.isEnabled()).to.be.true;
26+
});
27+
28+
it('sets a tooltip for the tray icon', function() {
29+
electron.app.getName = function() {return "foo";}
30+
electron.Tray.prototype.setToolTip = sinon.spy();
31+
trayModule = proxyquire('../src/tray.js', {electron: electron});
32+
33+
trayModule.enable({});
34+
expect(electron.Tray.prototype.setToolTip).to.have.been.calledOnce;
35+
expect(electron.Tray.prototype.setToolTip).to.have.been.calledWith("foo");
36+
});
37+
38+
});

0 commit comments

Comments
 (0)