From 77935b7c7a1fd813cb512776cccc4798f2c6c201 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 30 Jan 2019 16:10:50 -0800 Subject: [PATCH] Convert ha-entity-toggle to Lit/TS (#2639) * Convert ha-entity-toggle to Lit/TS * Update src/components/entity/ha-entity-toggle.ts Co-Authored-By: balloob --- src/components/entity/ha-entity-toggle.js | 168 ---------------------- src/components/entity/ha-entity-toggle.ts | 154 ++++++++++++++++++++ 2 files changed, 154 insertions(+), 168 deletions(-) delete mode 100644 src/components/entity/ha-entity-toggle.js create mode 100644 src/components/entity/ha-entity-toggle.ts diff --git a/src/components/entity/ha-entity-toggle.js b/src/components/entity/ha-entity-toggle.js deleted file mode 100644 index 3bb7e511f3..0000000000 --- a/src/components/entity/ha-entity-toggle.js +++ /dev/null @@ -1,168 +0,0 @@ -import "@polymer/paper-icon-button/paper-icon-button"; -import "@polymer/paper-toggle-button/paper-toggle-button"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; - -import { STATES_OFF } from "../../common/const"; -import computeStateDomain from "../../common/entity/compute_state_domain"; - -class HaEntityToggle extends PolymerElement { - static get template() { - return html` - - - - - `; - } - - static get properties() { - return { - hass: Object, - stateObj: { - type: Object, - observer: "stateObjObserver", - }, - - toggleChecked: { - type: Boolean, - value: false, - }, - - isOn: { - type: Boolean, - computed: "computeIsOn(stateObj)", - observer: "isOnChanged", - }, - }; - } - - ready() { - super.ready(); - this.addEventListener("click", (ev) => this.onTap(ev)); - this.forceStateChange(); - } - - onTap(ev) { - ev.stopPropagation(); - } - - toggleChanged(ev) { - const newVal = ev.target.checked; - - if (newVal && !this.isOn) { - this.callService(true); - } else if (!newVal && this.isOn) { - this.callService(false); - } - } - - isOnChanged(newVal) { - this.toggleChecked = newVal; - } - - forceStateChange() { - if (this.toggleChecked === this.isOn) { - this.toggleChecked = !this.toggleChecked; - } - this.toggleChecked = this.isOn; - } - - turnOn() { - this.callService(true); - } - - turnOff() { - this.callService(false); - } - - computeIsOn(stateObj) { - return stateObj && !STATES_OFF.includes(stateObj.state); - } - - stateObjObserver(newVal, oldVal) { - if (!oldVal || !newVal) return; - if (this.computeIsOn(newVal) === this.computeIsOn(oldVal)) { - // stateObj changed but isOn is the same. Make sure toggle is in the right position. - this.forceStateChange(); - } - } - - // We call updateToggle after a successful call to re-sync the toggle - // with the state. It will be out of sync if our service call did not - // result in the entity to be turned on. Since the state is not changing, - // the resync is not called automatic. - callService(turnOn) { - const stateDomain = computeStateDomain(this.stateObj); - let serviceDomain; - let service; - - if (stateDomain === "lock") { - serviceDomain = "lock"; - service = turnOn ? "unlock" : "lock"; - } else if (stateDomain === "cover") { - serviceDomain = "cover"; - service = turnOn ? "open_cover" : "close_cover"; - } else if (stateDomain === "group") { - serviceDomain = "homeassistant"; - service = turnOn ? "turn_on" : "turn_off"; - } else { - serviceDomain = stateDomain; - service = turnOn ? "turn_on" : "turn_off"; - } - - const currentState = this.stateObj; - this.hass - .callService(serviceDomain, service, { - entity_id: this.stateObj.entity_id, - }) - .then(() => { - setTimeout(() => { - // If after 2 seconds we have not received a state update - // reset the switch to it's original state. - if (this.stateObj === currentState) { - this.forceStateChange(); - } - }, 2000); - }); - } -} - -customElements.define("ha-entity-toggle", HaEntityToggle); diff --git a/src/components/entity/ha-entity-toggle.ts b/src/components/entity/ha-entity-toggle.ts new file mode 100644 index 0000000000..32d7140ac5 --- /dev/null +++ b/src/components/entity/ha-entity-toggle.ts @@ -0,0 +1,154 @@ +import "@polymer/paper-icon-button/paper-icon-button"; +import "@polymer/paper-toggle-button/paper-toggle-button"; + +import { STATES_OFF } from "../../common/const"; +import computeStateDomain from "../../common/entity/compute_state_domain"; +import { + LitElement, + TemplateResult, + html, + CSSResult, + css, + PropertyDeclarations, +} from "lit-element"; +import { HomeAssistant } from "../../types"; +import { HassEntity } from "home-assistant-js-websocket"; + +class HaEntityToggle extends LitElement { + // hass is not a property so that we only re-render on stateObj changes + public hass?: HomeAssistant; + public stateObj?: HassEntity; + + protected render(): TemplateResult | void { + if (!this.stateObj) { + return html` + + `; + } + + const isOn = this._isOn; + + if (this.stateObj.attributes.assumed_state) { + return html` + + + `; + } + + return html` + + `; + } + + static get properties(): PropertyDeclarations { + return { + stateObj: {}, + }; + } + + protected firstUpdated(changedProps) { + super.firstUpdated(changedProps); + this.addEventListener("click", (ev) => ev.stopPropagation()); + } + + private get _isOn(): boolean { + return ( + this.stateObj !== undefined && !STATES_OFF.includes(this.stateObj.state) + ); + } + + private _toggleChanged(ev) { + const newVal = ev.target.checked; + + if (newVal !== this._isOn) { + this._callService(newVal); + } + } + + private _turnOn() { + this._callService(true); + } + + private _turnOff() { + this._callService(false); + } + + // We will force a re-render after a successful call to re-sync the toggle + // with the state. It will be out of sync if our service call did not + // result in the entity to be turned on. Since the state is not changing, + // the resync is not called automatic. + private async _callService(turnOn): Promise { + if (!this.hass || !this.stateObj) { + return; + } + const stateDomain = computeStateDomain(this.stateObj); + let serviceDomain; + let service; + + if (stateDomain === "lock") { + serviceDomain = "lock"; + service = turnOn ? "unlock" : "lock"; + } else if (stateDomain === "cover") { + serviceDomain = "cover"; + service = turnOn ? "open_cover" : "close_cover"; + } else if (stateDomain === "group") { + serviceDomain = "homeassistant"; + service = turnOn ? "turn_on" : "turn_off"; + } else { + serviceDomain = stateDomain; + service = turnOn ? "turn_on" : "turn_off"; + } + + const currentState = this.stateObj; + + await this.hass.callService(serviceDomain, service, { + entity_id: this.stateObj.entity_id, + }); + + setTimeout(() => { + // If after 2 seconds we have not received a state update + // reset the switch to it's original state. + if (this.stateObj === currentState) { + this.requestUpdate(); + } + }, 2000); + } + + static get styles(): CSSResult { + return css` + :host { + white-space: nowrap; + min-width: 38px; + } + paper-icon-button { + color: var( + --paper-icon-button-inactive-color, + var(--primary-text-color) + ); + transition: color 0.5s; + } + paper-icon-button[state-active] { + color: var(--paper-icon-button-active-color, var(--primary-color)); + } + paper-toggle-button { + cursor: pointer; + --paper-toggle-button-label-spacing: 0; + padding: 13px 5px; + margin: -4px -5px; + } + `; + } +} + +customElements.define("ha-entity-toggle", HaEntityToggle);