From 58cda9cc7fb79ca9df6746de7f9662bc08dc156a Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Fri, 13 Oct 2017 12:29:40 +0200 Subject: initial commit --- src/electron/Settings.js | 15 +++++++ src/electron/exception.js | 4 ++ src/electron/ipc-api/appIndicator.js | 80 ++++++++++++++++++++++++++++++++++++ src/electron/ipc-api/autoUpdate.js | 54 ++++++++++++++++++++++++ src/electron/ipc-api/index.js | 9 ++++ src/electron/ipc-api/settings.js | 10 +++++ src/electron/ipc-api/tray.js | 48 ++++++++++++++++++++++ src/electron/webview-ime-focus.js | 40 ++++++++++++++++++ 8 files changed, 260 insertions(+) create mode 100644 src/electron/Settings.js create mode 100644 src/electron/exception.js create mode 100644 src/electron/ipc-api/appIndicator.js create mode 100644 src/electron/ipc-api/autoUpdate.js create mode 100644 src/electron/ipc-api/index.js create mode 100644 src/electron/ipc-api/settings.js create mode 100644 src/electron/ipc-api/tray.js create mode 100644 src/electron/webview-ime-focus.js (limited to 'src/electron') diff --git a/src/electron/Settings.js b/src/electron/Settings.js new file mode 100644 index 000000000..049a08296 --- /dev/null +++ b/src/electron/Settings.js @@ -0,0 +1,15 @@ +export default class Settings { + store = {}; + + set(settings) { + this.store = Object.assign(this.store, settings); + } + + all() { + return this.store; + } + + get(key) { + return this.store[key]; + } +} diff --git a/src/electron/exception.js b/src/electron/exception.js new file mode 100644 index 000000000..0065e2604 --- /dev/null +++ b/src/electron/exception.js @@ -0,0 +1,4 @@ +process.on('uncaughtException', (err) => { + // handle the error safely + console.error(err); +}); diff --git a/src/electron/ipc-api/appIndicator.js b/src/electron/ipc-api/appIndicator.js new file mode 100644 index 000000000..576234d25 --- /dev/null +++ b/src/electron/ipc-api/appIndicator.js @@ -0,0 +1,80 @@ +import { app, ipcMain, Tray, Menu } from 'electron'; +import path from 'path'; + +const INDICATOR_TRAY_PLAIN = 'tray'; +const INDICATOR_TRAY_UNREAD = 'tray-unread'; +const INDICATOR_TASKBAR = 'taskbar'; + +const FILE_EXTENSION = process.platform === 'win32' ? 'ico' : 'png'; +let trayIcon; + +function getAsset(type, asset) { + return path.join( + __dirname, '..', '..', 'assets', 'images', type, process.platform, `${asset}.${FILE_EXTENSION}`, + ); +} + +export default (params) => { + trayIcon = new Tray(getAsset('tray', INDICATOR_TRAY_PLAIN)); + const trayMenuTemplate = [ + { + label: 'Show Franz', + click() { + params.mainWindow.show(); + }, + }, { + label: 'Quit Franz', + click() { + app.quit(); + }, + }, + ]; + + const trayMenu = Menu.buildFromTemplate(trayMenuTemplate); + trayIcon.setContextMenu(trayMenu); + + trayIcon.on('click', () => { + params.mainWindow.show(); + }); + + ipcMain.on('updateAppIndicator', (event, args) => { + // Update badge + if (process.platform === 'darwin' + && typeof (args.indicator) === 'string') { + app.dock.setBadge(args.indicator); + } + + if ((process.platform === 'darwin' + || process.platform === 'linux') + && typeof (args.indicator) === 'number' + ) { + app.setBadgeCount(args.indicator); + } + + if (process.platform === 'win32') { + if (typeof args.indicator === 'number' + && args.indicator !== 0) { + params.mainWindow.setOverlayIcon( + getAsset('taskbar', `${INDICATOR_TASKBAR}-${(args.indicator >= 10 ? 10 : args.indicator)}`), + '', + ); + } else if (typeof args.indicator === 'string') { + params.mainWindow.setOverlayIcon( + getAsset('taskbar', `${INDICATOR_TASKBAR}-alert`), + '', + ); + } else { + params.mainWindow.setOverlayIcon(null, ''); + } + } + + // Update system tray + trayIcon.setImage(getAsset('tray', args.indicator !== 0 ? INDICATOR_TRAY_UNREAD : INDICATOR_TRAY_PLAIN)); + + if (process.platform === 'darwin') { + trayIcon.setPressedImage( + getAsset('tray', `${args.indicator !== 0 ? INDICATOR_TRAY_UNREAD : INDICATOR_TRAY_PLAIN}-active`), + ); + } + }); +}; diff --git a/src/electron/ipc-api/autoUpdate.js b/src/electron/ipc-api/autoUpdate.js new file mode 100644 index 000000000..7bc193e2d --- /dev/null +++ b/src/electron/ipc-api/autoUpdate.js @@ -0,0 +1,54 @@ +import { app, ipcMain } from 'electron'; +import { autoUpdater } from 'electron-updater'; + +export default (params) => { + if (process.platform === 'darwin' || process.platform === 'win32') { + // autoUpdater.setFeedURL(updateUrl); + ipcMain.on('autoUpdate', (event, args) => { + try { + autoUpdater.allowPrerelease = Boolean(params.settings.get('beta')); + if (args.action === 'check') { + autoUpdater.checkForUpdates(); + } else if (args.action === 'install') { + console.log('install update'); + autoUpdater.quitAndInstall(); + // we need to send a quit event + setTimeout(() => { + app.quit(); + }, 20); + } + } catch (e) { + console.error(e); + event.sender.send('autoUpdate', { error: true }); + } + }); + + autoUpdater.on('update-not-available', () => { + console.log('update-not-available'); + params.mainWindow.webContents.send('autoUpdate', { available: false }); + }); + + autoUpdater.on('update-available', () => { + console.log('update-available'); + params.mainWindow.webContents.send('autoUpdate', { available: true }); + }); + + autoUpdater.on('download-progress', (progressObj) => { + let logMessage = `Download speed: ${progressObj.bytesPerSecond}`; + logMessage = `${logMessage} - Downloaded ${progressObj.percent}%`; + logMessage = `${logMessage} (${progressObj.transferred}/${progressObj.total})`; + + console.log(logMessage); + }); + + autoUpdater.on('update-downloaded', () => { + console.log('update-downloaded'); + params.mainWindow.webContents.send('autoUpdate', { downloaded: true }); + }); + + autoUpdater.on('error', () => { + console.log('update-error'); + params.mainWindow.webContents.send('autoUpdate', { error: true }); + }); + } +}; diff --git a/src/electron/ipc-api/index.js b/src/electron/ipc-api/index.js new file mode 100644 index 000000000..4ea6d1475 --- /dev/null +++ b/src/electron/ipc-api/index.js @@ -0,0 +1,9 @@ +import autoUpdate from './autoUpdate'; +import settings from './settings'; +import appIndicator from './appIndicator'; + +export default (params) => { + settings(params); + autoUpdate(params); + appIndicator(params); +}; diff --git a/src/electron/ipc-api/settings.js b/src/electron/ipc-api/settings.js new file mode 100644 index 000000000..1d7eafa6c --- /dev/null +++ b/src/electron/ipc-api/settings.js @@ -0,0 +1,10 @@ +import { ipcMain } from 'electron'; + +export default (params) => { + if (process.platform === 'darwin' || process.platform === 'win32') { + // eslint-disable-next-line + ipcMain.on('settings', (event, args) => { + params.settings.set(args); + }); + } +}; diff --git a/src/electron/ipc-api/tray.js b/src/electron/ipc-api/tray.js new file mode 100644 index 000000000..43364c0ed --- /dev/null +++ b/src/electron/ipc-api/tray.js @@ -0,0 +1,48 @@ +import { Tray, Menu, ipcMain } from 'electron'; +import path from 'path'; + +const INDICATOR_PLAIN = 'franz-taskbar'; +const INDICATOR_UNREAD = 'franz-taskbar-unread'; + +const FILE_EXTENSION = process.platform === 'win32' ? 'ico' : 'png'; + +let trayIcon; + +function getAsset(asset) { + return path.join( + __dirname, '..', '..', 'assets', 'images', 'tray', process.platform, `${asset}.${FILE_EXTENSION}`, + ); +} + +export default (params) => { + // if (process.platform === 'win32' || process.platform === 'linux') { + trayIcon = new Tray(getAsset(INDICATOR_PLAIN)); + const trayMenuTemplate = [ + { + label: 'Show Franz', + click() { + params.mainWindow.show(); + }, + }, { + label: 'Quit Franz', + click() { + params.app.quit(); + }, + }, + ]; + + const trayMenu = Menu.buildFromTemplate(trayMenuTemplate); + trayIcon.setContextMenu(trayMenu); + + trayIcon.on('click', () => { + params.mainWindow.show(); + }); + + ipcMain.on('updateTrayIconIndicator', (event, args) => { + trayIcon.setImage(getAsset(args.count !== 0 ? INDICATOR_UNREAD : INDICATOR_PLAIN)); + + if (process.platform === 'darwin') { + trayIcon.setPressedImage(getAsset(`${args.count !== 0 ? INDICATOR_UNREAD : INDICATOR_PLAIN}-active`)); + } + }); +}; diff --git a/src/electron/webview-ime-focus.js b/src/electron/webview-ime-focus.js new file mode 100644 index 000000000..1213b518e --- /dev/null +++ b/src/electron/webview-ime-focus.js @@ -0,0 +1,40 @@ +const { releaseDocumentFocus } = require('./webview-ime-focus-helpers'); + +function giveWebviewDocumentFocus(element) { + releaseDocumentFocus(); + + window.requestAnimationFrame(() => { + element.send('claim-document-focus'); + }); +} + +function elementIsUnfocusedWebview(element) { + return element.tagName === 'WEBVIEW' && !element.getWebContents().isFocused(); +} + +function webviewDidAutofocus(element) { + function didKeyDown() { + element.removeEventListener('keydown', didKeyDown, true); + giveWebviewDocumentFocus(element); + } + + element.addEventListener('keydown', didKeyDown, true); +} + +function handleAutofocus(element) { + element.addEventListener('ipc-message', (event) => { + if (event.channel === 'autofocus') { + element.focus(); + webviewDidAutofocus(element); + } + }); +} + +function didMouseDown(event) { + if (elementIsUnfocusedWebview(event.target)) { + giveWebviewDocumentFocus(event.target); + } +} + +document.addEventListener('mousedown', didMouseDown, true); +document.querySelectorAll('webview').forEach(handleAutofocus); -- cgit v1.2.3-70-g09d2