Browse Source

Tray and Menu

- Added unread tray.
- Added tray and menu options to the app.
pull/3/head
saenzramiro 9 years ago
parent
commit
5088f1d07a
  1. 3
      app.json
  2. 12
      app/Application.js
  3. 15
      app/ux/WebView.js
  4. 4
      app/view/main/Main.js
  5. 203
      electron/menu.js
  6. 88
      electron/tray.js
  7. 82
      electron_main.js
  8. 6
      package.json
  9. BIN
      resources/Icon.icns
  10. BIN
      resources/Icon.ico
  11. 0
      resources/Icon.png
  12. 28
      resources/Icon.svg
  13. BIN
      resources/IconTray.png
  14. BIN
      resources/IconTray@2x.png
  15. BIN
      resources/IconTray@4x.png
  16. BIN
      resources/IconTrayUnread.ico
  17. BIN
      resources/IconTrayUnread.png
  18. BIN
      resources/IconTrayUnread@2x.png
  19. BIN
      resources/IconTrayUnread@4x.png
  20. BIN
      resources/logo_128.png
  21. BIN
      resources/logo_16.png
  22. BIN
      resources/logo_32.png
  23. BIN
      resources/logo_64.png

3
app.json

@ -277,7 +277,8 @@
* Extra resources to be copied along when build * Extra resources to be copied along when build
*/ */
"resources": [ "resources": [
"main.js", "electron",
"electron_main.js",
"package.json" "package.json"
], ],

12
app/Application.js

@ -9,7 +9,8 @@ Ext.define('Rambox.Application', {
] ]
,config: { ,config: {
totalServicesLoaded: 0 totalServicesLoaded: 0
,totalNotifications: 0
} }
,launch: function () { ,launch: function () {
@ -23,4 +24,13 @@ Ext.define('Rambox.Application', {
} }
}); });
} }
,updateTotalNotifications: function( newValue, oldValue ) {
newValue = parseInt(newValue);
if ( newValue > 0 ) {
document.title = 'Rambox (' + newValue + ')';
} else {
document.title = 'Rambox';
}
}
}); });

15
app/ux/WebView.js

@ -40,14 +40,25 @@ Ext.define('Rambox.ux.WebView',{
,autosize: 'on' ,autosize: 'on'
} }
}] }]
,tabConfig: {
listeners: {
badgetextchange: me.onBadgeTextChange
}
}
,listeners: { ,listeners: {
afterrender: me.onAfterRender afterrender: me.onAfterRender
} }
}); });
me.callParent(config); me.callParent(config);
} }
,onBadgeTextChange: function( tab, badgeText, oldBadgeText ) {
if ( oldBadgeText === null ) oldBadgeText = 0;
var actualNotifications = Rambox.app.getTotalNotifications();
Rambox.app.setTotalNotifications(actualNotifications - parseInt(oldBadgeText) + parseInt(badgeText));
}
,onAfterRender: function() { ,onAfterRender: function() {
var me = this; var me = this;
var webview = me.down('component').el.dom; var webview = me.down('component').el.dom;
@ -119,7 +130,7 @@ Ext.define('Rambox.ux.WebView',{
me.tab.setBadgeText(1); me.tab.setBadgeText(1);
me.notifications = 1; me.notifications = 1;
} else { } else {
me.tab.setBadgeText(''); me.tab.setBadgeText(0);
me.notifications = 0; me.notifications = 0;
} }
break; break;

4
app/view/main/Main.js

@ -35,13 +35,13 @@ Ext.define('Rambox.view.main.Main', {
} }
} }
] ]
,autoRender: true ,autoRender: true
,autoShow: true ,autoShow: true
,deferredRender: false ,deferredRender: false
,items: [ ,items: [
{ {
icon: 'resources/logo_32.png' icon: 'resources/IconTray.png'
,closable: false ,closable: false
,reorderable: false ,reorderable: false
,autoScroll: true ,autoScroll: true

203
electron/menu.js

@ -0,0 +1,203 @@
'use strict';
const os = require('os');
const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const shell = electron.shell;
const appName = app.getName();
function sendAction(action) {
const win = BrowserWindow.getAllWindows()[0];
if (process.platform === 'darwin') {
win.restore();
}
win.webContents.send(action);
}
const helpSubmenu = [
{
label: `Visit ${appName} Website`,
click() {
shell.openExternal('http://saenzramiro.github.io/rambox/');
}
},
{
label: 'Report an Issue...',
click() {
const body = `
<!-- Please describe here your issue and steps to reproduce it. -->
<!-- DON'T REMOVE THE FOLLOWING LINES -->
-
> ${app.getName()} ${app.getVersion()}
> Electron ${process.versions.electron}
> ${process.platform} ${process.arch} ${os.release()}`;
shell.openExternal(`https://github.com/saenzramiro/rambox/issues/new?body=${encodeURIComponent(body)}`);
}
}
];
let tpl = [
{
label: 'Edit',
submenu: [
{
label: 'Undo',
accelerator: 'CmdOrCtrl+Z',
role: 'undo'
},
{
label: 'Redo',
accelerator: 'Shift+CmdOrCtrl+Z',
role: 'redo'
},
{
type: 'separator'
},
{
label: 'Cut',
accelerator: 'CmdOrCtrl+X',
role: 'cut'
},
{
label: 'Copy',
accelerator: 'CmdOrCtrl+C',
role: 'copy'
},
{
label: 'Paste',
accelerator: 'CmdOrCtrl+V',
role: 'paste'
},
{
label: 'Select All',
accelerator: 'CmdOrCtrl+A',
role: 'selectall'
},
]
},
{
label: 'View',
submenu: [
{
label: 'Reload',
accelerator: 'CmdOrCtrl+R',
click(item, focusedWindow) {
if (focusedWindow) focusedWindow.reload();
}
},
{
label: 'Toggle Full Screen',
accelerator: process.platform === 'darwin' ? 'Ctrl+Command+F' : 'F11',
click(item, focusedWindow) {
if (focusedWindow)
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
}
},
{
label: 'Toggle Developer Tools',
accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
click(item, focusedWindow) {
if (focusedWindow)
focusedWindow.webContents.toggleDevTools();
}
},
]
},
{
label: 'Window',
role: 'window',
submenu: [
{
label: 'Minimize',
accelerator: 'CmdOrCtrl+M',
role: 'minimize'
},
{
label: 'Close',
accelerator: 'CmdOrCtrl+W',
role: 'close'
},
]
},
{
label: 'Help',
role: 'help'
}
];
if (process.platform === 'darwin') {
tpl.unshift({
label: appName,
submenu: [
{
label: `About ${appName}`,
role: 'about'
},
{
type: 'separator'
},
{
label: 'Services',
role: 'services',
submenu: []
},
{
type: 'separator'
},
{
label: `Hide ${appName}`,
accelerator: 'Command+H',
role: 'hide'
},
{
label: 'Hide Others',
accelerator: 'Command+Alt+H',
role: 'hideothers'
},
{
label: 'Show All',
role: 'unhide'
},
{
type: 'separator'
},
{
label: `Quit ${appName}`,
accelerator: 'Cmd+Q',
click() {
app.quit();
}
}
]
});
} else {
tpl.unshift({
label: 'File',
submenu: [
{
label: `Quit ${appName}`,
accelerator: 'Cmd+Q',
click() {
app.quit();
}
}
]
});
helpSubmenu.push({
type: 'separator'
});
helpSubmenu.push({
label: `About ${appName}`,
role: 'about'
});
}
tpl[tpl.length - 1].submenu = helpSubmenu;
module.exports = electron.Menu.buildFromTemplate(tpl);

88
electron/tray.js

@ -0,0 +1,88 @@
const path = require('path');
const electron = require('electron');
const app = electron.app;
const MenuItem = electron.MenuItem;
let tray = null;
exports.create = win => {
if (process.platform === 'darwin' || tray) {
return;
}
const icon = process.platform === 'linux' ? 'IconTray.png' : 'Icon.ico';
const iconPath = path.join(__dirname, `../resources/${icon}`);
let showMB = new MenuItem({
label: 'Show Rambox'
,position: '1'
,visible: false
,click(btn) {
win.show();
contextMenu.items[0].visible = false;
contextMenu.items[1].visible = true;
}
});
let hideMB = new MenuItem({
label: 'Minimize Rambox'
,position: '2'
,click(btn) {
win.hide();
contextMenu.items[1].visible = false;
contextMenu.items[0].visible = true;
}
});
const contextMenu = electron.Menu.buildFromTemplate([
showMB,
hideMB,
{
label: 'Preferences'
},
{
type: 'separator'
},
{
label: 'Quit'
,click() {
app.quit();
}
}
]);
tray = new electron.Tray(iconPath);
tray.setToolTip('Rambox');
tray.setContextMenu(contextMenu);
tray.on('click', function() {
if ( win.isVisible() ) {
win.hide();
contextMenu.items[1].visible = false;
contextMenu.items[0].visible = true;
} else {
win.show();
contextMenu.items[0].visible = false;
contextMenu.items[1].visible = true;
}
});
win.on('hide', function() {
contextMenu.items[1].visible = false;
contextMenu.items[0].visible = true;
});
};
exports.setBadge = shouldDisplayUnread => {
if (process.platform === 'darwin' || !tray) {
return;
}
let icon;
if (process.platform === 'linux') {
icon = shouldDisplayUnread ? 'IconTrayUnread.png' : 'IconTray.png';
} else {
icon = shouldDisplayUnread ? 'IconTrayUnread.ico' : 'Icon.ico';
}
const iconPath = path.join(__dirname, `../resources/${icon}`);
tray.setImage(iconPath);
};

82
main.js → electron_main.js

@ -9,6 +9,10 @@ const BrowserWindow = electron.BrowserWindow;
const Tray = electron.Tray; const Tray = electron.Tray;
// Module for shell // Module for shell
const shell = require('electron').shell; const shell = require('electron').shell;
// Require for menu file
const appMenu = require('./electron/menu');
// Require for tray file
const tray = require('./electron/tray');
const MenuItem = electron.MenuItem; const MenuItem = electron.MenuItem;
@ -16,62 +20,15 @@ const MenuItem = electron.MenuItem;
// be closed automatically when the JavaScript object is garbage collected. // be closed automatically when the JavaScript object is garbage collected.
let mainWindow; let mainWindow;
let isQuitting = false; let isQuitting = false;
let tray = null;
let showMB = new MenuItem({
label: 'Show Rambox'
,position: '1'
,visible: false
,click(btn) {
mainWindow.show();
contextMenu.items[0].visible = false;
contextMenu.items[1].visible = true;
}
});
let hideMB = new MenuItem({
label: 'Minimize Rambox'
,position: '2'
,click(btn) {
mainWindow.hide();
contextMenu.items[1].visible = false;
contextMenu.items[0].visible = true;
}
});
const contextMenu = electron.Menu.buildFromTemplate([
showMB,
hideMB,
{
label: 'Preferences'
},
{
label: 'Open Developer Console'
,click() {
mainWindow.webContents.openDevTools();
}
},
{
type: 'separator'
},
{
label: 'Quit'
,click() {
app.quit();
}
}
]);
function createWindow () { function createWindow () {
// Create the browser window. // Create the browser window.
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
title: 'Rambox' title: 'Rambox'
,skipTaskbar: false ,skipTaskbar: false
,icon: __dirname + '/resources/logo_256.png' ,icon: __dirname + '/resources/Icon.png'
,autoHideMenuBar: true
,webPreferences: { ,webPreferences: {
webSecurity: false webSecurity: false
,partition: 'trusted*'
,nodeIntegration: true ,nodeIntegration: true
,plugins: true ,plugins: true
,partition: 'persist:rambox' ,partition: 'persist:rambox'
@ -84,20 +41,11 @@ function createWindow () {
// and load the index.html of the app. // and load the index.html of the app.
mainWindow.loadURL('file://' + __dirname + '/index.html'); mainWindow.loadURL('file://' + __dirname + '/index.html');
tray = new Tray(__dirname + '/resources/logo_256.png'); electron.Menu.setApplicationMenu(appMenu);
tray.setToolTip('Rambox');
tray.setContextMenu(contextMenu); tray.create(mainWindow);
tray.on('click', function() {
if ( mainWindow.isVisible() ) { mainWindow.on('page-title-updated', (e, title) => updateBadge(title));
mainWindow.hide();
contextMenu.items[1].visible = false;
contextMenu.items[0].visible = true;
} else {
mainWindow.show();
contextMenu.items[0].visible = false;
contextMenu.items[1].visible = true;
}
});
// Emitted when the window is closed. // Emitted when the window is closed.
mainWindow.on('close', function(e) { mainWindow.on('close', function(e) {
@ -117,6 +65,16 @@ function createWindow () {
}); });
} }
function updateBadge(title) {
const messageCount = (/\(([0-9]+)\)/).exec(title);
if (process.platform === 'darwin') {
app.dock.setBadge(messageCount ? messageCount[1] : '');
} else {
tray.setBadge(messageCount);
}
}
// This method will be called when Electron has finished // This method will be called when Electron has finished
// initialization and is ready to create browser windows. // initialization and is ready to create browser windows.
app.on('ready', createWindow); app.on('ready', createWindow);

6
package.json

@ -2,9 +2,9 @@
"name": "Rambox", "name": "Rambox",
"version": "0.1.0", "version": "0.1.0",
"description": "Free messaging app that combines chat and messaging common services into one application.", "description": "Free messaging app that combines chat and messaging common services into one application.",
"main": "main.js", "main": "electron_main.js",
"scripts": { "scripts": {
"start": "electron main.js" "start": "electron electron_main.js"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -24,7 +24,7 @@
"skype" "skype"
], ],
"author": "Ramiro Saenz", "author": "Ramiro Saenz",
"license": "CC0-1.0", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/saenzramiro/rambox/issues" "url": "https://github.com/saenzramiro/rambox/issues"
}, },

BIN
resources/Icon.icns

Binary file not shown.

BIN
resources/Icon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

0
resources/logo_256.png → resources/Icon.png

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

28
resources/Icon.svg

@ -0,0 +1,28 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="256.000000pt" height="256.000000pt" viewBox="0 0 256.000000 256.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.13, written by Peter Selinger 2001-2015
</metadata>
<g transform="translate(0.000000,256.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M1675 2490 c-118 -25 -265 -97 -316 -156 -16 -19 -29 -51 -28 -68 0
-5 -3 -12 -8 -15 -17 -12 -84 -157 -90 -194 -4 -25 -9 -34 -14 -26 -12 21 -23
-39 -11 -64 6 -12 20 -62 31 -110 12 -48 43 -132 68 -185 26 -53 49 -104 50
-112 2 -8 7 -44 13 -80 6 -36 12 -71 15 -77 2 -7 -1 -13 -7 -13 -24 0 17 -28
65 -44 36 -12 68 -37 132 -100 47 -47 85 -83 85 -80 0 2 8 -4 18 -13 11 -10
17 -22 15 -28 -12 -27 39 45 56 80 42 85 41 88 -38 119 -230 90 -410 299 -460
534 -56 264 112 508 382 555 56 9 81 9 145 -5 42 -8 78 -15 78 -14 1 0 -5 25
-14 54 l-15 52 -56 -1 c-31 -1 -74 -5 -96 -9z"/>
<path d="M1906 1793 c-3 -21 -6 -54 -5 -73 0 -30 1 -32 9 -13 12 29 58 38 198
38 61 0 112 3 112 7 0 11 -121 47 -214 63 -49 8 -90 15 -91 15 -1 0 -5 -17 -9
-37z"/>
<path d="M1587 959 c-29 -17 -157 -59 -232 -75 -99 -22 -316 -29 -428 -14 -51
7 -126 23 -167 36 -41 13 -76 22 -78 20 -5 -5 105 -46 122 -46 8 0 24 -11 37
-25 13 -13 29 -25 35 -25 5 0 64 -17 130 -38 66 -22 185 -49 266 -62 87 -14
144 -28 141 -34 -4 -5 10 4 30 20 35 27 115 132 166 217 23 38 16 48 -22 26z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
resources/IconTray.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
resources/IconTray@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
resources/IconTray@4x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
resources/IconTrayUnread.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

BIN
resources/IconTrayUnread.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
resources/IconTrayUnread@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
resources/IconTrayUnread@4x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
resources/logo_128.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

BIN
resources/logo_16.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 823 B

BIN
resources/logo_32.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

BIN
resources/logo_64.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Loading…
Cancel
Save