From 7e08c96a029ff34ca6a81753c885154048346a31 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Thu, 29 Oct 2020 07:40:15 -0500 Subject: [PATCH 1/5] Convert ha-cover-controls to TypeScript/LitElement --- src/components/ha-cover-controls.js | 126 ------------------------- src/components/ha-cover-controls.ts | 138 ++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 126 deletions(-) delete mode 100644 src/components/ha-cover-controls.js create mode 100644 src/components/ha-cover-controls.ts diff --git a/src/components/ha-cover-controls.js b/src/components/ha-cover-controls.js deleted file mode 100644 index 3c9288399d19..000000000000 --- a/src/components/ha-cover-controls.js +++ /dev/null @@ -1,126 +0,0 @@ -import "./ha-icon-button"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -/* eslint-plugin-disable lit */ -import { PolymerElement } from "@polymer/polymer/polymer-element"; -import { UNAVAILABLE } from "../data/entity"; -import CoverEntity from "../util/cover-model"; - -class HaCoverControls extends PolymerElement { - static get template() { - return html` - - -
- - - -
- `; - } - - static get properties() { - return { - hass: { - type: Object, - }, - stateObj: { - type: Object, - }, - entityObj: { - type: Object, - computed: "computeEntityObj(hass, stateObj)", - }, - }; - } - - computeEntityObj(hass, stateObj) { - return new CoverEntity(hass, stateObj); - } - - computeOpenIcon(stateObj) { - switch (stateObj.attributes.device_class) { - case "awning": - case "door": - case "gate": - return "hass:arrow-expand-horizontal"; - default: - return "hass:arrow-up"; - } - } - - computeCloseIcon(stateObj) { - switch (stateObj.attributes.device_class) { - case "awning": - case "door": - case "gate": - return "hass:arrow-collapse-horizontal"; - default: - return "hass:arrow-down"; - } - } - - computeStopDisabled(stateObj) { - if (stateObj.state === UNAVAILABLE) { - return true; - } - return false; - } - - computeOpenDisabled(stateObj, entityObj) { - if (stateObj.state === UNAVAILABLE) { - return true; - } - const assumedState = stateObj.attributes.assumed_state === true; - return (entityObj.isFullyOpen || entityObj.isOpening) && !assumedState; - } - - computeClosedDisabled(stateObj, entityObj) { - if (stateObj.state === UNAVAILABLE) { - return true; - } - const assumedState = stateObj.attributes.assumed_state === true; - return (entityObj.isFullyClosed || entityObj.isClosing) && !assumedState; - } - - onOpenTap(ev) { - ev.stopPropagation(); - this.entityObj.openCover(); - } - - onCloseTap(ev) { - ev.stopPropagation(); - this.entityObj.closeCover(); - } - - onStopTap(ev) { - ev.stopPropagation(); - this.entityObj.stopCover(); - } -} - -customElements.define("ha-cover-controls", HaCoverControls); diff --git a/src/components/ha-cover-controls.ts b/src/components/ha-cover-controls.ts new file mode 100644 index 000000000000..ae89106f502c --- /dev/null +++ b/src/components/ha-cover-controls.ts @@ -0,0 +1,138 @@ +import { + css, + CSSResult, + customElement, + html, + LitElement, + property, +} from "lit-element"; +import { classMap } from "lit-html/directives/class-map"; + +import { UNAVAILABLE } from "../data/entity"; +import { HomeAssistant } from "../types"; +import { HassEntity } from "home-assistant-js-websocket"; +import CoverEntity from "../util/cover-model"; + +import "./ha-icon-button"; + +@customElement("ha-cover-controls") +class HaCoverControls extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public stateObj!: HassEntity; + + protected render() { + const entityObj = new CoverEntity(this.hass, this.stateObj); + + return html` +
+ + + +
+ `; + } + + static get styles(): CSSResult { + return css` + .state { + white-space: nowrap; + } + [invisible] { + visibility: hidden !important; + } + `; + } + + private computeOpenIcon(): string { + switch (this.stateObj.attributes.device_class) { + case "awning": + case "door": + case "gate": + return "hass:arrow-expand-horizontal"; + default: + return "hass:arrow-up"; + } + } + + private computeCloseIcon(): string { + switch (this.stateObj.attributes.device_class) { + case "awning": + case "door": + case "gate": + return "hass:arrow-collapse-horizontal"; + default: + return "hass:arrow-down"; + } + } + + private computeStopDisabled(): boolean { + if (this.stateObj.state === UNAVAILABLE) { + return true; + } + return false; + } + + private computeOpenDisabled(): boolean { + if (this.stateObj.state === UNAVAILABLE) { + return true; + } + const assumedState = this.stateObj.attributes.assumed_state === true; + const entityObj = new CoverEntity(this.hass, this.stateObj); + return (entityObj.isFullyOpen || entityObj.isOpening) && !assumedState; + } + + private computeClosedDisabled(): boolean { + if (this.stateObj.state === UNAVAILABLE) { + return true; + } + const assumedState = this.stateObj.attributes.assumed_state === true; + const entityObj = new CoverEntity(this.hass, this.stateObj); + return (entityObj.isFullyClosed || entityObj.isClosing) && !assumedState; + } + + private onOpenTap(ev): void { + ev.stopPropagation(); + new CoverEntity(this.hass, this.stateObj).openCover(); + } + + private onCloseTap(ev): void { + ev.stopPropagation(); + new CoverEntity(this.hass, this.stateObj).closeCover(); + } + + private onStopTap(ev): void { + ev.stopPropagation(); + new CoverEntity(this.hass, this.stateObj).stopCover(); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-cover-controls": HaCoverControls; + } +} From 0e9975a93b230ba4ca70d1f0e42294b0cfee5dba Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Thu, 29 Oct 2020 21:04:19 -0500 Subject: [PATCH 2/5] address review comments --- src/components/ha-cover-controls.ts | 120 +++++++++++++++------------- src/translations/en.json | 5 ++ 2 files changed, 70 insertions(+), 55 deletions(-) diff --git a/src/components/ha-cover-controls.ts b/src/components/ha-cover-controls.ts index ae89106f502c..0e890a8f5a3c 100644 --- a/src/components/ha-cover-controls.ts +++ b/src/components/ha-cover-controls.ts @@ -3,14 +3,16 @@ import { CSSResult, customElement, html, + internalProperty, LitElement, property, + TemplateResult, } from "lit-element"; import { classMap } from "lit-html/directives/class-map"; +import { HassEntity } from "home-assistant-js-websocket"; import { UNAVAILABLE } from "../data/entity"; import { HomeAssistant } from "../types"; -import { HassEntity } from "home-assistant-js-websocket"; import CoverEntity from "../util/cover-model"; import "./ha-icon-button"; @@ -19,57 +21,57 @@ import "./ha-icon-button"; class HaCoverControls extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @property() public stateObj!: HassEntity; + @internalProperty() private _stateObj!: HassEntity; - protected render() { - const entityObj = new CoverEntity(this.hass, this.stateObj); + private _entityObj?: CoverEntity; + + public set stateObj(stateObj: HassEntity) { + this._entityObj = new CoverEntity(this.hass, stateObj); + this._stateObj = stateObj; + } + + protected render(): TemplateResult { + if (!this._entityObj) { + return html``; + } return html`
`; } - static get styles(): CSSResult { - return css` - .state { - white-space: nowrap; - } - [invisible] { - visibility: hidden !important; - } - `; - } - - private computeOpenIcon(): string { - switch (this.stateObj.attributes.device_class) { + private _computeOpenIcon(): string { + switch (this._stateObj.attributes.device_class) { case "awning": case "door": case "gate": @@ -79,8 +81,8 @@ class HaCoverControls extends LitElement { } } - private computeCloseIcon(): string { - switch (this.stateObj.attributes.device_class) { + private _computeCloseIcon(): string { + switch (this._stateObj.attributes.device_class) { case "awning": case "door": case "gate": @@ -90,44 +92,52 @@ class HaCoverControls extends LitElement { } } - private computeStopDisabled(): boolean { - if (this.stateObj.state === UNAVAILABLE) { + private _computeOpenDisabled(): boolean { + if (this._stateObj.state === UNAVAILABLE) { return true; } - return false; + const assumedState = this._stateObj.attributes.assumed_state === true; + return ( + (this._entityObj.isFullyOpen || this._entityObj.isOpening) && + !assumedState + ); } - private computeOpenDisabled(): boolean { - if (this.stateObj.state === UNAVAILABLE) { + private _computeClosedDisabled(): boolean { + if (this._stateObj.state === UNAVAILABLE) { return true; } - const assumedState = this.stateObj.attributes.assumed_state === true; - const entityObj = new CoverEntity(this.hass, this.stateObj); - return (entityObj.isFullyOpen || entityObj.isOpening) && !assumedState; + const assumedState = this._stateObj.attributes.assumed_state === true; + return ( + (this._entityObj.isFullyClosed || this._entityObj.isClosing) && + !assumedState + ); } - private computeClosedDisabled(): boolean { - if (this.stateObj.state === UNAVAILABLE) { - return true; - } - const assumedState = this.stateObj.attributes.assumed_state === true; - const entityObj = new CoverEntity(this.hass, this.stateObj); - return (entityObj.isFullyClosed || entityObj.isClosing) && !assumedState; + private _onOpenTap(ev): void { + ev.stopPropagation(); + this._entityObj.openCover(); } - private onOpenTap(ev): void { + private _onCloseTap(ev): void { ev.stopPropagation(); - new CoverEntity(this.hass, this.stateObj).openCover(); + this._entityObj.closeCover(); } - private onCloseTap(ev): void { + private _onStopTap(ev): void { ev.stopPropagation(); - new CoverEntity(this.hass, this.stateObj).closeCover(); + this._entityObj.stopCover(); } - private onStopTap(ev): void { - ev.stopPropagation(); - new CoverEntity(this.hass, this.stateObj).stopCover(); + static get styles(): CSSResult { + return css` + .state { + white-space: nowrap; + } + .invisible { + visibility: hidden !important; + } + `; } } diff --git a/src/translations/en.json b/src/translations/en.json index 5b804e72ffef..6425a6c640c7 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -551,6 +551,11 @@ }, "person": { "create_zone": "Create zone from current location" + }, + "cover": { + "open_cover": "Open cover", + "stop_cover": "Stop the cover from moving", + "close_cover": "Close cover" } }, "entity_registry": { From 40760801c8f0fc657ed33e6957af752547e2d4d6 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Fri, 30 Oct 2020 16:45:11 -0500 Subject: [PATCH 3/5] Update src/components/ha-cover-controls.ts Co-authored-by: Zack Barett --- src/components/ha-cover-controls.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ha-cover-controls.ts b/src/components/ha-cover-controls.ts index 0e890a8f5a3c..54f5d22f8201 100644 --- a/src/components/ha-cover-controls.ts +++ b/src/components/ha-cover-controls.ts @@ -41,7 +41,7 @@ class HaCoverControls extends LitElement { class=${classMap({ invisible: !this._entityObj.supportsOpen, })} - label=${this.hass.localize("ui.dialogs.more_info_control.open_cover")} + .title=${this.hass.localize("ui.dialogs.more_info_control.open_cover")} .icon=${this._computeOpenIcon()} @click=${this._onOpenTap} .disabled=${this._computeOpenDisabled()} From b006f1147fd762715f901c13c1a39aed78aea36d Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Fri, 30 Oct 2020 16:46:09 -0500 Subject: [PATCH 4/5] Update ha-cover-controls.ts --- src/components/ha-cover-controls.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ha-cover-controls.ts b/src/components/ha-cover-controls.ts index 54f5d22f8201..3f1ca84f1346 100644 --- a/src/components/ha-cover-controls.ts +++ b/src/components/ha-cover-controls.ts @@ -41,7 +41,7 @@ class HaCoverControls extends LitElement { class=${classMap({ invisible: !this._entityObj.supportsOpen, })} - .title=${this.hass.localize("ui.dialogs.more_info_control.open_cover")} + .label=${this.hass.localize("ui.dialogs.more_info_control.open_cover")} .icon=${this._computeOpenIcon()} @click=${this._onOpenTap} .disabled=${this._computeOpenDisabled()} @@ -50,7 +50,7 @@ class HaCoverControls extends LitElement { class=${classMap({ invisible: !this._entityObj.supportsStop, })} - label=${this.hass.localize("ui.dialogs.more_info_control.stop_cover")} + .label=${this.hass.localize("ui.dialogs.more_info_control.stop_cover")} icon="hass:stop" @click=${this._onStopTap} .disabled=${this._stateObj.state === UNAVAILABLE} @@ -59,7 +59,7 @@ class HaCoverControls extends LitElement { class=${classMap({ invisible: !this._entityObj.supportsClose, })} - label=${this.hass.localize( + .label=${this.hass.localize( "ui.dialogs.more_info_control.close_cover" )} .icon=${this._computeCloseIcon()} From 792a8dc650bf7a3c79b696da33369f1143f456c8 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Wed, 11 Nov 2020 22:15:13 -0600 Subject: [PATCH 5/5] address review comments --- src/common/entity/cover_icon.ts | 22 +++++++++ src/components/ha-cover-controls.ts | 71 ++++++++++++----------------- 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/common/entity/cover_icon.ts b/src/common/entity/cover_icon.ts index 7c9bc5ed53d1..011f8e72945d 100644 --- a/src/common/entity/cover_icon.ts +++ b/src/common/entity/cover_icon.ts @@ -78,3 +78,25 @@ export const coverIcon = (state?: string, stateObj?: HassEntity): string => { return "hass:window-open"; } }; + +export const computeOpenIcon = (stateObj: HassEntity): string => { + switch (stateObj.attributes.device_class) { + case "awning": + case "door": + case "gate": + return "hass:arrow-expand-horizontal"; + default: + return "hass:arrow-up"; + } +}; + +export const computeCloseIcon = (stateObj: HassEntity): string => { + switch (stateObj.attributes.device_class) { + case "awning": + case "door": + case "gate": + return "hass:arrow-collapse-horizontal"; + default: + return "hass:arrow-down"; + } +}; diff --git a/src/components/ha-cover-controls.ts b/src/components/ha-cover-controls.ts index 3f1ca84f1346..06def92e2399 100644 --- a/src/components/ha-cover-controls.ts +++ b/src/components/ha-cover-controls.ts @@ -6,28 +6,33 @@ import { internalProperty, LitElement, property, + PropertyValues, TemplateResult, } from "lit-element"; import { classMap } from "lit-html/directives/class-map"; -import { HassEntity } from "home-assistant-js-websocket"; +import type { HassEntity } from "home-assistant-js-websocket"; +import type { HomeAssistant } from "../types"; import { UNAVAILABLE } from "../data/entity"; -import { HomeAssistant } from "../types"; import CoverEntity from "../util/cover-model"; import "./ha-icon-button"; +import { computeCloseIcon, computeOpenIcon } from "../common/entity/cover_icon"; @customElement("ha-cover-controls") class HaCoverControls extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _stateObj!: HassEntity; + @property({ attribute: false }) public stateObj!: HassEntity; - private _entityObj?: CoverEntity; + @internalProperty() private _entityObj?: CoverEntity; - public set stateObj(stateObj: HassEntity) { - this._entityObj = new CoverEntity(this.hass, stateObj); - this._stateObj = stateObj; + protected updated(changedProperties: PropertyValues): void { + super.updated(changedProperties); + + if (changedProperties.has("stateObj")) { + this._entityObj = new CoverEntity(this.hass, this.stateObj); + } } protected render(): TemplateResult { @@ -39,30 +44,34 @@ class HaCoverControls extends LitElement {
@@ -70,33 +79,11 @@ class HaCoverControls extends LitElement { `; } - private _computeOpenIcon(): string { - switch (this._stateObj.attributes.device_class) { - case "awning": - case "door": - case "gate": - return "hass:arrow-expand-horizontal"; - default: - return "hass:arrow-up"; - } - } - - private _computeCloseIcon(): string { - switch (this._stateObj.attributes.device_class) { - case "awning": - case "door": - case "gate": - return "hass:arrow-collapse-horizontal"; - default: - return "hass:arrow-down"; - } - } - private _computeOpenDisabled(): boolean { - if (this._stateObj.state === UNAVAILABLE) { + if (this.stateObj.state === UNAVAILABLE) { return true; } - const assumedState = this._stateObj.attributes.assumed_state === true; + const assumedState = this.stateObj.attributes.assumed_state === true; return ( (this._entityObj.isFullyOpen || this._entityObj.isOpening) && !assumedState @@ -104,10 +91,10 @@ class HaCoverControls extends LitElement { } private _computeClosedDisabled(): boolean { - if (this._stateObj.state === UNAVAILABLE) { + if (this.stateObj.state === UNAVAILABLE) { return true; } - const assumedState = this._stateObj.attributes.assumed_state === true; + const assumedState = this.stateObj.attributes.assumed_state === true; return ( (this._entityObj.isFullyClosed || this._entityObj.isClosing) && !assumedState @@ -134,7 +121,7 @@ class HaCoverControls extends LitElement { .state { white-space: nowrap; } - .invisible { + .hidden { visibility: hidden !important; } `;