fix: Fix folder media in timeline when camera is not timeline supported (#2246)
- Closes: #2205
This commit is contained in:
+33
-24
@@ -9,11 +9,14 @@ import {
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import { CameraManager } from '../camera-manager/manager.js';
|
||||
import { FoldersManager } from '../card-controller/folders/manager.js';
|
||||
import { ViewItemManager } from '../card-controller/view/item-manager.js';
|
||||
import { ViewManagerEpoch } from '../card-controller/view/types.js';
|
||||
import { TimelineKey } from '../components-lib/timeline/types.js';
|
||||
import { TimelineKeys } from '../components-lib/timeline/types.js';
|
||||
import { ConditionStateManagerReadonlyInterface } from '../conditions/types.js';
|
||||
import { ThumbnailsControlConfig } from '../config/schema/common/controls/thumbnails.js';
|
||||
import { MiniTimelineControlConfig } from '../config/schema/common/controls/timeline.js';
|
||||
import { FolderConfig } from '../config/schema/folders.js';
|
||||
import { CardWideConfig } from '../config/schema/types.js';
|
||||
import { HomeAssistant } from '../ha/types.js';
|
||||
import basicBlockStyle from '../scss/basic-block.scss';
|
||||
@@ -40,13 +43,19 @@ export class AdvancedCameraCardSurround extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public cameraManager?: CameraManager;
|
||||
|
||||
@property({ attribute: false })
|
||||
public foldersManager?: FoldersManager;
|
||||
|
||||
@property({ attribute: false })
|
||||
public conditionStateManager?: ConditionStateManagerReadonlyInterface;
|
||||
|
||||
@property({ attribute: false })
|
||||
public viewItemManager?: ViewItemManager;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cardWideConfig?: CardWideConfig;
|
||||
|
||||
protected _keysForTimeline?: TimelineKey[] = [];
|
||||
protected _timelineKeys?: TimelineKeys | null = null;
|
||||
|
||||
/**
|
||||
* Determine if a drawer is being used.
|
||||
@@ -74,24 +83,29 @@ export class AdvancedCameraCardSurround extends LitElement {
|
||||
) ||
|
||||
this.viewManagerEpoch?.oldView?.displayMode !== view?.displayMode)
|
||||
) {
|
||||
const newKeys = this._getKeysForTimeline();
|
||||
const newKeys = this._getTimelineKeys();
|
||||
// Update only if changed, to avoid unnecessary timeline destructions.
|
||||
if (!isEqual(newKeys, this._keysForTimeline)) {
|
||||
this._keysForTimeline = newKeys ?? undefined;
|
||||
if (!isEqual(newKeys, this._timelineKeys)) {
|
||||
this._timelineKeys = newKeys ?? undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected _getKeysForTimeline(): TimelineKey[] | null {
|
||||
const cameraIDsToKeys = (cameraIDs: Set<string> | null): TimelineKey[] => {
|
||||
const keys: TimelineKey[] = [];
|
||||
for (const cameraID of cameraIDs ?? []) {
|
||||
keys.push({
|
||||
type: 'camera',
|
||||
cameraID: cameraID,
|
||||
});
|
||||
}
|
||||
return keys;
|
||||
protected _getTimelineKeys(): TimelineKeys | null {
|
||||
const cameraIDsToKeys = (cameraIDs: Set<string> | null): TimelineKeys | null => {
|
||||
return cameraIDs?.size
|
||||
? {
|
||||
type: 'camera',
|
||||
cameraIDs,
|
||||
}
|
||||
: null;
|
||||
};
|
||||
|
||||
const folderToKeys = (folderConfig: FolderConfig): TimelineKeys => {
|
||||
return {
|
||||
type: 'folder',
|
||||
folder: folderConfig,
|
||||
};
|
||||
};
|
||||
|
||||
const view = this.viewManagerEpoch?.manager.getView();
|
||||
@@ -122,14 +136,7 @@ export class AdvancedCameraCardSurround extends LitElement {
|
||||
return cameraIDsToKeys(queries.getQueryCameraIDs());
|
||||
} else if (QueryClassifier.isFolderQuery(queries)) {
|
||||
const folderConfig = queries.getQuery()?.folder;
|
||||
return folderConfig
|
||||
? [
|
||||
{
|
||||
type: 'folder' as const,
|
||||
folder: folderConfig,
|
||||
},
|
||||
]
|
||||
: [];
|
||||
return folderConfig ? folderToKeys(folderConfig) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,11 +189,13 @@ export class AdvancedCameraCardSurround extends LitElement {
|
||||
this.thumbnailConfig?.mode === 'none'
|
||||
? 'play'
|
||||
: 'select'}
|
||||
.keys=${this._keysForTimeline}
|
||||
.keys=${this._timelineKeys}
|
||||
.mini=${true}
|
||||
.timelineConfig=${this.timelineConfig}
|
||||
.thumbnailConfig=${this.thumbnailConfig}
|
||||
.cameraManager=${this.cameraManager}
|
||||
.foldersManager=${this.foldersManager}
|
||||
.conditionStateManager=${this.conditionStateManager}
|
||||
.viewItemManager=${this.viewItemManager}
|
||||
.cardWideConfig=${this.cardWideConfig}
|
||||
>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { customElement, property } from 'lit/decorators.js';
|
||||
import { Ref, createRef, ref } from 'lit/directives/ref.js';
|
||||
import type { IdType } from 'vis-timeline/esnext';
|
||||
import { CameraManager } from '../camera-manager/manager';
|
||||
import { FoldersManager } from '../card-controller/folders/manager';
|
||||
import { ViewItemManager } from '../card-controller/view/item-manager';
|
||||
import { ViewManagerEpoch } from '../card-controller/view/types';
|
||||
import { TimelineController } from '../components-lib/timeline/controller';
|
||||
@@ -17,8 +18,9 @@ import {
|
||||
ThumbnailDataRequest,
|
||||
ThumbnailDataRequestEvent,
|
||||
TimelineItemClickAction,
|
||||
TimelineKey,
|
||||
TimelineKeys,
|
||||
} from '../components-lib/timeline/types';
|
||||
import { ConditionStateManagerReadonlyInterface } from '../conditions/types';
|
||||
import { ThumbnailsControlBaseConfig } from '../config/schema/common/controls/thumbnails';
|
||||
import { TimelineCoreConfig } from '../config/schema/common/controls/timeline';
|
||||
import { CardWideConfig } from '../config/schema/types';
|
||||
@@ -121,11 +123,17 @@ export class AdvancedCameraCardTimelineCore extends LitElement {
|
||||
// Which cameraIDs to include in the timeline. If not specified, all cameraIDs
|
||||
// are shown.
|
||||
@property({ attribute: false, hasChanged: contentsChanged })
|
||||
public keys: TimelineKey[] = [];
|
||||
public keys?: TimelineKeys;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cameraManager?: CameraManager;
|
||||
|
||||
@property({ attribute: false })
|
||||
public foldersManager?: FoldersManager;
|
||||
|
||||
@property({ attribute: false })
|
||||
public conditionStateManager?: ConditionStateManagerReadonlyInterface;
|
||||
|
||||
@property({ attribute: false })
|
||||
public viewItemManager?: ViewItemManager;
|
||||
|
||||
@@ -144,7 +152,7 @@ export class AdvancedCameraCardTimelineCore extends LitElement {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.keys.length) {
|
||||
if (!this.keys) {
|
||||
if (!this.mini) {
|
||||
return renderMessage({
|
||||
message: localize('error.no_camera_or_media_for_timeline'),
|
||||
@@ -228,20 +236,22 @@ export class AdvancedCameraCardTimelineCore extends LitElement {
|
||||
[
|
||||
'cameraManager',
|
||||
'viewItemManager',
|
||||
'viewManagerEpoch',
|
||||
'timelineConfig',
|
||||
'mini',
|
||||
'thumbnailConfig',
|
||||
'keys',
|
||||
'conditionStateManager',
|
||||
].some((prop) => changedProps.has(prop))
|
||||
) {
|
||||
this._controller.setOptions({
|
||||
cameraManager: this.cameraManager,
|
||||
foldersManager: this.foldersManager,
|
||||
viewItemManager: this.viewItemManager,
|
||||
conditionStateManager: this.conditionStateManager,
|
||||
timelineConfig: this.timelineConfig,
|
||||
mini: this.mini,
|
||||
thumbnailConfig: this.thumbnailConfig,
|
||||
keys: this.keys ?? [],
|
||||
keys: this.keys,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+35
-15
@@ -1,9 +1,11 @@
|
||||
import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { CameraManager } from '../camera-manager/manager';
|
||||
import { FoldersManager } from '../card-controller/folders/manager';
|
||||
import { ViewItemManager } from '../card-controller/view/item-manager';
|
||||
import { ViewManagerEpoch } from '../card-controller/view/types';
|
||||
import { TimelineKey } from '../components-lib/timeline/types';
|
||||
import { TimelineKeys } from '../components-lib/timeline/types';
|
||||
import { ConditionStateManagerReadonlyInterface } from '../conditions/types';
|
||||
import { TimelineConfig } from '../config/schema/timeline';
|
||||
import { CardWideConfig } from '../config/schema/types';
|
||||
import { HomeAssistant } from '../ha/types';
|
||||
@@ -26,41 +28,57 @@ export class AdvancedCameraCardTimeline extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public cameraManager?: CameraManager;
|
||||
|
||||
@property({ attribute: false })
|
||||
public foldersManager?: FoldersManager;
|
||||
|
||||
@property({ attribute: false })
|
||||
public conditionStateManager?: ConditionStateManagerReadonlyInterface;
|
||||
|
||||
@property({ attribute: false })
|
||||
public viewItemManager?: ViewItemManager;
|
||||
|
||||
@property({ attribute: false })
|
||||
public cardWideConfig?: CardWideConfig;
|
||||
|
||||
protected _getKeys(): TimelineKey[] {
|
||||
protected _getKeys(): TimelineKeys | undefined {
|
||||
const query = this.viewManagerEpoch?.manager.getView()?.query;
|
||||
|
||||
// If there's a query, try to extract camera IDs or folder info from it.
|
||||
if (QueryClassifier.isMediaQuery(query)) {
|
||||
const cameraIDs = query.getQueryCameraIDs();
|
||||
if (cameraIDs && cameraIDs.size) {
|
||||
return [...cameraIDs].map((cameraID) => ({ type: 'camera', cameraID }));
|
||||
return {
|
||||
type: 'camera',
|
||||
cameraIDs,
|
||||
};
|
||||
}
|
||||
} else if (QueryClassifier.isFolderQuery(query)) {
|
||||
const folderConfig = query.getQuery()?.folder;
|
||||
if (folderConfig) {
|
||||
return [
|
||||
{
|
||||
type: 'folder' as const,
|
||||
folder: folderConfig,
|
||||
},
|
||||
];
|
||||
return {
|
||||
type: 'folder',
|
||||
folder: folderConfig,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise fall back to all cameras that support media queries.
|
||||
const keys: TimelineKey[] = [];
|
||||
for (const camera of this.cameraManager?.getStore().getCameraIDsWithCapability({
|
||||
const cameraIDs = this.cameraManager?.getStore().getCameraIDsWithCapability({
|
||||
anyCapabilities: ['clips', 'snapshots', 'recordings'],
|
||||
}) ?? []) {
|
||||
keys.push({ type: 'camera', cameraID: camera });
|
||||
}
|
||||
return keys;
|
||||
});
|
||||
const folder = this.foldersManager?.getFolder() ?? null;
|
||||
|
||||
return cameraIDs?.size
|
||||
? {
|
||||
type: 'camera',
|
||||
cameraIDs,
|
||||
}
|
||||
: folder
|
||||
? {
|
||||
type: 'folder',
|
||||
folder,
|
||||
}
|
||||
: undefined;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
@@ -75,6 +93,8 @@ export class AdvancedCameraCardTimeline extends LitElement {
|
||||
.timelineConfig=${this.timelineConfig}
|
||||
.thumbnailConfig=${this.timelineConfig.controls.thumbnails}
|
||||
.cameraManager=${this.cameraManager}
|
||||
.foldersManager=${this.foldersManager}
|
||||
.conditionStateManager=${this.conditionStateManager}
|
||||
.viewItemManager=${this.viewItemManager}
|
||||
.keys=${this._getKeys()}
|
||||
.cardWideConfig=${this.cardWideConfig}
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { CameraManager } from '../camera-manager/manager.js';
|
||||
import { FoldersManager } from '../card-controller/folders/manager.js';
|
||||
import { MicrophoneState } from '../card-controller/types.js';
|
||||
import { ViewItemManager } from '../card-controller/view/item-manager.js';
|
||||
import { ViewManagerEpoch } from '../card-controller/view/types.js';
|
||||
@@ -36,6 +37,9 @@ export class AdvancedCameraCardViews extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public cameraManager?: CameraManager;
|
||||
|
||||
@property({ attribute: false })
|
||||
public foldersManager?: FoldersManager;
|
||||
|
||||
@property({ attribute: false })
|
||||
public viewItemManager?: ViewItemManager;
|
||||
|
||||
@@ -148,6 +152,8 @@ export class AdvancedCameraCardViews extends LitElement {
|
||||
.thumbnailConfig=${!this.hide ? thumbnailConfig : undefined}
|
||||
.timelineConfig=${!this.hide ? miniTimelineConfig : undefined}
|
||||
.cameraManager=${this.cameraManager}
|
||||
.foldersManager=${this.foldersManager}
|
||||
.conditionStateManager=${this.conditionStateManager}
|
||||
.viewItemManager=${this.viewItemManager}
|
||||
.cardWideConfig=${this.cardWideConfig}
|
||||
>
|
||||
@@ -191,6 +197,8 @@ export class AdvancedCameraCardViews extends LitElement {
|
||||
.viewManagerEpoch=${this.viewManagerEpoch}
|
||||
.timelineConfig=${this.config.timeline}
|
||||
.cameraManager=${this.cameraManager}
|
||||
.conditionStateManager=${this.conditionStateManager}
|
||||
.foldersManager=${this.foldersManager}
|
||||
.viewItemManager=${this.viewItemManager}
|
||||
.cardWideConfig=${this.cardWideConfig}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user