Convert HA-STATE-LABEL-BADGE to lit (#2268)

This commit is contained in:
Paulus Schoutsen 2018-12-11 21:41:38 +01:00 committed by GitHub
parent bd46e3b8e0
commit 99395360c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 208 additions and 195 deletions

View File

@ -1,25 +1,206 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
import "../ha-label-badge";
import {
LitElement,
html,
PropertyValues,
PropertyDeclarations,
} from "@polymer/lit-element";
import { TemplateResult } from "lit-html";
import { HassEntity } from "home-assistant-js-websocket";
import { classMap } from "lit-html/directives/classMap";
import computeStateDomain from "../../common/entity/compute_state_domain";
import computeStateName from "../../common/entity/compute_state_name";
import domainIcon from "../../common/entity/domain_icon";
import stateIcon from "../../common/entity/state_icon";
import timerTimeRemaining from "../../common/entity/timer_time_remaining";
import attributeClassNames from "../../common/entity/attribute_class_names";
import secondsToDuration from "../../common/datetime/seconds_to_duration";
import { fireEvent } from "../../common/dom/fire_event";
import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin";
import EventsMixin from "../../mixins/events-mixin";
import LocalizeMixin from "../../mixins/localize-mixin";
import "../ha-label-badge";
/*
* @appliesMixin LocalizeMixin
* @appliesMixin EventsMixin
*/
class HaStateLabelBadge extends LocalizeMixin(EventsMixin(PolymerElement)) {
static get template() {
export class HaStateLabelBadge extends hassLocalizeLitMixin(LitElement) {
public state?: HassEntity;
private _connected?: boolean;
private _updateRemaining?: number;
private _timerTimeRemaining?: number;
public connectedCallback(): void {
super.connectedCallback();
this._connected = true;
this.startInterval(this.state);
}
public disconnectedCallback(): void {
super.disconnectedCallback();
this._connected = false;
this.clearInterval();
}
protected render(): TemplateResult {
const state = this.state;
if (!state) {
return html`
${this.renderStyle()}
<ha-label-badge label="not found"></ha-label-badge>
`;
}
const domain = computeStateDomain(state);
return html`
${this.renderStyle()}
<ha-label-badge
class="${
classMap({
[domain]: true,
"has-unit_of_measurement":
"unit_of_measurement" in state.attributes,
})
}"
.value="${this._computeValue(domain, state)}"
.icon="${this._computeIcon(domain, state)}"
.image="${state.attributes.entity_picture}"
.label="${this._computeLabel(domain, state, this._timerTimeRemaining)}"
.description="${computeStateName(state)}"
></ha-label-badge>
`;
}
static get properties(): PropertyDeclarations {
return {
hass: {},
state: {},
_timerTimeRemaining: {},
};
}
protected firstUpdated(changedProperties: PropertyValues): void {
super.firstUpdated(changedProperties);
this.addEventListener("click", (ev) => {
ev.stopPropagation();
fireEvent(this, "hass-more-info", { entityId: this.state!.entity_id });
});
}
protected updated(changedProperties: PropertyValues): void {
super.updated(changedProperties);
if (this._connected && changedProperties.has("state")) {
this.startInterval(this.state);
}
}
private _computeValue(domain: string, state: HassEntity) {
switch (domain) {
case "binary_sensor":
case "device_tracker":
case "updater":
case "sun":
case "alarm_control_panel":
case "timer":
return null;
case "sensor":
default:
return state.state === "unknown"
? "-"
: this.localize(`component.${domain}.state.${state.state}`) ||
state.state;
}
}
private _computeIcon(domain: string, state: HassEntity) {
if (state.state === "unavailable") {
return null;
}
switch (domain) {
case "alarm_control_panel":
if (state.state === "pending") {
return "hass:clock-fast";
}
if (state.state === "armed_away") {
return "hass:nature";
}
if (state.state === "armed_home") {
return "hass:home-variant";
}
if (state.state === "armed_night") {
return "hass:weather-night";
}
if (state.state === "armed_custom_bypass") {
return "hass:security-home";
}
if (state.state === "triggered") {
return "hass:alert-circle";
}
// state == 'disarmed'
return domainIcon(domain, state.state);
case "binary_sensor":
case "device_tracker":
case "updater":
return stateIcon(state);
case "sun":
return state.state === "above_horizon"
? domainIcon(domain)
: "hass:brightness-3";
case "timer":
return state.state === "active" ? "hass:timer" : "hass:timer-off";
default:
return null;
}
}
private _computeLabel(domain, state, _timerTimeRemaining) {
if (
state.state === "unavailable" ||
["device_tracker", "alarm_control_panel"].includes(domain)
) {
// Localize the state with a special state_badge namespace, which has variations of
// the state translations that are truncated to fit within the badge label. Translations
// are only added for device_tracker and alarm_control_panel.
return (
this.localize(`state_badge.${domain}.${state.state}`) ||
this.localize(`state_badge.default.${state.state}`) ||
state.state
);
}
if (domain === "timer") {
return secondsToDuration(_timerTimeRemaining);
}
return state.attributes.unit_of_measurement || null;
}
private clearInterval() {
if (this._updateRemaining) {
clearInterval(this._updateRemaining);
this._updateRemaining = undefined;
}
}
private startInterval(stateObj) {
this.clearInterval();
if (computeStateDomain(stateObj) === "timer") {
this.calculateTimerRemaining(stateObj);
if (stateObj.state === "active") {
this._updateRemaining = window.setInterval(
() => this.calculateTimerRemaining(this.state),
1000
);
}
}
}
private calculateTimerRemaining(stateObj) {
this._timerTimeRemaining = timerTimeRemaining(stateObj);
}
private renderStyle(): TemplateResult {
return html`
<style>
:host {
@ -61,175 +242,13 @@ class HaStateLabelBadge extends LocalizeMixin(EventsMixin(PolymerElement)) {
);
}
</style>
<ha-label-badge
class$="[[computeClassNames(state)]]"
value="[[computeValue(localize, state)]]"
icon="[[computeIcon(state)]]"
image="[[computeImage(state)]]"
label="[[computeLabel(localize, state, _timerTimeRemaining)]]"
description="[[computeDescription(state)]]"
></ha-label-badge>
`;
}
}
static get properties() {
return {
hass: Object,
state: {
type: Object,
observer: "stateChanged",
},
_timerTimeRemaining: {
type: Number,
value: 0,
},
};
}
connectedCallback() {
super.connectedCallback();
this.startInterval(this.state);
}
disconnectedCallback() {
super.disconnectedCallback();
this.clearInterval();
}
ready() {
super.ready();
this.addEventListener("click", (ev) => this.badgeTap(ev));
}
badgeTap(ev) {
ev.stopPropagation();
this.fire("hass-more-info", { entityId: this.state.entity_id });
}
computeClassNames(state) {
const classes = [computeStateDomain(state)];
classes.push(attributeClassNames(state, ["unit_of_measurement"]));
return classes.join(" ");
}
computeValue(localize, state) {
const domain = computeStateDomain(state);
switch (domain) {
case "binary_sensor":
case "device_tracker":
case "updater":
case "sun":
case "alarm_control_panel":
case "timer":
return null;
case "sensor":
default:
return state.state === "unknown"
? "-"
: localize(`component.${domain}.state.${state.state}`) || state.state;
}
}
computeIcon(state) {
if (state.state === "unavailable") {
return null;
}
const domain = computeStateDomain(state);
switch (domain) {
case "alarm_control_panel":
if (state.state === "pending") {
return "hass:clock-fast";
}
if (state.state === "armed_away") {
return "hass:nature";
}
if (state.state === "armed_home") {
return "hass:home-variant";
}
if (state.state === "armed_night") {
return "hass:weather-night";
}
if (state.state === "armed_custom_bypass") {
return "hass:security-home";
}
if (state.state === "triggered") {
return "hass:alert-circle";
}
// state == 'disarmed'
return domainIcon(domain, state.state);
case "binary_sensor":
case "device_tracker":
case "updater":
return stateIcon(state);
case "sun":
return state.state === "above_horizon"
? domainIcon(domain)
: "hass:brightness-3";
case "timer":
return state.state === "active" ? "hass:timer" : "hass:timer-off";
default:
return null;
}
}
computeImage(state) {
return state.attributes.entity_picture || null;
}
computeLabel(localize, state, _timerTimeRemaining) {
const domain = computeStateDomain(state);
if (
state.state === "unavailable" ||
["device_tracker", "alarm_control_panel"].includes(domain)
) {
// Localize the state with a special state_badge namespace, which has variations of
// the state translations that are truncated to fit within the badge label. Translations
// are only added for device_tracker and alarm_control_panel.
return (
localize(`state_badge.${domain}.${state.state}`) ||
localize(`state_badge.default.${state.state}`) ||
state.state
);
}
if (domain === "timer") {
return secondsToDuration(_timerTimeRemaining);
}
return state.attributes.unit_of_measurement || null;
}
computeDescription(state) {
return computeStateName(state);
}
stateChanged(stateObj) {
this.updateStyles();
this.startInterval(stateObj);
}
clearInterval() {
if (this._updateRemaining) {
clearInterval(this._updateRemaining);
this._updateRemaining = null;
}
}
startInterval(stateObj) {
this.clearInterval();
if (computeStateDomain(stateObj) === "timer") {
this.calculateTimerRemaining(stateObj);
if (stateObj.state === "active") {
this._updateRemaining = setInterval(
() => this.calculateTimerRemaining(this.state),
1000
);
}
}
}
calculateTimerRemaining(stateObj) {
this._timerTimeRemaining = timerTimeRemaining(stateObj);
declare global {
interface HTMLElementTagNameMap {
"ha-state-label-badge": HaStateLabelBadge;
}
}

View File

@ -1,4 +1,5 @@
import IntlMessageFormat from "intl-messageformat/src/main";
import { HomeAssistant } from "../types";
/**
* Adapted from Polymer app-localize-behavior.
@ -32,6 +33,7 @@ export interface FormatsType {
export type LocalizeFunc = (key: string, ...args: any[]) => string;
export interface LocalizeMixin {
hass?: HomeAssistant;
localize: LocalizeFunc;
}

View File

@ -19,7 +19,7 @@ declare global {
export class HuiThemeSelectionEditor extends hassLocalizeLitMixin(LitElement) {
public value?: string;
protected hass?: HomeAssistant;
public hass?: HomeAssistant;
static get properties(): PropertyDeclarations {
return {

View File

@ -14,7 +14,7 @@ import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
import { SaveDialogParams } from "./show-save-config-dialog";
export class HuiSaveConfig extends hassLocalizeLitMixin(LitElement) {
protected hass?: HomeAssistant;
public hass?: HomeAssistant;
private _params?: SaveDialogParams;
private _saving: boolean;

View File

@ -30,7 +30,7 @@ import { deleteView, addView, replaceView } from "../config-util";
export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
public lovelace?: Lovelace;
public viewIndex?: number;
protected hass?: HomeAssistant;
public hass?: HomeAssistant;
private _config?: LovelaceViewConfig;
private _badges?: EntityConfig[];
private _cards?: LovelaceCardConfig[];

View File

@ -5,9 +5,11 @@ import {
PropertyDeclarations,
} from "@polymer/lit-element";
import { TemplateResult } from "lit-html";
import { PolymerElement } from "@polymer/polymer";
import "../../components/entity/ha-state-label-badge";
// This one is for types
// tslint:disable-next-line
import { HaStateLabelBadge } from "../../components/entity/ha-state-label-badge";
import applyThemesOnElement from "../../common/dom/apply_themes_on_element";
@ -28,7 +30,7 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) {
public columns?: number;
public index?: number;
private _cards: LovelaceCard[];
private _badges: Array<{ element: PolymerElement; entityId: string }>;
private _badges: Array<{ element: HaStateLabelBadge; entityId: string }>;
static get properties(): PropertyDeclarations {
return {
@ -158,10 +160,8 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) {
} else if (changedProperties.has("hass")) {
this._badges.forEach((badge) => {
const { element, entityId } = badge;
element.setProperties({
hass: this.hass,
state: this.hass!.states[entityId],
});
element.hass = this.hass!;
element.state = this.hass!.states[entityId];
});
}
@ -196,17 +196,9 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) {
const elements: HUIView["_badges"] = [];
for (const entityId of config.badges) {
if (!(entityId in this.hass!.states)) {
continue;
}
const element = document.createElement(
"ha-state-label-badge"
) as PolymerElement;
element.setProperties({
hass: this.hass,
state: this.hass!.states[entityId],
});
const element = document.createElement("ha-state-label-badge");
element.hass = this.hass;
element.state = this.hass!.states[entityId];
elements.push({ element, entityId });
root.appendChild(element);
}