From 30e7ee04bffca6bd6fc01872d7e1c9d7af055626 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Wed, 27 Jul 2022 21:03:10 -0700 Subject: [PATCH] Fix carousel forgetting its position in certain circumstances. --- src/components/carousel.ts | 34 +++++++++++++++++++++++----------- src/components/live.ts | 3 +-- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/components/carousel.ts b/src/components/carousel.ts index 175f6af1..4a018780 100644 --- a/src/components/carousel.ts +++ b/src/components/carousel.ts @@ -44,6 +44,12 @@ export class FrigateCardCarousel extends LitElement { @property({ attribute: true }) public transitionEffect?: TransitionEffect; + // An override to the startIndex, used to preserve the current carousel + // position after the carousel is destroyed (so it can be restored if + // recreated). + // See: https://github.com/dermotduffy/frigate-hass-card/issues/775 + protected _savedStartIndex: number | null = null; + protected _refSlot: Ref = createRef(); protected _carousel?: EmblaCarouselType; @@ -75,7 +81,7 @@ export class FrigateCardCarousel extends LitElement { // Destroy the carousel when the component is disconnected, which forces the // plugins (which may have registered event handlers) to also be destroyed. // The carousel will automatically reconstruct if the component is re-rendered. - this._destroyCarousel(); + this._destroyCarousel({ savePosition: true }); super.disconnectedCallback(); } @@ -90,7 +96,7 @@ export class FrigateCardCarousel extends LitElement { 'carouselPlugins', ] as const; if (destroyProperties.some((prop) => changedProps.has(prop))) { - this._destroyCarousel(); + this._destroyCarousel({ savePosition: true }); } } @@ -196,16 +202,18 @@ export class FrigateCardCarousel extends LitElement { super.updated(changedProperties); if (!this._carousel) { - this.updateComplete.then(() => { - // Re-check for the carousel to prevent a double init. - if (!this._carousel) { - this._initCarousel(); - } - }); + this._initCarousel(); } } - protected _destroyCarousel(): void { + /** + * Destroy the carousel. + * @param options If `savePosition` is set the existing carousel position + * will be saved so it can be restored if the carousel is recreated. + */ + protected _destroyCarousel(options?: { savePosition: boolean }): void { + this._savedStartIndex = + (options?.savePosition ? this._carousel?.selectedScrollSnap() : null) ?? null; if (this._carousel) { this._carousel.destroy(); } @@ -234,6 +242,7 @@ export class FrigateCardCarousel extends LitElement { axis: this.direction == 'horizontal' ? 'x' : 'y', speed: 20, ...this.carouselOptions, + ...(this._savedStartIndex && { startIndex: this._savedStartIndex }), }, this.carouselPlugins, ); @@ -276,8 +285,11 @@ export class FrigateCardCarousel extends LitElement { */ protected _slotChanged(): void { // Cannot just re-init, because the slide elements themselves may have - // changed, and only a carousel init can pass in new (slotted) children. - this._destroyCarousel(); + // changed, and only a carousel init can pass in new (slotted) children. If + // the slides themselves change, any position the user has set is assumed to + // be abandoned and so the startIndex is reset to whatever the carousel was + // originally configured with. + this._destroyCarousel({ savePosition: false }); this.requestUpdate(); } diff --git a/src/components/live.ts b/src/components/live.ts index d2d77d64..6ab3af26 100644 --- a/src/components/live.ts +++ b/src/components/live.ts @@ -284,9 +284,8 @@ export class FrigateCardLiveCarousel extends LitElement { const oldView = changedProperties.get('view') as View | undefined; if ( frigateCardCarousel && - oldView && this.view?.camera && - this.view?.camera != oldView.camera + (!oldView || this.view?.camera !== oldView.camera) ) { const slide: number | undefined = this._cameraToSlide[this.view.camera]; if (