diff --git a/gui/js/tray.js b/gui/js/tray.js index 4e6485ba3..8be4edb5c 100644 --- a/gui/js/tray.js +++ b/gui/js/tray.js @@ -3,11 +3,12 @@ * @module gui/js/tray */ -const { Tray, Menu, MenuItem } = require('electron') +const { Tray, Menu, MenuItem, nativeImage } = require('electron') const { translate } = require('./i18n') const path = require('path') let tray = null +let lastIconName = null const imgs = path.resolve(__dirname, '..', 'images') const isMac = process.platform === 'darwin' @@ -16,15 +17,35 @@ const isKde = process.env.XDG_CURRENT_DESKTOP && process.env.XDG_CURRENT_DESKTOP.match(/KDE/) +const platformIcon = (iconName, { pressed = false } = {}) => + nativeImage.createFromPath( + isMac + ? pressed + ? `${imgs}/tray-icon-osx/${iconName}Highlight.png` + : `${imgs}/tray-icon-osx/${iconName}Template.png` + : isWindows + ? `${imgs}/tray-icon-win/${iconName}.png` + : isKde + ? `${imgs}/tray-icon-linux-kde/${iconName}.png` + : `${imgs}/tray-icon-linux/${iconName}.png` + ) + +const setImage = iconName => { + const icon = platformIcon(iconName) + tray.setImage(icon) + + if (isMac) { + const pressedIcon = platformIcon(iconName, { pressed: true }) + tray.setPressedImage(pressedIcon) + } + + lastIconName = iconName +} + module.exports.init = (app, listener) => { - let icon = isMac - ? `${imgs}/tray-icon-osx/idleTemplate.png` - : isWindows - ? `${imgs}/tray-icon-win/idle.png` - : isKde - ? `${imgs}/tray-icon-linux-kde/idle.png` - : `${imgs}/tray-icon-linux/idle.png` - tray = new Tray(icon) + tray = new Tray(nativeImage.createEmpty()) + setImage('idle') + app.on('before-quit', () => tray.destroy()) let cachedBounds = null @@ -125,20 +146,8 @@ const systrayInfo = (status, label) => { } const setStatus = (module.exports.setStatus = (status, label) => { - const [icon, tooltip] = systrayInfo(status, label) - + const [iconName, tooltip] = systrayInfo(status, label) tray.setToolTip(tooltip) - if (process.platform === 'darwin') { - tray.setImage(`${imgs}/tray-icon-osx/${icon}Template.png`) - tray.setPressedImage(`${imgs}/tray-icon-osx/${icon}Highlight.png`) - } else if (process.platform === 'win32') { - tray.setImage(`${imgs}/tray-icon-win/${icon}.png`) - } else if ( - process.env.XDG_CURRENT_DESKTOP && - process.env.XDG_CURRENT_DESKTOP.match(/KDE/) - ) { - tray.setImage(`${imgs}/tray-icon-linux-kde/${icon}.png`) - } else { - tray.setImage(`${imgs}/tray-icon-linux/${icon}.png`) - } + + if (lastIconName !== iconName) setImage(iconName) }) diff --git a/gui/main.js b/gui/main.js index 82b18c4fa..4cd7f4381 100644 --- a/gui/main.js +++ b/gui/main.js @@ -9,6 +9,7 @@ const pkg = require('../package.json') const path = require('path') const os = require('os') +const async = require('async') const proxy = require('./js/proxy') const { @@ -104,11 +105,11 @@ const setupDesktop = async () => { desktopIsKO(err) if (err instanceof config.InvalidConfigError) { - showInvalidConfigError() + await showInvalidConfigError() } else if (err instanceof migrations.MigrationFailedError) { - showMigrationError(err) + await showMigrationError(err) } else { - dialog.showMessageBoxSync(null, { + await dialog.showMessageBox(null, { type: 'error', message: err.message, buttons: [translate('AppMenu Close')] @@ -167,7 +168,7 @@ const showWindow = async bounds => { } } -const showInvalidConfigError = () => { +const showInvalidConfigError = async () => { const options = { type: 'warning', title: translate('InvalidConfiguration Invalid configuration'), @@ -180,8 +181,8 @@ const showInvalidConfigError = () => { buttons: [translate('Button Log out'), translate('Button Contact support')], defaultId: 0 } - const userChoice = dialog.showMessageBoxSync(null, options) - if (userChoice === 0) { + const { response } = await dialog.showMessageBox(null, options) + if (response === 0) { desktop .removeConfig() .then(() => log.info('removed')) @@ -194,7 +195,7 @@ const showInvalidConfigError = () => { } } -const showMigrationError = (err /*: Error */) => { +const showMigrationError = async (err /*: Error */) => { const errorDetails = [`${err.name}:`].concat( err.errors.map(pouchErr => pouchErr.toString()) ) @@ -209,14 +210,14 @@ const showMigrationError = (err /*: Error */) => { buttons: [translate('Button Contact support')], defaultId: 0 } - const userChoice = dialog.showMessageBoxSync(null, options) - if (userChoice === 0) { + const { response } = await dialog.showMessageBox(null, options) + if (response === 0) { helpWindow = new HelpWM(app, desktop) helpWindow.show() } } -const sendErrorToMainWindow = ({ msg, code }) => { +const sendErrorToMainWindow = async ({ msg, code }) => { if (code === COZY_CLIENT_REVOKED_CODE) { if (notificationsState.revokedAlertShown) return notificationsState.revokedAlertShown = true // prevent the alert from appearing twice @@ -236,8 +237,8 @@ const sendErrorToMainWindow = ({ msg, code }) => { defaultId: 1 } trayWindow.hide() - const userChoice = dialog.showMessageBoxSync(null, options) - if (userChoice === 0) { + const { response } = await dialog.showMessageBox(null, options) + if (response === 0) { desktop .stopSync() .then(() => desktop.removeConfig()) @@ -263,7 +264,7 @@ const sendErrorToMainWindow = ({ msg, code }) => { defaultId: 0 } trayWindow.hide() - dialog.showMessageBoxSync(null, options) + await dialog.showMessageBox(null, options) desktop .stopSync() .then(() => desktop.pouch.db.destroy()) @@ -286,7 +287,7 @@ const sendErrorToMainWindow = ({ msg, code }) => { detail: translate('SyncDirEmpty Detail'), buttons: [translate('AppMenu Close')] } - dialog.showMessageBoxSync(null, options) + await dialog.showMessageBox(null, options) desktop .stopSync() .catch(err => log.error({ err, sentry: true }, 'failed stopping sync')) @@ -301,7 +302,7 @@ const sendErrorToMainWindow = ({ msg, code }) => { const LAST_SYNC_UPDATE_DELAY = 1000 // milliseconds let lastSyncTimeout = null -const updateState = (newState, data) => { +const updateState = async ({ newState, data }) => { const { status, filename, userActions, errors } = data || {} if (newState === 'sync-state') { @@ -354,9 +355,9 @@ const updateState = (newState, data) => { // TODO: get rid of sendErrorToMainWindow and move all error management to // main window? if (errors[0].code !== null) { - sendErrorToMainWindow({ code: errors[0].code }) + await sendErrorToMainWindow({ code: errors[0].code }) } else { - sendErrorToMainWindow({ + await sendErrorToMainWindow({ msg: errors[0].message || translate('Dashboard Synchronization impossible') @@ -365,6 +366,13 @@ const updateState = (newState, data) => { } } } +const updateStateQueue = Promise.promisifyAll(async.queue(updateState)) + +const enqueueStateUpdate = (newState, data) => { + updateStateQueue.pushAsync({ newState, data }).catch(err => { + log.warn({ err }, 'Failed to update state') + }) +} const addFile = async info => { const file = { @@ -374,7 +382,7 @@ const addFile = async info => { size: info.size || 0, updated: +new Date() } - updateState('syncing', file) + enqueueStateUpdate('syncing', file) await lastFiles.add(file) await lastFiles.persist() } @@ -387,7 +395,7 @@ const removeFile = async info => { size: 0, updated: 0 } - updateState('syncing') + enqueueStateUpdate('syncing') trayWindow.send('delete-file', file) await lastFiles.remove(file) await lastFiles.persist() @@ -414,9 +422,9 @@ const sendDiskUsage = () => { } const startSync = async () => { - updateState('syncing') + enqueueStateUpdate('syncing') desktop.events.on('sync-state', state => { - updateState('sync-state', state) + enqueueStateUpdate('sync-state', state) }) desktop.events.on('transfer-started', addFile) desktop.events.on('transfer-copy', addFile) @@ -538,7 +546,7 @@ app.on('ready', async () => { desktop = new Desktop.App(process.env.COZY_DESKTOP_DIR) } catch (err) { if (err.message.match(/GLIBCXX/)) { - dialog.showMessageBoxSync(null, { + await dialog.showMessageBox(null, { type: 'error', message: translate('Error Bad GLIBCXX version'), buttons: [translate('AppMenu Close')]