Allow custom actions to control the frigate card.

This commit is contained in:
Dermot Duffy
2021-11-10 07:45:59 -08:00
parent 6096b0e81e
commit 19291ae184
6 changed files with 240 additions and 158 deletions
+6 -1
View File
@@ -10,7 +10,11 @@ import {
MenuStateIcon,
PictureElements,
} from '../types.js';
import { dispatchErrorMessageEvent, dispatchFrigateCardEvent } from '../common.js';
import {
convertLovelaceEventToCardActionEvent,
dispatchErrorMessageEvent,
dispatchFrigateCardEvent,
} from '../common.js';
import elementsStyle from '../scss/elements.scss';
import { localize } from '../localize/localize.js';
@@ -180,6 +184,7 @@ export class FrigateCardElements extends LitElement {
.hass=${this._hass}
.view=${this.view}
.elements=${this.elements}
@ll-custom=${(ev: CustomEvent) => convertLovelaceEventToCardActionEvent(this, ev)}
>
</frigate-card-elements-core>`;
}
+79 -54
View File
@@ -1,5 +1,5 @@
import { HassEntity } from 'home-assistant-js-websocket';
import { HomeAssistant, hasAction, stateIcon } from 'custom-card-helpers';
import { HomeAssistant, handleAction, hasAction, stateIcon } from 'custom-card-helpers';
import {
CSSResultGroup,
LitElement,
@@ -10,21 +10,28 @@ import {
} from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { styleMap } from 'lit/directives/style-map.js';
import { StyleInfo, styleMap } from 'lit/directives/style-map.js';
import { actionHandler } from '../action-handler-directive.js';
import type {
CardAction,
ElementsActionType,
ExtendedHomeAssistant,
MenuButton,
MenuConfig,
MenuInteraction,
} from '../types.js';
import { dispatchFrigateCardEvent, shouldUpdateBasedOnHass } from '../common.js';
import {
convertActionToFrigateCardCustomAction,
convertLovelaceEventToCardActionEvent,
dispatchFrigateCardEvent,
shouldUpdateBasedOnHass,
} from '../common.js';
import menuStyle from '../scss/menu.scss';
export const MENU_HEIGHT = 46;
export const FRIGATE_BUTTON_MENU_ICON = 'frigate';
// A menu for the Frigate card.
@customElement('frigate-card-menu')
@@ -48,19 +55,50 @@ export class FrigateCardMenu extends LitElement {
public buttons: MenuButton[] = [];
protected _interactionHandler(ev: CustomEvent, button: MenuButton): void {
if (this._menuConfig?.mode.startsWith('hidden-')) {
if (button.type == 'internal-menu-icon' && button.tap_action === 'frigate') {
this.expand = !this.expand;
return;
}
// Collapse menu after the user clicks on something.
this.expand = false;
if (!ev) {
return;
}
dispatchFrigateCardEvent<MenuInteraction>(this, 'menu-interaction', {
interaction: ev.detail.action,
button: button,
});
const interaction: string = ev.detail.action;
let action: ElementsActionType | undefined;
if (interaction == 'tap') {
action = button.tap_action;
} else if (interaction == 'hold') {
action = button.hold_action;
} else if (interaction == 'double_tap') {
action = button.double_tap_action;
}
if (!action) {
return;
}
// Determine if this action is a Frigate card action, if so handle it
// internally.
const frigateCardAction = convertActionToFrigateCardCustomAction(action);
if (frigateCardAction) {
if (frigateCardAction.frigate_card_action == 'frigate') {
// If the user presses the frigate button and it's a hide-away menu,
// then expand the menu and return.
if (this._menuConfig?.mode.startsWith('hidden-')) {
this.expand = !this.expand;
return;
}
}
// Collapse menu after the user clicks on something.
this.expand = false;
dispatchFrigateCardEvent<CardAction>(this, 'card-action', {
action: frigateCardAction.frigate_card_action,
});
}
const node: HTMLElement | null = ev.currentTarget as HTMLElement | null;
if (node) {
handleAction(node, this.hass as HomeAssistant, button, interaction);
return;
}
}
// Determine whether the menu should be updated.
@@ -82,38 +120,47 @@ export class FrigateCardMenu extends LitElement {
return shouldUpdateBasedOnHass(this.hass, oldHass, entities);
}
public static getEmphasizedStyle(): StyleInfo {
return {
color: 'var(--primary-color, white)',
};
}
// Render a menu button.
protected _renderButton(button: MenuButton): TemplateResult | void {
let state: HassEntity | null = null;
let emphasize = false;
let title = button.title;
let icon = button.icon;
const style = ('style' in button ? button.style : {}) || {};
let style = ('style' in button ? button.style : {}) || {};
if (icon == FRIGATE_BUTTON_MENU_ICON) {
icon =
this._menuConfig?.mode.startsWith('hidden-') && !this.expand
? 'mdi:alpha-f-box-outline'
: 'mdi:alpha-f-box';
}
if (button.type === 'custom:frigate-card-menu-state-icon') {
if (!this.hass) {
return;
}
state = this.hass.states[button.entity];
emphasize =
!!state && button.state_color && ['on', 'active', 'home'].includes(state.state);
if (
!!state &&
button.state_color &&
['on', 'active', 'home'].includes(state.state)
) {
style = { ...style, ...FrigateCardMenu.getEmphasizedStyle() };
}
title = title ?? (state?.attributes?.friendly_name || button.entity);
icon = icon ?? stateIcon(state);
} else if (button.type === 'internal-menu-icon') {
emphasize = button.emphasize ?? false;
}
let hasHold = false;
let hasDoubleClick = false;
if (button.type != 'internal-menu-icon') {
hasHold = hasAction(button.hold_action);
hasDoubleClick = hasAction(button.double_tap_action);
}
const hasHold = hasAction(button.hold_action);
const hasDoubleClick = hasAction(button.double_tap_action);
const classes = {
button: true,
emphasize: emphasize,
};
// TODO: Upon a safe distance from the release of HA 2021.11 these
@@ -127,6 +174,7 @@ export class FrigateCardMenu extends LitElement {
.label=${title || ''}
title=${title || ''}
@action=${(ev) => this._interactionHandler(ev, button)}
@ll-custom=${(ev: CustomEvent) => convertLovelaceEventToCardActionEvent(this, ev)}
.actionHandler=${actionHandler({
hasHold: hasHold,
hasDoubleClick: hasDoubleClick,
@@ -136,16 +184,6 @@ export class FrigateCardMenu extends LitElement {
</ha-icon-button>`;
}
// Render the Frigate menu button.
protected _renderFrigateButton(button: MenuButton): TemplateResult | void {
const icon =
this._menuConfig?.mode.startsWith('hidden-') && !this.expand
? 'mdi:alpha-f-box-outline'
: 'mdi:alpha-f-box';
return this._renderButton(Object.assign({}, button, { icon: icon }));
}
// Render the menu.
protected render(): TemplateResult | void {
if (!this._menuConfig) {
@@ -153,16 +191,7 @@ export class FrigateCardMenu extends LitElement {
}
const mode = this._menuConfig.mode;
const isFrigateButton = function (button: MenuButton): boolean {
return button.type === 'internal-menu-icon' && button.tap_action === 'frigate';
};
// If the menu is off, or if it's in hidden mode but there's no button to
// unhide it, just show nothing.
if (
mode == 'none' ||
(mode.startsWith('hidden-') && !this.buttons.find(isFrigateButton))
) {
if (mode == 'none') {
return;
}
@@ -187,11 +216,7 @@ export class FrigateCardMenu extends LitElement {
return html`
<div class=${classMap(classes)}>
${Array.from(this.buttons).map((button) => {
return isFrigateButton(button)
? this._renderFrigateButton(button)
: this._renderButton(button);
})}
${Array.from(this.buttons).map((button) => this._renderButton(button))}
</div>
`;
}