From df93e572a25f051a8e59eb8fee938097bb04e31e Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 29 Jan 2022 17:17:56 -0800 Subject: [PATCH] Add option to choose view for newly selected cameras. --- README.md | 3 +- src/card.ts | 11 +-- src/const.ts | 1 + src/editor.ts | 172 +++++++++++++++++---------------- src/localize/languages/en.json | 4 +- src/types.ts | 9 +- 6 files changed, 105 insertions(+), 95 deletions(-) diff --git a/README.md b/README.md index a81fd506..570140bd 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ view: | Option | Default | Overridable | Description | | - | - | - | - | | `default` | `live` | :heavy_multiplication_x: | The view to show in the card by default. See [views](#views) below.| +| `camera_select` | `current` | :heavy_multiplication_x: | The view to show when a new camera is selected (e.g. in the camera menu). If `current` the view is unchanged when a new camera is selected. Other acceptable values may be seen at [views](#views) below.| | `timeout_seconds` | `300` | :heavy_multiplication_x: | A numbers of seconds of inactivity after user interaction, after which the card will reset to the default configured view (i.e. 'screensaver' functionality). Inactivity is defined as lack of mouse/touch interaction with the Frigate card. If the default view occurs sooner (e.g. via `update_seconds` or manually) the timer will be stopped. `0` means disable this functionality. | | `update_seconds` | `0` | :heavy_multiplication_x: | A number of seconds after which to automatically update/refresh the default view. See [card updates](#card-updates) below for behavior and usecases. If the default view occurs sooner (e.g. manually) the timer will start over. `0` disables this functionality.| | `update_force` | `false` | :heavy_multiplication_x: | Whether automated card updates/refreshes should ignore user interaction. See [card updates](#card-updates) below for behavior and usecases.| @@ -564,7 +565,7 @@ Parameters for the `custom:frigate-card-conditional` element: |`download`|Download the displayed media.| |`frigate_ui`|Open the Frigate UI at the configured URL.| |`fullscreen`|Toggle fullscreen.| -|`camera_select`|Select a given camera. Takes a single additional `camera` parameter with the [camera ID](#camera-ids) of the camera to select.| +|`camera_select`|Select a given camera. Takes a single additional `camera` parameter with the [camera ID](#camera-ids) of the camera to select. Respects the value of `view.camera_select` to choose the appropriate view on the new camera.| |`menu_toggle` | Show/hide the menu (for `hidden-*` mode menus). | diff --git a/src/card.ts b/src/card.ts index d6743a36..645096c6 100644 --- a/src/card.ts +++ b/src/card.ts @@ -10,11 +10,7 @@ import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { StyleInfo, styleMap } from 'lit/directives/style-map.js'; import { until } from 'lit/directives/until.js'; -import { - HomeAssistant, - LovelaceCardEditor, - getLovelace, -} from 'custom-card-helpers'; +import { HomeAssistant, LovelaceCardEditor, getLovelace } from 'custom-card-helpers'; import screenfull from 'screenfull'; import { z } from 'zod'; @@ -22,6 +18,7 @@ import { Actions, ActionType, CameraConfig, + FrigateCardView, RawFrigateCardConfig, entitySchema, frigateCardConfigSchema, @@ -826,7 +823,9 @@ export class FrigateCard extends LitElement { if (this._cameras?.has(camera) && this._view) { this._changeView({ view: new View({ - view: this._view.view, + view: this._getConfig().view.camera_select === 'current' + ? this._view.view + : this._getConfig().view.camera_select as FrigateCardView, camera: camera, }), }); diff --git a/src/const.ts b/src/const.ts index 876017be..8bf81f9a 100644 --- a/src/const.ts +++ b/src/const.ts @@ -19,6 +19,7 @@ export const CONF_CAMERAS_ARRAY_WEBRTC_URL = `${CONF_CAMERAS}.#.webrtc.url` as c export const CONF_CAMERAS_ARRAY_LIVE_PROVIDER = `${CONF_CAMERAS}.#.live_provider` as const; export const CONF_VIEW = 'view' as const; +export const CONF_VIEW_CAMERA_SELECT = `${CONF_VIEW}.camera_select` as const; export const CONF_VIEW_DEFAULT = `${CONF_VIEW}.default` as const; export const CONF_VIEW_TIMEOUT_SECONDS = `${CONF_VIEW}.timeout_seconds` as const; export const CONF_VIEW_UPDATE_CYCLE_CAMERA = `${CONF_VIEW}.update_cycle_camera` as const; diff --git a/src/editor.ts b/src/editor.ts index 40bac4aa..99be0a36 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -56,6 +56,7 @@ import { CONF_MENU_BUTTONS_SNAPSHOTS, CONF_MENU_BUTTON_SIZE, CONF_MENU_MODE, + CONF_VIEW_CAMERA_SELECT, CONF_VIEW_DEFAULT, CONF_VIEW_TIMEOUT_SECONDS, CONF_VIEW_UPDATE_CYCLE_CAMERA, @@ -238,12 +239,12 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor */ protected _renderDropdown( configPath: string, - dropdown: string[] | Record, + dropdown: string[] | Map, ): TemplateResult | void { if (!this._config) { return; } - const keys = Array.isArray(dropdown) ? dropdown : Object.keys(dropdown); + const keys = Array.isArray(dropdown) ? dropdown : [...dropdown.keys()]; return html` ${keys.map( (key) => html` - ${Array.isArray(dropdown) ? key : dropdown[key]} + ${Array.isArray(dropdown) ? key : dropdown.get(key)} `, )} @@ -357,13 +358,13 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor cameraEntities: string[], addNewCamera?: boolean, ): TemplateResult | void { - const liveProviders = { - '': '', - auto: localize('config.cameras.live_providers.auto'), - frigate: localize('config.cameras.live_providers.frigate'), - 'frigate-jsmpeg': localize('config.cameras.live_providers.frigate-jsmpeg'), - webrtc: localize('config.cameras.live_providers.webrtc'), - } as const; + const liveProviders = new Map([ + ['', ''], + ['auto', localize('config.cameras.live_providers.auto')], + ['frigate', localize('config.cameras.live_providers.frigate')], + ['frigate-jsmpeg', localize('config.cameras.live_providers.frigate-jsmpeg')], + ['webrtc', localize('config.cameras.live_providers.webrtc')], + ]); // Make a new config and update the editor with changes on it, const modifyConfig = (func: (config: RawFrigateCardConfig) => boolean): void => { @@ -450,7 +451,8 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor )} ${this._renderDropdown( getArrayConfigPath(CONF_CAMERAS_ARRAY_LIVE_PROVIDER, cameraIndex), - liveProviders)} + liveProviders, + )} ${this._renderStringInput( getArrayConfigPath(CONF_CAMERAS_ARRAY_URL, cameraIndex), )} @@ -497,7 +499,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor if (!this._config) { return; } - const allowedPattern = type == 'number' ? '[0-9]' : undefined + const allowedPattern = type == 'number' ? '[0-9]' : undefined; return html` ${this._renderDropdown(CONF_VIEW_DEFAULT, viewModes)} + ${this._renderDropdown(CONF_VIEW_CAMERA_SELECT, cameraSelectViewModes)} ${this._renderStringInput(CONF_VIEW_TIMEOUT_SECONDS, 'number')} ${this._renderStringInput(CONF_VIEW_UPDATE_SECONDS, 'number')} ${this._renderSwitch(CONF_VIEW_UPDATE_FORCE, defaults.view.update_force)} - ${this._renderSwitch(CONF_VIEW_UPDATE_CYCLE_CAMERA, defaults.view.update_cycle_camera)} + ${this._renderSwitch( + CONF_VIEW_UPDATE_CYCLE_CAMERA, + defaults.view.update_cycle_camera, + )} ` : ''} @@ -721,18 +734,9 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ? html`
${this._renderSwitch(CONF_LIVE_PRELOAD, defaults.live.preload)} - ${this._renderSwitch( - CONF_LIVE_DRAGGABLE, - defaults.live.draggable, - )} - ${this._renderSwitch( - CONF_LIVE_LAZY_LOAD, - defaults.live.lazy_load, - )} - ${this._renderSwitch( - CONF_LIVE_LAZY_UNLOAD, - defaults.live.lazy_unload, - )} + ${this._renderSwitch(CONF_LIVE_DRAGGABLE, defaults.live.draggable)} + ${this._renderSwitch(CONF_LIVE_LAZY_LOAD, defaults.live.lazy_load)} + ${this._renderSwitch(CONF_LIVE_LAZY_UNLOAD, defaults.live.lazy_unload)} ${this._renderDropdown( CONF_LIVE_CONTROLS_NEXT_PREVIOUS_STYLE, liveNextPreviousControlStyles, @@ -756,7 +760,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${this._renderSlider( CONF_EVENT_GALLERY_MIN_COLUMNS, defaults.event_gallery.min_columns, - "mdi:view-column", + 'mdi:view-column', 1, 10, )} diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index b06dbf39..38d1e377 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -32,6 +32,7 @@ "zone": "Frigate zone" }, "view": { + "camera_select": "View for newly selected cameras", "default": "Default view", "views": { "live": "Live view", @@ -39,7 +40,8 @@ "clips": "Clips gallery", "snapshot": "Most recent snapshot", "snapshots": "Snapshots gallery", - "image": "Static image" + "image": "Static image", + "current": "Current view" }, "timeout_seconds": "Reset to default view X seconds after user action (0=never)", "update_cycle_camera": "Cycle through cameras when default view updates", diff --git a/src/types.ts b/src/types.ts index 7c6d7aa0..48f49bc2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -377,7 +377,8 @@ export type PictureElements = z.infer; */ const viewConfigDefault = { default: 'live' as const, - timeout_seconds: 300, + camera_select: 'current' as const, + timeout_seconds: 300, update_seconds: 0, update_force: false, update_cycle_camera: false, @@ -386,8 +387,10 @@ const viewConfigSchema = z .object({ default: z .enum(FRIGATE_CARD_VIEWS_USER_SPECIFIED) - .optional() .default(viewConfigDefault.default), + camera_select: z + .enum([...FRIGATE_CARD_VIEWS_USER_SPECIFIED, 'current']) + .default(viewConfigDefault.camera_select), timeout_seconds: z.number().default(viewConfigDefault.timeout_seconds), update_seconds: z.number().default(viewConfigDefault.update_seconds), update_force: z.boolean().default(viewConfigDefault.update_force), @@ -407,7 +410,7 @@ const imageConfigDefault = { const imageConfigSchema = z .object({ src: z.string().optional(), - refresh_seconds: z.number().min(0).default(imageConfigDefault.refresh_seconds) + refresh_seconds: z.number().min(0).default(imageConfigDefault.refresh_seconds), }) .merge(actionsSchema) .default(imageConfigDefault);