From b56f637c98b5bdef975e843b94fecc2e88f47cb9 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Thu, 13 Feb 2025 15:09:15 +0100 Subject: [PATCH] feat(youtube-player): add API to put the player in fullscreen mode Adds a method on the `YouTubePlayer` to put the element in fullscreen mode. This is a bit more involved than just calling `requestFullScreen`, because we also need to change the styles to ensure that the placeholder and the `iframe` cover the whole screen. Fixes #30485. --- src/dev-app/youtube-player/BUILD.bazel | 1 + .../youtube-player/youtube-player-demo.html | 21 ++++++++++++------- .../youtube-player/youtube-player-demo.ts | 3 ++- src/youtube-player/BUILD.bazel | 6 ++++++ .../youtube-player-placeholder.scss | 5 +++++ src/youtube-player/youtube-player.scss | 6 ++++++ src/youtube-player/youtube-player.ts | 15 +++++++++++++ .../youtube-player/youtube-player.md | 1 + 8 files changed, 49 insertions(+), 9 deletions(-) create mode 100644 src/youtube-player/youtube-player.scss diff --git a/src/dev-app/youtube-player/BUILD.bazel b/src/dev-app/youtube-player/BUILD.bazel index bb06abeb2eca..956ed6cd4248 100644 --- a/src/dev-app/youtube-player/BUILD.bazel +++ b/src/dev-app/youtube-player/BUILD.bazel @@ -10,6 +10,7 @@ ng_module( ":youtube_player_demo_scss", ], deps = [ + "//src/material/button", "//src/material/checkbox", "//src/material/radio", "//src/youtube-player", diff --git a/src/dev-app/youtube-player/youtube-player-demo.html b/src/dev-app/youtube-player/youtube-player-demo.html index 4225e9f7bd9e..209eb6ec08e6 100644 --- a/src/dev-app/youtube-player/youtube-player-demo.html +++ b/src/dev-app/youtube-player/youtube-player-demo.html @@ -15,14 +15,19 @@

Basic Example

Disable placeholder Start at 30s - +
+ +
+

Placeholder quality comparison (high to low)

diff --git a/src/dev-app/youtube-player/youtube-player-demo.ts b/src/dev-app/youtube-player/youtube-player-demo.ts index a70864d23b37..605fd0712def 100644 --- a/src/dev-app/youtube-player/youtube-player-demo.ts +++ b/src/dev-app/youtube-player/youtube-player-demo.ts @@ -17,6 +17,7 @@ import { inject, } from '@angular/core'; import {FormsModule} from '@angular/forms'; +import {MatButton} from '@angular/material/button'; import {MatCheckboxModule} from '@angular/material/checkbox'; import {MatRadioModule} from '@angular/material/radio'; import {PlaceholderImageQuality, YouTubePlayer} from '@angular/youtube-player'; @@ -79,7 +80,7 @@ const VIDEOS: Video[] = [ selector: 'youtube-player-demo', templateUrl: 'youtube-player-demo.html', styleUrl: 'youtube-player-demo.css', - imports: [FormsModule, MatRadioModule, MatCheckboxModule, YouTubePlayer], + imports: [FormsModule, MatRadioModule, MatCheckboxModule, MatButton, YouTubePlayer], changeDetection: ChangeDetectionStrategy.OnPush, }) export class YouTubePlayerDemo implements AfterViewInit, OnDestroy { diff --git a/src/youtube-player/BUILD.bazel b/src/youtube-player/BUILD.bazel index 27d267619979..d5d65d4e7fce 100644 --- a/src/youtube-player/BUILD.bazel +++ b/src/youtube-player/BUILD.bazel @@ -19,6 +19,7 @@ ng_module( ], ), assets = [ + ":youtube_player_scss", ":youtube_player_placeholder_scss", ], deps = [ @@ -30,6 +31,11 @@ ng_module( ], ) +sass_binary( + name = "youtube_player_scss", + src = "youtube-player.scss", +) + sass_binary( name = "youtube_player_placeholder_scss", src = "youtube-player-placeholder.scss", diff --git a/src/youtube-player/youtube-player-placeholder.scss b/src/youtube-player/youtube-player-placeholder.scss index 69c2530afeba..a05b747a007d 100644 --- a/src/youtube-player/youtube-player-placeholder.scss +++ b/src/youtube-player/youtube-player-placeholder.scss @@ -14,6 +14,11 @@ // Note that they use a base64 image, likely for performance reasons. We can't use the // image, because it can break users with a CSP that doesn't allow `data:` URLs. box-shadow: inset 0 120px 90px -90px rgba(0, 0, 0, 0.8); + + :fullscreen & { + min-width: 100vw; + min-height: 100vh; + } } .youtube-player-placeholder-button { diff --git a/src/youtube-player/youtube-player.scss b/src/youtube-player/youtube-player.scss new file mode 100644 index 000000000000..65152ad1811a --- /dev/null +++ b/src/youtube-player/youtube-player.scss @@ -0,0 +1,6 @@ +youtube-player:fullscreen { + &, iframe { + min-width: 100vw; + min-height: 100vh; + } +} diff --git a/src/youtube-player/youtube-player.ts b/src/youtube-player/youtube-player.ts index 665ae54b90f3..398b8d8711bc 100644 --- a/src/youtube-player/youtube-player.ts +++ b/src/youtube-player/youtube-player.ts @@ -113,6 +113,7 @@ enum PlayerState { changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [YouTubePlayerPlaceholder], + styleUrl: 'youtube-player.css', template: ` @if (_shouldShowPlaceholder()) { >(ElementRef); private _player: YT.Player | undefined; private _pendingPlayer: YT.Player | undefined; private _existingApiReadyCallback: (() => void) | undefined; @@ -474,6 +476,19 @@ export class YouTubePlayer implements AfterViewInit, OnChanges, OnDestroy { return this._player ? this._player.getVideoEmbedCode() : ''; } + /** + * Attempts to put the player into fullscreen mode, depending on browser support. + * @param options Options controlling how the element behaves in fullscreen mode. + */ + async requestFullscreen(options?: FullscreenOptions): Promise { + // Note that we do this on the host, rather than the iframe, because it allows us to handle the + // placeholder in fullscreen mode. Null check the method since it's not supported everywhere. + const element = this._elementRef.nativeElement; + return element.requestFullscreen + ? element.requestFullscreen(options) + : Promise.reject(new Error('Fullscreen API not supported by browser.')); + } + /** * Loads the YouTube API and sets up the player. * @param playVideo Whether to automatically play the video once the player is loaded. diff --git a/tools/public_api_guard/youtube-player/youtube-player.md b/tools/public_api_guard/youtube-player/youtube-player.md index 236abe369746..0ef8c4112985 100644 --- a/tools/public_api_guard/youtube-player/youtube-player.md +++ b/tools/public_api_guard/youtube-player/youtube-player.md @@ -80,6 +80,7 @@ export class YouTubePlayer implements AfterViewInit, OnChanges, OnDestroy { playerVars: YT.PlayerVars | undefined; playVideo(): void; readonly ready: Observable; + requestFullscreen(options?: FullscreenOptions): Promise; seekTo(seconds: number, allowSeekAhead: boolean): void; setPlaybackRate(playbackRate: number): void; setVolume(volume: number): void;