@@ -36,9 +36,10 @@ import { ActionCreatorWithPayload, AsyncThunk } from "@reduxjs/toolkit";
3636
3737import { useTheme } from "../themes" ;
3838
39- import { backgroundBoxStyle } from "../cssStyles" ;
39+ import { backgroundBoxStyle , basicButtonStyle } from "../cssStyles" ;
4040import { BaseReactPlayerProps } from "react-player/base" ;
4141import { ErrorBox } from "@opencast/appkit" ;
42+ import { LuFullscreen } from "react-icons/lu" ;
4243
4344const VideoPlayers : React . FC < {
4445 refs ?: React . MutableRefObject < ( VideoPlayerForwardRef | null ) [ ] > ,
@@ -56,6 +57,7 @@ const VideoPlayers: React.FC<{
5657 const videoCount = useAppSelector ( selectVideoCount ) ;
5758
5859 const [ videoPlayers , setVideoPlayers ] = useState < JSX . Element [ ] > ( [ ] ) ;
60+ const [ fullscreenPlayerIndex , setFullscreenPlayerIndex ] = useState < number | undefined > ( undefined ) ;
5961
6062 const videoPlayerAreaStyle = css ( {
6163 display : "flex" ,
@@ -65,7 +67,9 @@ const VideoPlayers: React.FC<{
6567 borderRadius : "5px" ,
6668 gap : "10px" ,
6769
68- maxHeight : maxHeightInPixel + "px" ,
70+ maxHeight : fullscreenPlayerIndex === undefined
71+ ? maxHeightInPixel + "px"
72+ : maxHeightInPixel * 2 + "px" ,
6973 } ) ;
7074
7175 // Initialize video players
@@ -81,6 +85,9 @@ const VideoPlayers: React.FC<{
8185 subtitleUrl = { "" }
8286 first = { i === 0 }
8387 last = { i === videoCount - 1 }
88+ isFullscreenPossible = { true }
89+ fullscreenPlayerIndex = { fullscreenPlayerIndex }
90+ setFullscreenPlayerIndex = { setFullscreenPlayerIndex }
8491 selectIsPlaying = { selectIsPlaying }
8592 selectIsMuted = { selectIsMuted }
8693 selectVolume = { selectVolume }
@@ -103,7 +110,7 @@ const VideoPlayers: React.FC<{
103110 ) ;
104111 }
105112 setVideoPlayers ( videoPlayers ) ;
106- } , [ primaryIndex , refs , videoCount , videos ] ) ;
113+ } , [ primaryIndex , refs , videoCount , videos , fullscreenPlayerIndex ] ) ;
107114
108115
109116 return (
@@ -125,6 +132,9 @@ interface VideoPlayerProps {
125132 subtitleUrl : string ,
126133 first : boolean ,
127134 last : boolean ,
135+ isFullscreenPossible : boolean ,
136+ fullscreenPlayerIndex : number | undefined ,
137+ setFullscreenPlayerIndex : ( index : number | undefined ) => void ,
128138 selectIsPlaying : ( state : RootState ) => boolean ,
129139 selectIsMuted : ( state : RootState ) => boolean ,
130140 selectVolume : ( state : RootState ) => number ,
@@ -167,6 +177,9 @@ export const VideoPlayer = React.forwardRef<VideoPlayerForwardRef, VideoPlayerPr
167177 subtitleUrl,
168178 first,
169179 last,
180+ isFullscreenPossible,
181+ fullscreenPlayerIndex,
182+ setFullscreenPlayerIndex,
170183 selectCurrentlyAtInSeconds,
171184 selectPreviewTriggered,
172185 selectClickTriggered,
@@ -391,6 +404,7 @@ export const VideoPlayer = React.forwardRef<VideoPlayerForwardRef, VideoPlayerPr
391404 } ) ) ;
392405
393406 const reactPlayerStyle = css ( {
407+ position : "relative" , // For fullscreen button
394408 aspectRatio : "16 / 9" , // Hard-coded for now because there are problems with updating this value at runtime
395409
396410 overflow : "hidden" , // Required for borderRadius to show
@@ -404,10 +418,12 @@ export const VideoPlayer = React.forwardRef<VideoPlayerForwardRef, VideoPlayerPr
404418 } ,
405419 } ) ;
406420
421+ const shouldHide = fullscreenPlayerIndex !== undefined && fullscreenPlayerIndex !== dataKey ;
422+
407423 const videoPlayerWrapperStyles = css ( {
408424 height : "100%" ,
409425 width : "100%" ,
410- display : "flex" ,
426+ display : shouldHide ? "none" : "flex" ,
411427
412428 // For single video, center!
413429 ...( first && last ) && { justifyContent : "center" } ,
@@ -420,30 +436,51 @@ export const VideoPlayer = React.forwardRef<VideoPlayerForwardRef, VideoPlayerPr
420436
421437 // For multi videos, in between, fit content and center!
422438 ...( ! first && ! last ) && { justifyContent : "center" , flexBasis : "fit-content" } ,
439+
440+ // If fullscreen, treat like single video
441+ ...fullscreenPlayerIndex !== undefined && { justifyContent : "center" } ,
423442 } ) ;
424443
425444 const render = ( ) => {
426445 if ( ! errorState ) {
427446 return (
428447 < div css = { videoPlayerWrapperStyles } >
429- < ReactPlayer url = { url }
430- css = { [ backgroundBoxStyle ( theme ) , reactPlayerStyle ] }
431- ref = { ref }
432- width = "unset"
433- height = "100%"
434- playing = { isPlaying }
435- volume = { volume }
436- muted = { ! isPrimary || isMuted }
437- onProgress = { onProgressCallback }
438- progressInterval = { 100 }
439- onReady = { onReadyCallback }
440- onPlay = { onPlay }
441- onEnded = { onEndedCallback }
442- onError = { onErrorCallback }
443- tabIndex = { - 1 }
444- config = { playerConfig }
445- disablePictureInPicture
446- />
448+ { /* wrapper for positioning fullscreen button*/ }
449+ < div css = { [ backgroundBoxStyle ( theme ) , reactPlayerStyle ] } >
450+ < ReactPlayer url = { url }
451+ // css={[backgroundBoxStyle(theme), reactPlayerStyle]} // moved to wrapper
452+ ref = { ref }
453+ width = "unset"
454+ height = "100%"
455+ playing = { isPlaying }
456+ volume = { volume }
457+ muted = { ! isPrimary || isMuted }
458+ onProgress = { onProgressCallback }
459+ progressInterval = { 100 }
460+ onReady = { onReadyCallback }
461+ onPlay = { onPlay }
462+ onEnded = { onEndedCallback }
463+ onError = { onErrorCallback }
464+ tabIndex = { - 1 }
465+ config = { playerConfig }
466+ disablePictureInPicture
467+ />
468+ { isFullscreenPossible &&
469+ < button css = { [ basicButtonStyle ( theme ) , css ( {
470+ position : "absolute" ,
471+ bottom : "10px" ,
472+ right : "10px" ,
473+ } ) ] }
474+ onClick = { ( ) => {
475+ if ( fullscreenPlayerIndex === undefined ) {
476+ setFullscreenPlayerIndex ( dataKey ) ;
477+ } else {
478+ setFullscreenPlayerIndex ( undefined ) ;
479+ }
480+ } }
481+ > < LuFullscreen /> </ button >
482+ }
483+ </ div >
447484 </ div >
448485 ) ;
449486 } else {
0 commit comments