diff --git a/assets/skin-modern/images/leaf.svg b/assets/skin-modern/images/leaf.svg
new file mode 100644
index 000000000..f143e91e9
--- /dev/null
+++ b/assets/skin-modern/images/leaf.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/skin-modern/images/toggleOff.svg b/assets/skin-modern/images/toggleOff.svg
new file mode 100644
index 000000000..98254901a
--- /dev/null
+++ b/assets/skin-modern/images/toggleOff.svg
@@ -0,0 +1,17 @@
+
diff --git a/assets/skin-modern/images/toggleOn.svg b/assets/skin-modern/images/toggleOn.svg
new file mode 100644
index 000000000..99b015ab3
--- /dev/null
+++ b/assets/skin-modern/images/toggleOn.svg
@@ -0,0 +1,17 @@
+
diff --git a/package-lock.json b/package-lock.json
index 2d2cd9a2d..e02d7e79e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,7 +13,7 @@
"@types/jest": "^29.5.0",
"@types/jsdom": "^21.1.0",
"autoprefixer": "^10.4.14",
- "bitmovin-player": "^8.109.0",
+ "bitmovin-player": "^8.129.0",
"browser-sync": "^2.29.0",
"browserify": "^17.0.0",
"cssnano": "^5.1.15",
@@ -4502,9 +4502,9 @@
}
},
"node_modules/bitmovin-player": {
- "version": "8.109.0",
- "resolved": "https://registry.npmjs.org/bitmovin-player/-/bitmovin-player-8.109.0.tgz",
- "integrity": "sha512-GhsY2XAtcsarI4TqR+Lc5qXPgvKTW2yL932sHifI1dnYzczGO0vbbYkdG+zP/IidNiov8zJSFl84g+ozUFEbXA==",
+ "version": "8.129.0",
+ "resolved": "https://registry.npmjs.org/bitmovin-player/-/bitmovin-player-8.129.0.tgz",
+ "integrity": "sha512-4/bOVjPRa8MtJDeur1cWs2IjIOn5vg3NOwQMcEms6OwurjcPTPP7AWGahlPl6cPf1X7Y83ce5S+V4yfvoAfBQQ==",
"dev": true
},
"node_modules/bl": {
@@ -23267,9 +23267,9 @@
"dev": true
},
"bitmovin-player": {
- "version": "8.109.0",
- "resolved": "https://registry.npmjs.org/bitmovin-player/-/bitmovin-player-8.109.0.tgz",
- "integrity": "sha512-GhsY2XAtcsarI4TqR+Lc5qXPgvKTW2yL932sHifI1dnYzczGO0vbbYkdG+zP/IidNiov8zJSFl84g+ozUFEbXA==",
+ "version": "8.129.0",
+ "resolved": "https://registry.npmjs.org/bitmovin-player/-/bitmovin-player-8.129.0.tgz",
+ "integrity": "sha512-4/bOVjPRa8MtJDeur1cWs2IjIOn5vg3NOwQMcEms6OwurjcPTPP7AWGahlPl6cPf1X7Y83ce5S+V4yfvoAfBQQ==",
"dev": true
},
"bl": {
diff --git a/package.json b/package.json
index c5cd04806..5a63b78ab 100644
--- a/package.json
+++ b/package.json
@@ -27,7 +27,7 @@
"@types/jest": "^29.5.0",
"@types/jsdom": "^21.1.0",
"autoprefixer": "^10.4.14",
- "bitmovin-player": "^8.109.0",
+ "bitmovin-player": "^8.129.0",
"browser-sync": "^2.29.0",
"browserify": "^17.0.0",
"cssnano": "^5.1.15",
diff --git a/src/scss/skin-modern/_skin.scss b/src/scss/skin-modern/_skin.scss
index bb0d5c21b..ae1890277 100644
--- a/src/scss/skin-modern/_skin.scss
+++ b/src/scss/skin-modern/_skin.scss
@@ -10,6 +10,7 @@
@import 'components/fullscreentogglebutton';
@import 'components/vrtogglebutton';
@import 'components/volumetogglebutton';
+@import 'components/ecomodetogglebutton';
@import 'components/seekbar';
@import 'components/watermark';
@import 'components/hugeplaybacktogglebutton';
diff --git a/src/scss/skin-modern/components/_ecomodetogglebutton.scss b/src/scss/skin-modern/components/_ecomodetogglebutton.scss
new file mode 100644
index 000000000..bb70a2cf2
--- /dev/null
+++ b/src/scss/skin-modern/components/_ecomodetogglebutton.scss
@@ -0,0 +1,35 @@
+@import '../variables';
+@import '../mixins';
+
+.#{$prefix}-ui-ecomodetogglebutton {
+ @extend %ui-button;
+ height: 1em;
+ min-width: 5em;
+
+ &:hover {
+ @include svg-icon-shadow;
+ }
+
+ &.#{$prefix}-on {
+ background-image: url('../../assets/skin-modern/images/toggleOn.svg');
+ background-position: 20px center;
+ background-size: 45% auto;
+ margin-left: 2%;
+ }
+
+ &.#{$prefix}-off {
+ background-image: url('../../assets/skin-modern/images/toggleOff.svg');
+ background-position: 20px center;
+ background-size: 45% auto;
+ }
+}
+
+#ecomodelabel::before {
+ background-image: url('../../assets/skin-modern/images/leaf.svg');
+ background-repeat: no-repeat;
+ background-size: 1.7em auto;
+ content: ' ';
+ display: inline-block;
+ height: 1.5em;
+ width: 2em;
+}
diff --git a/src/scss/skin-modern/components/_label.scss b/src/scss/skin-modern/components/_label.scss
index 70e26540d..2d1865357 100644
--- a/src/scss/skin-modern/components/_label.scss
+++ b/src/scss/skin-modern/components/_label.scss
@@ -12,3 +12,10 @@
.#{$prefix}-ui-label {
@extend %ui-label;
}
+
+.#{$prefix}-ui-label-savedEnergy {
+ @extend %ui-label;
+ font-size: 0.8em;
+ color: #1fabe2;
+ margin-left: 2.2em;
+}
diff --git a/src/ts/components/ecomodecontainer.ts b/src/ts/components/ecomodecontainer.ts
new file mode 100644
index 000000000..3b7829de9
--- /dev/null
+++ b/src/ts/components/ecomodecontainer.ts
@@ -0,0 +1,126 @@
+import { PlayerAPI, SegmentPlaybackEvent, VideoQuality } from 'bitmovin-player';
+import { i18n } from '../localization/i18n';
+import { Container, ContainerConfig } from './container';
+import { EcoModeToggleButton } from './ecomodetogglebutton';
+import { Label, LabelConfig } from './label';
+import { SettingsPanelItem } from './settingspanelitem';
+
+export class EcoModeContainer extends Container {
+ private ecoModeSavedEmissionsItem: SettingsPanelItem;
+ private ecoModeToggleButtonItem: SettingsPanelItem;
+ private emissionsSavedLabel: Label;
+ private savedEmissons = 0;
+ private currentEnergyEmission: number;
+
+ constructor(config: ContainerConfig = {}) {
+ super(config);
+
+ const ecoModeToggleButton = new EcoModeToggleButton();
+ const labelEcoMode = new Label({
+ text: i18n.getLocalizer('ecoMode.title'),
+ for: ecoModeToggleButton.getConfig().id,
+ id: 'ecomodelabel',
+ });
+ this.emissionsSavedLabel = new Label({
+ text: `${this.savedEmissons.toFixed(4)} gCO2`,
+ cssClass: 'ui-label-savedEnergy',
+ });
+
+ this.ecoModeToggleButtonItem = new SettingsPanelItem(labelEcoMode, ecoModeToggleButton);
+ this.ecoModeSavedEmissionsItem = new SettingsPanelItem('Saved Emissions', this.emissionsSavedLabel, {
+ hidden: true,
+ });
+
+ this.addComponent(this.ecoModeToggleButtonItem);
+ this.addComponent(this.ecoModeSavedEmissionsItem);
+
+ ecoModeToggleButton.onToggleOn.subscribe(() => {
+ this.ecoModeSavedEmissionsItem.show();
+ this.onToggleCallback();
+ });
+
+ ecoModeToggleButton.onToggleOff.subscribe(() => {
+ this.ecoModeSavedEmissionsItem.hide();
+ this.onToggleCallback();
+ });
+ }
+
+ private onToggleCallback: () => void;
+
+ public setOnToggleCallback(callback: () => void) {
+ this.onToggleCallback = callback;
+ }
+
+ configure(player: PlayerAPI): void {
+ player.on(player.exports.PlayerEvent.SegmentPlayback, (segment: SegmentPlaybackEvent) => {
+ if (!segment.mimeType.includes('video')) {
+ return;
+ }
+
+ const { height, width, bitrate, frameRate } = segment.mediaInfo;
+ const {
+ height: maxHeight,
+ bitrate: maxBitrate,
+ width: maxWidth,
+ } = this.getMaxQualityAvailable(player.getAvailableVideoQualities());
+
+ const currentEnergyKwh = this.calculateEnergyConsumption(frameRate, height, width, bitrate, segment.duration);
+
+ const maxEnergyKwh = this.calculateEnergyConsumption(
+ frameRate,
+ maxHeight,
+ maxWidth,
+ maxBitrate,
+ segment.duration,
+ );
+
+ if (this.ecoModeSavedEmissionsItem.isShown()) {
+ this.updateSavedEmissions(currentEnergyKwh, maxEnergyKwh, this.emissionsSavedLabel);
+ }
+ });
+ }
+
+ updateSavedEmissions(
+ currentEnergyConsuption: number,
+ maxEnergyConsuption: number,
+ emissionsSavedLabel: Label,
+ ) {
+ // 475 is the average carbon intensity of all countries in gCO2/kWh
+ const averageCarbonIntensity = 475;
+
+ this.currentEnergyEmission = currentEnergyConsuption * averageCarbonIntensity;
+ const maxEnergyEmisson = maxEnergyConsuption * averageCarbonIntensity;
+ this.savedEmissons += maxEnergyEmisson - this.currentEnergyEmission;
+ emissionsSavedLabel.setText(this.savedEmissons.toFixed(4) + ' gCO2');
+ }
+
+ /**
+ * The calculations are based on the following paper: https://arxiv.org/pdf/2210.05444.pdf
+ */
+ calculateEnergyConsumption(fps: number, height: number, width: number, bitrate: number, duration: number): number {
+ const fpsWeight = 0.035;
+ const pixeldWeight = 5.76e-9;
+ const birateWeight = 6.97e-6;
+ const constantOffset = 8.52;
+ const bitrateInternetWeight = 3.24e-5;
+ const internetConnectionOffset = 1.15;
+ const videoCodec = 4.16;
+
+ const energyConsumptionW =
+ fpsWeight * fps +
+ pixeldWeight * height * width +
+ (birateWeight + bitrateInternetWeight) * (bitrate / 1000) +
+ videoCodec +
+ constantOffset +
+ internetConnectionOffset;
+
+ // Convert energy consumption from Watts (W) to Kilowatt-hours (kWh) for the given time duration of the segment
+ const energyConsumptionKwh = (energyConsumptionW * duration) / 3.6e6;
+
+ return energyConsumptionKwh;
+ }
+ getMaxQualityAvailable(availableVideoQualities: VideoQuality[]) {
+ const sortedQualities = availableVideoQualities.sort((a, b) => a.bitrate - b.bitrate);
+ return sortedQualities[sortedQualities.length - 1];
+ }
+}
diff --git a/src/ts/components/ecomodetogglebutton.ts b/src/ts/components/ecomodetogglebutton.ts
new file mode 100644
index 000000000..7f1d90fc1
--- /dev/null
+++ b/src/ts/components/ecomodetogglebutton.ts
@@ -0,0 +1,86 @@
+import { ToggleButton, ToggleButtonConfig } from './togglebutton';
+import { UIInstanceManager } from '../uimanager';
+import { DynamicAdaptationConfig, PlayerAPI, VideoQualityChangedEvent } from 'bitmovin-player';
+import { i18n } from '../localization/i18n';
+
+export class EcoModeToggleButton extends ToggleButton {
+ private adaptationConfig: DynamicAdaptationConfig;
+
+ constructor(config: ToggleButtonConfig = {}) {
+ super(config);
+
+ const defaultConfig: ToggleButtonConfig = {
+ text: i18n.getLocalizer('ecoMode'),
+ cssClass: 'ui-ecomodetogglebutton',
+ onClass: 'on',
+ offClass: 'off',
+ ariaLabel: i18n.getLocalizer('ecoMode'),
+ };
+
+ this.config = this.mergeConfig(config, defaultConfig, this.config);
+ }
+
+ configure(player: PlayerAPI, uimanager: UIInstanceManager): void {
+ super.configure(player, uimanager);
+
+ if (this.areAdaptationApisAvailable(player)) {
+ this.onClick.subscribe(() => {
+ this.toggle();
+ });
+
+ this.onToggleOn.subscribe(() => {
+ this.enableEcoMode(player);
+ player.setVideoQuality('auto');
+ });
+
+ this.onToggleOff.subscribe(() => {
+ this.disableEcoMode(player);
+ });
+
+ player.on(player.exports.PlayerEvent.VideoQualityChanged, (quality: VideoQualityChangedEvent) => {
+ if (quality.targetQuality.id !== 'auto') {
+ this.off();
+ this.disableEcoMode(player);
+ }
+ });
+ } else {
+ super.disable();
+ }
+
+ }
+
+ private areAdaptationApisAvailable(player: PlayerAPI): boolean {
+ const isGetConfigAvailable = Boolean(player.adaptation.getConfig && typeof player.adaptation.getConfig === 'function');
+ const isSetConfigAvailable = Boolean(player.adaptation.setConfig && typeof player.adaptation.setConfig === 'function');
+
+ return Boolean(player.adaptation && isGetConfigAvailable && isSetConfigAvailable);
+ }
+
+ enableEcoMode(player: PlayerAPI): void {
+ this.adaptationConfig = player.adaptation.getConfig();
+ const codec = player.getAvailableVideoQualities()[0].codec;
+
+ if (codec.includes('avc')) {
+ player.adaptation.setConfig({
+ resolution: { maxSelectableVideoHeight: 720 },
+ limitToPlayerSize: true,
+ });
+ }
+ if (codec.includes('hvc') || codec.includes('hev')) {
+ player.adaptation.setConfig({
+ resolution: { maxSelectableVideoHeight: 1080 },
+ limitToPlayerSize: true,
+ });
+ }
+ if (codec.includes('av1') || codec.includes('av01')) {
+ player.adaptation.setConfig({
+ resolution: { maxSelectableVideoHeight: 1440 },
+ limitToPlayerSize: true,
+ });
+ }
+ }
+
+ disableEcoMode(player: PlayerAPI): void {
+ player.adaptation.setConfig(this.adaptationConfig);
+ }
+}
diff --git a/src/ts/localization/i18n.ts b/src/ts/localization/i18n.ts
index aef22f73c..2980dff92 100644
--- a/src/ts/localization/i18n.ts
+++ b/src/ts/localization/i18n.ts
@@ -87,6 +87,8 @@ interface Vocabulary {
'seekBar.value': string;
'seekBar.timeshift': string;
'seekBar.durationText': string;
+ 'ecoMode': string;
+ 'ecoMode.title': string;
}
export type CustomVocabulary = V & Partial;
diff --git a/src/ts/localization/languages/de.json b/src/ts/localization/languages/de.json
index 48348d44a..f8fe68b80 100644
--- a/src/ts/localization/languages/de.json
+++ b/src/ts/localization/languages/de.json
@@ -53,5 +53,7 @@
"seekBar.timeshift": "Timeshift",
"seekBar.durationText": "aus",
"quickseek.forward": "Vor",
- "quickseek.rewind": "Zurück"
+ "quickseek.rewind": "Zurück",
+ "ecoMode": "ecoMode",
+ "ecoMode.title":"Eco Mode"
}
diff --git a/src/ts/localization/languages/en.json b/src/ts/localization/languages/en.json
index 5c570b225..ffc1167dc 100644
--- a/src/ts/localization/languages/en.json
+++ b/src/ts/localization/languages/en.json
@@ -52,6 +52,8 @@
"vr" : "VR",
"off": "off",
"auto": "auto",
+ "ecoMode": "ecoMode",
+ "ecoMode.title":"Eco Mode",
"back" : "Back",
"reset": "Reset",
"replay": "Replay",
diff --git a/src/ts/localization/languages/es.json b/src/ts/localization/languages/es.json
index 9fa97a53f..22224d616 100644
--- a/src/ts/localization/languages/es.json
+++ b/src/ts/localization/languages/es.json
@@ -52,6 +52,8 @@
"vr" : "VR",
"off": "off",
"auto": "auto",
+ "ecoMode": "ecoMode",
+ "ecoMode.title": "Eco Mode",
"back" : "Atrás",
"reset": "Reiniciar",
"replay": "Rebobinar",
diff --git a/src/ts/uiconfig.ts b/src/ts/uiconfig.ts
index b0ae3d713..7fb5157cc 100644
--- a/src/ts/uiconfig.ts
+++ b/src/ts/uiconfig.ts
@@ -121,4 +121,8 @@ export interface UIConfig {
* If set to true, prevents the UI from using `localStorage`.
*/
disableStorageApi?: boolean;
+ /**
+ * Specifies if the `EcoModeToggleButton` should be displayed within the `SettingsPanel`
+ */
+ ecoMode?: boolean;
}
diff --git a/src/ts/uifactory.ts b/src/ts/uifactory.ts
index 78cb36c67..3e1266a09 100644
--- a/src/ts/uifactory.ts
+++ b/src/ts/uifactory.ts
@@ -11,7 +11,7 @@ import { SettingsPanelPageOpenButton } from './components/settingspanelpageopenb
import { SubtitleSettingsLabel } from './components/subtitlesettings/subtitlesettingslabel';
import { SubtitleSelectBox } from './components/subtitleselectbox';
import { ControlBar } from './components/controlbar';
-import { Container } from './components/container';
+import { Container, ContainerConfig } from './components/container';
import { PlaybackTimeLabel, PlaybackTimeLabelMode } from './components/playbacktimelabel';
import { SeekBar } from './components/seekbar';
import { SeekBarLabel } from './components/seekbarlabel';
@@ -50,9 +50,9 @@ import { AudioTrackListBox } from './components/audiotracklistbox';
import { SpatialNavigation } from './spatialnavigation/spatialnavigation';
import { RootNavigationGroup } from './spatialnavigation/rootnavigationgroup';
import { ListNavigationGroup, ListOrientation } from './spatialnavigation/ListNavigationGroup';
+import { EcoModeContainer } from './components/ecomodecontainer';
export namespace UIFactory {
-
export function buildDefaultUI(player: PlayerAPI, config: UIConfig = {}): UIManager {
return UIFactory.buildModernUI(player, config);
}
@@ -69,22 +69,35 @@ export namespace UIFactory {
return UIFactory.buildModernTvUI(player, config);
}
- export function modernUI() {
+ export function modernUI(config: UIConfig) {
let subtitleOverlay = new SubtitleOverlay();
- let mainSettingsPanelPage = new SettingsPanelPage({
- components: [
- new SettingsPanelItem(i18n.getLocalizer('settings.video.quality'), new VideoQualitySelectBox()),
- new SettingsPanelItem(i18n.getLocalizer('speed'), new PlaybackSpeedSelectBox()),
- new SettingsPanelItem(i18n.getLocalizer('settings.audio.track'), new AudioTrackSelectBox()),
- new SettingsPanelItem(i18n.getLocalizer('settings.audio.quality'), new AudioQualitySelectBox()),
- ],
+ let mainSettingsPanelPage: SettingsPanelPage;
+
+ const components: Container[] = [
+ new SettingsPanelItem(i18n.getLocalizer('settings.video.quality'), new VideoQualitySelectBox()),
+ new SettingsPanelItem(i18n.getLocalizer('speed'), new PlaybackSpeedSelectBox()),
+ new SettingsPanelItem(i18n.getLocalizer('settings.audio.track'), new AudioTrackSelectBox()),
+ new SettingsPanelItem(i18n.getLocalizer('settings.audio.quality'), new AudioQualitySelectBox()),
+ ];
+
+ if (config.ecoMode) {
+ const ecoModeContainer = new EcoModeContainer();
+
+ ecoModeContainer.setOnToggleCallback(() => {
+ // forces the browser to re-calculate the height of the settings panel when adding/removing elements
+ settingsPanel.getDomElement().css({ width: '', height: '' });
+ });
+
+ components.unshift(ecoModeContainer);
+ }
+
+ mainSettingsPanelPage = new SettingsPanelPage({
+ components,
});
let settingsPanel = new SettingsPanel({
- components: [
- mainSettingsPanelPage,
- ],
+ components: [mainSettingsPanelPage],
hidden: true,
});
@@ -112,7 +125,8 @@ export namespace UIFactory {
{
role: 'menubar',
},
- ));
+ ),
+ );
settingsPanel.addComponent(subtitleSettingsPanelPage);
@@ -121,9 +135,15 @@ export namespace UIFactory {
settingsPanel,
new Container({
components: [
- new PlaybackTimeLabel({ timeLabelMode: PlaybackTimeLabelMode.CurrentTime, hideInLivePlayback: true }),
+ new PlaybackTimeLabel({
+ timeLabelMode: PlaybackTimeLabelMode.CurrentTime,
+ hideInLivePlayback: true,
+ }),
new SeekBar({ label: new SeekBarLabel() }),
- new PlaybackTimeLabel({ timeLabelMode: PlaybackTimeLabelMode.TotalTime, cssClasses: ['text-right'] }),
+ new PlaybackTimeLabel({
+ timeLabelMode: PlaybackTimeLabelMode.TotalTime,
+ cssClasses: ['text-right'],
+ }),
],
cssClasses: ['controlbar-top'],
}),
@@ -173,10 +193,7 @@ export namespace UIFactory {
new AdClickOverlay(),
new PlaybackToggleOverlay(),
new Container({
- components: [
- new AdMessageLabel({ text: i18n.getLocalizer('ads.remainingTime')}),
- new AdSkipButton(),
- ],
+ components: [new AdMessageLabel({ text: i18n.getLocalizer('ads.remainingTime') }), new AdSkipButton()],
cssClass: 'ui-ads-status',
}),
new ControlBar({
@@ -217,9 +234,7 @@ export namespace UIFactory {
});
let settingsPanel = new SettingsPanel({
- components: [
- mainSettingsPanelPage,
- ],
+ components: [mainSettingsPanelPage],
hidden: true,
pageTransitionAnimation: false,
hideDelay: -1,
@@ -249,7 +264,8 @@ export namespace UIFactory {
{
role: 'menubar',
},
- ));
+ ),
+ );
settingsPanel.addComponent(subtitleSettingsPanelPage);
@@ -260,9 +276,15 @@ export namespace UIFactory {
components: [
new Container({
components: [
- new PlaybackTimeLabel({ timeLabelMode: PlaybackTimeLabelMode.CurrentTime, hideInLivePlayback: true }),
+ new PlaybackTimeLabel({
+ timeLabelMode: PlaybackTimeLabelMode.CurrentTime,
+ hideInLivePlayback: true,
+ }),
new SeekBar({ label: new SeekBarLabel() }),
- new PlaybackTimeLabel({ timeLabelMode: PlaybackTimeLabelMode.TotalTime, cssClasses: ['text-right'] }),
+ new PlaybackTimeLabel({
+ timeLabelMode: PlaybackTimeLabelMode.TotalTime,
+ cssClasses: ['text-right'],
+ }),
],
cssClasses: ['controlbar-top'],
}),
@@ -317,10 +339,7 @@ export namespace UIFactory {
],
}),
new Container({
- components: [
- new AdMessageLabel({ text: 'Ad: {remainingTime} secs' }),
- new AdSkipButton(),
- ],
+ components: [new AdMessageLabel({ text: 'Ad: {remainingTime} secs' }), new AdSkipButton()],
cssClass: 'ui-ads-status',
}),
],
@@ -339,9 +358,15 @@ export namespace UIFactory {
components: [
new Container({
components: [
- new PlaybackTimeLabel({ timeLabelMode: PlaybackTimeLabelMode.CurrentTime, hideInLivePlayback: true }),
+ new PlaybackTimeLabel({
+ timeLabelMode: PlaybackTimeLabelMode.CurrentTime,
+ hideInLivePlayback: true,
+ }),
new SeekBar({ smoothPlaybackPositionUpdateIntervalMs: -1 }),
- new PlaybackTimeLabel({ timeLabelMode: PlaybackTimeLabelMode.TotalTime, cssClasses: ['text-right'] }),
+ new PlaybackTimeLabel({
+ timeLabelMode: PlaybackTimeLabelMode.TotalTime,
+ cssClasses: ['text-right'],
+ }),
],
cssClasses: ['controlbar-top'],
}),
@@ -372,43 +397,64 @@ export namespace UIFactory {
// show smallScreen UI only on mobile/handheld devices
let smallScreenSwitchWidth = 600;
- return new UIManager(player, [{
- ui: modernSmallScreenAdsUI(),
- condition: (context: UIConditionContext) => {
- return context.isMobile && context.documentWidth < smallScreenSwitchWidth && context.isAd
- && context.adRequiresUi;
- },
- }, {
- ui: modernAdsUI(),
- condition: (context: UIConditionContext) => {
- return context.isAd && context.adRequiresUi;
- },
- }, {
- ui: modernSmallScreenUI(),
- condition: (context: UIConditionContext) => {
- return !context.isAd && !context.adRequiresUi && context.isMobile
- && context.documentWidth < smallScreenSwitchWidth;
- },
- }, {
- ui: modernUI(),
- condition: (context: UIConditionContext) => {
- return !context.isAd && !context.adRequiresUi;
- },
- }], config);
+ return new UIManager(
+ player,
+ [
+ {
+ ui: modernSmallScreenAdsUI(),
+ condition: (context: UIConditionContext) => {
+ return (
+ context.isMobile && context.documentWidth < smallScreenSwitchWidth && context.isAd && context.adRequiresUi
+ );
+ },
+ },
+ {
+ ui: modernAdsUI(),
+ condition: (context: UIConditionContext) => {
+ return context.isAd && context.adRequiresUi;
+ },
+ },
+ {
+ ui: modernSmallScreenUI(),
+ condition: (context: UIConditionContext) => {
+ return (
+ !context.isAd &&
+ !context.adRequiresUi &&
+ context.isMobile &&
+ context.documentWidth < smallScreenSwitchWidth
+ );
+ },
+ },
+ {
+ ui: modernUI(config),
+ condition: (context: UIConditionContext) => {
+ return !context.isAd && !context.adRequiresUi;
+ },
+ },
+ ],
+ config,
+ );
}
export function buildModernSmallScreenUI(player: PlayerAPI, config: UIConfig = {}): UIManager {
- return new UIManager(player, [{
- ui: modernSmallScreenAdsUI(),
- condition: (context: UIConditionContext) => {
- return context.isAd && context.adRequiresUi;
- },
- }, {
- ui: modernSmallScreenUI(),
- condition: (context: UIConditionContext) => {
- return !context.isAd && !context.adRequiresUi;
- },
- }], config);
+ return new UIManager(
+ player,
+ [
+ {
+ ui: modernSmallScreenAdsUI(),
+ condition: (context: UIConditionContext) => {
+ return context.isAd && context.adRequiresUi;
+ },
+ },
+ {
+ ui: modernSmallScreenUI(),
+ condition: (context: UIConditionContext) => {
+ return !context.isAd && !context.adRequiresUi;
+ },
+ },
+ ],
+ config,
+ );
}
export function buildModernCastReceiverUI(player: PlayerAPI, config: UIConfig = {}): UIManager {
@@ -416,9 +462,15 @@ export namespace UIFactory {
}
export function buildModernTvUI(player: PlayerAPI, config: UIConfig = {}): UIManager {
- return new UIManager(player, [{
+ return new UIManager(
+ player,
+ [
+ {
...modernTvUI(),
- }], config);
+ },
+ ],
+ config,
+ );
}
export function modernTvUI() {
@@ -426,9 +478,7 @@ export namespace UIFactory {
const subtitleListPanel = new SettingsPanel({
components: [
new SettingsPanelPage({
- components: [
- new SettingsPanelItem(null, subtitleListBox),
- ],
+ components: [new SettingsPanelItem(null, subtitleListBox)],
}),
],
hidden: true,
@@ -438,9 +488,7 @@ export namespace UIFactory {
const audioTrackListPanel = new SettingsPanel({
components: [
new SettingsPanelPage({
- components: [
- new SettingsPanelItem(null, audioTrackListBox),
- ],
+ components: [new SettingsPanelItem(null, audioTrackListBox)],
}),
],
hidden: true,
@@ -470,9 +518,15 @@ export namespace UIFactory {
components: [
new Container({
components: [
- new PlaybackTimeLabel({ timeLabelMode: PlaybackTimeLabelMode.CurrentTime, hideInLivePlayback: true }),
+ new PlaybackTimeLabel({
+ timeLabelMode: PlaybackTimeLabelMode.CurrentTime,
+ hideInLivePlayback: true,
+ }),
seekBar,
- new PlaybackTimeLabel({ timeLabelMode: PlaybackTimeLabelMode.RemainingTime, cssClasses: ['text-right'] }),
+ new PlaybackTimeLabel({
+ timeLabelMode: PlaybackTimeLabelMode.RemainingTime,
+ cssClasses: ['text-right'],
+ }),
],
cssClasses: ['controlbar-top'],
}),