diff --git a/src/components/App.js b/src/components/App.js index e8b7d85..9e9ad7c 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -21,6 +21,7 @@ import ControlMap from "components/ControlMap"; import TopBar from "components/TopBar"; import UiItemList from "components/UiItemList"; +import MqttContext from "mqtt/context"; import connectMqtt from "../connectMqtt"; export type AppProps = { @@ -119,7 +120,6 @@ class App extends React.PureComponent { const val = transformValue == null ? value : transformValue(Buffer.from(value)); this.state.mqttSend(rawTopic, Buffer.from(val)); - throw new Error("test"); } catch (err) { this.setState({ error: err.toString() }); } @@ -127,9 +127,12 @@ class App extends React.PureComponent { render() { return ( -
+ -
+ { this.state.selectedControl.icon(this.state.mqttState)} > {this.state.selectedControl == null - || } + || } -
+
{ } /> -
+ ); } } diff --git a/src/components/ControlMap.js b/src/components/ControlMap.js index d480d2a..63bcbc2 100644 --- a/src/components/ControlMap.js +++ b/src/components/ControlMap.js @@ -3,7 +3,7 @@ import React from "react"; import { Map, ImageOverlay, Marker, LayersControl } from "react-leaflet"; import { CRS, point, divIcon } from "leaflet"; import map from "lodash/map"; - +import MqttContext from "mqtt/context"; import type { Controls, Control } from "config/flowtypes"; export type Point = [number, number]; @@ -16,8 +16,7 @@ export type ControlMapProps = { zoom: number, layers: Array, controls: Controls, - onChangeControl: (control: Control) => void, - state: State + onChangeControl: (control: Control) => void }; export default class ControlMap extends React.PureComponent { @@ -48,32 +47,36 @@ export default class ControlMap extends React.PureComponent { return map(this.props.controls, this.renderMarker.bind(this)); } - createLeafletIcon(control: Control) { - const icon = control.icon(this.props.state); + createLeafletIcon(control: Control, state: State) { + const icon = control.icon(state); const iconClass = `${icon} mdi-36px`; return divIcon({ iconSize: point(36, 36), iconAnchor: point(18, 18), html: `` + style="line-height: 1; color: ${this.iconColor(control, state)}">` }); } - iconColor(control: Control): string { + iconColor(control: Control, state: State): string { if (control.iconColor != null) { - return control.iconColor(this.props.state); + return control.iconColor(state); } return "#000"; } renderMarker(control: Control, key: string) { return ( - this.props.onChangeControl(control)} - > - + + {({ state }) => ( + this.props.onChangeControl(control)} + > + + )} + ); } diff --git a/src/components/SideBar.js b/src/components/SideBar.js index ee45c08..afea280 100644 --- a/src/components/SideBar.js +++ b/src/components/SideBar.js @@ -8,7 +8,7 @@ import IconButton from "@material-ui/core/IconButton"; import AppBar from "@material-ui/core/AppBar"; import Toolbar from "@material-ui/core/Toolbar"; import List from "@material-ui/core/List"; -import { renderIcon } from "config/icon"; +import { renderRawIcon } from "config/icon"; import type { RawIcon } from "config/icon"; import type { Control } from "config/flowtypes"; @@ -57,7 +57,7 @@ class SideBar extends React.PureComponent { {this.props.icon == null - || renderIcon(this.props.icon, "mdi-36px")} + || renderRawIcon(this.props.icon, "mdi-36px")} {this.props.control == null ? "" : this.props.control.name} diff --git a/src/components/UiItemList/UiItem.js b/src/components/UiItemList/UiItem.js index 0889440..703b345 100644 --- a/src/components/UiItemList/UiItem.js +++ b/src/components/UiItemList/UiItem.js @@ -3,7 +3,7 @@ import React from "react"; import keys from "lodash/keys"; import map from "lodash/map"; import debounce from "lodash/debounce"; -import { renderIcon } from "config/icon"; +import { renderRawIcon } from "config/icon"; import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction"; import ListItemText from "@material-ui/core/ListItemText"; import ListSubheader from "@material-ui/core/ListSubheader"; @@ -218,7 +218,7 @@ export class Link extends UiItem { disabled={!this.isEnabled()} > {this.props.item.icon == null ? "" - : renderIcon(this.props.item.icon(this.props.state), "mdi-24px")} + : renderRawIcon(this.props.item.icon(this.props.state), "mdi-24px")} {this.props.item.text} ); diff --git a/src/components/UiItemList/index.js b/src/components/UiItemList/index.js index cdfda90..518e8d7 100644 --- a/src/components/UiItemList/index.js +++ b/src/components/UiItemList/index.js @@ -2,17 +2,17 @@ import React from "react"; import ListItem from "@material-ui/core/ListItem"; import ListItemIcon from "@material-ui/core/ListItemIcon"; -import { renderIcon } from "config/icon"; +import { renderRawIcon } from "config/icon"; import type { ControlUI } from "config/flowtypes"; import { Toggle, DropDown, Link, Section, Text, Progress, Slider } from "./UiItem"; +import MqttContext from "mqtt/context"; +import type { MqttContextValue } from "mqtt/context"; export type UiItemListProps = { - controls: Array, - state: State, - onChangeState: (topic: string, nextState: string) => void + controls: Array }; export default class UiItemList extends React.PureComponent { @@ -27,66 +27,60 @@ export default class UiItemList extends React.PureComponent { "A control is missing the \"type\" parameter" ); } - if (control.type === "section") { - return this.renderControl(control, key.toString()); - } return ( - - {control.icon == null || control.type === "link" || - - {renderIcon(control.icon(this.props.state), "mdi-24px")} - } - {this.renderControl(control, key.toString())} - + + {this.renderListItem(control, key)} + ); }); } - renderControl(control: ControlUI, key: string) { + renderListItem(control: ControlUI, key: number) { + return (mqtt: MqttContextValue) => { + const node = this.renderControl(control, key.toString(), mqtt); + if (control.icon == null || control.type === "link" + || control.type === "section") { + return node; + } else { + const listIconNode = ( + + {renderRawIcon(control.icon(mqtt.state), "mdi-24px")} + + ); + return [listIconNode, node]; + } + }; + } + + renderControl(control: ControlUI, key: string, mqtt: MqttContextValue) { + const props = { + state: mqtt.state, + onChangeState: mqtt.changeState, + key: `${key}-licontrol` + }; switch (control.type) { case "toggle": { - return ; + return ; } case "dropDown": { - return ; + return ; } case "section": { - return
; + return
; } case "link": { - return ; + return ; } case "slider": { - return ; + return ; } case "text": { - return ; + return ; } case "progress": { - return ; + return ; } default: { throw new Error( diff --git a/src/config/icon.js b/src/config/icon.js index 95cb521..a8a44b1 100644 --- a/src/config/icon.js +++ b/src/config/icon.js @@ -1,5 +1,6 @@ // @flow import * as React from "react"; +import ReactContext from "mqtt/context"; export opaque type RawIcon: string = string; @@ -39,7 +40,16 @@ export const mdiBattery = (topic: string) => (state: State) => { } }; -export const renderIcon = +export const renderRawIcon = (icon: RawIcon, extraClass?: string): React.Node => { return ; }; + +export const renderIcon = + (icon: Icon, extraClass?: string): React.Node => { + return ( + + {({state}) => renderRawIcon(icon(state), extraClass)} + + ); + }; diff --git a/src/mqtt/context.js b/src/mqtt/context.js new file mode 100644 index 0000000..bb14c9c --- /dev/null +++ b/src/mqtt/context.js @@ -0,0 +1,12 @@ +// @flow +import React from "react"; + +export type MqttContextValue = { + state: State, + changeState: (topic: string, value: string) => void +}; + +export default React.createContext({ + state: {}, + changeState: (_topic, _val) => {} +});