mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
Display live remaining time for timer on tile card (#21290)
Display timer by default on tile card
This commit is contained in:
parent
d9583582e6
commit
e59c04c685
@ -92,7 +92,7 @@ export const computeDisplayTimer = (
|
|||||||
return hass.formatEntityState(stateObj);
|
return hass.formatEntityState(stateObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
let display = secondsToDuration(timeRemaining || 0);
|
let display = secondsToDuration(timeRemaining || 0) || "0";
|
||||||
|
|
||||||
if (stateObj.state === "paused") {
|
if (stateObj.state === "paused") {
|
||||||
display = `${display} (${hass.formatEntityState(stateObj)})`;
|
display = `${display} (${hass.formatEntityState(stateObj)})`;
|
||||||
|
@ -311,10 +311,19 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (domain === "update") {
|
if (domain === "update") {
|
||||||
return html`${computeUpdateStateDisplay(
|
return html`
|
||||||
stateObj as UpdateEntity,
|
${computeUpdateStateDisplay(stateObj as UpdateEntity, this.hass!)}
|
||||||
this.hass!
|
`;
|
||||||
)}`;
|
}
|
||||||
|
|
||||||
|
if (domain === "timer") {
|
||||||
|
import("../../../state-display/state-display-timer");
|
||||||
|
return html`
|
||||||
|
<state-display-timer
|
||||||
|
.hass=${this.hass}
|
||||||
|
.stateObj=${stateObj}
|
||||||
|
></state-display-timer>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._renderStateContent(stateObj, "state");
|
return this._renderStateContent(stateObj, "state");
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { LitElement, PropertyValues, html, nothing } from "lit";
|
||||||
import { html, LitElement, PropertyValues, nothing } from "lit";
|
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { computeDisplayTimer, timerTimeRemaining } from "../../../data/timer";
|
import "../../../state-display/state-display-timer";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||||
import "../components/hui-generic-entity-row";
|
import "../components/hui-generic-entity-row";
|
||||||
@ -14,42 +13,11 @@ class HuiTimerEntityRow extends LitElement {
|
|||||||
|
|
||||||
@state() private _config?: EntityConfig;
|
@state() private _config?: EntityConfig;
|
||||||
|
|
||||||
@state() private _timeRemaining?: number;
|
|
||||||
|
|
||||||
private _interval?: number;
|
|
||||||
|
|
||||||
public setConfig(config: EntityConfig): void {
|
public setConfig(config: EntityConfig): void {
|
||||||
if (!config) {
|
if (!config) {
|
||||||
throw new Error("Invalid configuration");
|
throw new Error("Invalid configuration");
|
||||||
}
|
}
|
||||||
this._config = config;
|
this._config = config;
|
||||||
|
|
||||||
if (!this.hass) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const stateObj = this.hass!.states[this._config.entity];
|
|
||||||
|
|
||||||
if (stateObj) {
|
|
||||||
this._startInterval(stateObj);
|
|
||||||
} else {
|
|
||||||
this._clearInterval();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public disconnectedCallback(): void {
|
|
||||||
super.disconnectedCallback();
|
|
||||||
this._clearInterval();
|
|
||||||
}
|
|
||||||
|
|
||||||
public connectedCallback(): void {
|
|
||||||
super.connectedCallback();
|
|
||||||
if (this._config && this._config.entity) {
|
|
||||||
const stateObj = this.hass?.states[this._config!.entity];
|
|
||||||
if (stateObj) {
|
|
||||||
this._startInterval(stateObj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
@ -70,61 +38,18 @@ class HuiTimerEntityRow extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
|
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
|
||||||
<div class="text-content">
|
<div class="text-content">
|
||||||
${computeDisplayTimer(this.hass, stateObj, this._timeRemaining)}
|
<state-display-timer
|
||||||
|
.hass=${this.hass}
|
||||||
|
.stateObj=${stateObj}
|
||||||
|
></state-display-timer>
|
||||||
</div>
|
</div>
|
||||||
</hui-generic-entity-row>
|
</hui-generic-entity-row>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||||
if (changedProps.has("_timeRemaining")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hasConfigOrEntityChanged(this, changedProps);
|
return hasConfigOrEntityChanged(this, changedProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected updated(changedProps: PropertyValues) {
|
|
||||||
super.updated(changedProps);
|
|
||||||
|
|
||||||
if (!this._config || !changedProps.has("hass")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const stateObj = this.hass!.states[this._config!.entity];
|
|
||||||
const oldHass = changedProps.get("hass") as this["hass"];
|
|
||||||
const oldStateObj = oldHass
|
|
||||||
? oldHass.states[this._config!.entity]
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
if (oldStateObj !== stateObj) {
|
|
||||||
this._startInterval(stateObj);
|
|
||||||
} else if (!stateObj) {
|
|
||||||
this._clearInterval();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _clearInterval(): void {
|
|
||||||
if (this._interval) {
|
|
||||||
window.clearInterval(this._interval);
|
|
||||||
this._interval = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _startInterval(stateObj: HassEntity): void {
|
|
||||||
this._clearInterval();
|
|
||||||
this._calculateRemaining(stateObj);
|
|
||||||
|
|
||||||
if (stateObj.state === "active") {
|
|
||||||
this._interval = window.setInterval(
|
|
||||||
() => this._calculateRemaining(stateObj),
|
|
||||||
1000
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _calculateRemaining(stateObj: HassEntity): void {
|
|
||||||
this._timeRemaining = timerTimeRemaining(stateObj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
74
src/state-display/state-display-timer.ts
Normal file
74
src/state-display/state-display-timer.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import type { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
import { PropertyValues, ReactiveElement } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { computeDisplayTimer, timerTimeRemaining } from "../data/timer";
|
||||||
|
import type { HomeAssistant } from "../types";
|
||||||
|
|
||||||
|
@customElement("state-display-timer")
|
||||||
|
class StateDisplayTimer extends ReactiveElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public stateObj!: HassEntity;
|
||||||
|
|
||||||
|
@state() private timeRemaining?: number;
|
||||||
|
|
||||||
|
private _updateRemaining: any;
|
||||||
|
|
||||||
|
protected createRenderRoot() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected update(changedProps: PropertyValues) {
|
||||||
|
super.update(changedProps);
|
||||||
|
this.innerHTML =
|
||||||
|
computeDisplayTimer(this.hass, this.stateObj, this.timeRemaining) ?? "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
if (this.stateObj) {
|
||||||
|
this._startInterval(this.stateObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
this._clearInterval();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected willUpdate(changedProp: PropertyValues): void {
|
||||||
|
super.willUpdate(changedProp);
|
||||||
|
if (changedProp.has("stateObj")) {
|
||||||
|
this._startInterval(this.stateObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _clearInterval() {
|
||||||
|
if (this._updateRemaining) {
|
||||||
|
clearInterval(this._updateRemaining);
|
||||||
|
this._updateRemaining = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _startInterval(stateObj: HassEntity) {
|
||||||
|
this._clearInterval();
|
||||||
|
this._calculateRemaining(stateObj);
|
||||||
|
|
||||||
|
if (stateObj.state === "active") {
|
||||||
|
this._updateRemaining = setInterval(
|
||||||
|
() => this._calculateRemaining(this.stateObj),
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _calculateRemaining(stateObj: HassEntity) {
|
||||||
|
this.timeRemaining = timerTimeRemaining(stateObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"state-display-timer": StateDisplayTimer;
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,10 @@
|
|||||||
import type { HassEntity } from "home-assistant-js-websocket";
|
import type { HassEntity } from "home-assistant-js-websocket";
|
||||||
import {
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
css,
|
|
||||||
CSSResultGroup,
|
|
||||||
html,
|
|
||||||
LitElement,
|
|
||||||
PropertyValues,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit";
|
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import "../components/entity/state-info";
|
import "../components/entity/state-info";
|
||||||
import { computeDisplayTimer, timerTimeRemaining } from "../data/timer";
|
|
||||||
import { HomeAssistant } from "../types";
|
|
||||||
import { haStyle } from "../resources/styles";
|
import { haStyle } from "../resources/styles";
|
||||||
|
import "../state-display/state-display-timer";
|
||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
@customElement("state-card-timer")
|
@customElement("state-card-timer")
|
||||||
class StateCardTimer extends LitElement {
|
class StateCardTimer extends LitElement {
|
||||||
@ -21,10 +14,6 @@ class StateCardTimer extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public inDialog = false;
|
@property({ type: Boolean }) public inDialog = false;
|
||||||
|
|
||||||
@property({ type: Number }) public timeRemaining?: number;
|
|
||||||
|
|
||||||
private _updateRemaining: any;
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="horizontal justified layout">
|
<div class="horizontal justified layout">
|
||||||
@ -34,63 +23,21 @@ class StateCardTimer extends LitElement {
|
|||||||
.inDialog=${this.inDialog}
|
.inDialog=${this.inDialog}
|
||||||
></state-info>
|
></state-info>
|
||||||
<div class="state">
|
<div class="state">
|
||||||
${this._displayState(this.timeRemaining, this.stateObj)}
|
<state-display-timer
|
||||||
|
.hass=${this.hass}
|
||||||
|
.stateObj=${this.stateObj}
|
||||||
|
></state-display-timer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
super.connectedCallback();
|
|
||||||
this._startInterval(this.stateObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnectedCallback() {
|
|
||||||
super.disconnectedCallback();
|
|
||||||
this._clearInterval();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected willUpdate(changedProp: PropertyValues): void {
|
|
||||||
super.willUpdate(changedProp);
|
|
||||||
if (changedProp.has("stateObj")) {
|
|
||||||
this._startInterval(this.stateObj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _clearInterval() {
|
|
||||||
if (this._updateRemaining) {
|
|
||||||
clearInterval(this._updateRemaining);
|
|
||||||
this._updateRemaining = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _startInterval(stateObj) {
|
|
||||||
this._clearInterval();
|
|
||||||
this._calculateRemaining(stateObj);
|
|
||||||
|
|
||||||
if (stateObj.state === "active") {
|
|
||||||
this._updateRemaining = setInterval(
|
|
||||||
() => this._calculateRemaining(this.stateObj),
|
|
||||||
1000
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _calculateRemaining(stateObj) {
|
|
||||||
this.timeRemaining = timerTimeRemaining(stateObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _displayState(timeRemaining, stateObj) {
|
|
||||||
return computeDisplayTimer(this.hass, stateObj, timeRemaining);
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
.state {
|
.state {
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
|
|
||||||
margin-left: 16px;
|
margin-left: 16px;
|
||||||
margin-inline-start: 16px;
|
margin-inline-start: 16px;
|
||||||
margin-inline-end: initial;
|
margin-inline-end: initial;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user