diff --git a/.babelrc b/.babelrc index f2bdc95..eabd309 100644 --- a/.babelrc +++ b/.babelrc @@ -2,4 +2,7 @@ "presets": [ "env", "react" ], + "plugins": [ + "transform-class-properties" + ], } diff --git a/config/rzl.js b/config/rzl.js index 85e4ee5..bfd4bbf 100644 --- a/config/rzl.js +++ b/config/rzl.js @@ -333,7 +333,7 @@ const config : Config = { somafm_lush: "Lush (SomaFM)" }, icon: "radio", - enableCondition: (a, b, state) => state.onkyo_connection.inernal == "connected" && state.onkyo_inputs.internal == "netzwerk" + enableCondition: (a, b, state) => state.onkyo_connection.internal == "connected" && state.onkyo_inputs.internal == "netzwerk" }, { type: "section", diff --git a/package.json b/package.json index 2a6ab62..96e9a85 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "babel-core": "^6.25.0", "babel-eslint": "^8.0.1", "babel-loader": "^7.1.1", + "babel-plugin-transform-class-properties": "^6.24.1", "babel-preset-react": "^6.24.1", "clean-webpack-plugin": "^0.1.17", "css-loader": "^0.28.7", diff --git a/src/components/App.js b/src/components/App.js index d502a8f..cd1b5a0 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -87,6 +87,9 @@ class App extends React.Component { } changeState(topic: string, value: any) { + // this.receiveMessage(this.props.config.topics[topic].state, String(this.props.config.topics[topic].values[value] || value)); + // return; + // const rawTopic = this.props.config.topics[topic].command; if (rawTopic == null) { return; diff --git a/src/components/UiItemList/UiItem.js b/src/components/UiItemList/UiItem.js new file mode 100644 index 0000000..82112c4 --- /dev/null +++ b/src/components/UiItemList/UiItem.js @@ -0,0 +1,176 @@ +// @flow +import React from "react"; +import _ from "lodash"; +import { + ListItem, + ListItemIcon, + ListItemSecondaryAction, + ListItemText, + ListSubheader +} from "material-ui/List"; +import Switch from "material-ui/Switch"; +import { renderIcon } from "utils/parseIconName"; +import Input, { InputLabel } from "material-ui/Input"; +import { FormControl } from "material-ui/Form"; +import Select from "material-ui/Select"; +import { MenuItem } from "material-ui/Menu"; +import Button from "material-ui/Button"; + +import keyOf from "utils/keyOf"; + +type UiItemProps = { + item: I, + state: State, + onChangeState: (topic: string, nextState: any) => void +}; + +export default class UiItem extends React.Component> { + constructor(props: UiItemProps) { + super(props); + } + + runPrimaryAction() { + + } + + changeState(next: any) { + if (this.props.item.topic == null) { + throw new Error( + `Undefined topic in ${control.type} "${control.text}"` + ); + } + this.props.onChangeState(this.props.item.topic, next); + } + + getValue() { + const topic: string = this.props.item.topic || ""; + const value = this.props.state[topic]; + if (value == null) { + throw new Error( + `Unknown topic "${control.topic}" in ${control.type} "${control.text}"` + ); + } + return value; + } + + isEnabled() { + const enableCondition = this.props.item.enableCondition; + if (enableCondition == null) { + return true; + } else { + const value = this.getValue(); + return enableCondition( + value.internal || value.actual, value.actual, this.props.state); + } + } + + render() { + return null; + } +} + +export class Toggle extends UiItem { + isToggled = () => { + const value = this.getValue(); + const control = this.props.item; + const isChecked = control.toggled || ((i) => i === (control.on || "on")); + const checked = isChecked( + value.internal || value.actual, value.actual, this.props.state); + return checked; + } + + runPrimaryAction = () => { + if (this.isEnabled()) { + const control = this.props.item; + const toggled = this.isToggled(); + const next = toggled ? (control.off || "off") : (control.on || "on"); + this.changeState(next); + } + } + + render() { + return [ + , + + + + ]; + } +} + +export class DropDown extends UiItem { + runPrimaryAction = (next?: any) => { + if (this.isEnabled()) { + const control = this.props.item; + const keys = _.keys(control.options); + const value = this.getValue(); + const valueIndex = keyOf(keys, value); + if (next == null) { + this.changeState(keys[(valueIndex + 1) % keys.length]); + } else { + this.changeState(next); + } + } + } + + render() { + const control = this.props.item; + const value = this.getValue(); + const id = `${control.topic}-${control.name}`; + const options = control.options; + if (options == null) { + throw new Error( + `Parameter "options" missing for ${control.type} "${control.text}"` + ); + } + return ( + + {control.text} + } + > + {_.map(options, (v, k) => {v})} + + + ); + } +} + +export class Link extends UiItem { + runPrimaryAction = () => { + const control = this.props.item; + if (control.link == null) { + throw new Error( + `Parameter "link" missing for ${control.type} "${control.text}"` + ); + } + if (this.isEnabled()) { + window.open(control.link, "_blank"); + } + } + + render() { + return ( + + ); + } +} + +export class Section extends UiItem { + render() { + return ( + {this.props.item.text} + ); + } +} diff --git a/src/components/UiItemList.js b/src/components/UiItemList/index.js similarity index 89% rename from src/components/UiItemList.js rename to src/components/UiItemList/index.js index 4160ce5..bba000d 100644 --- a/src/components/UiItemList.js +++ b/src/components/UiItemList/index.js @@ -20,6 +20,8 @@ import Button from "material-ui/Button"; import Slider from "material-ui-old/Slider"; import MuiThemeProvider from "material-ui-old/styles/MuiThemeProvider"; +import { Toggle, DropDown, Link, Section } from "./UiItem"; + export type UiItemListProps = { controls: Array, state: State, @@ -54,16 +56,24 @@ export default class UiItemList extends React.Component { renderControl(control: ControlUI) { switch (control.type) { case "toggle": { - return this.renderToggle(control); + return ; } case "dropDown": { - return this.renderDropDown(control); + return ; } case "section": { - return this.renderSection(control); + return
; } case "link": { - return this.renderLink(control); + return ; } case "slider": { return this.renderSlider(control); diff --git a/types/types.js b/types/types.js index 75b0f29..6e0e95c 100644 --- a/types/types.js +++ b/types/types.js @@ -13,32 +13,50 @@ declare type Topic = { }; declare type Topics = Map; -declare type ControlUI = { - type: "toggle" | "dropDown" | "slider" | "section" | "link", +declare type UIBase = { text: string, - topic?: string, - icon?: string, + topic: string, + icon?: string, + enableCondition?: (internal: string, actual: any, state: State) => boolean +} - enableCondition?: (internal: string, actual: any, state: State) => boolean, - - // LINK optiona properties - link?: string, - - // TOGGLE optional properties - on?: string, // on override for toggle - off?: string, // off override for toggle +declare type UIToggle = { + type: "toggle", + on?: string, + off?: string, toggled?: (internal: string, actual: any, state: State) => boolean, +} & UIBase; - // DROPDOWN optional properties - options?: Map, //options for dropDown - renderValue?: (value: string) => string, +declare type UIDropDown = { + type: "dropDown", + options: Map, + renderValue?: (value: string) => string +} & UIBase; - // SLIDER optional properties +declare type UISlider = { + type: "slider", min?: number, max?: number, step?: number +} & UIBase; + +declare type UISection = { + type: "section", + text: string }; +declare type UILink = { + type: "link", + link: string +} & UIBase; + +declare type ControlUI = + UIToggle + | UIDropDown + | UISlider + | UISection + | UILink + declare type Control = { name: string, position: Array, diff --git a/yarn.lock b/yarn.lock index b2b973e..7bb8fcf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -501,6 +501,10 @@ babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" @@ -525,6 +529,15 @@ babel-plugin-transform-async-to-generator@^6.22.0: babel-plugin-syntax-async-functions "^6.8.0" babel-runtime "^6.22.0" +babel-plugin-transform-class-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" + dependencies: + babel-helper-function-name "^6.24.1" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221"