commit
a26f2a2f89
26
CITATION.cff
Normal file
26
CITATION.cff
Normal file
@ -0,0 +1,26 @@
|
||||
# This CITATION.cff file was generated with cffinit.
|
||||
# Visit https://bit.ly/cffinit to generate yours today!
|
||||
|
||||
cff-version: 1.2.0
|
||||
title: senseBox Learn- and Programming Environment
|
||||
message: Please cite this software using these metadata.
|
||||
type: software
|
||||
version: 1.0.0
|
||||
date-released: 2021-09-30
|
||||
url: "https://github.com/sensebox/React-Ardublockly"
|
||||
authors:
|
||||
- given-names: Mario
|
||||
family-names: Pesch
|
||||
email: mario.pesch@uni-muenster.de
|
||||
affiliation: >-
|
||||
Institute for geoinformatics University of
|
||||
Muenster
|
||||
- given-names: Luc
|
||||
family-names: Niski
|
||||
affiliation: >-
|
||||
Institute for geoinformatics University of
|
||||
Muenster
|
||||
- given-names: Felix
|
||||
family-names: Erdmann
|
||||
email: f.erdmann@reedu.de
|
||||
affiliation: Reedu GmbH & Co. KG
|
@ -1,32 +1,38 @@
|
||||
import { VISIT, LANGUAGE, RENDERER, STATISTICS } from './types';
|
||||
|
||||
import { VISIT, LANGUAGE, RENDERER, STATISTICS, PLATFORM } from "./types";
|
||||
|
||||
export const visitPage = () => (dispatch) => {
|
||||
dispatch({
|
||||
type: VISIT
|
||||
type: VISIT,
|
||||
});
|
||||
};
|
||||
|
||||
export const setPlatform = (platform) => (dispatch) => {
|
||||
dispatch({
|
||||
type: PLATFORM,
|
||||
payload: platform,
|
||||
});
|
||||
};
|
||||
|
||||
export const setLanguage = (language) => (dispatch, getState) => {
|
||||
if (!getState().auth.progress && !getState().auth.isAuthenticated) {
|
||||
window.localStorage.setItem('locale', language);
|
||||
window.localStorage.setItem("locale", language);
|
||||
}
|
||||
dispatch({
|
||||
type: LANGUAGE,
|
||||
payload: language
|
||||
payload: language,
|
||||
});
|
||||
};
|
||||
|
||||
export const setRenderer = (renderer) => (dispatch) => {
|
||||
dispatch({
|
||||
type: RENDERER,
|
||||
payload: renderer
|
||||
payload: renderer,
|
||||
});
|
||||
};
|
||||
|
||||
export const setStatistics = (showStatistics) => (dispatch) => {
|
||||
dispatch({
|
||||
type: STATISTICS,
|
||||
payload: showStatistics
|
||||
payload: showStatistics,
|
||||
});
|
||||
};
|
||||
|
@ -43,6 +43,7 @@ export const PROGRESS = "PROGRESS";
|
||||
|
||||
export const VISIT = "VISIT";
|
||||
export const LANGUAGE = "LANGUAGE";
|
||||
export const PLATFORM = "PLATFORM";
|
||||
export const RENDERER = "RENDERER";
|
||||
export const STATISTICS = "STATISTICS";
|
||||
|
||||
|
@ -11,6 +11,7 @@ import "./blocks/index";
|
||||
import "./generator/index";
|
||||
import { ZoomToFitControl } from "@blockly/zoom-to-fit";
|
||||
import { initialXml } from "./initialXml.js";
|
||||
import { getMaxInstances } from "./helpers/maxInstances";
|
||||
|
||||
class BlocklyWindow extends Component {
|
||||
constructor(props) {
|
||||
@ -24,6 +25,7 @@ class BlocklyWindow extends Component {
|
||||
this.props.clearStats();
|
||||
workspace.addChangeListener((event) => {
|
||||
this.props.onChangeWorkspace(event);
|
||||
|
||||
// switch on that a block is displayed disabled or not depending on whether it is correctly connected
|
||||
// for SVG display, a deactivated block in the display is undesirable
|
||||
if (this.props.blockDisabled) {
|
||||
@ -37,6 +39,7 @@ class BlocklyWindow extends Component {
|
||||
|
||||
componentDidUpdate(props) {
|
||||
const workspace = Blockly.getMainWorkspace();
|
||||
|
||||
var xml = this.props.initialXml;
|
||||
// if svg is true, then the update process is done in the BlocklySvg component
|
||||
if (props.initialXml !== xml && !this.props.svg) {
|
||||
@ -69,6 +72,7 @@ class BlocklyWindow extends Component {
|
||||
this.props.trashcan !== undefined ? this.props.trashcan : true
|
||||
}
|
||||
renderer={this.props.renderer}
|
||||
maxInstances={getMaxInstances()}
|
||||
zoom={{
|
||||
// https://developers.google.com/blockly/guides/configure/web/zoom
|
||||
controls:
|
||||
|
@ -26,6 +26,17 @@
|
||||
|
||||
import * as Blockly from "blockly/core";
|
||||
|
||||
import store from "../../../store";
|
||||
|
||||
var ota = store.getState().general.platform
|
||||
? store.getState().general.platform
|
||||
: null;
|
||||
store.subscribe(() => {
|
||||
ota = store.getState().general.platform
|
||||
? store.getState().general.platform
|
||||
: null;
|
||||
});
|
||||
|
||||
/**
|
||||
* Arduino code generator.
|
||||
* @type !Blockly.Generator
|
||||
@ -254,7 +265,29 @@ Blockly["Arduino"].finish = function (code) {
|
||||
"\n}\n";
|
||||
|
||||
let loopCode = "\nvoid loop() { \n" + loopCodeOnce + code + "\n}\n";
|
||||
|
||||
// only add OTA code if tablet mode is enabled
|
||||
if (ota === true) {
|
||||
code =
|
||||
devVariables +
|
||||
"\n" +
|
||||
"#include <SenseBoxOTA.h>" +
|
||||
"\n" +
|
||||
libraryCode +
|
||||
"\n" +
|
||||
variablesCode +
|
||||
"\n" +
|
||||
definitionsCode +
|
||||
"\n" +
|
||||
codeFunctions +
|
||||
"\n" +
|
||||
Blockly["Arduino"].variablesInitCode_ +
|
||||
"\n" +
|
||||
functionsCode +
|
||||
"\n" +
|
||||
setupCode +
|
||||
"\n" +
|
||||
loopCode;
|
||||
} else {
|
||||
// Convert the definitions dictionary into a list.
|
||||
code =
|
||||
devVariables +
|
||||
@ -274,6 +307,7 @@ Blockly["Arduino"].finish = function (code) {
|
||||
setupCode +
|
||||
"\n" +
|
||||
loopCode;
|
||||
}
|
||||
|
||||
// Clean up temporary data.
|
||||
delete Blockly["Arduino"].definitions_;
|
||||
|
21
src/components/Blockly/helpers/maxInstances.js
Normal file
21
src/components/Blockly/helpers/maxInstances.js
Normal file
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* To limit number of specific blocks in the workspace add block name and number of maxInstances here.
|
||||
*
|
||||
*/
|
||||
|
||||
const maxInstances = {
|
||||
sensebox_wifi: 1,
|
||||
sensebox_startap: 1,
|
||||
sensebox_display_beginDisplay: 1,
|
||||
sensebox_telegram: 1,
|
||||
sensebox_telegram_do: 1,
|
||||
sensebox_interval_timer: 1,
|
||||
sensebox_osem_connection: 1,
|
||||
sensebox_lora_initialize_otaa: 1,
|
||||
sensebox_lora_initialize_abp: 1,
|
||||
sensebox_phyphox_init: 1,
|
||||
};
|
||||
|
||||
export const getMaxInstances = () => {
|
||||
return maxInstances;
|
||||
};
|
@ -19,9 +19,11 @@ Das Kopieren der Programme unter MacOS funktioniert nicht über den Finder, es g
|
||||
Grundsätzlich kann die Programmierumgebung mit jeder senseBox mit senseBox MCU verwendet werden.
|
||||
`,
|
||||
|
||||
|
||||
faq_q3_question: `Ich habe einen Fehler gefunden oder etwas funktioniert nicht. Wo kann ich diesen melden?`,
|
||||
faq_q3_answer: `
|
||||
Am besten legst du dazu ein Issue auf [Github](https://github.com/sensebox/React-Ardublockly/issues) an. Alternativ kannst du uns auch eine Email an info(at)sensebox.de senden
|
||||
`,
|
||||
}
|
||||
|
||||
faq_tablet_question: `Kann ich die senseBox auch über ein Tablet programmieren?`,
|
||||
faq_tablet_answer: `Ja! Installiere dazu die senseBox Connect App aus dem App Store und rufe die Learn- und Programmierumgebung in deinem Browser am Tablet auf. Genaue Informationen zur Verwendung der App findest du unter [https://sensebox.de/app](https://sensebox.de/app)`,
|
||||
};
|
||||
|
@ -49,7 +49,14 @@ export const UI = {
|
||||
tooltip_project_title: "Titel des Projektes",
|
||||
tooltip_check_solution: "Lösung kontrollieren",
|
||||
tooltip_copy_code: "Code in die Zwischenablage kopieren",
|
||||
|
||||
tooltip_statistics_current: "Anzahl aktueller Blöcke",
|
||||
tooltip_statistics_new: "Anzahl neuer Blöcke",
|
||||
tooltip_statistics_changed: "Anzahl veränderter Blöcke",
|
||||
tooltip_statistics_moved: "Anzahl bewegter Blöcke",
|
||||
tooltip_statistics_deleted: "Anzahl gelöschter Blöcke",
|
||||
tooltip_statistics_remaining: "Verbleibende Blöcke",
|
||||
tooltip_statistics_show: "Statistiken anzeigen",
|
||||
tooltip_start_tour: "Tour starten",
|
||||
/**
|
||||
* Messages
|
||||
*
|
||||
@ -83,6 +90,16 @@ export const UI = {
|
||||
messages_LOGIN_FAIL: "Der Benutzername oder das Passwort ist nicht korrekt.",
|
||||
messages_copy_code: "Code wurde in die Zwischenablage kopiert",
|
||||
|
||||
/**
|
||||
* Tablet Dialog
|
||||
*/
|
||||
|
||||
tabletDialog_headline: "Tablet Modus ist aktiviert!",
|
||||
tabletDialog_text:
|
||||
"Der Tablet Modus wurde aktiviert. Du kannst nun Programmcodes über die senseBox Connect App auf deine senseBox kopieren. Der Tablet Modus kann in den Einstellungen deaktiviert werden",
|
||||
tabletDialog_more:
|
||||
"Weitere Informationen und den Link zum Download der App findest du unter: ",
|
||||
|
||||
/**
|
||||
* Reset Dialog
|
||||
*/
|
||||
@ -154,6 +171,11 @@ export const UI = {
|
||||
"Die Anzeige von Statistiken zur Nutzung der Blöcke oberhalb der Arbeitsfläche kann ein- oder ausgeblendet werden.",
|
||||
settings_statistics_on: "An",
|
||||
settings_statistics_off: "Aus",
|
||||
settings_ota_head: "Tablet Modus",
|
||||
settings_ota_text:
|
||||
"Der Tablet Modus deaktiviert die Code anzeige und aktiviert die Möglichkeit den Programmcode über die senseBox Connect App zu übertragen. Weitere Informationen dazu findest du unter: ",
|
||||
settings_ota_on: "Aktiviert",
|
||||
settings_ota_off: "Deaktiviert",
|
||||
|
||||
/**
|
||||
* 404
|
||||
@ -175,7 +197,7 @@ export const UI = {
|
||||
/**
|
||||
* Tutorials
|
||||
*/
|
||||
|
||||
tutorials_home_head: "Tutorial-Übersicht",
|
||||
tutorials_assessment_task: "Aufgabe",
|
||||
tutorials_hardware_head: "Für die Umsetzung benötigst du folgende Hardware:",
|
||||
tutorials_hardware_moreInformation:
|
||||
@ -187,7 +209,9 @@ export const UI = {
|
||||
/**
|
||||
* Tutorial Builder
|
||||
*/
|
||||
|
||||
builder_createNew: "neues Tutorial erstellen",
|
||||
builder_changeExisting: "bestehendes Tutorial ändern",
|
||||
builder_deleteExisting: "bestehendes Tutorial löschen",
|
||||
builder_solution: "Lösung",
|
||||
builder_solution_submit: "Lösung einreichen",
|
||||
builder_example_submit: "Beispiel einreichen",
|
||||
@ -215,7 +239,7 @@ export const UI = {
|
||||
|
||||
navbar_tutorials: "Tutorials",
|
||||
navbar_tutorialbuilder: "Tutorial erstellen",
|
||||
navbar_gallery: "Gallerie",
|
||||
navbar_gallery: "Galerie",
|
||||
navbar_projects: "Projekte",
|
||||
|
||||
navbar_menu: "Menü",
|
||||
|
@ -3,7 +3,6 @@ export const FAQ = {
|
||||
* FAQ
|
||||
*/
|
||||
|
||||
|
||||
faq_q1_question: `How can I copy my program to the senseBox?`,
|
||||
faq_q1_answer: `To copy programs to the senseBox, connect it to the computer with the Micro USB cable. Then double click on the red reset button on the senseBox MCU. The senseBox will now be recognized as a removable disk on your computer and the previously created programs can be copied via drag & drop. After each change of the program code the program must be recompiled and transferred again.
|
||||
#### Activate learning mode of the MCU
|
||||
@ -20,10 +19,10 @@ Copying programs under MacOS does not work via the Finder, but there are still t
|
||||
Basically the programming environment can be used with any senseBox with senseBox MCU.
|
||||
`,
|
||||
|
||||
|
||||
faq_q3_question: `I found an error or something is not working. Where can I report it?`,
|
||||
faq_q3_answer: `
|
||||
The best way to do this is to create an issue on [Github](https://github.com/sensebox/React-Ardublockly/issues). Alternatively you can send us an email to info(at)sensebox.de
|
||||
`,
|
||||
|
||||
}
|
||||
faq_tablet_question: `Can I program the senseBox with a tablet?`,
|
||||
faq_tablet_answer: `Yes! Install the senseBox Connect app from the App Store and call up the learning and programming environment in your browser on the tablet. Detailed information on how to use the app can be found at [https://sensebox.de/app](https://sensebox.de/app)`,
|
||||
};
|
||||
|
@ -49,6 +49,14 @@ export const UI = {
|
||||
tooltip_project_title: "Project title",
|
||||
tooltip_check_solution: "Check solution",
|
||||
tooltip_copy_code: "Copy Code to clipboard",
|
||||
tooltip_statistics_current: "Number of current blocks",
|
||||
tooltip_statistics_new: "Number of new blocks",
|
||||
tooltip_statistics_changed: "Number of changed blocks",
|
||||
tooltip_statistics_moved: "Number of moved blocks",
|
||||
tooltip_statistics_deleted: "Number of deleted blocks",
|
||||
tooltip_statistics_remaining: "Remaining blocks",
|
||||
tooltip_statistics_show: "Show statistics",
|
||||
tooltip_start_tour: "start Tour",
|
||||
|
||||
/**
|
||||
* Messages
|
||||
@ -80,6 +88,15 @@ export const UI = {
|
||||
messages_login_error: "Enter both a username and a password.",
|
||||
messages_copy_code: "Copy code to clipboard succesfull",
|
||||
|
||||
/**
|
||||
* Tablet Dialog
|
||||
*/
|
||||
tabletDialog_headline: "Tablet mode is enabled!",
|
||||
tabletDialog_text:
|
||||
"Tablet mode has been activated. You can now copy program codes to your senseBox via the senseBox Connect app. Tablet mode can be deactivated in the settings",
|
||||
tabletDialog_more:
|
||||
"For more information and the link to download the app, please visit: ",
|
||||
|
||||
/**
|
||||
* Reset Dialog
|
||||
*/
|
||||
@ -149,6 +166,11 @@ export const UI = {
|
||||
"The display of statistics on the usage of the blocks above the workspace can be shown or hidden.",
|
||||
settings_statistics_on: "On",
|
||||
settings_statistics_off: "Off",
|
||||
settings_ota_head: "tablet mode",
|
||||
settings_ota_text:
|
||||
"Tablet mode disables the code display and enables the possibility to transfer the program code via the senseBox Connect app. You can find more information on: ",
|
||||
settings_ota_on: "Activated",
|
||||
settings_ota_off: "Deactivated",
|
||||
|
||||
/**
|
||||
* 404
|
||||
@ -169,7 +191,7 @@ export const UI = {
|
||||
/**
|
||||
* Tutorials
|
||||
*/
|
||||
|
||||
tutorials_home_head: "Tutorials",
|
||||
tutorials_assessment_task: "Task",
|
||||
tutorials_hardware_head:
|
||||
"For the implementation you need the following hardware:",
|
||||
@ -182,7 +204,9 @@ export const UI = {
|
||||
/**
|
||||
* Tutorial Builder
|
||||
*/
|
||||
|
||||
uilder_createNew: "create new Tutorial",
|
||||
builder_changeExisting: "change existing Tutorial",
|
||||
builder_deleteExisting: "remove existing Tutorial",
|
||||
builder_solution: "Solution",
|
||||
builder_solution_submit: "Submit Solution",
|
||||
builder_example_submit: "Submit example",
|
||||
|
@ -1,68 +1,78 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { clearStats, workspaceName } from '../actions/workspaceActions';
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { connect } from "react-redux";
|
||||
import { clearStats, workspaceName } from "../actions/workspaceActions";
|
||||
|
||||
import * as Blockly from 'blockly/core';
|
||||
import { createNameId } from 'mnemonic-id';
|
||||
import * as Blockly from "blockly/core";
|
||||
import { createNameId } from "mnemonic-id";
|
||||
|
||||
import WorkspaceStats from './Workspace/WorkspaceStats';
|
||||
import WorkspaceFunc from './Workspace/WorkspaceFunc';
|
||||
import BlocklyWindow from './Blockly/BlocklyWindow';
|
||||
import CodeViewer from './CodeViewer';
|
||||
import TrashcanButtons from './Workspace/TrashcanButtons';
|
||||
import HintTutorialExists from './Tutorial/HintTutorialExists';
|
||||
import Snackbar from './Snackbar';
|
||||
import WorkspaceStats from "./Workspace/WorkspaceStats";
|
||||
import WorkspaceFunc from "./Workspace/WorkspaceFunc";
|
||||
import BlocklyWindow from "./Blockly/BlocklyWindow";
|
||||
import CodeViewer from "./CodeViewer";
|
||||
import TrashcanButtons from "./Workspace/TrashcanButtons";
|
||||
import HintTutorialExists from "./Tutorial/HintTutorialExists";
|
||||
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import Tooltip from "@material-ui/core/Tooltip";
|
||||
import { withStyles } from "@material-ui/core/styles";
|
||||
|
||||
import { faCode } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import TooltipViewer from './TooltipViewer';
|
||||
|
||||
import TooltipViewer from "./TooltipViewer";
|
||||
import Dialog from "./Dialog";
|
||||
|
||||
const styles = (theme) => ({
|
||||
codeOn: {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
color: theme.palette.primary.contrastText,
|
||||
'&:hover': {
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.primary.contrastText,
|
||||
color: theme.palette.primary.main,
|
||||
border: `1px solid ${theme.palette.secondary.main}`
|
||||
}
|
||||
border: `1px solid ${theme.palette.secondary.main}`,
|
||||
},
|
||||
},
|
||||
codeOff: {
|
||||
backgroundColor: theme.palette.primary.contrastText,
|
||||
color: theme.palette.primary.main,
|
||||
border: `1px solid ${theme.palette.secondary.main}`,
|
||||
'&:hover': {
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
color: theme.palette.primary.contrastText,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
class Home extends Component {
|
||||
|
||||
state = {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
codeOn: true,
|
||||
snackbar: false,
|
||||
type: '',
|
||||
key: '',
|
||||
message: ''
|
||||
type: "",
|
||||
key: "",
|
||||
message: "",
|
||||
open: true,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({ stats: window.localStorage.getItem('stats') });
|
||||
console.log(this.props.platform);
|
||||
if (this.props.platform === true) {
|
||||
this.setState({ codeOn: false });
|
||||
}
|
||||
this.setState({ stats: window.localStorage.getItem("stats") });
|
||||
if (!this.props.project) {
|
||||
this.props.workspaceName(createNameId());
|
||||
}
|
||||
if (this.props.message && this.props.message.id === 'GET_SHARE_FAIL') {
|
||||
this.setState({ snackbar: true, key: Date.now(), message: `Das angefragte geteilte Projekt konnte nicht gefunden werden.`, type: 'error' });
|
||||
if (this.props.message && this.props.message.id === "GET_SHARE_FAIL") {
|
||||
this.setState({
|
||||
snackbar: true,
|
||||
key: Date.now(),
|
||||
message: `Das angefragte geteilte Projekt konnte nicht gefunden werden.`,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,6 +90,18 @@ class Home extends Component {
|
||||
this.props.workspaceName(null);
|
||||
}
|
||||
|
||||
toggleDialog = () => {
|
||||
this.setState({ open: !this.state });
|
||||
};
|
||||
|
||||
onChangeCheckbox = (e) => {
|
||||
if (e.target.checked) {
|
||||
window.localStorage.setItem("ota", e.target.checked);
|
||||
} else {
|
||||
window.localStorage.removeItem("ota");
|
||||
}
|
||||
};
|
||||
|
||||
onChange = () => {
|
||||
this.setState({ codeOn: !this.state.codeOn });
|
||||
const workspace = Blockly.getMainWorkspace();
|
||||
@ -87,67 +109,122 @@ class Home extends Component {
|
||||
if (workspace.trashcan && workspace.trashcan.flyout) {
|
||||
workspace.trashcan.flyout.hide(); // in case of resize, the trash flyout does not reposition
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.props.statistics ?
|
||||
<div style={{ float: 'left', height: '40px', position: 'relative' }}><WorkspaceStats /></div>
|
||||
: null
|
||||
}
|
||||
<div className='workspaceFunc' style={{ float: 'right', height: '40px', marginBottom: '20px' }}>
|
||||
<WorkspaceFunc project={this.props.project} projectType={this.props.projectType} />
|
||||
{this.props.statistics ? (
|
||||
<div style={{ float: "left", height: "40px", position: "relative" }}>
|
||||
<WorkspaceStats />
|
||||
</div>
|
||||
) : null}
|
||||
<div
|
||||
className="workspaceFunc"
|
||||
style={{ float: "right", height: "40px", marginBottom: "20px" }}
|
||||
>
|
||||
<WorkspaceFunc
|
||||
project={this.props.project}
|
||||
projectType={this.props.projectType}
|
||||
/>
|
||||
</div>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={this.state.codeOn ? 8 : 12} style={{ position: 'relative' }}>
|
||||
<Tooltip title={this.state.codeOn ? 'Code ausblenden' : 'Code anzeigen'} >
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
md={this.state.codeOn ? 8 : 12}
|
||||
style={{ position: "relative" }}
|
||||
>
|
||||
<Tooltip
|
||||
title={
|
||||
this.state.codeOn
|
||||
? Blockly.Msg.tooltip_hide_code
|
||||
: Blockly.Msg.tooltip_show_code
|
||||
}
|
||||
>
|
||||
<IconButton
|
||||
className={`showCode ${this.state.codeOn ? this.props.classes.codeOn : this.props.classes.codeOff}`}
|
||||
style={{ width: '40px', height: '40px', position: 'absolute', top: -12, right: 8, zIndex: 21 }}
|
||||
className={`showCode ${
|
||||
this.state.codeOn
|
||||
? this.props.classes.codeOn
|
||||
: this.props.classes.codeOff
|
||||
}`}
|
||||
style={{
|
||||
width: "40px",
|
||||
height: "40px",
|
||||
position: "absolute",
|
||||
top: -12,
|
||||
right: 8,
|
||||
zIndex: 21,
|
||||
}}
|
||||
onClick={() => this.onChange()}
|
||||
>
|
||||
<FontAwesomeIcon icon={faCode} size="xs" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<TrashcanButtons />
|
||||
<div className='blocklyWindow'>
|
||||
{this.props.project ?
|
||||
< BlocklyWindow blocklyCSS={{ height: '80vH' }} initialXml={this.props.project.xml} />
|
||||
: < BlocklyWindow blocklyCSS={{ height: '80vH' }} />
|
||||
}
|
||||
<div className="blocklyWindow">
|
||||
{this.props.project ? (
|
||||
<BlocklyWindow
|
||||
blocklyCSS={{ height: "80vH" }}
|
||||
initialXml={this.props.project.xml}
|
||||
/>
|
||||
) : (
|
||||
<BlocklyWindow blocklyCSS={{ height: "80vH" }} />
|
||||
)}
|
||||
</div>
|
||||
</Grid>
|
||||
{this.state.codeOn ?
|
||||
{this.state.codeOn ? (
|
||||
<Grid item xs={12} md={4}>
|
||||
<CodeViewer />
|
||||
<TooltipViewer />
|
||||
</Grid>
|
||||
: null}
|
||||
) : null}
|
||||
</Grid>
|
||||
<HintTutorialExists />
|
||||
<Snackbar
|
||||
open={this.state.snackbar}
|
||||
message={this.state.message}
|
||||
type={this.state.type}
|
||||
key={this.state.key}
|
||||
/>
|
||||
{this.props.platform ? (
|
||||
<Dialog
|
||||
style={{ zIndex: 9999999 }}
|
||||
fullWidth
|
||||
maxWidth={"sm"}
|
||||
open={this.state.open}
|
||||
title={Blockly.Msg.tabletDialog_headline}
|
||||
content={""}
|
||||
onClose={this.toggleDialog}
|
||||
onClick={this.toggleDialog}
|
||||
button={Blockly.Msg.button_close}
|
||||
>
|
||||
<div>{Blockly.Msg.tabletDialog_text}</div>
|
||||
<div>
|
||||
{Blockly.Msg.tabletDialog_more}{" "}
|
||||
<a
|
||||
href="https://sensebox.de/app"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
https://sensebox.de/app
|
||||
</a>
|
||||
</div>
|
||||
</Dialog>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Home.propTypes = {
|
||||
clearStats: PropTypes.func.isRequired,
|
||||
workspaceName: PropTypes.func.isRequired,
|
||||
message: PropTypes.object.isRequired,
|
||||
statistics: PropTypes.bool.isRequired
|
||||
statistics: PropTypes.bool.isRequired,
|
||||
platform: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state) => ({
|
||||
message: state.message,
|
||||
statistics: state.general.statistics
|
||||
statistics: state.general.statistics,
|
||||
platform: state.general.platform,
|
||||
});
|
||||
|
||||
|
||||
export default connect(mapStateToProps, { clearStats, workspaceName })(withStyles(styles, { withTheme: true })(Home));
|
||||
export default connect(mapStateToProps, { clearStats, workspaceName })(
|
||||
withStyles(styles, { withTheme: true })(Home)
|
||||
);
|
||||
|
@ -139,7 +139,7 @@ class Navbar extends Component {
|
||||
</Link>
|
||||
) : null}
|
||||
{isHome ? (
|
||||
<Tooltip title="Hilfe starten" arrow>
|
||||
<Tooltip title={Blockly.Msg.tooltip_start_tour} arrow>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
className={`openTour ${this.props.classes.button}`}
|
||||
@ -153,7 +153,7 @@ class Navbar extends Component {
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{isAssessment ? (
|
||||
<Tooltip title="Hilfe starten" arrow>
|
||||
<Tooltip title={Blockly.Msg.tooltip_start_tour} arrow>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
className={`openTour ${this.props.classes.button}`}
|
||||
|
66
src/components/Settings/OtaSelector.js
Normal file
66
src/components/Settings/OtaSelector.js
Normal file
@ -0,0 +1,66 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { connect } from "react-redux";
|
||||
import { setPlatform } from "../../actions/generalActions";
|
||||
|
||||
import * as Blockly from "blockly/core";
|
||||
|
||||
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";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import FormHelperText from "@material-ui/core/FormHelperText";
|
||||
|
||||
class OtaSelector extends Component {
|
||||
componentDidMount() {
|
||||
// Ensure that Blockly.setLocale is adopted in the component.
|
||||
// Otherwise, the text will not be displayed until the next update of the component.
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Typography style={{ fontWeight: "bold" }}>
|
||||
{Blockly.Msg.settings_ota_head}
|
||||
</Typography>
|
||||
<FormHelperText
|
||||
style={{ color: "black", lineHeight: 1.3, marginBottom: "8px" }}
|
||||
>
|
||||
{Blockly.Msg.settings_ota_text}
|
||||
<a href="https://sensebox.de/app" target="_blank" rel="noreferrer">
|
||||
https://sensebox.de/app
|
||||
</a>
|
||||
</FormHelperText>
|
||||
<FormControl>
|
||||
<InputLabel id="demo-simple-select-label">
|
||||
{Blockly.Msg.settings_statistics}
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
value={this.props.platform}
|
||||
onChange={(e) => this.props.setPlatform(e.target.value)}
|
||||
>
|
||||
<MenuItem value={true}>{Blockly.Msg.settings_ota_on}</MenuItem>
|
||||
<MenuItem value={false}>{Blockly.Msg.settings_ota_off}</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
OtaSelector.propTypes = {
|
||||
setPlatform: PropTypes.func.isRequired,
|
||||
language: PropTypes.string.isRequired,
|
||||
platform: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
language: state.general.language,
|
||||
platform: state.general.platform,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, { setPlatform })(OtaSelector);
|
@ -1,21 +1,21 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { withRouter } from "react-router-dom";
|
||||
|
||||
import * as Blockly from 'blockly/core';
|
||||
import * as Blockly from "blockly/core";
|
||||
|
||||
import Breadcrumbs from '../Breadcrumbs';
|
||||
import LanguageSelector from './LanguageSelector';
|
||||
import RenderSelector from './RenderSelector';
|
||||
import StatsSelector from './StatsSelector';
|
||||
import Breadcrumbs from "../Breadcrumbs";
|
||||
import LanguageSelector from "./LanguageSelector";
|
||||
import RenderSelector from "./RenderSelector";
|
||||
import StatsSelector from "./StatsSelector";
|
||||
import OtaSelector from "./OtaSelector";
|
||||
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
|
||||
class Settings extends Component {
|
||||
|
||||
componentDidMount() {
|
||||
// Ensure that Blockly.setLocale is adopted in the component.
|
||||
// Otherwise, the text will not be displayed until the next update of the component.
|
||||
@ -25,41 +25,55 @@ class Settings extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Breadcrumbs content={[{ link: this.props.location.pathname, title: Blockly.Msg.settings_head }]} />
|
||||
<Breadcrumbs
|
||||
content={[
|
||||
{
|
||||
link: this.props.location.pathname,
|
||||
title: Blockly.Msg.settings_head,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<h1>{Blockly.Msg.settings_head}</h1>
|
||||
|
||||
<Paper style={{margin: '10px 0px', padding: '10px'}}>
|
||||
<Paper style={{ margin: "10px 0px", padding: "10px" }}>
|
||||
<LanguageSelector />
|
||||
</Paper>
|
||||
<Paper style={{margin: '10px 0px', padding: '10px'}}>
|
||||
<Paper style={{ margin: "10px 0px", padding: "10px" }}>
|
||||
<RenderSelector />
|
||||
</Paper>
|
||||
<Paper style={{margin: '10px 0px', padding: '10px'}}>
|
||||
<Paper style={{ margin: "10px 0px", padding: "10px" }}>
|
||||
<StatsSelector />
|
||||
</Paper>
|
||||
<Paper style={{ margin: "10px 0px", padding: "10px" }}>
|
||||
<OtaSelector />
|
||||
</Paper>
|
||||
|
||||
<Button
|
||||
style={{ marginTop: '10px' }}
|
||||
style={{ marginTop: "10px" }}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={this.props.pageVisits > 0 ? () => this.props.history.goBack() : () => this.props.history.push('/')}
|
||||
onClick={
|
||||
this.props.pageVisits > 0
|
||||
? () => this.props.history.goBack()
|
||||
: () => this.props.history.push("/")
|
||||
}
|
||||
>
|
||||
{Blockly.Msg.button_back}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Settings.propTypes = {
|
||||
language: PropTypes.string.isRequired,
|
||||
pageVisits: PropTypes.number.isRequired
|
||||
pageVisits: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state) => ({
|
||||
language: state.general.language,
|
||||
pageVisits: state.general.pageVisits
|
||||
pageVisits: state.general.pageVisits,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, null)(withRouter(Settings));
|
||||
|
@ -39,6 +39,7 @@ 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";
|
||||
import * as Blockly from "blockly";
|
||||
|
||||
const styles = (theme) => ({
|
||||
backdrop: {
|
||||
@ -392,7 +393,7 @@ class Builder extends Component {
|
||||
style={{ color: "black" }}
|
||||
value="new"
|
||||
control={<Radio color="primary" />}
|
||||
label="neues Tutorial erstellen"
|
||||
label={Blockly.Msg.builder_createNew}
|
||||
labelPlacement="end"
|
||||
/>
|
||||
{filteredTutorials.length > 0 ? (
|
||||
@ -402,7 +403,7 @@ class Builder extends Component {
|
||||
disabled={this.props.index === 0}
|
||||
value="change"
|
||||
control={<Radio color="primary" />}
|
||||
label="bestehendes Tutorial ändern"
|
||||
label={Blockly.Msg.builder_changeExisting}
|
||||
labelPlacement="end"
|
||||
/>
|
||||
<FormControlLabel
|
||||
@ -410,7 +411,7 @@ class Builder extends Component {
|
||||
disabled={this.props.index === 0}
|
||||
value="delete"
|
||||
control={<Radio color="primary" />}
|
||||
label="bestehendes Tutorial löschen"
|
||||
label={Blockly.Msg.builder_deleteExisting}
|
||||
labelPlacement="end"
|
||||
/>
|
||||
</div>
|
||||
|
@ -1,56 +1,59 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { getTutorials, resetTutorial, tutorialProgress } from '../../actions/tutorialActions';
|
||||
import { clearMessages } from '../../actions/messageActions';
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
getTutorials,
|
||||
resetTutorial,
|
||||
tutorialProgress,
|
||||
} from "../../actions/tutorialActions";
|
||||
import { clearMessages } from "../../actions/messageActions";
|
||||
|
||||
import clsx from 'clsx';
|
||||
import clsx from "clsx";
|
||||
|
||||
import Breadcrumbs from '../Breadcrumbs';
|
||||
import Breadcrumbs from "../Breadcrumbs";
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
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 Typography from '@material-ui/core/Typography';
|
||||
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 Typography from "@material-ui/core/Typography";
|
||||
|
||||
import { faCheck, faTimes } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import * as Blockly from "blockly";
|
||||
|
||||
const styles = (theme) => ({
|
||||
outerDiv: {
|
||||
position: 'absolute',
|
||||
right: '-30px',
|
||||
bottom: '-30px',
|
||||
width: '160px',
|
||||
height: '160px',
|
||||
color: fade(theme.palette.secondary.main, 0.6)
|
||||
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)
|
||||
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)
|
||||
color: fade(theme.palette.primary.main, 0.6),
|
||||
},
|
||||
outerDivOther: {
|
||||
stroke: fade(theme.palette.secondary.main, 0.6)
|
||||
stroke: fade(theme.palette.secondary.main, 0.6),
|
||||
},
|
||||
innerDiv: {
|
||||
width: 'inherit',
|
||||
height: 'inherit',
|
||||
display: 'table-cell',
|
||||
verticalAlign: 'middle',
|
||||
textAlign: 'center'
|
||||
}
|
||||
width: "inherit",
|
||||
height: "inherit",
|
||||
display: "table-cell",
|
||||
verticalAlign: "middle",
|
||||
textAlign: "center",
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
class TutorialHome extends Component {
|
||||
|
||||
componentDidMount() {
|
||||
this.props.tutorialProgress();
|
||||
// retrieve tutorials only if a potential user is loaded - authentication
|
||||
@ -65,7 +68,7 @@ class TutorialHome extends Component {
|
||||
// authentication is completed
|
||||
this.props.getTutorials();
|
||||
}
|
||||
if(this.props.message.id === 'GET_TUTORIALS_FAIL'){
|
||||
if (this.props.message.id === "GET_TUTORIALS_FAIL") {
|
||||
alert(this.props.message.msg);
|
||||
}
|
||||
}
|
||||
@ -78,52 +81,144 @@ class TutorialHome extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
this.props.isLoading ? null :
|
||||
return this.props.isLoading ? null : (
|
||||
<div>
|
||||
<Breadcrumbs content={[{ link: '/tutorial', title: 'Tutorial' }]} />
|
||||
<Breadcrumbs content={[{ link: "/tutorial", title: "Tutorial" }]} />
|
||||
|
||||
<h1>Tutorial-Übersicht</h1>
|
||||
<h1>{Blockly.Msg.tutorials_home_head}</h1>
|
||||
<Grid container spacing={2}>
|
||||
{this.props.tutorials.map((tutorial, i) => {
|
||||
var status = this.props.status.filter(status => status._id === tutorial._id)[0];
|
||||
var status = this.props.status.filter(
|
||||
(status) => status._id === tutorial._id
|
||||
)[0];
|
||||
var tasks = status.tasks;
|
||||
var error = status.tasks.filter(task => task.type === 'error').length > 0;
|
||||
var success = status.tasks.filter(task => task.type === 'success').length / tasks.length
|
||||
var tutorialStatus = success === 1 ? 'Success' : error ? 'Error' : 'Other';
|
||||
var error =
|
||||
status.tasks.filter((task) => task.type === "error").length > 0;
|
||||
var success =
|
||||
status.tasks.filter((task) => task.type === "success").length /
|
||||
tasks.length;
|
||||
var tutorialStatus =
|
||||
success === 1 ? "Success" : error ? "Error" : "Other";
|
||||
return (
|
||||
<Grid item xs={12} sm={6} md={4} xl={3} key={i} style={{}}>
|
||||
<Link to={`/tutorial/${tutorial._id}`} style={{ textDecoration: 'none', color: 'inherit' }}>
|
||||
<Paper style={{ height: '150px', padding: '10px', position: 'relative', overflow: 'hidden' }}>
|
||||
<Link
|
||||
to={`/tutorial/${tutorial._id}`}
|
||||
style={{ textDecoration: "none", color: "inherit" }}
|
||||
>
|
||||
<Paper
|
||||
style={{
|
||||
height: "150px",
|
||||
padding: "10px",
|
||||
position: "relative",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{tutorial.title}
|
||||
<div className={clsx(this.props.classes.outerDiv)} style={{ width: '160px', height: '160px', border: 0 }}>
|
||||
<svg style={{ width: '100%', height: '100%' }}>
|
||||
{error || success === 1 ?
|
||||
<circle className={error ? this.props.classes.outerDivError : this.props.classes.outerDivSuccess} style={{ transform: 'rotate(-44deg)', transformOrigin: "50% 50%" }} r="75" cx="50%" cy="50%" fill="none" stroke-width="10"></circle>
|
||||
: <circle className={this.props.classes.outerDivOther} style={{ transform: 'rotate(-44deg)', transformOrigin: "50% 50%" }} r="75" cx="50%" cy="50%" fill="none" stroke-width="10" stroke-dashoffset={`${(75 * 2 * Math.PI) * (1 - (50 / 100 + success / 2))}`} stroke-dasharray={`${(75 * 2 * Math.PI) * (1 - (50 / 100 - success / 2))} ${(75 * 2 * Math.PI) * (1 - (50 / 100 + success / 2))}`}></circle>}
|
||||
{success < 1 && !error ?
|
||||
<circle className={this.props.classes.outerDivSuccess} style={{ transform: 'rotate(-44deg)', transformOrigin: "50% 50%" }} r="75" cx="50%" cy="50%" fill="none" stroke-width="10" stroke-dashoffset={`${(75 * 2 * Math.PI) * (1 - (50 / 100 + success / 2))}`} stroke-dasharray={`${(75 * 2 * Math.PI)}`}>
|
||||
</circle>
|
||||
: null}
|
||||
<div
|
||||
className={clsx(this.props.classes.outerDiv)}
|
||||
style={{ width: "160px", height: "160px", border: 0 }}
|
||||
>
|
||||
<svg style={{ width: "100%", height: "100%" }}>
|
||||
{error || success === 1 ? (
|
||||
<circle
|
||||
className={
|
||||
error
|
||||
? this.props.classes.outerDivError
|
||||
: this.props.classes.outerDivSuccess
|
||||
}
|
||||
style={{
|
||||
transform: "rotate(-44deg)",
|
||||
transformOrigin: "50% 50%",
|
||||
}}
|
||||
r="75"
|
||||
cx="50%"
|
||||
cy="50%"
|
||||
fill="none"
|
||||
stroke-width="10"
|
||||
></circle>
|
||||
) : (
|
||||
<circle
|
||||
className={this.props.classes.outerDivOther}
|
||||
style={{
|
||||
transform: "rotate(-44deg)",
|
||||
transformOrigin: "50% 50%",
|
||||
}}
|
||||
r="75"
|
||||
cx="50%"
|
||||
cy="50%"
|
||||
fill="none"
|
||||
stroke-width="10"
|
||||
stroke-dashoffset={`${
|
||||
75 * 2 * Math.PI * (1 - (50 / 100 + success / 2))
|
||||
}`}
|
||||
stroke-dasharray={`${
|
||||
75 * 2 * Math.PI * (1 - (50 / 100 - success / 2))
|
||||
} ${
|
||||
75 * 2 * Math.PI * (1 - (50 / 100 + success / 2))
|
||||
}`}
|
||||
></circle>
|
||||
)}
|
||||
{success < 1 && !error ? (
|
||||
<circle
|
||||
className={this.props.classes.outerDivSuccess}
|
||||
style={{
|
||||
transform: "rotate(-44deg)",
|
||||
transformOrigin: "50% 50%",
|
||||
}}
|
||||
r="75"
|
||||
cx="50%"
|
||||
cy="50%"
|
||||
fill="none"
|
||||
stroke-width="10"
|
||||
stroke-dashoffset={`${
|
||||
75 * 2 * Math.PI * (1 - (50 / 100 + success / 2))
|
||||
}`}
|
||||
stroke-dasharray={`${75 * 2 * Math.PI}`}
|
||||
></circle>
|
||||
) : null}
|
||||
</svg>
|
||||
</div>
|
||||
<div className={clsx(this.props.classes.outerDiv, tutorialStatus === 'Error' ? this.props.classes.outerDivError : tutorialStatus === 'Success' ? this.props.classes.outerDivSuccess : null)}>
|
||||
<div
|
||||
className={clsx(
|
||||
this.props.classes.outerDiv,
|
||||
tutorialStatus === "Error"
|
||||
? this.props.classes.outerDivError
|
||||
: tutorialStatus === "Success"
|
||||
? this.props.classes.outerDivSuccess
|
||||
: null
|
||||
)}
|
||||
>
|
||||
<div className={this.props.classes.innerDiv}>
|
||||
{error || success === 1 ?
|
||||
<FontAwesomeIcon size='4x' icon={tutorialStatus === 'Success' ? faCheck : faTimes} />
|
||||
: <Typography variant='h3' className={success > 0 ? this.props.classes.outerDivSuccess : {}}>{Math.round(success * 100)}%</Typography>
|
||||
{error || success === 1 ? (
|
||||
<FontAwesomeIcon
|
||||
size="4x"
|
||||
icon={
|
||||
tutorialStatus === "Success" ? faCheck : faTimes
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Typography
|
||||
variant="h3"
|
||||
className={
|
||||
success > 0
|
||||
? this.props.classes.outerDivSuccess
|
||||
: {}
|
||||
}
|
||||
>
|
||||
{Math.round(success * 100)}%
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Paper>
|
||||
</Link>
|
||||
</Grid>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
TutorialHome.propTypes = {
|
||||
@ -136,16 +231,21 @@ TutorialHome.propTypes = {
|
||||
tutorials: PropTypes.array.isRequired,
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
message: PropTypes.object.isRequired,
|
||||
progress: PropTypes.bool.isRequired
|
||||
progress: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state) => ({
|
||||
change: state.tutorial.change,
|
||||
status: state.tutorial.status,
|
||||
tutorials: state.tutorial.tutorials,
|
||||
isLoading: state.tutorial.progress,
|
||||
message: state.message,
|
||||
progress: state.auth.progress
|
||||
progress: state.auth.progress,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, { getTutorials, resetTutorial, clearMessages, tutorialProgress })(withStyles(styles, { withTheme: true })(TutorialHome));
|
||||
export default connect(mapStateToProps, {
|
||||
getTutorials,
|
||||
resetTutorial,
|
||||
clearMessages,
|
||||
tutorialProgress,
|
||||
})(withStyles(styles, { withTheme: true })(TutorialHome));
|
||||
|
@ -21,6 +21,7 @@ import "prismjs/themes/prism.css";
|
||||
import "prismjs/plugins/line-numbers/prism-line-numbers";
|
||||
import "prismjs/plugins/line-numbers/prism-line-numbers.css";
|
||||
import MuiDrawer from "@material-ui/core/Drawer";
|
||||
import Dialog from "../Dialog";
|
||||
|
||||
const styles = (theme) => ({
|
||||
backdrop: {
|
||||
@ -65,6 +66,8 @@ class Compile extends Component {
|
||||
content: "",
|
||||
name: props.name,
|
||||
error: "",
|
||||
appLink: "",
|
||||
appDialog: false,
|
||||
};
|
||||
}
|
||||
|
||||
@ -126,10 +129,19 @@ class Compile extends Component {
|
||||
};
|
||||
|
||||
toggleDialog = () => {
|
||||
this.setState({ open: !this.state, progress: false });
|
||||
this.setState({ open: !this.state, progress: false, appDialog: false });
|
||||
};
|
||||
|
||||
createFileName = () => {
|
||||
if (this.props.platform === true) {
|
||||
const filename = detectWhitespacesAndReturnReadableResult(
|
||||
this.state.name
|
||||
);
|
||||
this.setState({
|
||||
link: `blocklyconnect-app://sketch/${filename}/${this.state.id}`,
|
||||
});
|
||||
this.setState({ appDialog: true });
|
||||
} else {
|
||||
if (this.state.name) {
|
||||
this.download();
|
||||
} else {
|
||||
@ -141,6 +153,19 @@ class Compile extends Component {
|
||||
"Bitte gib einen Namen für die Bennenung des zu kompilierenden Programms ein und bestätige diesen mit einem Klick auf 'Eingabe'.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// if (this.state.name) {
|
||||
// this.download();
|
||||
// } else {
|
||||
// this.setState({
|
||||
// file: true,
|
||||
// open: true,
|
||||
// title: "Projekt kompilieren",
|
||||
// content:
|
||||
// "Bitte gib einen Namen für die Bennenung des zu kompilierenden Programms ein und bestätige diesen mit einem Klick auf 'Eingabe'.",
|
||||
// });
|
||||
// }
|
||||
};
|
||||
|
||||
setFileName = (e) => {
|
||||
@ -188,6 +213,8 @@ class Compile extends Component {
|
||||
Kompilieren
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{this.props.platform === false ? (
|
||||
<Backdrop
|
||||
className={this.props.classes.backdrop}
|
||||
open={this.state.progress}
|
||||
@ -205,6 +232,25 @@ class Compile extends Component {
|
||||
<CircularProgress color="inherit" />
|
||||
</div>
|
||||
</Backdrop>
|
||||
) : (
|
||||
<Backdrop
|
||||
className={this.props.classes.backdrop}
|
||||
open={this.state.progress}
|
||||
>
|
||||
<div className="overlay">
|
||||
{/* <img src={Copy} width="400" alt="copyimage"></img> */}
|
||||
<h2>Dein Code wird kompiliert!</h2>
|
||||
<p>übertrage ihn anschließend mithlfe der senseBoxConnect-App</p>
|
||||
<p>
|
||||
{Blockly.Msg.compile_overlay_help}
|
||||
<a href="/faq" target="_blank">
|
||||
FAQ
|
||||
</a>
|
||||
</p>
|
||||
<CircularProgress color="inherit" />
|
||||
</div>
|
||||
</Backdrop>
|
||||
)}
|
||||
<Drawer
|
||||
anchor={"bottom"}
|
||||
open={this.state.open}
|
||||
@ -240,29 +286,35 @@ class Compile extends Component {
|
||||
{`${this.state.error}`}{" "}
|
||||
</p>
|
||||
</Drawer>
|
||||
{/* <Dialog
|
||||
open={this.state.open}
|
||||
title={this.state.title}
|
||||
content={this.state.content}
|
||||
<Dialog
|
||||
style={{ zIndex: 9999999 }}
|
||||
fullWidth
|
||||
maxWidth={"sm"}
|
||||
open={this.state.appDialog}
|
||||
title=""
|
||||
content={""}
|
||||
onClose={this.toggleDialog}
|
||||
onClick={this.state.file ? () => { this.toggleDialog(); this.setState({ name: this.props.name }) } : this.toggleDialog}
|
||||
button={this.state.file ? Blockly.Msg.button_cancel : Blockly.Msg.button_close}
|
||||
onClick={this.toggleDialog}
|
||||
button={Blockly.Msg.button_close}
|
||||
>
|
||||
{this.state.file ?
|
||||
<div style={{ marginTop: '10px' }}>
|
||||
<TextField autoFocus placeholder='Dateiname' value={this.state.name} onChange={this.setFileName} style={{ marginRight: '10px' }} />
|
||||
<Button disabled={!this.state.name} variant='contained' color='primary' onClick={() => this.download()}>Eingabe</Button>
|
||||
<div>
|
||||
<p>Dein Code wurde erfolgreich kompiliert</p>
|
||||
<a href={this.state.link}>
|
||||
<Button
|
||||
style={{ color: "white" }}
|
||||
variant="contained"
|
||||
className={this.props.classes.button}
|
||||
onClick={() => this.toggleDialog()}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faClipboardCheck}
|
||||
style={{ marginRight: "5px" }}
|
||||
/>{" "}
|
||||
Starte Übertragung
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
:
|
||||
|
||||
<pre className="line-numbers" style={{ paddingBottom: 0, width: '100%', overflow: 'auto', scrollbarWidth: 'thin', height: '100%', margin: '15px 0', paddingTop: 0, whiteSpace: 'pre-wrap', backgroundColor: 'white' }}><code className="language-json">
|
||||
{`${this.state.error}`}
|
||||
</code></pre>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
|
||||
}
|
||||
</Dialog> */}
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -272,11 +324,13 @@ Compile.propTypes = {
|
||||
arduino: PropTypes.string.isRequired,
|
||||
name: PropTypes.string,
|
||||
workspaceName: PropTypes.func.isRequired,
|
||||
platform: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
arduino: state.workspace.code.arduino,
|
||||
name: state.workspace.name,
|
||||
platform: state.general.platform,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, { workspaceName })(
|
||||
|
@ -1,117 +1,176 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import * as Blockly from 'blockly/core';
|
||||
import * as Blockly from "blockly/core";
|
||||
|
||||
import withWidth, { isWidthDown } from '@material-ui/core/withWidth';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import Popover from '@material-ui/core/Popover';
|
||||
import withWidth, { isWidthDown } from "@material-ui/core/withWidth";
|
||||
import { withStyles } from "@material-ui/core/styles";
|
||||
import Tooltip from "@material-ui/core/Tooltip";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import Chip from "@material-ui/core/Chip";
|
||||
import Avatar from "@material-ui/core/Avatar";
|
||||
import Popover from "@material-ui/core/Popover";
|
||||
|
||||
import { faPuzzlePiece, faTrash, faPlus, faPen, faArrowsAlt, faEllipsisH } from "@fortawesome/free-solid-svg-icons";
|
||||
import {
|
||||
faPuzzlePiece,
|
||||
faTrash,
|
||||
faPlus,
|
||||
faPen,
|
||||
faArrowsAlt,
|
||||
faEllipsisH,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
const styles = (theme) => ({
|
||||
stats: {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
display: 'inline',
|
||||
marginLeft: '50px',
|
||||
padding: '3px 10px',
|
||||
display: "inline",
|
||||
marginLeft: "50px",
|
||||
padding: "3px 10px",
|
||||
// borderRadius: '25%'
|
||||
},
|
||||
menu: {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
color: theme.palette.secondary.contrastText,
|
||||
width: '40px',
|
||||
height: '40px',
|
||||
'&:hover': {
|
||||
width: "40px",
|
||||
height: "40px",
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
color: theme.palette.primary.main,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
class WorkspaceStats extends Component {
|
||||
|
||||
state = {
|
||||
anchor: null
|
||||
}
|
||||
anchor: null,
|
||||
};
|
||||
|
||||
handleClose = () => {
|
||||
this.setState({ anchor: null });
|
||||
}
|
||||
};
|
||||
|
||||
handleClick = (event) => {
|
||||
this.setState({ anchor: event.currentTarget });
|
||||
};
|
||||
|
||||
render() {
|
||||
|
||||
const bigDisplay = !isWidthDown('sm', this.props.width);
|
||||
const bigDisplay = !isWidthDown("sm", this.props.width);
|
||||
const workspace = Blockly.getMainWorkspace();
|
||||
const remainingBlocksInfinity = workspace ? workspace.remainingCapacity() !== Infinity : null;
|
||||
const stats = <div style={bigDisplay ? { display: 'flex' } : { display: 'inline' }}>
|
||||
<Tooltip title="Anzahl aktueller Blöcke" arrow>
|
||||
const remainingBlocksInfinity = workspace
|
||||
? workspace.remainingCapacity() !== Infinity
|
||||
: null;
|
||||
const stats = (
|
||||
<div style={bigDisplay ? { display: "flex" } : { display: "inline" }}>
|
||||
<Tooltip title={Blockly.Msg.tooltip_statistics_current} arrow>
|
||||
<Chip
|
||||
style={bigDisplay ? { marginRight: '1rem' } : { marginRight: '1rem', marginBottom: '5px' }}
|
||||
style={
|
||||
bigDisplay
|
||||
? { marginRight: "1rem" }
|
||||
: { marginRight: "1rem", marginBottom: "5px" }
|
||||
}
|
||||
color="primary"
|
||||
avatar={<Avatar><FontAwesomeIcon icon={faPuzzlePiece} /></Avatar>}
|
||||
label={workspace ? workspace.getAllBlocks().length : 0}>
|
||||
avatar={
|
||||
<Avatar>
|
||||
<FontAwesomeIcon icon={faPuzzlePiece} />
|
||||
</Avatar>
|
||||
}
|
||||
label={workspace ? workspace.getAllBlocks().length : 0}
|
||||
></Chip>
|
||||
</Tooltip>
|
||||
<Tooltip title={Blockly.Msg.tooltip_statistics_new} arrow>
|
||||
<Chip
|
||||
style={
|
||||
bigDisplay
|
||||
? { marginRight: "1rem" }
|
||||
: { marginRight: "1rem", marginBottom: "5px" }
|
||||
}
|
||||
color="primary"
|
||||
avatar={
|
||||
<Avatar>
|
||||
<FontAwesomeIcon icon={faPlus} />
|
||||
</Avatar>
|
||||
}
|
||||
label={this.props.create > 0 ? this.props.create : 0}
|
||||
>
|
||||
{" "}
|
||||
{/* initialXML is created automatically, Block is not part of the statistics */}
|
||||
</Chip>
|
||||
</Tooltip>
|
||||
<Tooltip title="Anzahl neuer Blöcke" arrow>
|
||||
<Tooltip title={Blockly.Msg.tooltip_statistics_changed} arrow>
|
||||
<Chip
|
||||
style={bigDisplay ? { marginRight: '1rem' } : { marginRight: '1rem', marginBottom: '5px' }}
|
||||
style={
|
||||
bigDisplay
|
||||
? { marginRight: "1rem" }
|
||||
: { marginRight: "1rem", marginBottom: "5px" }
|
||||
}
|
||||
color="primary"
|
||||
avatar={<Avatar><FontAwesomeIcon icon={faPlus} /></Avatar>}
|
||||
label={this.props.create > 0 ? this.props.create : 0}> {/* initialXML is created automatically, Block is not part of the statistics */}
|
||||
avatar={
|
||||
<Avatar>
|
||||
<FontAwesomeIcon icon={faPen} />
|
||||
</Avatar>
|
||||
}
|
||||
label={this.props.change}
|
||||
></Chip>
|
||||
</Tooltip>
|
||||
<Tooltip title={Blockly.Msg.tooltip_statistics_moved} arrow>
|
||||
<Chip
|
||||
style={
|
||||
bigDisplay
|
||||
? { marginRight: "1rem" }
|
||||
: { marginRight: "1rem", marginBottom: "5px" }
|
||||
}
|
||||
color="primary"
|
||||
avatar={
|
||||
<Avatar>
|
||||
<FontAwesomeIcon icon={faArrowsAlt} />
|
||||
</Avatar>
|
||||
}
|
||||
label={this.props.move > 0 ? this.props.move : 0}
|
||||
>
|
||||
{" "}
|
||||
{/* initialXML is moved automatically, Block is not part of the statistics */}
|
||||
</Chip>
|
||||
</Tooltip>
|
||||
<Tooltip title="Anzahl veränderter Blöcke" arrow>
|
||||
<Tooltip title={Blockly.Msg.tooltip_statistics_deleted} arrow>
|
||||
<Chip
|
||||
style={bigDisplay ? { marginRight: '1rem' } : { marginRight: '1rem', marginBottom: '5px' }}
|
||||
style={
|
||||
remainingBlocksInfinity
|
||||
? bigDisplay
|
||||
? { marginRight: "1rem" }
|
||||
: { marginRight: "1rem", marginBottom: "5px" }
|
||||
: {}
|
||||
}
|
||||
color="primary"
|
||||
avatar={<Avatar><FontAwesomeIcon icon={faPen} /></Avatar>}
|
||||
label={this.props.change}>
|
||||
</Chip>
|
||||
avatar={
|
||||
<Avatar>
|
||||
<FontAwesomeIcon icon={faTrash} />
|
||||
</Avatar>
|
||||
}
|
||||
label={this.props.delete}
|
||||
></Chip>
|
||||
</Tooltip>
|
||||
<Tooltip title="Anzahl bewegter Blöcke" arrow>
|
||||
{remainingBlocksInfinity ? (
|
||||
<Tooltip title={Blockly.Msg.tooltip_statistics_remaining} arrow>
|
||||
<Chip
|
||||
style={bigDisplay ? { marginRight: '1rem' } : { marginRight: '1rem', marginBottom: '5px' }}
|
||||
style={
|
||||
bigDisplay
|
||||
? { marginRight: "1rem" }
|
||||
: { marginRight: "1rem", marginBottom: "5px" }
|
||||
}
|
||||
color="primary"
|
||||
avatar={<Avatar><FontAwesomeIcon icon={faArrowsAlt} /></Avatar>}
|
||||
label={this.props.move > 0 ? this.props.move : 0}> {/* initialXML is moved automatically, Block is not part of the statistics */}
|
||||
</Chip>
|
||||
label={workspace.remainingCapacity()}
|
||||
></Chip>
|
||||
</Tooltip>
|
||||
<Tooltip title="Anzahl gelöschter Blöcke" arrow>
|
||||
<Chip
|
||||
style={remainingBlocksInfinity ? bigDisplay ? { marginRight: '1rem' } : { marginRight: '1rem', marginBottom: '5px' } : {}}
|
||||
color="primary"
|
||||
avatar={<Avatar><FontAwesomeIcon icon={faTrash} /></Avatar>}
|
||||
label={this.props.delete}>
|
||||
</Chip>
|
||||
</Tooltip>
|
||||
{remainingBlocksInfinity ?
|
||||
<Tooltip title="Verbleibende Blöcke" arrow>
|
||||
<Chip
|
||||
style={bigDisplay ? { marginRight: '1rem' } : { marginRight: '1rem', marginBottom: '5px' }}
|
||||
color="primary"
|
||||
label={workspace.remainingCapacity()}>
|
||||
</Chip>
|
||||
</Tooltip> : null}
|
||||
) : null}
|
||||
</div>
|
||||
return (
|
||||
bigDisplay ?
|
||||
<div style={{ bottom: 0, position: 'absolute' }}>
|
||||
{stats}
|
||||
</div>
|
||||
:
|
||||
);
|
||||
return bigDisplay ? (
|
||||
<div style={{ bottom: 0, position: "absolute" }}>{stats}</div>
|
||||
) : (
|
||||
<div>
|
||||
<Tooltip title='Statistiken anzeigen' arrow>
|
||||
<Tooltip title={Blockly.Msg.tooltip_statistics_show} arrow>
|
||||
<IconButton
|
||||
className={this.props.classes.menu}
|
||||
onClick={(event) => this.handleClick(event)}
|
||||
@ -124,24 +183,22 @@ class WorkspaceStats extends Component {
|
||||
anchorEl={this.state.anchor}
|
||||
onClose={this.handleClose}
|
||||
anchorOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'center',
|
||||
vertical: "bottom",
|
||||
horizontal: "center",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'center',
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
}}
|
||||
PaperProps={{
|
||||
style: { margin: '5px' }
|
||||
style: { margin: "5px" },
|
||||
}}
|
||||
>
|
||||
<div style={{ margin: '10px' }}>
|
||||
{stats}
|
||||
</div>
|
||||
<div style={{ margin: "10px" }}>{stats}</div>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
WorkspaceStats.propTypes = {
|
||||
@ -149,15 +206,18 @@ WorkspaceStats.propTypes = {
|
||||
change: PropTypes.number.isRequired,
|
||||
delete: PropTypes.number.isRequired,
|
||||
move: PropTypes.number.isRequired,
|
||||
workspaceChange: PropTypes.number.isRequired
|
||||
workspaceChange: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state) => ({
|
||||
create: state.workspace.stats.create,
|
||||
change: state.workspace.stats.change,
|
||||
delete: state.workspace.stats.delete,
|
||||
move: state.workspace.stats.move,
|
||||
workspaceChange: state.workspace.change
|
||||
workspaceChange: state.workspace.change,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, null)(withStyles(styles, { withTheme: true })(withWidth()(WorkspaceStats)));
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
null
|
||||
)(withStyles(styles, { withTheme: true })(withWidth()(WorkspaceStats)));
|
||||
|
@ -1,9 +1,7 @@
|
||||
import * as Blockly from 'blockly/core';
|
||||
|
||||
import * as Blockly from "blockly/core";
|
||||
|
||||
export const FaqQuestions = () => {
|
||||
return (
|
||||
[
|
||||
return [
|
||||
{
|
||||
question: `${Blockly.Msg.faq_q1_question}`,
|
||||
answer: `${Blockly.Msg.faq_q1_answer}`,
|
||||
@ -12,10 +10,13 @@ export const FaqQuestions = () => {
|
||||
question: `${Blockly.Msg.faq_q2_question}`,
|
||||
answer: `${Blockly.Msg.faq_q2_answer}`,
|
||||
},
|
||||
{
|
||||
question: `${Blockly.Msg.faq_tablet_question}`,
|
||||
answer: `${Blockly.Msg.faq_tablet_answer}`,
|
||||
},
|
||||
{
|
||||
question: `${Blockly.Msg.faq_q3_question}`,
|
||||
answer: `${Blockly.Msg.faq_q3_answer}`,
|
||||
},
|
||||
|
||||
])
|
||||
}
|
||||
];
|
||||
};
|
||||
|
@ -1,35 +1,69 @@
|
||||
import { VISIT, LANGUAGE, RENDERER, STATISTICS } from '../actions/types';
|
||||
import {
|
||||
VISIT,
|
||||
LANGUAGE,
|
||||
RENDERER,
|
||||
STATISTICS,
|
||||
PLATFORM,
|
||||
} from "../actions/types";
|
||||
|
||||
const initialLanguage = () => {
|
||||
if (window.localStorage.getItem('locale')) {
|
||||
return window.localStorage.getItem('locale');
|
||||
if (window.localStorage.getItem("locale")) {
|
||||
return window.localStorage.getItem("locale");
|
||||
}
|
||||
if (navigator.language === 'de-DE'){
|
||||
return 'de_DE';
|
||||
if (navigator.language === "de-DE") {
|
||||
return "de_DE";
|
||||
}
|
||||
return 'en_US';
|
||||
return "en_US";
|
||||
};
|
||||
|
||||
const initialPlatform = () => {
|
||||
return getPlatform();
|
||||
};
|
||||
|
||||
const getPlatform = () => {
|
||||
if (window.localStorage.getItem("platform")) {
|
||||
return JSON.parse(window.localStorage.getItem("platform"));
|
||||
}
|
||||
var userAgent = window.navigator.userAgent,
|
||||
platform = window.navigator.platform,
|
||||
macosPlatforms = ["Macintosh", "MacIntel", "MacPPC", "Mac68K"],
|
||||
windowsPlatforms = ["Win32", "Win64", "Windows", "WinCE"],
|
||||
iosPlatforms = ["iPhone", "iPad", "iPod"],
|
||||
os = null;
|
||||
if (macosPlatforms.indexOf(platform) !== -1) {
|
||||
os = false;
|
||||
} else if (iosPlatforms.indexOf(platform) !== -1) {
|
||||
os = true;
|
||||
} else if (windowsPlatforms.indexOf(userAgent) !== -1) {
|
||||
os = false;
|
||||
} else if (/Android/.test(userAgent)) {
|
||||
os = true;
|
||||
} else if (!os && /Linux/.test(platform)) {
|
||||
os = false;
|
||||
}
|
||||
return os;
|
||||
};
|
||||
|
||||
const initialRenderer = () => {
|
||||
if (window.localStorage.getItem('renderer')) {
|
||||
return window.localStorage.getItem('renderer');
|
||||
if (window.localStorage.getItem("renderer")) {
|
||||
return window.localStorage.getItem("renderer");
|
||||
}
|
||||
return 'geras';
|
||||
return "geras";
|
||||
};
|
||||
|
||||
const initialStatistics = () => {
|
||||
if (window.localStorage.getItem('statistics')) {
|
||||
return JSON.parse(window.localStorage.getItem('statistics'));
|
||||
if (window.localStorage.getItem("statistics")) {
|
||||
return JSON.parse(window.localStorage.getItem("statistics"));
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
const initialState = {
|
||||
pageVisits: 0, // detect if previous URL was
|
||||
language: initialLanguage(),
|
||||
renderer: initialRenderer(),
|
||||
statistics: initialStatistics()
|
||||
statistics: initialStatistics(),
|
||||
platform: initialPlatform(),
|
||||
};
|
||||
|
||||
export default function foo(state = initialState, action) {
|
||||
@ -37,24 +71,30 @@ export default function foo(state = initialState, action){
|
||||
case VISIT:
|
||||
return {
|
||||
...state,
|
||||
pageVisits: state.pageVisits += 1
|
||||
pageVisits: (state.pageVisits += 1),
|
||||
};
|
||||
case LANGUAGE:
|
||||
return {
|
||||
...state,
|
||||
language: action.payload
|
||||
language: action.payload,
|
||||
};
|
||||
case PLATFORM:
|
||||
window.localStorage.setItem("platform", action.payload);
|
||||
return {
|
||||
...state,
|
||||
platform: action.payload,
|
||||
};
|
||||
case RENDERER:
|
||||
window.localStorage.setItem('renderer', action.payload);
|
||||
window.localStorage.setItem("renderer", action.payload);
|
||||
return {
|
||||
...state,
|
||||
renderer: action.payload
|
||||
renderer: action.payload,
|
||||
};
|
||||
case STATISTICS:
|
||||
window.localStorage.setItem('statistics', action.payload);
|
||||
window.localStorage.setItem("statistics", action.payload);
|
||||
return {
|
||||
...state,
|
||||
statistics: action.payload
|
||||
statistics: action.payload,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
|
Loading…
x
Reference in New Issue
Block a user