2023-01-19 22:29:56 +01:00
|
|
|
import { MWMediaMeta } from "@/backend/metadata/types";
|
2023-01-10 19:53:55 +01:00
|
|
|
import { useCallback, useRef, useState } from "react";
|
|
|
|
import { CSSTransition } from "react-transition-group";
|
2023-01-22 20:51:58 +01:00
|
|
|
import { AirplayControl } from "./controls/AirplayControl";
|
2023-01-08 22:29:38 +01:00
|
|
|
import { BackdropControl } from "./controls/BackdropControl";
|
2023-01-22 23:03:55 +01:00
|
|
|
import { ChromeCastControl } from "./controls/ChromeCastControl";
|
2023-01-08 22:29:38 +01:00
|
|
|
import { FullscreenControl } from "./controls/FullscreenControl";
|
|
|
|
import { LoadingControl } from "./controls/LoadingControl";
|
2023-01-10 19:53:55 +01:00
|
|
|
import { MiddlePauseControl } from "./controls/MiddlePauseControl";
|
2023-01-08 22:29:38 +01:00
|
|
|
import { PauseControl } from "./controls/PauseControl";
|
|
|
|
import { ProgressControl } from "./controls/ProgressControl";
|
2023-01-23 01:55:57 +01:00
|
|
|
import { SeriesSelectionControl } from "./controls/SeriesSelectionControl";
|
2023-01-21 23:45:26 +01:00
|
|
|
import { ShowTitleControl } from "./controls/ShowTitleControl";
|
2023-01-23 22:38:05 +01:00
|
|
|
import { SkipTime } from "./controls/SkipTime";
|
2023-01-08 22:29:38 +01:00
|
|
|
import { TimeControl } from "./controls/TimeControl";
|
|
|
|
import { VolumeControl } from "./controls/VolumeControl";
|
2023-01-15 16:51:55 +01:00
|
|
|
import { VideoPlayerError } from "./parts/VideoPlayerError";
|
2023-01-10 00:27:04 +01:00
|
|
|
import { VideoPlayerHeader } from "./parts/VideoPlayerHeader";
|
2023-01-10 19:53:55 +01:00
|
|
|
import { useVideoPlayerState } from "./VideoContext";
|
2023-01-08 22:29:38 +01:00
|
|
|
import { VideoPlayer, VideoPlayerProps } from "./VideoPlayer";
|
|
|
|
|
2023-01-10 21:18:10 +01:00
|
|
|
interface DecoratedVideoPlayerProps {
|
2023-01-19 22:29:56 +01:00
|
|
|
media?: MWMediaMeta;
|
2023-01-10 21:18:10 +01:00
|
|
|
onGoBack?: () => void;
|
|
|
|
}
|
|
|
|
|
2023-01-10 19:53:55 +01:00
|
|
|
function LeftSideControls() {
|
|
|
|
const { videoState } = useVideoPlayerState();
|
|
|
|
|
|
|
|
const handleMouseEnter = useCallback(() => {
|
|
|
|
videoState.setLeftControlsHover(true);
|
|
|
|
}, [videoState]);
|
|
|
|
const handleMouseLeave = useCallback(() => {
|
|
|
|
videoState.setLeftControlsHover(false);
|
|
|
|
}, [videoState]);
|
|
|
|
|
|
|
|
return (
|
2023-01-21 23:45:26 +01:00
|
|
|
<>
|
|
|
|
<div
|
|
|
|
className="flex items-center px-2"
|
|
|
|
onMouseLeave={handleMouseLeave}
|
|
|
|
onMouseEnter={handleMouseEnter}
|
|
|
|
>
|
|
|
|
<PauseControl />
|
|
|
|
<TimeControl />
|
2023-01-23 22:38:05 +01:00
|
|
|
<VolumeControl className="mr-2" />
|
|
|
|
<SkipTime />
|
2023-01-21 23:45:26 +01:00
|
|
|
</div>
|
|
|
|
<ShowTitleControl />
|
|
|
|
</>
|
2023-01-10 19:53:55 +01:00
|
|
|
);
|
|
|
|
}
|
2023-01-10 00:27:04 +01:00
|
|
|
|
2023-01-10 21:18:10 +01:00
|
|
|
export function DecoratedVideoPlayer(
|
|
|
|
props: VideoPlayerProps & DecoratedVideoPlayerProps
|
|
|
|
) {
|
2023-01-10 19:53:55 +01:00
|
|
|
const top = useRef<HTMLDivElement>(null);
|
|
|
|
const bottom = useRef<HTMLDivElement>(null);
|
|
|
|
const [show, setShow] = useState(false);
|
|
|
|
|
|
|
|
const onBackdropChange = useCallback(
|
|
|
|
(showing: boolean) => {
|
|
|
|
setShow(showing);
|
|
|
|
},
|
|
|
|
[setShow]
|
|
|
|
);
|
|
|
|
|
2023-01-08 22:29:38 +01:00
|
|
|
return (
|
|
|
|
<VideoPlayer autoPlay={props.autoPlay}>
|
2023-01-19 22:29:56 +01:00
|
|
|
<VideoPlayerError media={props.media} onGoBack={props.onGoBack}>
|
2023-01-15 16:51:55 +01:00
|
|
|
<BackdropControl onBackdropChange={onBackdropChange}>
|
|
|
|
<div className="absolute inset-0 flex items-center justify-center">
|
|
|
|
<LoadingControl />
|
|
|
|
</div>
|
|
|
|
<div className="absolute inset-0 flex items-center justify-center">
|
|
|
|
<MiddlePauseControl />
|
|
|
|
</div>
|
|
|
|
<CSSTransition
|
|
|
|
nodeRef={bottom}
|
|
|
|
in={show}
|
|
|
|
timeout={200}
|
|
|
|
classNames={{
|
|
|
|
exit: "transition-[transform,opacity] translate-y-0 duration-200 opacity-100",
|
|
|
|
exitActive: "!translate-y-4 !opacity-0",
|
|
|
|
exitDone: "hidden",
|
|
|
|
enter:
|
|
|
|
"transition-[transform,opacity] translate-y-4 duration-200 opacity-0",
|
|
|
|
enterActive: "!translate-y-0 !opacity-100",
|
|
|
|
}}
|
2023-01-10 19:53:55 +01:00
|
|
|
>
|
2023-01-15 16:51:55 +01:00
|
|
|
<div
|
|
|
|
ref={bottom}
|
|
|
|
className="pointer-events-auto absolute inset-x-0 bottom-0 flex flex-col px-4 pb-2"
|
|
|
|
>
|
|
|
|
<ProgressControl />
|
|
|
|
<div className="flex items-center">
|
|
|
|
<LeftSideControls />
|
|
|
|
<div className="flex-1" />
|
2023-01-23 01:55:57 +01:00
|
|
|
<SeriesSelectionControl />
|
2023-01-22 20:51:58 +01:00
|
|
|
<AirplayControl />
|
2023-01-22 23:03:55 +01:00
|
|
|
<ChromeCastControl />
|
2023-01-15 16:51:55 +01:00
|
|
|
<FullscreenControl />
|
|
|
|
</div>
|
2023-01-10 19:53:55 +01:00
|
|
|
</div>
|
2023-01-15 16:51:55 +01:00
|
|
|
</CSSTransition>
|
|
|
|
<CSSTransition
|
|
|
|
nodeRef={top}
|
|
|
|
in={show}
|
|
|
|
timeout={200}
|
|
|
|
classNames={{
|
|
|
|
exit: "transition-[transform,opacity] translate-y-0 duration-200 opacity-100",
|
|
|
|
exitActive: "!-translate-y-4 !opacity-0",
|
|
|
|
exitDone: "hidden",
|
|
|
|
enter:
|
|
|
|
"transition-[transform,opacity] -translate-y-4 duration-200 opacity-0",
|
|
|
|
enterActive: "!translate-y-0 !opacity-100",
|
|
|
|
}}
|
2023-01-10 19:53:55 +01:00
|
|
|
>
|
2023-01-15 16:51:55 +01:00
|
|
|
<div
|
|
|
|
ref={top}
|
|
|
|
className="pointer-events-auto absolute inset-x-0 top-0 flex flex-col py-6 px-8 pb-2"
|
|
|
|
>
|
2023-01-19 22:29:56 +01:00
|
|
|
<VideoPlayerHeader media={props.media} onClick={props.onGoBack} />
|
2023-01-15 16:51:55 +01:00
|
|
|
</div>
|
|
|
|
</CSSTransition>
|
|
|
|
</BackdropControl>
|
|
|
|
{props.children}
|
|
|
|
</VideoPlayerError>
|
2023-01-08 22:29:38 +01:00
|
|
|
</VideoPlayer>
|
|
|
|
);
|
|
|
|
}
|