From 45509774717efc96013447fd9673114b3de906e3 Mon Sep 17 00:00:00 2001
From: Delucse <46593742+Delucse@users.noreply.github.com>
Date: Tue, 15 Sep 2020 14:39:47 +0200
Subject: [PATCH 1/3] upload, download, compile and reset blocks
---
package.json | 1 +
src/components/ClearWorkspace.js | 46 ----------
src/components/Compile.js | 34 ++++++-
src/components/Home.js | 4 +-
src/components/Navbar.js | 2 -
src/components/WorkspaceFunc.js | 146 ++++++++++++++++++++++++++-----
6 files changed, 155 insertions(+), 78 deletions(-)
delete mode 100644 src/components/ClearWorkspace.js
diff --git a/package.json b/package.json
index ff3634c..9f78c9a 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"blockly": "^3.20200625.2",
+ "file-saver": "^2.0.2",
"prismjs": "^1.20.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
diff --git a/src/components/ClearWorkspace.js b/src/components/ClearWorkspace.js
deleted file mode 100644
index 2e31b01..0000000
--- a/src/components/ClearWorkspace.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import React, {Component} from 'react';
-import PropTypes from 'prop-types';
-import { connect } from 'react-redux';
-import { clearStats, onChangeCode } from '../actions/workspaceActions';
-import { initialXml } from './Blockly/initialXml.js';
-
-import * as Blockly from 'blockly/core';
-
-import ListItem from '@material-ui/core/ListItem';
-import ListItemIcon from '@material-ui/core/ListItemIcon';
-import ListItemText from '@material-ui/core/ListItemText';
-
-import { faTrashRestore } from "@fortawesome/free-solid-svg-icons";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-
-class ClearWorkspace extends Component {
-
- clearWorkspace = () => {
- const workspace = Blockly.getMainWorkspace();
- Blockly.Events.disable(); // https://groups.google.com/forum/#!topic/blockly/m7e3g0TC75Y
- // if events are disabled, then the workspace will be cleared AND the blocks are not in the trashcan
- const xmlDom = Blockly.Xml.textToDom(initialXml)
- Blockly.Xml.clearWorkspaceAndLoadFromXml(xmlDom, workspace);
- Blockly.Events.enable();
- workspace.options.maxBlocks = Infinity;
- this.props.onChangeCode();
- this.props.clearStats();
- }
-
- render() {
- return (
- {this.clearWorkspace(); this.props.onClick();}}>
-
-
-
- );
- };
-}
-
-ClearWorkspace.propTypes = {
- clearStats: PropTypes.func.isRequired,
- onChangeCode: PropTypes.func.isRequired
-};
-
-
-export default connect(null, { clearStats, onChangeCode })(ClearWorkspace);
diff --git a/src/components/Compile.js b/src/components/Compile.js
index a6c86c2..e42f5cf 100644
--- a/src/components/Compile.js
+++ b/src/components/Compile.js
@@ -10,11 +10,26 @@ import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContent from '@material-ui/core/DialogContent';
import DialogActions from '@material-ui/core/DialogActions';
import Dialog from '@material-ui/core/Dialog';
+import IconButton from '@material-ui/core/IconButton';
+import Tooltip from '@material-ui/core/Tooltip';
+
+import { faPlay } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
const styles = (theme) => ({
backdrop: {
zIndex: theme.zIndex.drawer + 1,
color: '#fff',
+ },
+ button: {
+ backgroundColor: theme.palette.primary.main,
+ color: theme.palette.primary.contrastText,
+ width: '40px',
+ height: '40px',
+ '&:hover': {
+ backgroundColor: theme.palette.primary.main,
+ color: theme.palette.primary.contrastText,
+ }
}
});
@@ -60,10 +75,21 @@ class Compile extends Component {
render() {
return (
-
-
+
+ {this.props.iconButton ?
+
+ this.compile()}
+ >
+
+
+
+ :
+
+ }
diff --git a/src/components/Home.js b/src/components/Home.js
index 5b6f71f..47555f9 100644
--- a/src/components/Home.js
+++ b/src/components/Home.js
@@ -72,7 +72,8 @@ class Home extends Component {
render() {
return (
-
+
+
@@ -93,7 +94,6 @@ class Home extends Component {
: null}
-
);
};
diff --git a/src/components/Navbar.js b/src/components/Navbar.js
index fb5365f..55db003 100644
--- a/src/components/Navbar.js
+++ b/src/components/Navbar.js
@@ -1,7 +1,6 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
-import ClearWorkspace from './ClearWorkspace';
import senseboxLogo from './sensebox_logo.svg';
import { withRouter } from 'react-router-dom';
@@ -105,7 +104,6 @@ class Navbar extends Component {
))}
-
diff --git a/src/components/WorkspaceFunc.js b/src/components/WorkspaceFunc.js
index 8c4826c..117bf68 100644
--- a/src/components/WorkspaceFunc.js
+++ b/src/components/WorkspaceFunc.js
@@ -1,39 +1,143 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
+import { clearStats, onChangeCode } from '../actions/workspaceActions';
+
+import * as Blockly from 'blockly/core';
+
+import { saveAs } from 'file-saver';
+
+import { initialXml } from './Blockly/initialXml.js';
-import MaxBlocks from './MaxBlocks';
import Compile from './Compile';
+import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContent from '@material-ui/core/DialogContent';
import DialogActions from '@material-ui/core/DialogActions';
import Dialog from '@material-ui/core/Dialog';
+import IconButton from '@material-ui/core/IconButton';
+import Tooltip from '@material-ui/core/Tooltip';
+
+import { faSave, faUpload, faShare } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+
+const styles = (theme) => ({
+ button: {
+ backgroundColor: theme.palette.primary.main,
+ color: theme.palette.primary.contrastText,
+ width: '40px',
+ height: '40px',
+ '&:hover': {
+ backgroundColor: theme.palette.primary.main,
+ color: theme.palette.primary.contrastText,
+ }
+ }
+});
+
class WorkspaceFunc extends Component {
- state = {
- title: '',
- content: '',
- open: false
- }
-
- getArduinoCode = () => {
- this.setState({ title: 'Adurino Code', content: this.props.arduino, open: true });
- }
-
- getXMLCode = () => {
- this.setState({ title: 'XML Code', content: this.props.xml, open: true });
+ constructor(props){
+ super(props);
+ this.inputRef = React.createRef();
+ this.state = {
+ title: '',
+ content: '',
+ open: false
+ };
}
toggleDialog = () => {
this.setState({ open: !this.state });
}
+ saveXmlFile = (code) => {
+ // saveTextFileAs
+ var fileName = 'todo.xml'
+ var blob = new Blob([code], { type: 'text/xml' });
+ saveAs(blob, fileName);
+ }
+
+ uploadXmlFile = (xmlFile) => {
+ console.log(xmlFile);
+ if(xmlFile.type !== 'text/xml'){
+ this.setState({ open: true, title: 'Unzulässiger Dateityp', content: 'Die übergebene Datei entsprach nicht dem geforderten Format. Es sind nur XML-Dateien zulässig.' });
+ }
+ else {
+ var reader = new FileReader();
+ reader.readAsText(xmlFile);
+ reader.onloadend = () => {
+ var xmlDom = null;
+ try {
+ xmlDom = Blockly.Xml.textToDom(reader.result);
+ const workspace = Blockly.getMainWorkspace();
+ var xmlBefore = this.props.xml;
+ workspace.clear();
+ this.props.clearStats();
+ Blockly.Xml.domToWorkspace(xmlDom, workspace);
+ if(workspace.getAllBlocks().length < 1){
+ Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xmlBefore), workspace)
+ this.setState({ open: true, title: 'Keine Blöcke', content: 'Es wurden keine Blöcke detektiert. Bitte überprüfe den XML-Code und versuche es erneut.' });
+ }
+ } catch(err){
+ this.setState({ open: true, title: 'Ungültige XML', content: 'Die XML-Datei konnte nicht in Blöcke zerlegt werden. Bitte überprüfe den XML-Code und versuche es erneut.' });
+ }
+ };
+ }
+ }
+
+ resetWorkspace = () => {
+ const workspace = Blockly.getMainWorkspace();
+ Blockly.Events.disable(); // https://groups.google.com/forum/#!topic/blockly/m7e3g0TC75Y
+ // if events are disabled, then the workspace will be cleared AND the blocks are not in the trashcan
+ const xmlDom = Blockly.Xml.textToDom(initialXml)
+ Blockly.Xml.clearWorkspaceAndLoadFromXml(xmlDom, workspace);
+ Blockly.Events.enable();
+ workspace.options.maxBlocks = Infinity;
+ this.props.onChangeCode();
+ this.props.clearStats();
+ }
+
render() {
return (
-
+
+
+
+ this.saveXmlFile(this.props.xml)}
+ >
+
+
+
+
+
{this.uploadXmlFile(e.target.files[0])}}
+ id="open-blocks"
+ type="file"
+ />
+
+
+
+ this.resetWorkspace()}
+ >
+
+
+
-
-
-
-
);
};
@@ -60,7 +156,9 @@ class WorkspaceFunc extends Component {
WorkspaceFunc.propTypes = {
arduino: PropTypes.string.isRequired,
- xml: PropTypes.string.isRequired
+ xml: PropTypes.string.isRequired,
+ clearStats: PropTypes.func.isRequired,
+ onChangeCode: PropTypes.func.isRequired
};
const mapStateToProps = state => ({
@@ -68,4 +166,4 @@ const mapStateToProps = state => ({
xml: state.workspace.code.xml
});
-export default connect(mapStateToProps, null)(WorkspaceFunc);
+export default connect(mapStateToProps, { clearStats, onChangeCode })(withStyles(styles, {withTheme: true})(WorkspaceFunc));
From 1c29dd21096afba6f798af86a8e83c09f9d31999 Mon Sep 17 00:00:00 2001
From: Delucse <46593742+Delucse@users.noreply.github.com>
Date: Tue, 15 Sep 2020 17:05:22 +0200
Subject: [PATCH 2/3] display statistics as menu, if screen is too small
---
src/components/Home.js | 4 +-
src/components/WorkspaceFunc.js | 2 +-
src/components/WorkspaceStats.js | 165 +++++++++++++++++++++----------
3 files changed, 116 insertions(+), 55 deletions(-)
diff --git a/src/components/Home.js b/src/components/Home.js
index 47555f9..3da011d 100644
--- a/src/components/Home.js
+++ b/src/components/Home.js
@@ -72,8 +72,8 @@ class Home extends Component {
render() {
return (
-
-
+
+
diff --git a/src/components/WorkspaceFunc.js b/src/components/WorkspaceFunc.js
index 117bf68..86a32db 100644
--- a/src/components/WorkspaceFunc.js
+++ b/src/components/WorkspaceFunc.js
@@ -102,7 +102,7 @@ class WorkspaceFunc extends Component {
render() {
return (
-
+
({
@@ -19,65 +22,123 @@ const styles = (theme) => ({
marginLeft: '50px',
padding: '3px 10px',
// borderRadius: '25%'
+ },
+ menu: {
+ backgroundColor: theme.palette.secondary.main,
+ color: theme.palette.secondary.contrastText,
+ width: '40px',
+ height: '40px',
+ '&:hover': {
+ backgroundColor: theme.palette.secondary.main,
+ color: theme.palette.primary.main,
+ }
}
});
class WorkspaceStats extends Component {
+ state={
+ anchor: null
+ }
+
+ handleClose = () => {
+ this.setState({ anchor: null });
+ }
+
+ handleClick = (event) => {
+ this.setState({ anchor: event.currentTarget });
+ };
+
render() {
+ const bigDisplay = !isWidthDown('xs', this.props.width);
const workspace = Blockly.getMainWorkspace();
const remainingBlocksInfinity = workspace ? workspace.remainingCapacity() !== Infinity : null;
+ const stats =
+
+ }
+ label={workspace ? workspace.getAllBlocks().length : 0}>
+
+
+
+ }
+ label={this.props.create > 0 ? this.props.create : 0}> {/* initialXML is created automatically, Block is not part of the statistics */}
+
+
+
+ }
+ label={this.props.change}>
+
+
+
+ }
+ label={this.props.move > 0 ? this.props.move : 0}> {/* initialXML is moved automatically, Block is not part of the statistics */}
+
+
+
+ }
+ label={this.props.delete}>
+
+
+ {remainingBlocksInfinity ?
+
+
+
+ : null}
+
return (
-
-
- }
- label={workspace ? workspace.getAllBlocks().length : 0}>
-
-
-
- }
- label={this.props.create > 0 ? this.props.create : 0}> {/* initialXML is created automatically, Block is not part of the statistics */}
-
-
-
- }
- label={this.props.change}>
-
-
-
- }
- label={this.props.move > 0 ? this.props.move : 0}> {/* initialXML is moved automatically, Block is not part of the statistics */}
-
-
-
- }
- label={this.props.delete}>
-
-
- {remainingBlocksInfinity ?
-
-
-
- : null}
-
+ bigDisplay ?
+
+ {stats}
+
+ :
+
+
+ this.handleClick(event)}
+ >
+
+
+
+
+
+ {stats}
+
+
+
);
};
}
@@ -98,4 +159,4 @@ const mapStateToProps = state => ({
workspaceChange: state.workspace.change
});
-export default connect(mapStateToProps, null)(withStyles(styles, { withTheme: true })(WorkspaceStats));
+export default connect(mapStateToProps, null)(withStyles(styles, { withTheme: true })(withWidth()(WorkspaceStats)));
From 427467eb8a8b19fe33a8ad8e57e2f4c4ea4c2dbf Mon Sep 17 00:00:00 2001
From: Delucse <46593742+Delucse@users.noreply.github.com>
Date: Tue, 15 Sep 2020 17:21:02 +0200
Subject: [PATCH 3/3] add workspace functions to assessment
---
src/components/Tutorial/Assessment.js | 7 ++++---
src/components/Tutorial/SolutionCheck.js | 2 +-
src/components/WorkspaceFunc.js | 3 ++-
3 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/components/Tutorial/Assessment.js b/src/components/Tutorial/Assessment.js
index 0ff93e0..275e223 100644
--- a/src/components/Tutorial/Assessment.js
+++ b/src/components/Tutorial/Assessment.js
@@ -5,6 +5,7 @@ import { connect } from 'react-redux';
import BlocklyWindow from '../Blockly/BlocklyWindow';
import SolutionCheck from './SolutionCheck';
import CodeViewer from '../CodeViewer';
+import WorkspaceFunc from '../WorkspaceFunc';
import Grid from '@material-ui/core/Grid';
import Card from '@material-ui/core/Card';
@@ -21,10 +22,10 @@ class Assessment extends Component {
return (
-
{currentTask.headline}
+
{currentTask.headline}
+
-
-
+
diff --git a/src/components/Tutorial/SolutionCheck.js b/src/components/Tutorial/SolutionCheck.js
index 3156fc6..7d5f979 100644
--- a/src/components/Tutorial/SolutionCheck.js
+++ b/src/components/Tutorial/SolutionCheck.js
@@ -63,7 +63,7 @@ class SolutionCheck extends Component {
this.check()}
>
diff --git a/src/components/WorkspaceFunc.js b/src/components/WorkspaceFunc.js
index 86a32db..d0414c1 100644
--- a/src/components/WorkspaceFunc.js
+++ b/src/components/WorkspaceFunc.js
@@ -10,6 +10,7 @@ import { saveAs } from 'file-saver';
import { initialXml } from './Blockly/initialXml.js';
import Compile from './Compile';
+import SolutionCheck from './Tutorial/SolutionCheck';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
@@ -103,7 +104,7 @@ class WorkspaceFunc extends Component {
render() {
return (
-
+ {this.props.solutionCheck ? : }