diff --git a/.env b/.env index 8a24119..f3793fa 100644 --- a/.env +++ b/.env @@ -1,2 +1,3 @@ REACT_APP_COMPILER_URL=https://compiler.sensebox.de REACT_APP_BOARD=sensebox-mcu +REACT_APP_BLOCKLY_API=https://api.blockly.sensebox.de diff --git a/package-lock.json b/package-lock.json index 6a8dc6d..50dcf2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8720,6 +8720,11 @@ "minimist": "^1.2.5" } }, + "mnemonic-id": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/mnemonic-id/-/mnemonic-id-3.2.7.tgz", + "integrity": "sha512-kysx9gAGbvrzuFYxKkcRjnsg/NK61ovJOV4F1cHTRl9T5leg+bo6WI0pWIvOFh1Z/yDL0cjA5R3EEGPPLDv/XA==" + }, "moment": { "version": "2.29.0", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz", @@ -11394,6 +11399,13 @@ "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } } }, "request-promise-core": { @@ -12125,6 +12137,13 @@ "requires": { "faye-websocket": "^0.10.0", "uuid": "^3.0.1" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } } }, "sockjs-client": { @@ -13269,9 +13288,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", + "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==" }, "v8-compile-cache": { "version": "2.1.1", @@ -13929,6 +13948,13 @@ "requires": { "ansi-colors": "^3.0.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } } }, "webpack-manifest-plugin": { diff --git a/package.json b/package.json index a7a911e..67df513 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@testing-library/user-event": "^7.2.1", "blockly": "^3.20200924.0", "file-saver": "^2.0.2", + "mnemonic-id": "^3.2.7", "moment": "^2.28.0", "prismjs": "^1.20.0", "react": "^16.13.1", @@ -23,7 +24,8 @@ "react-router-dom": "^5.2.0", "react-scripts": "3.4.1", "redux": "^4.0.5", - "redux-thunk": "^2.3.0" + "redux-thunk": "^2.3.0", + "uuid": "^8.3.1" }, "scripts": { "start": "react-scripts start", diff --git a/src/components/Blockly/BlocklyComponent.jsx b/src/components/Blockly/BlocklyComponent.jsx index b025821..9e68f5a 100644 --- a/src/components/Blockly/BlocklyComponent.jsx +++ b/src/components/Blockly/BlocklyComponent.jsx @@ -24,22 +24,20 @@ import React from 'react'; import Blockly from 'blockly/core'; -import locale from 'blockly/msg/en'; import 'blockly/blocks'; import Toolbox from './toolbox/Toolbox'; import { Card } from '@material-ui/core'; -Blockly.setLocale(locale); class BlocklyComponent extends React.Component { - + constructor(props) { super(props); this.blocklyDiv = React.createRef(); this.toolbox = React.createRef(); - this.state = {workspace: undefined}; + this.state = { workspace: undefined }; } componentDidMount() { @@ -51,7 +49,7 @@ class BlocklyComponent extends React.Component { ...rest }, ); - this.setState({workspace: this.primaryWorkspace}) + this.setState({ workspace: this.primaryWorkspace }) if (initialXml) { Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(initialXml), this.primaryWorkspace); @@ -68,7 +66,7 @@ class BlocklyComponent extends React.Component { render() { return - + ; } diff --git a/src/components/Blockly/BlocklyWindow.js b/src/components/Blockly/BlocklyWindow.js index d68e272..f3c680d 100644 --- a/src/components/Blockly/BlocklyWindow.js +++ b/src/components/Blockly/BlocklyWindow.js @@ -2,8 +2,8 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { onChangeWorkspace, clearStats } from '../../actions/workspaceActions'; -// import * as De from 'blockly/msg/de'; -import {De} from './msg/de'; +import { De } from './msg/de'; +import { En } from './msg/en'; import BlocklyComponent from './BlocklyComponent'; import BlocklySvg from './BlocklySvg'; import * as Blockly from 'blockly/core'; @@ -18,10 +18,26 @@ class BlocklyWindow extends Component { constructor(props) { super(props); this.simpleWorkspace = React.createRef(); - Blockly.setLocale(De); + var locale = window.localStorage.getItem('locale'); + this.state = { + renderer: window.localStorage.getItem('renderer'), + }; + if (locale === null) { + if (navigator.language === 'de-DE') { + locale = 'de'; + } else { + locale = 'en'; + } + } + if (locale === 'de') { + Blockly.setLocale(De); + } else if (locale === 'en') { + Blockly.setLocale(En); + } } componentDidMount() { + const workspace = Blockly.getMainWorkspace(); this.props.onChangeWorkspace({}); this.props.clearStats(); @@ -56,7 +72,7 @@ class BlocklyWindow extends Component { style={this.props.svg ? { height: 0 } : this.props.blocklyCSS} readOnly={this.props.readOnly !== undefined ? this.props.readOnly : false} trashcan={this.props.trashcan !== undefined ? this.props.trashcan : true} - renderer='geras' + renderer={this.state.renderer} zoom={{ // https://developers.google.com/blockly/guides/configure/web/zoom controls: this.props.zoomControls !== undefined ? this.props.zoomControls : true, wheel: false, diff --git a/src/components/Blockly/blocks/index.js b/src/components/Blockly/blocks/index.js index 5ba7a02..7eeae60 100644 --- a/src/components/Blockly/blocks/index.js +++ b/src/components/Blockly/blocks/index.js @@ -17,5 +17,6 @@ import './map'; import './procedures'; import './time'; import './variables'; +import './lists'; import '../helpers/types' \ No newline at end of file diff --git a/src/components/Blockly/blocks/lists.js b/src/components/Blockly/blocks/lists.js new file mode 100644 index 0000000..2d33472 --- /dev/null +++ b/src/components/Blockly/blocks/lists.js @@ -0,0 +1,60 @@ +import Blockly, { FieldDropdown } from 'blockly/core'; +import { selectedBoard } from '../helpers/board' +import * as Types from '../helpers/types' +import { getColour } from '../helpers/colour'; + +Blockly.Blocks['lists_create_empty'] = { + /** + * Elapsed time in milliseconds block definition + * @this Blockly.Block + */ + init: function () { + this.setHelpUrl('http://arduino.cc/en/Reference/Millis'); + this.setColour(getColour().arrays); + this.appendDummyInput() + .appendField("create List with") + this.appendValueInput('NUMBER'); + this.appendDummyInput() + .appendField("Items of Type") + .appendField(new FieldDropdown(Types.VARIABLE_TYPES), 'type'); + this.setOutput(true, Types.ARRAY.typeId); + this.setTooltip(Blockly.Msg.ARD_TIME_MILLIS_TIP); + }, +}; + + +Blockly.Blocks['array_getIndex'] = { + /** + * Elapsed time in milliseconds block definition + * @this Blockly.Block + */ + init: function () { + this.setHelpUrl('http://arduino.cc/en/Reference/Millis'); + this.setColour(getColour().arrays); + this.appendDummyInput() + .appendField(new Blockly.FieldVariable( + 'X', + null, + ['Array'], + 'Array' + ), 'FIELDNAME'); + this.setOutput(true, Types.ARRAY.typeId); + this.setTooltip(Blockly.Msg.ARD_TIME_MILLIS_TIP); + }, +}; + +Blockly.Blocks['lists_length'] = { + /** + * Elapsed time in milliseconds block definition + * @this Blockly.Block + */ + init: function () { + this.setHelpUrl('http://arduino.cc/en/Reference/Millis'); + this.setColour(getColour().arrays); + this.appendValueInput('ARRAY') + .appendField('length of') + .setCheck(Types.ARRAY.compatibleTypes); + this.setOutput(true, Types.NUMBER.typeName); + this.setTooltip(Blockly.Msg.ARD_TIME_MILLIS_TIP); + }, +}; \ No newline at end of file diff --git a/src/components/Blockly/blocks/sensebox-display.js b/src/components/Blockly/blocks/sensebox-display.js index d9824d9..8092bff 100644 --- a/src/components/Blockly/blocks/sensebox-display.js +++ b/src/components/Blockly/blocks/sensebox-display.js @@ -81,6 +81,54 @@ Blockly.Blocks['sensebox_display_printDisplay'] = { LOOP_TYPES: ['sensebox_display_show'], }; +Blockly.Blocks['sensebox_display_fastPrint'] = { + init: function (block) { + this.setColour(getColour().sensebox); + this.appendDummyInput() + .appendField(Blockly.Msg.senseBox_display_fastPrint_show); + this.appendValueInput("Title1", 'Title1') + .appendField(Blockly.Msg.senseBox_display_fastPrint_title); + this.appendValueInput("Value1", 'Value1') + .appendField(Blockly.Msg.senseBox_display_fastPrint_value); + this.appendValueInput("Dimension1", 'Dimension1') + .appendField(Blockly.Msg.senseBox_display_fastPrint_dimension); + this.appendValueInput("Title2", 'Title2') + .appendField(Blockly.Msg.senseBox_display_fastPrint_title); + this.appendValueInput("Value2", 'Value2') + .appendField(Blockly.Msg.senseBox_display_fastPrint_value); + this.appendValueInput("Dimension2", 'Dimension2') + .appendField(Blockly.Msg.senseBox_display_fastPrint_dimension); + this.setPreviousStatement(true, null); + this.setNextStatement(true, null); + this.setTooltip(Blockly.Msg.sensebox_display_fastPrint_tip); + this.setHelpUrl('https://sensebox.de/books'); + }, + /** + * Called whenever anything on the workspace changes. + * Add warning if block is not nested inside a the correct loop. + * @param {!Blockly.Events.Abstract} e Change event. + * @this Blockly.Block + */ + onchange: function (e) { + var legal = false; + // Is the block nested in a loop? + var block = this; + do { + if (this.LOOP_TYPES.indexOf(block.type) != -1) { + legal = true; + break; + } + block = block.getSurroundParent(); + } while (block); + if (legal) { + this.setWarningText(null); + } else { + this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING); + } + }, + LOOP_TYPES: ['sensebox_display_show'], +}; + Blockly.Blocks['sensebox_display_plotDisplay'] = { init: function () { diff --git a/src/components/Blockly/blocks/sensebox-led.js b/src/components/Blockly/blocks/sensebox-led.js index 6038d34..0041dbc 100644 --- a/src/components/Blockly/blocks/sensebox-led.js +++ b/src/components/Blockly/blocks/sensebox-led.js @@ -41,4 +41,33 @@ Blockly.Blocks['sensebox_rgb_led'] = { this.setTooltip(Blockly.Msg.senseBox_rgb_led_tip); this.setHelpUrl('https://sensebox.de/books'); } +}; + + +Blockly.Blocks['sensebox_ws2818_led'] = { + init: function () { + + var dropdownOptions = [[Blockly.Msg.senseBox_ultrasonic_port_A, '1'], + [Blockly.Msg.senseBox_ultrasonic_port_B, '3'], [Blockly.Msg.senseBox_ultrasonic_port_C, '5']]; + + this.setColour(getColour().sensebox); + this.appendDummyInput() + .appendField(Blockly.Msg.senseBox_ws2818_rgb_led) + .appendField("Pin:") + .appendField(new Blockly.FieldDropdown(dropdownOptions), "Port") + this.appendValueInput("BRIGHTNESS", "brightness") + .appendField((Blockly.Msg.senseBox_ws2818_rgb_led_brightness)); + this.appendValueInput("POSITION", "position") + .appendField((Blockly.Msg.senseBox_ws2818_rgb_led_position)); + this.appendValueInput("RED", 'Number') + .appendField(Blockly.Msg.COLOUR_RGB_RED);//Blockly.Msg.senseBox_basic_red + this.appendValueInput("GREEN", 'Number') + .appendField(Blockly.Msg.COLOUR_RGB_GREEN);//Blockly.Msg.senseBox_basic_green + this.appendValueInput("BLUE", 'Number') + .appendField(Blockly.Msg.COLOUR_RGB_BLUE); + this.setPreviousStatement(true, null); + this.setNextStatement(true, null); + this.setTooltip(Blockly.Msg.senseBox_rgb_led_tip); + this.setHelpUrl('https://sensebox.de/books'); + } }; \ No newline at end of file diff --git a/src/components/Blockly/blocks/sensebox-osem.js b/src/components/Blockly/blocks/sensebox-osem.js index f6b8b66..0bad7b4 100644 --- a/src/components/Blockly/blocks/sensebox-osem.js +++ b/src/components/Blockly/blocks/sensebox-osem.js @@ -1,6 +1,7 @@ import * as Blockly from 'blockly/core'; import { getColour } from '../helpers/colour'; +var apiData = '[{"_id":"5e6073fe57703e001bb99453","createdAt":"2020-03-05T03:37:34.151Z","updatedAt":"2020-10-17T10:49:51.636Z","name":"Vtuzgorodok","currentLocation":{"timestamp":"2020-03-05T03:37:34.146Z","coordinates":[60.658676,56.833041,51],"type":"Point"},"exposure":"outdoor","sensors":[{"title":"PM10","unit":"µg/m³","sensorType":"SDS 011","icon":"osem-cloud","_id":"5e6073fe57703e001bb99458","lastMeasurement":{"value":"3.30","createdAt":"2020-10-17T10:49:51.627Z"}},{"title":"PM2.5","unit":"µg/m³","sensorType":"SDS 011","icon":"osem-cloud","_id":"5e6073fe57703e001bb99457","lastMeasurement":{"value":"0.90","createdAt":"2020-10-17T10:49:51.627Z"}},{"title":"Temperatur","unit":"°C","sensorType":"BME280","icon":"osem-thermometer","_id":"5e6073fe57703e001bb99456","lastMeasurement":{"value":"6.58","createdAt":"2020-10-17T10:49:51.627Z"}},{"title":"rel. Luftfeuchte","unit":"%","sensorType":"BME280","icon":"osem-humidity","_id":"5e6073fe57703e001bb99455","lastMeasurement":{"value":"53.76","createdAt":"2020-10-17T10:49:51.627Z"}},{"title":"Luftdruck","unit":"Pa","sensorType":"BME280","icon":"osem-barometer","_id":"5e6073fe57703e001bb99454","lastMeasurement":{"value":"96937.66","createdAt":"2020-10-17T10:49:51.627Z"}}],"model":"luftdaten_sds011_bme280","lastMeasurementAt":"2020-10-17T10:49:51.627Z","loc":[{"geometry":{"timestamp":"2020-03-05T03:37:34.146Z","coordinates":[60.658676,56.833041,51],"type":"Point"},"type":"Feature"}]}]'; Blockly.Blocks['sensebox_osem_connection'] = { init: function () { @@ -20,6 +21,10 @@ Blockly.Blocks['sensebox_osem_connection'] = { .setAlign(Blockly.ALIGN_LEFT) .appendField("senseBox ID") .appendField(new Blockly.FieldTextInput("senseBox ID"), "BoxID"); + this.appendDummyInput() + .setAlign(Blockly.ALIGN_LEFT) + .appendField(Blockly.Msg.senseBox_osem_access_token) + .appendField(new Blockly.FieldTextInput("access_token"), "access_token"); this.appendStatementInput('DO') .appendField(Blockly.Msg.senseBox_sensor) .setCheck(null); @@ -27,9 +32,14 @@ Blockly.Blocks['sensebox_osem_connection'] = { this.setNextStatement(true, null); }, onchange: function (e) { - - //Blockly.Blocks.sensebox.getDescendants = blocks; - + let boxID = this.getFieldValue('BoxID'); + if (boxID !== 'senseBox ID') { + fetch('https://api.opensensemap.org/boxes/ ' + boxID) + .then(res => res.json()) + .then((data) => { + apiData = data; + }) + } }, mutationToDom: function () { var container = document.createElement('mutation'); @@ -73,25 +83,47 @@ Blockly.Blocks['sensebox_osem_connection'] = { }; Blockly.Blocks['sensebox_send_to_osem'] = { init: function () { + this.setTooltip(Blockly.Msg.senseBox_send_to_osem_tip); this.setHelpUrl(''); this.setColour(getColour().sensebox); this.appendDummyInput() .appendField(Blockly.Msg.senseBox_send_to_osem); this.appendValueInput('Value') - .setCheck(null) - .appendField('Sensor ID') - .appendField(new Blockly.FieldTextInput('Sensor ID'), 'SensorID'); + .appendField('Phänomen') + .appendField(new Blockly.FieldDropdown( + this.generateOptions), 'SensorID'); this.setPreviousStatement(true, null); this.setNextStatement(true, null); }, + + generateOptions: function () { + var options = [['', '']]; + if (apiData.sensors != undefined) { + for (var i = 0; i < apiData.sensors.length; i++) { + options.push([apiData.sensors[i].title, apiData.sensors[i]._id]); + } + console.log(options); + + } + if (options.length > 1) { + + var dropdown = options.slice(1) + console.log(dropdown); + return dropdown; + } else + return options; + + + }, /** * Called whenever anything on the workspace changes. * Add warning if block is not nested inside a the correct loop. * @param {!Blockly.Events.Abstract} e Change event. * @this Blockly.Block */ - onchange: function (e) { + onchange: function () { + var legal = false; // Is the block nested in a loop? var block = this; @@ -108,5 +140,10 @@ Blockly.Blocks['sensebox_send_to_osem'] = { this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING); } }, - LOOP_TYPES: ['sensebox_osem_connection'], + /** + * List of block types that are loops and thus do not need warnings. + * To add a new loop type add this to your code: + * Blockly.Blocks['controls_flow_statements'].LOOP_TYPES.push('custom_loop'); + */ + LOOP_TYPES: ['sensebox_osem_connection'] }; \ No newline at end of file diff --git a/src/components/Blockly/generator/index.js b/src/components/Blockly/generator/index.js index fd2c108..afe28a7 100644 --- a/src/components/Blockly/generator/index.js +++ b/src/components/Blockly/generator/index.js @@ -17,5 +17,6 @@ import './audio'; import './procedures'; import './time'; import './variables'; +import './lists'; diff --git a/src/components/Blockly/generator/lists.js b/src/components/Blockly/generator/lists.js new file mode 100644 index 0000000..7902920 --- /dev/null +++ b/src/components/Blockly/generator/lists.js @@ -0,0 +1,19 @@ +import * as Blockly from 'blockly/core'; + + +Blockly.Arduino['lists_create_empty'] = function () { + var code = ''; + return [code, Blockly.Arduino.ORDER_ATOMIC]; +} + +Blockly.Arduino['array_getIndex'] = function () { + var code = ''; + return [code, Blockly.Arduino.ORDER_ATOMIC]; +} + + +Blockly.Arduino['lists_length'] = function () { + var array = Blockly.Arduino.valueToCode(this, 'ARRAY', Blockly.Arduino.ORDER_ATOMIC); + var code = `${array}.length`; + return [code, Blockly.Arduino.ORDER_ATOMIC]; +} \ No newline at end of file diff --git a/src/components/Blockly/generator/sensebox-display.js b/src/components/Blockly/generator/sensebox-display.js index 17f8542..5fbc114 100644 --- a/src/components/Blockly/generator/sensebox-display.js +++ b/src/components/Blockly/generator/sensebox-display.js @@ -31,6 +31,42 @@ Blockly.Arduino.sensebox_display_printDisplay = function () { return code; }; + +Blockly.Arduino.sensebox_display_fastPrint = function () { + var title1 = Blockly.Arduino.valueToCode(this, 'Title1', Blockly.Arduino.ORDER_ATOMIC) || '0' + var value1 = Blockly.Arduino.valueToCode(this, 'Value1', Blockly.Arduino.ORDER_ATOMIC); + var dimension1 = Blockly.Arduino.valueToCode(this, 'Dimension1', Blockly.Arduino.ORDER_ATOMIC) || '0' + var title2 = Blockly.Arduino.valueToCode(this, 'Title2', Blockly.Arduino.ORDER_ATOMIC) || '0' + var value2 = Blockly.Arduino.valueToCode(this, 'Value2', Blockly.Arduino.ORDER_ATOMIC); + var dimension2 = Blockly.Arduino.valueToCode(this, 'Dimension2', Blockly.Arduino.ORDER_ATOMIC) || '0' + Blockly.Arduino.codeFunctions_['sensebox_fastPrint'] = ` + void printOnDisplay(String title1, String measurement1, String unit1, String title2, String measurement2, String unit2) { + + display.setCursor(0, 0); + display.setTextSize(1); + display.setTextColor(WHITE, BLACK); + display.println(title1); + display.setCursor(0, 10); + display.setTextSize(2); + display.print(measurement1); + display.print(" "); + display.setTextSize(1); + display.println(unit1); + display.setCursor(0, 30); + display.setTextSize(1); + display.println(title2); + display.setCursor(0, 40); + display.setTextSize(2); + display.print(measurement2); + display.print(" "); + display.setTextSize(1); + display.println(unit2); + } + ` + var code = ` printOnDisplay(${title1}, String(${value1}), ${dimension1}, ${title2}, String(${value2}), ${dimension2});\n`; + return code; +}; + Blockly.Arduino.sensebox_display_show = function (block) { var show = Blockly.Arduino.statementToCode(block, 'SHOW'); var code = ''; diff --git a/src/components/Blockly/generator/sensebox-led.js b/src/components/Blockly/generator/sensebox-led.js index eea4c9f..f3e36d5 100644 --- a/src/components/Blockly/generator/sensebox-led.js +++ b/src/components/Blockly/generator/sensebox-led.js @@ -19,4 +19,28 @@ Blockly.Arduino.sensebox_rgb_led = function () { var code = 'rgb_led_' + dropdown_pin + '.setPixelColor(0,rgb_led_' + dropdown_pin + '.Color(' + red + ',' + green + ',' + blue + '));\n'; code += 'rgb_led_' + dropdown_pin + '.show();'; return code; +}; + + +Blockly.Arduino.sensebox_ws2818_led = function () { + var dropdown_pin = this.getFieldValue('Port'); + var blocks = Blockly.mainWorkspace.getAllBlocks(); + var count = 0; + for (var i = 0; i < blocks.length; i++) { + if (blocks[i].type === 'sensebox_ws2818_led' && blocks[i].getFieldValue('Port') === dropdown_pin) { + count++; + + } + } + var numPixel = count; + var brightness = Blockly.Arduino.valueToCode(this, 'BRIGHTNESS', Blockly.Arduino.ORDER_ATOMIC) || '50' + var position = Blockly.Arduino.valueToCode(this, 'POSITION', Blockly.Arduino.ORDER_ATOMIC) || '0'; + var red = Blockly.Arduino.valueToCode(this, 'RED', Blockly.Arduino.ORDER_ATOMIC) || '0' + var green = Blockly.Arduino.valueToCode(this, 'GREEN', Blockly.Arduino.ORDER_ATOMIC) || '0' + var blue = Blockly.Arduino.valueToCode(this, 'BLUE', Blockly.Arduino.ORDER_ATOMIC) || '0' + Blockly.Arduino.definitions_['define_rgb_led' + dropdown_pin] = `#include \n Adafruit_NeoPixel rgb_led_${dropdown_pin}= Adafruit_NeoPixel(${numPixel}, ${dropdown_pin},NEO_GRB + NEO_KHZ800);\n`; + Blockly.Arduino.setupCode_['setup_rgb_led' + dropdown_pin] = 'rgb_led_' + dropdown_pin + '.begin();\n'; + Blockly.Arduino.setupCode_['setup_rgb_led_brightness' + dropdown_pin] = `rgb_led_${dropdown_pin}.setBrightness(${brightness});\n`; + var code = `rgb_led_${dropdown_pin}.setPixelColor(${position},rgb_led_${dropdown_pin}.Color(${red},${green},${blue}));\nrgb_led_${dropdown_pin}.show();\n`; + return code; }; \ No newline at end of file diff --git a/src/components/Blockly/generator/sensebox-osem.js b/src/components/Blockly/generator/sensebox-osem.js index d4058ce..410dc7b 100644 --- a/src/components/Blockly/generator/sensebox-osem.js +++ b/src/components/Blockly/generator/sensebox-osem.js @@ -18,17 +18,20 @@ Blockly.Arduino.sensebox_osem_connection = function (Block) { var box_id = this.getFieldValue('BoxID'); var host = this.getFieldValue('host'); var branch = Blockly.Arduino.statementToCode(Block, 'DO'); - //var blocks = Blockly.Block.getDescendants; + var access_token = this.getFieldValue('access_token'); + var blocks = this.getDescendants(); var type = this.getFieldValue('type'); var ssl = this.getFieldValue('SSL'); var port = 0; var count = 0; - // for (var i = 0; i < blocks.length; i++) { - // if (blocks[i].type === 'sensebox_send_to_osem') { - // count++; + if (blocks != undefined) { + for (var i = 0; i < blocks.length; i++) { + if (blocks[i].type === 'sensebox_send_to_osem') { + count++; - // } - // } + } + } + } var num_sensors = count; Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"'; Blockly.Arduino.definitions_['num_sensors'] = 'static const uint8_t NUM_SENSORS = ' + num_sensors + ';' @@ -84,7 +87,7 @@ Blockly.Arduino.sensebox_osem_connection = function (Block) { if (connected == true) { // construct the HTTP POST request: sprintf_P(buffer, - PSTR("POST /boxes/%s/data HTTP/1.1\\nHost: %s\\nContent-Type: " + PSTR("POST /boxes/%s/data HTTP/1.1\\nAuthorization: ${access_token}\\nHost: %s\\nContent-Type: " "text/csv\\nConnection: close\\nContent-Length: %i\\n\\n"), SENSEBOX_ID, server, num_measurements * lengthMultiplikator); // send the HTTP POST request: @@ -144,7 +147,7 @@ Blockly.Arduino.sensebox_osem_connection = function (Block) { if (connected == true) { // construct the HTTP POST request: sprintf_P(buffer, - PSTR("POST /boxes/%s/data HTTP/1.1\\nHost: %s\\nContent-Type: " + PSTR("POST /boxes/%s/data HTTP/1.1\\nAuthorization: ${access_token}\\nHost: %s\\nContent-Type: " "text/csv\\nConnection: close\\nContent-Length: %i\\n\\n"), SENSEBOX_ID, server, num_measurements * lengthMultiplikator); // send the HTTP POST request: diff --git a/src/components/Blockly/generator/variables.js b/src/components/Blockly/generator/variables.js index c0733d5..8ef80ae 100644 --- a/src/components/Blockly/generator/variables.js +++ b/src/components/Blockly/generator/variables.js @@ -14,9 +14,28 @@ const setVariableFunction = function (defaultValue) { const allVars = Blockly.getMainWorkspace().getVariableMap().getAllVariables(); const myVar = allVars.filter(v => v.name === variableName)[0] + var code = '' - Blockly.Arduino.variables_[myVar + myVar.type] = myVar.type + " " + myVar.name + ';\n'; - return variableName + ' = ' + (variableValue || defaultValue) + ';\n'; + switch (myVar.type) { + default: + Blockly.Arduino.variables_[myVar + myVar.type] = myVar.type + " " + myVar.name + ';\n'; + code = variableName + ' = ' + (variableValue || defaultValue) + ';\n'; + break; + case 'Array': + var arrayType; + var number; + + if (this.getChildren().length > 0) { + if (this.getChildren()[0].type === 'lists_create_empty') { + + arrayType = this.getChildren()[0].getFieldValue('type'); + number = Blockly.Arduino.valueToCode(this.getChildren()[0], 'NUMBER', Blockly['Arduino'].ORDER_ATOMIC); + Blockly.Arduino.variables_[myVar + myVar.type] = `${arrayType} ${myVar.name} [${number}];\n`; + } + } + break; + } + return code; }; }; @@ -25,8 +44,8 @@ const getVariableFunction = function (block) { block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE ); - - return [variableName, Blockly['Arduino'].ORDER_ATOMIC]; + var code = variableName; + return [code, Blockly['Arduino'].ORDER_ATOMIC]; }; Blockly['Arduino']['variables_set_dynamic'] = setVariableFunction() diff --git a/src/components/Blockly/helpers/colour.js b/src/components/Blockly/helpers/colour.js index 7aea8df..e807695 100644 --- a/src/components/Blockly/helpers/colour.js +++ b/src/components/Blockly/helpers/colour.js @@ -10,6 +10,7 @@ const colours = { text: 160, variables: 330, audio: 250, + arrays: 33 } diff --git a/src/components/Blockly/helpers/types.js b/src/components/Blockly/helpers/types.js index 9abdd85..f7cacc7 100644 --- a/src/components/Blockly/helpers/types.js +++ b/src/components/Blockly/helpers/types.js @@ -60,7 +60,7 @@ export const DECIMAL = { /** Array/List of items. */ export const ARRAY = { typeId: 'Array', - typeName: 'array', + typeName: 'Array', typeMsgName: 'ARD_TYPE_ARRAY', compatibleTypes: [] } @@ -87,6 +87,7 @@ export const CHILD_BLOCK_MISSING = { } const compatibleTypes = { + Array: ['Array'], boolean: ['boolean'], int: ['int'], char: ['char'], diff --git a/src/components/Blockly/msg/de.js b/src/components/Blockly/msg/de.js index 202084e..bc722be 100644 --- a/src/components/Blockly/msg/de.js +++ b/src/components/Blockly/msg/de.js @@ -1,7 +1,3 @@ -// import * as Blockly from 'blockly/core'; - -// https://developers.google.com/blockly/guides/configure/web/translations - const Blockly = {}; Blockly.Msg = {}; @@ -610,6 +606,7 @@ Blockly.Msg.senseBox_osem_connection = "Verbinde mit openSenseMap"; Blockly.Msg.senseBox_osem_exposure = "Typ"; Blockly.Msg.senseBox_osem_stationary = "Stationär"; Blockly.Msg.senseBox_osem_mobile = "Mobil"; +Blockly.Msg.senseBox_osem_access_token = "API Schlüssel"; Blockly.Msg.senseBox_sds011 = "Feinstaubsensor"; Blockly.Msg.senseBox_sds011_dimension = "in µg/m³ an"; Blockly.Msg.senseBox_sds011_pm25 = "PM2.5"; @@ -650,7 +647,11 @@ Blockly.Msg.sensebox_display_fillCircle_radius = "Radius"; Blockly.Msg.sensebox_display_drawRectangle = "Zeichne Rechteck"; Blockly.Msg.sensebox_display_drawRectangle_width = "Breite"; Blockly.Msg.sensebox_display_drawRectangle_height = "Höhe"; -Blockly.Msg.senseBox_display_filled = "Ausgefüllt" +Blockly.Msg.senseBox_display_filled = "Ausgefüllt"; +Blockly.Msg.senseBox_display_fastPrint_show = "Zeige Messwerte"; +Blockly.Msg.senseBox_display_fastPrint_title = "Titel"; +Blockly.Msg.senseBox_display_fastPrint_value = "Messwert"; +Blockly.Msg.senseBox_display_fastPrint_dimension = "Einheit"; // GPS Blockly.Msg.senseBox_gps_getValues = "GPS Modul"; Blockly.Msg.senseBox_gps_getValues_tip = "ruft das GPS Signal ab"; @@ -771,7 +772,11 @@ Blockly.Msg.senseBox_telegram_do = "Telegram mache" Blockly.Msg.senseBox_telegram_do_on_message = "bei Nachricht" Blockly.Msg.senseBox_telegram_message = "Nachricht" Blockly.Msg.senseBox_telegram_send = "Sende Nachricht" - +//SCD30 CO2 Sensor Blockly.Msg.senseBox_scd30 = "CO2 Sensor (Sensirion SCD30)"; +//WS2818 RGB LED +Blockly.Msg.senseBox_ws2818_rgb_led = "senseBox WS2812 - RGB LED"; +Blockly.Msg.senseBox_ws2818_rgb_led_position = "Position"; +Blockly.Msg.senseBox_ws2818_rgb_led_brightness = "Helligkeit"; export const De = Blockly.Msg; diff --git a/src/components/Blockly/msg/en.js b/src/components/Blockly/msg/en.js index 856ef7c..3b66e33 100644 --- a/src/components/Blockly/msg/en.js +++ b/src/components/Blockly/msg/en.js @@ -1,7 +1,3 @@ -// import * as Blockly from 'blockly/core'; - -// https://developers.google.com/blockly/guides/configure/web/translations - const Blockly = {}; Blockly.Msg = {}; @@ -613,6 +609,11 @@ Blockly.Msg.senseBox_display_printDisplay_y = "y-coordinates"; Blockly.Msg.senseBox_display_setSize = "set font size to"; Blockly.Msg.senseBox_display_setSize_tip = "Change the font size. Set a Value between 1-10."; Blockly.Msg.senseBox_display_white = "White"; +Blockly.Msg.senseBox_display_fastPrint_dimension = "Unit"; +Blockly.Msg.senseBox_display_fastPrint_show = "Show Measurements"; +Blockly.Msg.senseBox_display_fastPrint_tip = "Show two measurements with title and dimension on the display"; +Blockly.Msg.senseBox_display_fastPrint_title = "Title"; +Blockly.Msg.senseBox_display_fastPrint_value = "Measurement"; Blockly.Msg.senseBox_foto = "Light Dependent Resistor"; Blockly.Msg.senseBox_foto_tip = "simple light depending resistor, gives values between 0 and 1023"; Blockly.Msg.senseBox_gas = "Gas (VOC)"; @@ -676,6 +677,7 @@ Blockly.Msg.senseBox_osem_host = "opensensemap.org"; Blockly.Msg.senseBox_osem_host_workshop = "workshop.opensensemap.org"; Blockly.Msg.senseBox_osem_mobile = "Mobile"; Blockly.Msg.senseBox_osem_stationary = "Stationary"; +Blockly.Msg.senseBox_osem_access_token = "API Key"; Blockly.Msg.senseBox_output_filename = "filename"; Blockly.Msg.senseBox_output_format = "format:"; Blockly.Msg.senseBox_output_linebreak = "linebreak"; @@ -753,7 +755,13 @@ Blockly.Msg.sensebox_display_show_tip = "Print on Display"; Blockly.Msg.sensebox_sd_filename = "data"; Blockly.Msg.sensebox_soil_smt50 = "Soil Moisture and Temperature (SMT50)"; Blockly.Msg.sensebox_web_readHTML_filename = "File:"; - +//SCD30 CO2 Sensor Blockly.Msg.senseBox_scd30 = "CO2 Sensor (Sensirion SCD30)"; +//WS2818 RGB LED +Blockly.Msg.senseBox_ws2818_rgb_led = "senseBox WS2812 - RGB LED"; +Blockly.Msg.senseBox_ws2818_rgb_led_brightness = "Helligkeit"; +Blockly.Msg.senseBox_ws2818_rgb_led_position = "Position"; + + export const En = Blockly.Msg; diff --git a/src/components/Blockly/toolbox/Toolbox.js b/src/components/Blockly/toolbox/Toolbox.js index ec5711e..95d2322 100644 --- a/src/components/Blockly/toolbox/Toolbox.js +++ b/src/components/Blockly/toolbox/Toolbox.js @@ -2,7 +2,6 @@ import React from 'react'; import { Block, Value, Field, Shadow, Category } from '../'; import { getColour } from '../helpers/colour' import '@blockly/block-plus-minus'; - import { TypedVariableModal } from '@blockly/plugin-typed-variable-modal'; import * as Blockly from 'blockly/core'; @@ -14,12 +13,14 @@ class Toolbox extends React.Component { componentDidUpdate() { this.props.workspace.registerToolboxCategoryCallback('CREATE_TYPED_VARIABLE', this.createFlyout); - const typedVarModal = new TypedVariableModal(this.props.workspace, 'callbackName', [['SHORT_NUMBER', 'char'], ['NUMBER', 'int'], ['DECIMAL', 'float'], ['TEXT', 'String'], ['CHARACTER', 'char'], ['BOOLEAN', 'boolean'], ['NULL', 'void'], ['UNDEF', 'undefined']]); + const typedVarModal = new TypedVariableModal(this.props.workspace, 'callbackName', [['SHORT_NUMBER', 'char'], ['NUMBER', 'int'], ['DECIMAL', 'float'], ['TEXT', 'String'], ['ARRAY', 'Array'], ['CHARACTER', 'char'], ['BOOLEAN', 'boolean'], ['NULL', 'void'], ['UNDEF', 'undefined']]); typedVarModal.init(); } createFlyout(workspace) { + let xmlList = []; + // Add your button and give it a callback name. const button = document.createElement('button'); button.setAttribute('text', 'Create Typed Variable'); @@ -61,6 +62,33 @@ class Toolbox extends React.Component { + + + + 0 + + + + + 30 + + + + + 0 + + + + + 0 + + + + + 0 + + + @@ -83,6 +111,28 @@ class Toolbox extends React.Component { + + + + Title + + + + + Unit + + + + + Title + + + + + Unit + + + @@ -323,7 +373,12 @@ class Toolbox extends React.Component { - ; + + + + + + diff --git a/src/components/Gallery/GalleryHome.js b/src/components/Gallery/GalleryHome.js new file mode 100644 index 0000000..6b55c1a --- /dev/null +++ b/src/components/Gallery/GalleryHome.js @@ -0,0 +1,122 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; + +import clsx from 'clsx'; + +import Breadcrumbs from '../Breadcrumbs'; + +// import gallery from './gallery.json'; +// import tutorials from '../../data/tutorials.json'; + +import { Link } from 'react-router-dom'; + +import { fade } from '@material-ui/core/styles/colorManipulator'; +import { withStyles } from '@material-ui/core/styles'; +import Grid from '@material-ui/core/Grid'; +import Paper from '@material-ui/core/Paper'; +import BlocklyWindow from '../Blockly/BlocklyWindow'; +import Divider from '@material-ui/core/Divider'; + + +const styles = (theme) => ({ + outerDiv: { + position: 'absolute', + right: '-30px', + bottom: '-30px', + width: '160px', + height: '160px', + color: fade(theme.palette.secondary.main, 0.6) + }, + outerDivError: { + stroke: fade(theme.palette.error.dark, 0.6), + color: fade(theme.palette.error.dark, 0.6) + }, + outerDivSuccess: { + stroke: fade(theme.palette.primary.main, 0.6), + color: fade(theme.palette.primary.main, 0.6) + }, + outerDivOther: { + stroke: fade(theme.palette.secondary.main, 0.6) + }, + innerDiv: { + width: 'inherit', + height: 'inherit', + display: 'table-cell', + verticalAlign: 'middle', + textAlign: 'center' + } +}); + + + + +class GalleryHome extends Component { + + state = { + gallery: [] + } + + componentDidMount() { + console.log(process.env.REACT_APP_BLOCKLY_API) + fetch(process.env.REACT_APP_BLOCKLY_API + this.props.location.pathname) + .then(res => res.json()) + .then((data) => { + this.setState({ gallery: data }) + }) + } + + + render() { + return ( +
+ + +

Gallery

+ + {this.state.gallery.map((gallery, i) => { + return ( + + + +

{gallery.title}

+ + + + + + +

{gallery.text}

+ + +
+
+
+ +
+ ) + })} +
+
+ ); + }; +} + +GalleryHome.propTypes = { + status: PropTypes.array.isRequired, + change: PropTypes.number.isRequired, +}; + +const mapStateToProps = state => ({ + change: state.tutorial.change, + status: state.tutorial.status +}); + +export default connect(mapStateToProps, null)(withStyles(styles, { withTheme: true })(GalleryHome)); diff --git a/src/components/Gallery/gallery.json b/src/components/Gallery/gallery.json new file mode 100644 index 0000000..0ff72ae --- /dev/null +++ b/src/components/Gallery/gallery.json @@ -0,0 +1,37 @@ +[ + { + "id": 15212, + "title": "Das senseBox Buch Kapitel 1", + "name": "Mario", + "text": "Die Blöcke findest du in der Kategorie \"Schleifen\". Die einfachste Schleife, die du Verwenden kannst, ist der Block \"Wiederhole 10 mal\". Bei diesem Block kannst du die Blöcke, die eine bestimmte Zahl wiederholt werden soll einfach in den offenen Block abschnitt ziehen. ", + "xml": "\n \n \n \n 10\n \n \n \n" + }, + { + "id": 25451, + "title": "Das senseBox Buch Kapitel 2", + "name": "Mario", + "text": "", + "xml": "\n \n \n \n 1\n HIGH\n \n \n \n \n 1000\n \n \n \n \n 1\n LOW\n \n \n \n \n 1000\n \n \n \n \n \n \n \n \n \n \n \n" + }, + { + "id": 3541512, + "title": "Das senseBox Buch Kapitel 3", + "name": "Mario", + "text": "", + "xml": "\n \n \n \n \n \n \n \n \n WHITE,BLACK\n \n \n 1\n \n \n \n \n 0\n \n \n \n \n 0\n \n \n \n \n \n \n \n Helligkeit:\n \n \n \n \n Illuminance\n \n \n \n \n \n \n \n \n \n" + }, + { + "id": 7487454, + "title": "Das senseBox Buch Kapitel 4", + "name": "Mario", + "text": "", + "xml": "\n \n \n \n \n \n \n \n \n WHITE,BLACK\n \n \n 1\n \n \n \n \n 0\n \n \n \n \n 0\n \n \n \n \n \n \n \n Helligkeit:\n \n \n \n \n Illuminance\n \n \n \n \n \n \n \n \n \n" + }, + { + "id": 54541251, + "title": "Das senseBox Buch Kapitel 5", + "name": "Mario", + "text": "", + "xml": "" + } +] \ No newline at end of file diff --git a/src/components/Home.js b/src/components/Home.js index cb42f31..f54b129 100644 --- a/src/components/Home.js +++ b/src/components/Home.js @@ -10,6 +10,7 @@ import WorkspaceFunc from './WorkspaceFunc'; import BlocklyWindow from './Blockly/BlocklyWindow'; import CodeViewer from './CodeViewer'; import TrashcanButtons from './TrashcanButtons'; +import { createNameId } from 'mnemonic-id'; import HintTutorialExists from './Tutorial/HintTutorialExists'; import Grid from '@material-ui/core/Grid'; @@ -45,14 +46,29 @@ const styles = (theme) => ({ class Home extends Component { state = { - codeOn: false + codeOn: false, + gallery: [], + share: [], + projectToLoad: undefined } + componentDidMount() { + + this.props.workspaceName(createNameId()); + fetch(process.env.REACT_APP_BLOCKLY_API + this.props.location.pathname) + .then(res => res.json()) + .then((data) => { + this.setState({ projectToLoad: data }) + }) + } + + componentDidUpdate() { /* Resize and reposition all of the workspace chrome (toolbox, trash, scrollbars etc.) This should be called when something changes that requires recalculating dimensions and positions of the trash, zoom, toolbox, etc. (e.g. window resize). */ + const workspace = Blockly.getMainWorkspace(); Blockly.svgResize(workspace); } @@ -72,6 +88,13 @@ class Home extends Component { } render() { + // console.log(this.props.match.params.galleryId); + // console.log(gallery); + // console.log(gallery.filter(project => project.id == this.props.match.params.galleryId)); + if (this.state.projectToLoad) { + console.log(this.state.projectToLoad.xml) + } + console.log(this.props); return (
@@ -88,7 +111,10 @@ class Home extends Component { - + {this.state.projectToLoad ? + < BlocklyWindow blocklyCSS={{ height: '80vH' }} initialXml={this.state.projectToLoad.xml} /> : < BlocklyWindow blocklyCSS={{ height: '80vH' }} /> + } + {this.state.codeOn ? diff --git a/src/components/Navbar.js b/src/components/Navbar.js index 023981a..a70d9a4 100644 --- a/src/components/Navbar.js +++ b/src/components/Navbar.js @@ -45,32 +45,32 @@ class Navbar extends Component { this.setState({ open: !this.state.open }); } - render(){ + render() { return (
- + - + senseBox Blockly - - senseBox-Logo + + senseBox-Logo {/^\/tutorial(\/.*$|$)/g.test(this.props.location.pathname) ? - + Tutorial @@ -82,34 +82,34 @@ class Navbar extends Component { anchor="left" onClose={this.toggleDrawer} open={this.state.open} - classes={{paper: this.props.classes.drawerWidth}} - ModalProps={{keepMounted: true}} // Better open performance on mobile. + classes={{ paper: this.props.classes.drawerWidth }} + ModalProps={{ keepMounted: true }} // Better open performance on mobile. > -
-
- +
+
+ Menü -
+
- {[{text: 'Tutorials', icon: faChalkboardTeacher, link: "/tutorial"}, {text: 'Tutorial-Builder', icon: faFolderPlus, link: "/tutorial/builder"}, {text: 'Einstellungen', icon: faCog, link: "/settings"}].map((item, index) => ( - + {[{ text: 'Tutorials', icon: faChalkboardTeacher, link: "/tutorial" }, { text: 'Tutorial-Builder', icon: faFolderPlus, link: "/tutorial/builder" }, { text: 'Gallery', icon: faFolderPlus, link: "/gallery" }, { text: 'Einstellungen', icon: faCog, link: "/settings" }].map((item, index) => ( + - + ))} - + - {[{text: 'Über uns', icon: faBuilding},{text: 'Kontakt', icon: faEnvelope}, {text: 'Impressum', icon: faIdCard}].map((item, index) => ( + {[{ text: 'Über uns', icon: faBuilding }, { text: 'Kontakt', icon: faEnvelope }, { text: 'Impressum', icon: faIdCard }].map((item, index) => ( - + ))} @@ -120,4 +120,4 @@ class Navbar extends Component { } } -export default withStyles(styles, {withTheme: true})(withRouter(Navbar)); +export default withStyles(styles, { withTheme: true })(withRouter(Navbar)); diff --git a/src/components/Routes.js b/src/components/Routes.js index 4a7666e..35e868a 100644 --- a/src/components/Routes.js +++ b/src/components/Routes.js @@ -10,10 +10,13 @@ import Tutorial from './Tutorial/Tutorial'; import TutorialHome from './Tutorial/TutorialHome'; import Builder from './Tutorial/Builder/Builder'; import NotFound from './NotFound'; +import GalleryHome from './Gallery/GalleryHome'; +import Settings from './Settings/Settings'; + class Routes extends Component { - componentDidUpdate(){ + componentDidUpdate() { this.props.visitPage(); } @@ -23,7 +26,11 @@ class Routes extends Component { - + + + + + diff --git a/src/components/Settings/LanguageSelector.js b/src/components/Settings/LanguageSelector.js new file mode 100644 index 0000000..dea7465 --- /dev/null +++ b/src/components/Settings/LanguageSelector.js @@ -0,0 +1,43 @@ +import React from 'react'; +import { makeStyles } from '@material-ui/core/styles'; +import InputLabel from '@material-ui/core/InputLabel'; +import MenuItem from '@material-ui/core/MenuItem'; +import FormControl from '@material-ui/core/FormControl'; +import Select from '@material-ui/core/Select'; + +const useStyles = makeStyles((theme) => ({ + formControl: { + margin: theme.spacing(1), + minWidth: 120, + }, + selectEmpty: { + marginTop: theme.spacing(2), + }, +})); + +export default function LanguageSelector() { + const classes = useStyles(); + const [lang, setLang] = React.useState(window.localStorage.getItem('locale')); + + const handleChange = (event) => { + setLang(event.target.value); + window.localStorage.setItem('locale', event.target.value); + }; + + return ( +
+ + Sprache + + +
+ ); +} diff --git a/src/components/Settings/RenderSelector.js b/src/components/Settings/RenderSelector.js new file mode 100644 index 0000000..46ad84e --- /dev/null +++ b/src/components/Settings/RenderSelector.js @@ -0,0 +1,45 @@ +import React from 'react'; +import { makeStyles } from '@material-ui/core/styles'; +import InputLabel from '@material-ui/core/InputLabel'; +import MenuItem from '@material-ui/core/MenuItem'; +import FormControl from '@material-ui/core/FormControl'; +import Select from '@material-ui/core/Select'; + +const useStyles = makeStyles((theme) => ({ + formControl: { + margin: theme.spacing(1), + minWidth: 400, + }, + selectEmpty: { + marginTop: theme.spacing(2), + }, +})); + +export default function LanguageSelector() { + const classes = useStyles(); + const [renderer, setRenderer] = React.useState(window.localStorage.getItem('renderer')); + + const handleChange = (event) => { + setRenderer(event.target.value); + window.localStorage.setItem('renderer', event.target.value); + }; + + return ( +
+ + Renderer + + +

Der Renderer bestimmt das aussehen der Blöcke

+
+ ); +} diff --git a/src/components/Settings/Settings.js b/src/components/Settings/Settings.js new file mode 100644 index 0000000..95b33dc --- /dev/null +++ b/src/components/Settings/Settings.js @@ -0,0 +1,30 @@ +import React, { Component } from 'react'; +import { withRouter } from 'react-router-dom'; + +import Button from '@material-ui/core/Button'; +import Typography from '@material-ui/core/Typography'; +import LanguageSelector from './LanguageSelector'; +import RenderSelector from './RenderSelector'; + + +class Settings extends Component { + render() { + return ( +
+ Einstellungen + + + +
+ ); + }; +} + +export default withRouter(Settings); diff --git a/src/components/WorkspaceFunc.js b/src/components/WorkspaceFunc.js index 5d380d2..253f9b4 100644 --- a/src/components/WorkspaceFunc.js +++ b/src/components/WorkspaceFunc.js @@ -12,7 +12,6 @@ import { initialXml } from './Blockly/initialXml.js'; import Compile from './Compile'; import SolutionCheck from './Tutorial/SolutionCheck'; -import Dialog from './Dialog'; import Snackbar from './Snackbar'; import withWidth, { isWidthDown } from '@material-ui/core/withWidth'; @@ -22,8 +21,19 @@ import IconButton from '@material-ui/core/IconButton'; import Tooltip from '@material-ui/core/Tooltip'; import TextField from '@material-ui/core/TextField'; import Typography from '@material-ui/core/Typography'; +import { createId } from 'mnemonic-id'; -import { faPen, faSave, faUpload, faCamera, faShare } from "@fortawesome/free-solid-svg-icons"; + +import Dialog from './Dialog'; +// import Dialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogTitle from '@material-ui/core/DialogTitle'; + + + +import { faPen, faSave, faUpload, faCamera, faShare, faShareAlt } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; const styles = (theme) => ({ @@ -49,9 +59,10 @@ const styles = (theme) => ({ }); + class WorkspaceFunc extends Component { - constructor(props){ + constructor(props) { super(props); this.inputRef = React.createRef(); this.state = { @@ -60,21 +71,25 @@ class WorkspaceFunc extends Component { open: false, file: false, saveFile: false, + share: false, name: props.name, snackbar: false, key: '', - message: '' + message: '', + id: '' }; } - componentDidUpdate(props){ - if(props.name !== this.props.name){ - this.setState({name: this.props.name}); + + + componentDidUpdate(props) { + if (props.name !== this.props.name) { + this.setState({ name: this.props.name }); } } toggleDialog = () => { - this.setState({ open: !this.state }); + this.setState({ open: !this.state, share: false }); } saveXmlFile = () => { @@ -87,6 +102,41 @@ class WorkspaceFunc extends Component { saveAs(blob, fileName); } + shareBlocks = () => { + let code = this.props.xml; + let requestOptions = ''; + let id = ''; + if (this.state.id !== '') { + requestOptions = { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + id: this.state.id, + name: this.state.name, + xml: code + }) + }; + fetch(process.env.REACT_APP_BLOCKLY_API + '/share' + this.state.id, requestOptions) + .then(response => response.json()) + .then(data => this.setState({ share: true })); + } + else { + id = createId(10); + requestOptions = { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + id: id, + name: this.state.name, + xml: code + }) + }; + fetch(process.env.REACT_APP_BLOCKLY_API + '/share', requestOptions) + .then(response => response.json()) + .then(data => this.setState({ id: data.id, share: true })); + } + } + getSvg = () => { const workspace = Blockly.getMainWorkspace(); var canvas = workspace.svgBlockCanvas_.cloneNode(true); @@ -98,7 +148,7 @@ class WorkspaceFunc extends Component { // var cssContent = Blockly.Css.CONTENT.join(''); var cssContent = ''; for (var i = 0; i < document.getElementsByTagName('style').length; i++) { - if(/^blockly.*$/.test(document.getElementsByTagName('style')[i].id)){ + if (/^blockly.*$/.test(document.getElementsByTagName('style')[i].id)) { cssContent += document.getElementsByTagName('style')[i].firstChild.data.replace(/\..* \./g, '.'); } } @@ -131,22 +181,22 @@ class WorkspaceFunc extends Component { } createFileName = (filetype) => { - this.setState({file: filetype}, () => { - if(this.state.name){ + this.setState({ file: filetype }, () => { + if (this.state.name) { this.state.file === 'xml' ? this.saveXmlFile() : this.getSvg() } - else{ + else { this.setState({ saveFile: true, file: filetype, open: true, title: this.state.file === 'xml' ? 'Blöcke speichern' : 'Screenshot erstellen', content: `Bitte gib einen Namen für die Bennenung der ${this.state.file === 'xml' ? 'XML' : 'SVG'}-Datei ein und bestätige diesen mit einem Klick auf 'Eingabe'.` }); } }); } setFileName = (e) => { - this.setState({name: e.target.value}); + this.setState({ name: e.target.value }); } uploadXmlFile = (xmlFile) => { - if(xmlFile.type !== 'text/xml'){ + if (xmlFile.type !== 'text/xml') { this.setState({ open: true, file: false, title: 'Unzulässiger Dateityp', content: 'Die übergebene Datei entsprach nicht dem geforderten Format. Es sind nur XML-Dateien zulässig.' }); } else { @@ -161,18 +211,18 @@ class WorkspaceFunc extends Component { workspace.clear(); this.props.clearStats(); Blockly.Xml.domToWorkspace(xmlDom, workspace); - if(workspace.getAllBlocks().length < 1){ + if (workspace.getAllBlocks().length < 1) { Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xmlBefore), workspace) this.setState({ open: true, file: false, title: 'Keine Blöcke', content: 'Es wurden keine Blöcke detektiert. Bitte überprüfe den XML-Code und versuche es erneut.' }); } else { - if(!this.props.solutionCheck){ + if (!this.props.solutionCheck) { var extensionPosition = xmlFile.name.lastIndexOf('.'); this.props.workspaceName(xmlFile.name.substr(0, extensionPosition)); } this.setState({ snackbar: true, key: Date.now(), message: 'Das Projekt aus gegebener XML-Datei wurde erfolgreich eingefügt.' }); } - } catch(err){ + } catch (err) { this.setState({ open: true, file: false, 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.' }); } }; @@ -195,83 +245,118 @@ class WorkspaceFunc extends Component { workspace.options.maxBlocks = Infinity; this.props.onChangeCode(); this.props.clearStats(); - if(!this.props.solutionCheck){ + if (!this.props.solutionCheck) { this.props.workspaceName(null); } this.setState({ snackbar: true, key: Date.now(), message: 'Das Projekt wurde erfolgreich zurückgesetzt.' }); } + + render() { return ( -
+
{!this.props.solutionCheck ? - -
{this.setState({file: true, open: true, saveFile: false, title: 'Projekt benennen', content: 'Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf \'Eingabe\'.'})}}> - {this.props.name && !isWidthDown('xs', this.props.width) ? {this.props.name} : null} -
- + +
{ this.setState({ file: true, open: true, saveFile: false, title: 'Projekt benennen', content: 'Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf \'Eingabe\'.' }) }}> + {this.props.name && !isWidthDown('xs', this.props.width) ? {this.props.name} : null} +
+ +
-
- : null} + : null} {this.props.solutionCheck ? : } - + {this.createFileName('xml');}} + onClick={() => { this.createFileName('xml'); }} > - + -
+
{this.uploadXmlFile(e.target.files[0])}} + onChange={(e) => { this.uploadXmlFile(e.target.files[0]) }} id="open-blocks" type="file" />