From 214a553aa7cbc7aa41ff216bdc5c220cfa68fab4 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 10 Jul 2022 20:05:18 -0700 Subject: [PATCH] Reset the carousel of the plugins/options change. --- src/components/carousel.ts | 19 +++++++++ src/components/image.ts | 1 - src/components/live.ts | 63 +++++++++++++++--------------- src/components/media-carousel.ts | 66 ++++++++++++++++---------------- src/components/viewer.ts | 16 +++++--- 5 files changed, 91 insertions(+), 74 deletions(-) diff --git a/src/components/carousel.ts b/src/components/carousel.ts index 024a0144..0e3a697a 100644 --- a/src/components/carousel.ts +++ b/src/components/carousel.ts @@ -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(); }); } } diff --git a/src/components/image.ts b/src/components/image.ts index ba21b97e..a37f5ddd 100644 --- a/src/components/image.ts +++ b/src/components/image.ts @@ -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) { diff --git a/src/components/live.ts b/src/components/live.ts index 23ec5fb1..2445190a 100644 --- a/src/components/live.ts +++ b/src/components/live.ts @@ -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) => { - wrapMediaShowEventForCarousel(slideIndex, e) + wrapMediaShowEventForCarousel(slideIndex, e); }} > @@ -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` = {}; protected _nextControlRef: Ref = 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(); } /** diff --git a/src/components/viewer.ts b/src/components/viewer.ts index 1f96beee..8a296d84 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -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`