From addf6edb3098b062aedfac82140a24fae19b5c34 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 11 Jan 2025 16:30:41 -0700 Subject: [PATCH] fix: Don't hide PTZ control menu button unnecessarily (#1823) - Closes: #1819 --- docs/configuration/live.md | 2 +- src/components-lib/menu-button-controller.ts | 10 +-- .../menu-button-controller.test.ts | 86 ++++++++++++++----- 3 files changed, 69 insertions(+), 29 deletions(-) diff --git a/docs/configuration/live.md b/docs/configuration/live.md index c3bc2843..f26e28f1 100644 --- a/docs/configuration/live.md +++ b/docs/configuration/live.md @@ -74,7 +74,7 @@ live: | `hide_home` | `false` | When `true` the Home button of the control is hidden | | `hide_pan_tilt` | `false` | When `true` the Pan & Tilt buttons of the control is hidden | | `hide_zoom` | `false` | When `true` the Zoom button of the control is hidden | -| `mode` | `auto` | If `on` or `off` will always or never show PTZ controls respectively, if `auto` will show PTZ controls only if the camera supports real PTZ. | +| `mode` | `auto` | If `on` or `off`, by default will always or never show PTZ controls respectively, if `auto` will show PTZ controls only if the camera supports real PTZ. | | `orientation` | `horizontal` | Whether to show a `vertical` or `horizontal` PTZ control. | | `position` | `bottom-right` | Whether to position the control on the `top-left`, `top-right`, `bottom-left` or `bottom-right`. This may be overridden by using the `style` parameter to precisely control placement. | | `style` | | Optionally position and style the element using CSS. Similar to [Picture Element styling](https://www.home-assistant.io/dashboards/picture-elements/#how-to-use-the-style-object), except without any default, e.g. `left: 42%` | diff --git a/src/components-lib/menu-button-controller.ts b/src/components-lib/menu-button-controller.ts index d7125df0..557cc5e2 100644 --- a/src/components-lib/menu-button-controller.ts +++ b/src/components-lib/menu-button-controller.ts @@ -582,20 +582,20 @@ export class MenuButtonController { ? config.media_viewer.controls.ptz : null; - if (!view || !ptzConfig || ptzConfig.mode === 'off') { + if (!view || !ptzConfig) { return null; } const ptzTarget = getPTZTarget(view, { cameraManager: cameraManager, - ...(ptzConfig.mode === 'auto' && { type: 'ptz' }), }); if (ptzTarget) { const isOn = - view.context?.ptzControls?.enabled !== false && - (ptzConfig.mode === 'on' || - (ptzConfig.mode === 'auto' && ptzTarget.type === 'ptz')); + view.context?.ptzControls?.enabled !== undefined + ? view.context.ptzControls.enabled + : ptzConfig.mode === 'on' || + (ptzConfig.mode === 'auto' && ptzTarget.type === 'ptz'); return { icon: 'mdi:pan', ...config.menu.buttons.ptz_controls, diff --git a/tests/components-lib/menu-button-controller.test.ts b/tests/components-lib/menu-button-controller.test.ts index 0fba379d..4192f70d 100644 --- a/tests/components-lib/menu-button-controller.test.ts +++ b/tests/components-lib/menu-button-controller.test.ts @@ -1428,26 +1428,7 @@ describe('MenuButtonController', () => { }); describe('should have show ptz button', () => { - it('when the selected camera is not PTZ enabled', () => { - const store = createStore([ - { - cameraID: 'camera-1', - }, - ]); - - const buttons = calculateButtons(controller, { - cameraManager: createCameraManager(store), - view: createView({ view: 'live' }), - }); - - expect(buttons).not.toContainEqual( - expect.objectContaining({ - title: 'Show PTZ controls', - }), - ); - }); - - it('when not in live view', () => { + it('should not show when not in live view', () => { const store = createStore([ { cameraID: 'camera-1', @@ -1467,7 +1448,7 @@ describe('MenuButtonController', () => { ); }); - it('when the selected camera is PTZ enabled', () => { + it('should show when in live view', () => { const store = createStore([ { cameraID: 'camera-1', @@ -1477,6 +1458,31 @@ describe('MenuButtonController', () => { const buttons = calculateButtons(controller, { cameraManager: createCameraManager(store), + view: createView({ view: 'live' }), + }); + + expect(buttons).toContainEqual( + expect.objectContaining({ + title: 'Show PTZ controls', + }), + ); + }); + + it('should show when the context has PTZ enabled', () => { + const store = createStore([ + { + cameraID: 'camera-1', + capabilities: new Capabilities({ ptz: { left: ['relative'] } }), + }, + ]); + + const view = createView({ + camera: 'camera-1', + context: { ptzControls: { enabled: true } }, + }); + const buttons = calculateButtons(controller, { + cameraManager: createCameraManager(store), + view: view, }); expect(buttons).toContainEqual({ @@ -1496,7 +1502,7 @@ describe('MenuButtonController', () => { }); }); - it('when the context has PTZ disabled', () => { + it('should show when the context has PTZ disabled', () => { const store = createStore([ { cameraID: 'camera-1', @@ -1528,7 +1534,41 @@ describe('MenuButtonController', () => { }); }); - it('when a substream is PTZ enabled', () => { + it('should detect current status without context in auto mode', () => { + const store = createStore([ + { + cameraID: 'camera-1', + capabilities: new Capabilities({ ptz: { left: ['relative'] } }), + }, + ]); + + const view = createView({ + camera: 'camera-1', + }); + const buttons = calculateButtons(controller, { + cameraManager: createCameraManager(store), + config: createConfig({ live: { controls: { ptz: { mode: 'auto' } } } }), + view: view, + }); + + expect(buttons).toContainEqual({ + enabled: false, + icon: 'mdi:pan', + priority: 50, + style: { + color: 'var(--frigate-card-menu-button-active-color)', + }, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'ptz_controls', + enabled: false, + }, + title: 'Show PTZ controls', + type: 'custom:frigate-card-menu-icon', + }); + }); + + it('should show when a substream is PTZ enabled', () => { const store = createStore([ { cameraID: 'camera-1',