From 1851a563c0237818feb4b20d4dd30c3f18cb6a49 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 7 Mar 2023 19:27:08 -0800 Subject: [PATCH] Allow views to have no selection. --- src/components/surround.ts | 1 + src/components/timeline-core.ts | 3 +++ src/components/viewer.ts | 12 ++++++++++-- src/utils/media-to-view.ts | 19 +++++++++++++++---- src/view/media-queries-results.ts | 4 +++- 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/components/surround.ts b/src/components/surround.ts index ddfede4d..9fee9c0d 100644 --- a/src/components/surround.ts +++ b/src/components/surround.ts @@ -94,6 +94,7 @@ export class FrigateCardSurround extends LitElement { { targetView: this.view.view, mediaType: this.fetchMedia, + select: 'latest', }, ); } diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index 02520857..8fcd38aa 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -490,6 +490,7 @@ export class FrigateCardTimelineCore extends LitElement { properties.what === 'background' ? properties.time : this._timeline.getWindow().end, + select: 'time', }, ); } @@ -513,6 +514,7 @@ export class FrigateCardTimelineCore extends LitElement { { targetView: 'recording', targetTime: properties.time, + select: 'time', }, ); } @@ -661,6 +663,7 @@ export class FrigateCardTimelineCore extends LitElement { query, { targetView: options?.targetView, + select: 'latest', }, ); if (!view) { diff --git a/src/components/viewer.ts b/src/components/viewer.ts index 1638bd8f..304f6cf3 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -120,6 +120,7 @@ export class FrigateCardViewer extends LitElement { this.view, { targetView: 'recording', + select: 'latest', }, ); } else { @@ -132,6 +133,7 @@ export class FrigateCardViewer extends LitElement { { targetView: 'media', mediaType: mediaType, + select: 'latest', }, ); } @@ -543,13 +545,19 @@ export class FrigateCardViewerCarousel extends LitElement { * @returns A template to display to the user. */ protected _render(): TemplateResult | void { - if ((this.view?.queryResults?.getResultsCount() ?? 0) === 0) { + const resultCount = this.view?.queryResults?.getResultsCount() ?? 0; + if (!resultCount) { return dispatchMessageEvent(this, localize('common.no_media'), 'info', { icon: 'mdi:multimedia', }); } - const media = this.view?.queryResults?.getSelectedResult(); + // If there's no selected media, just choose the last (most recent one) to + // avoid rendering a blank. This situation should not occur in practice, as + // this view should not be called without a selected media. + const media = + this.view?.queryResults?.getSelectedResult() ?? + this.view?.queryResults?.getResult(resultCount - 1); if (!media || !this.view || !this.view.queryResults) { return; } diff --git a/src/utils/media-to-view.ts b/src/utils/media-to-view.ts index e93ea145..274875e2 100644 --- a/src/utils/media-to-view.ts +++ b/src/utils/media-to-view.ts @@ -16,6 +16,8 @@ import { errorToConsole } from './basic'; import { MediaQuery } from '../camera-manager/types'; import { MEDIA_CHUNK_SIZE_DEFAULT } from '../const'; +type ResultSelectType = 'latest' | 'time' | 'none'; + export const changeViewToRecentEventsForCameraAndDependents = async ( element: HTMLElement, hass: HomeAssistant, @@ -25,6 +27,7 @@ export const changeViewToRecentEventsForCameraAndDependents = async ( options?: { mediaType?: ClipsOrSnapshotsOrAll; targetView?: FrigateCardView; + select?: ResultSelectType; }, ): Promise => { const cameraIDs = getAllDependentCameras(cameraManager, view.camera); @@ -42,6 +45,7 @@ export const changeViewToRecentEventsForCameraAndDependents = async ( ( await executeMediaQueryForView(element, hass, cameraManager, view, queries, { targetView: options?.targetView, + select: options?.select, }) )?.dispatchChangeEvent(element); }; @@ -81,6 +85,7 @@ export const changeViewToRecentRecordingForCameraAndDependents = async ( view: View, options?: { targetView?: 'recording' | 'recordings'; + select?: ResultSelectType; }, ): Promise => { const cameraIDs = getAllDependentCameras(cameraManager, view.camera); @@ -100,6 +105,7 @@ export const changeViewToRecentRecordingForCameraAndDependents = async ( ( await executeMediaQueryForView(element, hass, cameraManager, view, queries, { targetView: options?.targetView, + select: options?.select, }) )?.dispatchChangeEvent(element); }; @@ -133,6 +139,7 @@ export const executeMediaQueryForView = async ( targetCameraID?: string; targetView?: FrigateCardView; targetTime?: Date; + select?: ResultSelectType; }, ): Promise => { let mediaArray: ViewMedia[] | null; @@ -153,12 +160,16 @@ export const executeMediaQueryForView = async ( if (!mediaArray) { return null; } - // 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); + + const queryResults = new MediaQueriesResults( + mediaArray, + options?.select === 'latest' && mediaArray.length + ? mediaArray.length - 1 + : undefined, + ); let viewerContext: ViewContext | undefined = {}; - if (options?.targetTime) { + if (options?.select === 'time' && options?.targetTime) { queryResults.selectBestResult((media) => findClosestMediaIndex(media, options.targetTime as Date), ); diff --git a/src/view/media-queries-results.ts b/src/view/media-queries-results.ts index 318ae794..e0d9f5d4 100644 --- a/src/view/media-queries-results.ts +++ b/src/view/media-queries-results.ts @@ -11,7 +11,9 @@ export class MediaQueriesResults { if (results) { this.setResults(results); } - this.selectResult(selectedIndex ?? 0); + if (selectedIndex !== undefined) { + this.selectResult(selectedIndex); + } } public clone(): MediaQueriesResults {