Add consistent initialization logic to improve Chromecast support.

This commit is contained in:
Dermot Duffy
2022-05-10 14:48:06 -07:00
parent cf87e8543a
commit 5bc1d3375c
4 changed files with 92 additions and 48 deletions
+17
View File
@@ -57,6 +57,7 @@ import {
homeAssistantWSRequest,
isValidMediaShowInfo,
shouldUpdateBasedOnHass,
sideLoadHomeAssistantElements,
} from './common.js';
import { localize } from './localize/localize.js';
import { renderMessage, renderProgressIndicator } from './components/message.js';
@@ -186,6 +187,9 @@ export class FrigateCard extends LitElement {
// per second for performance reasons.
protected _boundMouseHandler = throttle(this._mouseHandler.bind(this), 1 * 1000);
// Whether the card has been successfully initialized.
protected _initialized = false;
/**
* Set the Home Assistant object.
*/
@@ -830,6 +834,19 @@ export class FrigateCard extends LitElement {
this._changeView({ view: e.detail });
}
/**
* Called before each update.
*/
protected willUpdate(): void {
if (!this._initialized) {
sideLoadHomeAssistantElements().then((success) => {
if (success) {
this._initialized = true;
}
})
}
}
/**
* Determine whether the element should be updated.
* @param changedProps The changed properties if any.
+50 -9
View File
@@ -21,6 +21,7 @@ import {
ActionsConfig,
ActionType,
CameraConfig,
CardHelpers,
ExtendedHomeAssistant,
FrigateCardAction,
FrigateCardCustomAction,
@@ -33,7 +34,7 @@ import {
signedPathSchema,
StateParameters,
} from './types.js';
import { stateIcon } from './icons/state-icon.js'
import { stateIcon } from './icons/state-icon.js';
const MEDIA_INFO_HEIGHT_CUTOFF = 50;
const MEDIA_INFO_WIDTH_CUTOFF = MEDIA_INFO_HEIGHT_CUTOFF;
@@ -290,10 +291,10 @@ export function convertActionToFrigateCardCustomAction(
export function createFrigateCardCustomAction(
action: FrigateCardAction,
args?: {
camera?: string,
media_player?: string,
media_player_action?: 'play' | 'stop',
}
camera?: string;
media_player?: string;
media_player_action?: 'play' | 'stop';
},
): FrigateCardCustomAction | null {
if (action === 'camera_select') {
if (!args?.camera) {
@@ -473,10 +474,7 @@ export function getEntityTitle(
* @param hass The Home Assistant object.
* @returns The icon or undefined.
*/
export function getEntityIcon(
hass?: HomeAssistant,
entity?: string,
): string {
export function getEntityIcon(hass?: HomeAssistant, entity?: string): string {
return stateIcon(entity ? hass?.states[entity] : null);
}
@@ -682,3 +680,46 @@ export function getEventDurationString(event: FrigateEvent): string {
duration += `${seconds}s`;
return duration;
}
/**
* Side loads the HA elements this card needs. This trickery is unfortunate
* necessary, see:
* - https://github.com/thomasloven/hass-config/wiki/PreLoading-Lovelace-Elements
* @returns `true` if the load is successful, `false` otherwise.
*/
export const sideLoadHomeAssistantElements = async (): Promise<boolean> => {
const neededElements = [
'ha-selector',
'ha-menu-button',
'ha-camera-stream',
'ha-hls-player',
'ha-web-rtc-player',
'ha-icon',
'ha-circular-progress',
'ha-icon-button',
'ha-card',
'ha-svg-icon',
'ha-button-menu',
];
if (neededElements.every((element) => customElements.get(element))) {
return true;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const helpers: CardHelpers = await (window as any).loadCardHelpers();
// The picture-glance editor loads everything this card needs. In particular:
//
// See: https://github.com/thomasloven/hass-config/wiki/PreLoading-Lovelace-Elements
const pictureGlance = await helpers.createCardElement({
type: 'picture-glance',
entities: [],
camera_image: 'dummy-to-load-editor-components',
});
if (pictureGlance.constructor.getConfigElement) {
await pictureGlance.constructor.getConfigElement();
return true;
}
return false;
};
+16 -39
View File
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
@@ -90,7 +89,12 @@ import {
CONF_VIEW_UPDATE_FORCE,
CONF_VIEW_UPDATE_SECONDS,
} from './const.js';
import { arrayMove, getCameraID, getCameraTitle } from './common.js';
import {
arrayMove,
getCameraID,
getCameraTitle,
sideLoadHomeAssistantElements,
} from './common.js';
import {
copyConfig,
deleteConfigValue,
@@ -183,7 +187,6 @@ const options: EditorOptions = {
export class FrigateCardEditor extends LitElement implements LovelaceCardEditor {
@property({ attribute: false }) public hass?: HomeAssistant;
@state() protected _config?: RawFrigateCardConfig;
@state() protected _helpers?: any;
protected _initialized = false;
protected _configUpgradeable = false;
@@ -386,15 +389,19 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
// such, RawFrigateCardConfig is used as the type.
this._config = config;
this._configUpgradeable = isConfigUpgradeable(config);
this.loadCardHelpers();
}
protected shouldUpdate(): boolean {
/**
* Called before each update.
*/
protected willUpdate(): void {
if (!this._initialized) {
this._initialize();
sideLoadHomeAssistantElements().then((success) => {
if (success) {
this._initialized = true;
}
});
}
return true;
}
protected _getEntities(domain: string): string[] {
@@ -929,7 +936,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
}
protected render(): TemplateResult | void {
if (!this.hass || !this._helpers || !this._config) {
if (!this.hass || !this._config) {
return html``;
}
@@ -1219,36 +1226,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
`;
}
/**
* Verify editor is initialized.
*/
protected _initialize(): void {
if (this.hass === undefined) return;
if (this._config === undefined) return;
if (this._helpers === undefined) return;
(async (): Promise<void> => {
// The picture-glance editor loads the ha-selectors.
// See: https://github.com/thomasloven/hass-config/wiki/PreLoading-Lovelace-Elements
const pictureGlance = await this._helpers.createCardElement({
type: 'picture-glance',
entities: [],
camera_image: 'dummy-to-load-editor-components',
});
if (pictureGlance.constructor.getConfigElement) {
await pictureGlance.constructor.getConfigElement();
this._initialized = true;
}
})();
}
/**
* Load card helpers.
*/
protected async loadCardHelpers(): Promise<void> {
this._helpers = await (window as any).loadCardHelpers();
}
/**
* Close the editor menu with the given domain.
* @param targetDomain The menu domain to close.
+9
View File
@@ -5,6 +5,7 @@ import {
CustomActionConfig,
HomeAssistant,
LovelaceCard,
LovelaceCardConfig,
LovelaceCardEditor,
MoreInfoActionConfig,
NavigateActionConfig,
@@ -1152,6 +1153,14 @@ export interface FrigateCardMediaPlayer {
unmute(): void;
}
export interface CardHelpers {
createCardElement(config: LovelaceCardConfig): Promise<{
constructor: {
getConfigElement(): HTMLElement
};
}>;
}
/**
* Home Assistant API types.
*/