You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
183 lines
7.0 KiB
183 lines
7.0 KiB
import { Transition } from "@/components/Transition"; |
|
import { useIsMobile } from "@/hooks/useIsMobile"; |
|
import { AirplayAction } from "@/video/components/actions/AirplayAction"; |
|
import { BackdropAction } from "@/video/components/actions/BackdropAction"; |
|
import { FullscreenAction } from "@/video/components/actions/FullscreenAction"; |
|
import { HeaderAction } from "@/video/components/actions/HeaderAction"; |
|
import { LoadingAction } from "@/video/components/actions/LoadingAction"; |
|
import { MiddlePauseAction } from "@/video/components/actions/MiddlePauseAction"; |
|
import { MobileCenterAction } from "@/video/components/actions/MobileCenterAction"; |
|
import { PageTitleAction } from "@/video/components/actions/PageTitleAction"; |
|
import { PauseAction } from "@/video/components/actions/PauseAction"; |
|
import { ProgressAction } from "@/video/components/actions/ProgressAction"; |
|
import { QualityDisplayAction } from "@/video/components/actions/QualityDisplayAction"; |
|
import { SeriesSelectionAction } from "@/video/components/actions/SeriesSelectionAction"; |
|
import { SourceSelectionAction } from "@/video/components/actions/SourceSelectionAction"; |
|
import { CaptionsSelectionAction } from "@/video/components/actions/CaptionsSelectionAction"; |
|
import { ShowTitleAction } from "@/video/components/actions/ShowTitleAction"; |
|
import { KeyboardShortcutsAction } from "@/video/components/actions/KeyboardShortcutsAction"; |
|
import { SkipTimeAction } from "@/video/components/actions/SkipTimeAction"; |
|
import { TimeAction } from "@/video/components/actions/TimeAction"; |
|
import { VolumeAction } from "@/video/components/actions/VolumeAction"; |
|
import { VideoPlayerError } from "@/video/components/parts/VideoPlayerError"; |
|
import { |
|
VideoPlayerBase, |
|
VideoPlayerBaseProps, |
|
} from "@/video/components/VideoPlayerBase"; |
|
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; |
|
import { useControls } from "@/video/state/logic/controls"; |
|
import { ReactNode, useCallback, useState } from "react"; |
|
import { PopoutProviderAction } from "@/video/components/popouts/PopoutProviderAction"; |
|
import { ChromecastAction } from "@/video/components/actions/ChromecastAction"; |
|
import { CastingTextAction } from "@/video/components/actions/CastingTextAction"; |
|
import { DownloadAction } from "@/video/components/actions/DownloadAction"; |
|
import { PictureInPictureAction } from "@/video/components/actions/PictureInPictureAction"; |
|
import { CaptionRenderer } from "./CaptionRenderer"; |
|
|
|
type Props = VideoPlayerBaseProps; |
|
|
|
function CenterPosition(props: { children: ReactNode }) { |
|
return ( |
|
<div className="absolute inset-0 flex items-center justify-center"> |
|
{props.children} |
|
</div> |
|
); |
|
} |
|
|
|
function LeftSideControls() { |
|
const descriptor = useVideoPlayerDescriptor(); |
|
const controls = useControls(descriptor); |
|
|
|
const handleMouseEnter = useCallback(() => { |
|
controls.setLeftControlsHover(true); |
|
}, [controls]); |
|
const handleMouseLeave = useCallback(() => { |
|
controls.setLeftControlsHover(false); |
|
}, [controls]); |
|
|
|
return ( |
|
<> |
|
<div |
|
className="flex items-center px-2" |
|
onMouseLeave={handleMouseLeave} |
|
onMouseEnter={handleMouseEnter} |
|
> |
|
<PauseAction /> |
|
<SkipTimeAction /> |
|
<VolumeAction className="mr-2" /> |
|
<TimeAction /> |
|
</div> |
|
<ShowTitleAction /> |
|
</> |
|
); |
|
} |
|
|
|
export function VideoPlayer(props: Props) { |
|
const [show, setShow] = useState(false); |
|
const { isMobile } = useIsMobile(); |
|
|
|
const onBackdropChange = useCallback( |
|
(showing: boolean) => { |
|
setShow(showing); |
|
}, |
|
[setShow] |
|
); |
|
|
|
return ( |
|
<VideoPlayerBase |
|
autoPlay={props.autoPlay} |
|
includeSafeArea={props.includeSafeArea} |
|
onGoBack={props.onGoBack} |
|
> |
|
{({ isFullscreen }) => ( |
|
<> |
|
<KeyboardShortcutsAction /> |
|
<PageTitleAction /> |
|
<VideoPlayerError onGoBack={props.onGoBack}> |
|
<BackdropAction onBackdropChange={onBackdropChange}> |
|
<CenterPosition> |
|
<LoadingAction /> |
|
</CenterPosition> |
|
<CenterPosition> |
|
<CastingTextAction /> |
|
</CenterPosition> |
|
<CenterPosition> |
|
<MiddlePauseAction /> |
|
</CenterPosition> |
|
{isMobile ? ( |
|
<Transition |
|
animation="fade" |
|
show={show} |
|
className="absolute inset-0 flex items-center justify-center" |
|
> |
|
<MobileCenterAction /> |
|
</Transition> |
|
) : ( |
|
"" |
|
)} |
|
<Transition |
|
animation="slide-down" |
|
show={show} |
|
className="pointer-events-auto absolute inset-x-0 top-0 flex flex-col py-6 px-8 pb-2" |
|
> |
|
<HeaderAction |
|
showControls={isMobile} |
|
onClick={props.onGoBack} |
|
isFullScreen |
|
/> |
|
</Transition> |
|
<Transition |
|
animation="slide-up" |
|
show={show} |
|
className={[ |
|
"pointer-events-auto absolute inset-x-0 bottom-0 flex flex-col px-4 pb-2", |
|
props.includeSafeArea || isFullscreen |
|
? "[margin-bottom:env(safe-area-inset-bottom)]" |
|
: "", |
|
].join(" ")} |
|
> |
|
<div className="flex w-full items-center space-x-3"> |
|
{isMobile && <TimeAction noDuration />} |
|
<ProgressAction /> |
|
</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"> |
|
<DownloadAction /> |
|
<PictureInPictureAction /> |
|
<CaptionsSelectionAction /> |
|
<SeriesSelectionAction /> |
|
<SourceSelectionAction /> |
|
</div> |
|
<FullscreenAction /> |
|
</div> |
|
) : ( |
|
<> |
|
<LeftSideControls /> |
|
<div className="flex-1" /> |
|
<QualityDisplayAction /> |
|
<SeriesSelectionAction /> |
|
<SourceSelectionAction /> |
|
<div className="mx-2 h-6 w-px bg-white opacity-50" /> |
|
<ChromecastAction /> |
|
<AirplayAction /> |
|
<DownloadAction /> |
|
<PictureInPictureAction /> |
|
<CaptionsSelectionAction /> |
|
<FullscreenAction /> |
|
</> |
|
)} |
|
</div> |
|
</Transition> |
|
{show ? <PopoutProviderAction /> : null} |
|
</BackdropAction> |
|
<CaptionRenderer isControlsShown={show} /> |
|
{props.children} |
|
</VideoPlayerError> |
|
</> |
|
)} |
|
</VideoPlayerBase> |
|
); |
|
}
|
|
|