diff --git a/ReleaseNotes.md b/ReleaseNotes.md index a6b8d80..3a38636 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,16 +1,12 @@ -## Version 0.2.0 +## Version 0.2.1 --- Release highlights: -* Added copying of logs to the clipboard +* Added tray icon --- -# Copying logs to the clipboard +# Tray Icon -It is now possible to copy the entire log of a terminal to the systems clipboard. This also includes the selected text. - -To copy only the selected text, first highlight the desired text then right click on the terminal. - -To copy the entire log, select `Copy Log` from the drop down menu of each terminal. +It is now possible to minimize Dotnet Runner to the system tray. A tray icon has been created, when minimized clicking the icon will maximize the application. diff --git a/app/Components/runner/Runner.js b/app/Components/runner/Runner.js index 4fd2c0c..13e4dd3 100644 --- a/app/Components/runner/Runner.js +++ b/app/Components/runner/Runner.js @@ -163,6 +163,8 @@ module.exports = class RunnerElement extends WebComponentBase { this._runningProccess.on('data', (d) => { this._terminalProcess.write(d); }); + + this._emitEvent('starting'); } clean() { @@ -196,6 +198,8 @@ module.exports = class RunnerElement extends WebComponentBase { this.setState(RunnerElement.states.stopping); this._runningProccess.kill(); + + this._emitEvent('stopped'); } exportLog() { @@ -234,17 +238,26 @@ module.exports = class RunnerElement extends WebComponentBase { stateEl.textContent = 'Starting'; stateEl.className = 'state badge badge-info'; actionBtn.textContent = 'Stop'; + this._emitEvent('state-change', { + state: RunnerElement.states.starting + }); break; case RunnerElement.states.running: stateEl.textContent = 'Running'; stateEl.className = 'state badge badge-success'; actionBtn.textContent = 'Stop'; this._enableAction(); + this._emitEvent('state-change', { + state: RunnerElement.states.running + }); break; case RunnerElement.states.stopping: stateEl.textContent = 'Stopping'; stateEl.className = 'state badge badge-info'; actionBtn.textContent = 'Start'; + this._emitEvent('state-change', { + state: RunnerElement.states.stopping + }); break; case RunnerElement.states.stopped: stateEl.textContent = 'Stopped'; @@ -252,10 +265,22 @@ module.exports = class RunnerElement extends WebComponentBase { this._enableAction(); this._enableClean(); actionBtn.textContent = 'Start'; + this._emitEvent('state-change', { + state: RunnerElement.states.stopped + }); break; } } + _emitEvent(key, data) { + const e = new CustomEvent(key, { + detail: data, + bubbles: true + }); + + this.dispatchEvent(e); + } + static register() { customElements.define('runner-element', RunnerElement); } diff --git a/app/DotnetRunnerApp.js b/app/DotnetRunnerApp.js index a4e09f3..62d4f75 100644 --- a/app/DotnetRunnerApp.js +++ b/app/DotnetRunnerApp.js @@ -213,6 +213,13 @@ module.exports = class DotnetRunnerApp { this._enableTasks(); } + _handleMinimizeToTray() { + this._mainWindow.on('minimize', (e) => { + e.preventDefault(); + this._mainWindow.hide(); + }); + } + /** * @returns {Menu} */ @@ -246,6 +253,8 @@ module.exports = class DotnetRunnerApp { this._menu.setApplicationMenu(this.getMenu()); + this._handleMinimizeToTray(); + const eixstingApps = getApplications(); if (!eixstingApps || eixstingApps.length === 0) { @@ -254,7 +263,7 @@ module.exports = class DotnetRunnerApp { if (displayReleaseNotes) this._mainWindow.once('ready-to-show', () => this._displayReleaseNotes()); - + return this; } @@ -267,4 +276,8 @@ module.exports = class DotnetRunnerApp { once(...args) { this._mainWindow.once(...args); } + + on(...args) { + ipcMain.on(...args); + } } \ No newline at end of file diff --git a/app/assets/icon.ico b/app/assets/icon.ico new file mode 100644 index 0000000..009e4c5 Binary files /dev/null and b/app/assets/icon.ico differ diff --git a/app/browserWindows/main/main.js b/app/browserWindows/main/main.js index ac9f260..44e68d8 100644 --- a/app/browserWindows/main/main.js +++ b/app/browserWindows/main/main.js @@ -22,6 +22,16 @@ let apps = []; document.addEventListener('DOMContentLoaded', onDomContentLoaded); + +document.addEventListener('state-change', () => { + const running = apps.reduce((accu, cur) => cur.component.state !== Runner.states.stopped ? accu + 1 : accu, 0); + + if (running === 0) + ipcRenderer.send(ipcMessages.trayTooltipText, ''); + else + ipcRenderer.send(ipcMessages.trayTooltipText, `(${running}) ${running ? 'app' : 'apps'} running`); +}); + ipcRenderer.on(ipcMessages.reloadApplications, onReloadDataIPC); ipcRenderer.on(ipcMessages.displayReleaseNotes, onDisplayReleaseNotes); diff --git a/app/ipcMessages.js b/app/ipcMessages.js index 298b317..9e2bf41 100644 --- a/app/ipcMessages.js +++ b/app/ipcMessages.js @@ -6,5 +6,6 @@ module.exports = Object.freeze({ reloadApplications: 'reload-apps', displayReleaseNotes: 'display-release-notes', displayPreferences: 'display-preferences', - taskComplete: 'task-complete' + taskComplete: 'task-complete', + trayTooltipText: 'tray-tooltip-text' }); \ No newline at end of file diff --git a/app/tray.js b/app/tray.js new file mode 100644 index 0000000..f3af8cc --- /dev/null +++ b/app/tray.js @@ -0,0 +1,26 @@ +const { Tray, Menu } = require('electron'); +const path = require('path'); + +let trayInstance; + +module.exports.create = function({ + onQuit, + onClick +}) { + trayInstance = new Tray(path.join(__dirname, 'assets/icon.ico')); + + const contextMenu = Menu.buildFromTemplate([ + { + label: 'Quit', click: onQuit + } + ]); + + trayInstance.setContextMenu(contextMenu); + + if (onClick) + trayInstance.on('click', onClick); +} + +module.exports.setTooltip = function(tooltipText) { + trayInstance.setToolTip(tooltipText); +} \ No newline at end of file diff --git a/package.json b/package.json index ea81431..37e9150 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dotnet-runner", - "version": "0.2.0", + "version": "0.2.1", "description": "Electron application to launch dotnet applications", "main": "startup.js", "scripts": { diff --git a/startup.js b/startup.js index 8975a57..2c208a1 100644 --- a/startup.js +++ b/startup.js @@ -5,6 +5,10 @@ const SplashScreenApp = require('./app/SplashScreenApp'); const preferenceStore = require('./app/data/preferencesStore'); +const ipcMessages = require('./app/ipcMessages'); + +const tray = require('./app/tray'); + const splashApp = new SplashScreenApp(); const dotnetApp = new DotnetRunnerApp(BrowserWindow, Menu); @@ -15,9 +19,19 @@ splashApp.onReady = function(settings) { .once('ready-to-show', () => { splashApp.close(); dotnetApp.show(); + + tray.create({ + onQuit() { + app.quit(); + }, + onClick() { + dotnetApp.show() + } + }); + + dotnetApp.on(ipcMessages.trayTooltipText, (e, t) => tray.setTooltip(t)); }); } - app.on('ready', () => { splashApp.run(); });