Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ npm-*

# Downloaded during "npm install"
/static/microbit
/static/microbitMore

# for act
.secrets
Expand Down
36 changes: 36 additions & 0 deletions scripts/prepublish.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,44 @@ const downloadMicrobitHex = async () => {
console.info(`Wrote ${relativeGeneratedFile}`);
};

const downloadMicrobitMoreHex = async () => {
const url = 'https://github.com/microbit-more/pxt-mbit-more-v2/releases/download/0.2.5/microbit-mbit-more-v2-0_2_5.hex';
console.info(`Downloading ${url}`);
const response = await crossFetch(url);
const hexBuffer = Buffer.from(await response.arrayBuffer());
const relativeHexDir = path.join('static', 'microbitMore');
const hexFileName = 'microbit-mbit-more-v2-0_2_5.hex';
const relativeHexFile = path.join(relativeHexDir, hexFileName);
const absoluteDestDir = path.join(basePath, relativeHexDir);
fs.mkdirSync(absoluteDestDir, {recursive: true});
const absoluteDestFile = path.join(basePath, relativeHexFile);
fs.writeFileSync(absoluteDestFile, hexBuffer);

const relativeGeneratedDir = path.join('src', 'generated');
const relativeGeneratedFile = path.join(relativeGeneratedDir, 'microbit-more-hex-url.cjs');
const absoluteGeneratedDir = path.join(basePath, relativeGeneratedDir);
fs.mkdirSync(absoluteGeneratedDir, {recursive: true});
const absoluteGeneratedFile = path.join(basePath, relativeGeneratedFile);
const requirePath = `./${path
.relative(relativeGeneratedDir, relativeHexFile)
.split(path.win32.sep)
.join(path.posix.sep)}`;
fs.writeFileSync(
absoluteGeneratedFile,
[
'// This file is generated by scripts/prepublish.mjs',
'// Do not edit this file directly',
'// This file relies on a loader to turn this `require` into a URL',
`module.exports = require('${requirePath}');`,
'' // final newline
].join('\n')
);
console.info(`Wrote ${relativeGeneratedFile}`);
};

const prepublish = async () => {
await downloadMicrobitHex();
await downloadMicrobitMoreHex();
};

prepublish().then(
Expand Down
5 changes: 5 additions & 0 deletions src/components/connection-modal/connection-modal.css
Original file line number Diff line number Diff line change
Expand Up @@ -446,3 +446,8 @@
height: 60%;
width: inherit;
}

.important-instruction {
font-weight: bold;
color: $ui-red;
}
18 changes: 16 additions & 2 deletions src/components/connection-modal/connection-modal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,20 @@ const ConnectionModalComponent = props => (
{props.phase === PHASES.scanning && props.useAutoScan && <AutoScanningStep {...props} />}
{props.phase === PHASES.connecting && <ConnectingStep {...props} />}
{props.phase === PHASES.connected && <ConnectedStep {...props} />}
{props.phase === PHASES.error && <ErrorStep {...props} />}
{props.phase === PHASES.unavailable && <UnavailableStep {...props} />}
{props.phase === PHASES.error && (
<ErrorStep
{...props}
onScanning={props.onScanning}
onUpdatePeripheral={props.onUpdatePeripheral}
/>
)}
{props.phase === PHASES.unavailable && (
<UnavailableStep
{...props}
onScanning={props.onScanning}
onUpdatePeripheral={props.onUpdatePeripheral}
/>
)}
{props.phase === PHASES.updatePeripheral && <UpdatePeripheralStep {...props} />}
</Box>
</Modal>
Expand All @@ -55,6 +67,8 @@ ConnectionModalComponent.propTypes = {
name: PropTypes.node,
onCancel: PropTypes.func.isRequired,
onHelp: PropTypes.func.isRequired,
onScanning: PropTypes.func,
onUpdatePeripheral: PropTypes.func,
phase: PropTypes.oneOf(Object.keys(PHASES)).isRequired,
title: PropTypes.string.isRequired,
useAutoScan: PropTypes.bool.isRequired
Expand Down
29 changes: 28 additions & 1 deletion src/components/connection-modal/error-step.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Box from '../box/box.jsx';
import Dots from './dots.jsx';
import helpIcon from './icons/help.svg';
import backIcon from './icons/back.svg';
import enterUpdateIcon from './icons/enter-update.svg';

import styles from './connection-modal.css';

Expand All @@ -30,6 +31,15 @@ const ErrorStep = props => (
id="gui.connection.error.errorMessage"
/>
</div>
{props.onUpdatePeripheral && (
<div className={classNames(styles.bottomAreaItem, styles.instructions)}>
<FormattedMessage
defaultMessage="If you don't see your device, you may need to update it to work with Scratch."
description="Prompt for updating a peripheral device"
id="gui.connection.scanning.updatePeripheralPrompt"
/>
</div>
)}
<Dots
error
className={styles.bottomAreaItem}
Expand All @@ -50,6 +60,22 @@ const ErrorStep = props => (
id="gui.connection.error.tryagainbutton"
/>
</button>
{props.onUpdatePeripheral && (
<button
className={styles.connectionButton}
onClick={props.onUpdatePeripheral}
>
<FormattedMessage
defaultMessage="Update my Device"
description="Button to enter the peripheral update mode"
id="gui.connection.scanning.updatePeripheralButton"
/>
<img
className={styles.buttonIconRight}
src={enterUpdateIcon}
/>
</button>
)}
<button
className={styles.connectionButton}
onClick={props.onHelp}
Expand All @@ -72,7 +98,8 @@ const ErrorStep = props => (
ErrorStep.propTypes = {
connectionIconURL: PropTypes.string.isRequired,
onHelp: PropTypes.func,
onScanning: PropTypes.func
onScanning: PropTypes.func,
onUpdatePeripheral: PropTypes.func
};

export default ErrorStep;
30 changes: 29 additions & 1 deletion src/components/connection-modal/unavailable-step.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import backIcon from './icons/back.svg';
import bluetoothIcon from './icons/bluetooth.svg';
import scratchLinkIcon from './icons/scratchlink.svg';

import enterUpdateIcon from './icons/enter-update.svg';

import styles from './connection-modal.css';

const UnavailableStep = props => (
Expand Down Expand Up @@ -55,6 +57,15 @@ const UnavailableStep = props => (
</div>
</Box>
<Box className={styles.bottomArea}>
<Box className={classNames(styles.bottomAreaItem, styles.instructions)}>
{props.onUpdatePeripheral && (
<FormattedMessage
defaultMessage="If you don't see your device, you may need to update it to work with Scratch."
description="Prompt for updating a peripheral device"
id="gui.connection.scanning.updatePeripheralPrompt"
/>
)}
</Box>
<Dots
error
className={styles.bottomAreaItem}
Expand All @@ -75,6 +86,22 @@ const UnavailableStep = props => (
id="gui.connection.unavailable.tryagainbutton"
/>
</button>
{props.onUpdatePeripheral && (
<button
className={styles.connectionButton}
onClick={props.onUpdatePeripheral}
>
<FormattedMessage
defaultMessage="Update my Device"
description="Button to enter the peripheral update mode"
id="gui.connection.scanning.updatePeripheralButton"
/>
<img
className={styles.buttonIconRight}
src={enterUpdateIcon}
/>
</button>
)}
<button
className={styles.connectionButton}
onClick={props.onHelp}
Expand All @@ -96,7 +123,8 @@ const UnavailableStep = props => (

UnavailableStep.propTypes = {
onHelp: PropTypes.func,
onScanning: PropTypes.func
onScanning: PropTypes.func,
onUpdatePeripheral: PropTypes.func
};

export default UnavailableStep;
49 changes: 38 additions & 11 deletions src/components/connection-modal/update-peripheral-step.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,36 @@ class UpdatePeripheralStep extends React.Component {
renderResults () {
let resultsContent;
if (this.state.err === null) {
resultsContent = (<FormattedMessage
defaultMessage="Update successful!"
description="Message to indicate that the peripheral update was successful"
id="gui.connection.updatePeripheral.updateSuccessful"
/>);
if (this.props.extensionId === 'microbitMore') {
resultsContent = (
<Box className={styles.scratchLinkError}>
<Box className={styles.centeredRow}>
<FormattedMessage
defaultMessage="MicrobitMore update successful!"
description="Message to indicate that the MicrobitMore update was successful"
id="gui.connection.updatePeripheral.microbitMoreUpdateSuccessful"
/>
</Box>
<Box className={classNames(styles.centeredRow, styles.importantInstruction)}>
<FormattedMessage
defaultMessage="Tilt your micro:bit to light up all 25 LEDs to complete."
description="Instructions to tilt the micro:bit to complete the update process"
id="gui.connection.updatePeripheral.microbitMoreTiltToLightUp"
/>
</Box>
</Box>
);
} else {
resultsContent = (
<Box className={styles.centeredRow}>
<FormattedMessage
defaultMessage="Update successful!"
description="Message to indicate that the peripheral update was successful"
id="gui.connection.updatePeripheral.updateSuccessful"
/>
</Box>
);
}
} else if (this.state.err.message === 'No valid interfaces found.') {
// this is a special case where the micro:bit's communication firmware is too old to support WebUSB
resultsContent = (<BalancedFormattedMessage
Expand All @@ -160,12 +185,13 @@ class UpdatePeripheralStep extends React.Component {
} else {
resultsContent = (
<Box className={styles.scratchLinkError}>
<FormattedMessage
className={styles.centeredRow}
defaultMessage="Update failed."
description="Message to indicate that the peripheral update failed"
id="gui.connection.updatePeripheral.updateFailed"
/>
<Box className={styles.centeredRow}>
<FormattedMessage
defaultMessage="Update failed."
description="Message to indicate that the peripheral update failed"
id="gui.connection.updatePeripheral.updateFailed"
/>
</Box>
<textarea
className={styles.scratchLinkErrorDetails}
readOnly
Expand Down Expand Up @@ -254,6 +280,7 @@ class UpdatePeripheralStep extends React.Component {

UpdatePeripheralStep.propTypes = {
connectionSmallIconURL: PropTypes.string,
extensionId: PropTypes.string,
name: PropTypes.string.isRequired,
onScanning: PropTypes.func.isRequired,
onSendPeripheralUpdate: PropTypes.func.isRequired
Expand Down
12 changes: 10 additions & 2 deletions src/containers/connection-modal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import {connect} from 'react-redux';

import {closeConnectionModal} from '../reducers/modals';
import {isMicroBitUpdateSupported, selectAndUpdateMicroBit} from '../lib/microbit-update';
import {
isMicroBitUpdateSupported as isMicroBitMoreUpdateSupported,
selectAndUpdateMicroBit as selectAndUpdateMicroBitMore
} from '../lib/microbit-more-update';

class ConnectionModal extends React.Component {
constructor (props) {
Expand Down Expand Up @@ -141,11 +145,15 @@ class ConnectionModal extends React.Component {
label: this.props.extensionId
});

// TODO: get this functionality from the extension
if (this.props.extensionId === 'microbitMore') {
return selectAndUpdateMicroBitMore(progressCallback);
}
return selectAndUpdateMicroBit(progressCallback);
}
render () {
const canUpdatePeripheral = (this.props.extensionId === 'microbit') && isMicroBitUpdateSupported();
const canUpdatePeripheral =
(this.props.extensionId === 'microbit' && isMicroBitUpdateSupported()) ||
(this.props.extensionId === 'microbitMore' && isMicroBitMoreUpdateSupported());
return (
<ConnectionModalComponent
connectingMessage={this.state.extension && this.state.extension.connectingMessage}
Expand Down
2 changes: 2 additions & 0 deletions src/css/colors.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ $ui-black-transparent-10: hsla(0, 0%, 0%, 0.10); /* 10% transparent version of b
$ui-green: hsla(163, 85%, 35%, 1); /* #0DA57A */
$ui-green-2: hsla(163, 85%, 40%, 1); /* #0FBD8C */

$ui-red: hsla(0, 100%, 50%, 1); /* #FF0000 */

$text-primary: hsla(225, 15%, 40%, 1); /* #575E75 */
$text-primary-transparent: hsla(225, 15%, 40%, 0.75);

Expand Down
Loading
Loading