Refactor aspect-ratio logic.

This commit is contained in:
Dermot Duffy
2022-05-23 21:15:31 -07:00
parent b92e7a6f80
commit f7da2c2793
2 changed files with 71 additions and 100 deletions
+58 -69
View File
@@ -963,10 +963,8 @@ export class FrigateCard extends LitElement {
* Get the most recent triggered camera.
*/
protected _getMostRecentTrigger(): string | null {
const sorted = (
[...this._triggers.entries()].sort(
(a: [string, Date], b: [string, Date]) => b[1].getTime() - a[1].getTime(),
)
const sorted = [...this._triggers.entries()].sort(
(a: [string, Date], b: [string, Date]) => b[1].getTime() - a[1].getTime(),
);
return sorted.length ? sorted[0][0] : null;
}
@@ -1009,7 +1007,10 @@ export class FrigateCard extends LitElement {
changedCamera = true;
} else {
const targetCamera = this._getMostRecentTrigger();
if (targetCamera && (this._view.camera !== targetCamera || !this._view.is('live'))) {
if (
targetCamera &&
(this._view.camera !== targetCamera || !this._view.is('live'))
) {
this._changeView({ view: new View({ view: 'live', camera: targetCamera }) });
changedCamera = true;
}
@@ -1510,21 +1511,21 @@ export class FrigateCard extends LitElement {
* required).
* @returns A padding percentage.
*/
protected _getAspectRatioPadding(): number | null {
protected _getAspectRatioStyle(): string {
if (!this._isAspectRatioEnforced()) {
return null;
return 'auto';
}
const aspectRatioMode = this._getConfig().dimensions.aspect_ratio_mode;
if (aspectRatioMode == 'dynamic' && this._mediaShowInfo) {
return (this._mediaShowInfo.height / this._mediaShowInfo.width) * 100;
return `${this._mediaShowInfo.width} / ${this._mediaShowInfo.height}`;
}
const defaultAspectRatio = this._getConfig().dimensions.aspect_ratio;
if (defaultAspectRatio) {
return (defaultAspectRatio[1] / defaultAspectRatio[0]) * 100;
return `${defaultAspectRatio[0]} / ${defaultAspectRatio[1]}`;
} else {
return (9 / 16) * 100;
return '16 / 9';
}
}
@@ -1557,26 +1558,15 @@ export class FrigateCard extends LitElement {
return;
}
const padding = this._getAspectRatioPadding();
const outerStyle = {};
// Padding to force a particular aspect ratio.
if (padding != null) {
outerStyle['padding-top'] = `${padding}%`;
}
const outerClasses = {
container: true,
outer: true,
const cardStyle = {
'aspect-ratio': this._getAspectRatioStyle(),
};
const mainClasses = {
main: true,
triggered:
!!this._triggers.size && this._getConfig().view.scan.show_trigger_status,
};
const contentClasses = {
'frigate-card-contents': true,
absolute: padding != null,
};
const actions = this._getMergedActions();
const renderMenuAbove =
this._getConfig().menu.style === 'outside' &&
@@ -1587,6 +1577,7 @@ export class FrigateCard extends LitElement {
hasHold: frigateCardHasAction(actions.hold_action),
hasDoubleClick: frigateCardHasAction(actions.double_tap_action),
})}
style="${styleMap(cardStyle)}"
@action=${(ev: CustomEvent) => this._actionHandler(ev, actions)}
@ll-custom=${this._cardActionHandler.bind(this)}
@frigate-card:message=${this._messageHandler}
@@ -1595,49 +1586,47 @@ export class FrigateCard extends LitElement {
@frigate-card:render=${() => this.requestUpdate()}
>
${renderMenuAbove ? this._renderMenu() : ''}
<div class="${classMap(outerClasses)}" style="${styleMap(outerStyle)}">
<div class="${classMap(contentClasses)}">
${this._cameras === undefined
? until(
(async () => {
await this._loadCameras();
// Don't reset messages as errors may have been generated
// during the camera load.
this._changeView({ resetMessage: false });
return this._render();
})(),
renderProgressIndicator(),
)
: // Always want to call render even if there's a message, to
// ensure live preload is always present (even if not displayed).
this._render()}
${this._getConfig().elements
? // Always show elements to allow for custom menu items (etc.) to
// be present even if a particular view has an error. Elements
// need to render after the main views so it can render 'on top'.
html` <frigate-card-elements
${ref(this._refElements)}
.hass=${this._hass}
.elements=${this._getConfig().elements}
.conditionState=${this._conditionState}
@frigate-card:menu-add=${(e) => {
this._addDynamicMenuButton(e.detail);
}}
@frigate-card:menu-remove=${(e) => {
this._removeDynamicMenuButton(e.detail);
}}
@frigate-card:condition-state-request=${(ev) => {
conditionStateRequestHandler(ev, this._conditionState);
}}
>
</frigate-card-elements>`
: ``}
${
// Keep message rendering to last to show messages that may have
// been generated during the render.
this._message ? renderMessage(this._message) : ''
}
</div>
<div class="${classMap(mainClasses)}">
${this._cameras === undefined
? until(
(async () => {
await this._loadCameras();
// Don't reset messages as errors may have been generated
// during the camera load.
this._changeView({ resetMessage: false });
return this._render();
})(),
renderProgressIndicator(),
)
: // Always want to call render even if there's a message, to
// ensure live preload is always present (even if not displayed).
this._render()}
${this._getConfig().elements
? // Always show elements to allow for custom menu items (etc.) to
// be present even if a particular view has an error. Elements
// need to render after the main views so it can render 'on top'.
html` <frigate-card-elements
${ref(this._refElements)}
.hass=${this._hass}
.elements=${this._getConfig().elements}
.conditionState=${this._conditionState}
@frigate-card:menu-add=${(e) => {
this._addDynamicMenuButton(e.detail);
}}
@frigate-card:menu-remove=${(e) => {
this._removeDynamicMenuButton(e.detail);
}}
@frigate-card:condition-state-request=${(ev) => {
conditionStateRequestHandler(ev, this._conditionState);
}}
>
</frigate-card-elements>`
: ``}
${
// Keep message rendering to last to show messages that may have
// been generated during the render.
this._message ? renderMessage(this._message) : ''
}
</div>
${!renderMenuAbove ? this._renderMenu() : ''}
</ha-card>`;
+13 -31
View File
@@ -9,21 +9,31 @@
filter: brightness(50%);
}
.container {
div.main {
position: relative;
overflow: auto;
width: 100%;
height: 100%;
margin: auto;
display: flex;
align-items: center;
justify-content: center;
// Need to apply the border radius on the container level, as the ha-card has
// overflow visible in order to allow a submenu to extend beyond the card
// boundary.
border-radius: var(--ha-card-border-radius, 4px);
// Include the borders in the sizing (to keep the triggered warning pulse
// visible in fullscreen).
box-sizing: border-box;
// Hide scrollbar: Firefox
scrollbar-width: none;
// Hide scrollbar: IE and Edge
-ms-overflow-style: none;
}
.container.triggered {
div.main.triggered {
@keyframes warning-pulse {
0% {
border: solid 1px rgba(0,0,0,0);
@@ -38,39 +48,11 @@
animation: warning-pulse 5s infinite;
}
.frigate-card-contents {
width: inherit;
height: inherit;
margin: auto;
overflow: auto;
display: flex;
align-items: center;
justify-content: center;
// Include the borders in the sizing (to keep the triggered warning pulse
// visible in fullscreen).
box-sizing: border-box;
// Hide scrollbar: Firefox
scrollbar-width: none;
// Hide scrollbar: IE and Edge
-ms-overflow-style: none;
}
/* Hide scrollbar for Chrome, Safari and Opera */
.frigate-card-contents::-webkit-scrollbar {
div.main::-webkit-scrollbar {
display: none;
}
/* When forcing aspect ratio absolute positioning is required */
.frigate-card-contents.absolute {
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
}
/* The 'hover' menu mode is styling applied outside of the menu itself */
frigate-card-menu[data-style='hover'] {
z-index: 1;