mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Add live camera & custom AR to Area card (#18643)
This commit is contained in:
parent
a1236924aa
commit
a45eefa742
@ -21,6 +21,7 @@ import {
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { STATES_OFF } from "../../../common/const";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
@ -29,6 +30,7 @@ import { domainIcon } from "../../../common/entity/domain_icon";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { formatNumber } from "../../../common/number/format_number";
|
||||
import { subscribeOne } from "../../../common/util/subscribe-one";
|
||||
import parseAspectRatio from "../../../common/util/parse-aspect-ratio";
|
||||
import "../../../components/entity/state-badge";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon-button";
|
||||
@ -55,6 +57,8 @@ import "../components/hui-warning";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { AreaCardConfig } from "./types";
|
||||
|
||||
export const DEFAULT_ASPECT_RATIO = "16:9";
|
||||
|
||||
const SENSOR_DOMAINS = ["sensor"];
|
||||
|
||||
const ALERT_DOMAINS = ["binary_sensor"];
|
||||
@ -109,6 +113,11 @@ export class HuiAreaCard
|
||||
|
||||
@state() private _areas?: AreaRegistryEntry[];
|
||||
|
||||
private _ratio: {
|
||||
w: number;
|
||||
h: number;
|
||||
} | null = null;
|
||||
|
||||
private _entitiesByDomain = memoizeOne(
|
||||
(
|
||||
areaId: string,
|
||||
@ -319,6 +328,18 @@ export class HuiAreaCard
|
||||
return false;
|
||||
}
|
||||
|
||||
public willUpdate(changedProps: PropertyValues) {
|
||||
if (changedProps.has("_config") || this._ratio === null) {
|
||||
this._ratio = this._config?.aspect_ratio
|
||||
? parseAspectRatio(this._config?.aspect_ratio)
|
||||
: null;
|
||||
|
||||
if (this._ratio === null || this._ratio.w <= 0 || this._ratio.h <= 0) {
|
||||
this._ratio = parseAspectRatio(DEFAULT_ASPECT_RATIO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
@ -374,15 +395,24 @@ export class HuiAreaCard
|
||||
cameraEntityId = entitiesByDomain.camera[0].entity_id;
|
||||
}
|
||||
|
||||
const imageClass = area.picture || cameraEntityId;
|
||||
return html`
|
||||
<ha-card class=${area.picture || cameraEntityId ? "image" : ""}>
|
||||
<ha-card
|
||||
class=${imageClass ? "image" : ""}
|
||||
style=${styleMap({
|
||||
paddingBottom: imageClass
|
||||
? "0"
|
||||
: `${((100 * this._ratio!.h) / this._ratio!.w).toFixed(2)}%`,
|
||||
})}
|
||||
>
|
||||
${area.picture || cameraEntityId
|
||||
? html`<hui-image
|
||||
.config=${this._config}
|
||||
.hass=${this.hass}
|
||||
.image=${area.picture ? area.picture : undefined}
|
||||
.cameraImage=${cameraEntityId}
|
||||
aspectRatio="16:9"
|
||||
.cameraView=${this._config.camera_view}
|
||||
.aspectRatio=${this._config.aspect_ratio || DEFAULT_ASPECT_RATIO}
|
||||
></hui-image>`
|
||||
: ""}
|
||||
|
||||
@ -488,14 +518,9 @@ export class HuiAreaCard
|
||||
ha-card {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
ha-card.image {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -93,6 +93,8 @@ export interface AreaCardConfig extends LovelaceCardConfig {
|
||||
area: string;
|
||||
navigation_path?: string;
|
||||
show_camera?: boolean;
|
||||
camera_view?: HuiImage["cameraView"];
|
||||
aspect_ratio?: string;
|
||||
}
|
||||
|
||||
export interface ButtonCardConfig extends LovelaceCardConfig {
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { assert, assign, boolean, object, optional, string } from "superstruct";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-form/ha-form";
|
||||
import { DEFAULT_ASPECT_RATIO } from "../../cards/hui-area-card";
|
||||
import type { SchemaUnion } from "../../../../components/ha-form/types";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { AreaCardConfig } from "../../cards/types";
|
||||
@ -16,26 +18,10 @@ const cardConfigStruct = assign(
|
||||
navigation_path: optional(string()),
|
||||
theme: optional(string()),
|
||||
show_camera: optional(boolean()),
|
||||
camera_view: optional(string()),
|
||||
aspect_ratio: optional(string()),
|
||||
})
|
||||
);
|
||||
|
||||
const SCHEMA = [
|
||||
{ name: "area", selector: { area: {} } },
|
||||
{ name: "show_camera", required: false, selector: { boolean: {} } },
|
||||
{
|
||||
name: "",
|
||||
type: "grid",
|
||||
schema: [
|
||||
{
|
||||
name: "navigation_path",
|
||||
required: false,
|
||||
selector: { navigation: {} },
|
||||
},
|
||||
{ name: "theme", required: false, selector: { theme: {} } },
|
||||
],
|
||||
},
|
||||
] as const;
|
||||
|
||||
@customElement("hui-area-card-editor")
|
||||
export class HuiAreaCardEditor
|
||||
extends LitElement
|
||||
@ -45,6 +31,39 @@ export class HuiAreaCardEditor
|
||||
|
||||
@state() private _config?: AreaCardConfig;
|
||||
|
||||
private _schema = memoizeOne(
|
||||
(showCamera: boolean) =>
|
||||
[
|
||||
{ name: "area", selector: { area: {} } },
|
||||
{ name: "show_camera", required: false, selector: { boolean: {} } },
|
||||
...(showCamera
|
||||
? ([
|
||||
{
|
||||
name: "camera_view",
|
||||
selector: { select: { options: ["auto", "live"] } },
|
||||
},
|
||||
] as const)
|
||||
: []),
|
||||
{
|
||||
name: "",
|
||||
type: "grid",
|
||||
schema: [
|
||||
{
|
||||
name: "navigation_path",
|
||||
required: false,
|
||||
selector: { navigation: {} },
|
||||
},
|
||||
{ name: "theme", required: false, selector: { theme: {} } },
|
||||
{
|
||||
name: "aspect_ratio",
|
||||
default: DEFAULT_ASPECT_RATIO,
|
||||
selector: { text: {} },
|
||||
},
|
||||
],
|
||||
},
|
||||
] as const
|
||||
);
|
||||
|
||||
public setConfig(config: AreaCardConfig): void {
|
||||
assert(config, cardConfigStruct);
|
||||
this._config = config;
|
||||
@ -55,11 +74,18 @@ export class HuiAreaCardEditor
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const schema = this._schema(this._config.show_camera || false);
|
||||
|
||||
const data = {
|
||||
camera_view: "auto",
|
||||
...this._config,
|
||||
};
|
||||
|
||||
return html`
|
||||
<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${this._config}
|
||||
.schema=${SCHEMA}
|
||||
.data=${data}
|
||||
.schema=${schema}
|
||||
.computeLabel=${this._computeLabelCallback}
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-form>
|
||||
@ -68,10 +94,15 @@ export class HuiAreaCardEditor
|
||||
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
const config = ev.detail.value;
|
||||
if (!config.show_camera) {
|
||||
delete config.camera_view;
|
||||
}
|
||||
fireEvent(this, "config-changed", { config });
|
||||
}
|
||||
|
||||
private _computeLabelCallback = (schema: SchemaUnion<typeof SCHEMA>) => {
|
||||
private _computeLabelCallback = (
|
||||
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||
) => {
|
||||
switch (schema.name) {
|
||||
case "theme":
|
||||
return `${this.hass!.localize(
|
||||
@ -85,6 +116,14 @@ export class HuiAreaCardEditor
|
||||
return this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.action-editor.navigation_path"
|
||||
);
|
||||
case "aspect_ratio":
|
||||
return this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.card.generic.aspect_ratio"
|
||||
);
|
||||
case "camera_view":
|
||||
return this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.card.generic.camera_view"
|
||||
);
|
||||
}
|
||||
return this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.area.${schema.name}`
|
||||
|
Loading…
x
Reference in New Issue
Block a user