Fix #304 - Add --tray CLI flag to let app running in background on window close. Supports in-title counter. (#457)

This commit is contained in:
omouren 2017-10-06 01:32:48 +02:00 committed by Ronan Jouchet
parent 4c581f9067
commit 885790bc22
7 changed files with 99 additions and 3 deletions

View File

@ -10,11 +10,14 @@ const { isOSX, linkIsInternal, getCssToInject, shouldInjectCss } = helpers;
const ZOOM_INTERVAL = 0.1;
function maybeHideWindow(window, event, fastQuit) {
function maybeHideWindow(window, event, fastQuit, tray) {
if (isOSX() && !fastQuit) {
// this is called when exiting from clicking the cross button on the window
event.preventDefault();
window.hide();
} else if (!fastQuit && tray) {
event.preventDefault();
window.hide();
}
// will close the window on other platforms
}
@ -211,7 +214,7 @@ function createMainWindow(inpOptions, onAppQuit, setDockBadge) {
mainWindow.setFullScreen(false);
mainWindow.once('leave-full-screen', maybeHideWindow.bind(this, mainWindow, event, options.fastQuit));
}
maybeHideWindow(mainWindow, event, options.fastQuit);
maybeHideWindow(mainWindow, event, options.fastQuit, options.tray);
});
return mainWindow;

View File

@ -0,0 +1,79 @@
import path from 'path';
const { app, Tray, Menu, ipcMain } = require('electron');
/**
*
* @param {{}} inpOptions AppArgs from nativefier.json
* @param {electron.BrowserWindow} mainWindow MainWindow created from main.js
* @returns {electron.Tray}
*/
function createTrayIcon(inpOptions, mainWindow) {
const options = Object.assign({}, inpOptions);
if (options.tray) {
const iconPath = path.join(__dirname, '../', '/icon.png');
const appIcon = new Tray(iconPath);
const onClick = () => {
if (mainWindow.isVisible()) {
mainWindow.hide();
} else {
mainWindow.show();
}
};
const contextMenu = Menu.buildFromTemplate([
{
label: options.name,
click: onClick,
},
{
label: 'Quit',
click: app.exit,
},
]);
appIcon.on('click', onClick);
mainWindow.on('show', () => {
appIcon.setHighlightMode('always');
});
mainWindow.on('hide', () => {
appIcon.setHighlightMode('never');
});
if (options.counter) {
mainWindow.on('page-title-updated', (e, title) => {
const itemCountRegex = /[([{](\d*?)\+?[}\])]/;
const match = itemCountRegex.exec(title);
if (match) {
appIcon.setToolTip(`(${match[1]}) ${options.name}`);
} else {
appIcon.setToolTip(options.name);
}
});
} else {
ipcMain.on('notification', () => {
if (mainWindow.isFocused()) {
return;
}
appIcon.setToolTip(`${options.name}`);
});
mainWindow.on('focus', () => {
appIcon.setToolTip(options.name);
});
}
appIcon.setToolTip(options.name);
appIcon.setContextMenu(contextMenu);
return appIcon;
}
return null;
}
export default createTrayIcon;

View File

@ -6,6 +6,7 @@ import electronDownload from 'electron-dl';
import createLoginWindow from './components/login/loginWindow';
import createMainWindow from './components/mainWindow/mainWindow';
import createTrayIcon from './components/trayIcon/trayIcon';
import helpers from './helpers/helpers';
import inferFlash from './helpers/inferFlash';
@ -103,6 +104,7 @@ if (appArgs.crashReporter) {
app.on('ready', () => {
mainWindow = createMainWindow(appArgs, app.quit, setDockBadge);
createTrayIcon(appArgs, mainWindow);
});
app.on('login', (event, webContents, request, authInfo, callback) => {

View File

@ -40,6 +40,7 @@
- [[zoom]](#zoom)
- [[crash-reporter]](#crash-reporter)
- [[single-instance]](#single-instance)
- [[tray]](#tray)
- [[basic-auth-username]](#basic-auth-username)
- [[basic-auth-password]](#basic-auth-username)
- [Programmatic API](#programmatic-api)
@ -410,6 +411,14 @@ Sets a default zoom factor to be used when the app is opened, defaults to `1.0`.
Prevents application from being run multiple times. If such an attempt occurs the already running instance is brought to front.
#### [tray]
```
--tray
```
Application will stay as an icon in the system tray. Prevents application from being closed from clicking the window close button.
#### [basic-auth-username]
```
@ -418,6 +427,7 @@ Prevents application from being run multiple times. If such an attempt occurs th
Set basic http(s) auth via the command line to have the app automatically log you in to a protected site. Both fields are required if one is set.
#### [processEnvs]
```

View File

@ -46,6 +46,7 @@ function selectAppArgs(options) {
win32metadata: options.win32metadata,
versionString: options.versionString,
processEnvs: options.processEnvs,
tray: options.tray,
basicAuthUsername: options.basicAuthUsername,
basicAuthPassword: options.basicAuthPassword,
};

View File

@ -82,6 +82,7 @@ if (require.main === module) {
.option('--crash-reporter <value>', 'remote server URL to send crash reports')
.option('--single-instance', 'allow only a single instance of the application')
.option('--processEnvs <json-string>', 'a JSON string of key/value pairs to be set as environment variables before any browser windows are opened.', getProcessEnvs)
.option('--tray', 'allow app to stay in system tray')
.option('--basic-auth-username <value>', 'basic http(s) auth username')
.option('--basic-auth-password <value>', 'basic http(s) auth password')
.parse(process.argv);

View File

@ -66,6 +66,7 @@ export default function (inpOptions) {
FileDescription: inpOptions.name,
},
processEnvs: inpOptions.processEnvs,
tray: inpOptions.tray || false,
basicAuthUsername: inpOptions.basicAuthUsername || null,
basicAuthPassword: inpOptions.basicAuthPassword || null,
};
@ -102,4 +103,3 @@ export default function (inpOptions) {
return asyncConfig(options);
}