Limit re-rendering to improve user experience.

This commit is contained in:
Dermot Duffy
2021-08-29 12:29:55 -07:00
parent 61f46241f8
commit 8439d5f550
2 changed files with 8 additions and 77 deletions
+7 -69
View File
@@ -35,7 +35,6 @@ import {
} from './types'; } from './types';
import type { import type {
BrowseMediaSource, BrowseMediaSource,
ControlVideosParameters,
FrigateCardView, FrigateCardView,
FrigateCardConfig, FrigateCardConfig,
FrigateMenuMode, FrigateMenuMode,
@@ -340,9 +339,13 @@ export class FrigateCard extends LitElement {
const oldHass = changedProps.get('_hass') as HomeAssistant | undefined; const oldHass = changedProps.get('_hass') as HomeAssistant | undefined;
if (oldHass) { if (oldHass) {
// A re-render will interrupt a clip that is playing. Do not allow this // Home Assistant pumps a lot of updates through. Re-rendering the card is
// for hass state updates. // necessary at times (e.g. to update the 'clip' view as new clips
if (this._clipPlaying) { // arrive), but also is a jarring experience for the user (e.g. if they
// are browsing the mini-gallery). Do not allow re-rendering from a Home
// Assistant update if there's been recent interaction (e.g. clicks on the
// card) or if there is a clip active playing.
if (this._interactionTimerID || this._clipPlaying) {
return false; return false;
} }
return shouldUpdateBasedOnHass(this._hass, oldHass, [ return shouldUpdateBasedOnHass(this._hass, oldHass, [
@@ -513,85 +516,20 @@ export class FrigateCard extends LitElement {
</div>`; </div>`;
} }
// Stop/Play video controls.
protected _controlVideos({
stop,
control_live = false,
control_clip = false,
}: ControlVideosParameters): void {
const controlVideo = (stop: boolean, is_live: boolean, video: HTMLVideoElement) => {
if (video) {
if (stop) {
video.pause();
video.currentTime = 0;
} else if (is_live) {
// Duration on webrtc is infinity so cannot fast-forward.
if (!this._webrtcElement) {
// If it's a live view, 'fast-forward' to most recent content.
const duration = video.duration;
video.currentTime = duration;
}
video.play();
}
}
};
if (!this.shadowRoot) {
return;
}
if (control_clip) {
controlVideo(
stop,
false,
this.shadowRoot?.querySelector('video.frigate-card-viewer') as HTMLVideoElement,
);
}
if (control_live) {
// Don't have direct access to the live video player as it is buried in
// multiple components/shadow-roots, so need to navigate the path to get to <video>.
if (this._webrtcElement) {
controlVideo(
stop,
true,
this.shadowRoot?.querySelector('webrtc-camera video') as HTMLVideoElement,
);
} else {
controlVideo(
stop,
true,
this.shadowRoot
?.querySelector('ha-camera-stream')
?.shadowRoot?.querySelector('ha-hls-player')
?.shadowRoot?.querySelector('video') as HTMLVideoElement,
);
}
}
}
protected _menuActionHandler(name: string): void { protected _menuActionHandler(name: string): void {
switch (name) { switch (name) {
case 'frigate': case 'frigate':
this._controlVideos({ stop: true, control_clip: true });
this._controlVideos({ stop: true, control_live: true });
this._changeView(); this._changeView();
break; break;
case 'live': case 'live':
this._controlVideos({ stop: true, control_clip: true });
this._controlVideos({ stop: false, control_live: true });
this._changeView(name);
break;
case 'clips': case 'clips':
this._controlVideos({ stop: true, control_live: true });
this._changeView(name);
break;
case 'snapshots': case 'snapshots':
this._controlVideos({ stop: true, control_clip: true, control_live: true });
this._changeView(name); this._changeView(name);
break; break;
case 'frigate_ui': case 'frigate_ui':
const frigate_url = this._getFrigateURLFromContext(); const frigate_url = this._getFrigateURLFromContext();
if (frigate_url) { if (frigate_url) {
window.open(frigate_url); window.open(frigate_url);
break;
} }
break; break;
case 'motion': case 'motion':
+1 -8
View File
@@ -41,7 +41,6 @@ export const frigateCardConfigSchema = z.object({
frigate_client_id: z.string().optional().default("frigate"), frigate_client_id: z.string().optional().default("frigate"),
frigate_camera_name: z.string().optional(), frigate_camera_name: z.string().optional(),
view_default: z.enum(FRIGATE_CARD_VIEWS).optional().default('live'), view_default: z.enum(FRIGATE_CARD_VIEWS).optional().default('live'),
view_timeout: z view_timeout: z
.number() .number()
.or( .or(
@@ -50,7 +49,7 @@ export const frigateCardConfigSchema = z.object({
.regex(/^\d+$/) .regex(/^\d+$/)
.transform((val) => Number(val)), .transform((val) => Number(val)),
) )
.optional(), .optional().default(180),
live_provider: z.enum(['frigate', 'webrtc']).default('frigate'), live_provider: z.enum(['frigate', 'webrtc']).default('frigate'),
webrtc: z.object({}).passthrough().optional(), webrtc: z.object({}).passthrough().optional(),
label: z.string().optional(), label: z.string().optional(),
@@ -66,12 +65,6 @@ export const frigateCardConfigSchema = z.object({
}); });
export type FrigateCardConfig = z.infer<typeof frigateCardConfigSchema>; export type FrigateCardConfig = z.infer<typeof frigateCardConfigSchema>;
export interface ControlVideosParameters {
stop: boolean;
control_live?: boolean;
control_clip?: boolean;
}
export interface MediaBeingShown { export interface MediaBeingShown {
browseMedia: BrowseMediaSource; browseMedia: BrowseMediaSource;
resolvedMedia: ResolvedMedia; resolvedMedia: ResolvedMedia;