Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/main/SubtitleVideoArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ const SubtitleVideoArea: React.FC<{
subtitleUrl={subtitleUrl}
first={true}
last={true}
isFullscreenPossible={false}
fullscreenPlayerIndex={undefined}
setFullscreenPlayerIndex={() => {}}
selectIsPlaying={selectIsPlaying}
selectIsMuted={selectIsMuted}
selectCurrentlyAtInSeconds={selectCurrentlyAtInSeconds}
Expand Down
113 changes: 91 additions & 22 deletions src/main/VideoPlayers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ import { ActionCreatorWithPayload, AsyncThunk } from "@reduxjs/toolkit";

import { useTheme } from "../themes";

import { backgroundBoxStyle } from "../cssStyles";
import { backgroundBoxStyle, basicButtonStyle } from "../cssStyles";
import { BaseReactPlayerProps } from "react-player/base";
import { ErrorBox } from "@opencast/appkit";
import { LuMaximize2, LuMinimize2 } from "react-icons/lu";
import { isSafari } from "react-device-detect";

const VideoPlayers: React.FC<{
refs?: React.MutableRefObject<(VideoPlayerForwardRef | null)[]>,
Expand All @@ -56,6 +58,7 @@ const VideoPlayers: React.FC<{
const videoCount = useAppSelector(selectVideoCount);

const [videoPlayers, setVideoPlayers] = useState<JSX.Element[]>([]);
const [fullscreenPlayerIndex, setFullscreenPlayerIndex] = useState<number | undefined>(undefined);

const videoPlayerAreaStyle = css({
display: "flex",
Expand All @@ -65,7 +68,9 @@ const VideoPlayers: React.FC<{
borderRadius: "5px",
gap: "10px",

maxHeight: maxHeightInPixel + "px",
maxHeight: fullscreenPlayerIndex === undefined
? maxHeightInPixel + "px"
: maxHeightInPixel * 2 + "px",
});

// Initialize video players
Expand All @@ -81,6 +86,9 @@ const VideoPlayers: React.FC<{
subtitleUrl={""}
first={i === 0}
last={i === videoCount - 1}
isFullscreenPossible={true}
fullscreenPlayerIndex={fullscreenPlayerIndex}
setFullscreenPlayerIndex={setFullscreenPlayerIndex}
selectIsPlaying={selectIsPlaying}
selectIsMuted={selectIsMuted}
selectVolume={selectVolume}
Expand All @@ -103,7 +111,7 @@ const VideoPlayers: React.FC<{
);
}
setVideoPlayers(videoPlayers);
}, [primaryIndex, refs, videoCount, videos]);
}, [primaryIndex, refs, videoCount, videos, fullscreenPlayerIndex]);


return (
Expand All @@ -125,6 +133,9 @@ interface VideoPlayerProps {
subtitleUrl: string,
first: boolean,
last: boolean,
isFullscreenPossible: boolean,
fullscreenPlayerIndex: number | undefined,
setFullscreenPlayerIndex: (index: number | undefined) => void,
selectIsPlaying: (state: RootState) => boolean,
selectIsMuted: (state: RootState) => boolean,
selectVolume: (state: RootState) => number,
Expand Down Expand Up @@ -167,6 +178,9 @@ export const VideoPlayer = React.forwardRef<VideoPlayerForwardRef, VideoPlayerPr
subtitleUrl,
first,
last,
isFullscreenPossible,
fullscreenPlayerIndex,
setFullscreenPlayerIndex,
selectCurrentlyAtInSeconds,
selectPreviewTriggered,
selectClickTriggered,
Expand Down Expand Up @@ -391,6 +405,7 @@ export const VideoPlayer = React.forwardRef<VideoPlayerForwardRef, VideoPlayerPr
}));

const reactPlayerStyle = css({
position: "relative", // For fullscreen button
aspectRatio: "16 / 9", // Hard-coded for now because there are problems with updating this value at runtime

overflow: "hidden", // Required for borderRadius to show
Expand All @@ -404,10 +419,39 @@ export const VideoPlayer = React.forwardRef<VideoPlayerForwardRef, VideoPlayerPr
},
});

const shouldHide = fullscreenPlayerIndex !== undefined && fullscreenPlayerIndex !== dataKey;

// Because of Safari and the fact that it is not able to read and occupy based on rendered aspect ratio,
// We need to toggle the display, in order for Safari to update itself!
const initialVideoPlayerWrapperDisplay = isSafari ? "none" : "flex";
const [videoPlayerWrapperDisplay, setVideoPlayerWrapperDisplay] = useState(initialVideoPlayerWrapperDisplay);

useEffect(() => {
if (ready && isSafari) {
const timeout = setTimeout(() => {
setVideoPlayerWrapperDisplay("flex");
}, 10);
return () => clearTimeout(timeout);
}
}, [ready]);

// Watch fullscreenPlayerIndex and toggle display briefly, in order for Safari to update itself!
useEffect(() => {
if (fullscreenPlayerIndex !== undefined && isSafari) {
setVideoPlayerWrapperDisplay("none");
const timeout = setTimeout(() => {
setVideoPlayerWrapperDisplay("flex");
}, 10);
return () => clearTimeout(timeout);
}
}, [fullscreenPlayerIndex]);

const videoPlayerWrapperStyles = css({
height: "100%",
width: "100%",
display: "flex",
display: shouldHide ? "none" : videoPlayerWrapperDisplay,

flexGrow: "1",

// For single video, center!
...(first && last) && { justifyContent: "center" },
Expand All @@ -420,30 +464,55 @@ export const VideoPlayer = React.forwardRef<VideoPlayerForwardRef, VideoPlayerPr

// For multi videos, in between, fit content and center!
...(!first && !last) && { justifyContent: "center", flexBasis: "fit-content" },

// If fullscreen, treat like single video
...fullscreenPlayerIndex !== undefined && { justifyContent: "center" },
});

const render = () => {
if (!errorState) {
return (
<div css={videoPlayerWrapperStyles}>
<ReactPlayer url={url}
css={[backgroundBoxStyle(theme), reactPlayerStyle]}
ref={ref}
width="unset"
height="100%"
playing={isPlaying}
volume={volume}
muted={!isPrimary || isMuted}
onProgress={onProgressCallback}
progressInterval={100}
onReady={onReadyCallback}
onPlay={onPlay}
onEnded={onEndedCallback}
onError={onErrorCallback}
tabIndex={-1}
config={playerConfig}
disablePictureInPicture
/>
{/* wrapper for positioning fullscreen button*/}
<div css={[backgroundBoxStyle(theme), reactPlayerStyle]}>
<ReactPlayer url={url}
// css={[backgroundBoxStyle(theme), reactPlayerStyle]} // moved to wrapper
ref={ref}
width="100%"
height="100%"
playing={isPlaying}
volume={volume}
muted={!isPrimary || isMuted}
onProgress={onProgressCallback}
progressInterval={100}
onReady={onReadyCallback}
onPlay={onPlay}
onEnded={onEndedCallback}
onError={onErrorCallback}
tabIndex={-1}
config={playerConfig}
disablePictureInPicture
/>
{isFullscreenPossible &&
<button css={[basicButtonStyle(theme), css({
position: "absolute",
bottom: "10px",
right: "10px",
cursor: "pointer",
})]}
aria-pressed={fullscreenPlayerIndex !== undefined}
onClick={() => {
if (fullscreenPlayerIndex === undefined) {
setFullscreenPlayerIndex(dataKey);
} else {
setFullscreenPlayerIndex(undefined);
}
}}
>
{fullscreenPlayerIndex === undefined ? <LuMaximize2 /> : <LuMinimize2 />}
</button>
}
</div>
</div>
);
} else {
Expand Down
Loading