init senseBox connect features

This commit is contained in:
Mario Pesch 2021-10-01 15:06:22 +02:00
parent e528a78e77
commit faabd9e693
5 changed files with 237 additions and 102 deletions

View File

@ -1,32 +1,38 @@
import { VISIT, LANGUAGE, RENDERER, STATISTICS } from './types'; import { VISIT, LANGUAGE, RENDERER, STATISTICS, PLATFORM } from "./types";
export const visitPage = () => (dispatch) => { export const visitPage = () => (dispatch) => {
dispatch({ dispatch({
type: VISIT type: VISIT,
});
};
export const setPlatform = (platform) => (dispatch) => {
dispatch({
type: PLATFORM,
payload: platform,
}); });
}; };
export const setLanguage = (language) => (dispatch, getState) => { export const setLanguage = (language) => (dispatch, getState) => {
if(!getState().auth.progress && !getState().auth.isAuthenticated){ if (!getState().auth.progress && !getState().auth.isAuthenticated) {
window.localStorage.setItem('locale', language); window.localStorage.setItem("locale", language);
} }
dispatch({ dispatch({
type: LANGUAGE, type: LANGUAGE,
payload: language payload: language,
}); });
}; };
export const setRenderer = (renderer) => (dispatch) => { export const setRenderer = (renderer) => (dispatch) => {
dispatch({ dispatch({
type: RENDERER, type: RENDERER,
payload: renderer payload: renderer,
}); });
}; };
export const setStatistics = (showStatistics) => (dispatch) => { export const setStatistics = (showStatistics) => (dispatch) => {
dispatch({ dispatch({
type: STATISTICS, type: STATISTICS,
payload: showStatistics payload: showStatistics,
}); });
}; };

View File

@ -43,6 +43,7 @@ export const PROGRESS = "PROGRESS";
export const VISIT = "VISIT"; export const VISIT = "VISIT";
export const LANGUAGE = "LANGUAGE"; export const LANGUAGE = "LANGUAGE";
export const PLATFORM = "PLATFORM";
export const RENDERER = "RENDERER"; export const RENDERER = "RENDERER";
export const STATISTICS = "STATISTICS"; export const STATISTICS = "STATISTICS";

View File

@ -1,68 +1,72 @@
import React, { Component } from 'react'; import React, { Component } from "react";
import PropTypes from 'prop-types'; import PropTypes from "prop-types";
import { connect } from 'react-redux'; import { connect } from "react-redux";
import { clearStats, workspaceName } from '../actions/workspaceActions'; import { clearStats, workspaceName } from "../actions/workspaceActions";
import * as Blockly from 'blockly/core'; import * as Blockly from "blockly/core";
import { createNameId } from 'mnemonic-id'; import { createNameId } from "mnemonic-id";
import WorkspaceStats from './Workspace/WorkspaceStats'; import WorkspaceStats from "./Workspace/WorkspaceStats";
import WorkspaceFunc from './Workspace/WorkspaceFunc'; import WorkspaceFunc from "./Workspace/WorkspaceFunc";
import BlocklyWindow from './Blockly/BlocklyWindow'; import BlocklyWindow from "./Blockly/BlocklyWindow";
import CodeViewer from './CodeViewer'; import CodeViewer from "./CodeViewer";
import TrashcanButtons from './Workspace/TrashcanButtons'; import TrashcanButtons from "./Workspace/TrashcanButtons";
import HintTutorialExists from './Tutorial/HintTutorialExists'; import HintTutorialExists from "./Tutorial/HintTutorialExists";
import Snackbar from './Snackbar';
import Grid from '@material-ui/core/Grid'; import Grid from "@material-ui/core/Grid";
import IconButton from '@material-ui/core/IconButton'; import IconButton from "@material-ui/core/IconButton";
import Tooltip from '@material-ui/core/Tooltip'; import Tooltip from "@material-ui/core/Tooltip";
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from "@material-ui/core/styles";
import { faCode } from "@fortawesome/free-solid-svg-icons"; import { faCode } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import TooltipViewer from './TooltipViewer'; import TooltipViewer from "./TooltipViewer";
import Dialog from "./Dialog";
const styles = (theme) => ({ const styles = (theme) => ({
codeOn: { codeOn: {
backgroundColor: theme.palette.primary.main, backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText, color: theme.palette.primary.contrastText,
'&:hover': { "&:hover": {
backgroundColor: theme.palette.primary.contrastText, backgroundColor: theme.palette.primary.contrastText,
color: theme.palette.primary.main, color: theme.palette.primary.main,
border: `1px solid ${theme.palette.secondary.main}` border: `1px solid ${theme.palette.secondary.main}`,
} },
}, },
codeOff: { codeOff: {
backgroundColor: theme.palette.primary.contrastText, backgroundColor: theme.palette.primary.contrastText,
color: theme.palette.primary.main, color: theme.palette.primary.main,
border: `1px solid ${theme.palette.secondary.main}`, border: `1px solid ${theme.palette.secondary.main}`,
'&:hover': { "&:hover": {
backgroundColor: theme.palette.primary.main, backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText, color: theme.palette.primary.contrastText,
} },
} },
}); });
class Home extends Component { class Home extends Component {
state = { state = {
codeOn: true, codeOn: true,
snackbar: false, snackbar: false,
type: '', type: "",
key: '', key: "",
message: '' message: "",
} open: true,
};
componentDidMount() { componentDidMount() {
this.setState({ stats: window.localStorage.getItem('stats') }); console.log(this.props.platform);
this.setState({ stats: window.localStorage.getItem("stats") });
if (!this.props.project) { if (!this.props.project) {
this.props.workspaceName(createNameId()); this.props.workspaceName(createNameId());
} }
if (this.props.message && this.props.message.id === 'GET_SHARE_FAIL') { 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' }); this.setState({
snackbar: true,
key: Date.now(),
message: `Das angefragte geteilte Projekt konnte nicht gefunden werden.`,
type: "error",
});
} }
} }
@ -80,6 +84,10 @@ class Home extends Component {
this.props.workspaceName(null); this.props.workspaceName(null);
} }
toggleDialog = () => {
this.setState({ open: !this.state });
};
onChange = () => { onChange = () => {
this.setState({ codeOn: !this.state.codeOn }); this.setState({ codeOn: !this.state.codeOn });
const workspace = Blockly.getMainWorkspace(); const workspace = Blockly.getMainWorkspace();
@ -87,67 +95,113 @@ class Home extends Component {
if (workspace.trashcan && workspace.trashcan.flyout) { if (workspace.trashcan && workspace.trashcan.flyout) {
workspace.trashcan.flyout.hide(); // in case of resize, the trash flyout does not reposition workspace.trashcan.flyout.hide(); // in case of resize, the trash flyout does not reposition
} }
} };
render() { render() {
return ( return (
<div> <div>
{this.props.statistics ? {this.props.statistics ? (
<div style={{ float: 'left', height: '40px', position: 'relative' }}><WorkspaceStats /></div> <div style={{ float: "left", height: "40px", position: "relative" }}>
: null <WorkspaceStats />
} </div>
<div className='workspaceFunc' style={{ float: 'right', height: '40px', marginBottom: '20px' }}> ) : null}
<WorkspaceFunc project={this.props.project} projectType={this.props.projectType} /> <div
className="workspaceFunc"
style={{ float: "right", height: "40px", marginBottom: "20px" }}
>
<WorkspaceFunc
project={this.props.project}
projectType={this.props.projectType}
/>
</div> </div>
<Grid container spacing={2}> <Grid container spacing={2}>
<Grid item xs={12} md={this.state.codeOn ? 8 : 12} style={{ position: 'relative' }}> <Grid
<Tooltip title={this.state.codeOn ? 'Code ausblenden' : 'Code anzeigen'} > item
xs={12}
md={this.state.codeOn ? 8 : 12}
style={{ position: "relative" }}
>
<Tooltip
title={this.state.codeOn ? "Code ausblenden" : "Code anzeigen"}
>
<IconButton <IconButton
className={`showCode ${this.state.codeOn ? this.props.classes.codeOn : this.props.classes.codeOff}`} className={`showCode ${
style={{ width: '40px', height: '40px', position: 'absolute', top: -12, right: 8, zIndex: 21 }} 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()} onClick={() => this.onChange()}
> >
<FontAwesomeIcon icon={faCode} size="xs" /> <FontAwesomeIcon icon={faCode} size="xs" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<TrashcanButtons /> <TrashcanButtons />
<div className='blocklyWindow'> <div className="blocklyWindow">
{this.props.project ? {this.props.project ? (
< BlocklyWindow blocklyCSS={{ height: '80vH' }} initialXml={this.props.project.xml} /> <BlocklyWindow
: < BlocklyWindow blocklyCSS={{ height: '80vH' }} /> blocklyCSS={{ height: "80vH" }}
} initialXml={this.props.project.xml}
/>
) : (
<BlocklyWindow blocklyCSS={{ height: "80vH" }} />
)}
</div> </div>
</Grid> </Grid>
{this.state.codeOn ? {this.state.codeOn ? (
<Grid item xs={12} md={4}> <Grid item xs={12} md={4}>
<CodeViewer /> <CodeViewer />
<TooltipViewer /> <TooltipViewer />
</Grid> </Grid>
: null} ) : null}
</Grid> </Grid>
<HintTutorialExists /> <HintTutorialExists />
<Snackbar {this.props.platform ? (
open={this.state.snackbar} <Dialog
message={this.state.message} style={{ zIndex: 9999999 }}
type={this.state.type} fullWidth
key={this.state.key} maxWidth={"sm"}
/> open={this.state.open}
title=""
content={""}
onClose={this.toggleDialog}
onClick={this.toggleDialog}
button={Blockly.Msg.button_close}
>
<div>Du verwendest: {this.props.platform}</div>
<div>Lade die App hier herunter: </div>
<div>
Testlink:{" "}
<a href="blocklyconnect-app://sketch/123456">Öffne App</a>
</div>
</Dialog>
) : null}
</div> </div>
); );
}; }
} }
Home.propTypes = { Home.propTypes = {
clearStats: PropTypes.func.isRequired, clearStats: PropTypes.func.isRequired,
workspaceName: PropTypes.func.isRequired, workspaceName: PropTypes.func.isRequired,
message: PropTypes.object.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, message: state.message,
statistics: state.general.statistics statistics: state.general.statistics,
platform: state.general.platform,
}); });
export default connect(mapStateToProps, { clearStats, workspaceName })(
export default connect(mapStateToProps, { clearStats, workspaceName })(withStyles(styles, { withTheme: true })(Home)); withStyles(styles, { withTheme: true })(Home)
);

View File

@ -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";
import "prismjs/plugins/line-numbers/prism-line-numbers.css"; import "prismjs/plugins/line-numbers/prism-line-numbers.css";
import MuiDrawer from "@material-ui/core/Drawer"; import MuiDrawer from "@material-ui/core/Drawer";
import Dialog from "../Dialog";
const styles = (theme) => ({ const styles = (theme) => ({
backdrop: { backdrop: {
@ -65,6 +66,8 @@ class Compile extends Component {
content: "", content: "",
name: props.name, name: props.name,
error: "", error: "",
appLink: "",
appDialog: false,
}; };
} }
@ -126,21 +129,40 @@ class Compile extends Component {
}; };
toggleDialog = () => { toggleDialog = () => {
this.setState({ open: !this.state, progress: false }); this.setState({ open: !this.state, progress: false, appDialog: false });
}; };
createFileName = () => { createFileName = () => {
if (this.state.name) { if (this.props.platform === "iOS") {
this.download();
} else {
this.setState({ this.setState({
file: true, link: `blocklyconnect-app://${this.state.name}/${this.state.id}`,
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'.",
}); });
this.setState({ appDialog: true });
} else {
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'.",
});
}
} }
// 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) => { setFileName = (e) => {
@ -240,6 +262,24 @@ class Compile extends Component {
{`${this.state.error}`}{" "} {`${this.state.error}`}{" "}
</p> </p>
</Drawer> </Drawer>
<Dialog
style={{ zIndex: 9999999 }}
fullWidth
maxWidth={"sm"}
open={this.state.appDialog}
title=""
content={""}
onClose={this.toggleDialog}
onClick={this.toggleDialog}
button={Blockly.Msg.button_close}
>
<div>Du verwendest: {this.props.platform}</div>
<div>Lade die App hier herunter: </div>
<div>
Testlink: <a href={this.state.link}>Öffne App</a>
</div>
</Dialog>
{/* <Dialog {/* <Dialog
open={this.state.open} open={this.state.open}
title={this.state.title} title={this.state.title}
@ -272,11 +312,13 @@ Compile.propTypes = {
arduino: PropTypes.string.isRequired, arduino: PropTypes.string.isRequired,
name: PropTypes.string, name: PropTypes.string,
workspaceName: PropTypes.func.isRequired, workspaceName: PropTypes.func.isRequired,
platform: PropTypes.object.isRequired,
}; };
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => ({
arduino: state.workspace.code.arduino, arduino: state.workspace.code.arduino,
name: state.workspace.name, name: state.workspace.name,
platform: state.general.platform,
}); });
export default connect(mapStateToProps, { workspaceName })( export default connect(mapStateToProps, { workspaceName })(

View File

@ -1,60 +1,92 @@
import { VISIT, LANGUAGE, RENDERER, STATISTICS } from '../actions/types'; import {
VISIT,
LANGUAGE,
RENDERER,
STATISTICS,
PLATFORM,
} from "../actions/types";
const initialLanguage = () => { const initialLanguage = () => {
if (window.localStorage.getItem('locale')) { if (window.localStorage.getItem("locale")) {
return window.localStorage.getItem('locale'); return window.localStorage.getItem("locale");
} }
if (navigator.language === 'de-DE'){ if (navigator.language === "de-DE") {
return 'de_DE'; return "de_DE";
} }
return 'en_US'; return "en_US";
};
const getPlatform = () => {
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 = "Mac OS";
} else if (iosPlatforms.indexOf(platform) !== -1) {
os = "iOS";
} else if (windowsPlatforms.indexOf(userAgent) !== -1) {
os = "Windows";
} else if (/Android/.test(userAgent)) {
os = "Android";
} else if (!os && /Linux/.test(platform)) {
os = "Linux";
}
return os;
}; };
const initialRenderer = () => { const initialRenderer = () => {
if (window.localStorage.getItem('renderer')) { if (window.localStorage.getItem("renderer")) {
return window.localStorage.getItem('renderer'); return window.localStorage.getItem("renderer");
} }
return 'geras'; return "geras";
}; };
const initialStatistics = () => { const initialStatistics = () => {
if (window.localStorage.getItem('statistics')) { if (window.localStorage.getItem("statistics")) {
return JSON.parse(window.localStorage.getItem('statistics')); return JSON.parse(window.localStorage.getItem("statistics"));
} }
return false; return false;
}; };
const initialState = { const initialState = {
pageVisits: 0, // detect if previous URL was pageVisits: 0, // detect if previous URL was
language: initialLanguage(), language: initialLanguage(),
renderer: initialRenderer(), renderer: initialRenderer(),
statistics: initialStatistics() statistics: initialStatistics(),
platform: getPlatform(),
}; };
export default function foo(state = initialState, action){ export default function foo(state = initialState, action) {
switch(action.type){ switch (action.type) {
case VISIT: case VISIT:
return { return {
...state, ...state,
pageVisits: state.pageVisits += 1 pageVisits: (state.pageVisits += 1),
}; };
case LANGUAGE: case LANGUAGE:
return { return {
...state, ...state,
language: action.payload language: action.payload,
};
case PLATFORM:
return {
...state,
platform: action.payload,
}; };
case RENDERER: case RENDERER:
window.localStorage.setItem('renderer', action.payload); window.localStorage.setItem("renderer", action.payload);
return { return {
...state, ...state,
renderer: action.payload renderer: action.payload,
}; };
case STATISTICS: case STATISTICS:
window.localStorage.setItem('statistics', action.payload); window.localStorage.setItem("statistics", action.payload);
return { return {
...state, ...state,
statistics: action.payload statistics: action.payload,
}; };
default: default:
return state; return state;