implement bluetooth connect using redux

This commit is contained in:
David Lechner
2020-04-16 19:09:50 -05:00
parent 0a50055574
commit b4d81fd3e5
11 changed files with 368 additions and 131 deletions
+16 -12
View File
@@ -4,31 +4,35 @@ import Tooltip from 'react-bootstrap/Tooltip';
import Image from 'react-bootstrap/Image';
import React from 'react';
interface ActionButtonProperties {
interface ActionButtonProps {
/** A unique id for each instance. */
readonly id: string;
readonly action: {
readonly id: string;
readonly tooltip: string;
readonly icon: string;
};
readonly onAction: (action: string) => void;
/** Tooltip text that appears when hovering over the button. */
readonly tooltip: string;
/** Icon shown on the button. */
readonly icon: string;
/** When true or undefined, the button is enabled. */
readonly enabled?: boolean;
/** Optional action hint passed to the onAction() callback. */
readonly action?: string;
/** Callback that is called when the button is activated (clicked). */
readonly onAction: (action?: string) => void;
}
class ActionButton extends React.Component<ActionButtonProperties> {
class ActionButton extends React.Component<ActionButtonProps> {
render(): JSX.Element {
return (
<OverlayTrigger
placement="bottom"
overlay={
<Tooltip id={`${this.props.id}-tooltip`}>
{this.props.action.tooltip}.
{this.props.tooltip}.
</Tooltip>
}
>
<Button
variant="primary"
onClick={(): void => this.props.onAction(this.props.action.id)}
onClick={(): void => this.props.onAction(this.props.action)}
disabled={this.props.enabled === false}
style={
this.props.enabled === false
@@ -37,8 +41,8 @@ class ActionButton extends React.Component<ActionButtonProperties> {
}
>
<Image
src={`/static/images/${this.props.action.icon}`}
alt={this.props.action.id}
src={`/static/images/${this.props.icon}`}
alt={this.props.id}
/>
</Button>
</OverlayTrigger>
+50
View File
@@ -0,0 +1,50 @@
import ActionButton from './ActionButton';
import { connect } from 'react-redux';
import { connect as bleConnect, disconnect as bleDisconnect } from '../actions/ble';
import { RootState } from '../reducers';
import { BLEConnectionState } from '../reducers/ble';
import { ThunkDispatch } from 'redux-thunk';
import { AnyAction } from 'redux';
type Dispatch = ThunkDispatch<{}, {}, AnyAction>;
interface StateProps {
readonly tooltip: string;
readonly icon: string;
readonly action?: string;
readonly enabled?: boolean;
}
interface DispatchProps {
readonly onAction: (action?: string) => void;
}
const mapStateToProps = (state: RootState): StateProps => {
if (state.ble.connection === BLEConnectionState.Disconnected) {
return {
tooltip: 'Connect using Bluetooth',
icon: 'btdisconnected.svg',
action: 'connect',
enabled: true,
};
} else {
return {
tooltip: 'Disconnect Bluetooth',
icon: 'btconnected.svg',
action: 'disconnect',
enabled: state.ble.connection === BLEConnectionState.Connected,
};
}
};
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({
onAction: (a): void => {
if (a === 'connect') {
dispatch(bleConnect());
} else {
dispatch(bleDisconnect());
}
},
});
export default connect(mapStateToProps, mapDispatchToProps)(ActionButton);
+1 -1
View File
@@ -2,7 +2,7 @@ import React from 'react';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import ProgressBar from 'react-bootstrap/ProgressBar';
import { BLEConnectionState } from '../services/BLEConnection';
import { BLEConnectionState } from '../reducers/ble';
interface StatusBarState {
bleState: BLEConnectionState;
+12 -78
View File
@@ -4,19 +4,13 @@ import ButtonGroup from 'react-bootstrap/ButtonGroup';
import ButtonToolbar from 'react-bootstrap/ButtonToolbar';
import React from 'react';
import ActionButton from './ActionButton';
import { BLEConnectionState } from '../services/BLEConnection';
import { BLEConnectionState } from '../reducers/ble';
import BluetoothButton from './BluetoothButton';
interface ToolbarState {
bleState: BLEConnectionState;
}
function oneOf(
bleState: BLEConnectionState,
...matches: BLEConnectionState[]
): boolean {
return matches.indexOf(bleState) >= 0;
}
class Toolbar extends React.Component<{}, ToolbarState> {
constructor(props: {}) {
super(props);
@@ -24,7 +18,7 @@ class Toolbar extends React.Component<{}, ToolbarState> {
this.onAction = this.onAction.bind(this);
}
private onAction(action: string): void {
private onAction(action?: string): void {
console.log(action);
}
@@ -38,92 +32,32 @@ class Toolbar extends React.Component<{}, ToolbarState> {
<Col>
<ButtonToolbar className="m-2">
<ButtonGroup className="mr-2" size="lg">
<ActionButton
id="bluetooth"
action={
this.state.bleState ===
BLEConnectionState.Disconnected
? {
id: 'connect',
tooltip: 'Connect using Bluetooth',
icon: 'btdisconnected.svg',
}
: {
id: 'disconnect',
tooltip: 'Disconnect Bluetooth',
icon: 'btconnected.svg',
}
}
onAction={this.onAction}
/>
<BluetoothButton id="bluetooth" />
<ActionButton
id="run"
action={{
id: 'run',
tooltip: 'Download and run this program',
icon: 'run.svg',
}}
tooltip="Download and run this program"
icon="run.svg"
onAction={this.onAction}
enabled={oneOf(
this.state.bleState,
BLEConnectionState.Waiting,
BLEConnectionState.Running,
BLEConnectionState.REPL,
)}
/>
<ActionButton
id="stop"
action={
this.state.bleState ===
BLEConnectionState.Downloading
? {
id: 'cancel',
tooltip: 'Cancel download',
icon: 'stop.svg',
}
: {
id: 'reset',
tooltip: 'Stop everything',
icon: 'stop.svg',
}
}
tooltip="Stop everything"
icon="stop.svg"
onAction={this.onAction}
enabled={oneOf(
this.state.bleState,
BLEConnectionState.Waiting,
BLEConnectionState.Downloading,
BLEConnectionState.Running,
BLEConnectionState.REPL,
)}
/>
</ButtonGroup>
<ButtonGroup className="mr-2" size="lg">
<ActionButton
id="repl"
action={{
id: 'repl',
tooltip: 'Start REPL in terminal',
icon: 'repl.svg',
}}
tooltip="Start REPL in terminal"
icon="repl.svg"
onAction={this.onAction}
enabled={oneOf(
this.state.bleState,
BLEConnectionState.Waiting,
BLEConnectionState.REPL,
)}
/>
<ActionButton
id="flash"
action={{
id: 'flash',
tooltip: 'Flash hub firmware',
icon: 'firmware.svg',
}}
tooltip="Flash hub firmware"
icon="firmware.svg"
onAction={this.onAction}
enabled={oneOf(
this.state.bleState,
BLEConnectionState.Disconnected,
)}
/>
</ButtonGroup>
</ButtonToolbar>