Merge branch 'develop' into load-library-images-through-storage

This commit is contained in:
Christopher Willis-Ford committed 2019-03-14 11:49:47 -07:00
commit 1fd9a1f689
9 files changed
+110 -20

No files matched your search

+2 -2
View File
@@ -106,13 +106,13 @@
"redux-throttle": "0.1.1",
"rimraf": "^2.6.1",
"scratch-audio": "0.1.0-prerelease.20190114210212",
"scratch-blocks": "0.1.0-prerelease.1551865183",
"scratch-blocks": "0.1.0-prerelease.1552509492",
"scratch-l10n": "3.1.20190220143732",
"scratch-paint": "0.2.0-prerelease.20190311150519",
"scratch-render": "0.1.0-prerelease.20190312125229",
"scratch-storage": "1.2.2",
"scratch-svg-renderer": "0.2.0-prerelease.20190304180800",
"scratch-vm": "0.2.0-prerelease.20190312212117",
"scratch-vm": "0.2.0-prerelease.20190314020908",
"selenium-webdriver": "3.6.0",
"startaudiocontext": "1.2.1",
"style-loader": "^0.23.0",
+2
View File
@@ -97,6 +97,7 @@ const GUIComponent = props => {
onActivateTab,
onClickLogo,
onExtensionButtonClick,
onProjectTelemetryEvent,
onRequestCloseBackdropLibrary,
onRequestCloseCostumeLibrary,
onRequestCloseTelemetryModal,
@@ -217,6 +218,7 @@ const GUIComponent = props => {
onCloseAccountNav={onCloseAccountNav}
onLogOut={onLogOut}
onOpenRegistration={onOpenRegistration}
onProjectTelemetryEvent={onProjectTelemetryEvent}
onSeeCommunity={onSeeCommunity}
onShare={onShare}
onToggleLoginOpen={onToggleLoginOpen}
@@ -178,6 +178,10 @@
font-weight: bold;
}
.featured-extension-metadata-detail img{
margin-right: 0.25rem;
}
.coming-soon-text {
position: absolute;
background-color: $data-primary;
+6 -6
View File
@@ -75,12 +75,12 @@ class LibraryItemComponent extends React.PureComponent {
<div
className={styles.featuredExtensionMetadataDetail}
>
<img
src={this.props.bluetoothRequired ?
bluetoothIconURL :
internetConnectionIconURL
}
/>
{this.props.bluetoothRequired ? (
<img src={bluetoothIconURL} />
) : null}
{this.props.internetConnectionRequired ? (
<img src={internetConnectionIconURL} />
) : null}
</div>
</div>
) : null}
+23 -11
View File
@@ -6,6 +6,8 @@ import bindAll from 'lodash.bindall';
import bowser from 'bowser';
import React from 'react';
import VM from 'scratch-vm';
import Box from '../box/box.jsx';
import Button from '../button/button.jsx';
import CommunityButton from './community-button.jsx';
@@ -55,6 +57,8 @@ import {
loginMenuOpen
} from '../../reducers/menus';
import collectMetadata from '../../lib/collect-metadata';
import styles from './menu-bar.css';
import helpIcon from '../../lib/assets/icon--tutorials.svg';
@@ -146,10 +150,10 @@ class MenuBar extends React.Component {
'handleClickSaveAsCopy',
'handleClickSeeCommunity',
'handleClickShare',
'handleCloseFileMenuAndThen',
'handleKeyPress',
'handleLanguageMouseUp',
'handleRestoreOption',
'handleSaveToComputer',
'restoreOptionMessage'
]);
}
@@ -216,12 +220,6 @@ class MenuBar extends React.Component {
this.props.onRequestCloseEdit();
};
}
handleCloseFileMenuAndThen (fn) {
return () => {
this.props.onRequestCloseFile();
fn();
};
}
handleKeyPress (event) {
const modifier = bowser.mac ? event.metaKey : event.ctrlKey;
if (modifier && event.key === 's') {
@@ -229,6 +227,16 @@ class MenuBar extends React.Component {
event.preventDefault();
}
}
handleSaveToComputer (downloadProjectCallback) {
return () => {
this.props.onRequestCloseFile();
downloadProjectCallback();
if (this.props.onProjectTelemetryEvent) {
const metadata = collectMetadata(this.props.vm, this.props.projectTitle, this.props.locale);
this.props.onProjectTelemetryEvent('projectDidSave', metadata);
}
};
}
handleLanguageMouseUp (e) {
if (!this.props.languageMenuOpen) {
this.props.onClickLanguage(e);
@@ -402,10 +410,10 @@ class MenuBar extends React.Component {
</MenuItem>
)}
</SBFileUploader>
<SB3Downloader>{(className, downloadProject) => (
<SB3Downloader>{(className, downloadProjectCallback) => (
<MenuItem
className={className}
onClick={this.handleCloseFileMenuAndThen(downloadProject)}
onClick={this.handleSaveToComputer(downloadProjectCallback)}
>
<FormattedMessage
defaultMessage="Save to your computer"
@@ -743,6 +751,7 @@ MenuBar.propTypes = {
onLogOut: PropTypes.func,
onOpenRegistration: PropTypes.func,
onOpenTipLibrary: PropTypes.func,
onProjectTelemetryEvent: PropTypes.func,
onRequestCloseAccount: PropTypes.func,
onRequestCloseEdit: PropTypes.func,
onRequestCloseFile: PropTypes.func,
@@ -757,7 +766,8 @@ MenuBar.propTypes = {
renderLogin: PropTypes.func,
sessionExists: PropTypes.bool,
showComingSoon: PropTypes.bool,
username: PropTypes.string
username: PropTypes.string,
vm: PropTypes.instanceOf(VM).isRequired
};
MenuBar.defaultProps = {
@@ -775,11 +785,13 @@ const mapStateToProps = state => {
isUpdating: getIsUpdating(loadingState),
isShowingProject: getIsShowingProject(loadingState),
languageMenuOpen: languageMenuOpen(state),
locale: state.locales.locale,
loginMenuOpen: loginMenuOpen(state),
projectChanged: state.scratchGui.projectChanged,
projectTitle: state.scratchGui.projectTitle,
sessionExists: state.session && typeof state.session.session !== 'undefined',
username: user ? user.username : null
username: user ? user.username : null,
vm: state.scratchGui.vm
};
};
+39
View File
@@ -0,0 +1,39 @@
/**
* Report a telemetry event.
* @param {string} event - one of `projectWasCreated`, `projectDidLoad`, `projectDidSave`, `projectWasUploaded`
*/
// TODO make a telemetry HOC and move this stuff there
const collectMetadata = function (vm, projectName = '', locale = '') {
// TODO move most or all of this into a collectMetadata() method on the VM/Runtime
const metadata = {
projectName: projectName,
language: locale,
spriteCount: 0,
blocksCount: 0,
costumesCount: 0,
listsCount: 0,
scriptCount: 0,
soundsCount: 0,
variablesCount: 0
};
for (const target of vm.runtime.targets) {
++metadata.spriteCount;
metadata.blocksCount += Object.keys(target.sprite.blocks._blocks).length;
metadata.costumesCount += target.sprite.costumes_.length;
metadata.scriptCount += target.sprite.blocks._scripts.length;
metadata.soundsCount += target.sprite.sounds.length;
for (const variableName in target.variables) {
const variable = target.variables[variableName];
if (variable.type === 'list') {
++metadata.listsCount;
} else {
++metadata.variablesCount;
}
}
}
return metadata;
};
export default collectMetadata;
+5 -1
View File
@@ -163,6 +163,7 @@ export default [
featured: true,
disabled: false,
bluetoothRequired: true,
internetConnectionRequired: true,
launchPeripheralConnectionFlow: true,
useAutoScan: false,
peripheralImage: microbitPeripheralImage,
@@ -192,6 +193,7 @@ export default [
featured: true,
disabled: false,
bluetoothRequired: true,
internetConnectionRequired: true,
launchPeripheralConnectionFlow: true,
useAutoScan: false,
peripheralImage: ev3PeripheralImage,
@@ -221,6 +223,7 @@ export default [
featured: true,
disabled: false,
bluetoothRequired: true,
internetConnectionRequired: true,
launchPeripheralConnectionFlow: true,
useAutoScan: true,
peripheralImage: wedoPeripheralImage,
@@ -250,6 +253,7 @@ export default [
),
featured: true,
disabled: true,
bluetoothRequired: true
bluetoothRequired: true,
internetConnectionRequired: true
}
];
+26
View File
@@ -6,6 +6,7 @@ import {connect} from 'react-redux';
import VM from 'scratch-vm';
import xhr from 'xhr';
import collectMetadata from '../lib/collect-metadata';
import log from '../lib/log';
import storage from '../lib/storage';
import dataURItoBlob from '../lib/data-uri-to-blob';
@@ -25,6 +26,7 @@ import {
getIsAnyCreatingNewState,
getIsCreatingCopy,
getIsCreatingNew,
getIsLoading,
getIsManualUpdating,
getIsRemixing,
getIsShowingWithId,
@@ -61,6 +63,13 @@ const ProjectSaverHOC = function (WrappedComponent) {
this.props.onSetProjectThumbnailer(this.getProjectThumbnail);
}
componentDidUpdate (prevProps) {
if (!this.props.isAnyCreatingNewState && prevProps.isAnyCreatingNewState) {
this.reportTelemetryEvent('projectWasCreated');
}
if (!this.props.isLoading && prevProps.isLoading) {
this.reportTelemetryEvent('projectDidLoad');
}
if (this.props.projectChanged && !prevProps.projectChanged) {
this.scheduleAutoSave();
}
@@ -305,6 +314,18 @@ const ProjectSaverHOC = function (WrappedComponent) {
this.props.vm.renderer.draw();
}
/**
* Report a telemetry event.
* @param {string} event - one of `projectWasCreated`, `projectDidLoad`, `projectDidSave`, `projectWasUploaded`
*/
// TODO make a telemetry HOC and move this stuff there
reportTelemetryEvent (event) {
if (this.props.onProjectTelemetryEvent) {
const metadata = collectMetadata(this.props.vm, this.props.reduxProjectTitle, this.props.locale);
this.props.onProjectTelemetryEvent(event, metadata);
}
}
render () {
const {
/* eslint-disable no-unused-vars */
@@ -314,6 +335,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
isCreatingNew,
projectChanged,
isAnyCreatingNewState,
isLoading,
isManualUpdating,
isRemixing,
isShowingSaveable,
@@ -359,6 +381,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
isAnyCreatingNewState: PropTypes.bool,
isCreatingCopy: PropTypes.bool,
isCreatingNew: PropTypes.bool,
isLoading: PropTypes.bool,
isManualUpdating: PropTypes.bool,
isRemixing: PropTypes.bool,
isShared: PropTypes.bool,
@@ -371,6 +394,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
onCreateProject: PropTypes.func,
onCreatedProject: PropTypes.func,
onProjectError: PropTypes.func,
onProjectTelemetryEvent: PropTypes.func,
onRemixing: PropTypes.func,
onShowAlert: PropTypes.func,
onShowCopySuccessAlert: PropTypes.func,
@@ -397,6 +421,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
return {
autoSaveTimeoutId: state.scratchGui.timeout.autoSaveTimeoutId,
isAnyCreatingNewState: getIsAnyCreatingNewState(loadingState),
isLoading: getIsLoading(loadingState),
isCreatingCopy: getIsCreatingCopy(loadingState),
isCreatingNew: getIsCreatingNew(loadingState),
isRemixing: getIsRemixing(loadingState),
@@ -406,6 +431,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
isUpdating: getIsUpdating(loadingState),
isManualUpdating: getIsManualUpdating(loadingState),
loadingState: loadingState,
locale: state.locales.locale,
projectChanged: state.scratchGui.projectChanged,
reduxProjectId: state.scratchGui.projectState.projectId,
reduxProjectTitle: state.scratchGui.projectTitle,
@@ -22,6 +22,9 @@ describe('projectSaverHOC', () => {
timeout: {
autoSaveTimeoutId: null
}
},
locales: {
locale: 'en'
}
});
vm = new VM();