bitmovin-player-ui
Version:
Bitmovin Player UI Framework
122 lines (105 loc) • 3.61 kB
text/typescript
import { Container, ContainerConfig } from './Container';
import { UIInstanceManager } from '../UIManager';
import { MetadataLabel, MetadataLabelContent } from './labels/MetadataLabel';
import { PlayerAPI } from 'bitmovin-player';
import { Label } from './labels/Label';
import { Component, ComponentConfig } from './Component';
/**
* Configuration interface for a {@link TitleBar}.
*
* @category Configs
*/
export interface TitleBarConfig extends ContainerConfig {
/**
* Specifies if the title bar should stay hidden when no label contains any text.
* Applies to any label component with an isEmpty() method, not just MetadataLabels.
* Default: false
*/
keepHiddenWithoutMetadata?: boolean;
}
/**
* Displays a title bar containing a label with the title of the video or other contextual messages.
*
* @category Components
*/
export class TitleBar extends Container<TitleBarConfig> {
constructor(config: TitleBarConfig = {}) {
super(config);
this.config = this.mergeConfig(
config,
{
cssClass: 'ui-titlebar',
hidden: true,
keepHiddenWithoutMetadata: false,
components: [
new Container({
components: [new MetadataLabel({ content: MetadataLabelContent.Title })],
cssClasses: ['titlebar-row'],
}),
new Container({
components: [new MetadataLabel({ content: MetadataLabelContent.Description })],
cssClasses: ['titlebar-row'],
}),
],
},
<TitleBarConfig>this.config,
);
}
configure(player: PlayerAPI, uimanager: UIInstanceManager): void {
super.configure(player, uimanager);
const config = this.getConfig();
let shouldBeShown = !this.isHidden();
let hasVisibleText = true;
const checkTextAndUpdateVisibility = () => {
hasVisibleText = this.hasNonEmptyComponents(this.getComponents());
if (this.isShown()) {
if (config.keepHiddenWithoutMetadata && !hasVisibleText) {
this.hide();
}
} else if (shouldBeShown) {
if (!config.keepHiddenWithoutMetadata || hasVisibleText) {
this.show();
}
}
};
// Subscribe to any label-like component's text changes
this.subscribeToTextChanges(this.getComponents(), checkTextAndUpdateVisibility);
uimanager.onControlsShow.subscribe(() => {
shouldBeShown = true;
if (!config.keepHiddenWithoutMetadata || hasVisibleText) {
this.show();
}
});
uimanager.onControlsHide.subscribe(() => {
shouldBeShown = false;
this.hide();
});
checkTextAndUpdateVisibility();
}
private hasNonEmptyComponents(components: Component<ComponentConfig>[]): boolean {
for (const component of components) {
if (hasIsEmpty(component) && !component.isEmpty()) {
return true;
}
if (component instanceof Container) {
if (this.hasNonEmptyComponents(component.getComponents())) {
return true;
}
}
}
return false;
}
private subscribeToTextChanges(components: Component<ComponentConfig>[], onChange: () => void): void {
for (const component of components) {
if (component instanceof Label) {
component.onTextChanged.subscribe(onChange);
}
if (component instanceof Container) {
this.subscribeToTextChanges(component.getComponents(), onChange);
}
}
}
}
function hasIsEmpty(obj: unknown): obj is { isEmpty: () => boolean } {
return typeof obj === 'object' && obj !== null && typeof (obj as any).isEmpty === 'function';
}