fix: Camera aspect-ratio should always apply (#2114)

- Closes #2073
This commit is contained in:
Dermot Duffy
2025-07-13 14:56:03 -07:00
committed by GitHub
parent d0bfb97843
commit c3e7cef9cf
29 changed files with 812 additions and 201 deletions
+41 -41
View File
@@ -11,6 +11,7 @@ import { guard } from 'lit/directives/guard.js';
import { createRef, ref, Ref } from 'lit/directives/ref.js';
import { CameraManager } from '../camera-manager/manager';
import { ViewManagerEpoch } from '../card-controller/view/types';
import { MediaProviderDimensionsController } from '../components-lib/media-provider-dimensions-controller';
import { ZoomSettingsObserved } from '../components-lib/zoom/types';
import { handleZoomSettingsObservedEvent } from '../components-lib/zoom/zoom-view-context';
import { CameraConfig } from '../config/schema/cameras';
@@ -19,8 +20,6 @@ import { IMAGE_VIEW_ZOOM_TARGET_SENTINEL } from '../const';
import { HomeAssistant } from '../ha/types';
import imageStyle from '../scss/image.scss';
import { MediaPlayer, MediaPlayerController, MediaPlayerElement } from '../types.js';
import { aspectRatioToString } from '../utils/basic';
import { updateElementStyleFromMediaLayoutConfig } from '../utils/media-layout.js';
import './image-updating-player';
import { resolveImageMode } from './image-updating-player';
import './zoomer.js';
@@ -42,36 +41,29 @@ export class AdvancedCameraCardImage extends LitElement implements MediaPlayer {
@property({ attribute: false })
public imageConfig?: ImageViewConfig;
protected _dimensionsController = new MediaProviderDimensionsController(this);
protected _refImage: Ref<MediaPlayerElement> = createRef();
protected _refContainer: Ref<HTMLElement> = createRef();
public async getMediaPlayerController(): Promise<MediaPlayerController | null> {
await this.updateComplete;
return (await this._refImage.value?.getMediaPlayerController()) ?? null;
}
protected _refImage: Ref<MediaPlayerElement> = createRef();
protected willUpdate(changedProps: PropertyValues): void {
if (changedProps.has('cameraConfig') || changedProps.has('imageConfig')) {
if (
this._dimensionsController.setCameraConfig(
resolveImageMode({
imageConfig: this.imageConfig,
cameraConfig: this.cameraConfig,
}) === 'camera'
) {
updateElementStyleFromMediaLayoutConfig(
this,
this.cameraConfig?.dimensions?.layout,
);
this.style.aspectRatio = aspectRatioToString({
ratio: this.cameraConfig?.dimensions?.aspect_ratio,
});
} else {
updateElementStyleFromMediaLayoutConfig(this);
this.style.removeProperty('aspect-ratio');
}
? this.cameraConfig?.dimensions
: undefined,
);
}
}
protected _useZoomIfRequired(template: TemplateResult): TemplateResult {
protected _renderContainer(template: TemplateResult): TemplateResult {
const zoomTarget = IMAGE_VIEW_ZOOM_TARGET_SENTINEL;
const view = this.viewManagerEpoch?.manager.getView();
const mode = resolveImageMode({
@@ -79,29 +71,33 @@ export class AdvancedCameraCardImage extends LitElement implements MediaPlayer {
cameraConfig: this.cameraConfig,
});
return this.imageConfig?.zoomable
? html` <advanced-camera-card-zoomer
.defaultSettings=${guard(
[this.imageConfig, this.cameraConfig?.dimensions?.layout],
() =>
mode === 'camera' && this.cameraConfig?.dimensions?.layout
? {
pan: this.cameraConfig.dimensions.layout.pan,
zoom: this.cameraConfig.dimensions.layout.zoom,
}
: undefined,
)}
.settings=${view?.context?.zoom?.[zoomTarget]?.requested}
@advanced-camera-card:zoom:change=${(ev: CustomEvent<ZoomSettingsObserved>) =>
handleZoomSettingsObservedEvent(
ev,
this.viewManagerEpoch?.manager,
zoomTarget,
return html`<div class="container" ${ref(this._refContainer)}>
${this.imageConfig?.zoomable
? html`<advanced-camera-card-zoomer
.defaultSettings=${guard(
[this.imageConfig, this.cameraConfig?.dimensions?.layout],
() =>
mode === 'camera' && this.cameraConfig?.dimensions?.layout
? {
pan: this.cameraConfig.dimensions.layout.pan,
zoom: this.cameraConfig.dimensions.layout.zoom,
}
: undefined,
)}
>
${template}
</advanced-camera-card-zoomer>`
: template;
.settings=${view?.context?.zoom?.[zoomTarget]?.requested}
@advanced-camera-card:zoom:change=${(
ev: CustomEvent<ZoomSettingsObserved>,
) =>
handleZoomSettingsObservedEvent(
ev,
this.viewManagerEpoch?.manager,
zoomTarget,
)}
>
${template}
</advanced-camera-card-zoomer>`
: template}
</div>`;
}
protected render(): TemplateResult | void {
@@ -109,7 +105,7 @@ export class AdvancedCameraCardImage extends LitElement implements MediaPlayer {
return;
}
return this._useZoomIfRequired(html`
return this._renderContainer(html`
<advanced-camera-card-image-updating-player
${ref(this._refImage)}
.hass=${this.hass}
@@ -121,6 +117,10 @@ export class AdvancedCameraCardImage extends LitElement implements MediaPlayer {
`);
}
public updated(): void {
this._dimensionsController.setContainer(this._refContainer.value);
}
static get styles(): CSSResultGroup {
return unsafeCSS(imageStyle);
}