How do you set different UI components and styles for when the player is in fullscreen

So let me explain in detail here
The company I am working for we use Bitmovin Player and have created different variants for different use case of player eg. default-for normal video watching, small- for trailer and more.

What I am looking for is the small- variant we have restricted the functionalities and kept it very minimal
Now we want to have all the functionalities and components that default variant has but just when it is in Fullscreen mode and once fullscreen mode is disabled or user comes back to small size then the controls should be reverted to small variant

Is it possible to do this ?

Hi @adityajadhav0096,

This would be possible by extending the UIFactory and changing the condition for your UIVariant. (or adding a new one)

You can see an example of this here:

The UIConditionContext already has a isFullscreen check which you could utilize for your UIVariant.

Hope this helps. Let me know if you have any additional questions.

1 Like

Hi @davidsteinacher using UIConditionContext is useful but here is the scenario
for Trailer we are using modernSmallUI similar to modernSmallScreenUI
And we have added very limited components to this. So now even if I use it in fullscreen this doesn’t change the fact that modernSmallUI was called, so it will have the same components that were present when not in Fullscreen mode.

So is there a different way that we can dynamically add and remove components in modernSmallUI when the ViewMode is Fullscreen ?

What you could do is create a separate variant (UIContainer) for fullscreen and non-fullscreen with the different components you need. This could look similar to this:

    new UIManager(player, [{
      ui: modernSmallUIFullscreen(),
      condition: (context: UIConditionContext) => {
        return context.isFullscreen;
      },
    }, {
      ui: modernSmallUI(),
      condition: (context: UIConditionContext) => {
        return !context.isFullscreen;
      },
    }], config);

In those modernSmallUI and modernSmallUIFullscreen, you can now build your UI with different components.

So I tried something here as you suggested I created a different variant and function for the fullscreen version and through index of Player where I handle the case for rendering the specific function based on player variant I did this and it solved the main issue in hand which was having different set of UI components for fullscreen and without fullscreen

case PlayerVariationEnum.SMALL:
            player.on(player.exports.PlayerEvent.Playing, () => {
              if (player.getViewMode() === ViewMode.Fullscreen) {
                setUIManager(buildDefaultFullScreenUI(player, {}, playConfig))
              } else {
                setUIManager(buildDefaultSmallScreenUI(player, {}, playConfig))
              }
            })

But here are few problems I am facing now

1- I need to find an Event which I can use to make this condition trigger, so for now I tried with PlayerEvent.Playing it works when I pause the video then it checks if ViewMode is Fullscreen or not and renders accordingly. But I need this condition to check as soon as I press the Fullscreen button so can you suggest me such an event if such event is available

2- I can see the dom elements for the small screen ui and fullscreen stacks up on each other and
duplicates components haven’t been released so maybe I can use UiManager.release() for the following issue correct me if I am wrong here

Edit- So for First scenario I just rendered the default small ui variant and then I made the event listener listen to Player.ViewModeChanged event

case PlayerVariationEnum.SMALL:
            setUIManager(buildDefaultSmallScreenUI(player, {}, playConfig))

            player.on(player.exports.PlayerEvent.ViewModeChanged, () => {
              if (player.getViewMode() === ViewMode.Fullscreen) {
                setUIManager(buildDefaultFullScreenUI(player, {}, playConfig))
              } else {
                setUIManager(buildDefaultSmallScreenUI(player, {}, playConfig))
              }
            })
            break

For 2nd case I can see multiple elements created every time I change the screen to fullscreen and back


How can I delete these elements or not create duplicate elements in the first place when its already present.

I’m not sure we are on the same page and talking about the same parts of the code.

  • Where did you put the code snippets you showed (the enum cases)?
  • What is the setUIManager method doing?
  • How do you initialize the UIManager?

So we are importing UImanager from Bitmovin like this
import { UIManager } from 'bitmovin-player-ui'

then we are using it like this
const [UIManager, setUIManager] = useState<UIManager>()

we are using setManager to pass the required variant UIcontainer for eg

case PlayerVariationEnum.PREVIEW:
            setUIManager(buildDefaultPreviewUI(player, {}, playConfig))

buildDefaultPreviewUI is declared in UIFactory

We have an Index page for Initialising all the config of the player and working
Here I have written the code for variant conditional rendering in updateUi function which is called every time in useffect After any changes to initPlayer or update playConfig, update UI and tryLoad source.

So below if you can see I am explicitly trying to remove duplicate elements that are been created when I go fullscreen and when I go to small screen

It works fine until a new trailer is played which is in the playlist, this triggers the UpdateUi creating a duplicate dom element of player

const updateUi = () => {
      if (UIManager) {
        UIManager.release()
      }

      if (player) {
        switch (variant) {
          case PlayerVariationEnum.PREVIEW:
            setUIManager(buildDefaultPreviewUI(player, {}, playConfig))

            break
          case PlayerVariationEnum.SMALL:
            setUIManager(buildDefaultSmallScreenUI(player, {}, playConfig))

            player.on(player.exports.PlayerEvent.ViewModeChanged, () => {
              if (player.getViewMode() === ViewMode.Fullscreen) {
                document
                  .querySelectorAll(`[class*="bmpui-ui-skin-small"]`)
                  .forEach((ele) => {
                    ele.parentNode?.removeChild(ele)
                  })

                setUIManager(buildDefaultFullScreenUI(player, {}, playConfig))
              } else if (player.getViewMode() === ViewMode.Inline) {
                document
                  .querySelectorAll(`[class*="bmpui-fullscreen"]`)
                  .forEach((ele) => {
                    ele.parentNode?.removeChild(ele)
                  })
                setUIManager(buildDefaultSmallScreenUI(player, {}, playConfig))
              }
            })
            break
      }
    }

Thanks; this is already very helpful. Can you also share the code from buildDefaultPreviewUI, especially the part where you initialize the UIManager? I would expect somewhere in there you have something like return new UIManager(player, ....) which is the part I’m most interested in.

Hi

This below code is written in the UIFactory page

export function buildDefaultPreviewUI(
  player: PlayerAPI,
  config: UIConfig = {},
  viuPlayerConfig: ViuPlayerConfig
): UIManager {
  return buildPreviewUI(player, config, viuPlayerConfig)
}

export function buildPreviewUI(
  player: PlayerAPI,
  config: UIConfig = {},
  viuPlayerConfig: ViuPlayerConfig,
  viuEventManager?: ViuEventManager
): UIManager {
  return new UIManager(
    player,
    [
      {
        ui: modernPreviewUI(viuPlayerConfig, viuEventManager),
        condition: (context: UIConditionContext) => {
          return (
            !context.isAd &&
            !context.adRequiresUi &&
            !viuPlayerConfig.isClassificationAd
          )
        }
      },
      {
        ui: modernAdsUI(viuPlayerConfig, viuEventManager),
        condition: (context: UIConditionContext) => {
          return (
            !context.isAd &&
            !context.adRequiresUi &&
            !!viuPlayerConfig.isClassificationAd
          )
        }
      },
      {
        ui: modernAdsUI(viuPlayerConfig, viuEventManager),
        condition: (context: UIConditionContext) => {
          return context.isAd
        }
      }
    ],
    config
  )
}

Ok, now I think I have a good full overview (thanks for all the insights).

Would it be possible that you extend the UIManager you create inside the buildPreviewUI to also integrate the fullscreen UI in the array of UIs?

The idea would be to have the following:

export function buildDefaultUI(
  player: PlayerAPI,
  config: UIConfig = {},
  viuPlayerConfig: ViuPlayerConfig
): UIManager {
  return buildUI(player, config, viuPlayerConfig)
}

export function buildUI(
  player: PlayerAPI,
  config: UIConfig = {},
  viuPlayerConfig: ViuPlayerConfig,
  viuEventManager?: ViuEventManager
): UIManager {
  return new UIManager(
    player,
    [
      {
        ui: modernPreviewUI(viuPlayerConfig, viuEventManager),
        condition: (context: UIConditionContext) => {
          return (
            !context.isFullscreen && // <-- Check for not fullscreen and use the PreviewUI
            !context.isAd &&
            !context.adRequiresUi &&
            !viuPlayerConfig.isClassificationAd
          )
        }
      },
      {
        ui: modernFullscreenUI(viuPlayerConfig, viuEventManager),
        condition: (context: UIConditionContext) => {
          return (
            context.isFullscreen && // <-- Check for fullscreen and use the according UI for fullscreen
            !context.isAd &&
            !context.adRequiresUi &&
            !viuPlayerConfig.isClassificationAd
          )
        }
      },
      // Potentially even more UI variants
      {
        ui: modernAdsUI(viuPlayerConfig, viuEventManager),
        condition: (context: UIConditionContext) => {
          return (
            !context.isAd &&
            !context.adRequiresUi &&
            !!viuPlayerConfig.isClassificationAd
          )
        }
      },
      {
        ui: modernAdsUI(viuPlayerConfig, viuEventManager),
        condition: (context: UIConditionContext) => {
          return context.isAd
        }
      }
    ],
    config
  )
}

Doing this should change between the Preview and Fullscreen UIs automatically when the player state changes. (Alternatively you could also do this for the Ad UIs as well)

I had done similar thing with creating new buildFullScreenUI and the other respective functions.

One thing to add we don’t manage fullscreen mode as a state config for player so the UI switch can’t trigger itself, instead we use player.on to listen to the event ViewModeChanged

so how can we add a event listener here to trigger the render, I had done this in way, works fine but after a playback is finished, updateUI triggers and runs again and the below code is rendered again for the next video creating a duplicate element so how can I fix this behaviour

case PlayerVariationEnum.SMALL:
            setUIManager(buildDefaultSmallScreenUI(player, {}, playConfig))

            player.on(player.exports.PlayerEvent.ViewModeChanged, () => {
              if (player.getViewMode() === ViewMode.Fullscreen) {
                document
                  .querySelectorAll(`[class*="bmpui-ui-skin-small"]`)
                  .forEach((ele) => {
                    ele.parentNode?.removeChild(ele)
                  })

                setUIManager(buildDefaultFullScreenUI(player, {}, playConfig))
              } else if (player.getViewMode() === ViewMode.Inline) {
                document
                  .querySelectorAll(`[class*="bmpui-fullscreen"]`)
                  .forEach((ele) => {
                    ele.parentNode?.removeChild(ele)
                  })
                setUIManager(buildDefaultSmallScreenUI(player, {}, playConfig))
              }
            })

Do you mean that the fullscreen state is not propagated through the UIConditionContext or that it is not called?

Hi David, thanks for the support actually had missed writing !context.isFullscreen causing the small UI to be rendered :sweat_smile:
Now its working as expected thank you for helping.

1 Like

This topic was automatically closed 60 minutes after the last reply. New replies are no longer allowed.