ha-frontend/src/state-control/lock/ha-state-control-lock-toggl...

202 lines
5.3 KiB
TypeScript

import {
css,
CSSResultGroup,
html,
LitElement,
PropertyValues,
TemplateResult,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
import { stateColorCss } from "../../common/entity/state_color";
import "../../components/ha-control-button";
import "../../components/ha-control-switch";
import "../../components/ha-state-icon";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { forwardHaptic } from "../../data/haptics";
import { callProtectedLockService, LockEntity } from "../../data/lock";
import { HomeAssistant } from "../../types";
@customElement("ha-state-control-lock-toggle")
export class HaStateControlLockToggle extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public stateObj!: LockEntity;
@state() private _isOn = false;
public willUpdate(changedProps: PropertyValues): void {
super.willUpdate(changedProps);
if (changedProps.has("stateObj")) {
this._isOn =
this.stateObj.state === "locked" || this.stateObj.state === "locking";
}
}
private _valueChanged(ev) {
const checked = ev.target.checked as boolean;
if (checked) {
this._turnOn();
} else {
this._turnOff();
}
}
private async _turnOn() {
this._isOn = true;
try {
await this._callService(true);
} catch (err) {
this._isOn = false;
}
}
private async _turnOff() {
this._isOn = false;
try {
await this._callService(false);
} catch (err) {
this._isOn = true;
}
}
private async _callService(turnOn: boolean): Promise<void> {
if (!this.hass || !this.stateObj) {
return;
}
forwardHaptic("light");
callProtectedLockService(
this,
this.hass,
this.stateObj,
turnOn ? "lock" : "unlock"
);
}
protected render(): TemplateResult {
const locking = this.stateObj.state === "locking";
const unlocking = this.stateObj.state === "unlocking";
const color = stateColorCss(this.stateObj);
if (this.stateObj.state === UNKNOWN) {
return html`
<div class="buttons">
<ha-control-button
.label=${this.hass.localize("ui.card.lock.lock")}
@click=${this._turnOn}
>
<ha-state-icon
.hass=${this.hass}
.stateObj=${this.stateObj}
.stateValue=${locking ? "locking" : "locked"}
></ha-state-icon>
</ha-control-button>
<ha-control-button
.label=${this.hass.localize("ui.card.lock.unlock")}
@click=${this._turnOff}
>
<ha-state-icon
.hass=${this.hass}
.stateObj=${this.stateObj}
.stateValue=${unlocking ? "unlocking" : "unlocked"}
></ha-state-icon>
</ha-control-button>
</div>
`;
}
return html`
<ha-control-switch
vertical
reversed
.checked=${this._isOn}
@change=${this._valueChanged}
.ariaLabel=${this._isOn
? this.hass.localize("ui.card.lock.unlock")
: this.hass.localize("ui.card.lock.lock")}
style=${styleMap({
"--control-switch-on-color": color,
"--control-switch-off-color": color,
})}
.disabled=${this.stateObj.state === UNAVAILABLE}
>
<ha-state-icon
slot="icon-on"
.hass=${this.hass}
.stateObj=${this.stateObj}
.stateValue=${locking ? "locking" : "locked"}
class=${classMap({ pulse: locking })}
></ha-state-icon>
<ha-state-icon
slot="icon-off"
.hass=${this.hass}
.stateObj=${this.stateObj}
.stateValue=${unlocking ? "unlocking" : "unlocked"}
class=${classMap({ pulse: unlocking })}
></ha-state-icon>
</ha-control-switch>
`;
}
static get styles(): CSSResultGroup {
return css`
@keyframes pulse {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
ha-control-switch {
height: 45vh;
max-height: 320px;
min-height: 200px;
--control-switch-thickness: 130px;
--control-switch-border-radius: 48px;
--control-switch-padding: 6px;
--mdc-icon-size: 24px;
}
.pulse {
animation: pulse 1s infinite;
}
.buttons {
display: flex;
flex-direction: column;
width: 130px;
height: 45vh;
max-height: 320px;
min-height: 200px;
padding: 6px;
box-sizing: border-box;
}
ha-control-button {
flex: 1;
width: 100%;
--control-button-border-radius: 48px;
--mdc-icon-size: 24px;
}
ha-control-button.active {
--control-button-icon-color: white;
--control-button-background-color: var(--color);
--control-button-background-opacity: 1;
}
ha-control-button:not(:last-child) {
margin-bottom: 6px;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-state-control-lock-toggle": HaStateControlLockToggle;
}
}