sandbox: finished result view; fixed some styling issues

feature/109
Christoph Oberhofer 9 years ago
parent bad79020a9
commit 435430b8fa

@ -10,7 +10,7 @@
<meta name="author" content="Christoph Oberhofer" /> <meta name="author" content="Christoph Oberhofer" />
<link rel="stylesheet" type="text/css" href="static/style.css" /> <link rel="stylesheet" type="text/css" href="static/style.css" />
<meta name="viewport" content="width=device-width; initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1">
<link href='https://fonts.googleapis.com/css?family=Roboto:400,300,500' rel='stylesheet' type='text/css'> <link href='https://fonts.googleapis.com/css?family=Roboto:400,300,500' rel='stylesheet' type='text/css'>
</head> </head>

@ -4,13 +4,15 @@ import Drawer from 'material-ui/Drawer';
import FloatingActionButton from 'material-ui/FloatingActionButton'; import FloatingActionButton from 'material-ui/FloatingActionButton';
import Dialog from 'material-ui/Dialog'; import Dialog from 'material-ui/Dialog';
import FlatButton from 'material-ui/FlatButton'; import FlatButton from 'material-ui/FlatButton';
import {Card, CardTitle, CardText} from 'material-ui/Card'; import {Card, CardText} from 'material-ui/Card';
import IconButton from 'material-ui/IconButton'; import IconButton from 'material-ui/IconButton';
import TuneIcon from 'material-ui/svg-icons/image/tune'; import TuneIcon from 'material-ui/svg-icons/image/tune';
import Scanner from './Scanner'; import Scanner from './Scanner';
import ScanIcon from './ScanIcon'; import ScanIcon from './ScanIcon';
import ScannedCode from './ScannedCode';
import ConfigView from './ConfigView'; import ConfigView from './ConfigView';
import {persist, load} from '../utils/Storage';
const cleanConfig = config => { const cleanConfig = config => {
if (typeof config.inputStream.constraints.deviceId === 'number') { if (typeof config.inputStream.constraints.deviceId === 'number') {
@ -19,50 +21,46 @@ const cleanConfig = config => {
return config; return config;
}; };
const defaultConfig = {
frequency: 5,
numOfWorkers: 2,
locate: true,
inputStream: {
name: "Live",
type: "LiveStream",
constraints: {
width: 800,
height: 600,
deviceId: 0,
facingMode: "environment",
},
area: {
top: "0%",
right: "0%",
left: "0%",
bottom: "0%",
},
},
decoder: {
readers: [
'ean_reader',
'code_39_reader',
'code_128_reader',
],
},
locator: {
halfSample: true,
patchSize: "medium",
},
};
export default class App extends React.Component { export default class App extends React.Component {
state = { state = {
drawerOpen: false, drawerOpen: false,
scanning: false, scanning: false,
currentView: 'root', currentView: 'root',
config: { config: load("config") || defaultConfig,
frequency: 5, scannedCodes: load('scannedCodes') || [],
numOfWorkers: 2,
locate: true,
inputStream: {
name: "Live",
type: "LiveStream",
constraints: {
width: 640,
height: 480,
deviceId: 0,
facingMode: "environment",
},
area: {
top: "0%",
right: "0%",
left: "0%",
bottom: "0%",
},
},
decoder: {
readers: [
'ean_reader',
'code_39_reader',
'code_128_reader',
],
},
locator: {
halfSample: true,
patchSize: "medium",
},
},
scannedCodes: [{
codeResult: {
code: "FANAVF1461710",
format: "code_128",
},
timestamp: new Date(),
}],
}; };
_handleToggle = () => { _handleToggle = () => {
@ -86,9 +84,20 @@ export default class App extends React.Component {
_handleResult = (result) => { _handleResult = (result) => {
this._stopScanning(); this._stopScanning();
this.setState({ const scannedCodes =
scannedCodes: [{...result, timestamp: new Date()}] [{
.concat(this.state.scannedCodes)}); angle: result.angle,
box: result.box,
codeResult: {
code: result.codeResult.code,
direction: result.codeResult.direction,
format: result.codeResult.format,
},
line: result.line,
}]
.concat(this.state.scannedCodes);
this.setState({scannedCodes});
persist('scannedCodes', scannedCodes);
} }
_navigateTo = (route) => { _navigateTo = (route) => {
@ -100,7 +109,17 @@ export default class App extends React.Component {
_handleConfigChange = config => { _handleConfigChange = config => {
this.setState({config: cleanConfig(config)}); this.setState({config: cleanConfig(config)});
console.log(config); persist("config", config);
}
_handleDelete = (scannedCode) => {
const index = this.state.scannedCodes.indexOf(scannedCode);
if (index !== -1) {
const newArray = this.state.scannedCodes.slice();
newArray.splice(index, 1);
this.setState({scannedCodes: newArray});
persist('scannedCodes', newArray);
}
} }
render() { render() {
@ -119,13 +138,6 @@ export default class App extends React.Component {
iconElementLeft={<IconButton onTouchTap={this._handleToggle}><TuneIcon /></IconButton>} iconElementLeft={<IconButton onTouchTap={this._handleToggle}><TuneIcon /></IconButton>}
onLeftIconButtonTouchTap={this._handleToggle} onLeftIconButtonTouchTap={this._handleToggle}
/> />
<FloatingActionButton
secondary={true}
onMouseDown={this._startScanning}
style={{position: 'fixed', right: 0, bottom: 0, margin: '0 1em 1em 0'}}
>
<ScanIcon />
</FloatingActionButton>
<Dialog <Dialog
style={{paddingTop: '0px'}} style={{paddingTop: '0px'}}
bodyStyle={{padding: '0.5rem'}} bodyStyle={{padding: '0.5rem'}}
@ -146,19 +158,27 @@ export default class App extends React.Component {
onCancel={this._stopScanning} /> onCancel={this._stopScanning} />
</Dialog> </Dialog>
<div style={{paddingTop: '64px'}}> <div style={{paddingTop: '64px'}}>
{this.state.currentView === 'root' && this.state.scannedCodes.map((scannedCode, i) => ( {this.state.currentView === 'root' && this.state.scannedCodes.length === 0 &&
<Card key={i} style={{margin: '0.5em 0.25em 0em'}}> <Card style={{margin: '0.5em 0.25em 0em'}}>
<CardTitle
titleStyle={{textOverflow: 'ellipsis', overflow: 'hidden'}}
title={scannedCode.codeResult.code}
subtitle={scannedCode.codeResult.format}
/>
<CardText> <CardText>
Scanned on {scannedCode.timestamp.toLocaleString()} Nothing scanned yet
</CardText> </CardText>
</Card> </Card>
}
{this.state.currentView === 'root' && this.state.scannedCodes.map((scannedCode, i) => (
<ScannedCode
key={i}
scannedCode={scannedCode}
onDelete={this._handleDelete.bind(this, scannedCode)} />
))} ))}
</div> </div>
<FloatingActionButton
secondary={true}
onMouseDown={this._startScanning}
style={{position: 'fixed', right: 0, bottom: 0, margin: '0 1em 1em 0'}}
>
<ScanIcon />
</FloatingActionButton>
</div> </div>
); );
} }

@ -4,7 +4,7 @@ import SvgIcon from 'material-ui/SvgIcon';
let ActionScanBarcode = (props) => ( let ActionScanBarcode = (props) => (
<SvgIcon {...props}> <SvgIcon {...props}>
<path d="M0 4h4v20h-4zM6 4h2v20h-2zM10 4h2v20h-2zM16 4h2v20h-2zM24 4h2v20h-2zM30 4h2v20h-2zM20 4h1v20h-1zM14 4h1v20h-1zM27 4h1v20h-1zM0 26h2v2h-2zM6 26h2v2h-2zM10 26h2v2h-2zM20 26h2v2h-2zM30 26h2v2h-2zM24 26h4v2h-4zM14 26h4v2h-4z"/> <path transform="translate(2, -3)" d="M0 4h4v20h-4zM6 4h2v20h-2zM10 4h2v20h-2zM16 4h2v20h-2zM24 4h2v20h-2zM30 4h2v20h-2zM20 4h1v20h-1zM14 4h1v20h-1zM27 4h1v20h-1zM0 26h2v2h-2zM6 26h2v2h-2zM10 26h2v2h-2zM20 26h2v2h-2zM30 26h2v2h-2zM24 26h4v2h-4zM14 26h4v2h-4z"/>
</SvgIcon> </SvgIcon>
); );

@ -0,0 +1,99 @@
import React from 'react';
import {Card, CardActions, CardText, CardHeader} from 'material-ui/Card';
import FlatButton from 'material-ui/FlatButton';
import DeleteIcon from 'material-ui/svg-icons/action/delete';
import Divider from 'material-ui/Divider';
const pointGenerator = points => i => `(${points[i][0].toFixed(0)}, ${points[i][1].toFixed(0)})`;
const lineGenerator = line => i => `(${line[i].x.toFixed(0)}, ${line[i].y.toFixed(0)})`;
const renderLineSegments = items => (
<div style={{display: 'flex', flexWrap: 'wrap', justifyContent: 'space-between', flexBasis: '100%'}}>
{items.map((item, i) => (
<div key={i} style={{width: `30%`, textAlign: 'center', padding: '0.2rem'}} >{item}</div>
))}
</div>
);
const renderBox = box => {
const p = pointGenerator(box);
const items = [p(1), ``, p(2), ``, ' ', ``, p(0), ``, p(3)];
return renderLineSegments(items);
};
const renderLine = line => {
const l = lineGenerator(line);
const items = [l(0), ``, l(1)];
return renderLineSegments(items);
};
const renderAngle = angle => (
<span>
{(angle * 180 / Math.PI).toFixed(2)}
</span>
);
const renderDirection = direction => (
<span>
{direction === -1 ? 'forward' : `reverse`}
</span>
);
const keyStyle = {
fontWeight: 'bold',
flex: '0 1 70px',
};
const lineStyle = {
marginBottom: '0.5rem',
marginTop: '0.5rem',
display: 'flex',
alignItems: 'center',
};
const ScannedCode = ({scannedCode, onDelete}) => {
return (
<Card
style={{margin: '0.5em 0.25em 0em'}}>
<CardHeader
textStyle={{paddingRight: '20px', maxWidth: '100%', boxSizing: 'border-box'}}
titleStyle={{fontSize: '18px', wordWrap: 'break-word'}}
title={scannedCode.codeResult.code}
subtitle={scannedCode.codeResult.format}
actAsExpander={true}
showExpandableButton={true}
/>
<CardText expandable={true}>
<div style={lineStyle}>
<div style={keyStyle}>Direction: </div><div>{renderDirection(scannedCode.codeResult.direction)}</div>
</div>
<Divider />
<div style={lineStyle}>
<div style={keyStyle}>Angle: </div><div>{renderAngle(scannedCode.angle)} deg</div>
</div>
<Divider />
<div style={lineStyle}>
<div style={keyStyle}>Line: </div>{renderLine(scannedCode.line)}
</div>
<Divider />
<div style={lineStyle}>
<div style={keyStyle}>Box: </div>
{renderBox(scannedCode.box)}
</div>
</CardText>
<CardActions expandable={true}>
<FlatButton
label=""
style={{minWidth: '36px', color: '#aaa'}}
onClick={onDelete} icon={<DeleteIcon />} />
</CardActions>
</Card>
);
};
ScannedCode.propTypes = {
scannedCode: React.PropTypes.object.isRequired,
onDelete: React.PropTypes.func,
};
export default ScannedCode;

@ -0,0 +1,35 @@
function storageWrapper(cb) {
if (typeof window.localStorage !== 'undefined') {
return cb(window.localStorage);
} else {
console.log("localStorage not available");
}
}
export function persist(key, object) {
storageWrapper((storage) => {
storage.setItem(key, JSON.stringify(object));
});
};
export function push(key, object) {
storageWrapper((storage) => {
const item = storage.getItem() || "[]",
parsed = JSON.parse(item);
if (Array.isArray(parsed)) {
parsed.push(object);
storage.setItem(key, JSON.stringify(parsed));
}
});
}
export function load(key) {
return storageWrapper((storage) => {
const item = storage.getItem(key);
if (item) {
return JSON.parse(item);
}
return null;
});
}
Loading…
Cancel
Save