From 6a8278deee038aaf69a5e986c537e12643549076 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Fri, 28 Jan 2022 23:41:38 -0800 Subject: [PATCH] Wait for WebRTC component to definitely be loaded. --- src/components/live.ts | 60 ++++++++++++++++++++++------------ src/components/message.ts | 21 ++++++++---- src/localize/languages/en.json | 2 +- src/scss/message.scss | 6 +++- 4 files changed, 60 insertions(+), 29 deletions(-) diff --git a/src/components/live.ts b/src/components/live.ts index 17f90f1d..f788fcb2 100644 --- a/src/components/live.ts +++ b/src/components/live.ts @@ -22,6 +22,7 @@ import { import { EmblaOptionsType, EmblaPluginType } from 'embla-carousel'; import { HomeAssistant } from 'custom-card-helpers'; import { Ref, createRef, ref } from 'lit/directives/ref.js'; +import { Task } from '@lit-labs/task'; import { customElement, property, state } from 'lit/decorators.js'; import { until } from 'lit/directives/until.js'; @@ -681,6 +682,9 @@ export class FrigateCardLiveWebRTC extends LitElement { protected hass?: HomeAssistant & ExtendedHomeAssistant; + // A task to await the load of the WebRTC component. + protected _webrtcTask = new Task(this, this._getWebRTCElement, () => [1]); + /** * Play the video. */ @@ -709,14 +713,22 @@ export class FrigateCardLiveWebRTC extends LitElement { return this.renderRoot?.querySelector('#video') as HTMLVideoElement | null; } + protected async _getWebRTCElement(): Promise { + await customElements.whenDefined('webrtc-camera'); + return customElements.get('webrtc-camera'); + } + /** * Create the WebRTC element. May throw. */ protected _createWebRTC(): HTMLElement | undefined { // eslint-disable-next-line @typescript-eslint/no-explicit-any - const webrtcElement = customElements.get('webrtc-camera') as any; - if (webrtcElement) { - const webrtc = new webrtcElement(); + const webrtcElement = this._webrtcTask.value; + if (webrtcElement && this.hass) { + const webrtc = new webrtcElement() as HTMLElement & { + hass: HomeAssistant; + setConfig: (config: Record) => void; + }; const config = { ...this.webRTCConfig }; // If the live WebRTC configuration does not specify a URL/entity to use, @@ -731,9 +743,8 @@ export class FrigateCardLiveWebRTC extends LitElement { webrtc.setConfig(config); webrtc.hass = this.hass; return webrtc; - } else { - throw new FrigateCardError(localize('error.webrtc_missing')); } + return undefined; } /** @@ -741,21 +752,30 @@ export class FrigateCardLiveWebRTC extends LitElement { * @returns A rendered template. */ protected render(): TemplateResult | void { - if (!this.hass) { - return; - } - let webrtcElement: HTMLElement | undefined; - try { - webrtcElement = this._createWebRTC(); - } catch (e) { - return dispatchErrorMessageEvent( - this, - e instanceof FrigateCardError - ? (e as FrigateCardError).message - : localize('error.webrtc_reported_error') + ': ' + (e as Error).message, - ); - } - return html`${webrtcElement}`; + const render = (): TemplateResult | void => { + let webrtcElement: HTMLElement | undefined; + try { + webrtcElement = this._createWebRTC(); + } catch (e) { + return dispatchErrorMessageEvent( + this, + e instanceof FrigateCardError + ? (e as FrigateCardError).message + : localize('error.webrtc_reported_error') + ': ' + (e as Error).message, + ); + } + return html`${webrtcElement}`; + }; + + // Use a task to allow us to asynchronously wait for the WebRTC card to + // load, but yet still have the card load be followed by the updated() + // lifecycle callback (unlike just using `until`). + return html`${this._webrtcTask.render({ + initial: () => renderProgressIndicator(localize('error.webrtc_waiting')), + pending: () => renderProgressIndicator(localize('error.webrtc_waiting')), + error: (e: unknown) => dispatchErrorMessageEvent(this, (e as Error).message), + complete: () => render(), + })}`; } /** diff --git a/src/components/message.ts b/src/components/message.ts index c0eacadd..8274a250 100644 --- a/src/components/message.ts +++ b/src/components/message.ts @@ -22,9 +22,7 @@ export class FrigateCardMessage extends LitElement { - - ${this.message ? html`${this.message}` : ''} - + ${this.message ? html`${this.message}` : ''} `; } @@ -50,9 +48,15 @@ export class FrigateCardErrorMessage extends LitElement { @customElement('frigate-card-progress-indicator') export class FrigateCardProgressIndicator extends LitElement { + @property({ attribute: false }) + protected message = ''; + protected render(): TemplateResult { - return html`
- + return html`
+ + + + ${this.message ? html`${this.message}` : html``}
`; } @@ -75,6 +79,9 @@ export function renderMessage(message: Message): TemplateResult { return html``; } -export function renderProgressIndicator(): TemplateResult { - return html` `; +export function renderProgressIndicator(message?: string): TemplateResult { + return html` + + + `; } diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 2a89bc00..b06dbf39 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -179,8 +179,8 @@ "invalid_configuration": "Invalid configuration", "invalid_configuration_no_hint": "No location hint available (bad or missing type?)", "upgrade_available": "An automated card configuration upgrade is available, please visit the visual card editor", - "webrtc_missing": "WebRTC component not found", "webrtc_reported_error": "WebRTC component reported an error", + "webrtc_waiting": "Waiting for WebRTC Card to load ...", "no_cameras": "No valid cameras found, you must configure at least one camera entry", "no_camera_id": "Could not determine camera id for the following camera, may need to set 'id' parameter manually", "duplicate_camera_id": "Duplicate Frigate camera id for the following camera, use the 'id' parameter to uniquely identify cameras", diff --git a/src/scss/message.scss b/src/scss/message.scss index 11a039c7..783f0a5d 100644 --- a/src/scss/message.scss +++ b/src/scss/message.scss @@ -13,6 +13,10 @@ padding: 10%; } +.vertical { + flex-direction: column; +} + .message a { color: var(--primary-text-color, white); } @@ -20,4 +24,4 @@ span { padding: 10px; word-break: break-word; -} \ No newline at end of file +}