Skip to content

Commit

Permalink
Improve open and opening state for lock (#20808)
Browse files Browse the repository at this point in the history
* Add open and opening color

* Split isAvailable into multiple function

* Use done wording
  • Loading branch information
piitaya authored May 21, 2024
1 parent 79abcca commit 4cc5d2d
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 57 deletions.
39 changes: 34 additions & 5 deletions src/data/lock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export function isLocked(stateObj: LockEntity) {
return stateObj.state === "locked";
}

export function isUnlocked(stateObj: LockEntity) {
return stateObj.state === "unlocked";
}

export function isUnlocking(stateObj: LockEntity) {
return stateObj.state === "unlocking";
}
Expand All @@ -38,15 +42,40 @@ export function isJammed(stateObj: LockEntity) {
return stateObj.state === "jammed";
}

export function isAvailable(stateObj: LockEntity) {
export function isOpen(stateObj: LockEntity) {
return stateObj.state === "open";
}

export function isOpening(stateObj: LockEntity) {
return stateObj.state === "opening";
}

export function isWaiting(stateObj: LockEntity) {
return ["opening", "unlocking", "locking"].includes(stateObj.state);
}

export function canOpen(stateObj: LockEntity) {
if (stateObj.state === UNAVAILABLE) {
return false;
}
const assumedState = stateObj.attributes.assumed_state === true;
return assumedState || (!isOpen(stateObj) && !isWaiting(stateObj));
}

export function canLock(stateObj: LockEntity) {
if (stateObj.state === UNAVAILABLE) {
return false;
}
const assumedState = stateObj.attributes.assumed_state === true;
return assumedState || (!isLocked(stateObj) && !isWaiting(stateObj));
}

export function canUnlock(stateObj: LockEntity) {
if (stateObj.state === UNAVAILABLE) {
return false;
}
const assumedState = stateObj.attributes.assumed_state === true;
return (
assumedState ||
(!isLocking(stateObj) && !isUnlocking(stateObj) && !isJammed(stateObj))
);
return assumedState || (!isUnlocked(stateObj) && !isWaiting(stateObj));
}

export const callProtectedLockService = async (
Expand Down
18 changes: 9 additions & 9 deletions src/dialogs/more-info/controls/more-info-lock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
LockEntity,
LockEntityFeature,
callProtectedLockService,
isAvailable,
canOpen,
isJammed,
} from "../../../data/lock";
import "../../../state-control/lock/ha-state-control-lock-toggle";
Expand All @@ -22,9 +22,9 @@ import "../components/ha-more-info-state-header";
import { moreInfoControlStyle } from "../components/more-info-control-style";

const CONFIRM_TIMEOUT_SECOND = 5;
const OPENED_TIMEOUT_SECOND = 3;
const DONE_TIMEOUT_SECOND = 2;

type ButtonState = "normal" | "confirm" | "success";
type ButtonState = "normal" | "confirm" | "done";

@customElement("more-info-lock")
class MoreInfoLock extends LitElement {
Expand Down Expand Up @@ -54,7 +54,7 @@ class MoreInfoLock extends LitElement {

callProtectedLockService(this, this.hass, this.stateObj!, "open");

this._setButtonState("success", OPENED_TIMEOUT_SECOND);
this._setButtonState("done", DONE_TIMEOUT_SECOND);
}

private _resetButtonState() {
Expand Down Expand Up @@ -115,16 +115,16 @@ class MoreInfoLock extends LitElement {
${supportsOpen
? html`
<div class="buttons">
${this._buttonState === "success"
${this._buttonState === "done"
? html`
<p class="open-success">
<p class="open-done">
<ha-svg-icon path=${mdiCheck}></ha-svg-icon>
${this.hass.localize("ui.card.lock.open_door_success")}
${this.hass.localize("ui.card.lock.open_door_done")}
</p>
`
: html`
<ha-control-button
.disabled=${!isAvailable(this.stateObj)}
.disabled=${!canOpen(this.stateObj)}
class="open-button ${this._buttonState}"
@click=${this._open}
>
Expand Down Expand Up @@ -175,7 +175,7 @@ class MoreInfoLock extends LitElement {
.open-button.confirm {
--control-button-background-color: var(--warning-color);
}
.open-success {
.open-done {
line-height: 60px;
display: flex;
align-items: center;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
import { mdiLock, mdiLockOpenVariant } from "@mdi/js";
import { HassEntity } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { computeDomain } from "../../../common/entity/compute_domain";

import "../../../components/ha-control-button";
import "../../../components/ha-control-button-group";
import { forwardHaptic } from "../../../data/haptics";
import {
callProtectedLockService,
isAvailable,
isLocking,
isUnlocking,
isLocked,
canLock,
canUnlock,
} from "../../../data/lock";
import { HomeAssistant } from "../../../types";
import { LovelaceCardFeature } from "../types";
import { LockCommandsCardFeatureConfig } from "./types";
import { forwardHaptic } from "../../../data/haptics";

export const supportsLockCommandsCardFeature = (stateObj: HassEntity) => {
const domain = computeDomain(stateObj.entity_id);
Expand Down Expand Up @@ -72,23 +69,17 @@ class HuiLockCommandsCardFeature
<ha-control-button-group>
<ha-control-button
.label=${this.hass.localize("ui.card.lock.lock")}
.disabled=${!isAvailable(this.stateObj) || isLocked(this.stateObj)}
.disabled=${!canLock(this.stateObj)}
@click=${this._onTap}
data-service="lock"
class=${classMap({
pulse: isLocking(this.stateObj) || isUnlocking(this.stateObj),
})}
>
<ha-svg-icon .path=${mdiLock}></ha-svg-icon>
</ha-control-button>
<ha-control-button
.label=${this.hass.localize("ui.card.lock.unlock")}
.disabled=${!isAvailable(this.stateObj) || !isLocked(this.stateObj)}
.disabled=${!canUnlock(this.stateObj)}
@click=${this._onTap}
data-service="unlock"
class=${classMap({
pulse: isLocking(this.stateObj) || isUnlocking(this.stateObj),
})}
>
<ha-svg-icon .path=${mdiLockOpenVariant}></ha-svg-icon>
</ha-control-button>
Expand All @@ -98,20 +89,6 @@ class HuiLockCommandsCardFeature

static get styles(): CSSResultGroup {
return css`
@keyframes pulse {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.pulse {
animation: pulse 1s infinite;
}
ha-control-button-group {
margin: 0 12px 12px 12px;
--control-button-group-spacing: 12px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { supportsFeature } from "../../../common/entity/supports-feature";
import "../../../components/ha-control-button";
import "../../../components/ha-control-button-group";
import {
LockEntityFeature,
callProtectedLockService,
isAvailable,
canOpen,
LockEntityFeature,
} from "../../../data/lock";
import { HomeAssistant } from "../../../types";
import { LovelaceCardFeature } from "../types";
Expand All @@ -22,9 +22,9 @@ export const supportsLockOpenDoorCardFeature = (stateObj: HassEntity) => {
};

const CONFIRM_TIMEOUT_SECOND = 5;
const OPENED_TIMEOUT_SECOND = 3;
const DONE_TIMEOUT_SECOND = 2;

type ButtonState = "normal" | "confirm" | "success";
type ButtonState = "normal" | "confirm" | "done";

@customElement("hui-lock-open-door-card-feature")
class HuiLockOpenDoorCardFeature
Expand Down Expand Up @@ -74,7 +74,7 @@ class HuiLockOpenDoorCardFeature
}
callProtectedLockService(this, this.hass, this.stateObj!, "open");

this._setButtonState("success", OPENED_TIMEOUT_SECOND);
this._setButtonState("done", DONE_TIMEOUT_SECOND);
}

protected render() {
Expand All @@ -88,17 +88,17 @@ class HuiLockOpenDoorCardFeature
}

return html`
${this._buttonState === "success"
${this._buttonState === "done"
? html`
<p class="open-success">
<p class="open-done">
<ha-svg-icon path=${mdiCheck}></ha-svg-icon>
${this.hass.localize("ui.card.lock.open_door_success")}
${this.hass.localize("ui.card.lock.open_door_done")}
</p>
`
: html`
<ha-control-button-group>
<ha-control-button
.disabled=${!isAvailable(this.stateObj)}
.disabled=${!canOpen(this.stateObj)}
class="open-button ${this._buttonState}"
@click=${this._open}
>
Expand Down Expand Up @@ -126,7 +126,7 @@ class HuiLockOpenDoorCardFeature
.open-button.confirm {
--control-button-background-color: var(--warning-color);
}
.open-success {
.open-done {
font-size: 14px;
line-height: 14px;
display: flex;
Expand All @@ -140,9 +140,6 @@ class HuiLockOpenDoorCardFeature
height: 40px;
text-align: center;
}
ha-control-button-group + ha-attributes:not([empty]) {
margin-top: 16px;
}
`;
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/resources/ha-style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ const mainStyles = css`
--state-lock-locked-color: var(--green-color);
--state-lock-pending-color: var(--orange-color);
--state-lock-unlocked-color: var(--red-color);
--state-lock-opening-color: var(--orange-color);
--state-lock-open-color: var(--red-color);
--state-media_player-active-color: var(--light-blue-color);
--state-person-active-color: var(--blue-color);
--state-person-home-color: var(--green-color);
Expand Down
2 changes: 1 addition & 1 deletion src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@
"open": "Open",
"open_door": "Open door",
"open_door_confirm": "Really open?",
"open_door_success": "Door open"
"open_door_done": "Done"
},
"media_player": {
"source": "Source",
Expand Down

0 comments on commit 4cc5d2d

Please sign in to comment.