Initial fullscreen functionality.
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
"dayjs": "^1.10.6",
|
"dayjs": "^1.10.6",
|
||||||
"home-assistant-js-websocket": "^5.11.1",
|
"home-assistant-js-websocket": "^5.11.1",
|
||||||
"lit": "^2.0.0-rc.2",
|
"lit": "^2.0.0-rc.2",
|
||||||
|
"screenfull": "^5.1.0",
|
||||||
"zod": "^3.8.2"
|
"zod": "^3.8.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
+33
@@ -17,6 +17,7 @@ import {
|
|||||||
getLovelace,
|
getLovelace,
|
||||||
stateIcon,
|
stateIcon,
|
||||||
} from 'custom-card-helpers';
|
} from 'custom-card-helpers';
|
||||||
|
import screenfull from 'screenfull';
|
||||||
|
|
||||||
import { MenuButton, frigateCardConfigSchema } from './types';
|
import { MenuButton, frigateCardConfigSchema } from './types';
|
||||||
import type {
|
import type {
|
||||||
@@ -191,6 +192,13 @@ export class FrigateCard extends LitElement {
|
|||||||
description: localize('menu.frigate_ui'),
|
description: localize('menu.frigate_ui'),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if ((this.config.menu_buttons?.fullscreen ?? false) && screenfull.isEnabled) {
|
||||||
|
buttons.set('fullscreen', {
|
||||||
|
icon: screenfull.isFullscreen ? 'mdi:fullscreen-exit' : 'mdi:fullscreen',
|
||||||
|
description: localize('menu.fullscreen'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const entities = this.config.entities || [];
|
const entities = this.config.entities || [];
|
||||||
for (let i = 0; this._hass && i < entities.length; i++) {
|
for (let i = 0; this._hass && i < entities.length; i++) {
|
||||||
if (!entities[i].show) {
|
if (!entities[i].show) {
|
||||||
@@ -294,6 +302,11 @@ export class FrigateCard extends LitElement {
|
|||||||
window.open(frigate_url);
|
window.open(frigate_url);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'fullscreen':
|
||||||
|
if (screenfull.isEnabled) {
|
||||||
|
screenfull.toggle(this);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// If it's unknown, it's assumed to be an entity_id.
|
// If it's unknown, it's assumed to be an entity_id.
|
||||||
fireEvent(this, 'hass-more-info', { entityId: name });
|
fireEvent(this, 'hass-more-info', { entityId: name });
|
||||||
@@ -383,6 +396,25 @@ export class FrigateCard extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected _fullScreenHandler(): void {
|
||||||
|
// Re-render after a change to fullscreen mode to take advantage of
|
||||||
|
// the expanded screen real-estate (vs staying in aspect-ratio locked
|
||||||
|
// modes).
|
||||||
|
this.requestUpdate();
|
||||||
|
}
|
||||||
|
connectedCallback(): void {
|
||||||
|
super.connectedCallback();
|
||||||
|
if (screenfull.isEnabled) {
|
||||||
|
screenfull.on('change', this._fullScreenHandler.bind(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disconnectedCallback(): void {
|
||||||
|
if (screenfull.isEnabled) {
|
||||||
|
screenfull.off('change', this._fullScreenHandler.bind(this));
|
||||||
|
}
|
||||||
|
super.disconnectedCallback();
|
||||||
|
}
|
||||||
|
|
||||||
protected _getAspectRatioPadding(): number | null {
|
protected _getAspectRatioPadding(): number | null {
|
||||||
const aspect_ratio_mode = this.config.dimensions?.aspect_ratio_mode ?? 'dynamic';
|
const aspect_ratio_mode = this.config.dimensions?.aspect_ratio_mode ?? 'dynamic';
|
||||||
|
|
||||||
@@ -391,6 +423,7 @@ export class FrigateCard extends LitElement {
|
|||||||
// dynamic mode (as the aspect_ratio is essentially whatever the media
|
// dynamic mode (as the aspect_ratio is essentially whatever the media
|
||||||
// dimensions are).
|
// dimensions are).
|
||||||
if (
|
if (
|
||||||
|
(screenfull.isEnabled && screenfull.isFullscreen) ||
|
||||||
aspect_ratio_mode == 'unconstrained' ||
|
aspect_ratio_mode == 'unconstrained' ||
|
||||||
(!this._view.isGalleryView() && aspect_ratio_mode == 'dynamic' && this._mediaInfo)
|
(!this._view.isGalleryView() && aspect_ratio_mode == 'dynamic' && this._mediaInfo)
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -41,7 +41,8 @@
|
|||||||
"snapshots": "Snapshots Gallery",
|
"snapshots": "Snapshots Gallery",
|
||||||
"clip": "Latest Clip",
|
"clip": "Latest Clip",
|
||||||
"snapshot": "Latest Snapshot",
|
"snapshot": "Latest Snapshot",
|
||||||
"frigate_ui": "Frigate User Interface"
|
"frigate_ui": "Frigate User Interface",
|
||||||
|
"fullscreen": "Fullscreen"
|
||||||
},
|
},
|
||||||
"control": {
|
"control": {
|
||||||
"nextprev": "Media Next & Previous Controls",
|
"nextprev": "Media Next & Previous Controls",
|
||||||
@@ -93,7 +94,6 @@
|
|||||||
"could_not_resolve": "Could not resolve media URL",
|
"could_not_resolve": "Could not resolve media URL",
|
||||||
"no_live_camera": "No live camera",
|
"no_live_camera": "No live camera",
|
||||||
"invalid_configuration": "Invalid configuration",
|
"invalid_configuration": "Invalid configuration",
|
||||||
"missing_webrtc": "WebRTC component not found",
|
"missing_webrtc": "WebRTC component not found"
|
||||||
"internal": "Internal error"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-2
@@ -1,5 +1,7 @@
|
|||||||
.container {
|
.container {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
overflow: auto;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.frigate-card-contents {
|
.frigate-card-contents {
|
||||||
@@ -8,6 +10,11 @@
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
-ms-overflow-style: none; /* Hide scrollbar: IE and Edge */
|
-ms-overflow-style: none; /* Hide scrollbar: IE and Edge */
|
||||||
scrollbar-width: none; /* Hide scrollbar: Firefox */
|
scrollbar-width: none; /* Hide scrollbar: Firefox */
|
||||||
|
|
||||||
|
// Vertically align items in case the container is larger than the media (e.g.
|
||||||
|
// fullscreen mode, or forced aspect ratios).
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hide scrollbar for Chrome, Safari and Opera */
|
/* Hide scrollbar for Chrome, Safari and Opera */
|
||||||
@@ -15,7 +22,7 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The 'hover' menu mode is styling applied outside of the menu itself */
|
/* When forcing aspect ratio absolute positioning is required */
|
||||||
.frigate-card-contents.absolute {
|
.frigate-card-contents.absolute {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
@@ -24,7 +31,7 @@
|
|||||||
left: 0px;
|
left: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Support the 'hover' menu mode. */
|
/* The 'hover' menu mode is styling applied outside of the menu itself */
|
||||||
.hover-menu {
|
.hover-menu {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
transition: all 0.5s ease;
|
transition: all 0.5s ease;
|
||||||
@@ -50,4 +57,31 @@ ha-card {
|
|||||||
|
|
||||||
ha-card a {
|
ha-card a {
|
||||||
color: var(--primary-text-color, white);
|
color: var(--primary-text-color, white);
|
||||||
|
}
|
||||||
|
|
||||||
|
frigate-card-gallery, frigate-card-viewer, frigate-card-live {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
frigate-card-gallery {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Browsers will reject invalid whole CSS selectors if one selector is bad, so
|
||||||
|
// need to use mixin here instead of just comma-separated selectors.
|
||||||
|
// - Related: https://stackoverflow.com/questions/16982449/why-isnt-it-possible-to-combine-vendor-specific-pseudo-elements-classes-into-on
|
||||||
|
@mixin fullscreen-ha-card {
|
||||||
|
// Make the background black, to give it the expected fullscreen feel.
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
:host(:fullscreen) ha-card {
|
||||||
|
@include fullscreen-ha-card;
|
||||||
|
}
|
||||||
|
:host(:-webkit-full-screen) ha-card {
|
||||||
|
@include fullscreen-ha-card;
|
||||||
|
}
|
||||||
|
:host(:-moz-full-screen) ha-card {
|
||||||
|
@include fullscreen-ha-card;
|
||||||
|
}
|
||||||
|
:host(:-webkit-full-screen) ha-card {
|
||||||
|
@include fullscreen-ha-card;
|
||||||
}
|
}
|
||||||
@@ -82,6 +82,7 @@ export const frigateCardConfigSchema = z.object({
|
|||||||
clips: z.boolean().default(true),
|
clips: z.boolean().default(true),
|
||||||
snapshots: z.boolean().default(true),
|
snapshots: z.boolean().default(true),
|
||||||
frigate_ui: z.boolean().default(true),
|
frigate_ui: z.boolean().default(true),
|
||||||
|
fullscreen: z.boolean().default(false),
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
entities: z
|
entities: z
|
||||||
|
|||||||
Reference in New Issue
Block a user