Add support for pre-defined zoom/pan settings.
This commit is contained in:
+21
-1
@@ -9,10 +9,13 @@ import {
|
||||
unsafeCSS,
|
||||
} from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { guard } from 'lit/directives/guard.js';
|
||||
import { live } from 'lit/directives/live.js';
|
||||
import { createRef, ref, Ref } from 'lit/directives/ref.js';
|
||||
import isEqual from 'lodash-es/isEqual';
|
||||
import { CachedValueController } from '../components-lib/cached-value-controller.js';
|
||||
import { ZoomDefault } from '../components-lib/zoom/types.js';
|
||||
import { handleZoomDefaultEvent } from '../components-lib/zoom/zoom-view-context.js';
|
||||
import { CameraConfig, ImageViewConfig } from '../config/types.js';
|
||||
import defaultImage from '../images/frigate-bird-in-sky.jpg';
|
||||
import { localize } from '../localize/localize.js';
|
||||
@@ -277,8 +280,25 @@ export class FrigateCardImage extends LitElement implements FrigateCardMediaPlay
|
||||
}
|
||||
|
||||
protected _useZoomIfRequired(template: TemplateResult): TemplateResult {
|
||||
const targetID = this.cameraConfig?.id;
|
||||
const zoomConfig = targetID ? this.view?.context?.zoom?.[targetID]?.zoom : undefined;
|
||||
|
||||
return this.imageConfig?.zoomable
|
||||
? html` <frigate-card-zoomer> ${template} </frigate-card-zoomer>`
|
||||
? html` <frigate-card-zoomer
|
||||
.defaultConfig=${guard([this.cameraConfig?.dimensions?.layout], () =>
|
||||
this.cameraConfig?.dimensions?.layout
|
||||
? {
|
||||
pan: this.cameraConfig.dimensions.layout.pan,
|
||||
zoom: this.cameraConfig.dimensions.layout.zoom,
|
||||
}
|
||||
: undefined,
|
||||
)}
|
||||
.config=${zoomConfig}
|
||||
@frigate-card:zoom:default=${(ev: CustomEvent<ZoomDefault>) =>
|
||||
handleZoomDefaultEvent(this, ev, targetID)}
|
||||
>
|
||||
${template}
|
||||
</frigate-card-zoomer>`
|
||||
: template;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { createRef, ref, Ref } from 'lit/directives/ref.js';
|
||||
import { CameraConfig } from '../../config/types';
|
||||
import { localize } from '../../localize/localize';
|
||||
import liveImageStyle from '../../scss/live-image.scss';
|
||||
import basicBlockStyle from '../../scss/basic-block.scss';
|
||||
import { FrigateCardMediaPlayer } from '../../types.js';
|
||||
import { getStateObjOrDispatchError } from '../../utils/get-state-obj';
|
||||
import '../image.js';
|
||||
@@ -17,9 +16,6 @@ export class FrigateCardLiveImage extends LitElement implements FrigateCardMedia
|
||||
@property({ attribute: false })
|
||||
public cameraConfig?: CameraConfig;
|
||||
|
||||
@property({ attribute: true })
|
||||
public watermark?: string;
|
||||
|
||||
protected _refImage: Ref<Element & FrigateCardMediaPlayer> = createRef();
|
||||
|
||||
public async play(): Promise<void> {
|
||||
@@ -80,17 +76,11 @@ export class FrigateCardLiveImage extends LitElement implements FrigateCardMedia
|
||||
.cameraConfig=${this.cameraConfig}
|
||||
>
|
||||
</frigate-card-image>
|
||||
${this.watermark
|
||||
? html`<ha-icon
|
||||
title=${localize('error.awaiting_live')}
|
||||
icon="${this.watermark}"
|
||||
></ha-icon>`
|
||||
: ''}
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return unsafeCSS(liveImageStyle);
|
||||
return unsafeCSS(basicBlockStyle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ import {
|
||||
import { ReadonlyMicrophoneManager } from '../../card-controller/microphone-manager.js';
|
||||
import { LiveController } from '../../components-lib/live/live-controller.js';
|
||||
import { MediaGridSelected } from '../../components-lib/media-grid-controller.js';
|
||||
import { ZoomConfig, ZoomDefault } from '../../components-lib/zoom/types.js';
|
||||
import { handleZoomDefaultEvent } from '../../components-lib/zoom/zoom-view-context.js';
|
||||
import {
|
||||
CameraConfig,
|
||||
CardWideConfig,
|
||||
@@ -501,6 +503,9 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
.liveConfig=${liveConfig}
|
||||
.hass=${this.hass}
|
||||
.cardWideConfig=${this.cardWideConfig}
|
||||
.zoomConfig=${this.view?.context?.zoom?.[cameraID]?.zoom}
|
||||
@frigate-card:zoom:default=${(ev: CustomEvent<ZoomDefault>) =>
|
||||
handleZoomDefaultEvent(this, ev, cameraID)}
|
||||
>
|
||||
</frigate-card-live-provider>
|
||||
</div>
|
||||
@@ -688,6 +693,9 @@ export class FrigateCardLiveProvider
|
||||
@property({ attribute: false })
|
||||
public microphoneStream?: MediaStream;
|
||||
|
||||
@property({ attribute: false })
|
||||
public zoomConfig?: ZoomConfig | null;
|
||||
|
||||
@state()
|
||||
protected _isVideoMediaLoaded = false;
|
||||
|
||||
@@ -793,9 +801,6 @@ export class FrigateCardLiveProvider
|
||||
this._isVideoMediaLoaded = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record that video media is being shown.
|
||||
*/
|
||||
protected _videoMediaShowHandler(): void {
|
||||
this._isVideoMediaLoaded = true;
|
||||
}
|
||||
@@ -852,6 +857,15 @@ export class FrigateCardLiveProvider
|
||||
protected _useZoomIfRequired(template: TemplateResult): TemplateResult {
|
||||
return this.liveConfig?.zoomable
|
||||
? html` <frigate-card-zoomer
|
||||
.defaultConfig=${guard([this.cameraConfig?.dimensions?.layout], () =>
|
||||
this.cameraConfig?.dimensions?.layout
|
||||
? {
|
||||
pan: this.cameraConfig.dimensions.layout.pan,
|
||||
zoom: this.cameraConfig.dimensions.layout.zoom,
|
||||
}
|
||||
: undefined,
|
||||
)}
|
||||
.config=${this.zoomConfig}
|
||||
@frigate-card:zoom:zoomed=${() => this.setControls(false)}
|
||||
@frigate-card:zoom:unzoomed=${() => this.setControls()}
|
||||
>
|
||||
@@ -899,15 +913,12 @@ export class FrigateCardLiveProvider
|
||||
}
|
||||
}
|
||||
|
||||
return this._useZoomIfRequired(html`
|
||||
return html`${this._useZoomIfRequired(html`
|
||||
${showImageDuringLoading || provider === 'image'
|
||||
? html` <frigate-card-live-image
|
||||
${ref(this._refProvider)}
|
||||
.hass=${this.hass}
|
||||
.cameraConfig=${this.cameraConfig}
|
||||
watermark=${ifDefined(
|
||||
showImageDuringLoading ? 'mdi:progress-helper' : undefined,
|
||||
)}
|
||||
@frigate-card:media:loaded=${(ev: Event) => {
|
||||
if (provider === 'image') {
|
||||
// Only count the media has loaded if the required provider is
|
||||
@@ -968,7 +979,13 @@ export class FrigateCardLiveProvider
|
||||
>
|
||||
</frigate-card-live-jsmpeg>`
|
||||
: html``}
|
||||
`);
|
||||
`)}
|
||||
${showImageDuringLoading && !this._isVideoMediaLoaded
|
||||
? html`<ha-icon
|
||||
title=${localize('error.awaiting_live')}
|
||||
icon="mdi:progress-helper"
|
||||
></ha-icon>`
|
||||
: ''} `;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
||||
@@ -12,6 +12,8 @@ import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { createRef, Ref, ref } from 'lit/directives/ref.js';
|
||||
import { CameraManager } from '../camera-manager/manager.js';
|
||||
import { MediaGridSelected } from '../components-lib/media-grid-controller.js';
|
||||
import { ZoomDefault } from '../components-lib/zoom/types.js';
|
||||
import { handleZoomDefaultEvent } from '../components-lib/zoom/zoom-view-context.js';
|
||||
import {
|
||||
dispatchMessageEvent,
|
||||
renderMessage,
|
||||
@@ -484,7 +486,7 @@ export class FrigateCardViewerCarousel extends LitElement {
|
||||
stopEventFromActivatingCardWideActions(ev);
|
||||
}}
|
||||
></frigate-card-next-previous-control>
|
||||
${guard(this._media, () => this._getSlides())}
|
||||
${guard([this._media, this.view], () => this._getSlides())}
|
||||
<frigate-card-next-previous-control
|
||||
slot="next"
|
||||
.hass=${this.hass}
|
||||
@@ -865,10 +867,28 @@ export class FrigateCardViewerProvider
|
||||
}
|
||||
|
||||
protected _useZoomIfRequired(template: TemplateResult): TemplateResult {
|
||||
if (!this.media) {
|
||||
return template;
|
||||
}
|
||||
const cameraID = this.media.getCameraID();
|
||||
const mediaID = this.media.getID() ?? undefined;
|
||||
const cameraConfig = this.cameraManager?.getStore().getCameraConfig(cameraID);
|
||||
|
||||
return this.viewerConfig?.zoomable
|
||||
? html` <frigate-card-zoomer
|
||||
.defaultConfig=${guard([cameraConfig?.dimensions?.layout], () =>
|
||||
cameraConfig?.dimensions?.layout
|
||||
? {
|
||||
pan: cameraConfig.dimensions.layout.pan,
|
||||
zoom: cameraConfig.dimensions.layout.zoom,
|
||||
}
|
||||
: undefined,
|
||||
)}
|
||||
.config=${mediaID ? this.view?.context?.zoom?.[mediaID]?.zoom : undefined}
|
||||
@frigate-card:zoom:zoomed=${() => this.setControls(false)}
|
||||
@frigate-card:zoom:unzoomed=${() => this.setControls()}
|
||||
@frigate-card:zoom:default=${(ev: CustomEvent<ZoomDefault>) =>
|
||||
handleZoomDefaultEvent(this, ev, mediaID)}
|
||||
>
|
||||
${template}
|
||||
</frigate-card-zoomer>`
|
||||
|
||||
@@ -6,13 +6,20 @@ import {
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { ZoomController } from '../components-lib/zoom-controller.js';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { ZoomConfig } from '../components-lib/zoom/types.js';
|
||||
import { ZoomController } from '../components-lib/zoom/zoom-controller.js';
|
||||
import { setOrRemoveAttribute } from '../utils/basic.js';
|
||||
|
||||
@customElement('frigate-card-zoomer')
|
||||
export class FrigateCardZoomer extends LitElement {
|
||||
protected _zoom = new ZoomController(this);
|
||||
protected _zoom: ZoomController | null = null;
|
||||
|
||||
@property({ attribute: false })
|
||||
public defaultConfig?: ZoomConfig;
|
||||
|
||||
@property({ attribute: false })
|
||||
public config?: ZoomConfig | null;
|
||||
|
||||
@state()
|
||||
protected _zoomed = false;
|
||||
@@ -24,11 +31,13 @@ export class FrigateCardZoomer extends LitElement {
|
||||
super.connectedCallback();
|
||||
this.addEventListener('frigate-card:zoom:zoomed', this._zoomHandler);
|
||||
this.addEventListener('frigate-card:zoom:unzoomed', this._unzoomHandler);
|
||||
this._zoom.activate();
|
||||
|
||||
// Call for an update to activate.
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
this._zoom.deactivate();
|
||||
this._zoom?.deactivate();
|
||||
this.removeEventListener('frigate-card:zoom:zoomed', this._zoomHandler);
|
||||
this.removeEventListener('frigate-card:zoom:unzoomed', this._unzoomHandler);
|
||||
}
|
||||
@@ -37,7 +46,26 @@ export class FrigateCardZoomer extends LitElement {
|
||||
if (changedProps.has('_zoomed')) {
|
||||
setOrRemoveAttribute(this, this._zoomed, 'zoomed');
|
||||
}
|
||||
|
||||
if (this._zoom) {
|
||||
if (changedProps.has('defaultConfig')) {
|
||||
this._zoom.setDefaultConfig(this.defaultConfig ?? null);
|
||||
}
|
||||
// If config is null, make no change to the zoom.
|
||||
if (changedProps.has('config') && this.config) {
|
||||
this._zoom.setConfig(this.config);
|
||||
}
|
||||
} else {
|
||||
// Ensure that the configuration will be set before activation (vs
|
||||
// activating in `connectedCallback`).
|
||||
this._zoom = new ZoomController(this, {
|
||||
config: this.config,
|
||||
defaultConfig: this.defaultConfig,
|
||||
});
|
||||
this._zoom.activate();
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html` <slot></slot> `;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user