Merge pull request #338 from aoneill01/feature/high-contrast

Feature/high contrast
This commit is contained in:
Andy O'Neill 2023-07-28 12:06:49 -04:00 committed by GitHub
commit 7bc88deb19
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 8070 additions and 3537 deletions

View file

@ -209,4 +209,7 @@ commands:
steps:
- run:
command: npm run distDev
environment: *clear_context
environment:
<<: *clear_context
# increased Node memory needed for macOS build
NODE_OPTIONS: --max-old-space-size=4096

View file

@ -22,7 +22,7 @@ Let's assume that you want to make a new release, version `3.999.0`, correspondi
1. `cd scratch-desktop`
2. `git pull --all --tags`
3. `git checkout develop`
4. `npm install --save-dev 'scratch-gui@github:LLK/scratch-gui#scratch-desktop-v3.999.0'`
4. `npm install --save-dev 'scratch-gui@github:scratchfoundation/scratch-gui#scratch-desktop-v3.999.0'`
5. `git add package.json package-lock.json`
6. Make sure the app works, the diffs look reasonable, etc.
7. `git commit -m "bump scratch-gui to scratch-desktop-v3.999.0"`

11335
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -32,6 +32,8 @@
"@babel/plugin-proposal-object-rest-spread": "^7.9.6",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-async-to-generator": "^7.8.3",
"@babel/plugin-transform-nullish-coalescing-operator": "^7.22.5",
"@babel/plugin-transform-optional-chaining": "^7.22.6",
"@babel/preset-env": "^7.9.6",
"@babel/preset-react": "^7.9.4",
"async": "^3.2.0",
@ -40,8 +42,8 @@
"babel-loader": "^8.1.0",
"babel-plugin-react-intl": "^7.5.7",
"copy-webpack-plugin": "^5.1.1",
"electron": "^15.3.1",
"electron-builder": "^22.13.1",
"electron": "^25.2.0",
"electron-builder": "^24.4.0",
"electron-devtools-installer": "^3.2.0",
"electron-notarize": "^1.1.1",
"electron-store": "^8.0.1",
@ -66,7 +68,7 @@
"react-redux": "5.1.2",
"redux": "3.7.2",
"rimraf": "^3.0.2",
"scratch-gui": "github:LLK/scratch-gui#scratch-desktop-v3.29.0",
"scratch-gui": "github:scratchfoundation/scratch-gui#scratch-desktop-v3.30.1",
"uuid": "^8.0.0",
"webpack": "^4.43.0",
"webpack-merge": "4.2.2"

View file

@ -230,6 +230,52 @@ const createPrivacyWindow = () => {
return window;
};
const createUsbWindow = () => {
const window = createWindow({
width: 400,
height: 300,
parent: _windows.main,
search: 'route=usb',
modal: true,
frame: false
});
// Filters from navigator.usb.requestDevice do not appear to be available here.
// Hard code to micro:bit since that is the only device that currently uses this api.
const getIsMicroBit = device => device.vendorId === 0x0d28 && device.productId === 0x0204;
let deviceList = [];
let selectedDeviceCallback;
_windows.main.webContents.session.on('select-usb-device', (event, details, callback) => {
deviceList = details.deviceList.filter(getIsMicroBit);
selectedDeviceCallback = callback;
window.webContents.send('usb-device-list', deviceList);
window.show();
event.preventDefault();
});
_windows.main.webContents.session.on('usb-device-added', (_event, device) => {
if (!getIsMicroBit(device)) return;
deviceList.push(device);
window.webContents.send('usb-device-list', deviceList);
});
_windows.main.webContents.session.on('usb-device-removed', (_event, device) => {
if (!getIsMicroBit(device)) return;
deviceList = deviceList.filter(existing => existing.deviceId !== device.deviceId);
window.webContents.send('usb-device-list', deviceList);
});
ipcMain.on('usb-device-selected', (_event, message) => {
selectedDeviceCallback(message);
window.hide();
});
return window;
};
const getIsProjectSave = downloadItem => {
switch (downloadItem.getMimeType()) {
case 'application/x.scratch.sb3':
@ -398,6 +444,8 @@ app.on('ready', () => {
event.preventDefault();
_windows.privacy.hide();
});
_windows.usb = createUsbWindow();
});
ipcMain.on('open-about-window', () => {

View file

@ -1,5 +1,5 @@
html, body {
background-color: #4D97FF;
background-color: #855CD6;
color: white;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: bolder;

View file

@ -4,7 +4,7 @@
<meta charset="utf-8">
<style>
body {
background-color: #4D97FF;
background-color: #855CD6;
}
.splash {
color: white;

View file

@ -24,6 +24,9 @@ case 'about':
case 'privacy':
routeModulePromise = import('./privacy.jsx');
break;
case 'usb':
routeModulePromise = import('./usb.jsx');
break;
}
routeModulePromise.then(routeModule => {

View file

@ -1,11 +1,15 @@
html, body {
background-color: #4D97FF;
background-color: #855CD6;
color: white;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: normal;
line-height: 150%;
}
a:active, a:hover, a:link, a:visited {
color: #855CD6;
}
.privacyBox {
background-color: white;
color: #575e75;

75
src/renderer/usb.css Normal file
View file

@ -0,0 +1,75 @@
html, body {
background-color: white;
color: #575E75;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: normal;
line-height: 150%;
margin: 0;
}
html, body, :global(#app), main {
height: 100%;
}
:global(#app) {
box-sizing: border-box;
padding: 1rem;
}
main {
display: flex;
flex-direction: column;
}
.devices {
border: 1px solid hsla(0, 0%, 0%, 0.15);
flex-grow: 1;
margin-block: 1em;
overflow-y: auto;
padding: 0;
}
.device.selected {
background-color: #855CD6;
color: white;
}
.device input[type="radio"] {
/* Hide the radio button but keep it accessible for keyboard */
opacity: 0;
position: absolute;
}
.device label {
box-sizing: border-box;
display: block;
padding-inline: .5em;
}
.buttons {
align-self: flex-end;
}
button {
border-radius: .25rem;
cursor: pointer;
font-weight: 600;
margin: 0.25rem;
padding: 0.6rem 0.75rem;
}
.cancelButton {
background: white;
border: 1px solid #855CD6;
color: #855CD6;
}
.connectButton {
background: #855CD6;
border: 1px solid #855CD6;
color: white;
}
.connectButton:disabled {
opacity: 50%;
}

70
src/renderer/usb.jsx Normal file
View file

@ -0,0 +1,70 @@
import React, {useEffect, useState} from 'react';
import {ipcRenderer} from 'electron';
import styles from './usb.css';
const UsbElement = () => {
const [deviceList, setDeviceList] = useState([]);
const [selectedDeviceId, setSelectedDeviceId] = useState(null);
useEffect(() => {
const listener = (_event, usbDeviceList) => {
setDeviceList(usbDeviceList);
if (!usbDeviceList.some(device => device.deviceId === selectedDeviceId)) {
setSelectedDeviceId(null);
}
};
ipcRenderer.on('usb-device-list', listener);
return () => ipcRenderer.removeListener('usb-device-list', listener);
}, []);
const selectHandler = deviceId => () => {
setSelectedDeviceId(deviceId);
};
const deviceHandler = deviceId => () => {
ipcRenderer.send('usb-device-selected', deviceId);
setSelectedDeviceId(null);
};
return (
<main>
Select your USB device:
<fieldset
className={styles.devices}
>
{deviceList.map(device => (
<div
className={`${styles.device} ${selectedDeviceId === device.deviceId ? styles.selected : ''}`}
key={device.deviceId}
>
<input
checked={selectedDeviceId === device.deviceId}
id={`device-${device.deviceId}`}
name="usbDevice"
onChange={selectHandler(device.deviceId)}
type="radio"
value={device.deviceId}
/>
<label htmlFor={`device-${device.deviceId}`}>{device.productName}</label>
</div>
))}
</fieldset>
<div className={styles.buttons}>
<button
className={styles.cancelButton}
onClick={deviceHandler(null)}
>Cancel</button>
<button
className={styles.connectButton}
disabled={!selectedDeviceId}
onClick={deviceHandler(selectedDeviceId)}
>Connect</button>
</div>
</main>
);
};
export default <UsbElement />;

View file

@ -24,7 +24,9 @@ const makeConfig = function (defaultConfig, options) {
plugins: [
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-transform-async-to-generator',
'@babel/plugin-proposal-object-rest-spread'
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-transform-nullish-coalescing-operator',
'@babel/plugin-transform-optional-chaining'
],
presets: [
['@babel/preset-env', {targets: {electron: electronVersion}}]
@ -101,6 +103,15 @@ const makeConfig = function (defaultConfig, options) {
options: {
outputPath: 'static/assets/'
}
},
{
test: /\.hex$/,
use: [{
loader: 'url-loader',
options: {
limit: 16 * 1024
}
}]
}
]
},

View file

@ -20,19 +20,31 @@ module.exports = defaultConfig =>
/node_modules[\\/]+@vernier[\\/]+godirect/
],
plugins: [
new CopyWebpackPlugin([{
from: path.join(getModulePath('scratch-blocks'), 'media'),
to: 'static/blocks-media'
}]),
new CopyWebpackPlugin([{
from: 'extension-worker.{js,js.map}',
context: path.join(getModulePath('scratch-vm'), 'dist', 'web')
}]),
new CopyWebpackPlugin([{
from: path.join(getModulePath('scratch-gui'), 'src', 'lib', 'libraries', '*.json'),
to: 'static/libraries',
flatten: true
}])
new CopyWebpackPlugin([
{
from: path.join(getModulePath('scratch-blocks'), 'media'),
to: 'static/blocks-media/default'
},
{
from: path.join(getModulePath('scratch-blocks'), 'media'),
to: 'static/blocks-media/high-contrast'
},
{
from: path.join(getModulePath('scratch-gui'),
'src', 'lib', 'themes', 'high-contrast', 'blocks-media'),
to: 'static/blocks-media/high-contrast',
force: true
},
{
from: 'extension-worker.{js,js.map}',
context: path.join(getModulePath('scratch-vm'), 'dist', 'web')
},
{
from: path.join(getModulePath('scratch-gui'), 'src', 'lib', 'libraries', '*.json'),
to: 'static/libraries',
flatten: true
}
])
]
}
);