fix: Panel height should be 100% when casted (#1750)
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { LitElement, ReactiveControllerHost } from 'lit';
|
import { LitElement, ReactiveControllerHost } from 'lit';
|
||||||
import { ActionEventTarget } from '../action-handler-directive';
|
import { ActionEventTarget } from '../action-handler-directive';
|
||||||
import { setOrRemoveAttribute } from '../utils/basic';
|
import { setOrRemoveAttribute } from '../utils/basic';
|
||||||
|
import { isBeingCasted } from '../utils/casting';
|
||||||
import { isCardInPanel } from '../utils/ha';
|
import { isCardInPanel } from '../utils/ha';
|
||||||
import { ActionExecutionRequestEventTarget } from './actions/utils/execution-request';
|
import { ActionExecutionRequestEventTarget } from './actions/utils/execution-request';
|
||||||
import { InitializationAspect } from './initialization-manager';
|
import { InitializationAspect } from './initialization-manager';
|
||||||
@@ -83,7 +84,7 @@ export class CardElementManager {
|
|||||||
|
|
||||||
// Whether or not the card is in panel mode on the dashboard.
|
// Whether or not the card is in panel mode on the dashboard.
|
||||||
setOrRemoveAttribute(this._element, isCardInPanel(this._element), 'panel');
|
setOrRemoveAttribute(this._element, isCardInPanel(this._element), 'panel');
|
||||||
setOrRemoveAttribute(this._element, true, 'tabindex', '0');
|
setOrRemoveAttribute(this._element, isBeingCasted(), 'casted');
|
||||||
|
|
||||||
this._api.getFullscreenManager().connect();
|
this._api.getFullscreenManager().connect();
|
||||||
|
|
||||||
@@ -137,6 +138,7 @@ export class CardElementManager {
|
|||||||
public elementDisconnected(): void {
|
public elementDisconnected(): void {
|
||||||
setOrRemoveAttribute(this._element, false, 'panel');
|
setOrRemoveAttribute(this._element, false, 'panel');
|
||||||
setOrRemoveAttribute(this._element, false, 'tabindex');
|
setOrRemoveAttribute(this._element, false, 'tabindex');
|
||||||
|
setOrRemoveAttribute(this._element, false, 'casted');
|
||||||
|
|
||||||
// When the dashboard 'tab' is changed, the media is effectively unloaded.
|
// When the dashboard 'tab' is changed, the media is effectively unloaded.
|
||||||
this._api.getMediaLoadedInfoManager().clear();
|
this._api.getMediaLoadedInfoManager().clear();
|
||||||
|
|||||||
@@ -15,13 +15,14 @@ import { localize } from '../localize/localize.js';
|
|||||||
import { MediaLoadedInfo } from '../types';
|
import { MediaLoadedInfo } from '../types';
|
||||||
import {
|
import {
|
||||||
createCameraAction,
|
createCameraAction,
|
||||||
createPTZMultiAction,
|
|
||||||
createDisplayModeAction,
|
createDisplayModeAction,
|
||||||
|
createGeneralAction,
|
||||||
createMediaPlayerAction,
|
createMediaPlayerAction,
|
||||||
createPTZControlsAction,
|
createPTZControlsAction,
|
||||||
createGeneralAction,
|
createPTZMultiAction,
|
||||||
} from '../utils/action';
|
} from '../utils/action';
|
||||||
import { isTruthy } from '../utils/basic';
|
import { isTruthy } from '../utils/basic';
|
||||||
|
import { isBeingCasted } from '../utils/casting';
|
||||||
import { getEntityIcon, getEntityTitle } from '../utils/ha';
|
import { getEntityIcon, getEntityTitle } from '../utils/ha';
|
||||||
import { getPTZTarget } from '../utils/ptz';
|
import { getPTZTarget } from '../utils/ptz';
|
||||||
import { getStreamCameraID, hasSubstream } from '../utils/substream';
|
import { getStreamCameraID, hasSubstream } from '../utils/substream';
|
||||||
@@ -340,11 +341,7 @@ export class MenuButtonController {
|
|||||||
const mediaCapabilities = selectedMedia
|
const mediaCapabilities = selectedMedia
|
||||||
? cameraManager?.getMediaCapabilities(selectedMedia)
|
? cameraManager?.getMediaCapabilities(selectedMedia)
|
||||||
: null;
|
: null;
|
||||||
if (
|
if (view?.isViewerView() && mediaCapabilities?.canDownload && !isBeingCasted()) {
|
||||||
view?.isViewerView() &&
|
|
||||||
mediaCapabilities?.canDownload &&
|
|
||||||
!this._isBeingCasted()
|
|
||||||
) {
|
|
||||||
return {
|
return {
|
||||||
icon: 'mdi:download',
|
icon: 'mdi:download',
|
||||||
...config.menu.buttons.download,
|
...config.menu.buttons.download,
|
||||||
@@ -429,7 +426,7 @@ export class MenuButtonController {
|
|||||||
config: FrigateCardConfig,
|
config: FrigateCardConfig,
|
||||||
inFullscreenMode?: boolean,
|
inFullscreenMode?: boolean,
|
||||||
): MenuItem | null {
|
): MenuItem | null {
|
||||||
return !this._isBeingCasted()
|
return !isBeingCasted()
|
||||||
? {
|
? {
|
||||||
icon: inFullscreenMode ? 'mdi:fullscreen-exit' : 'mdi:fullscreen',
|
icon: inFullscreenMode ? 'mdi:fullscreen-exit' : 'mdi:fullscreen',
|
||||||
...config.menu.buttons.fullscreen,
|
...config.menu.buttons.fullscreen,
|
||||||
@@ -712,12 +709,4 @@ export class MenuButtonController {
|
|||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if the card is currently being casted.
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
protected _isBeingCasted(): boolean {
|
|
||||||
return !!navigator.userAgent.match(/CrKey\//);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-2
@@ -39,10 +39,16 @@ frigate-card-loading {
|
|||||||
:host([dark]) {
|
:host([dark]) {
|
||||||
filter: brightness(75%);
|
filter: brightness(75%);
|
||||||
}
|
}
|
||||||
:host([panel]) {
|
:host([panel]:not([casted])) {
|
||||||
// Card always extends to the full height in panel mode
|
// Card always extends to the full height in panel mode minus the header.
|
||||||
height: calc(100vh - var(--header-height));
|
height: calc(100vh - var(--header-height));
|
||||||
}
|
}
|
||||||
|
:host([panel][casted]) {
|
||||||
|
// Card always extends to the full height in panel mode when casting (there is
|
||||||
|
// no header).
|
||||||
|
// See: https://github.com/dermotduffy/frigate-hass-card/issues/1746
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
div.main {
|
div.main {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* Determine if the card is currently being casted.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const isBeingCasted = (): boolean => {
|
||||||
|
return !!navigator.userAgent.match(/CrKey\//);
|
||||||
|
};
|
||||||
@@ -101,6 +101,7 @@ describe('CardElementManager', () => {
|
|||||||
manager.elementConnected();
|
manager.elementConnected();
|
||||||
|
|
||||||
expect(element.getAttribute('panel')).toBeNull();
|
expect(element.getAttribute('panel')).toBeNull();
|
||||||
|
expect(element.getAttribute('casted')).toBeNull();
|
||||||
expect(api.getFullscreenManager().connect).toBeCalled();
|
expect(api.getFullscreenManager().connect).toBeCalled();
|
||||||
|
|
||||||
expect(addEventListener).toBeCalledWith(
|
expect(addEventListener).toBeCalledWith(
|
||||||
@@ -134,6 +135,7 @@ describe('CardElementManager', () => {
|
|||||||
|
|
||||||
const element = createLitElement();
|
const element = createLitElement();
|
||||||
element.setAttribute('panel', '');
|
element.setAttribute('panel', '');
|
||||||
|
element.setAttribute('casted', '');
|
||||||
|
|
||||||
const removeEventListener = vi.fn();
|
const removeEventListener = vi.fn();
|
||||||
element.removeEventListener = removeEventListener;
|
element.removeEventListener = removeEventListener;
|
||||||
@@ -150,6 +152,7 @@ describe('CardElementManager', () => {
|
|||||||
manager.elementDisconnected();
|
manager.elementDisconnected();
|
||||||
|
|
||||||
expect(element.getAttribute('panel')).toBeNull();
|
expect(element.getAttribute('panel')).toBeNull();
|
||||||
|
expect(element.getAttribute('casted')).toBeNull();
|
||||||
expect(api.getMediaLoadedInfoManager().clear).toBeCalled();
|
expect(api.getMediaLoadedInfoManager().clear).toBeCalled();
|
||||||
expect(api.getFullscreenManager().disconnect).toBeCalled();
|
expect(api.getFullscreenManager().disconnect).toBeCalled();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { describe, expect, it, vi } from 'vitest';
|
||||||
|
import { isBeingCasted } from '../../src/utils/casting.js';
|
||||||
|
|
||||||
|
describe('isBeingCasted', () => {
|
||||||
|
it('should confirm being casted', () => {
|
||||||
|
vi.stubGlobal('navigator', {
|
||||||
|
userAgent:
|
||||||
|
'Mozilla/5.0 (Fuchsia) AppleWebKit/537.36 (KHTML, like Gecko) ' +
|
||||||
|
'Chrome/114.0.0.0 Safari/537.36 CrKey/1.56.500000',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Import the function
|
||||||
|
expect(isBeingCasted()).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should confirm not being casted', () => {
|
||||||
|
vi.stubGlobal('navigator', {
|
||||||
|
userAgent:
|
||||||
|
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) ' +
|
||||||
|
'Chrome/131.0.0.0 Safari/537.36',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Import the function
|
||||||
|
expect(isBeingCasted()).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -20,6 +20,7 @@ const FULL_COVERAGE_FILES_RELATIVE = [
|
|||||||
'utils/audio.ts',
|
'utils/audio.ts',
|
||||||
'utils/basic.ts',
|
'utils/basic.ts',
|
||||||
'utils/camera.ts',
|
'utils/camera.ts',
|
||||||
|
'utils/casting.ts',
|
||||||
'utils/custom-icons.ts',
|
'utils/custom-icons.ts',
|
||||||
'utils/debug.ts',
|
'utils/debug.ts',
|
||||||
'utils/diagnostics.ts',
|
'utils/diagnostics.ts',
|
||||||
|
|||||||
Reference in New Issue
Block a user