diff --git a/src/data/entity.ts b/src/data/entity.ts new file mode 100644 index 0000000000..69028008b9 --- /dev/null +++ b/src/data/entity.ts @@ -0,0 +1 @@ +export const UNAVAILABLE = "unavailable"; diff --git a/src/panels/lovelace/cards/hui-picture-entity-card.js b/src/panels/lovelace/cards/hui-picture-entity-card.js deleted file mode 100644 index 03d6fa488c..0000000000 --- a/src/panels/lovelace/cards/hui-picture-entity-card.js +++ /dev/null @@ -1,197 +0,0 @@ -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; - -import "../../../components/ha-card"; -import "../components/hui-image"; - -import computeDomain from "../../../common/entity/compute_domain"; -import computeStateDisplay from "../../../common/entity/compute_state_display"; -import computeStateName from "../../../common/entity/compute_state_name"; - -import EventsMixin from "../../../mixins/events-mixin"; -import LocalizeMixin from "../../../mixins/localize-mixin"; -import { toggleEntity } from "../common/entity/toggle-entity"; -import { longPressBind } from "../common/directives/long-press-directive"; - -const UNAVAILABLE = "Unavailable"; - -/* - * @appliesMixin LocalizeMixin - * @appliesMixin EventsMixin - */ -class HuiPictureEntityCard extends EventsMixin(LocalizeMixin(PolymerElement)) { - static get template() { - return html` - - - - - - - - - `; - } - - static get properties() { - return { - hass: { - type: Object, - observer: "_hassChanged", - }, - _config: Object, - _name: String, - _state: String, - }; - } - - getCardSize() { - return 3; - } - - setConfig(config) { - if (!config || !config.entity) { - throw new Error("Error in card configuration."); - } - - this._entityDomain = computeDomain(config.entity); - if ( - this._entityDomain !== "camera" && - (!config.image && !config.state_image && !config.camera_image) - ) { - throw new Error("No image source configured."); - } - - this._config = config; - } - - ready() { - super.ready(); - const card = this.shadowRoot.querySelector("#card"); - longPressBind(card); - card.addEventListener("ha-click", () => this._cardClicked(false)); - card.addEventListener("ha-hold", () => this._cardClicked(true)); - } - - _hassChanged(hass) { - const config = this._config; - const entityId = config.entity; - const stateObj = hass.states[entityId]; - - // Nothing changed - if ( - (!stateObj && this._oldState === UNAVAILABLE) || - (stateObj && stateObj.state === this._oldState) - ) { - return; - } - - let name; - let state; - let stateLabel; - let available; - - if (stateObj) { - name = config.name || computeStateName(stateObj); - state = stateObj.state; - stateLabel = computeStateDisplay(this.localize, stateObj); - available = true; - } else { - name = config.name || entityId; - state = UNAVAILABLE; - stateLabel = this.localize("state.default.unavailable"); - available = false; - } - - this.setProperties({ - _name: name, - _state: stateLabel, - _oldState: state, - }); - - this.$.card.classList.toggle("canInteract", available); - } - - _showNameAndState(config) { - return config.show_name !== false && config.show_state !== false; - } - - _showName(config) { - return config.show_name !== false && config.show_state === false; - } - - _showState(config) { - return config.show_name === false && config.show_state !== false; - } - - _cardClicked(hold) { - const config = this._config; - const entityId = config.entity; - - if (!(entityId in this.hass.states)) return; - - const action = hold ? config.hold_action : config.tap_action || "more-info"; - - switch (action) { - case "toggle": - toggleEntity(this.hass, entityId); - break; - case "more-info": - this.fire("hass-more-info", { entityId }); - break; - default: - } - } - - _getCameraImage(config) { - return this._entityDomain === "camera" - ? config.entity - : config.camera_image; - } -} - -customElements.define("hui-picture-entity-card", HuiPictureEntityCard); diff --git a/src/panels/lovelace/cards/hui-picture-entity-card.ts b/src/panels/lovelace/cards/hui-picture-entity-card.ts new file mode 100644 index 0000000000..8c2e1cde12 --- /dev/null +++ b/src/panels/lovelace/cards/hui-picture-entity-card.ts @@ -0,0 +1,175 @@ +import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { TemplateResult } from "lit-html/lib/shady-render"; +import { classMap } from "lit-html/directives/classMap"; + +import "../../../components/ha-card"; +import "../components/hui-image"; + +import computeDomain from "../../../common/entity/compute_domain"; +import computeStateDisplay from "../../../common/entity/compute_state_display"; +import computeStateName from "../../../common/entity/compute_state_name"; + +import { longPress } from "../common/directives/long-press-directive"; +import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; +import { HomeAssistant } from "../../../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; +import { LovelaceCard } from "../types"; +import { handleClick } from "../common/handle-click"; +import { UNAVAILABLE } from "../../../data/entity"; + +interface Config extends LovelaceCardConfig { + entity: string; + name?: string; + navigation_path?: string; + image?: string; + camera_image?: string; + state_image?: {}; + aspect_ratio?: string; + tap_action?: "toggle" | "call-service" | "more-info" | "navigate"; + hold_action?: "toggle" | "call-service" | "more-info" | "navigate"; + service?: string; + service_data?: object; + show_name?: boolean; + show_state?: boolean; +} + +class HuiPictureEntityCard extends hassLocalizeLitMixin(LitElement) + implements LovelaceCard { + public hass?: HomeAssistant; + private _config?: Config; + + static get properties(): PropertyDeclarations { + return { + hass: {}, + _config: {}, + }; + } + + public getCardSize(): number { + return 3; + } + + public setConfig(config: Config): void { + if (!config || !config.entity) { + throw new Error("Invalid Configuration: 'entity' required"); + } + + if ( + computeDomain(config.entity) !== "camera" && + (!config.image && !config.state_image && !config.camera_image) + ) { + throw new Error("No image source configured."); + } + + this._config = { show_name: true, show_state: true, ...config }; + } + + protected render(): TemplateResult { + if (!this._config || !this.hass || !this.hass.states[this._config.entity]) { + return html``; + } + + const stateObj = this.hass.states[this._config.entity]; + const name = this._config.name || computeStateName(stateObj); + const state = computeStateDisplay( + this.localize, + stateObj, + this.hass.language + ); + + let footer: TemplateResult | string = ""; + if (this._config.show_name && this._config.show_state) { + footer = html` + + `; + } else if (this._config.show_name) { + footer = html` + + `; + } else if (this._config.show_state) { + footer = html` + + `; + } + + return html` + ${this.renderStyle()} + + + ${footer} + + `; + } + + private renderStyle(): TemplateResult { + return html` + + `; + } + + private _handleClick() { + handleClick(this, this.hass!, this._config!, false); + } + + private _handleHold() { + handleClick(this, this.hass!, this._config!, true); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-picture-entity-card": HuiPictureEntityCard; + } +} + +customElements.define("hui-picture-entity-card", HuiPictureEntityCard); diff --git a/src/panels/lovelace/common/handle-click.ts b/src/panels/lovelace/common/handle-click.ts index 714f4217eb..f6f654f744 100644 --- a/src/panels/lovelace/common/handle-click.ts +++ b/src/panels/lovelace/common/handle-click.ts @@ -3,11 +3,12 @@ import { LovelaceElementConfig } from "../elements/types"; import { fireEvent } from "../../../common/dom/fire_event"; import { navigate } from "../../../common/navigate"; import { toggleEntity } from "../../../../src/panels/lovelace/common/entity/toggle-entity"; +import { LovelaceCardConfig } from "../../../data/lovelace"; export const handleClick = ( node: HTMLElement, hass: HomeAssistant, - config: LovelaceElementConfig, + config: LovelaceElementConfig | LovelaceCardConfig, hold: boolean ): void => { let action = config.tap_action || "more-info";