|
|
|
@ -1,4 +1,5 @@
@@ -1,4 +1,5 @@
|
|
|
|
|
import { MWMediaMeta } from "@/backend/metadata/types"; |
|
|
|
|
import { DetailedMeta } from "@/backend/metadata/getmeta"; |
|
|
|
|
import { useIsMobile } from "@/hooks/useIsMobile"; |
|
|
|
|
import { useCallback, useRef, useState } from "react"; |
|
|
|
|
import { CSSTransition } from "react-transition-group"; |
|
|
|
|
import { AirplayControl } from "./controls/AirplayControl"; |
|
|
|
@ -7,21 +8,24 @@ import { ChromeCastControl } from "./controls/ChromeCastControl";
@@ -7,21 +8,24 @@ import { ChromeCastControl } from "./controls/ChromeCastControl";
|
|
|
|
|
import { FullscreenControl } from "./controls/FullscreenControl"; |
|
|
|
|
import { LoadingControl } from "./controls/LoadingControl"; |
|
|
|
|
import { MiddlePauseControl } from "./controls/MiddlePauseControl"; |
|
|
|
|
import { MobileCenterControl } from "./controls/MobileCenterControl"; |
|
|
|
|
import { PageTitleControl } from "./controls/PageTitleControl"; |
|
|
|
|
import { PauseControl } from "./controls/PauseControl"; |
|
|
|
|
import { ProgressControl } from "./controls/ProgressControl"; |
|
|
|
|
import { QualityDisplayControl } from "./controls/QualityDisplayControl"; |
|
|
|
|
import { SeriesSelectionControl } from "./controls/SeriesSelectionControl"; |
|
|
|
|
import { ShowTitleControl } from "./controls/ShowTitleControl"; |
|
|
|
|
import { SkipTime } from "./controls/SkipTime"; |
|
|
|
|
import { SourceSelectionControl } from "./controls/SourceSelectionControl"; |
|
|
|
|
import { TimeControl } from "./controls/TimeControl"; |
|
|
|
|
import { VolumeControl } from "./controls/VolumeControl"; |
|
|
|
|
import { PageTitleControl } from "./controls/PageTitleControl"; |
|
|
|
|
import { VideoPlayerError } from "./parts/VideoPlayerError"; |
|
|
|
|
import { VideoPlayerHeader } from "./parts/VideoPlayerHeader"; |
|
|
|
|
import { useVideoPlayerState } from "./VideoContext"; |
|
|
|
|
import { VideoPlayer, VideoPlayerProps } from "./VideoPlayer"; |
|
|
|
|
|
|
|
|
|
interface DecoratedVideoPlayerProps { |
|
|
|
|
media?: MWMediaMeta; |
|
|
|
|
media?: DetailedMeta; |
|
|
|
|
onGoBack?: () => void; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -56,8 +60,10 @@ export function DecoratedVideoPlayer(
@@ -56,8 +60,10 @@ export function DecoratedVideoPlayer(
|
|
|
|
|
props: VideoPlayerProps & DecoratedVideoPlayerProps |
|
|
|
|
) { |
|
|
|
|
const top = useRef<HTMLDivElement>(null); |
|
|
|
|
const center = useRef<HTMLDivElement>(null); |
|
|
|
|
const bottom = useRef<HTMLDivElement>(null); |
|
|
|
|
const [show, setShow] = useState(false); |
|
|
|
|
const { isMobile } = useIsMobile(); |
|
|
|
|
|
|
|
|
|
const onBackdropChange = useCallback( |
|
|
|
|
(showing: boolean) => { |
|
|
|
@ -68,8 +74,8 @@ export function DecoratedVideoPlayer(
@@ -68,8 +74,8 @@ export function DecoratedVideoPlayer(
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<VideoPlayer autoPlay={props.autoPlay}> |
|
|
|
|
<PageTitleControl media={props.media} /> |
|
|
|
|
<VideoPlayerError media={props.media} onGoBack={props.onGoBack}> |
|
|
|
|
<PageTitleControl media={props.media?.meta} /> |
|
|
|
|
<VideoPlayerError media={props.media?.meta} onGoBack={props.onGoBack}> |
|
|
|
|
<BackdropControl onBackdropChange={onBackdropChange}> |
|
|
|
|
<div className="absolute inset-0 flex items-center justify-center"> |
|
|
|
|
<LoadingControl /> |
|
|
|
@ -77,52 +83,97 @@ export function DecoratedVideoPlayer(
@@ -77,52 +83,97 @@ export function DecoratedVideoPlayer(
|
|
|
|
|
<div className="absolute inset-0 flex items-center justify-center"> |
|
|
|
|
<MiddlePauseControl /> |
|
|
|
|
</div> |
|
|
|
|
{isMobile ? ( |
|
|
|
|
<CSSTransition |
|
|
|
|
nodeRef={center} |
|
|
|
|
in={show} |
|
|
|
|
timeout={200} |
|
|
|
|
classNames={{ |
|
|
|
|
exit: "transition-[transform,opacity] duration-200 opacity-100", |
|
|
|
|
exitActive: "!opacity-0", |
|
|
|
|
exitDone: "hidden", |
|
|
|
|
enter: "transition-[transform,opacity] duration-200 opacity-0", |
|
|
|
|
enterActive: "!opacity-100", |
|
|
|
|
}} |
|
|
|
|
> |
|
|
|
|
<div |
|
|
|
|
ref={center} |
|
|
|
|
className="absolute inset-0 flex items-center justify-center" |
|
|
|
|
> |
|
|
|
|
<MobileCenterControl /> |
|
|
|
|
</div> |
|
|
|
|
</CSSTransition> |
|
|
|
|
) : ( |
|
|
|
|
"" |
|
|
|
|
)} |
|
|
|
|
<CSSTransition |
|
|
|
|
nodeRef={bottom} |
|
|
|
|
nodeRef={top} |
|
|
|
|
in={show} |
|
|
|
|
timeout={200} |
|
|
|
|
classNames={{ |
|
|
|
|
exit: "transition-[transform,opacity] translate-y-0 duration-200 opacity-100", |
|
|
|
|
exitActive: "!translate-y-4 !opacity-0", |
|
|
|
|
exitActive: "!-translate-y-4 !opacity-0", |
|
|
|
|
exitDone: "hidden", |
|
|
|
|
enter: |
|
|
|
|
"transition-[transform,opacity] translate-y-4 duration-200 opacity-0", |
|
|
|
|
"transition-[transform,opacity] -translate-y-4 duration-200 opacity-0", |
|
|
|
|
enterActive: "!translate-y-0 !opacity-100", |
|
|
|
|
}} |
|
|
|
|
> |
|
|
|
|
<div |
|
|
|
|
ref={bottom} |
|
|
|
|
className="pointer-events-auto absolute inset-x-0 bottom-0 flex flex-col px-4 pb-2 [margin-bottom:env(safe-area-inset-bottom)]" |
|
|
|
|
ref={top} |
|
|
|
|
className="pointer-events-auto absolute inset-x-0 top-0 flex flex-col py-6 px-8 pb-2" |
|
|
|
|
> |
|
|
|
|
<ProgressControl /> |
|
|
|
|
<div className="flex items-center"> |
|
|
|
|
<LeftSideControls /> |
|
|
|
|
<div className="flex-1" /> |
|
|
|
|
<SeriesSelectionControl /> |
|
|
|
|
<AirplayControl /> |
|
|
|
|
<ChromeCastControl /> |
|
|
|
|
<FullscreenControl /> |
|
|
|
|
</div> |
|
|
|
|
<VideoPlayerHeader |
|
|
|
|
media={props.media?.meta} |
|
|
|
|
onClick={props.onGoBack} |
|
|
|
|
isMobile={isMobile} |
|
|
|
|
/> |
|
|
|
|
</div> |
|
|
|
|
</CSSTransition> |
|
|
|
|
<CSSTransition |
|
|
|
|
nodeRef={top} |
|
|
|
|
nodeRef={bottom} |
|
|
|
|
in={show} |
|
|
|
|
timeout={200} |
|
|
|
|
classNames={{ |
|
|
|
|
exit: "transition-[transform,opacity] translate-y-0 duration-200 opacity-100", |
|
|
|
|
exitActive: "!-translate-y-4 !opacity-0", |
|
|
|
|
exitActive: "!translate-y-4 !opacity-0", |
|
|
|
|
exitDone: "hidden", |
|
|
|
|
enter: |
|
|
|
|
"transition-[transform,opacity] -translate-y-4 duration-200 opacity-0", |
|
|
|
|
"transition-[transform,opacity] translate-y-4 duration-200 opacity-0", |
|
|
|
|
enterActive: "!translate-y-0 !opacity-100", |
|
|
|
|
}} |
|
|
|
|
> |
|
|
|
|
<div |
|
|
|
|
ref={top} |
|
|
|
|
className="pointer-events-auto absolute inset-x-0 top-0 flex flex-col py-6 px-8 pb-2" |
|
|
|
|
ref={bottom} |
|
|
|
|
className="pointer-events-auto absolute inset-x-0 bottom-0 flex flex-col px-4 pb-2 [margin-bottom:env(safe-area-inset-bottom)]" |
|
|
|
|
> |
|
|
|
|
<VideoPlayerHeader media={props.media} onClick={props.onGoBack} /> |
|
|
|
|
<div className="flex w-full items-center space-x-3"> |
|
|
|
|
{isMobile && <SkipTime noDuration />} |
|
|
|
|
<ProgressControl /> |
|
|
|
|
</div> |
|
|
|
|
<div className="flex items-center"> |
|
|
|
|
{isMobile ? ( |
|
|
|
|
<div className="grid w-full grid-cols-[56px,1fr,56px] items-center"> |
|
|
|
|
<div /> |
|
|
|
|
<div className="flex items-center justify-center"> |
|
|
|
|
<SeriesSelectionControl /> |
|
|
|
|
<SourceSelectionControl media={props.media} /> |
|
|
|
|
</div> |
|
|
|
|
<FullscreenControl /> |
|
|
|
|
</div> |
|
|
|
|
) : ( |
|
|
|
|
<> |
|
|
|
|
<LeftSideControls /> |
|
|
|
|
<div className="flex-1" /> |
|
|
|
|
<QualityDisplayControl /> |
|
|
|
|
<SeriesSelectionControl /> |
|
|
|
|
<SourceSelectionControl media={props.media} /> |
|
|
|
|
<AirplayControl /> |
|
|
|
|
<ChromeCastControl /> |
|
|
|
|
<FullscreenControl /> |
|
|
|
|
</> |
|
|
|
|
)} |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</CSSTransition> |
|
|
|
|
</BackdropControl> |
|
|
|
|