diff --git a/src/App.js b/src/App.js index 1eccac4..ef9ca04 100644 --- a/src/App.js +++ b/src/App.js @@ -11,10 +11,7 @@ import './App.css'; import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles'; -import Navbar from './components/Navbar'; -import Footer from './components/Footer'; -import Routes from './components/Route/Routes'; -import Cookies from './components/Cookies'; +import Content from './components/Content'; const theme = createMuiTheme({ palette: { @@ -43,12 +40,7 @@ class App extends Component { -
- - - -
-
+
diff --git a/src/actions/generalActions.js b/src/actions/generalActions.js index 6585a9a..3bd0c64 100644 --- a/src/actions/generalActions.js +++ b/src/actions/generalActions.js @@ -1,4 +1,4 @@ -import { VISIT } from './types'; +import { VISIT, LANGUAGE, RENDERER, STATISTICS } from './types'; export const visitPage = () => (dispatch) => { @@ -6,3 +6,24 @@ export const visitPage = () => (dispatch) => { type: VISIT }); }; + +export const setLanguage = (language) => (dispatch) => { + dispatch({ + type: LANGUAGE, + payload: language + }); +}; + +export const setRenderer = (renderer) => (dispatch) => { + dispatch({ + type: RENDERER, + payload: renderer + }); +}; + +export const setStatistics = (showStatistics) => (dispatch) => { + dispatch({ + type: STATISTICS, + payload: showStatistics + }); +}; diff --git a/src/actions/types.js b/src/actions/types.js index b3bff75..3e80a5e 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -46,6 +46,9 @@ export const PROGRESS = 'PROGRESS'; export const VISIT = 'VISIT'; +export const LANGUAGE = 'LANGUAGE'; +export const RENDERER = 'RENDERER'; +export const STATISTICS = 'STATISTICS'; // messages export const GET_ERRORS = 'GET_ERRORS'; diff --git a/src/components/Blockly/BlocklyWindow.js b/src/components/Blockly/BlocklyWindow.js index f3c680d..60b3ee3 100644 --- a/src/components/Blockly/BlocklyWindow.js +++ b/src/components/Blockly/BlocklyWindow.js @@ -18,26 +18,21 @@ class BlocklyWindow extends Component { constructor(props) { super(props); this.simpleWorkspace = React.createRef(); - 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') { + // if (locale === null) { + // if (navigator.language === 'de-DE') { + // locale = 'de'; + // } else { + // locale = 'en'; + // } + // } + if (this.props.language === 'de') { Blockly.setLocale(De); - } else if (locale === 'en') { + } else if (this.props.language === 'en') { Blockly.setLocale(En); } } componentDidMount() { - const workspace = Blockly.getMainWorkspace(); this.props.onChangeWorkspace({}); this.props.clearStats(); @@ -72,7 +67,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={this.state.renderer} + renderer={this.props.renderer} zoom={{ // https://developers.google.com/blockly/guides/configure/web/zoom controls: this.props.zoomControls !== undefined ? this.props.zoomControls : true, wheel: false, @@ -106,8 +101,14 @@ class BlocklyWindow extends Component { BlocklyWindow.propTypes = { onChangeWorkspace: PropTypes.func.isRequired, - clearStats: PropTypes.func.isRequired + clearStats: PropTypes.func.isRequired, + renderer: PropTypes.string.isRequired, + language: PropTypes.string.isRequired }; +const mapStateToProps = state => ({ + renderer: state.general.renderer, + language: state.general.language +}); -export default connect(null, { onChangeWorkspace, clearStats })(BlocklyWindow); +export default connect(mapStateToProps, { onChangeWorkspace, clearStats })(BlocklyWindow); diff --git a/src/components/Blockly/msg/de.js b/src/components/Blockly/msg/de.js index cca4e12..f8f8abb 100644 --- a/src/components/Blockly/msg/de.js +++ b/src/components/Blockly/msg/de.js @@ -804,7 +804,7 @@ Blockly.Msg.senseBox_mqtt_publish = "Sende an Feed/Topic"; /** * Typed Variable Modal - * + * */ @@ -835,7 +835,7 @@ Blockly.Msg.toolbox_variables = "Variablen"; /** * Tooltips - * + * */ Blockly.Msg.tooltip_compile_code = "Code kompilieren" @@ -863,7 +863,7 @@ Blockly.Msg.tooltip_project_title = "Titel des Projektes" /** * Messages - * + * */ Blockly.Msg.messages_delete_project_failed = "Fehler beim Löschen des Projektes. Versuche es noch einmal." @@ -895,7 +895,7 @@ Blockly.Msg.renamedialog_text = "Bitte gib einen Namen für das Projekt ein und /** * Compile Dialog - * + * */ Blockly.Msg.compiledialog_headline = "Fehler" @@ -903,7 +903,7 @@ Blockly.Msg.compiledialog_text = "Beim kompilieren ist ein Fehler aufgetreten. /** * Buttons - * + * */ Blockly.Msg.button_cancel = "Abbrechen"; @@ -915,7 +915,7 @@ Blockly.Msg.button_back = "Zurück" /** - * + * */ Blockly.Msg.filename = "Dateiname"; @@ -926,9 +926,15 @@ Blockly.Msg.projectname = "Projektname"; */ Blockly.Msg.settings_head = "Einstellungen" Blockly.Msg.settings_language = "Sprache" +Blockly.Msg.settings_language_text = "Auswahl der Sprache gilt für die gesamte Anwendung. Es kann zwischen Deutsch und Englisch unterschieden werden." Blockly.Msg.settings_language_de = "Deutsch" Blockly.Msg.settings_language_en = "Englisch" -Blockly.Msg.settings_renderer_text = "Der Renderer bestimmt das aussehen der Blöcke" +Blockly.Msg.settings_renderer = "Renderer" +Blockly.Msg.settings_renderer_text = "Der eingestellte Renderer bestimmt das Aussehen der Blöcke. Es kann zwischen 'Geras' und 'Zelos' unterschieden werden, wobei 'Zelos' insbesondere für eine Touch-Anwendung geeignet ist." +Blockly.Msg.settings_statistics = "Statistiken" +Blockly.Msg.settings_statistics_text = "Die Anzeige von Statistiken zur Nutzung der Blöcke oberhalb der Arbeitsfläche kann ein- oder ausgeblendet werden." +Blockly.Msg.settings_statistics_on = "An" +Blockly.Msg.settings_statistics_off = "Aus" /** * 404 diff --git a/src/components/Blockly/msg/en.js b/src/components/Blockly/msg/en.js index 6479613..b895bac 100644 --- a/src/components/Blockly/msg/en.js +++ b/src/components/Blockly/msg/en.js @@ -805,7 +805,7 @@ Blockly.Msg.toolbox_variables = "Variables"; /** * Tooltips - * + * */ Blockly.Msg.tooltip_compile_code = "Compile Code" @@ -834,7 +834,7 @@ Blockly.Msg.renamedialog_text = "Please enter a name for the project and confirm /** * Compile Dialog - * + * */ Blockly.Msg.compiledialog_headline = "Error" @@ -844,7 +844,7 @@ Blockly.Msg.compiledialog_text = "While compiling an error occured. Please check /** * Buttons - * + * */ Blockly.Msg.button_cancel = "Cancel"; @@ -855,12 +855,26 @@ Blockly.Msg.button_create_variableCreate = "Create Variable"; /** - * + * */ Blockly.Msg.filename = "Filename"; Blockly.Msg.projectname = "Projectname"; +/** + * Settings + */ +Blockly.Msg.settings_head = "Settings" +Blockly.Msg.settings_language = "Language" +Blockly.Msg.settings_language_text = "Selection of the language applies to the entire application. A distinction can be made between German and English." +Blockly.Msg.settings_language_de = "German" +Blockly.Msg.settings_language_en = "English" +Blockly.Msg.settings_renderer = "Renderer" +Blockly.Msg.settings_renderer_text = "The selected renderer determines the appearance of the blocks. A distinction can be made between 'Geras' and 'Zelos', whereby 'Zelos' is particularly suitable for a touch application." +Blockly.Msg.settings_statistics = "Statistics" +Blockly.Msg.settings_statistics_text = "The display of statistics on the usage of the blocks above the workspace can be shown or hidden." +Blockly.Msg.settings_statistics_on = "On" +Blockly.Msg.settings_statistics_off = "Off" diff --git a/src/components/Content.js b/src/components/Content.js new file mode 100644 index 0000000..38e6b85 --- /dev/null +++ b/src/components/Content.js @@ -0,0 +1,54 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; + +import * as Blockly from 'blockly/core'; +import { De } from './Blockly/msg/de'; +import { En } from './Blockly/msg/en'; + +import Navbar from './Navbar'; +import Footer from './Footer'; +import Routes from './Route/Routes'; +import Cookies from './Cookies'; + +class Content extends Component { + + componentDidMount() { + if (this.props.language === 'de') { + Blockly.setLocale(De); + } else if (this.props.language === 'en') { + Blockly.setLocale(En); + } + } + + componentDidUpdate(props){ + if(props.language !== this.props.language){ + if (this.props.language === 'de') { + Blockly.setLocale(De); + } else if (this.props.language === 'en') { + Blockly.setLocale(En); + } + } + } + + render() { + return ( +
+ + + +
+ ); + } +} + +Content.propTypes = { + language: PropTypes.string.isRequired +}; + +const mapStateToProps = state => ({ + language: state.general.language +}); + +export default connect(mapStateToProps, null)(Content); diff --git a/src/components/Home.js b/src/components/Home.js index 7c385ac..f5ec9cb 100644 --- a/src/components/Home.js +++ b/src/components/Home.js @@ -48,7 +48,6 @@ class Home extends Component { state = { codeOn: false, - stats: window.localStorage.getItem('stats'), snackbar: false, type: '', key: '', @@ -91,7 +90,7 @@ class Home extends Component { render() { return (
- {this.state.stats ? + {this.props.statistics ?
: null } @@ -136,11 +135,13 @@ class Home extends Component { Home.propTypes = { clearStats: PropTypes.func.isRequired, workspaceName: PropTypes.func.isRequired, - message: PropTypes.object.isRequired + message: PropTypes.object.isRequired, + statistics: PropTypes.bool.isRequired }; const mapStateToProps = state => ({ - message: state.message + message: state.message, + statistics: state.general.statistics }); diff --git a/src/components/NotFound.js b/src/components/NotFound.js index eb790f4..01b03f7 100644 --- a/src/components/NotFound.js +++ b/src/components/NotFound.js @@ -9,6 +9,13 @@ import Typography from '@material-ui/core/Typography'; import * as Blockly from 'blockly' class NotFound 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 (
diff --git a/src/components/Settings/LanguageSelector.js b/src/components/Settings/LanguageSelector.js index 7da299c..7164868 100644 --- a/src/components/Settings/LanguageSelector.js +++ b/src/components/Settings/LanguageSelector.js @@ -1,44 +1,58 @@ -import React from 'react'; -import { makeStyles } from '@material-ui/core/styles'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { setLanguage } 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 * as Blockly from 'blockly/core'; +import Typography from '@material-ui/core/Typography'; +import FormHelperText from '@material-ui/core/FormHelperText'; -const useStyles = makeStyles((theme) => ({ - formControl: { - margin: theme.spacing(1), - minWidth: 120, - }, - selectEmpty: { - marginTop: theme.spacing(2), - }, -})); +class LanguageSelector extends Component { -export default function LanguageSelector() { - const classes = useStyles(); - const [lang, setLang] = React.useState(window.localStorage.getItem('locale')); + 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(); + } - const handleChange = (event) => { - setLang(event.target.value); - window.localStorage.setItem('locale', event.target.value); - }; + handleChange = (event) => { + this.props.setLanguage(event.target.value); + } - return ( -
- - {Blockly.Msg.settings_language} - - -
+ render(){ + return( +
+ {Blockly.Msg.settings_language} + {Blockly.Msg.settings_language_text} + + {Blockly.Msg.settings_language} + + +
); + } } + +LanguageSelector.propTypes = { + setLanguage: PropTypes.func.isRequired, + language: PropTypes.string.isRequired +}; + +const mapStateToProps = state => ({ + language: state.general.language +}); + +export default connect(mapStateToProps, { setLanguage })(LanguageSelector); diff --git a/src/components/Settings/RenderSelector.js b/src/components/Settings/RenderSelector.js index d8284b6..7359283 100644 --- a/src/components/Settings/RenderSelector.js +++ b/src/components/Settings/RenderSelector.js @@ -1,45 +1,57 @@ -import React from 'react'; -import { makeStyles } from '@material-ui/core/styles'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { setRenderer } 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 * as Blockly from 'blockly/core' -const useStyles = makeStyles((theme) => ({ - formControl: { - margin: theme.spacing(1), - minWidth: 400, - }, - selectEmpty: { - marginTop: theme.spacing(2), - }, -})); +import Typography from '@material-ui/core/Typography'; +import FormHelperText from '@material-ui/core/FormHelperText'; -export default function RenderSelector() { - 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); - }; +class RenderSelector 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 ( -
- - Renderer - - -

{Blockly.Msg.settings_renderer_text}

-
+
+ {Blockly.Msg.settings_renderer} + {Blockly.Msg.settings_renderer_text} + + {Blockly.Msg.settings_renderer} + + +
); + } } + +RenderSelector.propTypes = { + setRenderer: PropTypes.func.isRequired, + language: PropTypes.string.isRequired, + renderer: PropTypes.string.isRequired +}; + +const mapStateToProps = state => ({ + renderer: state.general.renderer, + language: state.general.language +}); + +export default connect(mapStateToProps, { setRenderer })(RenderSelector); diff --git a/src/components/Settings/Settings.js b/src/components/Settings/Settings.js index d43f33f..24b3bfa 100644 --- a/src/components/Settings/Settings.js +++ b/src/components/Settings/Settings.js @@ -1,32 +1,65 @@ import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; + import { withRouter } from 'react-router-dom'; -import Button from '@material-ui/core/Button'; -import Typography from '@material-ui/core/Typography'; +import * as Blockly from 'blockly/core'; + +import Breadcrumbs from '../Breadcrumbs'; import LanguageSelector from './LanguageSelector'; import RenderSelector from './RenderSelector'; import StatsSelector from './StatsSelector'; -import * as Blockly from 'blockly' + +import Button from '@material-ui/core/Button'; +import Paper from '@material-ui/core/Paper'; class Settings extends Component { - render() { - return ( -
- {Blockly.Msg.settings_head} - - - - -
- ); - }; + + 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 ( +
+ + +

{Blockly.Msg.settings_head}

+ + + + + + + + + + + + +
+ ); + }; } -export default withRouter(Settings); +Settings.propTypes = { + language: PropTypes.string.isRequired, + pageVisits: PropTypes.number.isRequired +}; + +const mapStateToProps = state => ({ + language: state.general.language, + pageVisits: state.general.pageVisits +}); + +export default connect(mapStateToProps, null)(withRouter(Settings)); diff --git a/src/components/Settings/StatsSelector.js b/src/components/Settings/StatsSelector.js index 8c1322d..b0b3cfe 100644 --- a/src/components/Settings/StatsSelector.js +++ b/src/components/Settings/StatsSelector.js @@ -1,44 +1,56 @@ -import React from 'react'; -import { makeStyles } from '@material-ui/core/styles'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { setStatistics } 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'; -const useStyles = makeStyles((theme) => ({ - formControl: { - margin: theme.spacing(1), - minWidth: 400, - }, - selectEmpty: { - marginTop: theme.spacing(2), - }, -})); +class StatsSelector extends Component { -export default function StatsSelector() { - const classes = useStyles(); - const [stats, setStats] = React.useState(window.localStorage.getItem('stats')); - - const handleChange = (event) => { - setStats(event.target.value); - window.localStorage.setItem('stats', event.target.value); - }; + 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 ( -
- - Statistiken - - -

Schaltet die Statistiken Oberhalb der Arbeitsfläche ein bzw. aus

-
+
+ {Blockly.Msg.settings_statistics} + {Blockly.Msg.settings_statistics_text} + + {Blockly.Msg.settings_statistics} + + +
); + } } + +StatsSelector.propTypes = { + setStatistics: PropTypes.func.isRequired, + language: PropTypes.string.isRequired, + statistics: PropTypes.bool.isRequired +}; + +const mapStateToProps = state => ({ + statistics: state.general.statistics, + language: state.general.language +}); + +export default connect(mapStateToProps, { setStatistics })(StatsSelector); diff --git a/src/reducers/generalReducer.js b/src/reducers/generalReducer.js index 2d1c875..35ab59a 100644 --- a/src/reducers/generalReducer.js +++ b/src/reducers/generalReducer.js @@ -1,8 +1,11 @@ -import { VISIT } from '../actions/types'; +import { VISIT, LANGUAGE, RENDERER, STATISTICS } from '../actions/types'; const initialState = { - pageVisits: 0 // detect if previous URL was + pageVisits: 0, // detect if previous URL was + language: 'de', + renderer: window.localStorage.getItem('renderer') || 'geras', + statistics: window.localStorage.getItem('statistics') === 'true' ? true : window.localStorage.getItem('statistics') === 'false' ? false : false }; export default function(state = initialState, action){ @@ -12,6 +15,23 @@ export default function(state = initialState, action){ ...state, pageVisits: state.pageVisits += 1 }; + case LANGUAGE: + return { + ...state, + language: action.payload + }; + case RENDERER: + window.localStorage.setItem('renderer', action.payload); + return { + ...state, + renderer: action.payload + }; + case STATISTICS: + window.localStorage.setItem('statistics', action.payload); + return { + ...state, + statistics: action.payload + }; default: return state; }