diff --git a/src/components/App.js b/src/components/App.js
index fb4e67e9..72af5bc2 100644
--- a/src/components/App.js
+++ b/src/components/App.js
@@ -11,8 +11,9 @@ import theme from 'styles/theme'
import i18n from 'renderer/i18n'
-import Wrapper from 'components/Wrapper'
-import PrintWrapper from 'components/PrintWrapper'
+import Default from 'components/layout/Default'
+import Dev from 'components/layout/Dev'
+import Print from 'components/layout/Print'
export default ({
store,
@@ -28,8 +29,9 @@ export default ({
-
-
+ {__DEV__ && }
+
+
diff --git a/src/components/DevToolbar.js b/src/components/DevToolbar.js
index 6c44cfdc..a9255799 100644
--- a/src/components/DevToolbar.js
+++ b/src/components/DevToolbar.js
@@ -1,7 +1,7 @@
// @flow
import React, { PureComponent } from 'react'
-import { ipcRenderer } from 'electron'
+import { remote, ipcRenderer } from 'electron'
import { translate } from 'react-i18next'
import { AreaChart, Area } from 'recharts'
import takeRight from 'lodash/takeRight'
@@ -10,15 +10,18 @@ import reduce from 'lodash/fp/reduce'
import flow from 'lodash/fp/flow'
import filter from 'lodash/fp/filter'
import sortBy from 'lodash/fp/sortBy'
+import chunk from 'lodash/chunk'
import styled from 'styled-components'
import color from 'color'
import Box from 'components/base/Box'
-import GrowScroll from 'components/base/GrowScroll'
+import Bar from 'components/base/Bar'
import CopyToClipboard from 'components/base/CopyToClipboard'
import theme from 'styles/theme'
+const mainWindow = remote.BrowserWindow.getAllWindows().find(w => w.name === 'MainWindow')
+
type HslColor = {
color: Array,
}
@@ -53,40 +56,16 @@ const colors: Array = transform(theme.colors)
const Container = styled(Box).attrs({
bg: 'night',
- p: 1,
+ p: 5,
+ grow: true,
color: 'white',
- fontSize: 0,
-})`
- position: fixed;
- bottom: 0;
- right: 0;
- z-index: 1;
- border-top-left-radius: 3px;
- transition: ease-in-out transform 300ms;
- transform: translate3d(0, ${p => (p.isOpened ? '0' : '100%')}, 0);
-`
-
-const Handle = styled(Box).attrs({
- bg: 'night',
- justify: 'center',
- px: 1,
-})`
- cursor: pointer;
- position: absolute;
- bottom: 100%;
- right: 5px;
- font-size: 9px;
- height: 20px;
- border-top-left-radius: 3px;
- border-top-right-radius: 3px;
-`
+ fontSize: 3,
+})``
const Colors = styled(Box).attrs({
horizontal: true,
- align: 'flex-start',
-})`
- flex-wrap: wrap;
-`
+ flow: 4,
+})``
const Cl = styled(Box).attrs({
align: 'center',
@@ -94,9 +73,8 @@ const Cl = styled(Box).attrs({
p: 2,
})`
border: 2px solid white;
+ flex: 1;
cursor: pointer;
- margin: 2px;
- width: 80px;
`
const Color = ({ onClick, color }: { onClick: Function, color: ColorType }) => (
@@ -106,29 +84,22 @@ const Color = ({ onClick, color }: { onClick: Function, color: ColorType }) => (
)
const Lang = styled(Box).attrs({
- bg: p => (p.current ? 'white' : 'night'),
- color: p => (p.current ? 'night' : 'white'),
+ bg: 'night',
+ color: 'white',
borderColor: 'white',
- borderWidth: 1,
- p: 1,
+ borderWidth: 2,
+ borderRadius: 1,
+ p: 2,
})`
- border-radius: 3px;
cursor: pointer;
`
-const LANGUAGES = {
- fr: 'français',
- en: 'english',
-}
-
type State = {
- isOpened: boolean,
cpuUsage: Object,
}
class DevToolbar extends PureComponent {
state = {
- isOpened: false,
cpuUsage: {},
}
@@ -159,32 +130,34 @@ class DevToolbar extends PureComponent {
}
}
- handleToggle = () => this.setState({ isOpened: !this.state.isOpened })
- handleChangeLanguage = lang => () => this.props.i18n.changeLanguage(lang)
+ handleChangeLanguage = lang => () => {
+ mainWindow.webContents.send('msg', {
+ type: 'application.changeLanguage',
+ data: lang,
+ })
+ }
render() {
const { i18n } = this.props
- const { isOpened, cpuUsage } = this.state
+ const { cpuUsage } = this.state
return (
-
- {'DEV'}
-
-
- {Object.keys(LANGUAGES).map(lang => (
-
- {LANGUAGES[lang]}
+
+
+
+ {Object.keys(i18n.store.data).map(lang => (
+
+ {lang}
))}
-
-
-
- {colors.map(color => (
+
+
+ {chunk(colors, 8).map((c, i) => (
+
+ {c.map(color => (
{
/>
))}
-
+ ))}
-
+
+
{Object.keys(cpuUsage)
.sort()
.map(k => (
-
-
- {k}
- {last(cpuUsage[k]).value}%
+
+
+ {last(cpuUsage[k]).value}%
+ {k}
p.theme.sizes.topBarHeight + p.theme.space[7]}px;
`
-class Wrapper extends Component<{}> {
+class Default extends Component<{}> {
componentDidMount() {
window.requestAnimationFrame(
() => (this._timeout = setTimeout(() => ipcRenderer.send('app-finish-rendering'), 300)),
@@ -44,7 +43,6 @@ class Wrapper extends Component<{}> {
return (
{process.platform === 'darwin' && }
- {__DEV__ && }
{Object.entries(modals).map(([name, ModalComponent]: [string, any]) => (
@@ -70,4 +68,4 @@ class Wrapper extends Component<{}> {
}
}
-export default translate()(Wrapper)
+export default translate()(Default)
diff --git a/src/components/layout/Dev.js b/src/components/layout/Dev.js
new file mode 100644
index 00000000..b0dd5b1e
--- /dev/null
+++ b/src/components/layout/Dev.js
@@ -0,0 +1,25 @@
+// @flow
+
+import React, { PureComponent } from 'react'
+import styled from 'styled-components'
+
+import Box from 'components/base/Box'
+import DevToolbar from 'components/DevToolbar'
+
+const Container = styled(Box).attrs({
+ grow: true,
+})`
+ height: 100%;
+`
+
+class Dev extends PureComponent<{}> {
+ render() {
+ return (
+
+
+
+ )
+ }
+}
+
+export default Dev
diff --git a/src/components/PrintWrapper.js b/src/components/layout/Print.js
similarity index 92%
rename from src/components/PrintWrapper.js
rename to src/components/layout/Print.js
index da4e4fe9..53501912 100644
--- a/src/components/PrintWrapper.js
+++ b/src/components/layout/Print.js
@@ -12,7 +12,7 @@ type State = {
data: Object | null,
}
-class PrintWrapper extends PureComponent {
+class Print extends PureComponent {
state = {
data: null,
}
@@ -49,4 +49,4 @@ class PrintWrapper extends PureComponent {
}
}
-export default PrintWrapper
+export default Print
diff --git a/src/internals/index.js b/src/internals/index.js
index 2040becc..2c700f30 100644
--- a/src/internals/index.js
+++ b/src/internals/index.js
@@ -69,6 +69,7 @@ if (__DEV__) {
value: cpuPercent,
},
{
+ window: 'DevWindow',
kill: false,
},
)
diff --git a/src/main/app.js b/src/main/app.js
index 80ac2ba6..18470cf2 100644
--- a/src/main/app.js
+++ b/src/main/app.js
@@ -8,14 +8,15 @@ import db from 'helpers/db'
// necessary to prevent win from being garbage collected
let mainWindow
+let devWindow
let preloadWindow
let forceClose = false
const devTools = __DEV__
-const getWindowPosition = (height, width) => {
- const { bounds } = screen.getPrimaryDisplay()
+const getWindowPosition = (height, width, display = screen.getPrimaryDisplay()) => {
+ const { bounds } = display
return {
x: Math.ceil(bounds.x + (bounds.width - width) / 2),
@@ -23,10 +24,35 @@ const getWindowPosition = (height, width) => {
}
}
+const getDefaultUrl = () =>
+ __DEV__
+ ? `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT || ''}`
+ : `file://${__dirname}/index.html`
+
+const saveWindowSettings = window => {
+ window.on(
+ 'resize',
+ debounce(() => {
+ const [width, height] = window.getSize()
+ db.setIn('settings', `window.${window.name}.dimensions`, { width, height })
+ }, 100),
+ )
+
+ window.on(
+ 'move',
+ debounce(() => {
+ const [x, y] = window.getPosition()
+ db.setIn('settings', `window.${window.name}.positions`, { x, y })
+ }, 100),
+ )
+}
+
const defaultWindowOptions = {
backgroundColor: '#fff',
webPreferences: {
devTools,
+ // Enable, among other things, the ResizeObserver
+ experimentalFeatures: true,
},
}
@@ -34,8 +60,8 @@ function createMainWindow() {
const MIN_HEIGHT = 768
const MIN_WIDTH = 1024
- const savedDimensions = db.getIn('settings', 'window.dimensions', {})
- const savedPositions = db.getIn('settings', 'window.positions', null)
+ const savedDimensions = db.getIn('settings', 'window.MainWindow.dimensions', {})
+ const savedPositions = db.getIn('settings', 'window.MainWindow.positions', null)
const width = savedDimensions.width || MIN_WIDTH
const height = savedDimensions.height || MIN_HEIGHT
@@ -54,23 +80,20 @@ function createMainWindow() {
minWidth: MIN_WIDTH,
minHeight: MIN_HEIGHT,
show: false,
- webPreferences: {
- ...defaultWindowOptions.webPreferences,
- // Enable, among other things, the ResizeObserver
- experimentalFeatures: true,
- },
}
const window = new BrowserWindow(windowOptions)
- const url = __DEV__
- ? `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT || ''}`
- : `file://${__dirname}/index.html`
+ window.name = 'MainWindow'
+
+ const url = getDefaultUrl()
if (devTools) {
window.webContents.openDevTools()
}
+ saveWindowSettings(window)
+
window.loadURL(url)
window.on('close', e => {
@@ -83,22 +106,6 @@ function createMainWindow() {
}
})
- window.on(
- 'resize',
- debounce(() => {
- const [width, height] = window.getSize()
- db.setIn('settings', 'window.dimensions', { width, height })
- }, 100),
- )
-
- window.on(
- 'move',
- debounce(() => {
- const [x, y] = window.getPosition()
- db.setIn('settings', 'window.positions', { x, y })
- }, 100),
- )
-
window.webContents.on('devtools-opened', () => {
window.focus()
setImmediate(() => {
@@ -109,16 +116,64 @@ function createMainWindow() {
return window
}
+function createDevWindow() {
+ const MIN_HEIGHT = 400
+ const MIN_WIDTH = 600
+
+ const savedDimensions = db.getIn('settings', 'window.DevWindow.dimensions', {})
+ const savedPositions = db.getIn('settings', 'window.DevWindow.positions', null)
+
+ const width = savedDimensions.width || MIN_WIDTH
+ const height = savedDimensions.height || MIN_HEIGHT
+
+ const windowOptions = {
+ ...defaultWindowOptions,
+ ...(savedPositions !== null ? savedPositions : {}),
+ fullscreenable: false,
+ height,
+ show: false,
+ skipTaskbar: true,
+ width,
+ }
+
+ const window = new BrowserWindow(windowOptions)
+
+ window.name = 'DevWindow'
+
+ const url = getDefaultUrl()
+
+ if (devTools) {
+ window.webContents.openDevTools()
+ }
+
+ saveWindowSettings(window)
+
+ window.loadURL(`${url}/#/dev`)
+
+ window.on('ready-to-show', () => {
+ window.show()
+ })
+
+ return window
+}
+
function createPreloadWindow() {
// Preload renderer of main windows
mainWindow = createMainWindow()
+ const [x, y] = mainWindow.getPosition()
+
+ if (__DEV__) {
+ devWindow = createDevWindow()
+ }
+
const height = 144
const width = 256
const windowOptions = {
...defaultWindowOptions,
- ...getWindowPosition(height, width),
+ ...getWindowPosition(height, width, screen.getDisplayNearestPoint({ x, y })),
+ alwaysOnTop: true,
closable: false,
frame: false,
fullscreenable: false,
@@ -131,6 +186,8 @@ function createPreloadWindow() {
const window = new BrowserWindow(windowOptions)
+ window.name = 'PreloadWindow'
+
window.loadURL(`file://${__static}/preload-window.html`)
window.on('ready-to-show', () => {
@@ -197,4 +254,8 @@ ipcMain.on('app-finish-rendering', () => {
mainWindow.show()
setImmediate(() => mainWindow !== null && mainWindow.focus())
}
+
+ if (devWindow !== null) {
+ devWindow.show()
+ }
})
diff --git a/src/main/bridge.js b/src/main/bridge.js
index 14286441..e4f6f62d 100644
--- a/src/main/bridge.js
+++ b/src/main/bridge.js
@@ -1,7 +1,7 @@
// @flow
import { fork } from 'child_process'
-import { ipcMain } from 'electron'
+import { BrowserWindow, ipcMain } from 'electron'
import objectPath from 'object-path'
import { resolve } from 'path'
@@ -34,11 +34,17 @@ function onForkChannel(forkType, callType) {
const onMessage = payload => {
const { type, data, options = {} } = payload
- if (callType === 'async') {
- event.sender.send('msg', { type, data })
- }
- if (callType === 'sync') {
- event.returnValue = { type, data }
+
+ if (options.window) {
+ const devWindow = BrowserWindow.getAllWindows().find(w => w.name === options.window)
+ devWindow.webContents.send('msg', { type, data })
+ } else {
+ if (callType === 'async') {
+ event.sender.send('msg', { type, data })
+ }
+ if (callType === 'sync') {
+ event.returnValue = { type, data }
+ }
}
if (options.kill && compute) {
kill()
@@ -72,5 +78,5 @@ ipcMain.on('msg', (event: any, payload) => {
return
}
const send = (type: string, data: *) => event.sender.send('msg', { type, data })
- handler(send, data)
+ handler(send, data, type)
})
diff --git a/src/renderer/events.js b/src/renderer/events.js
index 807f75c6..70e24b4c 100644
--- a/src/renderer/events.js
+++ b/src/renderer/events.js
@@ -14,6 +14,8 @@ import { updateAccount } from 'actions/accounts'
import { setUpdateStatus } from 'reducers/update'
import { getAccountData, getAccounts } from 'reducers/accounts'
+import i18n from 'renderer/i18n'
+
const { DISABLED_SYNC, DISABLED_AUTO_SYNC } = process.env
type MsgPayload = {
@@ -64,6 +66,10 @@ export function checkUpdates() {
export default ({ store, locked }: { store: Object, locked: boolean }) => {
const handlers = {
+ dispatch: (type, payload) => store.dispatch({ type, payload }),
+ application: {
+ changeLanguage: lang => i18n.changeLanguage(lang),
+ },
account: {
sync: {
success: account => {
diff --git a/src/renderer/index.js b/src/renderer/index.js
index 6529d14b..1a230513 100644
--- a/src/renderer/index.js
+++ b/src/renderer/index.js
@@ -4,6 +4,7 @@ import 'env'
import React from 'react'
import Raven from 'raven-js'
+import { remote } from 'electron'
import { render } from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import createHistory from 'history/createHashHistory'
@@ -35,8 +36,6 @@ const history = createHistory()
const store = createStore(history)
const rootNode = document.getElementById('app')
-global.__PRINT_MODE__ = history.location.pathname.startsWith('/print')
-
store.dispatch(fetchSettings())
const state = store.getState() || {}
@@ -55,7 +54,8 @@ function r(Comp) {
r()
-if (!__PRINT_MODE__) {
+// Only init events on MainWindow
+if (remote.getCurrentWindow().name === 'MainWindow') {
events({ store, locked })
}