Files
advanced-camera-card/src/card-controller/style-manager.ts
T

163 lines
5.3 KiB
TypeScript

import { StyleInfo } from 'lit/directives/style-map';
import { AdvancedCameraCardConfig, configDefaults } from '../config/schema/types';
import { ThemeConfig, ThemeName } from '../config/schema/view';
import { aspectRatioToStyle, setOrRemoveAttribute } from '../utils/basic';
import { View } from '../view/view';
import { CardStyleAPI } from './types';
export class StyleManager {
protected _api: CardStyleAPI;
constructor(api: CardStyleAPI) {
this._api = api;
}
public setExpandedMode(): void {
const card = this._api.getCardElementManager().getElement();
const view = this._api.getViewManager().getView();
// When a new media loads, set the aspect ratio for when the card is
// expanded/popped-up. This is based exclusively on last media content,
// as dimension configuration does not apply in fullscreen or expanded mode.
const lastKnown = this._api.getMediaLoadedInfoManager().getLastKnown();
card.style.setProperty(
'--advanced-camera-card-expand-aspect-ratio',
view?.isAnyMediaView() && lastKnown
? `${lastKnown.width} / ${lastKnown.height}`
: 'unset',
);
// Non-media may have no intrinsic dimensions (or multiple media items in a
// grid) and so we need to explicit request the dialog to use all available
// space.
const isGrid = view?.isGrid();
card.style.setProperty(
'--advanced-camera-card-expand-width',
!isGrid && view?.isAnyMediaView()
? 'none'
: 'var(--advanced-camera-card-expand-max-width)',
);
card.style.setProperty(
'--advanced-camera-card-expand-height',
!isGrid && view?.isAnyMediaView()
? 'none'
: 'var(--advanced-camera-card-expand-max-height)',
);
}
public updateFromConfig(): void {
this.applyTheme();
this._setMinMaxHeight();
this._setPerformance();
this._setDimmable();
}
public applyTheme() {
const themeConfig = this._api.getConfigManager().getConfig()?.view.theme;
if (!themeConfig) {
return;
}
const element = this._api.getCardElementManager().getElement();
const themes = this._getThemeNames(themeConfig);
setOrRemoveAttribute(element, !!themes, 'themes', themes?.join(' '));
if (themeConfig.overrides) {
for (const [key, value] of Object.entries(themeConfig.overrides)) {
element.style.setProperty(key, value);
}
}
}
protected _getThemeNames(themeConfig: ThemeConfig): ThemeName[] | null {
return themeConfig.themes.length
? themeConfig.themes
: configDefaults.view.theme.themes;
}
protected _setDimmable(): void {
const config = this._api.getConfigManager().getConfig();
setOrRemoveAttribute(
this._api.getCardElementManager().getElement(),
!!config?.view.dim,
'dimmable',
);
}
protected _setMinMaxHeight(): void {
const config = this._api.getConfigManager().getConfig();
if (config) {
const card = this._api.getCardElementManager().getElement();
card.style.setProperty('--advanced-camera-card-height', config.dimensions.height);
}
}
protected _setPerformance(): void {
const STYLE_DISABLE_MAP = {
box_shadow: 'none',
border_radius: '0px',
};
const element = this._api.getCardElementManager().getElement();
const performance = this._api.getConfigManager().getCardWideConfig()?.performance;
const styles = performance?.style ?? {};
for (const configKey of Object.keys(styles)) {
const CSSKey = `--advanced-camera-card-css-${configKey.replaceAll('_', '-')}`;
if (styles[configKey] === false) {
element.style.setProperty(CSSKey, STYLE_DISABLE_MAP[configKey]);
} else {
element.style.removeProperty(CSSKey);
}
}
}
protected _isAspectRatioEnforced(
config: AdvancedCameraCardConfig,
view?: View | null,
): boolean {
const aspectRatioMode = config.dimensions.aspect_ratio_mode;
// Do not artifically constrain aspect ratio if:
// - It's fullscreen.
// - It's in expanded mode.
// - Aspect ratio enforcement is disabled.
// - Aspect ratio enforcement is dynamic and it's a media view (i.e. not the
// gallery) or diagnostics / timeline.
return !(
this._api.getFullscreenManager().isInFullscreen() ||
this._api.getExpandManager().isExpanded() ||
aspectRatioMode === 'unconstrained' ||
(aspectRatioMode === 'dynamic' &&
(!view ||
view?.isAnyMediaView() ||
view?.is('timeline') ||
view?.is('diagnostics')))
);
}
/**
* Get the aspect ratio padding required to enforce the aspect ratio (if it is
* required).
* @returns A padding percentage.
*/
public getAspectRatioStyle(): StyleInfo {
const config = this._api.getConfigManager().getConfig();
const view = this._api.getViewManager().getView();
if (config) {
if (!this._isAspectRatioEnforced(config, view)) {
return aspectRatioToStyle();
}
const aspectRatioMode = config.dimensions.aspect_ratio_mode;
const lastKnown = this._api.getMediaLoadedInfoManager().getLastKnown();
if (lastKnown && aspectRatioMode === 'dynamic') {
return aspectRatioToStyle({ ratio: [lastKnown.width, lastKnown.height] });
}
return aspectRatioToStyle({ ratio: config.dimensions.aspect_ratio });
}
return aspectRatioToStyle({ defaultStatic: true });
}
}