Browse Source

Add new window for DevToolbar, center PreloadWindow with MainWindow position

master
Loëck Vézien 7 years ago
parent
commit
3a0d18d2e1
No known key found for this signature in database GPG Key ID: CBCDCE384E853AC4
  1. 10
      src/components/App.js
  2. 114
      src/components/DevToolbar.js
  3. 6
      src/components/layout/Default.js
  4. 25
      src/components/layout/Dev.js
  5. 4
      src/components/layout/Print.js
  6. 1
      src/internals/index.js
  7. 119
      src/main/app.js
  8. 20
      src/main/bridge.js
  9. 6
      src/renderer/events.js
  10. 6
      src/renderer/index.js

10
src/components/App.js

@ -11,8 +11,9 @@ import theme from 'styles/theme'
import i18n from 'renderer/i18n' import i18n from 'renderer/i18n'
import Wrapper from 'components/Wrapper' import Default from 'components/layout/Default'
import PrintWrapper from 'components/PrintWrapper' import Dev from 'components/layout/Dev'
import Print from 'components/layout/Print'
export default ({ export default ({
store, store,
@ -28,8 +29,9 @@ export default ({
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<ConnectedRouter history={history}> <ConnectedRouter history={history}>
<Switch> <Switch>
<Route path="/print" component={PrintWrapper} /> {__DEV__ && <Route path="/dev" component={Dev} />}
<Route component={Wrapper} /> <Route path="/print" component={Print} />
<Route component={Default} />
</Switch> </Switch>
</ConnectedRouter> </ConnectedRouter>
</ThemeProvider> </ThemeProvider>

114
src/components/DevToolbar.js

@ -1,7 +1,7 @@
// @flow // @flow
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import { ipcRenderer } from 'electron' import { remote, ipcRenderer } from 'electron'
import { translate } from 'react-i18next' import { translate } from 'react-i18next'
import { AreaChart, Area } from 'recharts' import { AreaChart, Area } from 'recharts'
import takeRight from 'lodash/takeRight' import takeRight from 'lodash/takeRight'
@ -10,15 +10,18 @@ import reduce from 'lodash/fp/reduce'
import flow from 'lodash/fp/flow' import flow from 'lodash/fp/flow'
import filter from 'lodash/fp/filter' import filter from 'lodash/fp/filter'
import sortBy from 'lodash/fp/sortBy' import sortBy from 'lodash/fp/sortBy'
import chunk from 'lodash/chunk'
import styled from 'styled-components' import styled from 'styled-components'
import color from 'color' import color from 'color'
import Box from 'components/base/Box' 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 CopyToClipboard from 'components/base/CopyToClipboard'
import theme from 'styles/theme' import theme from 'styles/theme'
const mainWindow = remote.BrowserWindow.getAllWindows().find(w => w.name === 'MainWindow')
type HslColor = { type HslColor = {
color: Array<number>, color: Array<number>,
} }
@ -53,40 +56,16 @@ const colors: Array<ColorType> = transform(theme.colors)
const Container = styled(Box).attrs({ const Container = styled(Box).attrs({
bg: 'night', bg: 'night',
p: 1, p: 5,
grow: true,
color: 'white', color: 'white',
fontSize: 0, fontSize: 3,
})` })``
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;
`
const Colors = styled(Box).attrs({ const Colors = styled(Box).attrs({
horizontal: true, horizontal: true,
align: 'flex-start', flow: 4,
})` })``
flex-wrap: wrap;
`
const Cl = styled(Box).attrs({ const Cl = styled(Box).attrs({
align: 'center', align: 'center',
@ -94,9 +73,8 @@ const Cl = styled(Box).attrs({
p: 2, p: 2,
})` })`
border: 2px solid white; border: 2px solid white;
flex: 1;
cursor: pointer; cursor: pointer;
margin: 2px;
width: 80px;
` `
const Color = ({ onClick, color }: { onClick: Function, color: ColorType }) => ( 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({ const Lang = styled(Box).attrs({
bg: p => (p.current ? 'white' : 'night'), bg: 'night',
color: p => (p.current ? 'night' : 'white'), color: 'white',
borderColor: 'white', borderColor: 'white',
borderWidth: 1, borderWidth: 2,
p: 1, borderRadius: 1,
p: 2,
})` })`
border-radius: 3px;
cursor: pointer; cursor: pointer;
` `
const LANGUAGES = {
fr: 'français',
en: 'english',
}
type State = { type State = {
isOpened: boolean,
cpuUsage: Object, cpuUsage: Object,
} }
class DevToolbar extends PureComponent<any, State> { class DevToolbar extends PureComponent<any, State> {
state = { state = {
isOpened: false,
cpuUsage: {}, cpuUsage: {},
} }
@ -159,32 +130,34 @@ class DevToolbar extends PureComponent<any, State> {
} }
} }
handleToggle = () => this.setState({ isOpened: !this.state.isOpened }) handleChangeLanguage = lang => () => {
handleChangeLanguage = lang => () => this.props.i18n.changeLanguage(lang) mainWindow.webContents.send('msg', {
type: 'application.changeLanguage',
data: lang,
})
}
render() { render() {
const { i18n } = this.props const { i18n } = this.props
const { isOpened, cpuUsage } = this.state const { cpuUsage } = this.state
return ( return (
<Container isOpened={isOpened}> <Container>
<Handle onClick={this.handleToggle}>{'DEV'}</Handle> <Box grow flow={4}>
<Box horizontal grow flow={10}> <Box flow={4} horizontal>
<Box flow={10}> {Object.keys(i18n.store.data).map(lang => (
{Object.keys(LANGUAGES).map(lang => ( <Lang key={lang} onClick={this.handleChangeLanguage(lang)}>
<Lang {lang}
key={lang}
current={i18n.language === lang}
onClick={this.handleChangeLanguage(lang)}
>
{LANGUAGES[lang]}
</Lang> </Lang>
))} ))}
</Box> </Box>
<Box style={{ width: 168 }}> <Bar size={2} color="white" />
<GrowScroll> <Box flow={4}>
<Colors> {chunk(colors, 8).map((c, i) => (
{colors.map(color => ( <Colors
key={i} // eslint-disable-line react/no-array-index-key
>
{c.map(color => (
<CopyToClipboard <CopyToClipboard
key={color.name} key={color.name}
data={color.name} data={color.name}
@ -192,16 +165,17 @@ class DevToolbar extends PureComponent<any, State> {
/> />
))} ))}
</Colors> </Colors>
</GrowScroll> ))}
</Box> </Box>
<Box flow={10}> <Bar size={2} color="white" />
<Box flow={4} horizontal>
{Object.keys(cpuUsage) {Object.keys(cpuUsage)
.sort() .sort()
.map(k => ( .map(k => (
<Box key={k} grow> <Box key={k}>
<Box horizontal align="center"> <Box horizontal align="center" flow={2}>
<Box grow>{k}</Box> <Box fontSize={1}>{last(cpuUsage[k]).value}%</Box>
<Box fontSize="8px">{last(cpuUsage[k]).value}%</Box> <Box>{k}</Box>
</Box> </Box>
<Box> <Box>
<AreaChart <AreaChart

6
src/components/Wrapper.js → src/components/layout/Default.js

@ -15,7 +15,6 @@ import DashboardPage from 'components/DashboardPage'
import SettingsPage from 'components/SettingsPage' import SettingsPage from 'components/SettingsPage'
import AppRegionDrag from 'components/AppRegionDrag' import AppRegionDrag from 'components/AppRegionDrag'
import DevToolbar from 'components/DevToolbar'
import IsUnlocked from 'components/IsUnlocked' import IsUnlocked from 'components/IsUnlocked'
import SideBar from 'components/SideBar' import SideBar from 'components/SideBar'
import TopBar from 'components/TopBar' import TopBar from 'components/TopBar'
@ -27,7 +26,7 @@ const Container = styled(GrowScroll).attrs({
padding-top: ${p => p.theme.sizes.topBarHeight + p.theme.space[7]}px; padding-top: ${p => p.theme.sizes.topBarHeight + p.theme.space[7]}px;
` `
class Wrapper extends Component<{}> { class Default extends Component<{}> {
componentDidMount() { componentDidMount() {
window.requestAnimationFrame( window.requestAnimationFrame(
() => (this._timeout = setTimeout(() => ipcRenderer.send('app-finish-rendering'), 300)), () => (this._timeout = setTimeout(() => ipcRenderer.send('app-finish-rendering'), 300)),
@ -44,7 +43,6 @@ class Wrapper extends Component<{}> {
return ( return (
<Fragment> <Fragment>
{process.platform === 'darwin' && <AppRegionDrag />} {process.platform === 'darwin' && <AppRegionDrag />}
{__DEV__ && <DevToolbar />}
<IsUnlocked> <IsUnlocked>
{Object.entries(modals).map(([name, ModalComponent]: [string, any]) => ( {Object.entries(modals).map(([name, ModalComponent]: [string, any]) => (
@ -70,4 +68,4 @@ class Wrapper extends Component<{}> {
} }
} }
export default translate()(Wrapper) export default translate()(Default)

25
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 (
<Container>
<DevToolbar />
</Container>
)
}
}
export default Dev

4
src/components/PrintWrapper.js → src/components/layout/Print.js

@ -12,7 +12,7 @@ type State = {
data: Object | null, data: Object | null,
} }
class PrintWrapper extends PureComponent<any, State> { class Print extends PureComponent<any, State> {
state = { state = {
data: null, data: null,
} }
@ -49,4 +49,4 @@ class PrintWrapper extends PureComponent<any, State> {
} }
} }
export default PrintWrapper export default Print

1
src/internals/index.js

@ -69,6 +69,7 @@ if (__DEV__) {
value: cpuPercent, value: cpuPercent,
}, },
{ {
window: 'DevWindow',
kill: false, kill: false,
}, },
) )

119
src/main/app.js

@ -8,14 +8,15 @@ import db from 'helpers/db'
// necessary to prevent win from being garbage collected // necessary to prevent win from being garbage collected
let mainWindow let mainWindow
let devWindow
let preloadWindow let preloadWindow
let forceClose = false let forceClose = false
const devTools = __DEV__ const devTools = __DEV__
const getWindowPosition = (height, width) => { const getWindowPosition = (height, width, display = screen.getPrimaryDisplay()) => {
const { bounds } = screen.getPrimaryDisplay() const { bounds } = display
return { return {
x: Math.ceil(bounds.x + (bounds.width - width) / 2), 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 = { const defaultWindowOptions = {
backgroundColor: '#fff', backgroundColor: '#fff',
webPreferences: { webPreferences: {
devTools, devTools,
// Enable, among other things, the ResizeObserver
experimentalFeatures: true,
}, },
} }
@ -34,8 +60,8 @@ function createMainWindow() {
const MIN_HEIGHT = 768 const MIN_HEIGHT = 768
const MIN_WIDTH = 1024 const MIN_WIDTH = 1024
const savedDimensions = db.getIn('settings', 'window.dimensions', {}) const savedDimensions = db.getIn('settings', 'window.MainWindow.dimensions', {})
const savedPositions = db.getIn('settings', 'window.positions', null) const savedPositions = db.getIn('settings', 'window.MainWindow.positions', null)
const width = savedDimensions.width || MIN_WIDTH const width = savedDimensions.width || MIN_WIDTH
const height = savedDimensions.height || MIN_HEIGHT const height = savedDimensions.height || MIN_HEIGHT
@ -54,23 +80,20 @@ function createMainWindow() {
minWidth: MIN_WIDTH, minWidth: MIN_WIDTH,
minHeight: MIN_HEIGHT, minHeight: MIN_HEIGHT,
show: false, show: false,
webPreferences: {
...defaultWindowOptions.webPreferences,
// Enable, among other things, the ResizeObserver
experimentalFeatures: true,
},
} }
const window = new BrowserWindow(windowOptions) const window = new BrowserWindow(windowOptions)
const url = __DEV__ window.name = 'MainWindow'
? `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT || ''}`
: `file://${__dirname}/index.html` const url = getDefaultUrl()
if (devTools) { if (devTools) {
window.webContents.openDevTools() window.webContents.openDevTools()
} }
saveWindowSettings(window)
window.loadURL(url) window.loadURL(url)
window.on('close', e => { 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.webContents.on('devtools-opened', () => {
window.focus() window.focus()
setImmediate(() => { setImmediate(() => {
@ -109,16 +116,64 @@ function createMainWindow() {
return window 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() { function createPreloadWindow() {
// Preload renderer of main windows // Preload renderer of main windows
mainWindow = createMainWindow() mainWindow = createMainWindow()
const [x, y] = mainWindow.getPosition()
if (__DEV__) {
devWindow = createDevWindow()
}
const height = 144 const height = 144
const width = 256 const width = 256
const windowOptions = { const windowOptions = {
...defaultWindowOptions, ...defaultWindowOptions,
...getWindowPosition(height, width), ...getWindowPosition(height, width, screen.getDisplayNearestPoint({ x, y })),
alwaysOnTop: true,
closable: false, closable: false,
frame: false, frame: false,
fullscreenable: false, fullscreenable: false,
@ -131,6 +186,8 @@ function createPreloadWindow() {
const window = new BrowserWindow(windowOptions) const window = new BrowserWindow(windowOptions)
window.name = 'PreloadWindow'
window.loadURL(`file://${__static}/preload-window.html`) window.loadURL(`file://${__static}/preload-window.html`)
window.on('ready-to-show', () => { window.on('ready-to-show', () => {
@ -197,4 +254,8 @@ ipcMain.on('app-finish-rendering', () => {
mainWindow.show() mainWindow.show()
setImmediate(() => mainWindow !== null && mainWindow.focus()) setImmediate(() => mainWindow !== null && mainWindow.focus())
} }
if (devWindow !== null) {
devWindow.show()
}
}) })

20
src/main/bridge.js

@ -1,7 +1,7 @@
// @flow // @flow
import { fork } from 'child_process' import { fork } from 'child_process'
import { ipcMain } from 'electron' import { BrowserWindow, ipcMain } from 'electron'
import objectPath from 'object-path' import objectPath from 'object-path'
import { resolve } from 'path' import { resolve } from 'path'
@ -34,11 +34,17 @@ function onForkChannel(forkType, callType) {
const onMessage = payload => { const onMessage = payload => {
const { type, data, options = {} } = payload const { type, data, options = {} } = payload
if (callType === 'async') {
event.sender.send('msg', { type, data }) if (options.window) {
} const devWindow = BrowserWindow.getAllWindows().find(w => w.name === options.window)
if (callType === 'sync') { devWindow.webContents.send('msg', { type, data })
event.returnValue = { type, data } } else {
if (callType === 'async') {
event.sender.send('msg', { type, data })
}
if (callType === 'sync') {
event.returnValue = { type, data }
}
} }
if (options.kill && compute) { if (options.kill && compute) {
kill() kill()
@ -72,5 +78,5 @@ ipcMain.on('msg', (event: any, payload) => {
return return
} }
const send = (type: string, data: *) => event.sender.send('msg', { type, data }) const send = (type: string, data: *) => event.sender.send('msg', { type, data })
handler(send, data) handler(send, data, type)
}) })

6
src/renderer/events.js

@ -14,6 +14,8 @@ import { updateAccount } from 'actions/accounts'
import { setUpdateStatus } from 'reducers/update' import { setUpdateStatus } from 'reducers/update'
import { getAccountData, getAccounts } from 'reducers/accounts' import { getAccountData, getAccounts } from 'reducers/accounts'
import i18n from 'renderer/i18n'
const { DISABLED_SYNC, DISABLED_AUTO_SYNC } = process.env const { DISABLED_SYNC, DISABLED_AUTO_SYNC } = process.env
type MsgPayload = { type MsgPayload = {
@ -64,6 +66,10 @@ export function checkUpdates() {
export default ({ store, locked }: { store: Object, locked: boolean }) => { export default ({ store, locked }: { store: Object, locked: boolean }) => {
const handlers = { const handlers = {
dispatch: (type, payload) => store.dispatch({ type, payload }),
application: {
changeLanguage: lang => i18n.changeLanguage(lang),
},
account: { account: {
sync: { sync: {
success: account => { success: account => {

6
src/renderer/index.js

@ -4,6 +4,7 @@ import 'env'
import React from 'react' import React from 'react'
import Raven from 'raven-js' import Raven from 'raven-js'
import { remote } from 'electron'
import { render } from 'react-dom' import { render } from 'react-dom'
import { AppContainer } from 'react-hot-loader' import { AppContainer } from 'react-hot-loader'
import createHistory from 'history/createHashHistory' import createHistory from 'history/createHashHistory'
@ -35,8 +36,6 @@ const history = createHistory()
const store = createStore(history) const store = createStore(history)
const rootNode = document.getElementById('app') const rootNode = document.getElementById('app')
global.__PRINT_MODE__ = history.location.pathname.startsWith('/print')
store.dispatch(fetchSettings()) store.dispatch(fetchSettings())
const state = store.getState() || {} const state = store.getState() || {}
@ -55,7 +54,8 @@ function r(Comp) {
r(<App store={store} history={history} language={language} />) r(<App store={store} history={history} language={language} />)
if (!__PRINT_MODE__) { // Only init events on MainWindow
if (remote.getCurrentWindow().name === 'MainWindow') {
events({ store, locked }) events({ store, locked })
} }

Loading…
Cancel
Save