Initial configuration reorganization.

This commit is contained in:
Dermot Duffy
2021-11-01 12:43:33 -07:00
parent 12cee94d49
commit e0daa17834
11 changed files with 638 additions and 477 deletions
+5 -3
View File
@@ -3,17 +3,19 @@ import { customElement, property } from 'lit/decorators.js';
import { dispatchMediaShowEvent } from '../common.js';
import imageStyle from '../scss/image.scss';
import type { ImageViewConfig } from '../types.js';
import defaultImage from '../images/frigate-bird-in-sky.jpg'
import imageStyle from '../scss/image.scss';
@customElement('frigate-card-image')
export class FrigateCardImage extends LitElement {
@property({ attribute: false })
protected image?: string;
protected imageConfig?: ImageViewConfig;
protected render(): TemplateResult | void {
return html` <img
src=${this.image || defaultImage}
src=${this.imageConfig?.src || defaultImage}
@load=${(e) => {
dispatchMediaShowEvent(this, e);
}}
+6 -6
View File
@@ -1,5 +1,5 @@
import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit';
import type { ExtendedHomeAssistant, FrigateCardConfig, MediaShowInfo } from '../types.js';
import type { ExtendedHomeAssistant, FrigateCardConfig, MediaShowInfo, WebRTCConfig } from '../types.js';
import { HomeAssistant } from 'custom-card-helpers';
import { customElement, property } from 'lit/decorators.js';
import { until } from 'lit/directives/until.js';
@@ -75,24 +75,24 @@ export class FrigateCardLive extends LitElement {
return;
}
return html` ${this.config.live_provider == 'frigate'
return html` ${this.config.live.provider == 'frigate'
? html` <frigate-card-live-frigate
.hass=${this.hass}
.cameraEntity=${this.config.camera_entity}
@frigate-card:media-show=${this._mediaShowHandler}
>
</frigate-card-live-frigate>`
: this.config.live_provider == 'webrtc'
: this.config.live.provider == 'webrtc'
? html`<frigate-card-live-webrtc
.hass=${this.hass}
.webRTCConfig=${this.config.webrtc || {}}
.webRTCConfig=${this.config.live.webrtc || {}}
@frigate-card:media-show=${this._mediaShowHandler}
>
</frigate-card-live-webrtc>`
: html` <frigate-card-live-jsmpeg
.hass=${this.hass}
.cameraName=${this.frigateCameraName}
.clientId=${this.config.frigate_client_id}
.clientId=${this.config.frigate.client_id}
@frigate-card:media-show=${this._mediaShowHandler}
>
</frigate-card-live-jsmpeg>`}`;
@@ -152,7 +152,7 @@ export class FrigateCardLiveFrigate extends LitElement {
@customElement('frigate-card-live-webrtc')
export class FrigateCardLiveWebRTC extends LitElement {
@property({ attribute: false })
protected webRTCConfig?: Record<string, unknown>;
protected webRTCConfig?: WebRTCConfig;
protected hass?: HomeAssistant & ExtendedHomeAssistant;
protected _webRTCElement: HTMLElement | null = null;
+37 -32
View File
@@ -16,8 +16,8 @@ import { actionHandler } from '../action-handler-directive.js';
import type {
ExtendedHomeAssistant,
FrigateMenuMode,
MenuButton,
MenuConfig,
MenuInteraction,
} from '../types.js';
import { dispatchFrigateCardEvent, shouldUpdateBasedOnHass } from '../common.js';
@@ -30,10 +30,16 @@ export const MENU_HEIGHT = 46;
@customElement('frigate-card-menu')
export class FrigateCardMenu extends LitElement {
@property({ attribute: false })
public hass!: HomeAssistant & ExtendedHomeAssistant;
public hass?: HomeAssistant & ExtendedHomeAssistant;
@property({ attribute: false })
protected menuMode: FrigateMenuMode = 'hidden-top';
set menuConfig(menuConfig: MenuConfig) {
this._menuConfig = menuConfig;
if (menuConfig) {
this.style.setProperty('--frigate-card-menu-button-size', menuConfig.button_size);
}
}
public _menuConfig?: MenuConfig;
@property({ attribute: false })
protected expand = false;
@@ -41,13 +47,8 @@ export class FrigateCardMenu extends LitElement {
@property({ attribute: false })
public buttons: MenuButton[] = [];
@property({ attribute: false })
set buttonSize(buttonSize: string) {
this.style.setProperty('--frigate-card-menu-button-size', buttonSize);
}
protected _interactionHandler(ev: CustomEvent, button: MenuButton): void {
if (this.menuMode.startsWith('hidden-')) {
if (this._menuConfig?.mode.startsWith('hidden-')) {
if (button.type == 'internal-menu-icon' && button.tap_action === 'frigate') {
this.expand = !this.expand;
return;
@@ -82,7 +83,7 @@ export class FrigateCardMenu extends LitElement {
}
// Render a menu button.
protected _renderButton(button: MenuButton): TemplateResult {
protected _renderButton(button: MenuButton): TemplateResult | void {
let state: HassEntity | null = null;
let emphasize = false;
let title = button.title;
@@ -90,6 +91,9 @@ export class FrigateCardMenu extends LitElement {
const style = ('style' in button ? button.style : {}) || {};
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);
@@ -133,9 +137,9 @@ export class FrigateCardMenu extends LitElement {
}
// Render the Frigate menu button.
protected _renderFrigateButton(button: MenuButton): TemplateResult {
protected _renderFrigateButton(button: MenuButton): TemplateResult | void {
const icon =
this.menuMode.startsWith('hidden-') && !this.expand
this._menuConfig?.mode.startsWith('hidden-') && !this.expand
? 'mdi:alpha-f-box-outline'
: 'mdi:alpha-f-box';
@@ -143,7 +147,12 @@ export class FrigateCardMenu extends LitElement {
}
// Render the menu.
protected render(): TemplateResult {
protected render(): TemplateResult | void {
if (!this._menuConfig) {
return;
}
const mode = this._menuConfig.mode;
const isFrigateButton = function (button: MenuButton): boolean {
return button.type === 'internal-menu-icon' && button.tap_action === 'frigate';
};
@@ -151,33 +160,29 @@ export class FrigateCardMenu extends LitElement {
// If the menu is off, or if it's in hidden mode but there's no button to
// unhide it, just show nothing.
if (
this.menuMode == 'none' ||
(this.menuMode.startsWith('hidden-') && !this.buttons.find(isFrigateButton))
mode == 'none' ||
(mode.startsWith('hidden-') && !this.buttons.find(isFrigateButton))
) {
return html``;
return;
}
const classes = {
'frigate-card-menu': true,
'overlay-hidden':
this.menuMode.startsWith('hidden-') ||
this.menuMode.startsWith('overlay-') ||
this.menuMode.startsWith('hover-'),
mode.startsWith('hidden-') ||
mode.startsWith('overlay-') ||
mode.startsWith('hover-'),
'expanded-horizontal':
(this.menuMode.startsWith('overlay-') ||
this.menuMode.startsWith('hover-') ||
this.expand) &&
(this.menuMode.endsWith('-top') || this.menuMode.endsWith('-bottom')),
(mode.startsWith('overlay-') || mode.startsWith('hover-') || this.expand) &&
(mode.endsWith('-top') || mode.endsWith('-bottom')),
'expanded-vertical':
(this.menuMode.startsWith('overlay-') ||
this.menuMode.startsWith('hover-') ||
this.expand) &&
(this.menuMode.endsWith('-left') || this.menuMode.endsWith('-right')),
full: ['above', 'below'].includes(this.menuMode),
left: this.menuMode.endsWith('-left'),
right: this.menuMode.endsWith('-right'),
top: this.menuMode.endsWith('-top'),
bottom: this.menuMode.endsWith('-bottom'),
(mode.startsWith('overlay-') || mode.startsWith('hover-') || this.expand) &&
(mode.endsWith('-left') || mode.endsWith('-right')),
full: mode == 'above' || mode == 'below',
left: mode.endsWith('-left'),
right: mode.endsWith('-right'),
top: mode.endsWith('-top'),
bottom: mode.endsWith('-bottom'),
};
return html`
+14 -15
View File
@@ -2,30 +2,29 @@ import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit
import { customElement, property } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { NextPreviousControlStyle } from '../types.js';
import { NextPreviousControlConfig } from '../types.js';
import controlStyle from '../scss/next-previous-control.scss';
@customElement('frigate-card-next-previous-control')
export class FrigateCardMessage extends LitElement {
export class FrigateCardNextPreviousControl extends LitElement {
@property({ attribute: false })
protected direction?: 'next' | 'previous';
@property({ attribute: false })
protected controlStyle?: NextPreviousControlStyle;
set controlConfig(controlConfig: NextPreviousControlConfig | undefined) {
if (controlConfig?.size) {
this.style.setProperty('--frigate-card-next-prev-size', controlConfig.size);
}
this._controlConfig = controlConfig;
}
protected _controlConfig?: NextPreviousControlConfig;
@property({ attribute: false })
protected thumbnail?: string;
@property({ attribute: false })
set controlSize(controlSize: string | undefined) {
if (controlSize) {
this.style.setProperty('--frigate-card-next-prev-size', controlSize);
}
}
protected render(): TemplateResult {
if (!this.controlStyle || this.controlStyle == 'none') {
if (!this._controlConfig || this._controlConfig.style == 'none') {
return html``;
}
@@ -33,12 +32,12 @@ export class FrigateCardMessage extends LitElement {
controls: true,
previous: this.direction == 'previous',
next: this.direction == 'next',
thumbnails: this.controlStyle == 'thumbnails',
chevrons: this.controlStyle == 'chevrons',
button: this.controlStyle == 'chevrons',
thumbnails: this._controlConfig.style == 'thumbnails',
chevrons: this._controlConfig.style == 'chevrons',
button: this._controlConfig.style == 'chevrons',
};
if (this.controlStyle == 'chevrons') {
if (this._controlConfig.style == 'chevrons') {
const icon = this.direction == 'previous' ? 'mdi:chevron-left' : 'mdi:chevron-right';
// TODO: Upon a safe distance from the release of HA 2021.11 these
+39 -55
View File
@@ -19,7 +19,7 @@ import type {
BrowseMediaSource,
ExtendedHomeAssistant,
MediaShowInfo,
NextPreviousControlStyle,
ViewerConfig,
} from '../types.js';
import { ResolvedMediaCache, ResolvedMediaUtil } from '../resolved-media.js';
import { View } from '../view.js';
@@ -49,24 +49,15 @@ export class FrigateCardViewer extends LitElement {
@property({ attribute: false })
protected view?: View;
@property({ attribute: false })
protected viewerConfig?: ViewerConfig;
@property({ attribute: false })
protected browseMediaQueryParameters?: BrowseMediaQueryParameters;
@property({ attribute: false })
protected nextPreviousControlStyle?: NextPreviousControlStyle;
@property({ attribute: false })
protected nextPreviousControlSize?: string;
@property({ attribute: false })
protected autoplayClip?: boolean;
@property({ attribute: false })
protected resolvedMediaCache?: ResolvedMediaCache;
@property({ attribute: false })
protected lazyLoad?: boolean;
/**
* Resolve all the given media for a target.
* @param target The target to resolve media from.
@@ -92,21 +83,23 @@ export class FrigateCardViewer extends LitElement {
return errorFree;
}
/**
* Master render method.
* @returns A rendered template.
*/
protected render(): TemplateResult | void {
return html`${until(this._render(), renderProgressIndicator())}`;
}
/**
* Asyncronously render the element.
* @returns A template to render.
* @returns A rendered template.
*/
protected async _render(): Promise<TemplateResult | void> {
if (!this.hass || !this.view || !this.browseMediaQueryParameters) {
return html``;
}
let autoplay = true;
if (this.view.is('clip') || this.view.is('snapshot')) {
let parent: BrowseMediaSource | null = null;
try {
@@ -129,13 +122,6 @@ export class FrigateCardViewer extends LitElement {
}
this.view.target = parent;
this.view.childIndex = childIndex;
// In this block, no clip has been manually selected, so this is loading
// the most recent clip on card load. In this mode, autoplay of the clip
// may be disabled by configuration. If does not make sense to disable
// autoplay when the user has explicitly picked an event to play in the
// gallery.
autoplay = this.autoplayClip ?? true;
}
if (this.view.target && !(await this._resolveAllMediaForTarget(this.view.target))) {
@@ -144,13 +130,10 @@ export class FrigateCardViewer extends LitElement {
return html` <frigate-card-viewer-core
.view=${this.view}
.nextPreviousControlStyle=${this.nextPreviousControlStyle}
.nextPreviousControlSize=${this.nextPreviousControlSize}
.viewerConfig=${this.viewerConfig}
.resolvedMediaCache=${this.resolvedMediaCache}
.autoplayClip=${autoplay}
.hass=${this.hass}
.browseMediaQueryParameters=${this.browseMediaQueryParameters}
.lazyLoad=${this.lazyLoad}
>
</frigate-card-viewer-core>`;
}
@@ -165,29 +148,20 @@ export class FrigateCardViewer extends LitElement {
@customElement('frigate-card-viewer-core')
export class FrigateCardViewerCore extends LitElement {
@property({ attribute: false })
protected hass?: HomeAssistant & ExtendedHomeAssistant;
@property({ attribute: false })
protected view?: View;
@property({ attribute: false })
protected nextPreviousControlStyle?: NextPreviousControlStyle;
@property({ attribute: false })
protected nextPreviousControlSize?: string;
@property({ attribute: false })
protected resolvedMediaCache?: ResolvedMediaCache;
@property({ attribute: false })
protected autoplayClip?: boolean;
@property({ attribute: false })
protected hass?: HomeAssistant & ExtendedHomeAssistant;
protected viewerConfig?: ViewerConfig;
@property({ attribute: false })
protected browseMediaQueryParameters?: BrowseMediaQueryParameters;
@property({ attribute: false })
protected lazyLoad?: boolean;
protected resolvedMediaCache?: ResolvedMediaCache;
// Media carousel object.
protected _carousel?: EmblaCarouselType;
@@ -418,7 +392,7 @@ export class FrigateCardViewerCore extends LitElement {
* Lazily load media in the carousel.
*/
protected _lazyLoadMediaHandler(): void {
if (!this.lazyLoad || !this._carousel) {
if (!this.viewerConfig?.lazy_load || !this._carousel) {
return;
}
const slides = this._carousel.slideNodes();
@@ -504,8 +478,7 @@ export class FrigateCardViewerCore extends LitElement {
${neighbors && neighbors.previous
? html`<frigate-card-next-previous-control
.direction=${'previous'}
.controlStyle=${this.nextPreviousControlStyle}
.controlSize=${this.nextPreviousControlSize}
.controlConfig=${this.viewerConfig?.controls.next_previous}
.thumbnail=${neighbors.previous.thumbnail}
.title=${neighbors.previous.title}
@click=${() => this._nextPreviousHandler('previous')}
@@ -519,8 +492,7 @@ export class FrigateCardViewerCore extends LitElement {
${neighbors && neighbors.next
? html`<frigate-card-next-previous-control
.direction=${'next'}
.controlStyle=${this.nextPreviousControlStyle}
.controlSize=${this.nextPreviousControlSize}
.controlConfig=${this.viewerConfig?.controls.next_previous}
.thumbnail=${neighbors.next.thumbnail}
.title=${neighbors.next.title}
@click=${() => this._nextPreviousHandler('next')}
@@ -594,7 +566,7 @@ export class FrigateCardViewerCore extends LitElement {
): TemplateResult | void {
// media that can be expanded (folders) cannot be resolved to a single media
// item, skip them.
if (!this.view || !BrowseMediaUtil.isTrueMedia(mediaToRender)) {
if (!this.view || !this.viewerConfig || !BrowseMediaUtil.isTrueMedia(mediaToRender)) {
return;
}
@@ -603,20 +575,32 @@ export class FrigateCardViewerCore extends LitElement {
return;
}
// In this block, no clip has been manually selected, so this is loading
// the most recent clip on card load. In this mode, autoplay of the clip
// may be disabled by configuration. If does not make sense to disable
// autoplay when the user has explicitly picked an event to play in the
// gallery.
let autoplay = true;
if (this.view.is('clip') || this.view.is('snapshot')) {
autoplay = this.viewerConfig.autoplay_clip;
}
const lazyLoad = this.viewerConfig.lazy_load;
return html`
<div class="embla__slide">
${this.view.isClipRelatedView()
? resolvedMedia?.mime_type.toLowerCase() == 'application/x-mpegurl'
? html`<frigate-card-ha-hls-player
.hass=${this.hass}
url=${ifDefined(this.lazyLoad ? undefined : resolvedMedia.url)}
data-url=${ifDefined(this.lazyLoad ? resolvedMedia.url : undefined)}
url=${ifDefined(lazyLoad ? undefined : resolvedMedia.url)}
data-url=${ifDefined(lazyLoad ? resolvedMedia.url : undefined)}
title="${mediaToRender.title}"
muted
controls
playsinline
allow-exoplayer
?autoplay="${this.autoplayClip}"
?autoplay="${autoplay}"
@frigate-card:media-show=${(e: CustomEvent<MediaShowInfo>) =>
this._mediaShowEventHandler(slideIndex, e)}
>
@@ -626,7 +610,7 @@ export class FrigateCardViewerCore extends LitElement {
muted
controls
playsinline
?autoplay="${this.autoplayClip}"
?autoplay="${autoplay}"
@loadedmetadata="${(e: Event) => {
this._mediaShowInfoHandler(slideIndex, createMediaShowInfo(e));
}}"
@@ -634,14 +618,14 @@ export class FrigateCardViewerCore extends LitElement {
@pause=${() => dispatchPauseEvent(this)}
>
<source
src=${ifDefined(this.lazyLoad ? undefined : resolvedMedia.url)}
data-src=${ifDefined(this.lazyLoad ? resolvedMedia.url : undefined)}
src=${ifDefined(lazyLoad ? undefined : resolvedMedia.url)}
data-src=${ifDefined(lazyLoad ? resolvedMedia.url : undefined)}
type="${resolvedMedia.mime_type}"
/>
</video>`
: html`<img
src=${ifDefined(this.lazyLoad ? IMG_EMPTY : resolvedMedia.url)}
data-src=${ifDefined(this.lazyLoad ? resolvedMedia.url : undefined)}
src=${ifDefined(lazyLoad ? IMG_EMPTY : resolvedMedia.url)}
data-src=${ifDefined(lazyLoad ? resolvedMedia.url : undefined)}
title="${mediaToRender.title}"
@click=${() => {
if (this._carousel?.clickAllowed()) {