Match media direction to timeline.
This commit is contained in:
+1
-1
@@ -26,7 +26,7 @@
|
||||
"custom-card-helpers": "^1.9.0",
|
||||
"date-fns": "^2.29.2",
|
||||
"date-fns-tz": "^1.3.7",
|
||||
"embla-carousel": "^7.0.2",
|
||||
"embla-carousel": "^7.0.9",
|
||||
"embla-carousel-wheel-gestures": "^3.0.0",
|
||||
"home-assistant-js-websocket": "^8.0.0",
|
||||
"keycharm": "^0.4.0",
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { HomeAssistant } from 'custom-card-helpers';
|
||||
import fromUnixTime from 'date-fns/fromUnixTime';
|
||||
import isEqual from 'lodash-es/isEqual';
|
||||
import { CameraConfig } from '../../types';
|
||||
|
||||
@@ -525,9 +525,10 @@ export class CameraManager {
|
||||
// are assumed to be unique.
|
||||
uniqBy(mediaArray, (media) => media.getID() ?? media),
|
||||
|
||||
// Sort all items leading with the most recent.
|
||||
// Sort all items leading oldest -> youngest (so media is loaded in this
|
||||
// order in the viewer which matches the left-to-right timeline order).
|
||||
(media) => media.getStartTime(),
|
||||
'desc',
|
||||
'asc',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import { MediaQueriesResults } from '../view/media-queries-results';
|
||||
import { errorToConsole } from '../utils/basic';
|
||||
import './media-filter';
|
||||
import "./surround-basic";
|
||||
import { ViewMedia } from '../view/media';
|
||||
|
||||
const GALLERY_MEDIA_CHUNK_SIZE = 100;
|
||||
|
||||
@@ -181,6 +182,8 @@ export class FrigateCardGalleryCore extends LitElement {
|
||||
@state()
|
||||
protected _showExtensionLoader = true;
|
||||
|
||||
protected _media?: ViewMedia[];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._resizeObserver = new ResizeObserver(this._resizeHandler.bind(this));
|
||||
@@ -307,6 +310,14 @@ export class FrigateCardGalleryCore extends LitElement {
|
||||
}
|
||||
if (changedProps.has('view')) {
|
||||
this._showExtensionLoader = true;
|
||||
const oldView: View | undefined = changedProps.get('view');
|
||||
|
||||
if (oldView?.queryResults?.getResults() !== this.view?.queryResults?.getResults()) {
|
||||
// Gallery places the most recent media at the top (the query results place
|
||||
// the most recent media at the end for use in the viewer). This is copied
|
||||
// to a new array to avoid reversing the query results in place.
|
||||
this._media = [...this.view?.queryResults?.getResults() ?? []].reverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,10 +326,8 @@ export class FrigateCardGalleryCore extends LitElement {
|
||||
* @returns A rendered template.
|
||||
*/
|
||||
protected render(): TemplateResult | void {
|
||||
const results = this.view?.queryResults?.getResults();
|
||||
|
||||
if (
|
||||
!results ||
|
||||
!this._media ||
|
||||
!this.hass ||
|
||||
!this.view ||
|
||||
!this.view.isGalleryView() ||
|
||||
@@ -328,7 +337,7 @@ export class FrigateCardGalleryCore extends LitElement {
|
||||
}
|
||||
|
||||
return html`
|
||||
${results.map(
|
||||
${this._media.map(
|
||||
(media, index) =>
|
||||
html`<frigate-card-thumbnail
|
||||
.hass=${this.hass}
|
||||
@@ -342,11 +351,15 @@ export class FrigateCardGalleryCore extends LitElement {
|
||||
?show_timeline_control=${!!this.galleryConfig?.controls.thumbnails
|
||||
.show_timeline_control}
|
||||
@click=${(ev: Event) => {
|
||||
if (this.view) {
|
||||
if (this.view && this._media) {
|
||||
this.view
|
||||
.evolve({
|
||||
view: 'media',
|
||||
queryResults: this.view.queryResults?.clone().selectResult(index),
|
||||
queryResults: this.view.queryResults?.clone().selectResult(
|
||||
// Media in the gallery is reversed vs the queryResults (see
|
||||
// note above).
|
||||
this._media.length - index - 1
|
||||
),
|
||||
})
|
||||
.dispatchChangeEvent(this);
|
||||
}
|
||||
|
||||
@@ -402,18 +402,23 @@ export class FrigateCardViewerCarousel extends LitElement {
|
||||
.dispatchChangeEvent(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the user selecting a new slide in the carousel.
|
||||
*/
|
||||
protected _setViewHandler(ev: CustomEvent<CarouselSelect>): void {
|
||||
// The slide may already be selected on load, so don't dispatch a new view
|
||||
// unless necessary.
|
||||
if (ev.detail.index !== this.view?.queryResults?.getSelectedIndex()) {
|
||||
this._setViewSelectedIndex(ev.detail.index);
|
||||
}
|
||||
}
|
||||
|
||||
protected _setViewSelectedIndex(index: number): void {
|
||||
if (!this.view?.queryResults) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedIndex = this.view.queryResults.getSelectedIndex();
|
||||
if (selectedIndex === null || selectedIndex === index) {
|
||||
// The slide may already be selected on load, so don't dispatch a new view
|
||||
// unless necessary (i.e. the new index is different from the current
|
||||
// index).
|
||||
return;
|
||||
}
|
||||
|
||||
const newResults = this.view?.queryResults?.clone().selectResult(index);
|
||||
if (!newResults) {
|
||||
return;
|
||||
@@ -555,7 +560,7 @@ export class FrigateCardViewerCarousel extends LitElement {
|
||||
}
|
||||
|
||||
const media = this.view?.queryResults?.getSelectedResult();
|
||||
if (!media || !this.cameras) {
|
||||
if (!media || !this.cameras || !this.view || !this.view.queryResults) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -578,7 +583,7 @@ export class FrigateCardViewerCarousel extends LitElement {
|
||||
draggable: this.viewerConfig?.draggable ?? true,
|
||||
}))}
|
||||
.carouselPlugins=${guard(
|
||||
[this.viewerConfig, this.view?.queryResults?.getResults()],
|
||||
[this.viewerConfig, this.view.queryResults.getResults()],
|
||||
this._getPlugins.bind(this),
|
||||
)}
|
||||
.label=${media.getTitle() ?? undefined}
|
||||
|
||||
@@ -198,8 +198,9 @@ const executeMediaQueryForView = async (
|
||||
if (!mediaArray) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const queryResults = new MediaQueriesResults(mediaArray);
|
||||
// Select the last item by default (which is the most recent).
|
||||
const selectedIndex = mediaArray.length ? mediaArray.length - 1 : undefined;
|
||||
const queryResults = new MediaQueriesResults(mediaArray, selectedIndex);
|
||||
let viewerContext: ViewContext | undefined = {};
|
||||
|
||||
if (options?.targetTime && options.cameraIDs) {
|
||||
|
||||
@@ -132,12 +132,13 @@ export class TimelineDataSource {
|
||||
}
|
||||
|
||||
const mediaArray = await this._cameraManager.executeMediaQueries(hass, eventQueries);
|
||||
const data: FrigateCardTimelineItem[] = []
|
||||
for (const media of mediaArray ?? []) {
|
||||
const endTime = media.getEndTime();
|
||||
const startTime = media.getStartTime();
|
||||
const id = media.getID();
|
||||
if (id && startTime) {
|
||||
this._dataset.update({
|
||||
data.push({
|
||||
id: id,
|
||||
group: media.getCameraID(),
|
||||
content: '',
|
||||
@@ -148,6 +149,7 @@ export class TimelineDataSource {
|
||||
});
|
||||
}
|
||||
}
|
||||
this._dataset.update(data);
|
||||
|
||||
this._eventRanges.add({
|
||||
...cacheFriendlyWindow,
|
||||
|
||||
@@ -1858,7 +1858,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"embla-carousel@npm:^7.0.2":
|
||||
"embla-carousel@npm:^7.0.9":
|
||||
version: 7.0.9
|
||||
resolution: "embla-carousel@npm:7.0.9"
|
||||
checksum: dabb371a44c2d67f21aa7a0ff3f452a5c2678b79e80cb251e0a83b707c4b684fbdbe010927142cdcae3d1c9711a269e05655bd05c39608337fd1b6f5d2c20371
|
||||
@@ -2424,7 +2424,7 @@ __metadata:
|
||||
custom-card-helpers: ^1.9.0
|
||||
date-fns: ^2.29.2
|
||||
date-fns-tz: ^1.3.7
|
||||
embla-carousel: ^7.0.2
|
||||
embla-carousel: ^7.0.9
|
||||
embla-carousel-wheel-gestures: ^3.0.0
|
||||
eslint: ^8.23.0
|
||||
eslint-config-airbnb-base: ^15.0.0
|
||||
|
||||
Reference in New Issue
Block a user