Files
advanced-camera-card/src/components-lib/status-bar-controller.ts
T

120 lines
3.5 KiB
TypeScript

import { LitElement } from 'lit';
import { isEqual, orderBy } from 'lodash-es';
import { dispatchActionExecutionRequest } from '../card-controller/actions/utils/execution-request';
import { ActionsConfig, StatusBarItem } from '../config/schema/actions/types';
import { STATUS_BAR_PRIORITY_DEFAULT } from '../config/schema/common/const';
import { StatusBarConfig } from '../config/schema/status-bar';
import { getActionConfigGivenAction } from '../utils/action';
import { arrayify, setOrRemoveAttribute } from '../utils/basic';
import { Timer } from '../utils/timer';
export class StatusBarController {
private _host: LitElement;
private _config: StatusBarConfig | null = null;
private _popupTimer = new Timer();
private _items: StatusBarItem[] = [];
constructor(host: LitElement) {
this._host = host;
}
public getRenderItems(): StatusBarItem[] {
return this._items;
}
public setItems(items: StatusBarItem[]): void {
const exclusiveItems = items.filter((item) => !!item.exclusive);
const newItems = orderBy(
exclusiveItems.length ? exclusiveItems : items,
(item) => item.priority ?? STATUS_BAR_PRIORITY_DEFAULT,
'desc',
);
const sufficientBefore = this._getSufficientValues(this._items);
const sufficientAfter = this._getSufficientValues(newItems);
this._items = newItems;
if (this._config?.style === 'popup' && !isEqual(sufficientBefore, sufficientAfter)) {
this._show();
this._popupTimer.start(this._config.popup_seconds, () => this._hide());
}
this._host.requestUpdate();
}
public setConfig(config: StatusBarConfig): void {
this._config = config;
this._host.style.setProperty(
'--advanced-camera-card-status-bar-height',
`${config.height}px`,
);
this._host.setAttribute('data-style', config.style);
this._host.setAttribute('data-position', config.position);
if (this._config?.style !== 'popup') {
this._show();
}
this._host.requestUpdate();
}
public getConfig(): StatusBarConfig | null {
return this._config;
}
public shouldRender(): boolean {
return this._items.some((item) => item.enabled !== false && item.sufficient);
}
public actionHandler(
ev: CustomEvent<{ action: string; config?: ActionsConfig }>,
config?: ActionsConfig,
): void {
// These interactions should only be handled by the status bar, as nothing
// upstream has the user-provided configuration.
ev.stopPropagation();
const interaction: string = ev.detail.action;
const action = getActionConfigGivenAction(interaction, config);
if (!action) {
return;
}
dispatchActionExecutionRequest(this._host, {
actions: arrayify(action),
config: config,
});
}
private _getSufficientValue(item: StatusBarItem): string | null {
/* istanbul ignore else: cannot happen -- @preserve */
if (item.type === 'custom:advanced-camera-card-status-bar-icon') {
return item.icon;
} else if (item.type === 'custom:advanced-camera-card-status-bar-string') {
return item.string;
} else if (item.type === 'custom:advanced-camera-card-status-bar-image') {
return item.image;
} else {
return null;
}
}
private _getSufficientValues(items: StatusBarItem[]): (string | null)[] {
return items
.filter((item) => item.enabled !== false && item.sufficient)
.map((item) => this._getSufficientValue(item));
}
private _show(): void {
setOrRemoveAttribute(this._host, false, 'hide');
}
private _hide(): void {
setOrRemoveAttribute(this._host, true, 'hide');
}
}