diff --git a/package.json b/package.json index 7a9fbdb8..577bca14 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "name": "ledger-wallet-desktop", + "productName": "Ledger Wallet Desktop", "description": "Ledger Wallet Desktop", "repository": "https://github.com/LedgerHQ/ledger-wallet-desktop", "version": "0.1.0", @@ -27,6 +28,7 @@ ] }, "electronWebpack": { + "title": true, "renderer": { "webpackConfig": "./webpack/renderer.config.js" }, diff --git a/src/components/SettingsPage/Display.js b/src/components/SettingsPage/Display.js index 775ef879..7e60c74a 100644 --- a/src/components/SettingsPage/Display.js +++ b/src/components/SettingsPage/Display.js @@ -44,10 +44,6 @@ class TabProfile extends PureComponent { }, ], orderAccounts: [ - { - key: 'custom', - name: t('orderAccounts.custom'), - }, { key: 'name', name: t('orderAccounts.name'), diff --git a/src/components/Wrapper.js b/src/components/Wrapper.js index d065417f..7bc3e3ad 100644 --- a/src/components/Wrapper.js +++ b/src/components/Wrapper.js @@ -1,6 +1,7 @@ // @flow import React, { Fragment, Component } from 'react' +import { ipcRenderer } from 'electron' import { Route } from 'react-router' import { translate } from 'react-i18next' @@ -11,23 +12,34 @@ import GrowScroll from 'components/base/GrowScroll' import AccountPage from 'components/AccountPage' import DashboardPage from 'components/DashboardPage' import SettingsPage from 'components/SettingsPage' -import UpdateNotifier from 'components/UpdateNotifier' import AppRegionDrag from 'components/AppRegionDrag' +import DevToolbar from 'components/DevToolbar' import IsUnlocked from 'components/IsUnlocked' import SideBar from 'components/SideBar' import TopBar from 'components/TopBar' -import DevToolbar from 'components/DevToolbar' +import UpdateNotifier from 'components/UpdateNotifier' class Wrapper extends Component<{}> { + componentDidMount() { + window.requestAnimationFrame( + () => (this._timeout = setTimeout(() => ipcRenderer.send('app-finish-rendering'), 300)), + ) + } + + componentWillUnmount() { + clearTimeout(this._timeout) + } + + _timeout = undefined + render() { return ( {process.platform === 'darwin' && } + {__DEV__ && } - {__DEV__ && } - {Object.entries(modals).map(([name, ModalComponent]: [string, any]) => ( ))} diff --git a/src/internals/index.js b/src/internals/index.js index 2ff3aa68..2040becc 100644 --- a/src/internals/index.js +++ b/src/internals/index.js @@ -1,10 +1,11 @@ // @flow import objectPath from 'object-path' +import capitalize from 'lodash/capitalize' const { FORK_TYPE } = process.env -process.title = `ledger-wallet-desktop-${FORK_TYPE}` +process.title = `Ledger Wallet Desktop ${capitalize(FORK_TYPE)}` function sendEvent(type: string, data: any, options: Object = { kill: true }) { process.send({ type, data, options }) diff --git a/src/main/app.js b/src/main/app.js index c4430796..98806972 100644 --- a/src/main/app.js +++ b/src/main/app.js @@ -1,31 +1,44 @@ // @flow -import { app, BrowserWindow } from 'electron' +import { app, BrowserWindow, Menu, ipcMain } from 'electron' + +import menu from 'main/menu' // necessary to prevent win from being garbage collected let mainWindow +let preloadWindow + +let forceClose = false -const MIN_HEIGHT = 768 -const MIN_WIDTH = 1024 +const devTools = __DEV__ + +const defaultWindowOptions = { + backgroundColor: '#fff', + center: true, + webPreferences: { + devTools, + }, +} function createMainWindow() { + const MIN_HEIGHT = 768 + const MIN_WIDTH = 1024 + const windowOptions = { + ...defaultWindowOptions, ...(process.platform === 'darwin' ? { frame: false, titleBarStyle: 'hiddenInset', } : {}), - center: true, - show: true, height: MIN_HEIGHT, - width: MIN_WIDTH, minHeight: MIN_HEIGHT, minWidth: MIN_WIDTH, + show: false, + width: MIN_WIDTH, webPreferences: { - // Disable auxclick event - // See https://developers.google.com/web/updates/2016/10/auxclick - disableBlinkFeatures: 'Auxclick', + ...defaultWindowOptions.webPreferences, // Enable, among other things, the ResizeObserver experimentalFeatures: true, }, @@ -37,18 +50,20 @@ function createMainWindow() { ? `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT || ''}` : `file://${__dirname}/index.html` - if (__DEV__) { + if (devTools) { window.webContents.openDevTools() } window.loadURL(url) - window.on('close', () => { - mainWindow = null - }) + window.on('close', e => { + if (!forceClose) { + e.preventDefault() - window.once('ready-to-show', () => { - window.show() + if (mainWindow !== null) { + mainWindow.hide() + } + } }) window.webContents.on('devtools-opened', () => { @@ -61,17 +76,55 @@ function createMainWindow() { return window } +function createPreloadWindow() { + // Preload renderer of main windows + mainWindow = createMainWindow() + + const HEIGHT = 144 + const WIDTH = 256 + + const windowOptions = { + ...defaultWindowOptions, + closable: false, + frame: false, + fullscreenable: false, + height: HEIGHT, + resizable: false, + show: false, + skipTaskbar: true, + width: WIDTH, + } + + const window = new BrowserWindow(windowOptions) + + window.loadURL(`file://${__static}/preload-window.html`) + + window.on('ready-to-show', () => { + window.show() + }) + + return window +} + +app.on('before-quit', () => { + forceClose = true +}) + app.on('window-all-closed', () => { // On macOS it is common for applications to stay open // until the user explicitly quits - if (process.platform !== 'darwin') app.quit() + if (process.platform !== 'darwin') { + app.quit() + } }) app.on('activate', () => { // On macOS it is common to re-create a window // even after all windows have been closed - if (mainWindow === null) { - mainWindow = createMainWindow() + if (mainWindow === null && preloadWindow === null) { + preloadWindow = createPreloadWindow() + } else if (mainWindow !== null) { + mainWindow.show() } }) @@ -91,5 +144,19 @@ app.on('ready', async () => { await installExtensions() } - mainWindow = createMainWindow() + Menu.setApplicationMenu(menu) + + preloadWindow = createPreloadWindow() +}) + +ipcMain.on('app-finish-rendering', () => { + if (preloadWindow !== null) { + preloadWindow.destroy() + preloadWindow = null + } + + if (mainWindow !== null) { + mainWindow.show() + setImmediate(() => mainWindow !== null && mainWindow.focus()) + } }) diff --git a/src/main/index.js b/src/main/index.js index 8a556e40..efda3b7a 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -5,9 +5,10 @@ require('env') process.setMaxListeners(0) require('../globals') -require('./bridge') require('./app') +setImmediate(() => require('./bridge')) // eslint-disable-line global-require + if (__PROD__ && __SENTRY_URL__) { const Raven = require('raven') // eslint-disable-line global-require const ravenConfig = { captureUnhandledRejections: true } diff --git a/src/main/menu.js b/src/main/menu.js new file mode 100644 index 00000000..38d9d9e0 --- /dev/null +++ b/src/main/menu.js @@ -0,0 +1,30 @@ +import { app, Menu } from 'electron' + +const template = [ + ...(process.platform === 'darwin' + ? [ + { + label: app.getName(), + submenu: [ + { role: 'hide' }, + { role: 'hideothers' }, + { role: 'unhide' }, + { type: 'separator' }, + { role: 'quit' }, + ], + }, + { + role: 'window', + submenu: [ + { role: 'close' }, + { role: 'minimize' }, + { role: 'zoom' }, + { type: 'separator' }, + { role: 'front' }, + ], + }, + ] + : []), +] + +export default Menu.buildFromTemplate(template) diff --git a/src/renderer/index.js b/src/renderer/index.js index ba86a525..b1b86301 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -45,8 +45,6 @@ if (!locked) { store.dispatch(fetchAccounts()) } -events({ store, locked }) - function r(Comp) { if (rootNode) { render({Comp}, rootNode) @@ -55,6 +53,8 @@ function r(Comp) { r() +events({ store, locked }) + if (module.hot) { module.hot.accept('../components/App', () => { const NewApp = require('../components/App').default // eslint-disable-line global-require diff --git a/static/i18n/en/translation.yml b/static/i18n/en/translation.yml index 6c43f9e9..fc5db919 100644 --- a/static/i18n/en/translation.yml +++ b/static/i18n/en/translation.yml @@ -9,7 +9,6 @@ language: fr: French orderAccounts: - custom: Custom name: By name balance: By balance type: By type diff --git a/static/i18n/fr/translation.yml b/static/i18n/fr/translation.yml index 7635eee1..1ad797ea 100644 --- a/static/i18n/fr/translation.yml +++ b/static/i18n/fr/translation.yml @@ -9,7 +9,6 @@ language: fr: Français orderAccounts: - custom: Personnalisé name: Par nom balance: Par solde type: Par type diff --git a/static/preload-window.html b/static/preload-window.html new file mode 100644 index 00000000..55c07b82 --- /dev/null +++ b/static/preload-window.html @@ -0,0 +1,36 @@ + + + + + +
+
+ + diff --git a/static/videos/loader.mp4 b/static/videos/loader.mp4 new file mode 100644 index 00000000..da3ac218 Binary files /dev/null and b/static/videos/loader.mp4 differ