Initial configuration reorganization.
This commit is contained in:
@@ -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);
|
||||
}}
|
||||
|
||||
@@ -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
@@ -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`
|
||||
|
||||
@@ -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
@@ -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()) {
|
||||
|
||||
Reference in New Issue
Block a user