From 5ff17c45edb96b91e803beeaf431f7d790707249 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Fri, 6 Dec 2024 10:28:14 -0700 Subject: [PATCH 01/23] refactor the modern settings panel to add support for subtitle settings as well --- src/scss/demo.scss | 8 + .../components/_settingspanelpage.scss | 113 ++++++-- .../_settingspanelpagebackbutton.scss | 54 ++-- .../_settingspanelpageopenbutton.scss | 4 +- src/ts/components/button.ts | 3 +- src/ts/components/component.ts | 2 +- src/ts/components/ecomodecontainer.ts | 12 +- src/ts/components/listselector.ts | 4 +- src/ts/components/modernsettingspanel.ts | 51 +--- src/ts/components/modernsettingspanelitem.ts | 244 ++++++++---------- src/ts/components/modernsettingspanelpage.ts | 16 +- .../modernsettingspanelselectoption.ts | 50 ++++ src/ts/components/seekbar.ts | 2 + src/ts/components/settingspanel.ts | 18 +- src/ts/components/settingspanelitem.ts | 30 ++- src/ts/components/settingspanelpage.ts | 6 +- .../subtitlesettingselectbox.ts | 2 +- .../subtitlesettings/subtitlesettingslabel.ts | 33 +-- .../subtitlesettingspanelpage.ts | 103 +++++--- src/ts/demofactory.ts | 10 +- src/ts/uifactory.ts | 149 ++++++----- 21 files changed, 512 insertions(+), 402 deletions(-) create mode 100644 src/ts/components/modernsettingspanelselectoption.ts diff --git a/src/scss/demo.scss b/src/scss/demo.scss index 74e5c9c49..a373a0980 100644 --- a/src/scss/demo.scss +++ b/src/scss/demo.scss @@ -6,3 +6,11 @@ body { #player { position: relative; } + +.player-wrapper { + &.portrait { + aspect-ratio: 9/19; + margin: auto; + width: 300px; + } +} diff --git a/src/scss/skin-super-modern/components/_settingspanelpage.scss b/src/scss/skin-super-modern/components/_settingspanelpage.scss index d6af522f8..64a902ff7 100644 --- a/src/scss/skin-super-modern/components/_settingspanelpage.scss +++ b/src/scss/skin-super-modern/components/_settingspanelpage.scss @@ -15,7 +15,6 @@ font-weight: 500; margin: 0; text-align: justify; - width: 45%; } &.#{$prefix}-ui-label-setting-selected-option { @@ -40,32 +39,6 @@ font-weight: normal; } - &.#{$prefix}-heading { - &::before { - background-image: url('../../assets/skin-super-modern/images/angle-left.svg'); - background-repeat: no-repeat; - background-size: 1.5em auto; - content: ' '; - display: inline-block; - height: 1.5em; - vertical-align: -.4em; - width: 1.5em; - } - } - - &.#{$prefix}-selected { - &::before { - background-image: url('../../assets/skin-super-modern/images/check.svg'); - background-repeat: no-repeat; - background-size: 1.5em auto; - content: ' '; - display: inline-block; - height: 1.5em; - vertical-align: -.4em; - width: 1.5em; - } - } - // Controls (e.g. selectbox) &.#{$prefix}-ui-selectbox { margin-left: 10%; @@ -74,7 +47,6 @@ } .#{$prefix}-ui-settings-panel-item { - //height: 20px; padding: .5em .7em; white-space: nowrap; @@ -93,6 +65,91 @@ width: 100%; } } + + // TODO: de-duplicate this + .#{$prefix}-ui-settings-panel-item-select-option { + padding: .5em .7em; + white-space: nowrap; + + &:hover { + background-color: transparentize($color-item-hover, .15); + } + + &.#{$prefix}-hidden { + display: none; + } + + .#{$prefix}-container-wrapper { + align-items: center; + display: flex; + height: 100%; + width: 100%; + } + + &.#{$prefix}-selected { + .#{$prefix}-ui-label { + &::before { + background-image: url('../../assets/skin-super-modern/images/check.svg'); + background-repeat: no-repeat; + background-size: 1.5em auto; + content: ' '; + display: inline-block; + height: 1.5em; + vertical-align: -.4em; + width: 1.5em; + } + } + } + } + + // TODO: de-duplicate this + .#{$prefix}-ui-settings-panel-item-back { + @extend %ui-button; + + border-bottom: 1px solid transparentize($color-item-hover, .15);; + padding: .5em .7em; + white-space: nowrap; + + &:active { + transform: unset; + } + + &:hover { + background-color: transparentize($color-item-hover, .15); + } + + &.#{$prefix}-hidden { + display: none; + } + + //.#{$prefix}-container-wrapper { + align-items: center; + display: flex; + height: 100%; + width: 100%; + //} + + .#{$prefix}-label { + // TODO: de-duplicate this with the -ui-label from above + display: inline-block; + font-size: .8em; + font-weight: 500; + margin: 0; + text-align: justify; + width: 45%; + + &::before { + background-image: url('../../assets/skin-super-modern/images/angle-left.svg'); + background-repeat: no-repeat; + background-size: 1.5em auto; + content: ' '; + display: inline-block; + height: 1.5em; + vertical-align: -.4em; + width: 1.5em; + } + } + } } .#{$prefix}-ui-settings-panel-page { diff --git a/src/scss/skin-super-modern/components/_settingspanelpagebackbutton.scss b/src/scss/skin-super-modern/components/_settingspanelpagebackbutton.scss index a5a1a4e87..a6bc3610d 100644 --- a/src/scss/skin-super-modern/components/_settingspanelpagebackbutton.scss +++ b/src/scss/skin-super-modern/components/_settingspanelpagebackbutton.scss @@ -1,29 +1,29 @@ @import '../variables'; -%ui-settingspanelpagebackbutton { - @extend %ui-button; - - font-size: .8em; - position: relative; - width: 8em; - - .#{$prefix}-label { - display: inline-block; - - &::before { - border-bottom: .2em solid $color-primary; - border-left: .2em solid $color-primary; - content: ''; - height: .6em; - margin-left: -.8em; - position: absolute; - top: .6em; - transform: rotate(45deg); - width: .6em; - } - } -} - -.#{$prefix}-ui-settingspanelpagebackbutton { - @extend %ui-settingspanelpagebackbutton; -} +//%ui-settingspanelpagebackbutton { +// @extend %ui-button; +// +// font-size: .8em; +// position: relative; +// width: 8em; +// +// .#{$prefix}-label { +// display: inline-block; +// +// &::before { +// border-bottom: .2em solid $color-primary; +// border-left: .2em solid $color-primary; +// content: ''; +// height: .6em; +// margin-left: -.8em; +// position: absolute; +// top: .6em; +// transform: rotate(45deg); +// width: .6em; +// } +// } +//} +// +//.#{$prefix}-ui-settingspanelpagebackbutton { +// @extend %ui-settingspanelpagebackbutton; +//} diff --git a/src/scss/skin-super-modern/components/_settingspanelpageopenbutton.scss b/src/scss/skin-super-modern/components/_settingspanelpageopenbutton.scss index cc517ab2d..ab056005d 100644 --- a/src/scss/skin-super-modern/components/_settingspanelpageopenbutton.scss +++ b/src/scss/skin-super-modern/components/_settingspanelpageopenbutton.scss @@ -6,8 +6,8 @@ background-image: url('../../assets/skin-super-modern/images/setting.svg'); max-height: .8em; - padding: .5em 0; - vertical-align: bottom; + //padding: .5em 0; + //vertical-align: bottom; &:hover { @include svg-icon-shadow; diff --git a/src/ts/components/button.ts b/src/ts/components/button.ts index d5fe59f16..210039f98 100644 --- a/src/ts/components/button.ts +++ b/src/ts/components/button.ts @@ -71,7 +71,8 @@ export class Button extends Component { }).html(i18n.performLocalization(this.config.text))); // Listen for the click event on the button element and trigger the corresponding event on the button component - buttonElement.on('click', () => { + buttonElement.on('click', (e) => { + e.stopPropagation(); this.onClickEvent(); }); diff --git a/src/ts/components/component.ts b/src/ts/components/component.ts index 50cfa79f6..dc3e9fd46 100644 --- a/src/ts/components/component.ts +++ b/src/ts/components/component.ts @@ -339,7 +339,7 @@ export class Component { * @param base configuration inherited from a superclass * @returns {Config} */ - protected mergeConfig(config: Config, defaults: Config, base: Config): Config { + protected mergeConfig(config: Config, defaults: Partial, base: Config): Config { // Extend default config with supplied config let merged = Object.assign({}, base, defaults, config); diff --git a/src/ts/components/ecomodecontainer.ts b/src/ts/components/ecomodecontainer.ts index 02ea81ead..dac5dc589 100644 --- a/src/ts/components/ecomodecontainer.ts +++ b/src/ts/components/ecomodecontainer.ts @@ -3,14 +3,14 @@ import { i18n } from '../localization/i18n'; import { Container, ContainerConfig } from './container'; import { EcoModeToggleButton } from './ecomodetogglebutton'; import { Label, LabelConfig } from './label'; -import { SettingsPanelItem } from './settingspanelitem'; +import { SettingsPanelItem, SettingsPanelItemConfig } from './settingspanelitem'; /** * @category Containers */ export class EcoModeContainer extends Container { - private ecoModeSavedEmissionsItem: SettingsPanelItem; - private ecoModeToggleButtonItem: SettingsPanelItem; + private ecoModeSavedEmissionsItem: SettingsPanelItem; + private ecoModeToggleButtonItem: SettingsPanelItem; private emissionsSavedLabel: Label; private savedEmissons = 0; private currentEnergyEmission: number; @@ -29,8 +29,10 @@ export class EcoModeContainer extends Container { cssClass: 'ui-label-savedEnergy', }); - this.ecoModeToggleButtonItem = new SettingsPanelItem(labelEcoMode, ecoModeToggleButton); - this.ecoModeSavedEmissionsItem = new SettingsPanelItem('Saved Emissions', this.emissionsSavedLabel, { + this.ecoModeToggleButtonItem = new SettingsPanelItem({ label: labelEcoMode, setting: ecoModeToggleButton }); + this.ecoModeSavedEmissionsItem = new SettingsPanelItem({ + label: 'Saved Emissions', + setting: this.emissionsSavedLabel, hidden: true, }); diff --git a/src/ts/components/listselector.ts b/src/ts/components/listselector.ts index c8157295a..a029ca340 100644 --- a/src/ts/components/listselector.ts +++ b/src/ts/components/listselector.ts @@ -57,7 +57,7 @@ export interface ListSelectorConfig extends ComponentConfig { export abstract class ListSelector extends Component { protected items: ListItem[]; - protected selectedItem: string; + protected selectedItem: string | null = null; private listSelectorEvents = { onItemAdded: new EventDispatcher, string>(), @@ -191,7 +191,7 @@ export abstract class ListSelector extends Co * @param key the key of the item to return * @returns {ListItem} the item with the requested key. Undefined if no item with the given key exists. */ - getItemForKey(key: string): ListItem { + getItemForKey(key: string): ListItem | null { return this.items.find((item) => item.key === key); } diff --git a/src/ts/components/modernsettingspanel.ts b/src/ts/components/modernsettingspanel.ts index e6b3a4b2b..f4d0647af 100644 --- a/src/ts/components/modernsettingspanel.ts +++ b/src/ts/components/modernsettingspanel.ts @@ -1,54 +1,9 @@ -import { UIInstanceManager } from '../uimanager'; import { ModernSettingsPanelPage } from './modernsettingspanelpage'; -import { PlayerAPI } from 'bitmovin-player'; -import { SettingsPanel, SettingsPanelConfig, NavigationDirection } from './settingspanel'; - +import { SettingsPanel } from './settingspanel'; export class ModernSettingsPanel extends SettingsPanel { - constructor(config: SettingsPanelConfig) { - super(config); - - this.config = this.mergeConfig(config, { - cssClass: 'ui-settings-panel', - hideDelay: 3000, - pageTransitionAnimation: true, - } as SettingsPanelConfig, this.config); - - (this.getActivePage()).onRequestsDisplaySubMenu.subscribe(this.handleShowSubPage); - } - - configure(player: PlayerAPI, uimanager: UIInstanceManager): void { - super.configure(player, uimanager); - - uimanager.onPreviewControlsHide.subscribe(() => { - this.hide(); - }); - } - - private handleShowSubPage = (sender: ModernSettingsPanelPage, subPage: ModernSettingsPanelPage) => { - this.show(); - this.addComponent(subPage); - this.updateComponents(); - this.setActivePage(subPage); - } - - private handleNavigateBack = (page: ModernSettingsPanelPage) => { - this.popSettingsPanelPage(); - this.removeComponent(page); + public addDynamicPage(page: ModernSettingsPanelPage): void { + this.addComponent(page); this.updateComponents(); } - - protected navigateToPage( - targetPage: ModernSettingsPanelPage, - sourcePage: ModernSettingsPanelPage, - direction: NavigationDirection, - skipAnimation: boolean, - ): void { - super.navigateToPage(targetPage, sourcePage, direction, skipAnimation); - - if (direction === NavigationDirection.Forwards) { - targetPage.onRequestsDisplaySubMenu.subscribe(this.handleShowSubPage); - targetPage.onRequestsNavigateBack.subscribe(() => this.handleNavigateBack(targetPage)); - } - } } diff --git a/src/ts/components/modernsettingspanelitem.ts b/src/ts/components/modernsettingspanelitem.ts index 1494b8f75..6b3acc8e8 100644 --- a/src/ts/components/modernsettingspanelitem.ts +++ b/src/ts/components/modernsettingspanelitem.ts @@ -1,26 +1,35 @@ -import { ContainerConfig} from './container'; -import {Component, ComponentConfig} from './component'; -import {Event as EDEvent, EventDispatcher, NoArgs} from '../eventdispatcher'; import { Label, LabelConfig } from './label'; import {UIInstanceManager} from '../uimanager'; import {SelectBox} from './selectbox'; -import {ListBox} from './listbox'; -import {VideoQualitySelectBox} from './videoqualityselectbox'; -import {AudioQualitySelectBox} from './audioqualityselectbox'; -import {PlaybackSpeedSelectBox} from './playbackspeedselectbox'; import { PlayerAPI } from 'bitmovin-player'; -import { i18n, LocalizableText } from '../localization/i18n'; +import { LocalizableText } from '../localization/i18n'; import { ModernSettingsPanelPage } from './modernsettingspanelpage'; import { ListSelector, ListSelectorConfig } from './listselector'; import { SubtitleSelectBox } from './subtitleselectbox'; -import { SettingsPanelItem } from './settingspanelitem'; +import { SettingsPanelItem, SettingsPanelItemConfig } from './settingspanelitem'; +import { + Component, + ComponentConfig, + Container, + ContainerConfig, + SettingsPanelPageBackButton, + SubtitleSettingSelectBox, SubtitleSettingsLabel, +} from '../main'; +import { ModernSettingsPanel } from './modernsettingspanel'; +import { ModernSettingsPanelSelectOption } from './modernsettingspanelselectoption'; /** * An item for a {@link ModernSettingsPanelPage}, * Containing an optional {@link Label} and a component that configures a setting. * If the components is a {@link SelectBox} it will handle the logic of displaying it or not */ -export class ModernSettingsPanelItem extends SettingsPanelItem { +export interface ModernSettingsPanelItemConfig extends SettingsPanelItemConfig { + label: LocalizableText | SubtitleSettingsLabel; + setting: ListSelector; + container: ModernSettingsPanel; +} + +export class ModernSettingsPanelItem extends SettingsPanelItem { /** * If setting is null, that means that the item is not an option and does not @@ -28,165 +37,122 @@ export class ModernSettingsPanelItem extends SettingsPanelItem { * used as a back button */ private selectedOptionLabel: Label; - private isOption: Boolean; - private key: string; + protected setting: ListSelector; private player: PlayerAPI; private uimanager: UIInstanceManager; - private modernSettingsPanelItemEvents = { - onRequestSubPage: new EventDispatcher(), - onRequestNavigateBack: new EventDispatcher(), - onItemSelect: new EventDispatcher(), - }; + constructor(config: ModernSettingsPanelItemConfig) { + // TODO: is that the way? -> Should this happen in configure? -> I think so + config.addSettingAsComponent = false; - constructor(label: LocalizableText | Component, setting: Component, key: string = null, config: ContainerConfig = {}) { - super(label, setting, config, false); + super(config); - this.isOption = Boolean(key); - this.key = key; + this.setting = config.setting; + + // TODO: this now does no longer work with the custom label with the opening button + this.selectedOptionLabel = new Label({ + text: '-', + for: this.getConfig().id, + cssClasses: ['ui-label-setting-selected-option'], + }); this.config = this.mergeConfig(config, { + components: [ + this.selectedOptionLabel, + ], cssClass: 'ui-settings-panel-item', role: 'menuitem', + addSettingAsComponent: false, }, this.config); } configure(player: PlayerAPI, uimanager: UIInstanceManager): void { + super.configure(player, uimanager); + this.player = player; this.uimanager = uimanager; - if (this.setting !== null) { - this.setting.configure(this.player, this.uimanager); + if (this.config.label instanceof SubtitleSettingsLabel) { + this.config.label.opener.configure(player, uimanager); } - if (!this.isOption && (this.setting instanceof SelectBox || this.setting instanceof ListBox)) { - this.setting.onItemSelected.subscribe(() => { - this.removeComponent(this.selectedOptionLabel); - const setting = this.setting as ListSelector; - let selectedOptionLabel: LocalizableText = setting.getItemForKey(setting.getSelectedItem()).label; - - if (this.setting instanceof SubtitleSelectBox) { - let availableSettings = setting.getItems().length; - selectedOptionLabel = selectedOptionLabel + ' (' + (availableSettings - 1) + ')'; - } - this.selectedOptionLabel = new Label({ text: selectedOptionLabel, for: this.getConfig().id } as LabelConfig); - this.selectedOptionLabel.getDomElement().addClass(this.prefixCss('ui-label-setting-selected-option')); - this.addComponent(this.selectedOptionLabel); - this.updateComponents(); - }); - - let handleConfigItemChanged = () => { - if (!(this.setting instanceof SelectBox) && !(this.setting instanceof ListBox)) { - return; - } - // The minimum number of items that must be available for the setting to be displayed - // By default, at least two items must be available, else a selection is not possible - let minItemsToDisplay = 2; - // Audio/video quality select boxes contain an additional 'auto' mode, which in combination with a single - // available quality also does not make sense - if ((this.setting instanceof VideoQualitySelectBox && this.setting.hasAutoItem()) - || this.setting instanceof AudioQualitySelectBox) { - minItemsToDisplay = 3; - } - if (this.setting.itemCount() < minItemsToDisplay) { - // Hide the setting if no meaningful choice is available - this.hide(); - } else if (this.setting instanceof PlaybackSpeedSelectBox - && !uimanager.getConfig().playbackSpeedSelectionEnabled) { - // Hide the PlaybackSpeedSelectBox if disabled in config - this.hide(); - } else { - this.show(); - } - - // Visibility might have changed and therefore the active state might have changed so we fire the event - // TODO fire only when state has really changed (e.g. check if visibility has really changed) - this.onActiveChangedEvent(); - - this.getDomElement().attr('aria-haspopup', 'true'); - }; - - this.setting.onItemAdded.subscribe(handleConfigItemChanged); - this.setting.onItemRemoved.subscribe(handleConfigItemChanged); - - // Initialize hidden state - handleConfigItemChanged(); - } - else if (this.isOption) { - this.show(); - this.onActiveChangedEvent(); - this.getLabel.getDomElement().addClass(this.prefixCss('option')); + if (this.setting != null) { + this.setting.configure(this.player, this.uimanager); } - const handleItemClick = (e: Event) => { - if (this.setting !== null) { - if (!this.isOption) { - this.displayItemsSubPage(); - } - - else { - if (this.setting instanceof SelectBox || this.setting instanceof ListBox) { - this.setting.selectItem(this.key); - this.modernSettingsPanelItemEvents.onItemSelect.dispatch(this, this.key); - this.getLabel.getDomElement().addClass(this.prefixCss('selected')); - } - } - } else { - this.modernSettingsPanelItemEvents.onRequestNavigateBack.dispatch(this); + const handleSelectedItemChanged = () => { + let selectedItem = this.setting.getItemForKey(this.setting.getSelectedItem()); + if (selectedItem == null) { + this.selectedOptionLabel.hide(); + return; } - }; - const domElement = this.getDomElement(); - domElement.on('click', (e) => handleItemClick(e)); - } - private getSubPage(): ModernSettingsPanelPage { - if (this.setting instanceof SelectBox || this.setting instanceof ListBox) { - let menuOptions = this.setting.getItems(); - let selectedItem = this.setting.getSelectedItem(); - let page = new ModernSettingsPanelPage({}); - let label = this.getLabel instanceof Label ? new Label({ text: this.getLabel.getConfig().text, for: page.getConfig().id } as LabelConfig) : new Label({ text: i18n.getLocalizer('back'), for: page.getConfig().id } as LabelConfig); - label.getDomElement().addClass(this.prefixCss('heading')); - let itemToAdd = new ModernSettingsPanelItem(label, null); - itemToAdd.configure(this.player, this.uimanager); - page.addComponent(itemToAdd); - - for (let option of menuOptions) { - let itemToAdd = new ModernSettingsPanelItem(option.label, this.setting, option.key); - itemToAdd.configure(this.player, this.uimanager); - - if (option.key === selectedItem) { - itemToAdd.getLabel.getDomElement().addClass(this.prefixCss('selected')); - } - page.addComponent(itemToAdd); + this.selectedOptionLabel.show(); + let selectedOptionLabelText = selectedItem.label; + if (this.setting instanceof SubtitleSelectBox) { + let availableSettings = this.setting.getItems().length; + selectedOptionLabelText = selectedOptionLabelText + ' (' + (availableSettings - 1) + ')'; } - page.configure(this.player, this.uimanager); - return page; - } - } + this.selectedOptionLabel.setText(selectedOptionLabelText); + }; + this.setting.onItemSelected.subscribe(handleSelectedItemChanged); - public getSetting(): Component { - return this.setting; - } + handleSelectedItemChanged(); - public displayItemsSubPage(): void { - let page = this.getSubPage(); - this.modernSettingsPanelItemEvents.onRequestSubPage.dispatch(this, page); + const handleItemClick = () => { + this.displayItemsSubPage(); + }; + this.getDomElement().on('click', (e) => { e.stopPropagation(); handleItemClick(); }); } - /** - * Gets the event that is fired, when the SettingsPanelItem has been clicked - * and wants to display its sub menu on the {@link ModernSettingsPanel} as a seperate {@link ModernSettingsPanelPage} - */ - get getOnDisplaySubPage(): EDEvent { - return this.modernSettingsPanelItemEvents.onRequestSubPage.getEvent(); - } + private buildSubPanelPage(): ModernSettingsPanelPage { + const menuOptions = this.setting.getItems(); + const page = new ModernSettingsPanelPage({}); + + const text = this.config.label instanceof SubtitleSettingsLabel ? this.config.label.text : this.config.label; + + const backButton = new SettingsPanelPageBackButton({ + text: text, + container: this.config.container, + cssClasses: ['ui-settings-panel-item-back'], + }); + backButton.configure(this.player, this.uimanager); + page.addComponent(backButton); + + menuOptions + .map((option) => { + return new ModernSettingsPanelSelectOption({ + label: option.label, + setting: this.setting, + settingsValue: option.key, + addSettingAsComponent: false, + }); + }) + .forEach((selectOption) => { + selectOption.configure(this.player, this.uimanager); + page.addComponent(selectOption); + }); - get getOnRequestNavigateBack(): EDEvent { - return this.modernSettingsPanelItemEvents.onRequestNavigateBack.getEvent(); + page.configure(this.player, this.uimanager); + + if (this.setting instanceof SubtitleSettingSelectBox) { + // Keep the preview subtitle overlay visible when the sub-page is for a subtitle setting + page.onActive.subscribe(() => { + (this.setting).overlay.enablePreviewSubtitleLabel(); + }); + + page.onInactive.subscribe(() => { + (this.setting).overlay.removePreviewSubtitleLabel(); + }); + } + + return page; } - get onItemSelect(): EDEvent { - return this.modernSettingsPanelItemEvents.onItemSelect.getEvent(); + public displayItemsSubPage(): void { + let page = this.buildSubPanelPage(); + this.config.container.addDynamicPage(page); + this.config.container.setActivePage(page); } } diff --git a/src/ts/components/modernsettingspanelpage.ts b/src/ts/components/modernsettingspanelpage.ts index 59023b90f..16ab077c3 100644 --- a/src/ts/components/modernsettingspanelpage.ts +++ b/src/ts/components/modernsettingspanelpage.ts @@ -5,6 +5,7 @@ import { PlayerAPI } from 'bitmovin-player'; import { ModernSettingsPanelItem } from './modernsettingspanelitem'; import { SettingsPanelPage } from './settingspanelpage'; +// TODO: needed? /** * A panel containing a list of {@link ModernSettingsPanelItem items} that represent labelled settings. */ @@ -27,15 +28,12 @@ export class ModernSettingsPanelPage extends SettingsPanelPage { configure(player: PlayerAPI, uimanager: UIInstanceManager): void { super.configure(player, uimanager); - for (let component of this.getItems()) { - (component).getOnDisplaySubPage.subscribe((_, args: ModernSettingsPanelPage) => this.requestsDisplaySubMenu(this, args)); - (component).getOnRequestNavigateBack.subscribe(() => this.modernSettingsPanelPageEvents.onRequestsNavigateBack.dispatch(this)); - (component).onItemSelect.subscribe(() => { - for (let component of this.getItems()) { - component.getLabel.getDomElement().removeClass(this.prefixCss('selected')); - } - }); - } + // for (let component of this.getItems()) { + // if (component instanceof ModernSettingsPanelItem) { + // component.getOnDisplaySubPage.subscribe((_, args: ModernSettingsPanelPage) => this.requestsDisplaySubMenu(this, args)); + // component.getOnRequestNavigateBack.subscribe(() => this.modernSettingsPanelPageEvents.onRequestsNavigateBack.dispatch(this)); + // } + // } } requestsDisplaySubMenu(_: Sender, args: ModernSettingsPanelPage) { diff --git a/src/ts/components/modernsettingspanelselectoption.ts b/src/ts/components/modernsettingspanelselectoption.ts new file mode 100644 index 000000000..5340be98e --- /dev/null +++ b/src/ts/components/modernsettingspanelselectoption.ts @@ -0,0 +1,50 @@ +import { SettingsPanelItem, SettingsPanelItemConfig } from './settingspanelitem'; +import { PlayerAPI } from 'bitmovin-player'; +import { UIInstanceManager } from '../uimanager'; +import { ListSelector, ListSelectorConfig } from './listselector'; + +export interface ModernSettingsPanelSelectOptionConfig extends SettingsPanelItemConfig { + setting: ListSelector; + settingsValue: string | undefined; + autoCloseOnSelect?: boolean; +} + +export class ModernSettingsPanelSelectOption extends SettingsPanelItem { + + private settingsValue: string | undefined; + protected setting: ListSelector; + + constructor(config: ModernSettingsPanelSelectOptionConfig) { + super(config); + + this.settingsValue = config.settingsValue; + + this.config = this.mergeConfig(config, { + cssClass: 'ui-settings-panel-item-select-option', + role: 'menuitem', + } as ModernSettingsPanelSelectOptionConfig, this.config); + } + + configure(player: PlayerAPI, uimanager: UIInstanceManager) { + super.configure(player, uimanager); + + const handleSelectedOptionChanged = () => { + let selectedItem = this.setting.getSelectedItem(); + + if (this.settingsValue === selectedItem) { + this.getDomElement().addClass(this.prefixCss('selected')); + } else { + this.getDomElement().removeClass(this.prefixCss('selected')); + } + }; + this.setting.onItemSelected.subscribe(handleSelectedOptionChanged); + + const handleItemClick = () => { + this.setting.selectItem(this.settingsValue); + }; + this.getDomElement().on('click', () => handleItemClick()); + + // Initial state + handleSelectedOptionChanged(); + } +} diff --git a/src/ts/components/seekbar.ts b/src/ts/components/seekbar.ts index e16e0d0a9..ba2d99a2b 100644 --- a/src/ts/components/seekbar.ts +++ b/src/ts/components/seekbar.ts @@ -747,6 +747,8 @@ export class SeekBar extends Component { this.onSeekedEvent(targetPercentage); }; + // TODO: the problem is that the SeekbarLabel is also inside the seekbarContainer and therefore reacts to the + // TODO: mouse inputs. let domElementToListen: DOM = this.config.renderSeekBarPlaybackPositionMarkerInOuterSeekBar ? seekBarContainer : seekBar; // A seek always start with a touchstart or mousedown directly on the seekbar. diff --git a/src/ts/components/settingspanel.ts b/src/ts/components/settingspanel.ts index 950cc3899..ca8c5be99 100644 --- a/src/ts/components/settingspanel.ts +++ b/src/ts/components/settingspanel.ts @@ -4,7 +4,7 @@ import { UIInstanceManager } from '../uimanager'; import { Timeout } from '../timeout'; import { Event, EventDispatcher, NoArgs } from '../eventdispatcher'; import { SettingsPanelPage } from './settingspanelpage'; -import { SettingsPanelItem } from './settingspanelitem'; +import { SettingsPanelItem, SettingsPanelItemConfig } from './settingspanelitem'; import { PlayerAPI } from 'bitmovin-player'; import { Component, ComponentConfig } from './component'; @@ -113,6 +113,15 @@ export class SettingsPanel extends Container { }); } + if (config.pageTransitionAnimation) { + const handleResize = () => { + // Reset the dimension of the settingsPanel to let the browser calculate the new dimension after resizing + this.getDomElement().css({ width: '', height: '' }); + }; + + player.on(player.exports.PlayerEvent.PlayerResized, handleResize); + } + this.onHide.subscribe(() => { if (config.hideDelay > -1) { // Clear timeout when hidden from outside @@ -300,8 +309,8 @@ export class SettingsPanel extends Container { this.animateNavigation(targetPage, sourcePage, skipAnimation); this.updateActivePageClass(); - targetPage.onActiveEvent(); sourcePage.onInactiveEvent(); + targetPage.onActiveEvent(); } /** @@ -321,6 +330,7 @@ export class SettingsPanel extends Container { const settingsPanelHTMLElement = this.getDomElement().get(0); // get current dimension + // TODO: handle resizing properly const settingsPanelWidth = settingsPanelHTMLElement.scrollWidth; const settingsPanelHeight = settingsPanelHTMLElement.scrollHeight; @@ -383,8 +393,8 @@ export class SettingsPanel extends Container { } // collect all items from all pages (see hideHoveredSelectBoxes) - private getComputedItems(): SettingsPanelItem[] { - const allItems: SettingsPanelItem[] = []; + private getComputedItems(): SettingsPanelItem[] { + const allItems: SettingsPanelItem[] = []; for (let page of this.getPages()) { allItems.push(...page.getItems()); } diff --git a/src/ts/components/settingspanelitem.ts b/src/ts/components/settingspanelitem.ts index 0ca84091c..8e9bfd77b 100644 --- a/src/ts/components/settingspanelitem.ts +++ b/src/ts/components/settingspanelitem.ts @@ -11,6 +11,12 @@ import {PlaybackSpeedSelectBox} from './playbackspeedselectbox'; import { PlayerAPI } from 'bitmovin-player'; import { LocalizableText } from '../localization/i18n'; +export interface SettingsPanelItemConfig extends ContainerConfig { + label?: LocalizableText | Component; + setting: Component; + addSettingAsComponent?: boolean; +} + /** * An item for a {@link SettingsPanelPage}, * Containing an optional {@link Label} and a component that configures a setting. @@ -18,35 +24,38 @@ import { LocalizableText } from '../localization/i18n'; * * @category Components */ -export class SettingsPanelItem extends Container { +export class SettingsPanelItem extends Container { private label: Component; protected setting: Component; private settingsPanelItemEvents = { - onActiveChanged: new EventDispatcher(), + onActiveChanged: new EventDispatcher, NoArgs>(), }; - constructor(label: LocalizableText | Component, setting: Component, config: ContainerConfig = {}, addSettingAsComponent: boolean = true) { - super(config); + constructor(config: SettingsPanelItemConfig) { + super(config as Config); - this.setting = setting; + this.setting = config.setting; - this.config = this.mergeConfig(config, { + // TODO: this feels ugly -> typescript weak type problem (no matching property from parent) + this.config = this.mergeConfig(config as Config, { cssClass: 'ui-settings-panel-item', role: 'menuitem', - }, this.config); + addSettingAsComponent: true, + } as Config, this.config as Config); + const label = config.label; if (label !== null) { if (label instanceof Component) { this.label = label; } else { - this.label = new Label({ text: label, for: this.setting.getConfig() ? this.setting.getConfig().id : this.getConfig().id } as LabelConfig); + this.label = new Label({ text: label } as LabelConfig); } this.addComponent(this.label); } - if (addSettingAsComponent) { + if (config.addSettingAsComponent) { this.addComponent(this.setting); } } @@ -110,9 +119,10 @@ export class SettingsPanelItem extends Container { * @see #isActive * @returns {Event} */ - get onActiveChanged(): Event { + get onActiveChanged(): Event, NoArgs> { return this.settingsPanelItemEvents.onActiveChanged.getEvent(); } + get getLabel(): Component { return this.label; } diff --git a/src/ts/components/settingspanelpage.ts b/src/ts/components/settingspanelpage.ts index 8e8f089ff..28818fbca 100644 --- a/src/ts/components/settingspanelpage.ts +++ b/src/ts/components/settingspanelpage.ts @@ -1,5 +1,5 @@ import {Container, ContainerConfig} from './container'; -import {SettingsPanelItem} from './settingspanelitem'; +import { SettingsPanelItem, SettingsPanelItemConfig } from './settingspanelitem'; import {UIInstanceManager} from '../uimanager'; import {Event, EventDispatcher, NoArgs} from '../eventdispatcher'; import { PlayerAPI } from 'bitmovin-player'; @@ -63,8 +63,8 @@ export class SettingsPanelPage extends Container { return false; } - getItems(): SettingsPanelItem[] { - return this.config.components.filter(component => component instanceof SettingsPanelItem); + getItems(): SettingsPanelItem[] { + return []>this.config.components.filter(component => component instanceof SettingsPanelItem); } onSettingsStateChangedEvent() { diff --git a/src/ts/components/subtitlesettings/subtitlesettingselectbox.ts b/src/ts/components/subtitlesettings/subtitlesettingselectbox.ts index e6448d56f..a33c1c113 100644 --- a/src/ts/components/subtitlesettings/subtitlesettingselectbox.ts +++ b/src/ts/components/subtitlesettings/subtitlesettingselectbox.ts @@ -20,7 +20,7 @@ export interface SubtitleSettingSelectBoxConfig extends ListSelectorConfig { export class SubtitleSettingSelectBox extends SelectBox { protected settingsManager?: SubtitleSettingsManager; - protected overlay: SubtitleOverlay; + public overlay: SubtitleOverlay; private currentCssClass: string; constructor(config: SubtitleSettingSelectBoxConfig) { diff --git a/src/ts/components/subtitlesettings/subtitlesettingslabel.ts b/src/ts/components/subtitlesettings/subtitlesettingslabel.ts index 723db03c5..6a9a1761a 100644 --- a/src/ts/components/subtitlesettings/subtitlesettingslabel.ts +++ b/src/ts/components/subtitlesettings/subtitlesettingslabel.ts @@ -1,4 +1,4 @@ -import {LabelConfig} from '../label'; +import { Label, LabelConfig } from '../label'; import {Container, ContainerConfig} from '../container'; import {DOM} from '../../dom'; import {SettingsPanelPageOpenButton} from '../settingspanelpageopenbutton'; @@ -16,9 +16,9 @@ export interface SubtitleSettingsLabelConfig extends LabelConfig { */ export class SubtitleSettingsLabel extends Container { - private opener: SettingsPanelPageOpenButton; + readonly opener: SettingsPanelPageOpenButton; - private text: LocalizableText; + readonly text: LocalizableText; private for: string; @@ -30,23 +30,24 @@ export class SubtitleSettingsLabel extends Container { this.for = config.for; this.config = this.mergeConfig(config, { - cssClass: 'ui-label', + // cssClass: 'ui-label', components: [ + new Label({ text: this.text, for: this.for } as LabelConfig), this.opener, ], }, this.config); } - protected toDomElement(): DOM { - let labelElement = new DOM('label', { - 'id': this.config.id, - 'class': this.getCssClasses(), - 'for': this.for, - }, this).append( - new DOM('span', {}).html(i18n.performLocalization(this.text)), - this.opener.getDomElement(), - ); - - return labelElement; - } + // protected toDomElement(): DOM { + // let labelElement = new DOM('label', { + // 'id': this.config.id, + // 'class': this.getCssClasses(), + // 'for': this.for, + // }, this).append( + // new DOM('span', {}).html(i18n.performLocalization(this.text)), + // this.opener.getDomElement(), + // ); + // + // return labelElement; + // } } diff --git a/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts b/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts index 95b560a53..e15b93806 100644 --- a/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts +++ b/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts @@ -19,6 +19,9 @@ import {SettingsPanelPageBackButton} from '../settingspanelpagebackbutton'; import {SettingsPanelItem} from '../settingspanelitem'; import { PlayerAPI } from 'bitmovin-player'; import { i18n } from '../../localization/i18n'; +import { ModernSettingsPanelPage } from '../modernsettingspanelpage'; +import { ModernSettingsPanelItem } from '../modernsettingspanelitem'; +import { ModernSettingsPanel } from '../modernsettingspanel'; /** * @category Configs @@ -31,7 +34,7 @@ export interface SubtitleSettingsPanelPageConfig extends ContainerConfig { /** * @category Components */ -export class SubtitleSettingsPanelPage extends SettingsPanelPage { +export class SubtitleSettingsPanelPage extends ModernSettingsPanelPage { private readonly overlay: SubtitleOverlay; private readonly settingsPanel: SettingsPanel; @@ -42,41 +45,75 @@ export class SubtitleSettingsPanelPage extends SettingsPanelPage { this.overlay = config.overlay; this.settingsPanel = config.settingsPanel; - this.config = this.mergeConfig(config, { components: []>[ - new SettingsPanelItem(i18n.getLocalizer('settings.subtitles.font.size'), new FontSizeSelectBox({ - overlay: this.overlay, - })), - new SettingsPanelItem(i18n.getLocalizer('settings.subtitles.font.family'), new FontFamilySelectBox({ - overlay: this.overlay, - })), - new SettingsPanelItem(i18n.getLocalizer('settings.subtitles.font.color'), new FontColorSelectBox({ - overlay: this.overlay, - })), - new SettingsPanelItem(i18n.getLocalizer('settings.subtitles.font.opacity'), new FontOpacitySelectBox({ - overlay: this.overlay, - })), - new SettingsPanelItem(i18n.getLocalizer('settings.subtitles.characterEdge'), new CharacterEdgeSelectBox({ - overlay: this.overlay, - })), - new SettingsPanelItem(i18n.getLocalizer('settings.subtitles.background.color'), new BackgroundColorSelectBox({ - overlay: this.overlay, - })), - new SettingsPanelItem(i18n.getLocalizer('settings.subtitles.background.opacity'), new BackgroundOpacitySelectBox({ - overlay: this.overlay, - })), - new SettingsPanelItem(i18n.getLocalizer('settings.subtitles.window.color'), new WindowColorSelectBox({ - overlay: this.overlay, - })), - new SettingsPanelItem(i18n.getLocalizer('settings.subtitles.window.opacity'), new WindowOpacitySelectBox({ - overlay: this.overlay, - })), - new SettingsPanelItem(new SettingsPanelPageBackButton({ - container: this.settingsPanel, + new SettingsPanelPageBackButton({ text: i18n.getLocalizer('back'), - }), new SubtitleSettingsResetButton({}), { - role: 'menubar', + container: this.settingsPanel, + cssClasses: ['ui-settings-panel-item-back'], + }), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('settings.subtitles.font.size'), + setting: new FontSizeSelectBox({ + overlay: this.overlay, + }), + container: this.settingsPanel as ModernSettingsPanel, + }), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('settings.subtitles.font.family'), + setting: new FontFamilySelectBox({ + overlay: this.overlay, + }), + container: this.settingsPanel as ModernSettingsPanel, + }), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('settings.subtitles.font.color'), + setting: new FontColorSelectBox({ + overlay: this.overlay, + }), + container: this.settingsPanel as ModernSettingsPanel, + }), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('settings.subtitles.font.opacity'), + setting: new FontOpacitySelectBox({ + overlay: this.overlay, + }), + container: this.settingsPanel as ModernSettingsPanel, + }), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('settings.subtitles.characterEdge'), + setting: new CharacterEdgeSelectBox({ + overlay: this.overlay, + }), + container: this.settingsPanel as ModernSettingsPanel, + }), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('settings.subtitles.background.color'), + setting: new BackgroundColorSelectBox({ + overlay: this.overlay, + }), + container: this.settingsPanel as ModernSettingsPanel, + }), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('settings.subtitles.background.opacity'), + setting: new BackgroundOpacitySelectBox({ + overlay: this.overlay, + }), + container: this.settingsPanel as ModernSettingsPanel, + }), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('settings.subtitles.window.color'), + setting: new WindowColorSelectBox({ + overlay: this.overlay, + }), + container: this.settingsPanel as ModernSettingsPanel, + }), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('settings.subtitles.window.opacity'), + setting: new WindowOpacitySelectBox({ + overlay: this.overlay, + }), + container: this.settingsPanel as ModernSettingsPanel, }), ], }, this.config); diff --git a/src/ts/demofactory.ts b/src/ts/demofactory.ts index e9f5eb144..596af48b3 100644 --- a/src/ts/demofactory.ts +++ b/src/ts/demofactory.ts @@ -70,9 +70,9 @@ export namespace DemoFactory { components: [ new SettingsPanelPage({ components: [ - new SettingsPanelItem('Video Quality', new VideoQualitySelectBox()), - new SettingsPanelItem('Speed', new PlaybackSpeedSelectBox()), - new SettingsPanelItem('Audio Quality', new AudioQualitySelectBox()), + new SettingsPanelItem({ label: 'Video Quality', setting: new VideoQualitySelectBox() }), + new SettingsPanelItem({ label: 'Speed', setting: new PlaybackSpeedSelectBox() }), + new SettingsPanelItem({ label: 'Audio Quality', setting: new AudioQualitySelectBox() }), ], }), ], @@ -84,7 +84,7 @@ export namespace DemoFactory { components: [ new SettingsPanelPage({ components: [ - new SettingsPanelItem(null, subtitleListBox), + new SettingsPanelItem({ label: null, setting: subtitleListBox }), ], }), ], @@ -96,7 +96,7 @@ export namespace DemoFactory { components: [ new SettingsPanelPage({ components: [ - new SettingsPanelItem(null, audioTrackListBox), + new SettingsPanelItem({ label: null, setting: audioTrackListBox }), ], }), ], diff --git a/src/ts/uifactory.ts b/src/ts/uifactory.ts index f05b75ef1..fd6fa7425 100644 --- a/src/ts/uifactory.ts +++ b/src/ts/uifactory.ts @@ -1,6 +1,6 @@ import { SubtitleOverlay } from './components/subtitleoverlay'; import { SettingsPanelPage } from './components/settingspanelpage'; -import { SettingsPanelItem } from './components/settingspanelitem'; +import { SettingsPanelItem, SettingsPanelItemConfig } from './components/settingspanelitem'; import { VideoQualitySelectBox } from './components/videoqualityselectbox'; import { PlaybackSpeedSelectBox } from './components/playbackspeedselectbox'; import { AudioTrackSelectBox } from './components/audiotrackselectbox'; @@ -84,10 +84,10 @@ export namespace UIFactory { 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()), + new SettingsPanelItem({ label: i18n.getLocalizer('settings.video.quality'), setting: new VideoQualitySelectBox() }), + new SettingsPanelItem({ label: i18n.getLocalizer('speed'), setting: new PlaybackSpeedSelectBox() }), + new SettingsPanelItem({ label: i18n.getLocalizer('settings.audio.track'), setting: new AudioTrackSelectBox() }), + new SettingsPanelItem({ label: i18n.getLocalizer('settings.audio.quality'), setting: new AudioQualitySelectBox() }), ]; if (config.ecoMode) { @@ -125,16 +125,14 @@ export namespace UIFactory { }); mainSettingsPanelPage.addComponent( - new SettingsPanelItem( - new SubtitleSettingsLabel({ + new SettingsPanelItem({ + label: new SubtitleSettingsLabel({ text: i18n.getLocalizer('settings.subtitles'), opener: subtitleSettingsOpenButton, }), - subtitleSelectBox, - { - role: 'menubar', - }, - ), + setting: subtitleSelectBox, + role: 'menubar', + }), ); settingsPanel.addComponent(subtitleSettingsPanelPage); @@ -236,10 +234,10 @@ export namespace UIFactory { 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()), + new SettingsPanelItem({ label: i18n.getLocalizer('settings.video.quality'), setting: new VideoQualitySelectBox() }), + new SettingsPanelItem({ label: i18n.getLocalizer('speed'), setting: new PlaybackSpeedSelectBox() }), + new SettingsPanelItem({ label: i18n.getLocalizer('settings.audio.track'), setting: new AudioTrackSelectBox() }), + new SettingsPanelItem({ label: i18n.getLocalizer('settings.audio.quality'), setting: new AudioQualitySelectBox() }), ], }); @@ -265,16 +263,14 @@ export namespace UIFactory { const subtitleSelectBox = new SubtitleSelectBox(); mainSettingsPanelPage.addComponent( - new SettingsPanelItem( - new SubtitleSettingsLabel({ + new SettingsPanelItem({ + label: new SubtitleSettingsLabel({ text: i18n.getLocalizer('settings.subtitles'), opener: subtitleSettingsOpenButton, }), - subtitleSelectBox, - { - role: 'menubar', - }, - ), + setting: subtitleSelectBox, + role: 'menubar', + }), ); settingsPanel.addComponent(subtitleSettingsPanelPage); @@ -459,10 +455,10 @@ export namespace UIFactory { let mainSettingsPanelPage = new ModernSettingsPanelPage({ components: [ - new ModernSettingsPanelItem(i18n.getLocalizer('settings.video.quality'), new VideoQualitySelectBox()), - new ModernSettingsPanelItem(i18n.getLocalizer('speed'), new PlaybackSpeedSelectBox()), - new ModernSettingsPanelItem(i18n.getLocalizer('settings.audio.track'), new AudioTrackSelectBox()), - new ModernSettingsPanelItem(i18n.getLocalizer('settings.audio.quality'), new AudioQualitySelectBox()), + // new ModernSettingsPanelItem(i18n.getLocalizer('settings.video.quality'), new VideoQualitySelectBox()), + // new ModernSettingsPanelItem(i18n.getLocalizer('speed'), new PlaybackSpeedSelectBox()), + // new ModernSettingsPanelItem(i18n.getLocalizer('settings.audio.track'), new AudioTrackSelectBox()), + // new ModernSettingsPanelItem(i18n.getLocalizer('settings.audio.quality'), new AudioQualitySelectBox()), ], }); @@ -474,15 +470,14 @@ export namespace UIFactory { }); const subtitleSelectBox = new SubtitleSelectBox(); - let subtitleSelectItem = new ModernSettingsPanelItem( - new Label({ text: i18n.getLocalizer('settings.subtitles') } as LabelConfig), - subtitleSelectBox, - null, - { - role: 'menubar', - }, - ); - mainSettingsPanelPage.addComponent(subtitleSelectItem); + // let subtitleSelectItem = new ModernSettingsPanelItem( + // new Label({ text: i18n.getLocalizer('settings.subtitles') } as LabelConfig), + // subtitleSelectBox, + // { + // role: 'menubar', + // }, + // ); + // mainSettingsPanelPage.addComponent(subtitleSelectItem); let controlBar = new ControlBar({ components: [ @@ -506,7 +501,7 @@ export namespace UIFactory { new VolumeToggleButton(), new Spacer(), new SettingsToggleButton({ settingsPanel: settingsPanel }), - new SubtitleToggleButton(subtitleSelectItem, subtitleSelectBox), + // new SubtitleToggleButton(subtitleSelectItem, subtitleSelectBox), new FullscreenToggleButton(), ], cssClasses: ['controlbar-bottom'], @@ -548,47 +543,65 @@ export namespace UIFactory { let mainSettingsPanelPage: SettingsPanelPage; + let settingsPanel = new ModernSettingsPanel({ + components: [], + hidden: true, + pageTransitionAnimation: true, + }); + const components: Container[] = [ - new ModernSettingsPanelItem(i18n.getLocalizer('settings.video.quality'), new VideoQualitySelectBox()), - new ModernSettingsPanelItem(i18n.getLocalizer('speed'), new PlaybackSpeedSelectBox()), - new ModernSettingsPanelItem(i18n.getLocalizer('settings.audio.track'), new AudioTrackSelectBox()), - new ModernSettingsPanelItem(i18n.getLocalizer('settings.audio.quality'), new AudioQualitySelectBox()), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('settings.video.quality'), + setting: new VideoQualitySelectBox(), + container: settingsPanel, + }), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('speed'), + setting: new PlaybackSpeedSelectBox(), + container: settingsPanel, + }), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('settings.audio.track'), + setting: new AudioTrackSelectBox(), + container: settingsPanel, + }), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('settings.audio.quality'), + setting: new AudioQualitySelectBox(), + container: settingsPanel, + }), ]; mainSettingsPanelPage = new ModernSettingsPanelPage({ components, }); - let settingsPanel = new ModernSettingsPanel({ - components: [mainSettingsPanelPage], - hidden: true, - pageTransitionAnimation: true, + settingsPanel.addComponent(mainSettingsPanelPage); + + let subtitleSettingsPanelPage = new SubtitleSettingsPanelPage({ + settingsPanel: settingsPanel, + overlay: subtitleOverlay, }); - // let subtitleSettingsPanelPage = new SubtitleSettingsPanelPage({ - // settingsPanel: settingsPanel, - // overlay: subtitleOverlay, - // }); - // - // let subtitleSettingsOpenButton = new SettingsPanelPageOpenButton({ - // targetPage: subtitleSettingsPanelPage, - // container: settingsPanel, - // ariaLabel: i18n.getLocalizer('settings.subtitles'), - // text: i18n.getLocalizer('open'), - // }); + let subtitleSettingsOpenButton = new SettingsPanelPageOpenButton({ + targetPage: subtitleSettingsPanelPage, + container: settingsPanel, + ariaLabel: i18n.getLocalizer('settings.subtitles'), + text: i18n.getLocalizer('open'), + }); const subtitleSelectBox = new SubtitleSelectBox(); - let subtitleSelectItem = new ModernSettingsPanelItem( - new Label({ text: i18n.getLocalizer('settings.subtitles') } as LabelConfig), - subtitleSelectBox, - null, - { - role: 'menubar', - }, - ); + let subtitleSelectItem = new ModernSettingsPanelItem({ + label: new SubtitleSettingsLabel({ + text: i18n.getLocalizer('settings.subtitles'), + opener: subtitleSettingsOpenButton, + }), + setting: subtitleSelectBox, + role: 'menubar', + container: settingsPanel, + }); mainSettingsPanelPage.addComponent(subtitleSelectItem); - - // settingsPanel.addComponent(subtitleSettingsPanelPage); + settingsPanel.addComponent(subtitleSettingsPanelPage); let controlBar = new ControlBar({ components: [ @@ -753,7 +766,7 @@ export namespace UIFactory { const subtitleListPanel = new SettingsPanel({ components: [ new SettingsPanelPage({ - components: [new SettingsPanelItem(null, subtitleListBox)], + components: [new SettingsPanelItem({ setting: subtitleListBox })], }), ], hidden: true, @@ -763,7 +776,7 @@ export namespace UIFactory { const audioTrackListPanel = new SettingsPanel({ components: [ new SettingsPanelPage({ - components: [new SettingsPanelItem(null, audioTrackListBox)], + components: [new SettingsPanelItem({ setting: audioTrackListBox })], }), ], hidden: true, From ea9fc09eb8d04778cafc0a9d15833c18937731d6 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Fri, 6 Dec 2024 10:51:50 -0700 Subject: [PATCH 02/23] clear hide timeout on mouse move --- src/ts/components/settingspanel.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ts/components/settingspanel.ts b/src/ts/components/settingspanel.ts index ca8c5be99..853574ca3 100644 --- a/src/ts/components/settingspanel.ts +++ b/src/ts/components/settingspanel.ts @@ -97,9 +97,11 @@ export class SettingsPanel extends Container { this.hide(); this.hideHoveredSelectBoxes(); }); - this.getDomElement().on('mouseenter', () => { - // On mouse enter clear the timeout - this.hideTimeout.clear(); + this.getDomElement().on('mouseenter mousemove', () => { + // On mouse enter and mouse move clear the timeout + if (this.hideTimeout.isActive()) { + this.hideTimeout.clear(); + } }); this.getDomElement().on('mouseleave', () => { // On mouse leave activate the timeout From 0c0e9fd56dbea50d7bfe5d6abac130e2c64feb15 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Fri, 6 Dec 2024 11:46:19 -0700 Subject: [PATCH 03/23] add a min gap between elements in a settings panel item --- src/scss/skin-super-modern/components/_settingspanelpage.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/scss/skin-super-modern/components/_settingspanelpage.scss b/src/scss/skin-super-modern/components/_settingspanelpage.scss index 64a902ff7..0996b3a95 100644 --- a/src/scss/skin-super-modern/components/_settingspanelpage.scss +++ b/src/scss/skin-super-modern/components/_settingspanelpage.scss @@ -64,6 +64,10 @@ height: 100%; width: 100%; } + + > .#{$prefix}-container-wrapper { + column-gap: 10px; + } } // TODO: de-duplicate this From 545e6807365fd4c925f134c0aa87b4eb36bab3c1 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Fri, 6 Dec 2024 12:27:56 -0700 Subject: [PATCH 04/23] remove dynamic pages from DOM after navigating back --- src/ts/components/modernsettingspanel.ts | 11 +++++++++++ src/ts/components/modernsettingspanelitem.ts | 2 +- src/ts/components/modernsettingspanelpage.ts | 5 ++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/ts/components/modernsettingspanel.ts b/src/ts/components/modernsettingspanel.ts index f4d0647af..fe0b5b0d5 100644 --- a/src/ts/components/modernsettingspanel.ts +++ b/src/ts/components/modernsettingspanel.ts @@ -6,4 +6,15 @@ export class ModernSettingsPanel extends SettingsPanel { this.addComponent(page); this.updateComponents(); } + + popSettingsPanelPage() { + const currentActivePage = this.getActivePage(); + + super.popSettingsPanelPage(); + + if (currentActivePage instanceof ModernSettingsPanelPage && currentActivePage.isDynamic) { + this.removeComponent(currentActivePage); + this.updateComponents(); + } + } } diff --git a/src/ts/components/modernsettingspanelitem.ts b/src/ts/components/modernsettingspanelitem.ts index 6b3acc8e8..649db1f88 100644 --- a/src/ts/components/modernsettingspanelitem.ts +++ b/src/ts/components/modernsettingspanelitem.ts @@ -108,7 +108,7 @@ export class ModernSettingsPanelItem extends SettingsPanelItem(), onRequestsNavigateBack: new EventDispatcher(), }; - constructor(config: ContainerConfig) { + constructor(config: ContainerConfig, isDynamic: boolean = false) { super(config); + this.isDynamic = isDynamic; + this.config = this.mergeConfig(config, { cssClass: 'ui-settings-panel-page', role: 'menu', From 64dad45efc948d2d9e4286e1918361919394acbe Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Mon, 9 Dec 2024 11:52:57 -0700 Subject: [PATCH 05/23] replace hardcoded back text with localization --- src/ts/components/settingspanelpagebackbutton.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ts/components/settingspanelpagebackbutton.ts b/src/ts/components/settingspanelpagebackbutton.ts index e02b4be31..43d16ba9e 100644 --- a/src/ts/components/settingspanelpagebackbutton.ts +++ b/src/ts/components/settingspanelpagebackbutton.ts @@ -1,6 +1,7 @@ import {UIInstanceManager} from '../uimanager'; import {SettingsPanelPageNavigatorButton, SettingsPanelPageNavigatorConfig} from './settingspanelpagenavigatorbutton'; import { PlayerAPI } from 'bitmovin-player'; +import { i18n } from '../localization/i18n'; /** * @category Buttons @@ -12,7 +13,7 @@ export class SettingsPanelPageBackButton extends SettingsPanelPageNavigatorButto this.config = this.mergeConfig(config, { cssClass: 'ui-settingspanelpagebackbutton', - text: 'back', + text: i18n.getLocalizer('back'), } as SettingsPanelPageNavigatorConfig, this.config); } From 6f21cbf9d2cfcd05c848f8eec6c5ac67c2573c00 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Mon, 9 Dec 2024 11:54:18 -0700 Subject: [PATCH 06/23] improve typing for optional settings --- src/ts/components/modernsettingspanelitem.ts | 6 +++++- src/ts/components/modernsettingspanelselectoption.ts | 2 +- src/ts/components/settingspanelitem.ts | 6 +++--- .../subtitlesettings/subtitlesettingspanelpage.ts | 10 ++++++---- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/ts/components/modernsettingspanelitem.ts b/src/ts/components/modernsettingspanelitem.ts index 649db1f88..a4b913ecc 100644 --- a/src/ts/components/modernsettingspanelitem.ts +++ b/src/ts/components/modernsettingspanelitem.ts @@ -118,7 +118,11 @@ export class ModernSettingsPanelItem extends SettingsPanelItem { diff --git a/src/ts/components/modernsettingspanelselectoption.ts b/src/ts/components/modernsettingspanelselectoption.ts index 5340be98e..c26fda641 100644 --- a/src/ts/components/modernsettingspanelselectoption.ts +++ b/src/ts/components/modernsettingspanelselectoption.ts @@ -20,7 +20,7 @@ export class ModernSettingsPanelSelectOption extends SettingsPanelItem; - setting: Component; + setting?: Component; addSettingAsComponent?: boolean; } @@ -27,7 +27,7 @@ export interface SettingsPanelItemConfig extends ContainerConfig { export class SettingsPanelItem extends Container { private label: Component; - protected setting: Component; + protected setting: Component | null; private settingsPanelItemEvents = { onActiveChanged: new EventDispatcher, NoArgs>(), @@ -55,7 +55,7 @@ export class SettingsPanelItem extends C this.addComponent(this.label); } - if (config.addSettingAsComponent) { + if (this.setting != null && this.config.addSettingAsComponent) { this.addComponent(this.setting); } } diff --git a/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts b/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts index e15b93806..9d2ab2c2a 100644 --- a/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts +++ b/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts @@ -47,10 +47,12 @@ export class SubtitleSettingsPanelPage extends ModernSettingsPanelPage { this.config = this.mergeConfig(config, { components: []>[ - new SettingsPanelPageBackButton({ - text: i18n.getLocalizer('back'), - container: this.settingsPanel, - cssClasses: ['ui-settings-panel-item-back'], + new SettingsPanelItem({ + label: new SettingsPanelPageBackButton({ + container: this.settingsPanel, + }), + setting: new SubtitleSettingsResetButton({}), + cssClasses: ['title-item'], }), new ModernSettingsPanelItem({ label: i18n.getLocalizer('settings.subtitles.font.size'), From cf3ff8a3be05cf29db71347b911d1e8c86b06943 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Mon, 9 Dec 2024 11:55:01 -0700 Subject: [PATCH 07/23] cleanup duplicate css for settings panel items --- src/scss/skin-super-modern/_skin.scss | 1 + .../components/_settingspanelitem.scss | 81 ++++++++++ .../components/_settingspanelpage.scss | 148 ------------------ .../_settingspanelpagebackbutton.scss | 62 ++++---- .../_settingspanelpageopenbutton.scss | 4 +- .../components/_settingstogglebutton.scss | 2 +- .../_subtitlesettingsresetbutton.scss | 2 +- src/ts/components/modernsettingspanelitem.ts | 1 - 8 files changed, 120 insertions(+), 181 deletions(-) create mode 100644 src/scss/skin-super-modern/components/_settingspanelitem.scss diff --git a/src/scss/skin-super-modern/_skin.scss b/src/scss/skin-super-modern/_skin.scss index cd706b96f..32a33dc77 100644 --- a/src/scss/skin-super-modern/_skin.scss +++ b/src/scss/skin-super-modern/_skin.scss @@ -20,6 +20,7 @@ @import 'components/label'; @import 'components/settingspanel'; @import 'components/settingspanelpage'; + @import 'components/settingspanelitem'; @import 'components/settingspanelpageopenbutton'; @import 'components/settingspanelpagebackbutton'; @import 'components/settingstogglebutton'; diff --git a/src/scss/skin-super-modern/components/_settingspanelitem.scss b/src/scss/skin-super-modern/components/_settingspanelitem.scss new file mode 100644 index 000000000..8ab515288 --- /dev/null +++ b/src/scss/skin-super-modern/components/_settingspanelitem.scss @@ -0,0 +1,81 @@ +@import '../variables'; + +%ui-settings-panel-item { + padding: .5em .7em; + white-space: nowrap; + + cursor: pointer; + * { + cursor: pointer; + } + + &:hover { + background-color: transparentize($color-item-hover, .15); + } + + &.#{$prefix}-hidden { + display: none; + } + + .#{$prefix}-container-wrapper { + align-items: center; + display: flex; + height: 100%; + width: 100%; + } + + > .#{$prefix}-container-wrapper { + column-gap: 10px; + } + + .#{$prefix}-ui-label { + display: inline-block; + font-size: .8em; + font-weight: 500; + margin: 0; + text-align: justify; + } + + .#{$prefix}-ui-label-setting-selected-option { + align-self: center; + font-weight: normal; + margin-left: auto; + width: fit-content; + + &::after { + background-image: url('../../assets/skin-super-modern/images/angle-right.svg'); + background-repeat: no-repeat; + background-size: 1.5em auto; + content: ' '; + display: inline-block; + height: 1.5em; + vertical-align: -.4em; + width: 1.5em; + } + } + + &.#{$prefix}-ui-settings-panel-item-select-option { + &.#{$prefix}-selected { + .#{$prefix}-ui-label { + &::before { + background-image: url('../../assets/skin-super-modern/images/check.svg'); + background-repeat: no-repeat; + background-size: 1.5em auto; + content: ' '; + display: inline-block; + height: 1.5em; + vertical-align: -.4em; + width: 1.5em; + } + } + } + } + + &.#{$prefix}-title-item { + border-bottom: 1px solid transparentize($color-item-hover, .15); + } +} + +.#{$prefix}-ui-settings-panel-item { + @extend %ui-settings-panel-item; +} \ No newline at end of file diff --git a/src/scss/skin-super-modern/components/_settingspanelpage.scss b/src/scss/skin-super-modern/components/_settingspanelpage.scss index 0996b3a95..4e687f702 100644 --- a/src/scss/skin-super-modern/components/_settingspanelpage.scss +++ b/src/scss/skin-super-modern/components/_settingspanelpage.scss @@ -6,154 +6,6 @@ &.#{$prefix}-active { display: block; } - - // A "line" in the panel: a container holding a label + control - .#{$prefix}-container-wrapper > * { - &.#{$prefix}-ui-label { - display: inline-block; - font-size: .8em; - font-weight: 500; - margin: 0; - text-align: justify; - } - - &.#{$prefix}-ui-label-setting-selected-option { - align-self: center; - font-weight: normal; - margin-left: auto; - width: fit-content; - - &::after { - background-image: url('../../assets/skin-super-modern/images/angle-right.svg'); - background-repeat: no-repeat; - background-size: 1.5em auto; - content: ' '; - display: inline-block; - height: 1.5em; - vertical-align: -.4em; - width: 1.5em; - } - } - - &.#{$prefix}-option { - font-weight: normal; - } - - // Controls (e.g. selectbox) - &.#{$prefix}-ui-selectbox { - margin-left: 10%; - width: 45%; - } - } - - .#{$prefix}-ui-settings-panel-item { - padding: .5em .7em; - white-space: nowrap; - - &:hover { - background-color: transparentize($color-item-hover, .15); - } - - &.#{$prefix}-hidden { - display: none; - } - - .#{$prefix}-container-wrapper { - align-items: center; - display: flex; - height: 100%; - width: 100%; - } - - > .#{$prefix}-container-wrapper { - column-gap: 10px; - } - } - - // TODO: de-duplicate this - .#{$prefix}-ui-settings-panel-item-select-option { - padding: .5em .7em; - white-space: nowrap; - - &:hover { - background-color: transparentize($color-item-hover, .15); - } - - &.#{$prefix}-hidden { - display: none; - } - - .#{$prefix}-container-wrapper { - align-items: center; - display: flex; - height: 100%; - width: 100%; - } - - &.#{$prefix}-selected { - .#{$prefix}-ui-label { - &::before { - background-image: url('../../assets/skin-super-modern/images/check.svg'); - background-repeat: no-repeat; - background-size: 1.5em auto; - content: ' '; - display: inline-block; - height: 1.5em; - vertical-align: -.4em; - width: 1.5em; - } - } - } - } - - // TODO: de-duplicate this - .#{$prefix}-ui-settings-panel-item-back { - @extend %ui-button; - - border-bottom: 1px solid transparentize($color-item-hover, .15);; - padding: .5em .7em; - white-space: nowrap; - - &:active { - transform: unset; - } - - &:hover { - background-color: transparentize($color-item-hover, .15); - } - - &.#{$prefix}-hidden { - display: none; - } - - //.#{$prefix}-container-wrapper { - align-items: center; - display: flex; - height: 100%; - width: 100%; - //} - - .#{$prefix}-label { - // TODO: de-duplicate this with the -ui-label from above - display: inline-block; - font-size: .8em; - font-weight: 500; - margin: 0; - text-align: justify; - width: 45%; - - &::before { - background-image: url('../../assets/skin-super-modern/images/angle-left.svg'); - background-repeat: no-repeat; - background-size: 1.5em auto; - content: ' '; - display: inline-block; - height: 1.5em; - vertical-align: -.4em; - width: 1.5em; - } - } - } } .#{$prefix}-ui-settings-panel-page { diff --git a/src/scss/skin-super-modern/components/_settingspanelpagebackbutton.scss b/src/scss/skin-super-modern/components/_settingspanelpagebackbutton.scss index a6bc3610d..5d1bcb218 100644 --- a/src/scss/skin-super-modern/components/_settingspanelpagebackbutton.scss +++ b/src/scss/skin-super-modern/components/_settingspanelpagebackbutton.scss @@ -1,29 +1,37 @@ @import '../variables'; -//%ui-settingspanelpagebackbutton { -// @extend %ui-button; -// -// font-size: .8em; -// position: relative; -// width: 8em; -// -// .#{$prefix}-label { -// display: inline-block; -// -// &::before { -// border-bottom: .2em solid $color-primary; -// border-left: .2em solid $color-primary; -// content: ''; -// height: .6em; -// margin-left: -.8em; -// position: absolute; -// top: .6em; -// transform: rotate(45deg); -// width: .6em; -// } -// } -//} -// -//.#{$prefix}-ui-settingspanelpagebackbutton { -// @extend %ui-settingspanelpagebackbutton; -//} +%ui-settingspanelpagebackbutton { + @extend %ui-button; + + border-collapse: collapse; + padding: unset; + flex: 1; + text-align: left; + + &:active { + transform: unset; + } + + .#{$prefix}-label { + display: inline-block; + font-size: .8em; + font-weight: 500; + margin: 0; + text-align: justify; + + &::before { + background-image: url('../../assets/skin-super-modern/images/angle-left.svg'); + background-repeat: no-repeat; + background-size: 1.5em auto; + content: ' '; + display: inline-block; + height: 1.5em; + vertical-align: -.4em; + width: 1.5em; + } + } +} + +.#{$prefix}-ui-settingspanelpagebackbutton { + @extend %ui-settingspanelpagebackbutton; +} diff --git a/src/scss/skin-super-modern/components/_settingspanelpageopenbutton.scss b/src/scss/skin-super-modern/components/_settingspanelpageopenbutton.scss index ab056005d..c4a99e3ae 100644 --- a/src/scss/skin-super-modern/components/_settingspanelpageopenbutton.scss +++ b/src/scss/skin-super-modern/components/_settingspanelpageopenbutton.scss @@ -6,15 +6,13 @@ background-image: url('../../assets/skin-super-modern/images/setting.svg'); max-height: .8em; - //padding: .5em 0; - //vertical-align: bottom; &:hover { @include svg-icon-shadow; } &.#{$prefix}-on { - background-image: url('../../assets/skin-super-modern/images/setting.svg'); + transform: rotate(30deg); } } diff --git a/src/scss/skin-super-modern/components/_settingstogglebutton.scss b/src/scss/skin-super-modern/components/_settingstogglebutton.scss index 889daaa23..35130618d 100644 --- a/src/scss/skin-super-modern/components/_settingstogglebutton.scss +++ b/src/scss/skin-super-modern/components/_settingstogglebutton.scss @@ -15,6 +15,6 @@ background-image: url('../../assets/skin-super-modern/images/setting.svg'); &.#{$prefix}-on { - background-image: url('../../assets/skin-super-modern/images/setting.svg'); + transform: rotate(30deg); } } diff --git a/src/scss/skin-super-modern/components/subtitlesettings/_subtitlesettingsresetbutton.scss b/src/scss/skin-super-modern/components/subtitlesettings/_subtitlesettingsresetbutton.scss index 1c5043bfb..799f0b9ba 100644 --- a/src/scss/skin-super-modern/components/subtitlesettings/_subtitlesettingsresetbutton.scss +++ b/src/scss/skin-super-modern/components/subtitlesettings/_subtitlesettingsresetbutton.scss @@ -4,7 +4,7 @@ @extend %ui-button; font-size: .8em; - width: 12em; + font-weight: 500; .#{$prefix}-label { display: inline-block; diff --git a/src/ts/components/modernsettingspanelitem.ts b/src/ts/components/modernsettingspanelitem.ts index a4b913ecc..439b63e52 100644 --- a/src/ts/components/modernsettingspanelitem.ts +++ b/src/ts/components/modernsettingspanelitem.ts @@ -115,7 +115,6 @@ export class ModernSettingsPanelItem extends SettingsPanelItem Date: Mon, 9 Dec 2024 11:56:21 -0700 Subject: [PATCH 08/23] enable the subtitle settings for the new ui layout --- src/ts/uifactory.ts | 76 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 17 deletions(-) diff --git a/src/ts/uifactory.ts b/src/ts/uifactory.ts index fd6fa7425..e6a8b5eb4 100644 --- a/src/ts/uifactory.ts +++ b/src/ts/uifactory.ts @@ -453,31 +453,64 @@ export namespace UIFactory { export function superModernMobileUI() { let subtitleOverlay = new SubtitleOverlay(); + let settingsPanel = new ModernSettingsPanel({ + components: [], + hidden: true, + pageTransitionAnimation: true, + hideDelay: -1, + }); + let mainSettingsPanelPage = new ModernSettingsPanelPage({ components: [ - // new ModernSettingsPanelItem(i18n.getLocalizer('settings.video.quality'), new VideoQualitySelectBox()), - // new ModernSettingsPanelItem(i18n.getLocalizer('speed'), new PlaybackSpeedSelectBox()), - // new ModernSettingsPanelItem(i18n.getLocalizer('settings.audio.track'), new AudioTrackSelectBox()), - // new ModernSettingsPanelItem(i18n.getLocalizer('settings.audio.quality'), new AudioQualitySelectBox()), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('settings.video.quality'), + setting: new VideoQualitySelectBox(), + container: settingsPanel, + }), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('speed'), + setting: new PlaybackSpeedSelectBox(), + container: settingsPanel, + }), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('settings.audio.track'), + setting: new AudioTrackSelectBox() , + container: settingsPanel, + }), + new ModernSettingsPanelItem({ + label: i18n.getLocalizer('settings.audio.quality'), + setting: new AudioQualitySelectBox(), + container: settingsPanel, + }), ], }); - let settingsPanel = new ModernSettingsPanel({ - components: [mainSettingsPanelPage], - hidden: true, - pageTransitionAnimation: true, - hideDelay: -1, + settingsPanel.addComponent(mainSettingsPanelPage); + + let subtitleSettingsPanelPage = new SubtitleSettingsPanelPage({ + settingsPanel: settingsPanel, + overlay: subtitleOverlay, + }); + + let subtitleSettingsOpenButton = new SettingsPanelPageOpenButton({ + targetPage: subtitleSettingsPanelPage, + container: settingsPanel, + ariaLabel: i18n.getLocalizer('settings.subtitles'), + text: i18n.getLocalizer('open'), }); const subtitleSelectBox = new SubtitleSelectBox(); - // let subtitleSelectItem = new ModernSettingsPanelItem( - // new Label({ text: i18n.getLocalizer('settings.subtitles') } as LabelConfig), - // subtitleSelectBox, - // { - // role: 'menubar', - // }, - // ); - // mainSettingsPanelPage.addComponent(subtitleSelectItem); + let subtitleSelectItem = new ModernSettingsPanelItem({ + label: new SubtitleSettingsLabel({ + text: i18n.getLocalizer('settings.subtitles'), + opener: subtitleSettingsOpenButton, + }), + setting: subtitleSelectBox, + role: 'menubar', + container: settingsPanel, + }); + mainSettingsPanelPage.addComponent(subtitleSelectItem); + settingsPanel.addComponent(subtitleSettingsPanelPage); let controlBar = new ControlBar({ components: [ @@ -572,6 +605,15 @@ export namespace UIFactory { }), ]; + 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 ModernSettingsPanelPage({ components, }); From d1ca0937288a393cd2847cfffb307fd39e1d08f3 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Mon, 9 Dec 2024 14:31:40 -0700 Subject: [PATCH 09/23] add empty line at EOF --- src/scss/skin-super-modern/components/_settingspanelitem.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scss/skin-super-modern/components/_settingspanelitem.scss b/src/scss/skin-super-modern/components/_settingspanelitem.scss index 8ab515288..868a073f7 100644 --- a/src/scss/skin-super-modern/components/_settingspanelitem.scss +++ b/src/scss/skin-super-modern/components/_settingspanelitem.scss @@ -78,4 +78,4 @@ .#{$prefix}-ui-settings-panel-item { @extend %ui-settings-panel-item; -} \ No newline at end of file +} From ebd13e4830a779edb991008561dd2eeae2da58ed Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Mon, 9 Dec 2024 15:58:58 -0700 Subject: [PATCH 10/23] remove the ModernSettingsPanel and ModernSettingsPanelPage and merge functionality in the default ones --- src/ts/components/modernsettingspanel.ts | 20 ------- src/ts/components/modernsettingspanelitem.ts | 23 +++----- src/ts/components/modernsettingspanelpage.ts | 59 ------------------- src/ts/components/settingspanel.ts | 7 ++- src/ts/components/settingspanelpage.ts | 13 ++-- .../subtitlesettingspanelpage.ts | 27 ++++----- src/ts/uifactory.ts | 17 +++--- 7 files changed, 43 insertions(+), 123 deletions(-) delete mode 100644 src/ts/components/modernsettingspanel.ts delete mode 100644 src/ts/components/modernsettingspanelpage.ts diff --git a/src/ts/components/modernsettingspanel.ts b/src/ts/components/modernsettingspanel.ts deleted file mode 100644 index fe0b5b0d5..000000000 --- a/src/ts/components/modernsettingspanel.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ModernSettingsPanelPage } from './modernsettingspanelpage'; -import { SettingsPanel } from './settingspanel'; - -export class ModernSettingsPanel extends SettingsPanel { - public addDynamicPage(page: ModernSettingsPanelPage): void { - this.addComponent(page); - this.updateComponents(); - } - - popSettingsPanelPage() { - const currentActivePage = this.getActivePage(); - - super.popSettingsPanelPage(); - - if (currentActivePage instanceof ModernSettingsPanelPage && currentActivePage.isDynamic) { - this.removeComponent(currentActivePage); - this.updateComponents(); - } - } -} diff --git a/src/ts/components/modernsettingspanelitem.ts b/src/ts/components/modernsettingspanelitem.ts index 439b63e52..70271a752 100644 --- a/src/ts/components/modernsettingspanelitem.ts +++ b/src/ts/components/modernsettingspanelitem.ts @@ -3,20 +3,15 @@ import {UIInstanceManager} from '../uimanager'; import {SelectBox} from './selectbox'; import { PlayerAPI } from 'bitmovin-player'; import { LocalizableText } from '../localization/i18n'; -import { ModernSettingsPanelPage } from './modernsettingspanelpage'; import { ListSelector, ListSelectorConfig } from './listselector'; import { SubtitleSelectBox } from './subtitleselectbox'; import { SettingsPanelItem, SettingsPanelItemConfig } from './settingspanelitem'; -import { - Component, - ComponentConfig, - Container, - ContainerConfig, - SettingsPanelPageBackButton, - SubtitleSettingSelectBox, SubtitleSettingsLabel, -} from '../main'; -import { ModernSettingsPanel } from './modernsettingspanel'; import { ModernSettingsPanelSelectOption } from './modernsettingspanelselectoption'; +import { SettingsPanelPage } from './settingspanelpage'; +import { SubtitleSettingsLabel } from './subtitlesettings/subtitlesettingslabel'; +import { SettingsPanel } from './settingspanel'; +import { SettingsPanelPageBackButton } from './settingspanelpagebackbutton'; +import { SubtitleSettingSelectBox } from './subtitlesettings/subtitlesettingselectbox'; /** * An item for a {@link ModernSettingsPanelPage}, @@ -26,7 +21,7 @@ import { ModernSettingsPanelSelectOption } from './modernsettingspanelselectopti export interface ModernSettingsPanelItemConfig extends SettingsPanelItemConfig { label: LocalizableText | SubtitleSettingsLabel; setting: ListSelector; - container: ModernSettingsPanel; + container: SettingsPanel; } export class ModernSettingsPanelItem extends SettingsPanelItem { @@ -106,9 +101,9 @@ export class ModernSettingsPanelItem extends SettingsPanelItem { e.stopPropagation(); handleItemClick(); }); } - private buildSubPanelPage(): ModernSettingsPanelPage { + private buildSubPanelPage(): SettingsPanelPage { const menuOptions = this.setting.getItems(); - const page = new ModernSettingsPanelPage({}, true); + const page = new SettingsPanelPage({ removeOnPop: true }); const text = this.config.label instanceof SubtitleSettingsLabel ? this.config.label.text : this.config.label; @@ -155,7 +150,7 @@ export class ModernSettingsPanelItem extends SettingsPanelItem(), - onRequestsNavigateBack: new EventDispatcher(), - }; - - constructor(config: ContainerConfig, isDynamic: boolean = false) { - super(config); - - this.isDynamic = isDynamic; - - this.config = this.mergeConfig(config, { - cssClass: 'ui-settings-panel-page', - role: 'menu', - }, this.config); - } - - configure(player: PlayerAPI, uimanager: UIInstanceManager): void { - super.configure(player, uimanager); - - // for (let component of this.getItems()) { - // if (component instanceof ModernSettingsPanelItem) { - // component.getOnDisplaySubPage.subscribe((_, args: ModernSettingsPanelPage) => this.requestsDisplaySubMenu(this, args)); - // component.getOnRequestNavigateBack.subscribe(() => this.modernSettingsPanelPageEvents.onRequestsNavigateBack.dispatch(this)); - // } - // } - } - - requestsDisplaySubMenu(_: Sender, args: ModernSettingsPanelPage) { - this.modernSettingsPanelPageEvents.onRequestsDisplaySubPage.dispatch(this, args); - } - - /** - * Is fired, when an item inside this page wants to show its sub-page - * This event is subscribed by the {@link ModernSettingsPanel}, which - * takes the page as an argument in order to display it. - */ - get onRequestsDisplaySubMenu(): Event { - return this.modernSettingsPanelPageEvents.onRequestsDisplaySubPage.getEvent(); - } - - get onRequestsNavigateBack(): Event { - return this.modernSettingsPanelPageEvents.onRequestsNavigateBack.getEvent(); - } - -} diff --git a/src/ts/components/settingspanel.ts b/src/ts/components/settingspanel.ts index 853574ca3..3a1cabc80 100644 --- a/src/ts/components/settingspanel.ts +++ b/src/ts/components/settingspanel.ts @@ -3,7 +3,7 @@ import { SelectBox } from './selectbox'; import { UIInstanceManager } from '../uimanager'; import { Timeout } from '../timeout'; import { Event, EventDispatcher, NoArgs } from '../eventdispatcher'; -import { SettingsPanelPage } from './settingspanelpage'; +import { SettingsPanelPage, SettingsPanelPageConfig } from './settingspanelpage'; import { SettingsPanelItem, SettingsPanelItemConfig } from './settingspanelitem'; import { PlayerAPI } from 'bitmovin-player'; import { Component, ComponentConfig } from './component'; @@ -261,6 +261,11 @@ export class SettingsPanel extends Container { super.addComponent(component); } + addPage(page: SettingsPanelPage) { + this.addComponent(page); + this.updateComponents(); + } + protected suspendHideTimeout() { this.hideTimeout.suspend(); } diff --git a/src/ts/components/settingspanelpage.ts b/src/ts/components/settingspanelpage.ts index 28818fbca..95117d44f 100644 --- a/src/ts/components/settingspanelpage.ts +++ b/src/ts/components/settingspanelpage.ts @@ -5,12 +5,16 @@ import {Event, EventDispatcher, NoArgs} from '../eventdispatcher'; import { PlayerAPI } from 'bitmovin-player'; import { BrowserUtils } from '../browserutils'; +export interface SettingsPanelPageConfig extends ContainerConfig { + removeOnPop?: Boolean; +} + /** * A panel containing a list of {@link SettingsPanelItem items} that represent labelled settings. * * @category Components */ -export class SettingsPanelPage extends Container { +export class SettingsPanelPage extends Container { private static readonly CLASS_LAST = 'last'; @@ -20,13 +24,14 @@ export class SettingsPanelPage extends Container { onInactive: new EventDispatcher(), }; - constructor(config: ContainerConfig) { + constructor(config: SettingsPanelPageConfig) { super(config); - this.config = this.mergeConfig(config, { + this.config = this.mergeConfig(config, { cssClass: 'ui-settings-panel-page', role: 'menu', - }, this.config); + removeOnPop: false, + } as SettingsPanelPageConfig, this.config); } configure(player: PlayerAPI, uimanager: UIInstanceManager): void { diff --git a/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts b/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts index 9d2ab2c2a..d50a405ad 100644 --- a/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts +++ b/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts @@ -1,8 +1,7 @@ -import {SettingsPanelPage} from '../settingspanelpage'; +import { SettingsPanelPage, SettingsPanelPageConfig } from '../settingspanelpage'; import {SettingsPanel} from '../settingspanel'; import {SubtitleOverlay} from '../subtitleoverlay'; import {ContainerConfig} from '../container'; -import {SubtitleSettingsManager} from './subtitlesettingsmanager'; import {Component, ComponentConfig} from '../component'; import {FontSizeSelectBox} from './fontsizeselectbox'; import {FontFamilySelectBox} from './fontfamilyselectbox'; @@ -19,14 +18,12 @@ import {SettingsPanelPageBackButton} from '../settingspanelpagebackbutton'; import {SettingsPanelItem} from '../settingspanelitem'; import { PlayerAPI } from 'bitmovin-player'; import { i18n } from '../../localization/i18n'; -import { ModernSettingsPanelPage } from '../modernsettingspanelpage'; import { ModernSettingsPanelItem } from '../modernsettingspanelitem'; -import { ModernSettingsPanel } from '../modernsettingspanel'; /** * @category Configs */ -export interface SubtitleSettingsPanelPageConfig extends ContainerConfig { +export interface SubtitleSettingsPanelPageConfig extends SettingsPanelPageConfig { settingsPanel: SettingsPanel; overlay: SubtitleOverlay; } @@ -34,7 +31,7 @@ export interface SubtitleSettingsPanelPageConfig extends ContainerConfig { /** * @category Components */ -export class SubtitleSettingsPanelPage extends ModernSettingsPanelPage { +export class SubtitleSettingsPanelPage extends SettingsPanelPage { private readonly overlay: SubtitleOverlay; private readonly settingsPanel: SettingsPanel; @@ -59,63 +56,63 @@ export class SubtitleSettingsPanelPage extends ModernSettingsPanelPage { setting: new FontSizeSelectBox({ overlay: this.overlay, }), - container: this.settingsPanel as ModernSettingsPanel, + container: this.settingsPanel, }), new ModernSettingsPanelItem({ label: i18n.getLocalizer('settings.subtitles.font.family'), setting: new FontFamilySelectBox({ overlay: this.overlay, }), - container: this.settingsPanel as ModernSettingsPanel, + container: this.settingsPanel, }), new ModernSettingsPanelItem({ label: i18n.getLocalizer('settings.subtitles.font.color'), setting: new FontColorSelectBox({ overlay: this.overlay, }), - container: this.settingsPanel as ModernSettingsPanel, + container: this.settingsPanel, }), new ModernSettingsPanelItem({ label: i18n.getLocalizer('settings.subtitles.font.opacity'), setting: new FontOpacitySelectBox({ overlay: this.overlay, }), - container: this.settingsPanel as ModernSettingsPanel, + container: this.settingsPanel, }), new ModernSettingsPanelItem({ label: i18n.getLocalizer('settings.subtitles.characterEdge'), setting: new CharacterEdgeSelectBox({ overlay: this.overlay, }), - container: this.settingsPanel as ModernSettingsPanel, + container: this.settingsPanel, }), new ModernSettingsPanelItem({ label: i18n.getLocalizer('settings.subtitles.background.color'), setting: new BackgroundColorSelectBox({ overlay: this.overlay, }), - container: this.settingsPanel as ModernSettingsPanel, + container: this.settingsPanel, }), new ModernSettingsPanelItem({ label: i18n.getLocalizer('settings.subtitles.background.opacity'), setting: new BackgroundOpacitySelectBox({ overlay: this.overlay, }), - container: this.settingsPanel as ModernSettingsPanel, + container: this.settingsPanel, }), new ModernSettingsPanelItem({ label: i18n.getLocalizer('settings.subtitles.window.color'), setting: new WindowColorSelectBox({ overlay: this.overlay, }), - container: this.settingsPanel as ModernSettingsPanel, + container: this.settingsPanel, }), new ModernSettingsPanelItem({ label: i18n.getLocalizer('settings.subtitles.window.opacity'), setting: new WindowOpacitySelectBox({ overlay: this.overlay, }), - container: this.settingsPanel as ModernSettingsPanel, + container: this.settingsPanel, }), ], }, this.config); diff --git a/src/ts/uifactory.ts b/src/ts/uifactory.ts index e6a8b5eb4..41a777a3a 100644 --- a/src/ts/uifactory.ts +++ b/src/ts/uifactory.ts @@ -1,6 +1,6 @@ import { SubtitleOverlay } from './components/subtitleoverlay'; -import { SettingsPanelPage } from './components/settingspanelpage'; -import { SettingsPanelItem, SettingsPanelItemConfig } from './components/settingspanelitem'; +import { SettingsPanelPage, SettingsPanelPageConfig } from './components/settingspanelpage'; +import { SettingsPanelItem } from './components/settingspanelitem'; import { VideoQualitySelectBox } from './components/videoqualityselectbox'; import { PlaybackSpeedSelectBox } from './components/playbackspeedselectbox'; import { AudioTrackSelectBox } from './components/audiotrackselectbox'; @@ -39,7 +39,7 @@ import { AdSkipButton } from './components/adskipbutton'; import { CloseButton } from './components/closebutton'; import { MetadataLabel, MetadataLabelContent } from './components/metadatalabel'; import { PlayerUtils } from './playerutils'; -import { Label, LabelConfig } from './components/label'; +import { Label } from './components/label'; import { CastUIContainer } from './components/castuicontainer'; import { UIConditionContext, UIManager } from './uimanager'; import { UIConfig } from './uiconfig'; @@ -51,10 +51,7 @@ import { SpatialNavigation } from './spatialnavigation/spatialnavigation'; import { RootNavigationGroup } from './spatialnavigation/rootnavigationgroup'; import { ListNavigationGroup, ListOrientation } from './spatialnavigation/ListNavigationGroup'; import { EcoModeContainer } from './components/ecomodecontainer'; -import { SubtitleToggleButton } from './components/subtitletogglebutton'; import { ModernSettingsPanelItem } from './components/modernsettingspanelitem'; -import { ModernSettingsPanelPage } from './components/modernsettingspanelpage'; -import { ModernSettingsPanel } from './components/modernsettingspanel'; import { TouchControlOverlay } from './components/touchcontroloverlay'; export namespace UIFactory { @@ -453,14 +450,14 @@ export namespace UIFactory { export function superModernMobileUI() { let subtitleOverlay = new SubtitleOverlay(); - let settingsPanel = new ModernSettingsPanel({ + let settingsPanel = new SettingsPanel({ components: [], hidden: true, pageTransitionAnimation: true, hideDelay: -1, }); - let mainSettingsPanelPage = new ModernSettingsPanelPage({ + let mainSettingsPanelPage = new SettingsPanelPage({ components: [ new ModernSettingsPanelItem({ label: i18n.getLocalizer('settings.video.quality'), @@ -576,7 +573,7 @@ export namespace UIFactory { let mainSettingsPanelPage: SettingsPanelPage; - let settingsPanel = new ModernSettingsPanel({ + let settingsPanel = new SettingsPanel({ components: [], hidden: true, pageTransitionAnimation: true, @@ -614,7 +611,7 @@ export namespace UIFactory { components.unshift(ecoModeContainer); - mainSettingsPanelPage = new ModernSettingsPanelPage({ + mainSettingsPanelPage = new SettingsPanelPage({ components, }); From f2b581be8fbdc9cf83154a645356074977d13815 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Mon, 9 Dec 2024 16:04:10 -0700 Subject: [PATCH 11/23] rename modern settings component to dynamic --- ...nelitem.ts => dynamicsettingspanelitem.ts} | 38 +++++++++++-------- ...option.ts => settingspanelselectoption.ts} | 27 ++++++++++--- .../subtitlesettingspanelpage.ts | 23 ++++++----- src/ts/components/subtitletogglebutton.ts | 6 +-- src/ts/uifactory.ts | 22 +++++------ 5 files changed, 69 insertions(+), 47 deletions(-) rename src/ts/components/{modernsettingspanelitem.ts => dynamicsettingspanelitem.ts} (84%) rename src/ts/components/{modernsettingspanelselectoption.ts => settingspanelselectoption.ts} (64%) diff --git a/src/ts/components/modernsettingspanelitem.ts b/src/ts/components/dynamicsettingspanelitem.ts similarity index 84% rename from src/ts/components/modernsettingspanelitem.ts rename to src/ts/components/dynamicsettingspanelitem.ts index 70271a752..e181f0fe9 100644 --- a/src/ts/components/modernsettingspanelitem.ts +++ b/src/ts/components/dynamicsettingspanelitem.ts @@ -1,12 +1,11 @@ import { Label, LabelConfig } from './label'; import {UIInstanceManager} from '../uimanager'; -import {SelectBox} from './selectbox'; import { PlayerAPI } from 'bitmovin-player'; import { LocalizableText } from '../localization/i18n'; import { ListSelector, ListSelectorConfig } from './listselector'; import { SubtitleSelectBox } from './subtitleselectbox'; import { SettingsPanelItem, SettingsPanelItemConfig } from './settingspanelitem'; -import { ModernSettingsPanelSelectOption } from './modernsettingspanelselectoption'; +import { SettingsPanelSelectOption } from './settingspanelselectoption'; import { SettingsPanelPage } from './settingspanelpage'; import { SubtitleSettingsLabel } from './subtitlesettings/subtitlesettingslabel'; import { SettingsPanel } from './settingspanel'; @@ -14,30 +13,39 @@ import { SettingsPanelPageBackButton } from './settingspanelpagebackbutton'; import { SubtitleSettingSelectBox } from './subtitlesettings/subtitlesettingselectbox'; /** - * An item for a {@link ModernSettingsPanelPage}, - * Containing an optional {@link Label} and a component that configures a setting. - * If the components is a {@link SelectBox} it will handle the logic of displaying it or not + * Configuration interface for a {@link DynamicSettingsPanelItem}. + * + * @category Configs */ -export interface ModernSettingsPanelItemConfig extends SettingsPanelItemConfig { +export interface DynamicSettingsPanelItemConfig extends SettingsPanelItemConfig { + /** + * The label component or the text for the label. + */ label: LocalizableText | SubtitleSettingsLabel; + /** + * The list selector component which will be used to build the sub page. + */ setting: ListSelector; + /** + * The enclosing {@link SettingsPanel} where the sub page will be added. + */ container: SettingsPanel; } -export class ModernSettingsPanelItem extends SettingsPanelItem { - - /** - * If setting is null, that means that the item is not an option and does not - * have a submenu. So if setting is null we can assume that the item should be - * used as a back button - */ +/** + * A dynamic settings panel item which can build a sub page with the items of a {@link ListSelector}. + * The page will be dynamically added and removed from the {@link SettingsPanel}. +* + * @category Components + */ +export class DynamicSettingsPanelItem extends SettingsPanelItem { private selectedOptionLabel: Label; protected setting: ListSelector; private player: PlayerAPI; private uimanager: UIInstanceManager; - constructor(config: ModernSettingsPanelItemConfig) { + constructor(config: DynamicSettingsPanelItemConfig) { // TODO: is that the way? -> Should this happen in configure? -> I think so config.addSettingAsComponent = false; @@ -120,7 +128,7 @@ export class ModernSettingsPanelItem extends SettingsPanelItem { - return new ModernSettingsPanelSelectOption({ + return new SettingsPanelSelectOption({ label: option.label, setting: this.setting, settingsValue: option.key, diff --git a/src/ts/components/modernsettingspanelselectoption.ts b/src/ts/components/settingspanelselectoption.ts similarity index 64% rename from src/ts/components/modernsettingspanelselectoption.ts rename to src/ts/components/settingspanelselectoption.ts index c26fda641..99af1b56b 100644 --- a/src/ts/components/modernsettingspanelselectoption.ts +++ b/src/ts/components/settingspanelselectoption.ts @@ -3,18 +3,33 @@ import { PlayerAPI } from 'bitmovin-player'; import { UIInstanceManager } from '../uimanager'; import { ListSelector, ListSelectorConfig } from './listselector'; -export interface ModernSettingsPanelSelectOptionConfig extends SettingsPanelItemConfig { +/** + * Configuration interface for a {@link SettingsPanelSelectOption}. + * + * @category Configs + */ +export interface SettingsPanelSelectOptionConfig extends SettingsPanelItemConfig { + /** + * The setting that will be changed when this option is clicked. + */ setting: ListSelector; + /** + * The value of the setting that will be selected when this option is clicked. + */ settingsValue: string | undefined; - autoCloseOnSelect?: boolean; } -export class ModernSettingsPanelSelectOption extends SettingsPanelItem { - +/** + * A custom select option for a {@link ListSelector} option. + * Is used for building dynamic sub pages from a {@link DynamicSettingsPanelItem}. + * + * @category Components + */ +export class SettingsPanelSelectOption extends SettingsPanelItem { private settingsValue: string | undefined; protected setting: ListSelector; - constructor(config: ModernSettingsPanelSelectOptionConfig) { + constructor(config: SettingsPanelSelectOptionConfig) { super(config); this.settingsValue = config.settingsValue; @@ -22,7 +37,7 @@ export class ModernSettingsPanelSelectOption extends SettingsPanelItem { /** * Requires the settingsPanelItem which holds the SubtitleSelectBox in its setting */ - private settingsPanelItem: ModernSettingsPanelItem; + private settingsPanelItem: DynamicSettingsPanelItem; private subtitleSelectBox: SubtitleSelectBox; private player: PlayerAPI; - constructor(settingsPanelItem: ModernSettingsPanelItem, subtitleSelectBox: SubtitleSelectBox, config: ToggleButtonConfig = {}) { + constructor(settingsPanelItem: DynamicSettingsPanelItem, subtitleSelectBox: SubtitleSelectBox, config: ToggleButtonConfig = {}) { super(config); this.settingsPanelItem = settingsPanelItem; diff --git a/src/ts/uifactory.ts b/src/ts/uifactory.ts index 41a777a3a..06afa66ab 100644 --- a/src/ts/uifactory.ts +++ b/src/ts/uifactory.ts @@ -51,7 +51,7 @@ import { SpatialNavigation } from './spatialnavigation/spatialnavigation'; import { RootNavigationGroup } from './spatialnavigation/rootnavigationgroup'; import { ListNavigationGroup, ListOrientation } from './spatialnavigation/ListNavigationGroup'; import { EcoModeContainer } from './components/ecomodecontainer'; -import { ModernSettingsPanelItem } from './components/modernsettingspanelitem'; +import { DynamicSettingsPanelItem } from './components/dynamicsettingspanelitem'; import { TouchControlOverlay } from './components/touchcontroloverlay'; export namespace UIFactory { @@ -459,22 +459,22 @@ export namespace UIFactory { let mainSettingsPanelPage = new SettingsPanelPage({ components: [ - new ModernSettingsPanelItem({ + new DynamicSettingsPanelItem({ label: i18n.getLocalizer('settings.video.quality'), setting: new VideoQualitySelectBox(), container: settingsPanel, }), - new ModernSettingsPanelItem({ + new DynamicSettingsPanelItem({ label: i18n.getLocalizer('speed'), setting: new PlaybackSpeedSelectBox(), container: settingsPanel, }), - new ModernSettingsPanelItem({ + new DynamicSettingsPanelItem({ label: i18n.getLocalizer('settings.audio.track'), setting: new AudioTrackSelectBox() , container: settingsPanel, }), - new ModernSettingsPanelItem({ + new DynamicSettingsPanelItem({ label: i18n.getLocalizer('settings.audio.quality'), setting: new AudioQualitySelectBox(), container: settingsPanel, @@ -497,7 +497,7 @@ export namespace UIFactory { }); const subtitleSelectBox = new SubtitleSelectBox(); - let subtitleSelectItem = new ModernSettingsPanelItem({ + let subtitleSelectItem = new DynamicSettingsPanelItem({ label: new SubtitleSettingsLabel({ text: i18n.getLocalizer('settings.subtitles'), opener: subtitleSettingsOpenButton, @@ -580,22 +580,22 @@ export namespace UIFactory { }); const components: Container[] = [ - new ModernSettingsPanelItem({ + new DynamicSettingsPanelItem({ label: i18n.getLocalizer('settings.video.quality'), setting: new VideoQualitySelectBox(), container: settingsPanel, }), - new ModernSettingsPanelItem({ + new DynamicSettingsPanelItem({ label: i18n.getLocalizer('speed'), setting: new PlaybackSpeedSelectBox(), container: settingsPanel, }), - new ModernSettingsPanelItem({ + new DynamicSettingsPanelItem({ label: i18n.getLocalizer('settings.audio.track'), setting: new AudioTrackSelectBox(), container: settingsPanel, }), - new ModernSettingsPanelItem({ + new DynamicSettingsPanelItem({ label: i18n.getLocalizer('settings.audio.quality'), setting: new AudioQualitySelectBox(), container: settingsPanel, @@ -630,7 +630,7 @@ export namespace UIFactory { }); const subtitleSelectBox = new SubtitleSelectBox(); - let subtitleSelectItem = new ModernSettingsPanelItem({ + let subtitleSelectItem = new DynamicSettingsPanelItem({ label: new SubtitleSettingsLabel({ text: i18n.getLocalizer('settings.subtitles'), opener: subtitleSettingsOpenButton, From 9fb9cc09d7f65cf6728adb21b7f6f0a7e4a97cf3 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Mon, 9 Dec 2024 16:22:47 -0700 Subject: [PATCH 12/23] improve settingspanelitem initialization and configuration --- src/ts/components/dynamicsettingspanelitem.ts | 4 --- src/ts/components/settingspanelitem.ts | 36 +++++++++++++------ 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/ts/components/dynamicsettingspanelitem.ts b/src/ts/components/dynamicsettingspanelitem.ts index e181f0fe9..eece698cb 100644 --- a/src/ts/components/dynamicsettingspanelitem.ts +++ b/src/ts/components/dynamicsettingspanelitem.ts @@ -46,14 +46,10 @@ export class DynamicSettingsPanelItem extends SettingsPanelItem Should this happen in configure? -> I think so - config.addSettingAsComponent = false; - super(config); this.setting = config.setting; - // TODO: this now does no longer work with the custom label with the opening button this.selectedOptionLabel = new Label({ text: '-', for: this.getConfig().id, diff --git a/src/ts/components/settingspanelitem.ts b/src/ts/components/settingspanelitem.ts index 7d0b7e66a..e3fd4c020 100644 --- a/src/ts/components/settingspanelitem.ts +++ b/src/ts/components/settingspanelitem.ts @@ -11,9 +11,23 @@ import {PlaybackSpeedSelectBox} from './playbackspeedselectbox'; import { PlayerAPI } from 'bitmovin-player'; import { LocalizableText } from '../localization/i18n'; +/** + * Configuration interface for a {@link SettingsPanelItem} + * + * @category Configs + */ export interface SettingsPanelItemConfig extends ContainerConfig { + /** + * The label component or the text for the label. + */ label?: LocalizableText | Component; + /** + * The component that configures a setting. + */ setting?: Component; + /** + * If the setting should be added as a component to this item. + */ addSettingAsComponent?: boolean; } @@ -33,17 +47,17 @@ export class SettingsPanelItem extends C onActiveChanged: new EventDispatcher, NoArgs>(), }; - constructor(config: SettingsPanelItemConfig) { - super(config as Config); + constructor(config: SettingsPanelItemConfig) + constructor(config: Config) { + super(config); this.setting = config.setting; - // TODO: this feels ugly -> typescript weak type problem (no matching property from parent) - this.config = this.mergeConfig(config as Config, { + this.config = this.mergeConfig(config, { cssClass: 'ui-settings-panel-item', role: 'menuitem', addSettingAsComponent: true, - } as Config, this.config as Config); + } as Config, this.config); const label = config.label; if (label !== null) { @@ -52,15 +66,19 @@ export class SettingsPanelItem extends C } else { this.label = new Label({ text: label } as LabelConfig); } + this.addComponent(this.label); } + } + + configure(player: PlayerAPI, uimanager: UIInstanceManager): void { + super.configure(player, uimanager); if (this.setting != null && this.config.addSettingAsComponent) { this.addComponent(this.setting); + this.updateComponents(); } - } - configure(player: PlayerAPI, uimanager: UIInstanceManager): void { if (this.setting instanceof SelectBox || this.setting instanceof ListBox) { let handleConfigItemChanged = () => { if (!(this.setting instanceof SelectBox) && !(this.setting instanceof ListBox)) { @@ -122,8 +140,4 @@ export class SettingsPanelItem extends C get onActiveChanged(): Event, NoArgs> { return this.settingsPanelItemEvents.onActiveChanged.getEvent(); } - - get getLabel(): Component { - return this.label; - } } From 0d9e490b5031246497a836ad4f14f974dfaedea6 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Tue, 10 Dec 2024 10:08:03 -0700 Subject: [PATCH 13/23] improve subtitle example overlay access --- src/ts/components/dynamicsettingspanelitem.ts | 12 ++++-------- .../subtitlesettings/subtitlesettingselectbox.ts | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/ts/components/dynamicsettingspanelitem.ts b/src/ts/components/dynamicsettingspanelitem.ts index eece698cb..3713f77d8 100644 --- a/src/ts/components/dynamicsettingspanelitem.ts +++ b/src/ts/components/dynamicsettingspanelitem.ts @@ -138,15 +138,11 @@ export class DynamicSettingsPanelItem extends SettingsPanelItem { - (this.setting).overlay.enablePreviewSubtitleLabel(); - }); - - page.onInactive.subscribe(() => { - (this.setting).overlay.removePreviewSubtitleLabel(); - }); + page.onActive.subscribe(() => setting.overlay.enablePreviewSubtitleLabel()); + page.onInactive.subscribe(() => setting.overlay.removePreviewSubtitleLabel()); } return page; diff --git a/src/ts/components/subtitlesettings/subtitlesettingselectbox.ts b/src/ts/components/subtitlesettings/subtitlesettingselectbox.ts index a33c1c113..eba68286f 100644 --- a/src/ts/components/subtitlesettings/subtitlesettingselectbox.ts +++ b/src/ts/components/subtitlesettings/subtitlesettingselectbox.ts @@ -20,7 +20,7 @@ export interface SubtitleSettingSelectBoxConfig extends ListSelectorConfig { export class SubtitleSettingSelectBox extends SelectBox { protected settingsManager?: SubtitleSettingsManager; - public overlay: SubtitleOverlay; + readonly overlay: SubtitleOverlay; private currentCssClass: string; constructor(config: SubtitleSettingSelectBoxConfig) { From 9c6c20fb61ae8781bca831db7c023bd15da97007 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Tue, 10 Dec 2024 10:08:12 -0700 Subject: [PATCH 14/23] add documentation --- src/ts/components/settingspanelpage.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ts/components/settingspanelpage.ts b/src/ts/components/settingspanelpage.ts index 95117d44f..de6e09456 100644 --- a/src/ts/components/settingspanelpage.ts +++ b/src/ts/components/settingspanelpage.ts @@ -5,7 +5,15 @@ import {Event, EventDispatcher, NoArgs} from '../eventdispatcher'; import { PlayerAPI } from 'bitmovin-player'; import { BrowserUtils } from '../browserutils'; +/** + * Configuration interface for a {@link SettingsPanelPage} + * + * @category Configs + */ export interface SettingsPanelPageConfig extends ContainerConfig { + /** + * If the page should be removed from the DOM when it is popped from the navigation stack. + */ removeOnPop?: Boolean; } From 9626fedb8d0801d7d25c3b862d9c3f09e11a4c0f Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Tue, 10 Dec 2024 10:08:18 -0700 Subject: [PATCH 15/23] remove outdated todo --- src/ts/components/settingspanel.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ts/components/settingspanel.ts b/src/ts/components/settingspanel.ts index 3a1cabc80..184b48d44 100644 --- a/src/ts/components/settingspanel.ts +++ b/src/ts/components/settingspanel.ts @@ -337,7 +337,6 @@ export class SettingsPanel extends Container { const settingsPanelHTMLElement = this.getDomElement().get(0); // get current dimension - // TODO: handle resizing properly const settingsPanelWidth = settingsPanelHTMLElement.scrollWidth; const settingsPanelHeight = settingsPanelHTMLElement.scrollHeight; From a0497f5f5e7f151622f16def097e06fc8eecefc4 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Tue, 10 Dec 2024 10:08:28 -0700 Subject: [PATCH 16/23] minor code style improvements --- src/ts/components/dynamicsettingspanelitem.ts | 7 +++++-- .../subtitlesettingselectbox.ts | 2 +- .../subtitlesettings/subtitlesettingslabel.ts | 17 +---------------- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/ts/components/dynamicsettingspanelitem.ts b/src/ts/components/dynamicsettingspanelitem.ts index 3713f77d8..54c85614f 100644 --- a/src/ts/components/dynamicsettingspanelitem.ts +++ b/src/ts/components/dynamicsettingspanelitem.ts @@ -1,5 +1,5 @@ import { Label, LabelConfig } from './label'; -import {UIInstanceManager} from '../uimanager'; +import { UIInstanceManager } from '../uimanager'; import { PlayerAPI } from 'bitmovin-player'; import { LocalizableText } from '../localization/i18n'; import { ListSelector, ListSelectorConfig } from './listselector'; @@ -102,7 +102,10 @@ export class DynamicSettingsPanelItem extends SettingsPanelItem { this.displayItemsSubPage(); }; - this.getDomElement().on('click', (e) => { e.stopPropagation(); handleItemClick(); }); + this.getDomElement().on('click', (e) => { + e.stopPropagation(); + handleItemClick(); + }); } private buildSubPanelPage(): SettingsPanelPage { diff --git a/src/ts/components/subtitlesettings/subtitlesettingselectbox.ts b/src/ts/components/subtitlesettings/subtitlesettingselectbox.ts index eba68286f..605849d10 100644 --- a/src/ts/components/subtitlesettings/subtitlesettingselectbox.ts +++ b/src/ts/components/subtitlesettings/subtitlesettingselectbox.ts @@ -48,6 +48,6 @@ export class SubtitleSettingSelectBox extends SelectBox { } configure(player: PlayerAPI, uimanager: UIInstanceManager): void { - this.settingsManager = uimanager.getSubtitleSettingsManager(); + this.settingsManager = uimanager.getSubtitleSettingsManager(); } } diff --git a/src/ts/components/subtitlesettings/subtitlesettingslabel.ts b/src/ts/components/subtitlesettings/subtitlesettingslabel.ts index 6a9a1761a..1560208dd 100644 --- a/src/ts/components/subtitlesettings/subtitlesettingslabel.ts +++ b/src/ts/components/subtitlesettings/subtitlesettingslabel.ts @@ -1,8 +1,7 @@ import { Label, LabelConfig } from '../label'; import {Container, ContainerConfig} from '../container'; -import {DOM} from '../../dom'; import {SettingsPanelPageOpenButton} from '../settingspanelpageopenbutton'; -import { LocalizableText, i18n } from '../../localization/i18n'; +import { LocalizableText } from '../../localization/i18n'; /** * @category Configs @@ -30,24 +29,10 @@ export class SubtitleSettingsLabel extends Container { this.for = config.for; this.config = this.mergeConfig(config, { - // cssClass: 'ui-label', components: [ new Label({ text: this.text, for: this.for } as LabelConfig), this.opener, ], }, this.config); } - - // protected toDomElement(): DOM { - // let labelElement = new DOM('label', { - // 'id': this.config.id, - // 'class': this.getCssClasses(), - // 'for': this.for, - // }, this).append( - // new DOM('span', {}).html(i18n.performLocalization(this.text)), - // this.opener.getDomElement(), - // ); - // - // return labelElement; - // } } From 0dff63a574ec37c14c55765611746f812bd644ec Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Tue, 10 Dec 2024 11:58:54 -0700 Subject: [PATCH 17/23] add support to include the SubtitleSettingsPanelPage in the old and new skin --- .../components/_settingspanelpage.scss | 9 + .../subtitlesettings/subtitlesettingslabel.ts | 1 + .../subtitlesettingspanelpage.ts | 162 +++++++++++------- src/ts/uifactory.ts | 4 +- 4 files changed, 109 insertions(+), 67 deletions(-) diff --git a/src/scss/skin-modern/components/_settingspanelpage.scss b/src/scss/skin-modern/components/_settingspanelpage.scss index 97a0d3ec1..5bd94716a 100644 --- a/src/scss/skin-modern/components/_settingspanelpage.scss +++ b/src/scss/skin-modern/components/_settingspanelpage.scss @@ -16,6 +16,15 @@ width: 45%; } + &.#{$prefix}-ui-subtitle-settings-label { + display: inline-block; + width: 45%; + + .#{$prefix}-ui-label { + margin-right: 10px; + } + } + // Controls (e.g. selectbox) &.#{$prefix}-ui-selectbox { margin-left: 10%; diff --git a/src/ts/components/subtitlesettings/subtitlesettingslabel.ts b/src/ts/components/subtitlesettings/subtitlesettingslabel.ts index 1560208dd..184c8c265 100644 --- a/src/ts/components/subtitlesettings/subtitlesettingslabel.ts +++ b/src/ts/components/subtitlesettings/subtitlesettingslabel.ts @@ -33,6 +33,7 @@ export class SubtitleSettingsLabel extends Container { new Label({ text: this.text, for: this.for } as LabelConfig), this.opener, ], + cssClass: 'ui-subtitle-settings-label', }, this.config); } } diff --git a/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts b/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts index 4752c2cdc..55c3147e0 100644 --- a/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts +++ b/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts @@ -14,10 +14,11 @@ import {WindowOpacitySelectBox} from './windowopacityselectbox'; import {SubtitleSettingsResetButton} from './subtitlesettingsresetbutton'; import {UIInstanceManager} from '../../uimanager'; import {SettingsPanelPageBackButton} from '../settingspanelpagebackbutton'; -import {SettingsPanelItem} from '../settingspanelitem'; +import { SettingsPanelItem, SettingsPanelItemConfig } from '../settingspanelitem'; import { PlayerAPI } from 'bitmovin-player'; -import { i18n } from '../../localization/i18n'; +import { i18n, LocalizableText } from '../../localization/i18n'; import { DynamicSettingsPanelItem } from '../dynamicsettingspanelitem'; +import { ListSelector, ListSelectorConfig } from '../listselector'; /** * @category Configs @@ -25,6 +26,7 @@ import { DynamicSettingsPanelItem } from '../dynamicsettingspanelitem'; export interface SubtitleSettingsPanelPageConfig extends SettingsPanelPageConfig { settingsPanel: SettingsPanel; overlay: SubtitleOverlay; + useDynamicSettingsPanelItem?: boolean; } /** @@ -41,79 +43,88 @@ export class SubtitleSettingsPanelPage extends SettingsPanelPage { this.overlay = config.overlay; this.settingsPanel = config.settingsPanel; - this.config = this.mergeConfig(config, { - components: []>[ - new SettingsPanelItem({ - label: new SettingsPanelPageBackButton({ - container: this.settingsPanel, - }), - setting: new SubtitleSettingsResetButton({}), - cssClasses: ['title-item'], - }), - new DynamicSettingsPanelItem({ - label: i18n.getLocalizer('settings.subtitles.font.size'), - setting: new FontSizeSelectBox({ - overlay: this.overlay, - }), - container: this.settingsPanel, + const components = [ + this.buildSettingsPanelItem( + i18n.getLocalizer('settings.subtitles.font.size'), + new FontSizeSelectBox({ + overlay: this.overlay, }), - new DynamicSettingsPanelItem({ - label: i18n.getLocalizer('settings.subtitles.font.family'), - setting: new FontFamilySelectBox({ - overlay: this.overlay, - }), - container: this.settingsPanel, + config.useDynamicSettingsPanelItem, + ), + this.buildSettingsPanelItem( + i18n.getLocalizer('settings.subtitles.font.family'), + new FontFamilySelectBox({ + overlay: this.overlay, }), - new DynamicSettingsPanelItem({ - label: i18n.getLocalizer('settings.subtitles.font.color'), - setting: new FontColorSelectBox({ - overlay: this.overlay, - }), - container: this.settingsPanel, + config.useDynamicSettingsPanelItem, + ), + this.buildSettingsPanelItem( + i18n.getLocalizer('settings.subtitles.font.color'), + new FontColorSelectBox({ + overlay: this.overlay, }), - new DynamicSettingsPanelItem({ - label: i18n.getLocalizer('settings.subtitles.font.opacity'), - setting: new FontOpacitySelectBox({ - overlay: this.overlay, - }), - container: this.settingsPanel, + config.useDynamicSettingsPanelItem, + ), + this.buildSettingsPanelItem( + i18n.getLocalizer('settings.subtitles.font.opacity'), + new FontOpacitySelectBox({ + overlay: this.overlay, }), - new DynamicSettingsPanelItem({ - label: i18n.getLocalizer('settings.subtitles.characterEdge'), - setting: new CharacterEdgeSelectBox({ - overlay: this.overlay, - }), - container: this.settingsPanel, + config.useDynamicSettingsPanelItem, + ), + this.buildSettingsPanelItem( + i18n.getLocalizer('settings.subtitles.characterEdge'), + new CharacterEdgeSelectBox({ + overlay: this.overlay, }), - new DynamicSettingsPanelItem({ - label: i18n.getLocalizer('settings.subtitles.background.color'), - setting: new BackgroundColorSelectBox({ - overlay: this.overlay, - }), - container: this.settingsPanel, + config.useDynamicSettingsPanelItem, + ), + this.buildSettingsPanelItem( + i18n.getLocalizer('settings.subtitles.background.color'), + new BackgroundColorSelectBox({ + overlay: this.overlay, }), - new DynamicSettingsPanelItem({ - label: i18n.getLocalizer('settings.subtitles.background.opacity'), - setting: new BackgroundOpacitySelectBox({ - overlay: this.overlay, - }), - container: this.settingsPanel, + config.useDynamicSettingsPanelItem, + ), + this.buildSettingsPanelItem( + i18n.getLocalizer('settings.subtitles.background.opacity'), + new BackgroundOpacitySelectBox({ + overlay: this.overlay, }), - new DynamicSettingsPanelItem({ - label: i18n.getLocalizer('settings.subtitles.window.color'), - setting: new WindowColorSelectBox({ - overlay: this.overlay, - }), - container: this.settingsPanel, + config.useDynamicSettingsPanelItem, + ), + this.buildSettingsPanelItem( + i18n.getLocalizer('settings.subtitles.window.color'), + new WindowColorSelectBox({ + overlay: this.overlay, }), - new DynamicSettingsPanelItem({ - label: i18n.getLocalizer('settings.subtitles.window.opacity'), - setting: new WindowOpacitySelectBox({ - overlay: this.overlay, - }), - container: this.settingsPanel, + config.useDynamicSettingsPanelItem, + ), + this.buildSettingsPanelItem( + i18n.getLocalizer('settings.subtitles.window.opacity'), + new WindowOpacitySelectBox({ + overlay: this.overlay, }), - ], + config.useDynamicSettingsPanelItem, + ), + ]; + + const backItem = new SettingsPanelItem({ + label: new SettingsPanelPageBackButton({ + container: this.settingsPanel, + }), + setting: new SubtitleSettingsResetButton({}), + cssClasses: ['title-item'], + }); + + if (config.useDynamicSettingsPanelItem) { + components.unshift(backItem); + } else { + components.push(backItem); + } + + this.config = this.mergeConfig(config, { + components: components, }, this.config); } @@ -128,4 +139,23 @@ export class SubtitleSettingsPanelPage extends SettingsPanelPage { this.overlay.removePreviewSubtitleLabel(); }); } + + private buildSettingsPanelItem( + label: LocalizableText, + setting: ListSelector, + useDynamicSettingsPanelItem: boolean = false, + ): SettingsPanelItem { + if (useDynamicSettingsPanelItem) { + return new DynamicSettingsPanelItem({ + label: label, + setting: setting, + container: this.settingsPanel, + }); + } else { + return new SettingsPanelItem({ + label: label, + setting: setting, + }); + } + } } diff --git a/src/ts/uifactory.ts b/src/ts/uifactory.ts index 06afa66ab..6189d3b2b 100644 --- a/src/ts/uifactory.ts +++ b/src/ts/uifactory.ts @@ -1,5 +1,5 @@ import { SubtitleOverlay } from './components/subtitleoverlay'; -import { SettingsPanelPage, SettingsPanelPageConfig } from './components/settingspanelpage'; +import { SettingsPanelPage } from './components/settingspanelpage'; import { SettingsPanelItem } from './components/settingspanelitem'; import { VideoQualitySelectBox } from './components/videoqualityselectbox'; import { PlaybackSpeedSelectBox } from './components/playbackspeedselectbox'; @@ -487,6 +487,7 @@ export namespace UIFactory { let subtitleSettingsPanelPage = new SubtitleSettingsPanelPage({ settingsPanel: settingsPanel, overlay: subtitleOverlay, + useDynamicSettingsPanelItem: true, }); let subtitleSettingsOpenButton = new SettingsPanelPageOpenButton({ @@ -620,6 +621,7 @@ export namespace UIFactory { let subtitleSettingsPanelPage = new SubtitleSettingsPanelPage({ settingsPanel: settingsPanel, overlay: subtitleOverlay, + useDynamicSettingsPanelItem: true, }); let subtitleSettingsOpenButton = new SettingsPanelPageOpenButton({ From ad708ce73797ff5864a3f3a768be313e55a151d3 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Tue, 10 Dec 2024 12:01:28 -0700 Subject: [PATCH 18/23] hide the eco mode container behind the ecoMode flag when creating the new layout --- src/ts/uifactory.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/ts/uifactory.ts b/src/ts/uifactory.ts index 6189d3b2b..627e47308 100644 --- a/src/ts/uifactory.ts +++ b/src/ts/uifactory.ts @@ -569,7 +569,7 @@ export namespace UIFactory { }); } - export function superModernUI() { + export function superModernUI(config: UIConfig) { let subtitleOverlay = new SubtitleOverlay(); let mainSettingsPanelPage: SettingsPanelPage; @@ -603,14 +603,16 @@ export namespace UIFactory { }), ]; - const ecoModeContainer = new EcoModeContainer(); + 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: '' }); - }); + 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); + components.unshift(ecoModeContainer); + } mainSettingsPanelPage = new SettingsPanelPage({ components, @@ -734,7 +736,7 @@ export namespace UIFactory { }, }, { - ui: superModernUI(), + ui: superModernUI(config), condition: (context: UIConditionContext) => { return !context.isAd && !context.adRequiresUi; }, From b2e0324e7b6f3d9c5706386bd1a3613f6fa386ee Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Tue, 10 Dec 2024 12:14:17 -0700 Subject: [PATCH 19/23] fix failing tests --- spec/components/listselector.spec.ts | 2 +- spec/components/settingspanel.spec.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/components/listselector.spec.ts b/spec/components/listselector.spec.ts index c806f0253..88483ab2e 100644 --- a/spec/components/listselector.spec.ts +++ b/spec/components/listselector.spec.ts @@ -165,7 +165,7 @@ describe('ListSelector', () => { it('returns false if selected item does not exist', () => { const result = listSelector.selectItem('notExistingKey'); - expect(listSelector.getSelectedItem()).toBeUndefined(); + expect(listSelector.getSelectedItem()).toBeNull(); expect(result).toBeFalsy(); }); diff --git a/spec/components/settingspanel.spec.ts b/spec/components/settingspanel.spec.ts index 99cb17ab6..46778f883 100644 --- a/spec/components/settingspanel.spec.ts +++ b/spec/components/settingspanel.spec.ts @@ -224,8 +224,8 @@ describe('SettingsPanel', () => { const selectBox = new SelectBox(); const closeDropdownSpy = jest.spyOn(selectBox, 'closeDropdown'); - settingsPanel.getActivePage().addComponent(new SettingsPanelItem(new Label(), selectBox)); - settingsPanel.getActivePage().addComponent(new SettingsPanelItem(new Label(), new VolumeSlider())); + settingsPanel.getActivePage().addComponent(new SettingsPanelItem({ label: new Label(), setting: selectBox })); + settingsPanel.getActivePage().addComponent(new SettingsPanelItem({ label: new Label(), setting: new VolumeSlider() })); settingsPanel['hideHoveredSelectBoxes'](); From 38f83ec211c73100762a4a6f2823af4258a2adbf Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Tue, 10 Dec 2024 19:11:10 -0700 Subject: [PATCH 20/23] add missing removing from dynamic settings panel pages --- src/ts/components/settingspanel.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ts/components/settingspanel.ts b/src/ts/components/settingspanel.ts index 184b48d44..9bb25779c 100644 --- a/src/ts/components/settingspanel.ts +++ b/src/ts/components/settingspanel.ts @@ -217,12 +217,18 @@ export class SettingsPanel extends Container { targetPage = this.getRootPage(); } + const currentActivePage = this.activePage; this.navigateToPage( targetPage, this.activePage, NavigationDirection.Backwards, !(this.config as SettingsPanelConfig).pageTransitionAnimation, ); + + if (currentActivePage.getConfig().removeOnPop) { + this.removeComponent(currentActivePage); + this.updateComponents(); + } } /** From 86ff8c61bdc69b5ca43b8b57747dc9193f8ff17d Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Tue, 10 Dec 2024 20:44:11 -0700 Subject: [PATCH 21/23] add line-height to the settings panel item to ensure all have the same height --- src/scss/skin-super-modern/components/_settingspanelitem.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/src/scss/skin-super-modern/components/_settingspanelitem.scss b/src/scss/skin-super-modern/components/_settingspanelitem.scss index 868a073f7..574cf9392 100644 --- a/src/scss/skin-super-modern/components/_settingspanelitem.scss +++ b/src/scss/skin-super-modern/components/_settingspanelitem.scss @@ -1,6 +1,7 @@ @import '../variables'; %ui-settings-panel-item { + line-height: 1.5em; padding: .5em .7em; white-space: nowrap; From 59a7bf5ec18e6c9b2615dbb7240dd53fe8dcaac1 Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Fri, 20 Dec 2024 08:48:34 +0100 Subject: [PATCH 22/23] rename setting to settingComponent --- src/ts/components/dynamicsettingspanelitem.ts | 24 +++++----- src/ts/components/ecomodecontainer.ts | 4 +- src/ts/components/settingspanel.ts | 2 +- src/ts/components/settingspanelitem.ts | 26 +++++------ .../components/settingspanelselectoption.ts | 10 ++--- .../subtitlesettingspanelpage.ts | 6 +-- src/ts/demofactory.ts | 10 ++--- src/ts/uifactory.ts | 44 +++++++++---------- 8 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/ts/components/dynamicsettingspanelitem.ts b/src/ts/components/dynamicsettingspanelitem.ts index 54c85614f..72ae6a01b 100644 --- a/src/ts/components/dynamicsettingspanelitem.ts +++ b/src/ts/components/dynamicsettingspanelitem.ts @@ -25,7 +25,7 @@ export interface DynamicSettingsPanelItemConfig extends SettingsPanelItemConfig /** * The list selector component which will be used to build the sub page. */ - setting: ListSelector; + settingComponent: ListSelector; /** * The enclosing {@link SettingsPanel} where the sub page will be added. */ @@ -40,7 +40,7 @@ export interface DynamicSettingsPanelItemConfig extends SettingsPanelItemConfig */ export class DynamicSettingsPanelItem extends SettingsPanelItem { private selectedOptionLabel: Label; - protected setting: ListSelector; + protected settingComponent: ListSelector; private player: PlayerAPI; private uimanager: UIInstanceManager; @@ -48,7 +48,7 @@ export class DynamicSettingsPanelItem extends SettingsPanelItem { - let selectedItem = this.setting.getItemForKey(this.setting.getSelectedItem()); + let selectedItem = this.settingComponent.getItemForKey(this.settingComponent.getSelectedItem()); if (selectedItem == null) { this.selectedOptionLabel.hide(); return; @@ -89,13 +89,13 @@ export class DynamicSettingsPanelItem extends SettingsPanelItem { return new SettingsPanelSelectOption({ label: option.label, - setting: this.setting, + settingComponent: this.settingComponent, settingsValue: option.key, addSettingAsComponent: false, }); @@ -141,7 +141,7 @@ export class DynamicSettingsPanelItem extends SettingsPanelItem setting.overlay.enablePreviewSubtitleLabel()); diff --git a/src/ts/components/ecomodecontainer.ts b/src/ts/components/ecomodecontainer.ts index dac5dc589..77bb7b4e5 100644 --- a/src/ts/components/ecomodecontainer.ts +++ b/src/ts/components/ecomodecontainer.ts @@ -29,10 +29,10 @@ export class EcoModeContainer extends Container { cssClass: 'ui-label-savedEnergy', }); - this.ecoModeToggleButtonItem = new SettingsPanelItem({ label: labelEcoMode, setting: ecoModeToggleButton }); + this.ecoModeToggleButtonItem = new SettingsPanelItem({ label: labelEcoMode, settingComponent: ecoModeToggleButton }); this.ecoModeSavedEmissionsItem = new SettingsPanelItem({ label: 'Saved Emissions', - setting: this.emissionsSavedLabel, + settingComponent: this.emissionsSavedLabel, hidden: true, }); diff --git a/src/ts/components/settingspanel.ts b/src/ts/components/settingspanel.ts index 9bb25779c..dade69b86 100644 --- a/src/ts/components/settingspanel.ts +++ b/src/ts/components/settingspanel.ts @@ -399,7 +399,7 @@ export class SettingsPanel extends Container { */ private hideHoveredSelectBoxes(): void { this.getComputedItems() - .map(item => item['setting']) + .map(item => item['settingComponent']) .filter(component => component instanceof SelectBox) .forEach((selectBox: SelectBox) => selectBox.closeDropdown()); } diff --git a/src/ts/components/settingspanelitem.ts b/src/ts/components/settingspanelitem.ts index e3fd4c020..50a8fddea 100644 --- a/src/ts/components/settingspanelitem.ts +++ b/src/ts/components/settingspanelitem.ts @@ -24,7 +24,7 @@ export interface SettingsPanelItemConfig extends ContainerConfig { /** * The component that configures a setting. */ - setting?: Component; + settingComponent?: Component; /** * If the setting should be added as a component to this item. */ @@ -41,7 +41,7 @@ export interface SettingsPanelItemConfig extends ContainerConfig { export class SettingsPanelItem extends Container { private label: Component; - protected setting: Component | null; + protected settingComponent: Component | null; private settingsPanelItemEvents = { onActiveChanged: new EventDispatcher, NoArgs>(), @@ -51,7 +51,7 @@ export class SettingsPanelItem extends C constructor(config: Config) { super(config); - this.setting = config.setting; + this.settingComponent = config.settingComponent; this.config = this.mergeConfig(config, { cssClass: 'ui-settings-panel-item', @@ -74,14 +74,14 @@ export class SettingsPanelItem extends C configure(player: PlayerAPI, uimanager: UIInstanceManager): void { super.configure(player, uimanager); - if (this.setting != null && this.config.addSettingAsComponent) { - this.addComponent(this.setting); + if (this.settingComponent != null && this.config.addSettingAsComponent) { + this.addComponent(this.settingComponent); this.updateComponents(); } - if (this.setting instanceof SelectBox || this.setting instanceof ListBox) { + if (this.settingComponent instanceof SelectBox || this.settingComponent instanceof ListBox) { let handleConfigItemChanged = () => { - if (!(this.setting instanceof SelectBox) && !(this.setting instanceof ListBox)) { + if (!(this.settingComponent instanceof SelectBox) && !(this.settingComponent instanceof ListBox)) { return; } // The minimum number of items that must be available for the setting to be displayed @@ -89,15 +89,15 @@ export class SettingsPanelItem extends C let minItemsToDisplay = 2; // Audio/video quality select boxes contain an additional 'auto' mode, which in combination with a single // available quality also does not make sense - if ((this.setting instanceof VideoQualitySelectBox && this.setting.hasAutoItem()) - || this.setting instanceof AudioQualitySelectBox) { + if ((this.settingComponent instanceof VideoQualitySelectBox && this.settingComponent.hasAutoItem()) + || this.settingComponent instanceof AudioQualitySelectBox) { minItemsToDisplay = 3; } - if (this.setting.itemCount() < minItemsToDisplay) { + if (this.settingComponent.itemCount() < minItemsToDisplay) { // Hide the setting if no meaningful choice is available this.hide(); - } else if (this.setting instanceof PlaybackSpeedSelectBox + } else if (this.settingComponent instanceof PlaybackSpeedSelectBox && !uimanager.getConfig().playbackSpeedSelectionEnabled) { // Hide the PlaybackSpeedSelectBox if disabled in config this.hide(); @@ -112,8 +112,8 @@ export class SettingsPanelItem extends C this.getDomElement().attr('aria-haspopup', 'true'); }; - this.setting.onItemAdded.subscribe(handleConfigItemChanged); - this.setting.onItemRemoved.subscribe(handleConfigItemChanged); + this.settingComponent.onItemAdded.subscribe(handleConfigItemChanged); + this.settingComponent.onItemRemoved.subscribe(handleConfigItemChanged); // Initialize hidden state handleConfigItemChanged(); diff --git a/src/ts/components/settingspanelselectoption.ts b/src/ts/components/settingspanelselectoption.ts index 99af1b56b..bb1a55b5b 100644 --- a/src/ts/components/settingspanelselectoption.ts +++ b/src/ts/components/settingspanelselectoption.ts @@ -12,7 +12,7 @@ export interface SettingsPanelSelectOptionConfig extends SettingsPanelItemConfig /** * The setting that will be changed when this option is clicked. */ - setting: ListSelector; + settingComponent: ListSelector; /** * The value of the setting that will be selected when this option is clicked. */ @@ -27,7 +27,7 @@ export interface SettingsPanelSelectOptionConfig extends SettingsPanelItemConfig */ export class SettingsPanelSelectOption extends SettingsPanelItem { private settingsValue: string | undefined; - protected setting: ListSelector; + protected settingComponent: ListSelector; constructor(config: SettingsPanelSelectOptionConfig) { super(config); @@ -44,7 +44,7 @@ export class SettingsPanelSelectOption extends SettingsPanelItem { - let selectedItem = this.setting.getSelectedItem(); + let selectedItem = this.settingComponent.getSelectedItem(); if (this.settingsValue === selectedItem) { this.getDomElement().addClass(this.prefixCss('selected')); @@ -52,10 +52,10 @@ export class SettingsPanelSelectOption extends SettingsPanelItem { - this.setting.selectItem(this.settingsValue); + this.settingComponent.selectItem(this.settingsValue); }; this.getDomElement().on('click', () => handleItemClick()); diff --git a/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts b/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts index 55c3147e0..235229ed1 100644 --- a/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts +++ b/src/ts/components/subtitlesettings/subtitlesettingspanelpage.ts @@ -113,7 +113,7 @@ export class SubtitleSettingsPanelPage extends SettingsPanelPage { label: new SettingsPanelPageBackButton({ container: this.settingsPanel, }), - setting: new SubtitleSettingsResetButton({}), + settingComponent: new SubtitleSettingsResetButton({}), cssClasses: ['title-item'], }); @@ -148,13 +148,13 @@ export class SubtitleSettingsPanelPage extends SettingsPanelPage { if (useDynamicSettingsPanelItem) { return new DynamicSettingsPanelItem({ label: label, - setting: setting, + settingComponent: setting, container: this.settingsPanel, }); } else { return new SettingsPanelItem({ label: label, - setting: setting, + settingComponent: setting, }); } } diff --git a/src/ts/demofactory.ts b/src/ts/demofactory.ts index 596af48b3..125e27c2c 100644 --- a/src/ts/demofactory.ts +++ b/src/ts/demofactory.ts @@ -70,9 +70,9 @@ export namespace DemoFactory { components: [ new SettingsPanelPage({ components: [ - new SettingsPanelItem({ label: 'Video Quality', setting: new VideoQualitySelectBox() }), - new SettingsPanelItem({ label: 'Speed', setting: new PlaybackSpeedSelectBox() }), - new SettingsPanelItem({ label: 'Audio Quality', setting: new AudioQualitySelectBox() }), + new SettingsPanelItem({ label: 'Video Quality', settingComponent: new VideoQualitySelectBox() }), + new SettingsPanelItem({ label: 'Speed', settingComponent: new PlaybackSpeedSelectBox() }), + new SettingsPanelItem({ label: 'Audio Quality', settingComponent: new AudioQualitySelectBox() }), ], }), ], @@ -84,7 +84,7 @@ export namespace DemoFactory { components: [ new SettingsPanelPage({ components: [ - new SettingsPanelItem({ label: null, setting: subtitleListBox }), + new SettingsPanelItem({ label: null, settingComponent: subtitleListBox }), ], }), ], @@ -96,7 +96,7 @@ export namespace DemoFactory { components: [ new SettingsPanelPage({ components: [ - new SettingsPanelItem({ label: null, setting: audioTrackListBox }), + new SettingsPanelItem({ label: null, settingComponent: audioTrackListBox }), ], }), ], diff --git a/src/ts/uifactory.ts b/src/ts/uifactory.ts index 627e47308..4abc5d01d 100644 --- a/src/ts/uifactory.ts +++ b/src/ts/uifactory.ts @@ -81,10 +81,10 @@ export namespace UIFactory { let mainSettingsPanelPage: SettingsPanelPage; const components: Container[] = [ - new SettingsPanelItem({ label: i18n.getLocalizer('settings.video.quality'), setting: new VideoQualitySelectBox() }), - new SettingsPanelItem({ label: i18n.getLocalizer('speed'), setting: new PlaybackSpeedSelectBox() }), - new SettingsPanelItem({ label: i18n.getLocalizer('settings.audio.track'), setting: new AudioTrackSelectBox() }), - new SettingsPanelItem({ label: i18n.getLocalizer('settings.audio.quality'), setting: new AudioQualitySelectBox() }), + new SettingsPanelItem({ label: i18n.getLocalizer('settings.video.quality'), settingComponent: new VideoQualitySelectBox() }), + new SettingsPanelItem({ label: i18n.getLocalizer('speed'), settingComponent: new PlaybackSpeedSelectBox() }), + new SettingsPanelItem({ label: i18n.getLocalizer('settings.audio.track'), settingComponent: new AudioTrackSelectBox() }), + new SettingsPanelItem({ label: i18n.getLocalizer('settings.audio.quality'), settingComponent: new AudioQualitySelectBox() }), ]; if (config.ecoMode) { @@ -127,7 +127,7 @@ export namespace UIFactory { text: i18n.getLocalizer('settings.subtitles'), opener: subtitleSettingsOpenButton, }), - setting: subtitleSelectBox, + settingComponent: subtitleSelectBox, role: 'menubar', }), ); @@ -231,10 +231,10 @@ export namespace UIFactory { let mainSettingsPanelPage = new SettingsPanelPage({ components: [ - new SettingsPanelItem({ label: i18n.getLocalizer('settings.video.quality'), setting: new VideoQualitySelectBox() }), - new SettingsPanelItem({ label: i18n.getLocalizer('speed'), setting: new PlaybackSpeedSelectBox() }), - new SettingsPanelItem({ label: i18n.getLocalizer('settings.audio.track'), setting: new AudioTrackSelectBox() }), - new SettingsPanelItem({ label: i18n.getLocalizer('settings.audio.quality'), setting: new AudioQualitySelectBox() }), + new SettingsPanelItem({ label: i18n.getLocalizer('settings.video.quality'), settingComponent: new VideoQualitySelectBox() }), + new SettingsPanelItem({ label: i18n.getLocalizer('speed'), settingComponent: new PlaybackSpeedSelectBox() }), + new SettingsPanelItem({ label: i18n.getLocalizer('settings.audio.track'), settingComponent: new AudioTrackSelectBox() }), + new SettingsPanelItem({ label: i18n.getLocalizer('settings.audio.quality'), settingComponent: new AudioQualitySelectBox() }), ], }); @@ -265,7 +265,7 @@ export namespace UIFactory { text: i18n.getLocalizer('settings.subtitles'), opener: subtitleSettingsOpenButton, }), - setting: subtitleSelectBox, + settingComponent: subtitleSelectBox, role: 'menubar', }), ); @@ -461,22 +461,22 @@ export namespace UIFactory { components: [ new DynamicSettingsPanelItem({ label: i18n.getLocalizer('settings.video.quality'), - setting: new VideoQualitySelectBox(), + settingComponent: new VideoQualitySelectBox(), container: settingsPanel, }), new DynamicSettingsPanelItem({ label: i18n.getLocalizer('speed'), - setting: new PlaybackSpeedSelectBox(), + settingComponent: new PlaybackSpeedSelectBox(), container: settingsPanel, }), new DynamicSettingsPanelItem({ label: i18n.getLocalizer('settings.audio.track'), - setting: new AudioTrackSelectBox() , + settingComponent: new AudioTrackSelectBox() , container: settingsPanel, }), new DynamicSettingsPanelItem({ label: i18n.getLocalizer('settings.audio.quality'), - setting: new AudioQualitySelectBox(), + settingComponent: new AudioQualitySelectBox(), container: settingsPanel, }), ], @@ -503,7 +503,7 @@ export namespace UIFactory { text: i18n.getLocalizer('settings.subtitles'), opener: subtitleSettingsOpenButton, }), - setting: subtitleSelectBox, + settingComponent: subtitleSelectBox, role: 'menubar', container: settingsPanel, }); @@ -583,22 +583,22 @@ export namespace UIFactory { const components: Container[] = [ new DynamicSettingsPanelItem({ label: i18n.getLocalizer('settings.video.quality'), - setting: new VideoQualitySelectBox(), + settingComponent: new VideoQualitySelectBox(), container: settingsPanel, }), new DynamicSettingsPanelItem({ label: i18n.getLocalizer('speed'), - setting: new PlaybackSpeedSelectBox(), + settingComponent: new PlaybackSpeedSelectBox(), container: settingsPanel, }), new DynamicSettingsPanelItem({ label: i18n.getLocalizer('settings.audio.track'), - setting: new AudioTrackSelectBox(), + settingComponent: new AudioTrackSelectBox(), container: settingsPanel, }), new DynamicSettingsPanelItem({ label: i18n.getLocalizer('settings.audio.quality'), - setting: new AudioQualitySelectBox(), + settingComponent: new AudioQualitySelectBox(), container: settingsPanel, }), ]; @@ -639,7 +639,7 @@ export namespace UIFactory { text: i18n.getLocalizer('settings.subtitles'), opener: subtitleSettingsOpenButton, }), - setting: subtitleSelectBox, + settingComponent: subtitleSelectBox, role: 'menubar', container: settingsPanel, }); @@ -809,7 +809,7 @@ export namespace UIFactory { const subtitleListPanel = new SettingsPanel({ components: [ new SettingsPanelPage({ - components: [new SettingsPanelItem({ setting: subtitleListBox })], + components: [new SettingsPanelItem({ settingComponent: subtitleListBox })], }), ], hidden: true, @@ -819,7 +819,7 @@ export namespace UIFactory { const audioTrackListPanel = new SettingsPanel({ components: [ new SettingsPanelPage({ - components: [new SettingsPanelItem({ setting: audioTrackListBox })], + components: [new SettingsPanelItem({ settingComponent: audioTrackListBox })], }), ], hidden: true, From 901be17de0ac6bcd1d761a8fcfb362f44474979a Mon Sep 17 00:00:00 2001 From: David Steinacher Date: Fri, 20 Dec 2024 08:51:17 +0100 Subject: [PATCH 23/23] fix test build after renaming --- spec/components/settingspanel.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/components/settingspanel.spec.ts b/spec/components/settingspanel.spec.ts index 46778f883..ec2e092b8 100644 --- a/spec/components/settingspanel.spec.ts +++ b/spec/components/settingspanel.spec.ts @@ -224,8 +224,8 @@ describe('SettingsPanel', () => { const selectBox = new SelectBox(); const closeDropdownSpy = jest.spyOn(selectBox, 'closeDropdown'); - settingsPanel.getActivePage().addComponent(new SettingsPanelItem({ label: new Label(), setting: selectBox })); - settingsPanel.getActivePage().addComponent(new SettingsPanelItem({ label: new Label(), setting: new VolumeSlider() })); + settingsPanel.getActivePage().addComponent(new SettingsPanelItem({ label: new Label(), settingComponent: selectBox })); + settingsPanel.getActivePage().addComponent(new SettingsPanelItem({ label: new Label(), settingComponent: new VolumeSlider() })); settingsPanel['hideHoveredSelectBoxes']();