From 162b925889c67b032dcfea31d994b5a1eebc5d5c Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Fri, 3 Sep 2021 22:43:06 -0700 Subject: [PATCH] Support hiding menu buttons. Add editor localization. --- src/editor.ts | 215 +++++++++++++++++++++++---------- src/frigate-hass-card.ts | 27 +++-- src/localize/languages/en.json | 56 ++++++++- src/types.ts | 15 +++ 4 files changed, 239 insertions(+), 74 deletions(-) diff --git a/src/editor.ts b/src/editor.ts index b7e41e6f..51418571 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -10,34 +10,40 @@ import { unsafeCSS, } from 'lit-element'; import { HomeAssistant, fireEvent, LovelaceCardEditor } from 'custom-card-helpers'; - -import { FrigateCardConfig } from './types'; +import { localize } from './localize/localize'; +import type { FrigateCardConfig } from './types'; import frigate_card_editor_style from './frigate-hass-card-editor.scss'; const options = { required: { icon: 'cog', - name: 'Required', - secondary: 'Required options for this card to function', + name: localize('editor.required'), + secondary: localize('editor.required_secondary'), show: true, }, optional: { icon: 'tune', - name: 'Optional', - secondary: 'Optional configuration to tweak card behavior', + name: localize('editor.optional'), + secondary: localize('editor.optional_secondary'), + show: false, + }, + appearance: { + icon: 'palette', + name: localize('editor.appearance'), + secondary: localize('editor.appearance_secondary'), show: false, }, webrtc: { icon: 'webrtc', - name: 'WebRTC', - secondary: 'Optional WebRTC parameters', + name: localize('editor.webrtc'), + secondary: localize('editor.webrtc_secondary'), show: false, }, advanced: { icon: 'cogs', - name: 'Advanced', - secondary: 'Advanced options', + name: localize('editor.advanced'), + secondary: localize('editor.advanced_secondary'), show: false, }, }; @@ -51,6 +57,9 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor private _initialized = false; public setConfig(config: FrigateCardConfig): void { + // Note: This does not use Zod to parse the configuration, so it may be + // partially or completely invalid. It's more useful to have a partially + // valid configuration here, to allow the user to fix the broken parts. this._config = config; this.loadCardHelpers(); } @@ -96,33 +105,32 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor const viewModes = { '': '', - live: 'Live view', - clips: 'Clip gallery', - snapshots: 'Snapshot gallery', - clip: 'Latest clip', - snapshot: 'Latest snapshot', + live: localize('menu.live'), + clips: localize('menu.clips'), + snapshots: localize('menu.snapshots'), + clip: localize('menu.clip'), + snapshot: localize('menu.snapshot'), }; const menuModes = { '': '', - 'hidden-top': 'Hidden Top', - 'hidden-left': 'Hidden Left', - 'hidden-bottom': 'Hidden Bottom', - 'hidden-right': 'Hidden Right', - 'overlay-top': 'Overlay Top', - 'overlay-left': 'Overlay Left', - 'overlay-bottom': 'Overlay Bottom', - 'overlay-right': 'Overlay Right', - above: 'Above', - below: 'Below', + 'hidden-top': localize('menu_mode.hidden-top'), + 'hidden-left': localize('menu_mode.hidden-left'), + 'hidden-bottom': localize('menu_mode.hidden-bottom'), + 'hidden-right': localize('menu_mode.hidden-right'), + 'overlay-top': localize('menu_mode.overlay-top'), + 'overlay-left': localize('menu_mode.overlay-left'), + 'overlay-bottom': localize('menu_mode.overlay-bottom'), + 'overlay-right': localize('menu_mode.overlay-right'), + above: localize('menu_mode.above'), + below: localize('menu_mode.below'), }; const liveProvider = { '': '', - frigate: 'Frigate', - webrtc: 'WebRTC', + frigate: localize('live_provider.frigate'), + webrtc: localize('live_provider.webrtc'), }; - return html`
@@ -136,7 +144,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ? html`
@@ -164,7 +172,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${options.optional.show ? html`
@@ -180,13 +188,13 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor @@ -203,8 +211,47 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor })} - + + + + + +
` + : ''} +
+
+ +
${options.appearance.name}
+
+
${options.appearance.secondary}
+
+ ${options.appearance.show + ? html` @@ -219,38 +266,74 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${menuModes[key]} `; })} - - - - - - +

+ -
` +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
` : ''}
@@ -262,7 +345,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${options.advanced.show ? html`
@@ -305,7 +388,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor diff --git a/src/frigate-hass-card.ts b/src/frigate-hass-card.ts index 658c9389..929e884b 100644 --- a/src/frigate-hass-card.ts +++ b/src/frigate-hass-card.ts @@ -180,6 +180,12 @@ export class FrigateCardMenu extends LitElement { bottom: this.menuMode.endsWith('-bottom'), }; + // If the menu is in hidden mode and there's no button to unhide it, just + // show nothing. + if (this.menuMode.startsWith('hidden-') && !this.buttons.get('frigate')) { + return html``; + } + return html`
${Array.from(this.buttons.keys()).map((name) => { @@ -295,15 +301,22 @@ export class FrigateCard extends LitElement { protected _getMenuButtons(): Map { const buttons: Map = new Map(); - buttons.set('frigate', { description: 'Frigate Menu' }); - buttons.set('live', { icon: 'mdi:cctv', description: 'View Live' }); - buttons.set('clips', { icon: 'mdi:filmstrip', description: 'View Clips' }); - buttons.set('snapshots', { icon: 'mdi:camera', description: 'View Snapshots' }); - if (this.config.frigate_url) { + if (this.config.menu_buttons?.frigate) { + buttons.set('frigate', { description: 'Frigate Menu' }); + } + if (this.config.menu_buttons?.live) { + buttons.set('live', { icon: 'mdi:cctv', description: 'View Live' }); + } + if (this.config.menu_buttons?.clips) { + buttons.set('clips', { icon: 'mdi:filmstrip', description: 'View Clips' }); + } + if (this.config.menu_buttons?.snapshots) { + buttons.set('snapshots', { icon: 'mdi:camera', description: 'View Snapshots' }); + } + if (this.config.menu_buttons?.frigate_ui && this.config.frigate_url) { buttons.set('frigate_ui', { icon: 'mdi:web', description: 'View Frigate UI' }); } - - if (this._hass && this.config.motion_entity) { + if (this.config.menu_buttons?.motion && this._hass && this.config.motion_entity) { const on = this._hass.states[this.config.motion_entity]?.state == 'on'; const motionIcon = on ? 'mdi:motion-sensor' : 'mdi:walk'; diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 7e1b0a54..97a58d1d 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -5,5 +5,59 @@ "missing_webrtc": "WebRTC component not found", "show_warning": "Show Warning", "show_error": "Show Error" + }, + "editor": { + "required": "Required", + "required_secondary": "Required options for this card to function", + "optional": "Optional", + "optional_secondary": "Optional configuration to tweak card behavior", + "appearance": "Appearance", + "appearance_secondary": "Appearance of the card", + "webrtc": "WebRTC", + "webrtc_secondary": "Optional WebRTC parameters", + "advanced": "Advanced", + "advanced_secondary": "Advanced options", + "camera_entity": "Camera Entity (Required)", + "motion_entity": "Motion Entity (Optional)", + "frigate_camera_name": "Frigate camera name (Optional)", + "default_view": "Default view (Optional)", + "frigate_client_id": "Frigate client id (Optional, for >1 Frigate server)", + "view_timeout": "View timeout (seconds)", + "frigate_url": "Frigate URL (Optional, for Frigate UI button)", + "autoplay_clip": "Autoplay latest clip", + "menu_mode": "Menu mode (Optional)", + "show_button": "Show button", + "zone": "Zone", + "label": "Frigate label/object filter (Optional)", + "live_provider": "Live view provider (Optional)" + }, + "menu": { + "frigate": "Frigate", + "live": "Live View", + "clips": "Clips Gallery", + "snapshots": "Snapshots Gallery", + "clip": "Latest Clip", + "snapshot": "Latest Snapshot", + "frigate_ui": "Frigate User Interface", + "motion": "Motion Entity" + }, + "menu_mode": { + "hidden-top": "Hidden Top", + "hidden-left": "Hidden Left", + "hidden-bottom": "Hidden Bottom", + "hidden-right": "Hidden Right", + "overlay-top": "Overlay Top", + "overlay-left": "Overlay Left", + "overlay-bottom": "Overlay Bottom", + "overlay-right": "Overlay Right", + "above": "Above", + "below": "Below" + }, + "live_provider": { + "frigate": "Frigate", + "webrtc": "WebRTC" + }, + "webrtc": { + "entity": "WebRTC Camera Entity (To use with WebRTC Live Provider)" } -} \ No newline at end of file +} diff --git a/src/types.ts b/src/types.ts index ae90a074..6cad8ed7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -62,6 +62,21 @@ export const frigateCardConfigSchema = z.object({ zone: z.string().optional(), autoplay_clip: z.boolean().default(false), menu_mode: z.enum(FRIGATE_MENU_MODES).optional().default('hidden-top'), + menu_buttons: z.object({ + frigate: z.boolean().default(true), + live: z.boolean().default(true), + clips: z.boolean().default(true), + snapshots: z.boolean().default(true), + frigate_ui: z.boolean().default(true), + motion: z.boolean().default(true), + }).default({ + frigate: true, + live: true, + clips: true, + snapshots: true, + frigate_ui: true, + motion: true, + }), // Stock lovelace card config. type: z.string(),