diff --git a/demo/app.js b/demo/app.js index f1894c24..2c85b872 100644 --- a/demo/app.js +++ b/demo/app.js @@ -72,7 +72,7 @@ const App = ({ manifestURL }) => { manifestUrl={manifestUrl} >
- +
diff --git a/src/components/MediaPlayer/MediaPlayer.js b/src/components/MediaPlayer/MediaPlayer.js index 271a2b5b..698f8927 100644 --- a/src/components/MediaPlayer/MediaPlayer.js +++ b/src/components/MediaPlayer/MediaPlayer.js @@ -16,7 +16,11 @@ import { IS_ANDROID, IS_MOBILE, IS_SAFARI, IS_TOUCH_ONLY } from '@Services/brows const PLAYER_ID = "iiif-media-player"; -const MediaPlayer = ({ enableFileDownload = false, enablePIP = false }) => { +const MediaPlayer = ({ + enableFileDownload = false, + enablePIP = false, + enablePlaybackRate = false, +}) => { const manifestState = useManifestState(); const playerState = usePlayerState(); const playerDispatch = usePlayerDispatch(); @@ -311,6 +315,7 @@ const MediaPlayer = ({ enableFileDownload = false, enablePIP = false }) => { autoplay: false, bigPlayButton: isVideo, id: PLAYER_ID, + playbackRates: enablePlaybackRate ? [0.5, 0.75, 1, 1.5, 2] : [], // Setting inactivity timeout to zero in mobile and tablet devices translates to // user is always active. And the control bar is not hidden when user is active. // With this user can always use the controls when the media is playing. @@ -335,6 +340,7 @@ const MediaPlayer = ({ enableFileDownload = false, enablePIP = false }) => { (playerConfig.tracks.length > 0 && isVideo) ? 'subsCapsButton' : '', IS_MOBILE ? 'muteToggle' : 'volumePanel', 'qualitySelector', + enablePlaybackRate ? 'playbackRateMenuButton' : '', enablePIP ? 'pictureInPictureToggle' : '', enableFileDownload ? 'videoJSFileDownload' : '', 'fullscreenToggle' @@ -444,7 +450,8 @@ const MediaPlayer = ({ enableFileDownload = false, enablePIP = false }) => { MediaPlayer.propTypes = { enableFileDownload: PropTypes.bool, - enablePIP: PropTypes.bool + enablePIP: PropTypes.bool, + enablePlaybackRate: PropTypes.bool, }; export default MediaPlayer; diff --git a/src/components/MediaPlayer/MediaPlayer.md b/src/components/MediaPlayer/MediaPlayer.md index 0a25d78a..9243e472 100644 --- a/src/components/MediaPlayer/MediaPlayer.md +++ b/src/components/MediaPlayer/MediaPlayer.md @@ -2,8 +2,9 @@ MediaPlayer component provides a player that facilitates both audio and video me `MediaPlayer` component accepts the following props; -- `enableFileDownload` : accepts a Boolean value, which has a default value of `false` and is not required. Once this is set to `true` it adds an icon to the player's toolbar to display `rendering` files in the Canvas and enables downloading them. This is a custom feature added to the VideoJS instance in Ramp. -- `enablePIP` : accepts a Boolean value, which has a default value of `false` and is not required. When this is set to `true`, it adds an icon to the player's toolbar to enable Picture-In-Picture feature for the current player. This icon is a VideoJS feature. +- `enableFileDownload` : accepts a Boolean value, which has a default value of `false` and is _not required_. Once this is set to `true` it adds an icon to the player's control bar to display `rendering` files in the Canvas and enables downloading them. This is a custom VideoJS componend added to the VideoJS instance in Ramp. +- `enablePIP` : accepts a Boolean value, which has a default value of `false` and is _not required_. When this is set to `true`, it adds an icon to the player's control bar to enable Picture-In-Picture feature for the current player. This icon is a VideoJS component. +- `enablePlaybackRate`: accepts a Boolean value, which has a default value of `false` and is _not required_. When this is set to `true`, it adds an icon to the player's control bar which provides a menu to select a different playback speed for the media. The available speed options are 0.5x, 0.75x, 1x, 1.5x, and 2x. This icon is a VideoJS component. To import and use this component from the library; ```js static diff --git a/src/components/MediaPlayer/MediaPlayer.test.js b/src/components/MediaPlayer/MediaPlayer.test.js index 89518fac..f4a9e973 100644 --- a/src/components/MediaPlayer/MediaPlayer.test.js +++ b/src/components/MediaPlayer/MediaPlayer.test.js @@ -91,32 +91,90 @@ describe('MediaPlayer component', () => { }); describe('with props', () => { - test('enableFileDownload = false', () => { - const PlayerWithManifest = withManifestAndPlayerProvider(MediaPlayer, { - initialManifestState: { ...manifestState, manifest: videoManifest, canvasIndex: 0 }, - initialPlayerState: {}, - enableFileDownload: false, + describe('enableFileDownload', () => { + test('with default value: `false`', () => { + const PlayerWithManifest = withManifestAndPlayerProvider(MediaPlayer, { + initialManifestState: { ...manifestState, manifest: videoManifest, canvasIndex: 0 }, + initialPlayerState: {}, + enableFileDownload: false, + }); + render( + + + + ); + expect(screen.queryByTestId('videojs-file-download')).not.toBeInTheDocument(); + }); + + test('set to `true`', async () => { + const PlayerWithManifest = withManifestAndPlayerProvider(MediaPlayer, { + initialManifestState: { ...manifestState, manifest: videoManifest, canvasIndex: 0 }, + initialPlayerState: {}, + enableFileDownload: true, + }); + await act(async () => render( + + + + )); + expect(screen.queryByTestId('videojs-file-download')).toBeInTheDocument(); }); - render( - - - - ); - expect(screen.queryByTestId('videojs-file-download')).not.toBeInTheDocument(); }); - test('enableFileDownload = true', async () => { - const PlayerWithManifest = withManifestAndPlayerProvider(MediaPlayer, { - initialManifestState: { ...manifestState, manifest: videoManifest, canvasIndex: 0 }, - initialPlayerState: {}, - enableFileDownload: true, + describe('enablePIP', () => { + test('with default value: `false`', async () => { + const PlayerWithManifest = withManifestAndPlayerProvider(MediaPlayer, { + initialManifestState: { ...manifestState, manifest: videoManifest, canvasIndex: 0 }, + initialPlayerState: {}, + }); + await act(async () => render( + + + + )); + expect(screen.queryByTitle('Picture-in-Picture')).not.toBeInTheDocument(); + }); + test('set to `true`', async () => { + const PlayerWithManifest = withManifestAndPlayerProvider(MediaPlayer, { + initialManifestState: { ...manifestState, manifest: videoManifest, canvasIndex: 0 }, + initialPlayerState: {}, + enablePIP: true, + }); + await act(async () => render( + + + + )); + expect(screen.queryByTitle('Picture-in-Picture')).toBeInTheDocument(); + }); + }); + + describe('enablePlaybackRate', () => { + test('with default value: `false`', async () => { + const PlayerWithManifest = withManifestAndPlayerProvider(MediaPlayer, { + initialManifestState: { ...manifestState, manifest: videoManifest, canvasIndex: 0 }, + initialPlayerState: {}, + }); + await act(async () => render( + + + + )); + expect(screen.queryByTitle('Playback Rate')).not.toBeInTheDocument(); + }); + test('set to `true`', async () => { + const PlayerWithManifest = withManifestAndPlayerProvider(MediaPlayer, { + initialManifestState: { ...manifestState, manifest: videoManifest, canvasIndex: 0 }, + initialPlayerState: {}, + enablePlaybackRate: true, + }); + await act(async () => render( + + + + )); + expect(screen.queryByTitle('Playback Rate')).toBeInTheDocument(); }); - await act(async () => render( - - - - )); - expect(screen.queryByTestId('videojs-file-download')).toBeInTheDocument(); }); }); diff --git a/src/components/MediaPlayer/VideoJS/components/styles/VideoJSFileDownload.scss b/src/components/MediaPlayer/VideoJS/components/styles/VideoJSFileDownload.scss index 49632518..39e96ed4 100644 --- a/src/components/MediaPlayer/VideoJS/components/styles/VideoJSFileDownload.scss +++ b/src/components/MediaPlayer/VideoJS/components/styles/VideoJSFileDownload.scss @@ -1,18 +1,5 @@ @import '../../../../../styles/vars'; -.vjs-download-btn { - color: white; - border: none; - cursor: pointer; - width: 2rem; - height: 2rem; -} - -.vjs-file-download { - position: relative; - display: inline-block; -} - .vjs-file-download-icon { background-image: url("data:image/svg+xml;utf8, "); background-repeat: no-repeat; diff --git a/src/styles/main.scss b/src/styles/main.scss index dc897308..8ae129cf 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -114,6 +114,10 @@ video/poster area the controls are displayed correctly. */ display: block !important; } +.vjs-playback-rate-value { + scale: 0.75 !important; +} + /* big-play button */ .video-js .vjs-big-play-button { border-radius: 50%;