Merge pull request #66 from cwillisf/about-window

About window
This commit is contained in:
Chris Willis-Ford 2019-07-28 17:38:04 -07:00 committed by GitHub
commit 8dcbbfe5c9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 106 additions and 19 deletions

View file

@ -1,4 +1,4 @@
import {BrowserWindow, Menu, app, dialog} from 'electron'; import {BrowserWindow, Menu, app, dialog, ipcMain} from 'electron';
import * as path from 'path'; import * as path from 'path';
import {format as formatUrl} from 'url'; import {format as formatUrl} from 'url';
import {getFilterForExtension} from './FileFilters'; import {getFilterForExtension} from './FileFilters';
@ -13,20 +13,17 @@ const defaultSize = {width: 1280, height: 800}; // good for MAS screenshots
const isDevelopment = process.env.NODE_ENV !== 'production'; const isDevelopment = process.env.NODE_ENV !== 'production';
const createMainWindow = () => { // global window references prevent them from being garbage-collected
const _windows = {};
const createWindow = ({url, ...browserWindowOptions}) => {
const window = new BrowserWindow({ const window = new BrowserWindow({
width: defaultSize.width,
height: defaultSize.height,
useContentSize: true, useContentSize: true,
show: false show: false,
...browserWindowOptions
}); });
const webContents = window.webContents; const webContents = window.webContents;
if (process.platform === 'darwin') {
const osxMenu = Menu.buildFromTemplate(MacOSMenu(app));
Menu.setApplicationMenu(osxMenu);
}
if (isDevelopment) { if (isDevelopment) {
webContents.openDevTools(); webContents.openDevTools();
import('electron-devtools-installer').then(importedModule => { import('electron-devtools-installer').then(importedModule => {
@ -46,15 +43,38 @@ const createMainWindow = () => {
}); });
if (isDevelopment) { if (isDevelopment) {
window.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`); window.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}/${url}`);
} else { } else {
window.loadURL(formatUrl({ window.loadURL(formatUrl({
pathname: path.join(__dirname, 'index.html'), pathname: path.join(__dirname, url),
protocol: 'file', protocol: 'file',
slashes: true slashes: true
})); }));
} }
return window;
};
const createAboutWindow = () => {
const window = createWindow({
width: 400,
height: 400,
parent: _windows.main,
title: 'About Scratch Desktop',
url: 'index.html?route=about'
});
return window;
};
const createMainWindow = () => {
const window = createWindow({
width: defaultSize.width,
height: defaultSize.height,
title: 'Scratch Desktop',
url: 'index.html'
});
const webContents = window.webContents;
webContents.session.on('will-download', (ev, item) => { webContents.session.on('will-download', (ev, item) => {
const itemPath = item.getFilename(); const itemPath = item.getFilename();
const baseName = path.basename(itemPath); const baseName = path.basename(itemPath);
@ -104,6 +124,11 @@ const createMainWindow = () => {
return window; return window;
}; };
if (process.platform === 'darwin') {
const osxMenu = Menu.buildFromTemplate(MacOSMenu(app));
Menu.setApplicationMenu(osxMenu);
}
// quit application when all windows are closed // quit application when all windows are closed
app.on('window-all-closed', () => { app.on('window-all-closed', () => {
app.quit(); app.quit();
@ -113,13 +138,19 @@ app.on('will-quit', () => {
telemetry.appWillClose(); telemetry.appWillClose();
}); });
// global reference to mainWindow (necessary to prevent window from being garbage collected)
let _mainWindow;
// create main BrowserWindow when electron is ready // create main BrowserWindow when electron is ready
app.on('ready', () => { app.on('ready', () => {
_mainWindow = createMainWindow(); _windows.main = createMainWindow();
_mainWindow.on('closed', () => { _windows.main.on('closed', () => {
_mainWindow = null; delete _windows.main;
});
_windows.about = createAboutWindow();
_windows.about.on('close', event => {
event.preventDefault();
_windows.about.hide();
}); });
}); });
ipcMain.on('open-about-window', () => {
_windows.about.show();
});

43
src/renderer/about.jsx Normal file
View file

@ -0,0 +1,43 @@
import React from 'react';
import ReactDOM from 'react-dom';
import {author, productName, version} from '../../package.json';
import logo from '../icon/ScratchDesktop.svg';
// TODO: localization?
const AboutElement = () => (
<div
style={{
color: 'white',
fontFamily: '"Helvetica Neue", Helvetica, Arial, sans-serif',
fontWeight: 'bolder',
margin: 0,
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)'
}}
>
<div><img
alt={`${productName} icon`}
src={logo}
style={{
maxWidth: '10rem',
maxHeight: '10rem'
}}
/></div>
<h2>{productName}</h2>
<div>Version {version}</div>
<table style={{fontSize: 'x-small'}}>
{
['Electron', 'Chrome'].map(component => {
const componentVersion = process.versions[component.toLowerCase()];
return <tr key={component}><td>{component}</td><td>{componentVersion}</td></tr>;
})
}
</table>
</div>
);
const appTarget = document.getElementById('app');
ReactDOM.render(<AboutElement />, appTarget);

View file

@ -45,6 +45,9 @@ const ScratchDesktopHOC = function (WrappedComponent) {
componentWillUnmount () { componentWillUnmount () {
ipcRenderer.removeListener('setTitleFromSave', this.handleSetTitleFromSave); ipcRenderer.removeListener('setTitleFromSave', this.handleSetTitleFromSave);
} }
handleClickLogo () {
ipcRenderer.send('open-about-window');
}
handleProjectTelemetryEvent (event, metadata) { handleProjectTelemetryEvent (event, metadata) {
ipcRenderer.send(event, metadata); ipcRenderer.send(event, metadata);
} }
@ -66,6 +69,7 @@ const ScratchDesktopHOC = function (WrappedComponent) {
isScratchDesktop isScratchDesktop
projectId={defaultProjectId} projectId={defaultProjectId}
showTelemetryModal={shouldShowTelemetryModal} showTelemetryModal={shouldShowTelemetryModal}
onClickLogo={this.handleClickLogo}
onProjectTelemetryEvent={this.handleProjectTelemetryEvent} onProjectTelemetryEvent={this.handleProjectTelemetryEvent}
onStorageInit={this.handleStorageInit} onStorageInit={this.handleStorageInit}
onTelemetryModalOptIn={this.handleTelemetryModalOptIn} onTelemetryModalOptIn={this.handleTelemetryModalOptIn}

View file

@ -1,3 +1,12 @@
// this is an async import so that it doesn't block the first render // this is an async import so that it doesn't block the first render
// index.html contains a loading/splash screen which will display while this import loads // index.html contains a loading/splash screen which will display while this import loads
const route = new URLSearchParams(window.location.search).get('route') || 'app';
switch (route) {
case 'app':
import('./app.jsx'); import('./app.jsx');
break;
case 'about':
import('./about.jsx');
break;
}