mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-18 23:06:40 +00:00
Convert cover UI to Lit + ensure proper tilt rendering (#10671)
This commit is contained in:
parent
faec09f0d1
commit
2c0b2f4bc5
164
gallery/src/demos/demo-more-info-cover.ts
Normal file
164
gallery/src/demos/demo-more-info-cover.ts
Normal file
@ -0,0 +1,164 @@
|
||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import "../../../src/components/ha-card";
|
||||
import {
|
||||
SUPPORT_OPEN,
|
||||
SUPPORT_STOP,
|
||||
SUPPORT_CLOSE,
|
||||
SUPPORT_SET_POSITION,
|
||||
SUPPORT_OPEN_TILT,
|
||||
SUPPORT_STOP_TILT,
|
||||
SUPPORT_CLOSE_TILT,
|
||||
SUPPORT_SET_TILT_POSITION,
|
||||
} from "../../../src/data/cover";
|
||||
import "../../../src/dialogs/more-info/more-info-content";
|
||||
import { getEntity } from "../../../src/fake_data/entity";
|
||||
import {
|
||||
MockHomeAssistant,
|
||||
provideHass,
|
||||
} from "../../../src/fake_data/provide_hass";
|
||||
import "../components/demo-more-infos";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("cover", "position_buttons", "on", {
|
||||
friendly_name: "Position Buttons",
|
||||
supported_features: SUPPORT_OPEN + SUPPORT_STOP + SUPPORT_CLOSE,
|
||||
}),
|
||||
getEntity("cover", "position_slider_half", "on", {
|
||||
friendly_name: "Position Half-Open",
|
||||
supported_features:
|
||||
SUPPORT_OPEN + SUPPORT_STOP + SUPPORT_CLOSE + SUPPORT_SET_POSITION,
|
||||
current_position: 50,
|
||||
}),
|
||||
getEntity("cover", "position_slider_open", "on", {
|
||||
friendly_name: "Position Open",
|
||||
supported_features:
|
||||
SUPPORT_OPEN + SUPPORT_STOP + SUPPORT_CLOSE + SUPPORT_SET_POSITION,
|
||||
current_position: 100,
|
||||
}),
|
||||
getEntity("cover", "position_slider_closed", "on", {
|
||||
friendly_name: "Position Closed",
|
||||
supported_features:
|
||||
SUPPORT_OPEN + SUPPORT_STOP + SUPPORT_CLOSE + SUPPORT_SET_POSITION,
|
||||
current_position: 0,
|
||||
}),
|
||||
getEntity("cover", "tilt_buttons", "on", {
|
||||
friendly_name: "Tilt Buttons",
|
||||
supported_features:
|
||||
SUPPORT_OPEN_TILT + SUPPORT_STOP_TILT + SUPPORT_CLOSE_TILT,
|
||||
}),
|
||||
getEntity("cover", "tilt_slider_half", "on", {
|
||||
friendly_name: "Tilt Half-Open",
|
||||
supported_features:
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT +
|
||||
SUPPORT_SET_TILT_POSITION,
|
||||
current_tilt_position: 50,
|
||||
}),
|
||||
getEntity("cover", "tilt_slider_open", "on", {
|
||||
friendly_name: "Tilt Open",
|
||||
supported_features:
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT +
|
||||
SUPPORT_SET_TILT_POSITION,
|
||||
current_tilt_position: 100,
|
||||
}),
|
||||
getEntity("cover", "tilt_slider_closed", "on", {
|
||||
friendly_name: "Tilt Closed",
|
||||
supported_features:
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT +
|
||||
SUPPORT_SET_TILT_POSITION,
|
||||
current_tilt_position: 0,
|
||||
}),
|
||||
getEntity("cover", "position_slider_tilt_slider", "on", {
|
||||
friendly_name: "Both Sliders",
|
||||
supported_features:
|
||||
SUPPORT_OPEN +
|
||||
SUPPORT_STOP +
|
||||
SUPPORT_CLOSE +
|
||||
SUPPORT_SET_POSITION +
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT +
|
||||
SUPPORT_SET_TILT_POSITION,
|
||||
current_position: 30,
|
||||
current_tilt_position: 70,
|
||||
}),
|
||||
getEntity("cover", "position_tilt_slider", "on", {
|
||||
friendly_name: "Position & Tilt Slider",
|
||||
supported_features:
|
||||
SUPPORT_OPEN +
|
||||
SUPPORT_STOP +
|
||||
SUPPORT_CLOSE +
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT +
|
||||
SUPPORT_SET_TILT_POSITION,
|
||||
current_tilt_position: 70,
|
||||
}),
|
||||
getEntity("cover", "position_slider_tilt", "on", {
|
||||
friendly_name: "Position Slider & Tilt",
|
||||
supported_features:
|
||||
SUPPORT_OPEN +
|
||||
SUPPORT_STOP +
|
||||
SUPPORT_CLOSE +
|
||||
SUPPORT_SET_POSITION +
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT,
|
||||
current_position: 30,
|
||||
}),
|
||||
getEntity("cover", "position_slider_only_tilt_slider", "on", {
|
||||
friendly_name: "Position Slider Only & Tilt Buttons",
|
||||
supported_features:
|
||||
SUPPORT_SET_POSITION +
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT,
|
||||
current_position: 30,
|
||||
}),
|
||||
getEntity("cover", "position_slider_only_tilt", "on", {
|
||||
friendly_name: "Position Slider Only & Tilt",
|
||||
supported_features:
|
||||
SUPPORT_SET_POSITION +
|
||||
SUPPORT_OPEN_TILT +
|
||||
SUPPORT_STOP_TILT +
|
||||
SUPPORT_CLOSE_TILT +
|
||||
SUPPORT_SET_TILT_POSITION,
|
||||
current_position: 30,
|
||||
current_tilt_position: 70,
|
||||
}),
|
||||
];
|
||||
|
||||
@customElement("demo-more-info-cover")
|
||||
class DemoMoreInfoCover extends LitElement {
|
||||
@property() public hass!: MockHomeAssistant;
|
||||
|
||||
@query("demo-more-infos") private _demoRoot!: HTMLElement;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<demo-more-infos
|
||||
.hass=${this.hass}
|
||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||
></demo-more-infos>
|
||||
`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProperties: PropertyValues) {
|
||||
super.firstUpdated(changedProperties);
|
||||
const hass = provideHass(this._demoRoot);
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-more-info-cover": DemoMoreInfoCover;
|
||||
}
|
||||
}
|
@ -1,39 +1,30 @@
|
||||
import { mdiStop } from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { computeCloseIcon, computeOpenIcon } from "../common/entity/cover_icon";
|
||||
import {
|
||||
CoverEntity,
|
||||
isClosing,
|
||||
isFullyClosed,
|
||||
isFullyOpen,
|
||||
isOpening,
|
||||
supportsClose,
|
||||
supportsOpen,
|
||||
supportsStop,
|
||||
} from "../data/cover";
|
||||
import { UNAVAILABLE } from "../data/entity";
|
||||
import type { HomeAssistant } from "../types";
|
||||
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({ attribute: false }) public stateObj!: HassEntity;
|
||||
|
||||
@state() private _entityObj?: CoverEntity;
|
||||
|
||||
public willUpdate(changedProperties: PropertyValues): void {
|
||||
super.willUpdate(changedProperties);
|
||||
|
||||
if (changedProperties.has("stateObj")) {
|
||||
this._entityObj = new CoverEntity(this.hass, this.stateObj);
|
||||
}
|
||||
}
|
||||
@property({ attribute: false }) public stateObj!: CoverEntity;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this._entityObj) {
|
||||
if (!this.stateObj) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
@ -41,7 +32,7 @@ class HaCoverControls extends LitElement {
|
||||
<div class="state">
|
||||
<ha-icon-button
|
||||
class=${classMap({
|
||||
hidden: !this._entityObj.supportsOpen,
|
||||
hidden: !supportsOpen(this.stateObj),
|
||||
})}
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.open_cover"
|
||||
@ -53,7 +44,7 @@ class HaCoverControls extends LitElement {
|
||||
</ha-icon-button>
|
||||
<ha-icon-button
|
||||
class=${classMap({
|
||||
hidden: !this._entityObj.supportsStop,
|
||||
hidden: !supportsStop(this.stateObj),
|
||||
})}
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.stop_cover"
|
||||
@ -64,7 +55,7 @@ class HaCoverControls extends LitElement {
|
||||
></ha-icon-button>
|
||||
<ha-icon-button
|
||||
class=${classMap({
|
||||
hidden: !this._entityObj.supportsClose,
|
||||
hidden: !supportsClose(this.stateObj),
|
||||
})}
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.close_cover"
|
||||
@ -84,8 +75,7 @@ class HaCoverControls extends LitElement {
|
||||
}
|
||||
const assumedState = this.stateObj.attributes.assumed_state === true;
|
||||
return (
|
||||
(this._entityObj.isFullyOpen || this._entityObj.isOpening) &&
|
||||
!assumedState
|
||||
(isFullyOpen(this.stateObj) || isOpening(this.stateObj)) && !assumedState
|
||||
);
|
||||
}
|
||||
|
||||
@ -95,24 +85,30 @@ class HaCoverControls extends LitElement {
|
||||
}
|
||||
const assumedState = this.stateObj.attributes.assumed_state === true;
|
||||
return (
|
||||
(this._entityObj.isFullyClosed || this._entityObj.isClosing) &&
|
||||
(isFullyClosed(this.stateObj) || isClosing(this.stateObj)) &&
|
||||
!assumedState
|
||||
);
|
||||
}
|
||||
|
||||
private _onOpenTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this._entityObj.openCover();
|
||||
this.hass.callService("cover", "open_cover", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _onCloseTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this._entityObj.closeCover();
|
||||
this.hass.callService("cover", "close_cover", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _onStopTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this._entityObj.stopCover();
|
||||
this.hass.callService("cover", "stop_cover", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
@ -1,44 +1,33 @@
|
||||
import { mdiArrowBottomLeft, mdiArrowTopRight, mdiStop } from "@mdi/js";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import {
|
||||
CoverEntity,
|
||||
isFullyClosedTilt,
|
||||
isFullyOpenTilt,
|
||||
supportsCloseTilt,
|
||||
supportsOpenTilt,
|
||||
supportsStopTilt,
|
||||
} from "../data/cover";
|
||||
import { UNAVAILABLE } from "../data/entity";
|
||||
import { HomeAssistant } from "../types";
|
||||
import CoverEntity from "../util/cover-model";
|
||||
import "./ha-icon-button";
|
||||
|
||||
@customElement("ha-cover-tilt-controls")
|
||||
class HaCoverTiltControls extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) stateObj!: HassEntity;
|
||||
|
||||
@state() private _entityObj?: CoverEntity;
|
||||
|
||||
public willUpdate(changedProperties: PropertyValues): void {
|
||||
super.willUpdate(changedProperties);
|
||||
|
||||
if (changedProperties.has("stateObj")) {
|
||||
this._entityObj = new CoverEntity(this.hass, this.stateObj);
|
||||
}
|
||||
}
|
||||
@property({ attribute: false }) stateObj!: CoverEntity;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this._entityObj) {
|
||||
if (!this.stateObj) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
return html` <ha-icon-button
|
||||
class=${classMap({
|
||||
invisible: !this._entityObj.supportsOpenTilt,
|
||||
invisible: !supportsOpenTilt(this.stateObj),
|
||||
})}
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.open_tilt_cover"
|
||||
@ -49,7 +38,7 @@ class HaCoverTiltControls extends LitElement {
|
||||
></ha-icon-button>
|
||||
<ha-icon-button
|
||||
class=${classMap({
|
||||
invisible: !this._entityObj.supportsStopTilt,
|
||||
invisible: !supportsStopTilt(this.stateObj),
|
||||
})}
|
||||
.label=${this.hass.localize("ui.dialogs.more_info_control.stop_cover")}
|
||||
.path=${mdiStop}
|
||||
@ -58,7 +47,7 @@ class HaCoverTiltControls extends LitElement {
|
||||
></ha-icon-button>
|
||||
<ha-icon-button
|
||||
class=${classMap({
|
||||
invisible: !this._entityObj.supportsCloseTilt,
|
||||
invisible: !supportsCloseTilt(this.stateObj),
|
||||
})}
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.close_tilt_cover"
|
||||
@ -74,7 +63,7 @@ class HaCoverTiltControls extends LitElement {
|
||||
return true;
|
||||
}
|
||||
const assumedState = this.stateObj.attributes.assumed_state === true;
|
||||
return this._entityObj.isFullyOpenTilt && !assumedState;
|
||||
return isFullyOpenTilt(this.stateObj) && !assumedState;
|
||||
}
|
||||
|
||||
private _computeClosedDisabled(): boolean {
|
||||
@ -82,22 +71,28 @@ class HaCoverTiltControls extends LitElement {
|
||||
return true;
|
||||
}
|
||||
const assumedState = this.stateObj.attributes.assumed_state === true;
|
||||
return this._entityObj.isFullyClosedTilt && !assumedState;
|
||||
return isFullyClosedTilt(this.stateObj) && !assumedState;
|
||||
}
|
||||
|
||||
private _onOpenTiltTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this._entityObj.openCoverTilt();
|
||||
this.hass.callService("cover", "open_cover_tilt", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _onCloseTiltTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this._entityObj.closeCoverTilt();
|
||||
this.hass.callService("cover", "close_cover_tilt", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _onStopTiltTap(ev): void {
|
||||
ev.stopPropagation();
|
||||
this._entityObj.stopCoverTilt();
|
||||
this.hass.callService("cover", "stop_cover_tilt", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
95
src/data/cover.ts
Normal file
95
src/data/cover.ts
Normal file
@ -0,0 +1,95 @@
|
||||
import {
|
||||
HassEntityAttributeBase,
|
||||
HassEntityBase,
|
||||
} from "home-assistant-js-websocket";
|
||||
import { supportsFeature } from "../common/entity/supports-feature";
|
||||
|
||||
export const SUPPORT_OPEN = 1;
|
||||
export const SUPPORT_CLOSE = 2;
|
||||
export const SUPPORT_SET_POSITION = 4;
|
||||
export const SUPPORT_STOP = 8;
|
||||
export const SUPPORT_OPEN_TILT = 16;
|
||||
export const SUPPORT_CLOSE_TILT = 32;
|
||||
export const SUPPORT_STOP_TILT = 64;
|
||||
export const SUPPORT_SET_TILT_POSITION = 128;
|
||||
|
||||
export const FEATURE_CLASS_NAMES = {
|
||||
4: "has-set_position",
|
||||
16: "has-open_tilt",
|
||||
32: "has-close_tilt",
|
||||
64: "has-stop_tilt",
|
||||
128: "has-set_tilt_position",
|
||||
};
|
||||
|
||||
export const supportsOpen = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_OPEN);
|
||||
|
||||
export const supportsClose = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_CLOSE);
|
||||
|
||||
export const supportsSetPosition = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_SET_POSITION);
|
||||
|
||||
export const supportsStop = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_STOP);
|
||||
|
||||
export const supportsOpenTilt = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_OPEN_TILT);
|
||||
|
||||
export const supportsCloseTilt = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_CLOSE_TILT);
|
||||
|
||||
export const supportsStopTilt = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_STOP_TILT);
|
||||
|
||||
export const supportsSetTiltPosition = (stateObj) =>
|
||||
supportsFeature(stateObj, SUPPORT_SET_TILT_POSITION);
|
||||
|
||||
export function isFullyOpen(stateObj: CoverEntity) {
|
||||
if (stateObj.attributes.current_position !== undefined) {
|
||||
return stateObj.attributes.current_position === 100;
|
||||
}
|
||||
return stateObj.state === "open";
|
||||
}
|
||||
|
||||
export function isFullyClosed(stateObj: CoverEntity) {
|
||||
if (stateObj.attributes.current_position !== undefined) {
|
||||
return stateObj.attributes.current_position === 0;
|
||||
}
|
||||
return stateObj.state === "closed";
|
||||
}
|
||||
|
||||
export function isFullyOpenTilt(stateObj: CoverEntity) {
|
||||
return stateObj.attributes.current_tilt_position === 100;
|
||||
}
|
||||
|
||||
export function isFullyClosedTilt(stateObj: CoverEntity) {
|
||||
return stateObj.attributes.current_tilt_position === 0;
|
||||
}
|
||||
|
||||
export function isOpening(stateObj: CoverEntity) {
|
||||
return stateObj.state === "opening";
|
||||
}
|
||||
|
||||
export function isClosing(stateObj: CoverEntity) {
|
||||
return stateObj.state === "closing";
|
||||
}
|
||||
|
||||
export function isTiltOnly(stateObj: CoverEntity) {
|
||||
const supportsCover =
|
||||
supportsOpen(stateObj) || supportsClose(stateObj) || supportsStop(stateObj);
|
||||
const supportsTilt =
|
||||
supportsOpenTilt(stateObj) ||
|
||||
supportsCloseTilt(stateObj) ||
|
||||
supportsStopTilt(stateObj);
|
||||
return supportsTilt && !supportsCover;
|
||||
}
|
||||
|
||||
interface CoverEntityAttributes extends HassEntityAttributeBase {
|
||||
current_position: number;
|
||||
current_tilt_position: number;
|
||||
}
|
||||
|
||||
export interface CoverEntity extends HassEntityBase {
|
||||
attributes: CoverEntityAttributes;
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
/* eslint-plugin-disable lit */
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import { attributeClassNames } from "../../../common/entity/attribute_class_names";
|
||||
import { featureClassNames } from "../../../common/entity/feature_class_names";
|
||||
import "../../../components/ha-cover-tilt-controls";
|
||||
import "../../../components/ha-labeled-slider";
|
||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||
import CoverEntity from "../../../util/cover-model";
|
||||
|
||||
const FEATURE_CLASS_NAMES = {
|
||||
4: "has-set_position",
|
||||
128: "has-set_tilt_position",
|
||||
};
|
||||
class MoreInfoCover extends LocalizeMixin(PolymerElement) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style include="iron-flex"></style>
|
||||
<style>
|
||||
.current_position,
|
||||
.tilt {
|
||||
max-height: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.has-set_position .current_position,
|
||||
.has-current_position .current_position,
|
||||
.has-set_tilt_position .tilt,
|
||||
.has-current_tilt_position .tilt {
|
||||
max-height: 208px;
|
||||
}
|
||||
|
||||
[invisible] {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
</style>
|
||||
<div class$="[[computeClassNames(stateObj)]]">
|
||||
<div class="current_position">
|
||||
<ha-labeled-slider
|
||||
caption="[[localize('ui.card.cover.position')]]"
|
||||
pin=""
|
||||
value="{{coverPositionSliderValue}}"
|
||||
disabled="[[!entityObj.supportsSetPosition]]"
|
||||
on-change="coverPositionSliderChanged"
|
||||
></ha-labeled-slider>
|
||||
</div>
|
||||
|
||||
<div class="tilt">
|
||||
<ha-labeled-slider
|
||||
caption="[[localize('ui.card.cover.tilt_position')]]"
|
||||
pin=""
|
||||
extra=""
|
||||
value="{{coverTiltPositionSliderValue}}"
|
||||
disabled="[[!entityObj.supportsSetTiltPosition]]"
|
||||
on-change="coverTiltPositionSliderChanged"
|
||||
>
|
||||
<ha-cover-tilt-controls
|
||||
slot="extra"
|
||||
hidden$="[[entityObj.isTiltOnly]]"
|
||||
hass="[[hass]]"
|
||||
state-obj="[[stateObj]]"
|
||||
></ha-cover-tilt-controls>
|
||||
</ha-labeled-slider>
|
||||
</div>
|
||||
</div>
|
||||
<ha-attributes
|
||||
hass="[[hass]]"
|
||||
state-obj="[[stateObj]]"
|
||||
extra-filters="current_position,current_tilt_position"
|
||||
></ha-attributes>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
stateObj: {
|
||||
type: Object,
|
||||
observer: "stateObjChanged",
|
||||
},
|
||||
entityObj: {
|
||||
type: Object,
|
||||
computed: "computeEntityObj(hass, stateObj)",
|
||||
},
|
||||
coverPositionSliderValue: Number,
|
||||
coverTiltPositionSliderValue: Number,
|
||||
};
|
||||
}
|
||||
|
||||
computeEntityObj(hass, stateObj) {
|
||||
return new CoverEntity(hass, stateObj);
|
||||
}
|
||||
|
||||
stateObjChanged(newVal) {
|
||||
if (newVal) {
|
||||
this.setProperties({
|
||||
coverPositionSliderValue: newVal.attributes.current_position,
|
||||
coverTiltPositionSliderValue: newVal.attributes.current_tilt_position,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
computeClassNames(stateObj) {
|
||||
const classes = [
|
||||
attributeClassNames(stateObj, [
|
||||
"current_position",
|
||||
"current_tilt_position",
|
||||
]),
|
||||
featureClassNames(stateObj, FEATURE_CLASS_NAMES),
|
||||
];
|
||||
return classes.join(" ");
|
||||
}
|
||||
|
||||
coverPositionSliderChanged(ev) {
|
||||
this.entityObj.setCoverPosition(ev.target.value);
|
||||
}
|
||||
|
||||
coverTiltPositionSliderChanged(ev) {
|
||||
this.entityObj.setCoverTiltPosition(ev.target.value);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("more-info-cover", MoreInfoCover);
|
140
src/dialogs/more-info/controls/more-info-cover.ts
Normal file
140
src/dialogs/more-info/controls/more-info-cover.ts
Normal file
@ -0,0 +1,140 @@
|
||||
import { css, CSSResult, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { attributeClassNames } from "../../../common/entity/attribute_class_names";
|
||||
import { featureClassNames } from "../../../common/entity/feature_class_names";
|
||||
import "../../../components/ha-attributes";
|
||||
import "../../../components/ha-cover-tilt-controls";
|
||||
import "../../../components/ha-labeled-slider";
|
||||
import {
|
||||
CoverEntity,
|
||||
FEATURE_CLASS_NAMES,
|
||||
isTiltOnly,
|
||||
supportsSetPosition,
|
||||
supportsSetTiltPosition,
|
||||
} from "../../../data/cover";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
@customElement("more-info-cover")
|
||||
class MoreInfoCover extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public stateObj!: CoverEntity;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.stateObj) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const _isTiltOnly = isTiltOnly(this.stateObj);
|
||||
|
||||
return html`
|
||||
<div class=${this._computeClassNames(this.stateObj)}>
|
||||
<div class="current_position">
|
||||
<ha-labeled-slider
|
||||
.caption=${this.hass.localize("ui.card.cover.position")}
|
||||
pin=""
|
||||
.value=${this.stateObj.attributes.current_position}
|
||||
.disabled=${!supportsSetPosition(this.stateObj)}
|
||||
@change=${this._coverPositionSliderChanged}
|
||||
></ha-labeled-slider>
|
||||
</div>
|
||||
|
||||
<div class="tilt">
|
||||
${supportsSetTiltPosition(this.stateObj)
|
||||
? // Either render the labeled slider and put the tilt buttons into its slot
|
||||
// or (if tilt position is not supported and therefore no slider is shown)
|
||||
// render a title <div> (same style as for a labeled slider) and directly put
|
||||
// the tilt controls on the more-info.
|
||||
html` <ha-labeled-slider
|
||||
.caption=${this.hass.localize("ui.card.cover.tilt_position")}
|
||||
pin=""
|
||||
extra=""
|
||||
.value=${this.stateObj.attributes.current_tilt_position}
|
||||
@change=${this._coverTiltPositionSliderChanged}
|
||||
>
|
||||
${!_isTiltOnly
|
||||
? html`<ha-cover-tilt-controls
|
||||
.hass=${this.hass}
|
||||
slot="extra"
|
||||
.stateObj=${this.stateObj}
|
||||
></ha-cover-tilt-controls> `
|
||||
: html``}
|
||||
</ha-labeled-slider>`
|
||||
: !_isTiltOnly
|
||||
? html`
|
||||
<div class="title">
|
||||
${this.hass.localize("ui.card.cover.tilt_position")}
|
||||
</div>
|
||||
<ha-cover-tilt-controls
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
></ha-cover-tilt-controls>
|
||||
`
|
||||
: html``}
|
||||
</div>
|
||||
</div>
|
||||
<ha-attributes
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
extra-filters="current_position,current_tilt_position"
|
||||
></ha-attributes>
|
||||
`;
|
||||
}
|
||||
|
||||
private _computeClassNames(stateObj) {
|
||||
const classes = [
|
||||
attributeClassNames(stateObj, [
|
||||
"current_position",
|
||||
"current_tilt_position",
|
||||
]),
|
||||
featureClassNames(stateObj, FEATURE_CLASS_NAMES),
|
||||
];
|
||||
return classes.join(" ");
|
||||
}
|
||||
|
||||
private _coverPositionSliderChanged(ev) {
|
||||
this.hass.callService("cover", "set_cover_position", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
position: ev.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
private _coverTiltPositionSliderChanged(ev) {
|
||||
this.hass.callService("cover", "set_cover_tilt_position", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
tilt_position: ev.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
.current_position,
|
||||
.tilt {
|
||||
max-height: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.has-set_position .current_position,
|
||||
.has-current_position .current_position,
|
||||
.has-open_tilt .tilt,
|
||||
.has-close_tilt .tilt,
|
||||
.has-stop_tilt .tilt,
|
||||
.has-set_tilt_position .tilt,
|
||||
.has-current_tilt_position .tilt {
|
||||
max-height: 208px;
|
||||
}
|
||||
|
||||
/* from ha-labeled-slider for consistent look */
|
||||
.title {
|
||||
margin: 5px 0 8px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"more-info-cover": MoreInfoCover;
|
||||
}
|
||||
}
|
@ -9,8 +9,8 @@ import {
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../components/ha-cover-controls";
|
||||
import "../../../components/ha-cover-tilt-controls";
|
||||
import { CoverEntity, isTiltOnly } from "../../../data/cover";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { isTiltOnly } from "../../../util/cover-model";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import "../components/hui-generic-entity-row";
|
||||
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||
@ -38,7 +38,7 @@ class HuiCoverEntityRow extends LitElement implements LovelaceRow {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const stateObj = this.hass.states[this._config.entity];
|
||||
const stateObj = this.hass.states[this._config.entity] as CoverEntity;
|
||||
|
||||
if (!stateObj) {
|
||||
return html`
|
||||
|
@ -1,68 +0,0 @@
|
||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
/* eslint-plugin-disable lit */
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import "../components/entity/state-info";
|
||||
import "../components/ha-cover-controls";
|
||||
import "../components/ha-cover-tilt-controls";
|
||||
import CoverEntity from "../util/cover-model";
|
||||
|
||||
class StateCardCover extends PolymerElement {
|
||||
static get template() {
|
||||
return html`
|
||||
<style include="iron-flex iron-flex-alignment"></style>
|
||||
<style>
|
||||
:host {
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="horizontal justified layout">
|
||||
${this.stateInfoTemplate}
|
||||
<div class="horizontal layout">
|
||||
<ha-cover-controls
|
||||
hidden$="[[entityObj.isTiltOnly]]"
|
||||
hass="[[hass]]"
|
||||
state-obj="[[stateObj]]"
|
||||
></ha-cover-controls>
|
||||
<ha-cover-tilt-controls
|
||||
hidden$="[[!entityObj.isTiltOnly]]"
|
||||
hass="[[hass]]"
|
||||
state-obj="[[stateObj]]"
|
||||
></ha-cover-tilt-controls>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static get stateInfoTemplate() {
|
||||
return html`
|
||||
<state-info
|
||||
hass="[[hass]]"
|
||||
state-obj="[[stateObj]]"
|
||||
in-dialog="[[inDialog]]"
|
||||
></state-info>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
stateObj: Object,
|
||||
inDialog: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
entityObj: {
|
||||
type: Object,
|
||||
computed: "computeEntityObj(hass, stateObj)",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
computeEntityObj(hass, stateObj) {
|
||||
const entity = new CoverEntity(hass, stateObj);
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
customElements.define("state-card-cover", StateCardCover);
|
56
src/state-summary/state-card-cover.ts
Normal file
56
src/state-summary/state-card-cover.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../components/entity/state-info";
|
||||
import "../components/ha-cover-controls";
|
||||
import "../components/ha-cover-tilt-controls";
|
||||
import { CoverEntity, isTiltOnly } from "../data/cover";
|
||||
import { haStyle } from "../resources/styles";
|
||||
import { HomeAssistant } from "../types";
|
||||
|
||||
@customElement("state-card-cover")
|
||||
class StateCardCover extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public stateObj!: CoverEntity;
|
||||
|
||||
@property({ type: Boolean }) public inDialog = false;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<div class="horizontal justified layout">
|
||||
<state-info
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
.inDialog=${this.inDialog}
|
||||
></state-info>
|
||||
<ha-cover-controls
|
||||
.hass=${this.hass}
|
||||
.hidden=${isTiltOnly(this.stateObj)}
|
||||
.stateObj=${this.stateObj}
|
||||
></ha-cover-controls>
|
||||
<ha-cover-tilt-controls
|
||||
.hass=${this.hass}
|
||||
.hidden=${!isTiltOnly(this.stateObj)}
|
||||
.stateObj=${this.stateObj}
|
||||
></ha-cover-tilt-controls>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
:host {
|
||||
line-height: 1.5;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"state-card-cover": StateCardCover;
|
||||
}
|
||||
}
|
@ -1,149 +0,0 @@
|
||||
import { supportsFeature } from "../common/entity/supports-feature";
|
||||
|
||||
/* eslint-enable no-bitwise */
|
||||
export default class CoverEntity {
|
||||
constructor(hass, stateObj) {
|
||||
this.hass = hass;
|
||||
this.stateObj = stateObj;
|
||||
this._attr = stateObj.attributes;
|
||||
this._feat = this._attr.supported_features;
|
||||
}
|
||||
|
||||
get isFullyOpen() {
|
||||
if (this._attr.current_position !== undefined) {
|
||||
return this._attr.current_position === 100;
|
||||
}
|
||||
return this.stateObj.state === "open";
|
||||
}
|
||||
|
||||
get isFullyClosed() {
|
||||
if (this._attr.current_position !== undefined) {
|
||||
return this._attr.current_position === 0;
|
||||
}
|
||||
return this.stateObj.state === "closed";
|
||||
}
|
||||
|
||||
get isFullyOpenTilt() {
|
||||
return this._attr.current_tilt_position === 100;
|
||||
}
|
||||
|
||||
get isFullyClosedTilt() {
|
||||
return this._attr.current_tilt_position === 0;
|
||||
}
|
||||
|
||||
get isOpening() {
|
||||
return this.stateObj.state === "opening";
|
||||
}
|
||||
|
||||
get isClosing() {
|
||||
return this.stateObj.state === "closing";
|
||||
}
|
||||
|
||||
get supportsOpen() {
|
||||
return supportsFeature(this.stateObj, 1);
|
||||
}
|
||||
|
||||
get supportsClose() {
|
||||
return supportsFeature(this.stateObj, 2);
|
||||
}
|
||||
|
||||
get supportsSetPosition() {
|
||||
return supportsFeature(this.stateObj, 4);
|
||||
}
|
||||
|
||||
get supportsStop() {
|
||||
return supportsFeature(this.stateObj, 8);
|
||||
}
|
||||
|
||||
get supportsOpenTilt() {
|
||||
return supportsFeature(this.stateObj, 16);
|
||||
}
|
||||
|
||||
get supportsCloseTilt() {
|
||||
return supportsFeature(this.stateObj, 32);
|
||||
}
|
||||
|
||||
get supportsStopTilt() {
|
||||
return supportsFeature(this.stateObj, 64);
|
||||
}
|
||||
|
||||
get supportsSetTiltPosition() {
|
||||
return supportsFeature(this.stateObj, 128);
|
||||
}
|
||||
|
||||
get isTiltOnly() {
|
||||
const supportsCover =
|
||||
this.supportsOpen || this.supportsClose || this.supportsStop;
|
||||
const supportsTilt =
|
||||
this.supportsOpenTilt || this.supportsCloseTilt || this.supportsStopTilt;
|
||||
return supportsTilt && !supportsCover;
|
||||
}
|
||||
|
||||
openCover() {
|
||||
this.callService("open_cover");
|
||||
}
|
||||
|
||||
closeCover() {
|
||||
this.callService("close_cover");
|
||||
}
|
||||
|
||||
stopCover() {
|
||||
this.callService("stop_cover");
|
||||
}
|
||||
|
||||
openCoverTilt() {
|
||||
this.callService("open_cover_tilt");
|
||||
}
|
||||
|
||||
closeCoverTilt() {
|
||||
this.callService("close_cover_tilt");
|
||||
}
|
||||
|
||||
stopCoverTilt() {
|
||||
this.callService("stop_cover_tilt");
|
||||
}
|
||||
|
||||
setCoverPosition(position) {
|
||||
this.callService("set_cover_position", { position });
|
||||
}
|
||||
|
||||
setCoverTiltPosition(tiltPosition) {
|
||||
this.callService("set_cover_tilt_position", {
|
||||
tilt_position: tiltPosition,
|
||||
});
|
||||
}
|
||||
|
||||
// helper method
|
||||
|
||||
callService(service, data = {}) {
|
||||
data.entity_id = this.stateObj.entity_id;
|
||||
this.hass.callService("cover", service, data);
|
||||
}
|
||||
}
|
||||
|
||||
export const supportsOpen = (stateObj) => supportsFeature(stateObj, 1);
|
||||
|
||||
export const supportsClose = (stateObj) => supportsFeature(stateObj, 2);
|
||||
|
||||
export const supportsSetPosition = (stateObj) => supportsFeature(stateObj, 4);
|
||||
|
||||
export const supportsStop = (stateObj) => supportsFeature(stateObj, 8);
|
||||
|
||||
export const supportsOpenTilt = (stateObj) => supportsFeature(stateObj, 16);
|
||||
|
||||
export const supportsCloseTilt = (stateObj) => supportsFeature(stateObj, 32);
|
||||
|
||||
export const supportsStopTilt = (stateObj) => supportsFeature(stateObj, 64);
|
||||
|
||||
export const supportsSetTiltPosition = (stateObj) =>
|
||||
supportsFeature(stateObj, 128);
|
||||
|
||||
export function isTiltOnly(stateObj) {
|
||||
const supportsCover =
|
||||
supportsOpen(stateObj) || supportsClose(stateObj) || supportsStop(stateObj);
|
||||
const supportsTilt =
|
||||
supportsOpenTilt(stateObj) ||
|
||||
supportsCloseTilt(stateObj) ||
|
||||
supportsStopTilt(stateObj);
|
||||
return supportsTilt && !supportsCover;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user