mirror of
https://github.com/Qortal/qapp-core.git
synced 2025-07-14 21:11:23 +00:00
fixed global player for mobile
This commit is contained in:
parent
4847b4a002
commit
b01232b39f
202
src/components/VideoPlayer/MobileControls.tsx
Normal file
202
src/components/VideoPlayer/MobileControls.tsx
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
import { alpha, Box, IconButton } from "@mui/material";
|
||||||
|
import React from "react";
|
||||||
|
import { ProgressSlider } from "./VideoControls";
|
||||||
|
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
|
||||||
|
import PauseIcon from "@mui/icons-material/Pause";
|
||||||
|
import SubtitlesIcon from "@mui/icons-material/Subtitles";
|
||||||
|
import SlowMotionVideoIcon from "@mui/icons-material/SlowMotionVideo";
|
||||||
|
import Fullscreen from "@mui/icons-material/Fullscreen";
|
||||||
|
import Forward10Icon from "@mui/icons-material/Forward10";
|
||||||
|
import Replay10Icon from "@mui/icons-material/Replay10";
|
||||||
|
|
||||||
|
interface MobileControlsProps {
|
||||||
|
showControlsMobile: boolean;
|
||||||
|
progress: number;
|
||||||
|
duration: number;
|
||||||
|
playerRef: any;
|
||||||
|
setShowControlsMobile: (val: boolean) => void;
|
||||||
|
isPlaying: boolean;
|
||||||
|
togglePlay: () => void;
|
||||||
|
openSubtitleManager: () => void;
|
||||||
|
openPlaybackMenu: () => void;
|
||||||
|
toggleFullscreen: () => void;
|
||||||
|
setProgressRelative: (val: number) => void;
|
||||||
|
}
|
||||||
|
export const MobileControls = ({
|
||||||
|
showControlsMobile,
|
||||||
|
togglePlay,
|
||||||
|
isPlaying,
|
||||||
|
setShowControlsMobile,
|
||||||
|
playerRef,
|
||||||
|
progress,
|
||||||
|
duration,
|
||||||
|
openSubtitleManager,
|
||||||
|
openPlaybackMenu,
|
||||||
|
toggleFullscreen,
|
||||||
|
setProgressRelative,
|
||||||
|
}: MobileControlsProps) => {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
onClick={() => setShowControlsMobile(false)}
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
display: showControlsMobile ? "block" : "none",
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
right: 0,
|
||||||
|
left: 0,
|
||||||
|
zIndex: 1,
|
||||||
|
background: "rgba(0,0,0,.5)",
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
top: "10px",
|
||||||
|
right: "10px",
|
||||||
|
display: "flex",
|
||||||
|
gap: "10px",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
openSubtitleManager();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SubtitlesIcon
|
||||||
|
sx={{
|
||||||
|
fontSize: "24px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
<IconButton
|
||||||
|
sx={{
|
||||||
|
fontSize: "24px",
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
openPlaybackMenu();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SlowMotionVideoIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
top: "50%",
|
||||||
|
left: "50%",
|
||||||
|
transform: "translate(-50%, -50%)",
|
||||||
|
gap: "50px",
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
sx={{
|
||||||
|
opacity: 1,
|
||||||
|
zIndex: 2,
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setProgressRelative(-10);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Replay10Icon
|
||||||
|
sx={{
|
||||||
|
fontSize: "36px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
{isPlaying && (
|
||||||
|
<IconButton
|
||||||
|
sx={{
|
||||||
|
opacity: 1,
|
||||||
|
zIndex: 2,
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
togglePlay();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PauseIcon
|
||||||
|
sx={{
|
||||||
|
fontSize: "36px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
{!isPlaying && (
|
||||||
|
<IconButton
|
||||||
|
sx={{
|
||||||
|
opacity: 1,
|
||||||
|
zIndex: 2,
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
togglePlay();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PlayArrowIcon
|
||||||
|
sx={{
|
||||||
|
fontSize: "36px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
<IconButton
|
||||||
|
sx={{
|
||||||
|
opacity: 1,
|
||||||
|
zIndex: 2,
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setProgressRelative(10);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Forward10Icon
|
||||||
|
sx={{
|
||||||
|
fontSize: "36px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
bottom: "20px",
|
||||||
|
right: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
sx={{
|
||||||
|
fontSize: "24px",
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
toggleFullscreen();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Fullscreen />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
position: "absolute",
|
||||||
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ProgressSlider
|
||||||
|
playerRef={playerRef}
|
||||||
|
progress={progress}
|
||||||
|
duration={duration}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
@ -72,6 +72,8 @@ export interface SubtitleManagerProps {
|
|||||||
onSelect: (subtitle: SubtitlePublishedData) => void;
|
onSelect: (subtitle: SubtitlePublishedData) => void;
|
||||||
subtitleBtnRef: any;
|
subtitleBtnRef: any;
|
||||||
currentSubTrack: null | string
|
currentSubTrack: null | string
|
||||||
|
setDrawerOpenSubtitles: (val: boolean)=> void
|
||||||
|
isFromDrawer: boolean
|
||||||
}
|
}
|
||||||
export interface Subtitle {
|
export interface Subtitle {
|
||||||
language: string | null;
|
language: string | null;
|
||||||
@ -108,6 +110,8 @@ const SubtitleManagerComponent = ({
|
|||||||
onSelect,
|
onSelect,
|
||||||
subtitleBtnRef,
|
subtitleBtnRef,
|
||||||
currentSubTrack,
|
currentSubTrack,
|
||||||
|
setDrawerOpenSubtitles,
|
||||||
|
isFromDrawer = false
|
||||||
}: SubtitleManagerProps) => {
|
}: SubtitleManagerProps) => {
|
||||||
const [mode, setMode] = useState(1);
|
const [mode, setMode] = useState(1);
|
||||||
const [isOpenPublish, setIsOpenPublish] = useState(false);
|
const [isOpenPublish, setIsOpenPublish] = useState(false);
|
||||||
@ -177,8 +181,11 @@ const SubtitleManagerComponent = ({
|
|||||||
}
|
}
|
||||||
}, [open])
|
}, [open])
|
||||||
|
|
||||||
|
console.log('isFromDrawer', )
|
||||||
|
|
||||||
const handleBlur = (e: React.FocusEvent) => {
|
const handleBlur = (e: React.FocusEvent) => {
|
||||||
if (!e.currentTarget.contains(e.relatedTarget) && !isOpenPublish) {
|
if (!e.currentTarget.contains(e.relatedTarget) && !isOpenPublish && !isFromDrawer && open) {
|
||||||
|
console.log('hello close')
|
||||||
close();
|
close();
|
||||||
setIsOpenPublish(false)
|
setIsOpenPublish(false)
|
||||||
}
|
}
|
||||||
@ -262,13 +269,13 @@ const SubtitleManagerComponent = ({
|
|||||||
|
|
||||||
sx={
|
sx={
|
||||||
{
|
{
|
||||||
position: 'absolute',
|
position: isFromDrawer ? 'relative' : 'absolute',
|
||||||
bottom: 60,
|
bottom: isFromDrawer ? 'unset' : 60,
|
||||||
right: 5,
|
right: isFromDrawer ? 'unset' : 5,
|
||||||
color: "white",
|
color: "white",
|
||||||
opacity: 0.9,
|
opacity: 0.9,
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
boxShadow: 5,
|
boxShadow: isFromDrawer ? 'unset' : 5,
|
||||||
p: 1,
|
p: 1,
|
||||||
minWidth: 225,
|
minWidth: 225,
|
||||||
height: 300,
|
height: 300,
|
||||||
@ -387,30 +394,7 @@ const SubtitleManagerComponent = ({
|
|||||||
Load community subs
|
Load community subs
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
{/* <Box>
|
|
||||||
{[
|
|
||||||
'Ambient mode',
|
|
||||||
'Annotations',
|
|
||||||
'Subtitles/CC',
|
|
||||||
'Sleep timer',
|
|
||||||
'Playback speed',
|
|
||||||
'Quality',
|
|
||||||
].map((label) => (
|
|
||||||
<Typography
|
|
||||||
key={label}
|
|
||||||
sx={{
|
|
||||||
px: 2,
|
|
||||||
py: 1,
|
|
||||||
'&:hover': {
|
|
||||||
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
|
||||||
cursor: 'pointer',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</Typography>
|
|
||||||
))}
|
|
||||||
</Box> */}
|
|
||||||
|
|
||||||
</Box>
|
</Box>
|
||||||
<PublishSubtitles
|
<PublishSubtitles
|
||||||
@ -421,70 +405,10 @@ const SubtitleManagerComponent = ({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
</>
|
</>
|
||||||
// <Dialog
|
|
||||||
// open={!!open}
|
|
||||||
// fullWidth={true}
|
|
||||||
// maxWidth={"md"}
|
|
||||||
// sx={{
|
|
||||||
// zIndex: 999990,
|
|
||||||
// }}
|
|
||||||
// slotProps={{
|
|
||||||
// paper: {
|
|
||||||
// elevation: 0,
|
|
||||||
// },
|
|
||||||
// }}
|
|
||||||
// >
|
|
||||||
// <DialogTitle>Subtitles</DialogTitle>
|
|
||||||
// <IconButton
|
|
||||||
// aria-label="close"
|
|
||||||
// onClick={handleClose}
|
|
||||||
// sx={(theme) => ({
|
|
||||||
// position: "absolute",
|
|
||||||
// right: 8,
|
|
||||||
// top: 8,
|
|
||||||
// })}
|
|
||||||
// >
|
|
||||||
// <CloseIcon />
|
|
||||||
// </IconButton>
|
|
||||||
// <Button onClick={() => setMode(5)}>New subtitles</Button>
|
|
||||||
// {mode === 1 && (
|
|
||||||
// <PublisherSubtitles
|
|
||||||
// subtitles={subtitles}
|
|
||||||
// publisherName={qortalMetadata.name}
|
|
||||||
// setMode={setMode}
|
|
||||||
// onSelect={onSelect}
|
|
||||||
// />
|
|
||||||
// )}
|
|
||||||
// {mode === 5 && <PublishSubtitles publishHandler={publishHandler} />}
|
|
||||||
// {/* {mode === 2 && (
|
|
||||||
// <CommunitySubtitles
|
|
||||||
// link={open?.link}
|
|
||||||
// name={open?.name}
|
|
||||||
// mode={mode}
|
|
||||||
// setMode={setMode}
|
|
||||||
// username={username}
|
|
||||||
// category={open?.category}
|
|
||||||
// rootName={open?.rootName}
|
|
||||||
// />
|
|
||||||
// )}
|
|
||||||
|
|
||||||
// {mode === 4 && (
|
|
||||||
// <MySubtitles
|
|
||||||
// link={open?.link}
|
|
||||||
// name={open?.name}
|
|
||||||
// mode={mode}
|
|
||||||
// setMode={setMode}
|
|
||||||
// username={username}
|
|
||||||
// title={title}
|
|
||||||
// description={description}
|
|
||||||
// setDescription={setDescription}
|
|
||||||
// setTitle={setTitle}
|
|
||||||
// />
|
|
||||||
// )} */}
|
|
||||||
// </Dialog>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
interface PublisherSubtitlesProps {
|
interface PublisherSubtitlesProps {
|
||||||
publisherName: string;
|
publisherName: string;
|
||||||
subtitles: any[];
|
subtitles: any[];
|
||||||
|
@ -71,7 +71,7 @@ export const ProgressSlider = ({ progress, duration, playerRef }: any) => {
|
|||||||
const [hoverX, setHoverX] = useState<number | null>(null);
|
const [hoverX, setHoverX] = useState<number | null>(null);
|
||||||
const [thumbnailUrl, setThumbnailUrl] = useState<string | null>(null);
|
const [thumbnailUrl, setThumbnailUrl] = useState<string | null>(null);
|
||||||
const [showDuration, setShowDuration] = useState(0);
|
const [showDuration, setShowDuration] = useState(0);
|
||||||
const onProgressChange = (_: any, value: number | number[]) => {
|
const onProgressChange = (e: any, value: number | number[]) => {
|
||||||
if (!playerRef.current) return;
|
if (!playerRef.current) return;
|
||||||
|
|
||||||
playerRef.current?.currentTime(value as number);
|
playerRef.current?.currentTime(value as number);
|
||||||
@ -128,6 +128,11 @@ export const ProgressSlider = ({ progress, duration, playerRef }: any) => {
|
|||||||
console.log("thumbnailUrl", thumbnailUrl, hoverX);
|
console.log("thumbnailUrl", thumbnailUrl, hoverX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleClickCapture = (e: React.MouseEvent) => {
|
||||||
|
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@ -152,6 +157,7 @@ export const ProgressSlider = ({ progress, duration, playerRef }: any) => {
|
|||||||
ref={sliderRef}
|
ref={sliderRef}
|
||||||
onMouseMove={handleMouseMove}
|
onMouseMove={handleMouseMove}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
|
onClickCapture={handleClickCapture}
|
||||||
value={progress}
|
value={progress}
|
||||||
onChange={onProgressChange}
|
onChange={onProgressChange}
|
||||||
min={0}
|
min={0}
|
||||||
@ -439,8 +445,9 @@ interface PlayBackMenuProps {
|
|||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
onSelect: (speed: number)=> void;
|
onSelect: (speed: number)=> void;
|
||||||
playbackRate: number
|
playbackRate: number
|
||||||
|
isFromDrawer: boolean
|
||||||
}
|
}
|
||||||
export const PlayBackMenu = ({close, onSelect, isOpen, playbackRate}: PlayBackMenuProps)=> {
|
export const PlayBackMenu = ({close, onSelect, isOpen, playbackRate, isFromDrawer}: PlayBackMenuProps)=> {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const ref = useRef<any>(null)
|
const ref = useRef<any>(null)
|
||||||
|
|
||||||
@ -451,7 +458,7 @@ export const PlayBackMenu = ({close, onSelect, isOpen, playbackRate}: PlayBackMe
|
|||||||
}, [isOpen])
|
}, [isOpen])
|
||||||
|
|
||||||
const handleBlur = (e: React.FocusEvent) => {
|
const handleBlur = (e: React.FocusEvent) => {
|
||||||
if (!e.currentTarget.contains(e.relatedTarget)) {
|
if (!e.currentTarget.contains(e.relatedTarget) && !isFromDrawer) {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -466,13 +473,13 @@ export const PlayBackMenu = ({close, onSelect, isOpen, playbackRate}: PlayBackMe
|
|||||||
|
|
||||||
sx={
|
sx={
|
||||||
{
|
{
|
||||||
position: 'absolute',
|
position: isFromDrawer ? 'relative' : 'absolute',
|
||||||
bottom: 60,
|
bottom: isFromDrawer ? 'relative' : 60,
|
||||||
right: 5,
|
right:isFromDrawer ? 'relative' : 5,
|
||||||
color: "white",
|
color: "white",
|
||||||
opacity: 0.9,
|
opacity: 0.9,
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
boxShadow: 5,
|
boxShadow: isFromDrawer ? 'relative' : 5,
|
||||||
p: 1,
|
p: 1,
|
||||||
minWidth: 225,
|
minWidth: 225,
|
||||||
height: 300,
|
height: 300,
|
||||||
|
@ -42,9 +42,10 @@ interface VideoControlsBarProps {
|
|||||||
toggleMute: ()=> void
|
toggleMute: ()=> void
|
||||||
openPlaybackMenu: ()=> void
|
openPlaybackMenu: ()=> void
|
||||||
togglePictureInPicture: ()=> void
|
togglePictureInPicture: ()=> void
|
||||||
|
isVideoPlayerSmall: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const VideoControlsBar = ({subtitleBtnRef, showControls, playbackRate, increaseSpeed,decreaseSpeed, isFullScreen, showControlsFullScreen, reloadVideo, onVolumeChange, volume, isPlaying, canPlay, isScreenSmall, controlsHeight, playerRef, duration, progress, togglePlay, toggleFullscreen, extractFrames, openSubtitleManager, onSelectPlaybackRate, isMuted, toggleMute, openPlaybackMenu, togglePictureInPicture}: VideoControlsBarProps) => {
|
export const VideoControlsBar = ({subtitleBtnRef, showControls, playbackRate, increaseSpeed,decreaseSpeed, isFullScreen, showControlsFullScreen, reloadVideo, onVolumeChange, volume, isPlaying, canPlay, isScreenSmall, controlsHeight, playerRef, duration, progress, togglePlay, toggleFullscreen, extractFrames, openSubtitleManager, onSelectPlaybackRate, isMuted, toggleMute, openPlaybackMenu, togglePictureInPicture, isVideoPlayerSmall}: VideoControlsBarProps) => {
|
||||||
|
|
||||||
const showMobileControls = isScreenSmall && canPlay;
|
const showMobileControls = isScreenSmall && canPlay;
|
||||||
|
|
||||||
@ -87,7 +88,8 @@ export const VideoControlsBar = ({subtitleBtnRef, showControls, playbackRate, in
|
|||||||
}}>
|
}}>
|
||||||
|
|
||||||
<ProgressSlider playerRef={playerRef} progress={progress} duration={duration} />
|
<ProgressSlider playerRef={playerRef} progress={progress} duration={duration} />
|
||||||
<Box sx={{
|
{!isVideoPlayerSmall && (
|
||||||
|
<Box sx={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
display: 'flex'
|
display: 'flex'
|
||||||
}}>
|
}}>
|
||||||
@ -117,6 +119,8 @@ export const VideoControlsBar = ({subtitleBtnRef, showControls, playbackRate, in
|
|||||||
<FullscreenButton toggleFullscreen={toggleFullscreen} />
|
<FullscreenButton toggleFullscreen={toggleFullscreen} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
</Box>
|
</Box>
|
||||||
) : null}
|
) : null}
|
||||||
</ControlsContainer>
|
</ControlsContainer>
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { styled } from "@mui/system";
|
import { styled, Theme } from "@mui/system";
|
||||||
import { Box } from "@mui/material";
|
import { Box } from "@mui/material";
|
||||||
|
|
||||||
export const VideoContainer = styled(Box)(({ theme }) => ({
|
export const VideoContainer = styled(Box, {
|
||||||
|
shouldForwardProp: (prop) => prop !== 'isVideoPlayerSmall',
|
||||||
|
})<{ isVideoPlayerSmall?: boolean }>(({ theme, isVideoPlayerSmall }) => ({
|
||||||
position: "relative",
|
position: "relative",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
@ -11,7 +13,7 @@ export const VideoContainer = styled(Box)(({ theme }) => ({
|
|||||||
height: "100%",
|
height: "100%",
|
||||||
margin: 0,
|
margin: 0,
|
||||||
padding: 0,
|
padding: 0,
|
||||||
borderRadius: '12px',
|
borderRadius: isVideoPlayerSmall ? '0px' : '12px',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
"&:focus": { outline: "none" },
|
"&:focus": { outline: "none" },
|
||||||
}));
|
}));
|
||||||
|
@ -33,6 +33,8 @@ import { TimelineActionsComponent } from "./TimelineActionsComponent";
|
|||||||
import { PlayBackMenu } from "./VideoControls";
|
import { PlayBackMenu } from "./VideoControls";
|
||||||
import { useGlobalPlayerStore } from "../../state/pip";
|
import { useGlobalPlayerStore } from "../../state/pip";
|
||||||
import { LocationContext } from "../../context/GlobalProvider";
|
import { LocationContext } from "../../context/GlobalProvider";
|
||||||
|
import { alpha, Box, Drawer, List, ListItem } from "@mui/material";
|
||||||
|
import { MobileControls } from "./MobileControls";
|
||||||
|
|
||||||
export async function srtBase64ToVttBlobUrl(
|
export async function srtBase64ToVttBlobUrl(
|
||||||
base64Srt: string
|
base64Srt: string
|
||||||
@ -107,6 +109,8 @@ async function getVideoMimeTypeFromUrl(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
||||||
|
|
||||||
|
|
||||||
export const VideoPlayer = ({
|
export const VideoPlayer = ({
|
||||||
videoRef,
|
videoRef,
|
||||||
@ -117,9 +121,19 @@ export const VideoPlayer = ({
|
|||||||
onEnded,
|
onEnded,
|
||||||
timelineActions
|
timelineActions
|
||||||
}: VideoPlayerProps) => {
|
}: VideoPlayerProps) => {
|
||||||
const containerRef = useRef<RefObject<HTMLDivElement> | null>(null);
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||||
const [videoObjectFit] = useState<StretchVideoType>("contain");
|
const [videoObjectFit] = useState<StretchVideoType>("contain");
|
||||||
const [isPlaying, setIsPlaying] = useState(false);
|
const [isPlaying, setIsPlaying] = useState(false);
|
||||||
|
|
||||||
|
const [width, setWidth] = useState(0);
|
||||||
|
console.log('width',width)
|
||||||
|
useEffect(() => {
|
||||||
|
const observer = new ResizeObserver(([entry]) => {
|
||||||
|
setWidth(entry.contentRect.width);
|
||||||
|
});
|
||||||
|
if (containerRef.current) observer.observe(containerRef.current);
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, []);
|
||||||
const { volume, setVolume, setPlaybackRate, playbackRate } = useVideoStore(
|
const { volume, setVolume, setPlaybackRate, playbackRate } = useVideoStore(
|
||||||
(state) => ({
|
(state) => ({
|
||||||
volume: state.playbackSettings.volume,
|
volume: state.playbackSettings.volume,
|
||||||
@ -129,6 +143,9 @@ export const VideoPlayer = ({
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
const playerRef = useRef<Player | null>(null);
|
const playerRef = useRef<Player | null>(null);
|
||||||
|
const [drawerOpenSubtitles, setDrawerOpenSubtitles] = useState(false)
|
||||||
|
const [drawerOpenPlayback, setDrawerOpenPlayback] = useState(false)
|
||||||
|
const [showControlsMobile, setShowControlsMobile] = useState(false)
|
||||||
const [isPlayerInitialized, setIsPlayerInitialized] = useState(false);
|
const [isPlayerInitialized, setIsPlayerInitialized] = useState(false);
|
||||||
const [videoCodec, setVideoCodec] = useState<null | false | string>(null);
|
const [videoCodec, setVideoCodec] = useState<null | false | string>(null);
|
||||||
const [isMuted, setIsMuted] = useState(false);
|
const [isMuted, setIsMuted] = useState(false);
|
||||||
@ -144,6 +161,7 @@ export const VideoPlayer = ({
|
|||||||
|
|
||||||
const locationRef = useRef<string | null>(null)
|
const locationRef = useRef<string | null>(null)
|
||||||
const [isOpenPlaybackMenu, setIsOpenPlaybackmenu] = useState(false)
|
const [isOpenPlaybackMenu, setIsOpenPlaybackmenu] = useState(false)
|
||||||
|
const isVideoPlayerSmall = width < 600
|
||||||
const {
|
const {
|
||||||
reloadVideo,
|
reloadVideo,
|
||||||
togglePlay,
|
togglePlay,
|
||||||
@ -188,18 +206,71 @@ export const VideoPlayer = ({
|
|||||||
|
|
||||||
const { getProgress } = useProgressStore();
|
const { getProgress } = useProgressStore();
|
||||||
|
|
||||||
const enterFullscreen = useCallback(() => {
|
const enterFullscreen = useCallback(async () => {
|
||||||
const ref = containerRef?.current as any;
|
const ref = containerRef?.current as HTMLElement | null;
|
||||||
if (!ref) return;
|
if (!ref || document.fullscreenElement) return;
|
||||||
|
|
||||||
if (ref.requestFullscreen && !isFullscreen) {
|
try {
|
||||||
ref.requestFullscreen();
|
// Wait for fullscreen to activate
|
||||||
|
if (ref.requestFullscreen) {
|
||||||
|
await ref.requestFullscreen();
|
||||||
|
} else if ((ref as any).webkitRequestFullscreen) {
|
||||||
|
await (ref as any).webkitRequestFullscreen(); // Safari fallback
|
||||||
}
|
}
|
||||||
}, []);
|
|
||||||
|
|
||||||
const exitFullscreen = useCallback(() => {
|
|
||||||
document?.exitFullscreen();
|
if (
|
||||||
}, [isFullscreen]);
|
typeof screen.orientation !== 'undefined' &&
|
||||||
|
'lock' in screen.orientation &&
|
||||||
|
typeof screen.orientation.lock === 'function'
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
await (screen.orientation as any).lock('landscape');
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Orientation lock failed:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await qortalRequest({
|
||||||
|
action: 'SCREEN_ORIENTATION',
|
||||||
|
mode: 'landscape'
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to enter fullscreen or lock orientation:', err);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
// const exitFullscreen = useCallback(() => {
|
||||||
|
// document?.exitFullscreen();
|
||||||
|
// }, [isFullscreen]);
|
||||||
|
|
||||||
|
const exitFullscreen = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
if (document.fullscreenElement) {
|
||||||
|
await document.exitFullscreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof screen.orientation !== 'undefined' &&
|
||||||
|
'lock' in screen.orientation &&
|
||||||
|
typeof screen.orientation.lock === 'function'
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
// Attempt to reset by locking to 'portrait' or 'any' (if supported)
|
||||||
|
await screen.orientation.lock('portrait'); // or 'any' if supported
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Orientation lock failed:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await qortalRequest({
|
||||||
|
action: 'SCREEN_ORIENTATION',
|
||||||
|
mode: 'portrait'
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Error exiting fullscreen or unlocking orientation:', err);
|
||||||
|
}
|
||||||
|
}, [isFullscreen]);
|
||||||
|
|
||||||
const toggleFullscreen = useCallback(() => {
|
const toggleFullscreen = useCallback(() => {
|
||||||
isFullscreen ? exitFullscreen() : enterFullscreen();
|
isFullscreen ? exitFullscreen() : enterFullscreen();
|
||||||
@ -239,10 +310,14 @@ export const VideoPlayer = ({
|
|||||||
|
|
||||||
const closeSubtitleManager = useCallback(() => {
|
const closeSubtitleManager = useCallback(() => {
|
||||||
setIsOpenSubtitleManage(false);
|
setIsOpenSubtitleManage(false);
|
||||||
|
setDrawerOpenSubtitles(false)
|
||||||
}, []);
|
}, []);
|
||||||
const openSubtitleManager = useCallback(() => {
|
const openSubtitleManager = useCallback(() => {
|
||||||
|
if(isVideoPlayerSmall){
|
||||||
|
setDrawerOpenSubtitles(true)
|
||||||
|
}
|
||||||
setIsOpenSubtitleManage(true);
|
setIsOpenSubtitleManage(true);
|
||||||
}, []);
|
}, [isVideoPlayerSmall]);
|
||||||
|
|
||||||
const videoLocation = useMemo(() => {
|
const videoLocation = useMemo(() => {
|
||||||
if (!qortalVideoResource) return null;
|
if (!qortalVideoResource) return null;
|
||||||
@ -388,6 +463,7 @@ const videoLocationRef = useRef< null | string>(null)
|
|||||||
const hideTimeout = useRef<any>(null);
|
const hideTimeout = useRef<any>(null);
|
||||||
|
|
||||||
const resetHideTimer = () => {
|
const resetHideTimer = () => {
|
||||||
|
if(isTouchDevice) return
|
||||||
setShowControls(true);
|
setShowControls(true);
|
||||||
if (hideTimeout.current) clearTimeout(hideTimeout.current);
|
if (hideTimeout.current) clearTimeout(hideTimeout.current);
|
||||||
hideTimeout.current = setTimeout(() => {
|
hideTimeout.current = setTimeout(() => {
|
||||||
@ -396,17 +472,24 @@ const videoLocationRef = useRef< null | string>(null)
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseMove = () => {
|
const handleMouseMove = () => {
|
||||||
|
if(isTouchDevice) return
|
||||||
resetHideTimer();
|
resetHideTimer();
|
||||||
};
|
};
|
||||||
|
|
||||||
const closePlaybackMenu = useCallback(()=> {
|
const closePlaybackMenu = useCallback(()=> {
|
||||||
setIsOpenPlaybackmenu(false)
|
setIsOpenPlaybackmenu(false)
|
||||||
|
setDrawerOpenPlayback(false)
|
||||||
}, [])
|
}, [])
|
||||||
const openPlaybackMenu = useCallback(()=> {
|
const openPlaybackMenu = useCallback(()=> {
|
||||||
|
if(isVideoPlayerSmall){
|
||||||
|
setDrawerOpenPlayback(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
setIsOpenPlaybackmenu(true)
|
setIsOpenPlaybackmenu(true)
|
||||||
}, [])
|
}, [isVideoPlayerSmall])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if(isTouchDevice) return
|
||||||
resetHideTimer(); // initial show
|
resetHideTimer(); // initial show
|
||||||
return () => {
|
return () => {
|
||||||
if (hideTimeout.current) clearTimeout(hideTimeout.current);
|
if (hideTimeout.current) clearTimeout(hideTimeout.current);
|
||||||
@ -717,6 +800,33 @@ savedVideoRef.current = video.current;
|
|||||||
player.off("ratechange", handleRateChange);
|
player.off("ratechange", handleRateChange);
|
||||||
};
|
};
|
||||||
}, [isPlayerInitialized]);
|
}, [isPlayerInitialized]);
|
||||||
|
const hideTimeoutRef = useRef<number | null>(null);
|
||||||
|
|
||||||
|
|
||||||
|
const resetHideTimeout = () => {
|
||||||
|
setShowControlsMobile(true);
|
||||||
|
if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
|
||||||
|
hideTimeoutRef.current = setTimeout(() => {
|
||||||
|
setShowControlsMobile(false);
|
||||||
|
}, 3000);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleInteraction = () => resetHideTimeout();
|
||||||
|
|
||||||
|
const container = containerRef.current;
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
container.addEventListener('touchstart', handleInteraction);
|
||||||
|
// container.addEventListener('mousemove', handleInteraction);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
container.removeEventListener('touchstart', handleInteraction);
|
||||||
|
// container.removeEventListener('mousemove', handleInteraction);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
console.log('showControlsMobile', showControlsMobile)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -728,6 +838,7 @@ savedVideoRef.current = video.current;
|
|||||||
onMouseMove={handleMouseMove}
|
onMouseMove={handleMouseMove}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
|
isVideoPlayerSmall={isVideoPlayerSmall}
|
||||||
>
|
>
|
||||||
<LoadingVideo
|
<LoadingVideo
|
||||||
togglePlay={togglePlay}
|
togglePlay={togglePlay}
|
||||||
@ -754,11 +865,11 @@ savedVideoRef.current = video.current;
|
|||||||
onVolumeChange={onVolumeChangeHandler}
|
onVolumeChange={onVolumeChangeHandler}
|
||||||
controls={false}
|
controls={false}
|
||||||
/>
|
/>
|
||||||
<PlayBackMenu close={closePlaybackMenu} isOpen={isOpenPlaybackMenu} onSelect={onSelectPlaybackRate} playbackRate={playbackRate} />
|
<PlayBackMenu isFromDrawer={false} close={closePlaybackMenu} isOpen={isOpenPlaybackMenu} onSelect={onSelectPlaybackRate} playbackRate={playbackRate} />
|
||||||
{/* <canvas ref={canvasRef} style={{ display: "none" }}></canvas> */}
|
|
||||||
|
|
||||||
{isReady && (
|
{isReady && !showControlsMobile && (
|
||||||
<VideoControlsBar
|
<VideoControlsBar
|
||||||
|
isVideoPlayerSmall={isVideoPlayerSmall}
|
||||||
subtitleBtnRef={subtitleBtnRef}
|
subtitleBtnRef={subtitleBtnRef}
|
||||||
playbackRate={playbackRate}
|
playbackRate={playbackRate}
|
||||||
increaseSpeed={hotkeyHandlers.increaseSpeed}
|
increaseSpeed={hotkeyHandlers.increaseSpeed}
|
||||||
@ -790,15 +901,73 @@ savedVideoRef.current = video.current;
|
|||||||
{timelineActions && Array.isArray(timelineActions) && (
|
{timelineActions && Array.isArray(timelineActions) && (
|
||||||
<TimelineActionsComponent seekTo={seekTo} containerRef={containerRef} progress={localProgress} timelineActions={timelineActions}/>
|
<TimelineActionsComponent seekTo={seekTo} containerRef={containerRef} progress={localProgress} timelineActions={timelineActions}/>
|
||||||
)}
|
)}
|
||||||
<SubtitleManager
|
{showControlsMobile && (
|
||||||
|
<MobileControls setProgressRelative={setProgressRelative} toggleFullscreen={toggleFullscreen} openPlaybackMenu={openPlaybackMenu} openSubtitleManager={openSubtitleManager} togglePlay={togglePlay} isPlaying={isPlaying} setShowControlsMobile={setShowControlsMobile} duration={duration}
|
||||||
|
progress={localProgress} playerRef={playerRef} showControlsMobile={showControlsMobile} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
{!isVideoPlayerSmall && (
|
||||||
|
<SubtitleManager
|
||||||
subtitleBtnRef={subtitleBtnRef}
|
subtitleBtnRef={subtitleBtnRef}
|
||||||
close={closeSubtitleManager}
|
close={closeSubtitleManager}
|
||||||
open={isOpenSubtitleManage}
|
open={isOpenSubtitleManage}
|
||||||
qortalMetadata={qortalVideoResource}
|
qortalMetadata={qortalVideoResource}
|
||||||
onSelect={onSelectSubtitle}
|
onSelect={onSelectSubtitle}
|
||||||
currentSubTrack={currentSubTrack}
|
currentSubTrack={currentSubTrack}
|
||||||
|
setDrawerOpenSubtitles={setDrawerOpenSubtitles}
|
||||||
|
isFromDrawer={false}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
</VideoContainer>
|
</VideoContainer>
|
||||||
|
<Drawer anchor="bottom" open={drawerOpenSubtitles} onClose={() => setDrawerOpenSubtitles(false)} sx={{
|
||||||
|
|
||||||
|
}} slotProps={{
|
||||||
|
paper: {
|
||||||
|
sx: {
|
||||||
|
backgroundColor: alpha("#181818", 0.98),
|
||||||
|
borderRadius: 2,
|
||||||
|
width: '90%',
|
||||||
|
margin: '0 auto',
|
||||||
|
p: 1,
|
||||||
|
backgroundImage: 'none',
|
||||||
|
mb: 1
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
|
||||||
|
<SubtitleManager
|
||||||
|
subtitleBtnRef={subtitleBtnRef}
|
||||||
|
close={closeSubtitleManager}
|
||||||
|
open={true}
|
||||||
|
qortalMetadata={qortalVideoResource}
|
||||||
|
onSelect={onSelectSubtitle}
|
||||||
|
currentSubTrack={currentSubTrack}
|
||||||
|
setDrawerOpenSubtitles={setDrawerOpenSubtitles}
|
||||||
|
isFromDrawer={true}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</Drawer>
|
||||||
|
<Drawer anchor="bottom" open={drawerOpenPlayback} onClose={() => setDrawerOpenPlayback(false)} sx={{
|
||||||
|
|
||||||
|
}} slotProps={{
|
||||||
|
paper: {
|
||||||
|
sx: {
|
||||||
|
backgroundColor: alpha("#181818", 0.98),
|
||||||
|
borderRadius: 2,
|
||||||
|
width: '90%',
|
||||||
|
margin: '0 auto',
|
||||||
|
p: 1,
|
||||||
|
backgroundImage: 'none',
|
||||||
|
mb: 1
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
|
||||||
|
<PlayBackMenu isFromDrawer close={closePlaybackMenu} isOpen={true} onSelect={onSelectPlaybackRate} playbackRate={playbackRate} />
|
||||||
|
|
||||||
|
</Drawer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -18,6 +18,7 @@ import { GlobalPipPlayer } from "../hooks/useGlobalPipPlayer";
|
|||||||
import { Location, NavigateFunction } from "react-router-dom";
|
import { Location, NavigateFunction } from "react-router-dom";
|
||||||
import { MultiPublishDialog } from "../components/MultiPublish/MultiPublishDialog";
|
import { MultiPublishDialog } from "../components/MultiPublish/MultiPublishDialog";
|
||||||
import { useMultiplePublishStore } from "../state/multiplePublish";
|
import { useMultiplePublishStore } from "../state/multiplePublish";
|
||||||
|
import { useGlobalPlayerStore } from "../state/pip";
|
||||||
|
|
||||||
// ✅ Define Global Context Type
|
// ✅ Define Global Context Type
|
||||||
interface GlobalContextType {
|
interface GlobalContextType {
|
||||||
@ -62,7 +63,7 @@ export const GlobalProvider = ({
|
|||||||
// ✅ Call hooks and pass in options dynamically
|
// ✅ Call hooks and pass in options dynamically
|
||||||
const auth = useAuth(config?.auth || {});
|
const auth = useAuth(config?.auth || {});
|
||||||
const isPublishing = useMultiplePublishStore((s)=> s.isPublishing);
|
const isPublishing = useMultiplePublishStore((s)=> s.isPublishing);
|
||||||
|
const videoSrc = useGlobalPlayerStore((s)=> s.videoSrc);
|
||||||
const appInfo = useAppInfo(config.appName, config?.publicSalt);
|
const appInfo = useAppInfo(config.appName, config?.publicSalt);
|
||||||
const lists = useResources();
|
const lists = useResources();
|
||||||
const identifierOperations = useIdentifiers(
|
const identifierOperations = useIdentifiers(
|
||||||
@ -97,7 +98,8 @@ export const GlobalProvider = ({
|
|||||||
<LocationContext.Provider value={location}>
|
<LocationContext.Provider value={location}>
|
||||||
|
|
||||||
<GlobalContext.Provider value={contextValue}>
|
<GlobalContext.Provider value={contextValue}>
|
||||||
<GlobalPipPlayer />
|
<GlobalPipPlayer />
|
||||||
|
|
||||||
{isPublishing && (
|
{isPublishing && (
|
||||||
<MultiPublishDialog />
|
<MultiPublishDialog />
|
||||||
)}
|
)}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { AddForeignServerQortalRequest, AddListItemsQortalRequest, BuyNameQortalRequest, CancelSellNameQortalRequest, CancelTradeSellOrderQortalRequest, CreatePollQortalRequest, CreateTradeBuyOrderQortalRequest, CreateTradeSellOrderQortalRequest, DecryptDataQortalRequest, DecryptDataWithSharingKeyQortalRequest, DecryptQortalGroupDataQortalRequest, DeleteHostedDataQortalRequest, DeleteListItemQortalRequest, EncryptDataQortalRequest, EncryptDataWithSharingKeyQortalRequest, EncryptQortalGroupDataQortalRequest, FetchQdnResourceQortalRequest, GetAccountDataQortalRequest, GetAccountNamesQortalRequest, GetBalanceQortalRequest, GetCrosschainServerInfoQortalRequest, GetDaySummaryQortalRequest, GetForeignFeeQortalRequest, GetHostedDataQortalRequest, GetListItemsQortalRequest, GetNameDataQortalRequest, GetPriceQortalRequest, GetQdnResourceMetadataQortalRequest, GetQdnResourcePropertiesQortalRequest, GetQdnResourceStatusQortalRequest, GetQdnResourceUrlQortalRequest, GetServerConnectionHistoryQortalRequest, GetTxActivitySummaryQortalRequest, GetUserAccountQortalRequest, GetUserWalletInfoQortalRequest, GetUserWalletQortalRequest, GetWalletBalanceQortalRequest, LinkToQdnResourceQortalRequest, ListQdnResourcesQortalRequest, PublishMultipleQdnResourcesQortalRequest, PublishQdnResourceQortalRequest, RegisterNameQortalRequest, RemoveForeignServerQortalRequest, SearchNamesQortalRequest, SearchQdnResourcesQortalRequest, SellNameQortalRequest, SendCoinQortalRequest, SetCurrentForeignServerQortalRequest, UpdateForeignFeeQortalRequest, UpdateNameQortalRequest, VoteOnPollQortalRequest, SendChatMessageQortalRequest, SearchChatMessagesQortalRequest, JoinGroupQortalRequest, AddGroupAdminQortalRequest, UpdateGroupQortalRequest, ListGroupsQortalRequest, CreateGroupQortalRequest, RemoveGroupAdminQortalRequest, BanFromGroupQortalRequest, CancelGroupBanQortalRequest, KickFromGroupQortalRequest, InviteToGroupQortalRequest, CancelGroupInviteQortalRequest, LeaveGroupQortalRequest, DeployAtQortalRequest, GetAtQortalRequest, GetAtDataQortalRequest, ListAtsQortalRequest, FetchBlockQortalRequest, FetchBlockRangeQortalRequest, SearchTransactionsQortalRequest, IsUsingPublicNodeQortalRequest, AdminActionQortalRequest, OpenNewTabQortalRequest, ShowActionsQortalRequest, SignTransactionQortalRequest, CreateAndCopyEmbedLinkQortalRequest, TransferAssetQortalRequest, ShowPdfReaderQortalRequest, SaveFileQortalRequest, GetPrimaryNameQortalRequest, } from "./types/qortalRequests/interfaces"
|
import { AddForeignServerQortalRequest, AddListItemsQortalRequest, BuyNameQortalRequest, CancelSellNameQortalRequest, CancelTradeSellOrderQortalRequest, CreatePollQortalRequest, CreateTradeBuyOrderQortalRequest, CreateTradeSellOrderQortalRequest, DecryptDataQortalRequest, DecryptDataWithSharingKeyQortalRequest, DecryptQortalGroupDataQortalRequest, DeleteHostedDataQortalRequest, DeleteListItemQortalRequest, EncryptDataQortalRequest, EncryptDataWithSharingKeyQortalRequest, EncryptQortalGroupDataQortalRequest, FetchQdnResourceQortalRequest, GetAccountDataQortalRequest, GetAccountNamesQortalRequest, GetBalanceQortalRequest, GetCrosschainServerInfoQortalRequest, GetDaySummaryQortalRequest, GetForeignFeeQortalRequest, GetHostedDataQortalRequest, GetListItemsQortalRequest, GetNameDataQortalRequest, GetPriceQortalRequest, GetQdnResourceMetadataQortalRequest, GetQdnResourcePropertiesQortalRequest, GetQdnResourceStatusQortalRequest, GetQdnResourceUrlQortalRequest, GetServerConnectionHistoryQortalRequest, GetTxActivitySummaryQortalRequest, GetUserAccountQortalRequest, GetUserWalletInfoQortalRequest, GetUserWalletQortalRequest, GetWalletBalanceQortalRequest, LinkToQdnResourceQortalRequest, ListQdnResourcesQortalRequest, PublishMultipleQdnResourcesQortalRequest, PublishQdnResourceQortalRequest, RegisterNameQortalRequest, RemoveForeignServerQortalRequest, SearchNamesQortalRequest, SearchQdnResourcesQortalRequest, SellNameQortalRequest, SendCoinQortalRequest, SetCurrentForeignServerQortalRequest, UpdateForeignFeeQortalRequest, UpdateNameQortalRequest, VoteOnPollQortalRequest, SendChatMessageQortalRequest, SearchChatMessagesQortalRequest, JoinGroupQortalRequest, AddGroupAdminQortalRequest, UpdateGroupQortalRequest, ListGroupsQortalRequest, CreateGroupQortalRequest, RemoveGroupAdminQortalRequest, BanFromGroupQortalRequest, CancelGroupBanQortalRequest, KickFromGroupQortalRequest, InviteToGroupQortalRequest, CancelGroupInviteQortalRequest, LeaveGroupQortalRequest, DeployAtQortalRequest, GetAtQortalRequest, GetAtDataQortalRequest, ListAtsQortalRequest, FetchBlockQortalRequest, FetchBlockRangeQortalRequest, SearchTransactionsQortalRequest, IsUsingPublicNodeQortalRequest, AdminActionQortalRequest, OpenNewTabQortalRequest, ShowActionsQortalRequest, SignTransactionQortalRequest, CreateAndCopyEmbedLinkQortalRequest, TransferAssetQortalRequest, ShowPdfReaderQortalRequest, SaveFileQortalRequest, GetPrimaryNameQortalRequest, ScreenOrientation, GetNodeStatusQortalRequest, GetNodeInfoQortalRequest, } from "./types/qortalRequests/interfaces"
|
||||||
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@ -84,7 +84,7 @@ declare global {
|
|||||||
CreateAndCopyEmbedLinkQortalRequest |
|
CreateAndCopyEmbedLinkQortalRequest |
|
||||||
TransferAssetQortalRequest |
|
TransferAssetQortalRequest |
|
||||||
ShowPdfReaderQortalRequest |
|
ShowPdfReaderQortalRequest |
|
||||||
SaveFileQortalRequest | GetPrimaryNameQortalRequest
|
SaveFileQortalRequest | GetPrimaryNameQortalRequest | ScreenOrientation | GetNodeStatusQortalRequest | GetNodeInfoQortalRequest;
|
||||||
|
|
||||||
|
|
||||||
function qortalRequest(options: QortalRequestOptions): Promise<any>
|
function qortalRequest(options: QortalRequestOptions): Promise<any>
|
||||||
|
@ -1,46 +1,65 @@
|
|||||||
// GlobalVideoPlayer.tsx
|
// GlobalVideoPlayer.tsx
|
||||||
import videojs from 'video.js';
|
import videojs from "video.js";
|
||||||
import { useGlobalPlayerStore } from '../state/pip';
|
import { useGlobalPlayerStore } from "../state/pip";
|
||||||
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
import { useCallback, useContext, useEffect, useRef, useState } from "react";
|
||||||
import { Box, IconButton } from '@mui/material';
|
import { Box, IconButton } from "@mui/material";
|
||||||
import { VideoContainer } from '../components/VideoPlayer/VideoPlayer-styles';
|
import { VideoContainer } from "../components/VideoPlayer/VideoPlayer-styles";
|
||||||
import { Rnd } from "react-rnd";
|
import { Rnd } from "react-rnd";
|
||||||
import { useProgressStore } from '../state/video';
|
import { useProgressStore } from "../state/video";
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
|
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
|
||||||
import PauseIcon from '@mui/icons-material/Pause';
|
import PauseIcon from "@mui/icons-material/Pause";
|
||||||
import OpenInFullIcon from '@mui/icons-material/OpenInFull';
|
import OpenInFullIcon from "@mui/icons-material/OpenInFull";
|
||||||
import { GlobalContext } from '../context/GlobalProvider';
|
import { GlobalContext } from "../context/GlobalProvider";
|
||||||
|
import { isTouchDevice } from "../components/VideoPlayer/VideoPlayer";
|
||||||
export const GlobalPipPlayer = () => {
|
export const GlobalPipPlayer = () => {
|
||||||
const { videoSrc, reset, isPlaying, location, type, currentTime, mode, videoId } = useGlobalPlayerStore();
|
const {
|
||||||
const [playing , setPlaying] = useState(false)
|
videoSrc,
|
||||||
const [hasStarted, setHasStarted] = useState(false)
|
reset,
|
||||||
|
isPlaying,
|
||||||
|
location,
|
||||||
|
type,
|
||||||
|
currentTime,
|
||||||
|
mode,
|
||||||
|
videoId,
|
||||||
|
} = useGlobalPlayerStore();
|
||||||
|
const [playing, setPlaying] = useState(false);
|
||||||
|
const [hasStarted, setHasStarted] = useState(false);
|
||||||
const playerRef = useRef<any>(null);
|
const playerRef = useRef<any>(null);
|
||||||
const context = useContext(GlobalContext)
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||||
const navigate = context?.navigate
|
|
||||||
const videoNode = useRef<HTMLVideoElement>(null);
|
|
||||||
const { setProgress } = useProgressStore();
|
|
||||||
|
|
||||||
const updateProgress = useCallback(() => {
|
const context = useContext(GlobalContext);
|
||||||
const player = playerRef?.current;
|
const navigate = context?.navigate;
|
||||||
if (!player || typeof player?.currentTime !== "function") return;
|
const videoNode = useRef<HTMLVideoElement>(null);
|
||||||
|
const hideTimeoutRef = useRef<number | null>(null);
|
||||||
const currentTime = player.currentTime();
|
const { setProgress } = useProgressStore();
|
||||||
if (typeof currentTime === "number" && videoId && currentTime > 0.1) {
|
|
||||||
setProgress(videoId, currentTime);
|
const updateProgress = useCallback(() => {
|
||||||
}
|
const player = playerRef?.current;
|
||||||
}, [videoId]);
|
if (!player || typeof player?.currentTime !== "function") return;
|
||||||
|
|
||||||
const rndRef = useRef<any>(null)
|
const currentTime = player.currentTime();
|
||||||
|
if (typeof currentTime === "number" && videoId && currentTime > 0.1) {
|
||||||
|
setProgress(videoId, currentTime);
|
||||||
|
}
|
||||||
|
}, [videoId]);
|
||||||
|
|
||||||
|
const rndRef = useRef<any>(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!playerRef.current && videoNode.current) {
|
if (!playerRef.current && videoNode.current) {
|
||||||
playerRef.current = videojs(videoNode.current, { autoplay: true, controls: false,
|
playerRef.current = videojs(videoNode.current, {
|
||||||
responsive: true, fluid: true });
|
autoplay: true,
|
||||||
|
controls: false,
|
||||||
|
responsive: true,
|
||||||
|
fluid: true,
|
||||||
|
});
|
||||||
|
playerRef.current?.on("error", () => {
|
||||||
|
// Optional: display user-friendly message
|
||||||
|
});
|
||||||
|
|
||||||
// Resume playback if needed
|
// Resume playback if needed
|
||||||
playerRef.current.on('ready', () => {
|
playerRef.current.on("ready", () => {
|
||||||
if (videoSrc) {
|
if (videoSrc) {
|
||||||
|
|
||||||
playerRef.current.src(videoSrc);
|
playerRef.current.src(videoSrc);
|
||||||
playerRef.current.currentTime(currentTime);
|
playerRef.current.currentTime(currentTime);
|
||||||
if (isPlaying) playerRef.current.play();
|
if (isPlaying) playerRef.current.play();
|
||||||
@ -53,181 +72,216 @@ export const GlobalPipPlayer = () => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(()=> {
|
|
||||||
if(!videoSrc){
|
|
||||||
setHasStarted(false)
|
|
||||||
}
|
|
||||||
}, [videoSrc])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const player = playerRef.current;
|
|
||||||
|
|
||||||
if (!player) return;
|
|
||||||
|
|
||||||
if (!videoSrc && player.src) {
|
|
||||||
// Only pause the player and unload the source without re-triggering playback
|
|
||||||
player.pause();
|
|
||||||
|
|
||||||
// Remove the video source safely
|
|
||||||
const tech = player.tech({ IWillNotUseThisInPlugins: true });
|
|
||||||
if (tech && tech.el_) {
|
|
||||||
tech.setAttribute('src', '');
|
|
||||||
setPlaying(false)
|
|
||||||
setHasStarted(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optionally clear the poster and currentTime
|
|
||||||
player.poster('');
|
|
||||||
player.currentTime(0);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(videoSrc){
|
|
||||||
// Set source and resume if needed
|
|
||||||
player.src({ src: videoSrc, type: type });
|
|
||||||
player.currentTime(currentTime);
|
|
||||||
|
|
||||||
if (isPlaying) {
|
|
||||||
const playPromise = player.play();
|
|
||||||
|
|
||||||
|
|
||||||
if (playPromise?.catch) {
|
|
||||||
playPromise.catch((err: any) => {
|
|
||||||
console.warn('Unable to autoplay:', err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
player.pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [videoSrc, type, isPlaying, currentTime]);
|
|
||||||
|
|
||||||
|
|
||||||
// const onDragStart = () => {
|
|
||||||
// timer = Date.now();
|
|
||||||
// isDragging.current = true;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const handleStopDrag = async () => {
|
|
||||||
// const time = Date.now();
|
|
||||||
// if (timer && time - timer < 300) {
|
|
||||||
// isDragging.current = false;
|
|
||||||
// } else {
|
|
||||||
// isDragging.current = true;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// const onDragStop = () => {
|
|
||||||
// handleStopDrag();
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const checkIfDrag = useCallback(() => {
|
|
||||||
// return isDragging.current;
|
|
||||||
// }, []);
|
|
||||||
const margin = 50;
|
|
||||||
|
|
||||||
|
|
||||||
const [height, setHeight] = useState(300)
|
|
||||||
const [width, setWidth] = useState(400)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!videoSrc) {
|
||||||
rndRef.current.updatePosition({
|
setHasStarted(false);
|
||||||
x: window.innerWidth - (width || 400) - margin,
|
}
|
||||||
y: window.innerHeight - (height || 300) - margin,
|
|
||||||
width: width || 400,
|
|
||||||
height: height || 300
|
|
||||||
});
|
|
||||||
}, [videoSrc]);
|
}, [videoSrc]);
|
||||||
|
|
||||||
const [showControls, setShowControls] = useState(false)
|
useEffect(() => {
|
||||||
|
const player = playerRef.current;
|
||||||
|
|
||||||
const handleMouseMove = () => {
|
if (!player) return;
|
||||||
setShowControls(true)
|
|
||||||
|
if (!videoSrc && player.src) {
|
||||||
|
// Only pause the player and unload the source without re-triggering playback
|
||||||
|
player.pause();
|
||||||
|
|
||||||
|
|
||||||
|
// player.src({ src: '', type: '' }); // ⬅️ this is the safe way to clear it
|
||||||
|
|
||||||
|
|
||||||
|
setPlaying(false);
|
||||||
|
setHasStarted(false);
|
||||||
|
|
||||||
|
// Optionally clear the poster and currentTime
|
||||||
|
player.poster("");
|
||||||
|
player.currentTime(0);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (videoSrc) {
|
||||||
|
// Set source and resume if needed
|
||||||
|
player.src({ src: videoSrc, type: type });
|
||||||
|
player.currentTime(currentTime);
|
||||||
|
|
||||||
|
if (isPlaying) {
|
||||||
|
const playPromise = player.play();
|
||||||
|
|
||||||
|
if (playPromise?.catch) {
|
||||||
|
playPromise.catch((err: any) => {
|
||||||
|
console.warn("Unable to autoplay:", err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
player.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [videoSrc, type, isPlaying, currentTime]);
|
||||||
|
|
||||||
|
// const onDragStart = () => {
|
||||||
|
// timer = Date.now();
|
||||||
|
// isDragging.current = true;
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const handleStopDrag = async () => {
|
||||||
|
// const time = Date.now();
|
||||||
|
// if (timer && time - timer < 300) {
|
||||||
|
// isDragging.current = false;
|
||||||
|
// } else {
|
||||||
|
// isDragging.current = true;
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// const onDragStop = () => {
|
||||||
|
// handleStopDrag();
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const checkIfDrag = useCallback(() => {
|
||||||
|
// return isDragging.current;
|
||||||
|
// }, []);
|
||||||
|
const margin = 50;
|
||||||
|
|
||||||
|
const [height, setHeight] = useState(300);
|
||||||
|
const [width, setWidth] = useState(400);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!videoSrc) return;
|
||||||
|
|
||||||
|
const screenWidth = window.innerWidth;
|
||||||
|
const screenHeight = window.innerHeight;
|
||||||
|
const aspectRatio = 0.75; // 300 / 400 = 3:4
|
||||||
|
|
||||||
|
const maxWidthByScreen = screenWidth * 0.75;
|
||||||
|
const maxWidthByHeight = (screenHeight * 0.2) / aspectRatio;
|
||||||
|
|
||||||
|
const maxWidth = Math.min(maxWidthByScreen, maxWidthByHeight);
|
||||||
|
const maxHeight = maxWidth * aspectRatio;
|
||||||
|
|
||||||
|
setWidth(maxWidth);
|
||||||
|
setHeight(maxHeight);
|
||||||
|
|
||||||
|
rndRef.current.updatePosition({
|
||||||
|
x: screenWidth - maxWidth - margin,
|
||||||
|
y: screenHeight - maxHeight - margin,
|
||||||
|
width: maxWidth,
|
||||||
|
height: maxHeight,
|
||||||
|
});
|
||||||
|
}, [videoSrc]);
|
||||||
|
|
||||||
|
const [showControls, setShowControls] = useState(false);
|
||||||
|
|
||||||
|
const handleMouseMove = () => {
|
||||||
|
if (isTouchDevice) return;
|
||||||
|
setShowControls(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseLeave = () => {
|
const handleMouseLeave = () => {
|
||||||
|
if (isTouchDevice) return;
|
||||||
setShowControls(false);
|
setShowControls(false);
|
||||||
};
|
};
|
||||||
const startPlay = useCallback(() => {
|
const startPlay = useCallback(() => {
|
||||||
try {
|
try {
|
||||||
|
const player = playerRef.current;
|
||||||
const player = playerRef.current;
|
if (!player) return;
|
||||||
if (!player) return;
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
player.play();
|
player.play();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('Play failed:', err);
|
console.warn("Play failed:", err);
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
} catch (error) {
|
console.error("togglePlay", error);
|
||||||
console.error('togglePlay', error)
|
}
|
||||||
}
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const stopPlay = useCallback(() => {
|
const stopPlay = useCallback(() => {
|
||||||
const player = playerRef.current;
|
const player = playerRef.current;
|
||||||
if (!player) return;
|
if (!player) return;
|
||||||
|
|
||||||
try {
|
|
||||||
player.pause();
|
|
||||||
} catch (err) {
|
|
||||||
console.warn('Play failed:', err);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
player.pause();
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("Play failed:", err);
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onPlayHandlerStart = useCallback(() => {
|
const onPlayHandlerStart = useCallback(() => {
|
||||||
setPlaying(true)
|
setPlaying(true);
|
||||||
setHasStarted(true)
|
setHasStarted(true);
|
||||||
}, [setPlaying]);
|
}, [setPlaying]);
|
||||||
const onPlayHandlerStop = useCallback(() => {
|
const onPlayHandlerStop = useCallback(() => {
|
||||||
setPlaying(false)
|
setPlaying(false);
|
||||||
}, [setPlaying]);
|
}, [setPlaying]);
|
||||||
|
|
||||||
|
const resetHideTimeout = () => {
|
||||||
|
setShowControls(true);
|
||||||
|
if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
|
||||||
|
hideTimeoutRef.current = setTimeout(() => {
|
||||||
|
setShowControls(false);
|
||||||
|
}, 3000);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const container = containerRef.current;
|
||||||
|
if (!videoSrc || !container) return;
|
||||||
|
|
||||||
|
const handleInteraction = () => {
|
||||||
|
console.log("Touchstart detected!");
|
||||||
|
resetHideTimeout();
|
||||||
|
};
|
||||||
|
|
||||||
|
container.addEventListener("touchstart", handleInteraction, {
|
||||||
|
passive: true,
|
||||||
|
capture: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
container.removeEventListener("touchstart", handleInteraction, {
|
||||||
|
capture: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}, [videoSrc]);
|
||||||
|
|
||||||
|
console.log("showControls", showControls);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Rnd
|
<Rnd
|
||||||
enableResizing={{
|
enableResizing={{
|
||||||
top: false,
|
top: false,
|
||||||
right: false,
|
right: false,
|
||||||
bottom: false,
|
bottom: false,
|
||||||
left: false,
|
left: false,
|
||||||
topRight: true,
|
topRight: true,
|
||||||
bottomLeft: true,
|
bottomLeft: true,
|
||||||
topLeft: true,
|
topLeft: true,
|
||||||
bottomRight: true,
|
bottomRight: true,
|
||||||
}}
|
}}
|
||||||
|
ref={rndRef}
|
||||||
|
// onDragStart={onDragStart}
|
||||||
|
// onDragStop={onDragStop}
|
||||||
|
style={{
|
||||||
|
display: hasStarted ? "block" : "none",
|
||||||
|
position: "fixed",
|
||||||
|
zIndex: 999999999,
|
||||||
|
|
||||||
ref={rndRef}
|
cursor: "default",
|
||||||
// onDragStart={onDragStart}
|
}}
|
||||||
// onDragStop={onDragStop}
|
size={{ width, height }}
|
||||||
style={{
|
onResize={(e, direction, ref, delta, position) => {
|
||||||
display: hasStarted ? "block" : "none",
|
setWidth(ref.offsetWidth);
|
||||||
position: "fixed",
|
setHeight(ref.offsetHeight);
|
||||||
zIndex: 999999999,
|
}}
|
||||||
|
// default={{
|
||||||
cursor: 'default'
|
// x: 500,
|
||||||
}}
|
// y: 500,
|
||||||
size={{ width, height }}
|
// width: 350,
|
||||||
onResize={(e, direction, ref, delta, position) => {
|
// height: "auto",
|
||||||
setWidth(ref.offsetWidth);
|
// }}
|
||||||
setHeight(ref.offsetHeight);
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
}}
|
onDrag={() => {}}
|
||||||
|
>
|
||||||
// default={{
|
{/* <div
|
||||||
// x: 500,
|
|
||||||
// y: 500,
|
|
||||||
// width: 350,
|
|
||||||
// height: "auto",
|
|
||||||
// }}
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
||||||
onDrag={() => {}}
|
|
||||||
>
|
|
||||||
{/* <div
|
|
||||||
style={{
|
style={{
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
bottom: '20px',
|
bottom: '20px',
|
||||||
@ -238,90 +292,135 @@ const margin = 50;
|
|||||||
display: videoSrc ? 'block' : 'none'
|
display: videoSrc ? 'block' : 'none'
|
||||||
}}
|
}}
|
||||||
> */}
|
> */}
|
||||||
<Box sx={{height, width, position: 'relative' , background: 'black', overflow: 'hidden', borderRadius: '10px' }} onMouseMove={handleMouseMove}
|
<Box
|
||||||
onMouseLeave={handleMouseLeave}>
|
ref={containerRef}
|
||||||
{/* {backgroundColor: showControls ? 'rgba(0,0,0,.5)' : 'unset'} */}
|
sx={{
|
||||||
{showControls && (
|
height,
|
||||||
<Box sx={{
|
pointerEvents: "auto",
|
||||||
position: 'absolute',
|
width,
|
||||||
top: 0, bottom: 0, left: 0, right: 0,
|
position: "relative",
|
||||||
zIndex: 1,
|
background: "black",
|
||||||
opacity: 0,
|
overflow: "hidden",
|
||||||
transition: 'opacity 1s',
|
borderRadius: "10px",
|
||||||
"&:hover": {
|
}}
|
||||||
opacity: 1
|
onMouseMove={handleMouseMove}
|
||||||
}
|
onMouseLeave={handleMouseLeave}
|
||||||
}}>
|
>
|
||||||
<Box sx={{
|
{/* {backgroundColor: showControls ? 'rgba(0,0,0,.5)' : 'unset'} */}
|
||||||
position: 'absolute',
|
{showControls && (
|
||||||
background: 'rgba(0,0,0,.5)',
|
<Box
|
||||||
top: 0, bottom: 0, left: 0, right: 0,
|
sx={{
|
||||||
zIndex: 1,
|
position: "absolute",
|
||||||
opacity: 0,
|
top: 0,
|
||||||
transition: 'opacity 1s',
|
bottom: 0,
|
||||||
"&:hover": {
|
left: 0,
|
||||||
opacity: 1
|
right: 0,
|
||||||
}
|
zIndex: 1,
|
||||||
}} />
|
opacity: showControls ? 1 : 0,
|
||||||
<IconButton sx={{
|
pointerEvents: showControls ? "auto" : "none",
|
||||||
position: 'absolute',
|
transition: "opacity 0.5s ease-in-out",
|
||||||
top: 10,
|
}}
|
||||||
opacity: 1,
|
>
|
||||||
right: 10,
|
<Box
|
||||||
zIndex: 2,
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
}} onClick={reset}><CloseIcon /></IconButton>
|
background: "rgba(0,0,0,.5)",
|
||||||
{location && (
|
top: 0,
|
||||||
<IconButton sx={{
|
bottom: 0,
|
||||||
position: 'absolute',
|
left: 0,
|
||||||
top: 10,
|
right: 0,
|
||||||
left: 10,
|
zIndex: 1,
|
||||||
zIndex: 2,
|
opacity: showControls ? 1 : 0,
|
||||||
opacity: 1,
|
pointerEvents: showControls ? "auto" : "none",
|
||||||
|
transition: "opacity 0.5s ease-in-out",
|
||||||
}} onClick={()=> {
|
}}
|
||||||
if(navigate){
|
/>
|
||||||
navigate(location)
|
<IconButton
|
||||||
}
|
sx={{
|
||||||
}}><OpenInFullIcon /></IconButton>
|
position: "absolute",
|
||||||
)}
|
top: 10,
|
||||||
{playing && (
|
opacity: 1,
|
||||||
<IconButton sx={{
|
right: 10,
|
||||||
position: 'absolute',
|
zIndex: 2,
|
||||||
top: '50%',
|
}}
|
||||||
left: '50%',
|
onClick={reset}
|
||||||
transform: 'translate(-50%, -50%)',
|
onTouchStart={reset}
|
||||||
opacity: 1,
|
>
|
||||||
zIndex: 2,
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
}} onClick={stopPlay}><PauseIcon /></IconButton>
|
{location && (
|
||||||
)}
|
<IconButton
|
||||||
{!playing && (
|
sx={{
|
||||||
<IconButton sx={{
|
position: "absolute",
|
||||||
position: 'absolute',
|
top: 10,
|
||||||
opacity: 1,
|
left: 10,
|
||||||
top: '50%',
|
zIndex: 2,
|
||||||
left: '50%',
|
opacity: 1,
|
||||||
transform: 'translate(-50%, -50%)',
|
}}
|
||||||
zIndex: 2,
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
}} onClick={startPlay}><PlayArrowIcon /></IconButton>
|
if (navigate) {
|
||||||
)}
|
navigate(location);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onTouchStart={(e) => {
|
||||||
<Box/>
|
e.stopPropagation()
|
||||||
</Box>
|
if (navigate) {
|
||||||
|
navigate(location);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<OpenInFullIcon />
|
||||||
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
|
{playing && (
|
||||||
|
<IconButton
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
top: "50%",
|
||||||
|
left: "50%",
|
||||||
|
transform: "translate(-50%, -50%)",
|
||||||
|
opacity: 1,
|
||||||
|
zIndex: 2,
|
||||||
|
}}
|
||||||
|
onClick={stopPlay}
|
||||||
|
onTouchStart={stopPlay}
|
||||||
|
>
|
||||||
|
<PauseIcon />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
{!playing && (
|
||||||
|
<IconButton
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
opacity: 1,
|
||||||
|
top: "50%",
|
||||||
|
left: "50%",
|
||||||
|
transform: "translate(-50%, -50%)",
|
||||||
|
zIndex: 2,
|
||||||
|
}}
|
||||||
|
onClick={startPlay}
|
||||||
|
onTouchStart={startPlay}
|
||||||
|
>
|
||||||
|
<PlayArrowIcon />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Box />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
<VideoContainer>
|
<VideoContainer>
|
||||||
<video onPlay={onPlayHandlerStart} onPause={onPlayHandlerStop} onTimeUpdate={updateProgress}
|
<video
|
||||||
ref={videoNode} className="video-js" style={{
|
onPlay={onPlayHandlerStart}
|
||||||
|
onPause={onPlayHandlerStop}
|
||||||
|
onTimeUpdate={updateProgress}
|
||||||
}}/>
|
ref={videoNode}
|
||||||
</VideoContainer>
|
className="video-js"
|
||||||
|
style={{}}
|
||||||
|
/>
|
||||||
|
</VideoContainer>
|
||||||
</Box>
|
</Box>
|
||||||
{/* </div> */}
|
{/* </div> */}
|
||||||
</Rnd>
|
</Rnd>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -615,12 +615,29 @@ export interface ShowActionsQortalRequest extends BaseRequest {
|
|||||||
action: 'SHOW_ACTIONS'
|
action: 'SHOW_ACTIONS'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ScreenOrientation extends BaseRequest {
|
||||||
|
action: 'SCREEN_ORIENTATION',
|
||||||
|
mode: | "portrait"
|
||||||
|
| "landscape"
|
||||||
|
| "portrait-primary"
|
||||||
|
| "portrait-secondary"
|
||||||
|
| "landscape-primary"
|
||||||
|
| "landscape-secondary" | "unlock";
|
||||||
|
}
|
||||||
|
|
||||||
export interface SignTransactionQortalRequest extends BaseRequest {
|
export interface SignTransactionQortalRequest extends BaseRequest {
|
||||||
action: 'SIGN_TRANSACTION'
|
action: 'SIGN_TRANSACTION'
|
||||||
unsignedBytes: string
|
unsignedBytes: string
|
||||||
process?: boolean
|
process?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GetNodeStatusQortalRequest extends BaseRequest {
|
||||||
|
action: 'GET_NODE_STATUS'
|
||||||
|
}
|
||||||
|
export interface GetNodeInfoQortalRequest extends BaseRequest {
|
||||||
|
action: 'GET_NODE_INFO'
|
||||||
|
}
|
||||||
|
|
||||||
export interface CreateAndCopyEmbedLinkQortalRequest extends BaseRequest {
|
export interface CreateAndCopyEmbedLinkQortalRequest extends BaseRequest {
|
||||||
action: 'CREATE_AND_COPY_EMBED_LINK'
|
action: 'CREATE_AND_COPY_EMBED_LINK'
|
||||||
type: string
|
type: string
|
||||||
|
Loading…
x
Reference in New Issue
Block a user