Reset the carousel of the plugins/options change.

This commit is contained in:
Dermot Duffy
2022-07-10 20:05:18 -07:00
parent 898a46fda2
commit 214a553aa7
5 changed files with 91 additions and 74 deletions
+19
View File
@@ -65,6 +65,21 @@ export class FrigateCardCarousel extends LitElement {
super.disconnectedCallback();
}
/**
* Destroy the carousel if certain properties change.
* @param changedProps The changed properties
*/
protected willUpdate(changedProps: PropertyValues): void {
const destroyProperties = [
'direction',
'carouselOptions',
'carouselOptions',
] as const;
if (destroyProperties.some((prop) => changedProps.has(prop))) {
this._destroyCarousel();
}
}
/**
* Scroll to a particular slide.
* @param index Slide number.
@@ -193,6 +208,10 @@ export class FrigateCardCarousel extends LitElement {
index: selected,
});
}
// Make sure every select causes a refresh to allow for re-paint of the
// next/previous controls.
this.requestUpdate();
});
}
}
-1
View File
@@ -86,7 +86,6 @@ export class FrigateCardImage extends LitElement {
* Ensure there is a cached value before an update.
* @param _changedProps The changed properties
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
protected willUpdate(changedProps: PropertyValues): void {
if (changedProps.has('imageConfig')) {
if (this._cachedValueController) {
+30 -33
View File
@@ -1,7 +1,7 @@
import JSMpeg from '@cycjimmy/jsmpeg-player';
import { Task } from '@lit-labs/task';
import { HomeAssistant } from 'custom-card-helpers';
import { EmblaOptionsType, EmblaPluginType } from 'embla-carousel';
import { EmblaOptionsType } from 'embla-carousel';
import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures';
import {
CSSResultGroup,
@@ -13,6 +13,7 @@ import {
} from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { createRef, Ref, ref } from 'lit/directives/ref.js';
import { guard } from 'lit/directives/guard.js';
import { until } from 'lit/directives/until.js';
import { ConditionState, getOverriddenConfig } from '../card-condition.js';
import {
@@ -51,12 +52,16 @@ import {
import { View } from '../view.js';
import { AutoMediaPlugin } from './embla-plugins/automedia.js';
import { Lazyload } from './embla-plugins/lazyload.js';
import { FrigateCardMediaCarousel, wrapMediaShowEventForCarousel } from './media-carousel.js';
import {
FrigateCardMediaCarousel,
wrapMediaShowEventForCarousel,
} from './media-carousel.js';
import { dispatchErrorMessageEvent } from './message.js';
import './next-prev-control.js';
import './title-control.js';
import './surround-thumbnails';
import '../patches/ha-camera-stream';
import { EmblaCarouselPlugins } from './carousel.js';
// Number of seconds a signed URL is valid for.
const URL_SIGN_EXPIRY_SECONDS = 24 * 60 * 60;
@@ -241,27 +246,14 @@ export class FrigateCardLiveCarousel extends LitElement {
frigateCardCarousel &&
changedProperties.has('preloaded')
) {
const automedia = frigateCardCarousel.getCarouselPlugins()?.autoMedia;
if (automedia) {
// If this has changed to preloaded (i.e. is now loaded but in the
// background) take the appropriate play/pause/mute/unmute actions.
if (this.preloaded) {
if (
this.liveConfig?.auto_pause &&
['all', 'unselected'].includes(this.liveConfig.auto_pause)
) {
automedia.pause();
}
if (
this.liveConfig?.auto_mute &&
['all', 'unselected'].includes(this.liveConfig.auto_mute)
) {
automedia.mute();
}
} else {
frigateCardMediaCarousel.autoPlay();
frigateCardMediaCarousel.autoUnmute();
}
// If this has changed to preloaded (i.e. is now loaded but in the
// background) take the appropriate play/pause/mute/unmute actions.
if (this.preloaded) {
frigateCardMediaCarousel.autoPause();
frigateCardMediaCarousel.autoMute();
} else {
frigateCardMediaCarousel.autoPlay();
frigateCardMediaCarousel.autoUnmute();
}
}
}
@@ -296,7 +288,7 @@ export class FrigateCardLiveCarousel extends LitElement {
* Get the Embla plugins to use.
* @returns A list of EmblaOptionsTypes.
*/
protected _getPlugins(): EmblaPluginType[] {
protected _getPlugins(): EmblaCarouselPlugins {
return [
// Only enable wheel plugin if there is more than one camera.
...(this.cameras && this.cameras.size > 1
@@ -406,7 +398,7 @@ export class FrigateCardLiveCarousel extends LitElement {
slide: Element,
): void {
if (slide instanceof HTMLSlotElement) {
slide = slide.assignedElements({flatten: true})[0];
slide = slide.assignedElements({ flatten: true })[0];
}
const liveProvider = slide?.querySelector(
@@ -448,7 +440,7 @@ export class FrigateCardLiveCarousel extends LitElement {
.liveConfig=${config}
.hass=${this.hass}
@frigate-card:media-show=${(e: CustomEvent<MediaShowInfo>) => {
wrapMediaShowEventForCarousel(slideIndex, e)
wrapMediaShowEventForCarousel(slideIndex, e);
}}
>
</frigate-card-live-provider>
@@ -498,15 +490,20 @@ export class FrigateCardLiveCarousel extends LitElement {
const [prev, next] = this._getCameraNeighbors();
const title = getCameraTitle(this.hass, this.cameras.get(this.view.camera));
// guard() is used below to avoid reseting the carousel unless the
// options/plugins actually change.
return html`
<frigate-card-media-carousel
${ref(this._refMediaCarousel)}
.carouselOptions=${this._getOptions()}
.carouselPlugins=${this._getPlugins()}
.autoPlayCondition=${this.liveConfig.auto_play}
.autoPauseCondition=${this.liveConfig.auto_pause}
.autoMuteCondition=${this.liveConfig.auto_mute}
.autoUnmuteCondition=${this.liveConfig.auto_unmute}
.carouselOptions=${guard(
[this.cameras, this.liveConfig],
this._getOptions.bind(this),
)}
.carouselPlugins=${guard(
[this.cameras, this.liveConfig],
this._getPlugins.bind(this),
) as EmblaCarouselPlugins}
.label="${title ? `${localize('common.live')}: ${title}` : ''}"
.titlePopupConfig=${config.controls.title}
transitionEffect=${this._getTransitionEffect()}
@@ -548,7 +545,7 @@ export class FrigateCardLiveCarousel extends LitElement {
/**
* Get styles.
*/
static get styles(): CSSResultGroup {
static get styles(): CSSResultGroup {
return unsafeCSS(liveCarouselStyle);
}
}
+32 -34
View File
@@ -1,17 +1,12 @@
// TODO: Use the auto-height plugin instead of adaptive height
import { EmblaOptionsType } from 'embla-carousel';
import { EmblaPluginsType } from 'embla-carousel/components/Plugins';
import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { createRef, ref, Ref } from 'lit/directives/ref.js';
import mediaCarouselStyle from '../scss/media-carousel.scss';
import type {
AutoMuteCondition,
AutoPauseCondition,
AutoPlayCondition,
AutoUnmuteCondition,
MediaShowInfo,
NextPreviousControlConfig,
TitleControlConfig,
@@ -106,18 +101,6 @@ export class FrigateCardMediaCarousel extends LitElement {
@property({ attribute: false })
public titlePopupConfig?: TitleControlConfig;
@property({ attribute: false })
public autoPlayCondition?: AutoPlayCondition;
@property({ attribute: false })
public autoUnmuteCondition?: AutoUnmuteCondition;
@property({ attribute: false })
public autoPauseCondition?: AutoPauseCondition;
@property({ attribute: false })
public autoMuteCondition?: AutoMuteCondition;
// A "map" from slide number to MediaShowInfo object.
protected _mediaShowInfo: Record<number, MediaShowInfo> = {};
protected _nextControlRef: Ref<FrigateCardNextPreviousControl> = createRef();
@@ -126,9 +109,9 @@ export class FrigateCardMediaCarousel extends LitElement {
protected _titleTimerID: number | null = null;
protected _boundAutoPlayHandler = this.autoPlay.bind(this);
protected _boundAutoPauseHandler = this.autoPause.bind(this);
protected _boundAutoMuteHandler = this.autoMute.bind(this);
protected _boundAutoUnmuteHandler = this.autoUnmute.bind(this);
protected _boundAdaptiveHeightHandler = this._adaptiveHeightHandler.bind(this);
protected _boundTitleHandler = this._titleHandler.bind(this);
// This carousel may be resized by Lovelace resizes, window resizes,
// fullscreen, etc. Always call the adaptive height handler when the size
@@ -165,7 +148,11 @@ export class FrigateCardMediaCarousel extends LitElement {
* Play the media on the selected slide.
*/
public autoPlay(): void {
if (this.autoPlayCondition && ['all', 'selected'].includes(this.autoPlayCondition)) {
const automediaOptions = this._getAutoMediaPlugin()?.options;
if (
automediaOptions?.autoPlayCondition &&
['all', 'selected'].includes(automediaOptions?.autoPlayCondition)
) {
this._getAutoMediaPlugin()?.play();
}
}
@@ -174,9 +161,10 @@ export class FrigateCardMediaCarousel extends LitElement {
* Pause the media on the selected slide.
*/
public autoPause(): void {
const automediaOptions = this._getAutoMediaPlugin()?.options;
if (
this.autoPauseCondition &&
['all', 'selected'].includes(this.autoPauseCondition)
automediaOptions?.autoPauseCondition &&
['all', 'selected'].includes(automediaOptions.autoPauseCondition)
) {
this._getAutoMediaPlugin()?.pause();
}
@@ -186,9 +174,10 @@ export class FrigateCardMediaCarousel extends LitElement {
* Unmute the media on the selected slide.
*/
public autoUnmute(): void {
const automediaOptions = this._getAutoMediaPlugin()?.options;
if (
this.autoUnmuteCondition &&
['all', 'selected'].includes(this.autoUnmuteCondition)
automediaOptions?.autoUnmuteCondition &&
['all', 'selected'].includes(automediaOptions?.autoUnmuteCondition)
) {
this._getAutoMediaPlugin()?.unmute();
}
@@ -198,7 +187,11 @@ export class FrigateCardMediaCarousel extends LitElement {
* Mute the media on the selected slide.
*/
public autoMute(): void {
if (this.autoMuteCondition && ['all', 'selected'].includes(this.autoMuteCondition)) {
const automediaOptions = this._getAutoMediaPlugin()?.options;
if (
automediaOptions?.autoMuteCondition &&
['all', 'selected'].includes(automediaOptions?.autoMuteCondition)
) {
this._getAutoMediaPlugin()?.mute();
}
}
@@ -233,10 +226,11 @@ export class FrigateCardMediaCarousel extends LitElement {
*/
connectedCallback(): void {
super.connectedCallback();
this.addEventListener('frigate-card:media-show', this.autoPlay);
this.addEventListener('frigate-card:media-show', this.autoUnmute);
this.addEventListener('frigate-card:media-show', this._adaptiveHeightHandler);
this.addEventListener('frigate-card:media-show', this._titleHandler);
this.addEventListener('frigate-card:media-show', this._boundAutoPlayHandler);
this.addEventListener('frigate-card:media-show', this._boundAutoUnmuteHandler);
this.addEventListener('frigate-card:media-show', this._boundAdaptiveHeightHandler);
this.addEventListener('frigate-card:media-show', this._boundTitleHandler);
this._resizeObserver.observe(this);
this._intersectionObserver.observe(this);
}
@@ -245,13 +239,17 @@ export class FrigateCardMediaCarousel extends LitElement {
* Component disconnected callback.
*/
disconnectedCallback(): void {
super.disconnectedCallback();
this.removeEventListener('frigate-card:media-show', this.autoPlay);
this.removeEventListener('frigate-card:media-show', this.autoUnmute);
this.removeEventListener('frigate-card:media-show', this._adaptiveHeightHandler);
this.removeEventListener('frigate-card:media-show', this._titleHandler);
this.removeEventListener('frigate-card:media-show', this._boundAutoPlayHandler);
this.removeEventListener('frigate-card:media-show', this._boundAutoUnmuteHandler);
this.removeEventListener(
'frigate-card:media-show',
this._boundAdaptiveHeightHandler,
);
this.removeEventListener('frigate-card:media-show', this._boundTitleHandler);
this._resizeObserver.disconnect();
this._intersectionObserver.disconnect();
super.disconnectedCallback();
}
/**
+10 -6
View File
@@ -9,6 +9,7 @@ import {
TemplateResult,
unsafeCSS,
} from 'lit';
import { guard } from 'lit/directives/guard.js';
import { customElement, property } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { createRef, Ref, ref } from 'lit/directives/ref.js';
@@ -54,6 +55,7 @@ import './next-prev-control.js';
import './title-control.js';
import '../patches/ha-hls-player';
import './surround-thumbnails';
import { EmblaCarouselPlugins } from './carousel.js';
@customElement('frigate-card-viewer')
export class FrigateCardViewer extends LitElement {
@@ -603,14 +605,16 @@ export class FrigateCardViewerCarousel extends LitElement {
const neighbors = this._getMediaNeighbors();
const [prev, next] = [neighbors?.previous, neighbors?.next];
// guard() is used below to avoid reseting the carousel unless the
// options/plugins actually change.
return html` <frigate-card-media-carousel
${ref(this._refMediaCarousel)}
.carouselOptions=${this._getOptions()}
.carouselPlugins=${this._getPlugins()}
.autoPlayCondition=${this.viewerConfig?.auto_play}
.autoPauseCondition=${this.viewerConfig?.auto_pause}
.autoMuteCondition=${this.viewerConfig?.auto_mute}
.autoUnmuteCondition=${this.viewerConfig?.auto_unmute}
.carouselOptions=${guard([this.viewerConfig], this._getOptions.bind(this))}
.carouselPlugins=${guard(
[this.viewerConfig, this.view?.target?.children?.length],
this._getPlugins.bind(this),
) as EmblaCarouselPlugins}
.label="${this.view.media.title}"
.titlePopupConfig=${this.viewerConfig?.controls.title}
transitionEffect=${this._getTransitionEffect()}