mirror of
https://github.com/Qortal/qapp-core.git
synced 2025-07-13 04:41:27 +00:00
fix mobile options
This commit is contained in:
parent
378ec78c25
commit
8afeb4af7b
@ -21,6 +21,7 @@ interface MobileControlsProps {
|
|||||||
openPlaybackMenu: () => void;
|
openPlaybackMenu: () => void;
|
||||||
toggleFullscreen: () => void;
|
toggleFullscreen: () => void;
|
||||||
setProgressRelative: (val: number) => void;
|
setProgressRelative: (val: number) => void;
|
||||||
|
setLocalProgress: (val: number)=> void;
|
||||||
}
|
}
|
||||||
export const MobileControls = ({
|
export const MobileControls = ({
|
||||||
showControlsMobile,
|
showControlsMobile,
|
||||||
@ -34,6 +35,7 @@ export const MobileControls = ({
|
|||||||
openPlaybackMenu,
|
openPlaybackMenu,
|
||||||
toggleFullscreen,
|
toggleFullscreen,
|
||||||
setProgressRelative,
|
setProgressRelative,
|
||||||
|
setLocalProgress
|
||||||
}: MobileControlsProps) => {
|
}: MobileControlsProps) => {
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@ -195,6 +197,7 @@ export const MobileControls = ({
|
|||||||
playerRef={playerRef}
|
playerRef={playerRef}
|
||||||
progress={progress}
|
progress={progress}
|
||||||
duration={duration}
|
duration={duration}
|
||||||
|
setLocalProgress={setLocalProgress}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -65,17 +65,26 @@ export const ReloadButton = ({ reloadVideo, isScreenSmall }: any) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ProgressSlider = ({ progress, duration, playerRef }: any) => {
|
export const ProgressSlider = ({ progress, setLocalProgress, duration, playerRef }: any) => {
|
||||||
const sliderRef = useRef(null);
|
const sliderRef = useRef(null);
|
||||||
|
const [isDragging, setIsDragging] = useState(false);
|
||||||
|
const [sliderValue, setSliderValue] = useState(0); // local slider value
|
||||||
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 = (e: any, value: number | number[]) => {
|
const onProgressChange = (e: any, value: number | number[]) => {
|
||||||
if (!playerRef.current) return;
|
setIsDragging(true);
|
||||||
|
setSliderValue(value as number);
|
||||||
playerRef.current?.currentTime(value as number);
|
|
||||||
};
|
};
|
||||||
|
const onChangeCommitted = (e: any, value: number | number[]) => {
|
||||||
|
if (!playerRef.current) return;
|
||||||
|
setSliderValue(value as number);
|
||||||
|
playerRef.current?.currentTime(value as number);
|
||||||
|
setIsDragging(false);
|
||||||
|
setLocalProgress(value)
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const THUMBNAIL_DEBOUNCE = 500;
|
const THUMBNAIL_DEBOUNCE = 500;
|
||||||
const THUMBNAIL_MIN_DIFF = 10;
|
const THUMBNAIL_MIN_DIFF = 10;
|
||||||
@ -158,8 +167,10 @@ export const ProgressSlider = ({ progress, duration, playerRef }: any) => {
|
|||||||
onMouseMove={handleMouseMove}
|
onMouseMove={handleMouseMove}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
onClickCapture={handleClickCapture}
|
onClickCapture={handleClickCapture}
|
||||||
value={progress}
|
value={isDragging ? sliderValue : progress} // use local state if dragging
|
||||||
|
|
||||||
onChange={onProgressChange}
|
onChange={onProgressChange}
|
||||||
|
onChangeCommitted={onChangeCommitted}
|
||||||
min={0}
|
min={0}
|
||||||
max={duration || 100}
|
max={duration || 100}
|
||||||
step={0.1}
|
step={0.1}
|
||||||
|
@ -43,9 +43,10 @@ interface VideoControlsBarProps {
|
|||||||
openPlaybackMenu: ()=> void
|
openPlaybackMenu: ()=> void
|
||||||
togglePictureInPicture: ()=> void
|
togglePictureInPicture: ()=> void
|
||||||
isVideoPlayerSmall: boolean
|
isVideoPlayerSmall: boolean
|
||||||
|
setLocalProgress: (val: number)=> void
|
||||||
}
|
}
|
||||||
|
|
||||||
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) => {
|
export const VideoControlsBar = ({subtitleBtnRef, setLocalProgress, 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,7 @@ export const VideoControlsBar = ({subtitleBtnRef, showControls, playbackRate, in
|
|||||||
width: '100%'
|
width: '100%'
|
||||||
}}>
|
}}>
|
||||||
|
|
||||||
<ProgressSlider playerRef={playerRef} progress={progress} duration={duration} />
|
<ProgressSlider setLocalProgress={setLocalProgress} playerRef={playerRef} progress={progress} duration={duration} />
|
||||||
{!isVideoPlayerSmall && (
|
{!isVideoPlayerSmall && (
|
||||||
<Box sx={{
|
<Box sx={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
@ -33,7 +33,14 @@ 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 {
|
||||||
|
alpha,
|
||||||
|
Box,
|
||||||
|
ClickAwayListener,
|
||||||
|
Drawer,
|
||||||
|
List,
|
||||||
|
ListItem,
|
||||||
|
} from "@mui/material";
|
||||||
import { MobileControls } from "./MobileControls";
|
import { MobileControls } from "./MobileControls";
|
||||||
|
|
||||||
export async function srtBase64ToVttBlobUrl(
|
export async function srtBase64ToVttBlobUrl(
|
||||||
@ -61,21 +68,21 @@ type StretchVideoType = "contain" | "fill" | "cover" | "none" | "scale-down";
|
|||||||
|
|
||||||
export type TimelineAction =
|
export type TimelineAction =
|
||||||
| {
|
| {
|
||||||
type: 'SEEK';
|
type: "SEEK";
|
||||||
time: number;
|
time: number;
|
||||||
duration: number;
|
duration: number;
|
||||||
label: string;
|
label: string;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
seekToTime: number; // ✅ Required for SEEK
|
seekToTime: number; // ✅ Required for SEEK
|
||||||
placement?: 'TOP-RIGHT' | 'TOP-LEFT' | 'BOTTOM-LEFT' | 'BOTTOM-RIGHT';
|
placement?: "TOP-RIGHT" | "TOP-LEFT" | "BOTTOM-LEFT" | "BOTTOM-RIGHT";
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: 'CUSTOM';
|
type: "CUSTOM";
|
||||||
time: number;
|
time: number;
|
||||||
duration: number;
|
duration: number;
|
||||||
label: string;
|
label: string;
|
||||||
onClick: () => void; // ✅ Required for CUSTOM
|
onClick: () => void; // ✅ Required for CUSTOM
|
||||||
placement?: 'TOP-RIGHT' | 'TOP-LEFT' | 'BOTTOM-LEFT' | 'BOTTOM-RIGHT';
|
placement?: "TOP-RIGHT" | "TOP-LEFT" | "BOTTOM-LEFT" | "BOTTOM-RIGHT";
|
||||||
};
|
};
|
||||||
interface VideoPlayerProps {
|
interface VideoPlayerProps {
|
||||||
qortalVideoResource: QortalGetMetadata;
|
qortalVideoResource: QortalGetMetadata;
|
||||||
@ -84,18 +91,14 @@ interface VideoPlayerProps {
|
|||||||
poster?: string;
|
poster?: string;
|
||||||
autoPlay?: boolean;
|
autoPlay?: boolean;
|
||||||
onEnded?: (e: React.SyntheticEvent<HTMLVideoElement, Event>) => void;
|
onEnded?: (e: React.SyntheticEvent<HTMLVideoElement, Event>) => void;
|
||||||
timelineActions?: TimelineAction[]
|
timelineActions?: TimelineAction[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const videoStyles = {
|
const videoStyles = {
|
||||||
videoContainer: {},
|
videoContainer: {},
|
||||||
video: {},
|
video: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function getVideoMimeTypeFromUrl(
|
async function getVideoMimeTypeFromUrl(
|
||||||
qortalVideoResource: any
|
qortalVideoResource: any
|
||||||
): Promise<string | null> {
|
): Promise<string | null> {
|
||||||
@ -109,8 +112,8 @@ async function getVideoMimeTypeFromUrl(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
export const isTouchDevice =
|
||||||
|
"ontouchstart" in window || navigator.maxTouchPoints > 0;
|
||||||
|
|
||||||
export const VideoPlayer = ({
|
export const VideoPlayer = ({
|
||||||
videoRef,
|
videoRef,
|
||||||
@ -119,21 +122,21 @@ export const VideoPlayer = ({
|
|||||||
poster,
|
poster,
|
||||||
autoPlay,
|
autoPlay,
|
||||||
onEnded,
|
onEnded,
|
||||||
timelineActions
|
timelineActions,
|
||||||
}: VideoPlayerProps) => {
|
}: VideoPlayerProps) => {
|
||||||
const containerRef = useRef<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);
|
const [width, setWidth] = useState(0);
|
||||||
console.log('width',width)
|
console.log("width", width);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const observer = new ResizeObserver(([entry]) => {
|
const observer = new ResizeObserver(([entry]) => {
|
||||||
setWidth(entry.contentRect.width);
|
setWidth(entry.contentRect.width);
|
||||||
});
|
});
|
||||||
if (containerRef.current) observer.observe(containerRef.current);
|
if (containerRef.current) observer.observe(containerRef.current);
|
||||||
return () => observer.disconnect();
|
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,
|
||||||
@ -143,9 +146,9 @@ useEffect(() => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
const playerRef = useRef<Player | null>(null);
|
const playerRef = useRef<Player | null>(null);
|
||||||
const [drawerOpenSubtitles, setDrawerOpenSubtitles] = useState(false)
|
const [drawerOpenSubtitles, setDrawerOpenSubtitles] = useState(false);
|
||||||
const [drawerOpenPlayback, setDrawerOpenPlayback] = useState(false)
|
const [drawerOpenPlayback, setDrawerOpenPlayback] = useState(false);
|
||||||
const [showControlsMobile, setShowControlsMobile] = 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);
|
||||||
@ -156,12 +159,12 @@ useEffect(() => {
|
|||||||
const [showControls, setShowControls] = useState(false);
|
const [showControls, setShowControls] = useState(false);
|
||||||
const [isOpenSubtitleManage, setIsOpenSubtitleManage] = useState(false);
|
const [isOpenSubtitleManage, setIsOpenSubtitleManage] = useState(false);
|
||||||
const subtitleBtnRef = useRef(null);
|
const subtitleBtnRef = useRef(null);
|
||||||
const [currentSubTrack, setCurrentSubTrack] = useState<null | string>(null)
|
const [currentSubTrack, setCurrentSubTrack] = useState<null | string>(null);
|
||||||
const location = useContext(LocationContext)
|
const location = useContext(LocationContext);
|
||||||
|
|
||||||
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 isVideoPlayerSmall = width < 600 || isTouchDevice;
|
||||||
const {
|
const {
|
||||||
reloadVideo,
|
reloadVideo,
|
||||||
togglePlay,
|
togglePlay,
|
||||||
@ -186,7 +189,7 @@ useEffect(() => {
|
|||||||
showControlsFullScreen,
|
showControlsFullScreen,
|
||||||
onSelectPlaybackRate,
|
onSelectPlaybackRate,
|
||||||
seekTo,
|
seekTo,
|
||||||
togglePictureInPicture
|
togglePictureInPicture,
|
||||||
} = useVideoPlayerController({
|
} = useVideoPlayerController({
|
||||||
autoPlay,
|
autoPlay,
|
||||||
playerRef,
|
playerRef,
|
||||||
@ -194,89 +197,84 @@ useEffect(() => {
|
|||||||
retryAttempts,
|
retryAttempts,
|
||||||
isPlayerInitialized,
|
isPlayerInitialized,
|
||||||
isMuted,
|
isMuted,
|
||||||
videoRef
|
videoRef,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(()=> {
|
useEffect(() => {
|
||||||
if(location){
|
if (location) {
|
||||||
locationRef.current = location.pathname
|
locationRef.current = location.pathname;
|
||||||
|
|
||||||
}
|
}
|
||||||
},[location])
|
}, [location]);
|
||||||
|
|
||||||
const { getProgress } = useProgressStore();
|
const { getProgress } = useProgressStore();
|
||||||
|
|
||||||
const enterFullscreen = useCallback(async () => {
|
const enterFullscreen = useCallback(async () => {
|
||||||
const ref = containerRef?.current as HTMLElement | null;
|
const ref = containerRef?.current as HTMLElement | null;
|
||||||
if (!ref || document.fullscreenElement) return;
|
if (!ref || document.fullscreenElement) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Wait for fullscreen to activate
|
// Wait for fullscreen to activate
|
||||||
if (ref.requestFullscreen) {
|
if (ref.requestFullscreen) {
|
||||||
await ref.requestFullscreen();
|
await ref.requestFullscreen();
|
||||||
} else if ((ref as any).webkitRequestFullscreen) {
|
} else if ((ref as any).webkitRequestFullscreen) {
|
||||||
await (ref as any).webkitRequestFullscreen(); // Safari fallback
|
await (ref as any).webkitRequestFullscreen(); // Safari fallback
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
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(() => {
|
// const exitFullscreen = useCallback(() => {
|
||||||
// document?.exitFullscreen();
|
// document?.exitFullscreen();
|
||||||
// }, [isFullscreen]);
|
// }, [isFullscreen]);
|
||||||
|
|
||||||
const exitFullscreen = useCallback(async () => {
|
const exitFullscreen = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
if (document.fullscreenElement) {
|
if (document.fullscreenElement) {
|
||||||
await document.exitFullscreen();
|
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]);
|
||||||
|
|
||||||
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();
|
||||||
}, [isFullscreen]);
|
}, [isFullscreen]);
|
||||||
|
|
||||||
|
|
||||||
const hotkeyHandlers = useMemo(
|
const hotkeyHandlers = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
reloadVideo,
|
reloadVideo,
|
||||||
@ -290,7 +288,7 @@ const enterFullscreen = useCallback(async () => {
|
|||||||
toggleMute,
|
toggleMute,
|
||||||
setProgressAbsolute,
|
setProgressAbsolute,
|
||||||
setAlwaysShowControls,
|
setAlwaysShowControls,
|
||||||
toggleFullscreen
|
toggleFullscreen,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
reloadVideo,
|
reloadVideo,
|
||||||
@ -304,17 +302,17 @@ const enterFullscreen = useCallback(async () => {
|
|||||||
toggleMute,
|
toggleMute,
|
||||||
setProgressAbsolute,
|
setProgressAbsolute,
|
||||||
setAlwaysShowControls,
|
setAlwaysShowControls,
|
||||||
toggleFullscreen
|
toggleFullscreen,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const closeSubtitleManager = useCallback(() => {
|
const closeSubtitleManager = useCallback(() => {
|
||||||
setIsOpenSubtitleManage(false);
|
setIsOpenSubtitleManage(false);
|
||||||
setDrawerOpenSubtitles(false)
|
setDrawerOpenSubtitles(false);
|
||||||
}, []);
|
}, []);
|
||||||
const openSubtitleManager = useCallback(() => {
|
const openSubtitleManager = useCallback(() => {
|
||||||
if(isVideoPlayerSmall){
|
if (isVideoPlayerSmall) {
|
||||||
setDrawerOpenSubtitles(true)
|
setDrawerOpenSubtitles(true);
|
||||||
}
|
}
|
||||||
setIsOpenSubtitleManage(true);
|
setIsOpenSubtitleManage(true);
|
||||||
}, [isVideoPlayerSmall]);
|
}, [isVideoPlayerSmall]);
|
||||||
@ -323,10 +321,10 @@ const enterFullscreen = useCallback(async () => {
|
|||||||
if (!qortalVideoResource) return null;
|
if (!qortalVideoResource) return null;
|
||||||
return `${qortalVideoResource.service}-${qortalVideoResource.name}-${qortalVideoResource.identifier}`;
|
return `${qortalVideoResource.service}-${qortalVideoResource.name}-${qortalVideoResource.identifier}`;
|
||||||
}, [qortalVideoResource]);
|
}, [qortalVideoResource]);
|
||||||
const videoLocationRef = useRef< null | string>(null)
|
const videoLocationRef = useRef<null | string>(null);
|
||||||
useEffect(()=> {
|
useEffect(() => {
|
||||||
videoLocationRef.current = videoLocation
|
videoLocationRef.current = videoLocation;
|
||||||
}, [videoLocation])
|
}, [videoLocation]);
|
||||||
useVideoPlayerHotKeys(hotkeyHandlers);
|
useVideoPlayerHotKeys(hotkeyHandlers);
|
||||||
|
|
||||||
const updateProgress = useCallback(() => {
|
const updateProgress = useCallback(() => {
|
||||||
@ -340,14 +338,14 @@ const videoLocationRef = useRef< null | string>(null)
|
|||||||
}
|
}
|
||||||
}, [videoLocation]);
|
}, [videoLocation]);
|
||||||
|
|
||||||
useEffect(()=> {
|
useEffect(() => {
|
||||||
if(videoLocation){
|
if (videoLocation) {
|
||||||
const vidId = useGlobalPlayerStore.getState().videoId
|
const vidId = useGlobalPlayerStore.getState().videoId;
|
||||||
if(vidId === videoLocation){
|
if (vidId === videoLocation) {
|
||||||
togglePlay()
|
togglePlay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [videoLocation])
|
}, [videoLocation]);
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
// const ref = videoRef as React.RefObject<HTMLVideoElement>;
|
// const ref = videoRef as React.RefObject<HTMLVideoElement>;
|
||||||
// if (!ref.current) return;
|
// if (!ref.current) return;
|
||||||
@ -428,7 +426,6 @@ const videoLocationRef = useRef< null | string>(null)
|
|||||||
};
|
};
|
||||||
}, [isPlayerInitialized]);
|
}, [isPlayerInitialized]);
|
||||||
|
|
||||||
|
|
||||||
const canvasRef = useRef(null);
|
const canvasRef = useRef(null);
|
||||||
const videoRefForCanvas = useRef<any>(null);
|
const videoRefForCanvas = useRef<any>(null);
|
||||||
const extractFrames = useCallback((time: number): void => {
|
const extractFrames = useCallback((time: number): void => {
|
||||||
@ -463,7 +460,7 @@ const videoLocationRef = useRef< null | string>(null)
|
|||||||
const hideTimeout = useRef<any>(null);
|
const hideTimeout = useRef<any>(null);
|
||||||
|
|
||||||
const resetHideTimer = () => {
|
const resetHideTimer = () => {
|
||||||
if(isTouchDevice) return
|
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(() => {
|
||||||
@ -472,24 +469,24 @@ const videoLocationRef = useRef< null | string>(null)
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseMove = () => {
|
const handleMouseMove = () => {
|
||||||
if(isTouchDevice) return
|
if (isTouchDevice) return;
|
||||||
resetHideTimer();
|
resetHideTimer();
|
||||||
};
|
};
|
||||||
|
|
||||||
const closePlaybackMenu = useCallback(()=> {
|
const closePlaybackMenu = useCallback(() => {
|
||||||
setIsOpenPlaybackmenu(false)
|
setIsOpenPlaybackmenu(false);
|
||||||
setDrawerOpenPlayback(false)
|
setDrawerOpenPlayback(false);
|
||||||
}, [])
|
}, []);
|
||||||
const openPlaybackMenu = useCallback(()=> {
|
const openPlaybackMenu = useCallback(() => {
|
||||||
if(isVideoPlayerSmall){
|
if (isVideoPlayerSmall) {
|
||||||
setDrawerOpenPlayback(true)
|
setDrawerOpenPlayback(true);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
setIsOpenPlaybackmenu(true)
|
setIsOpenPlaybackmenu(true);
|
||||||
}, [isVideoPlayerSmall])
|
}, [isVideoPlayerSmall]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(isTouchDevice) return
|
if (isTouchDevice) return;
|
||||||
resetHideTimer(); // initial show
|
resetHideTimer(); // initial show
|
||||||
return () => {
|
return () => {
|
||||||
if (hideTimeout.current) clearTimeout(hideTimeout.current);
|
if (hideTimeout.current) clearTimeout(hideTimeout.current);
|
||||||
@ -510,34 +507,34 @@ setDrawerOpenPlayback(false)
|
|||||||
|
|
||||||
const onSelectSubtitle = useCallback(
|
const onSelectSubtitle = useCallback(
|
||||||
async (subtitle: SubtitlePublishedData) => {
|
async (subtitle: SubtitlePublishedData) => {
|
||||||
if(subtitle === null){
|
if (subtitle === null) {
|
||||||
setCurrentSubTrack(null)
|
setCurrentSubTrack(null);
|
||||||
if (previousSubtitleUrlRef.current) {
|
if (previousSubtitleUrlRef.current) {
|
||||||
URL.revokeObjectURL(previousSubtitleUrlRef.current);
|
URL.revokeObjectURL(previousSubtitleUrlRef.current);
|
||||||
previousSubtitleUrlRef.current = null;
|
previousSubtitleUrlRef.current = null;
|
||||||
}
|
}
|
||||||
const remoteTracksList = playerRef.current?.remoteTextTracks();
|
const remoteTracksList = playerRef.current?.remoteTextTracks();
|
||||||
|
|
||||||
if (remoteTracksList) {
|
if (remoteTracksList) {
|
||||||
const toRemove: TextTrack[] = [];
|
const toRemove: TextTrack[] = [];
|
||||||
|
|
||||||
// Bypass TS restrictions safely
|
// Bypass TS restrictions safely
|
||||||
const list = remoteTracksList as unknown as {
|
const list = remoteTracksList as unknown as {
|
||||||
length: number;
|
length: number;
|
||||||
[index: number]: TextTrack;
|
[index: number]: TextTrack;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (let i = 0; i < list.length; i++) {
|
for (let i = 0; i < list.length; i++) {
|
||||||
const track = list[i];
|
const track = list[i];
|
||||||
if (track) toRemove.push(track);
|
if (track) toRemove.push(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
toRemove.forEach((track) => {
|
||||||
|
playerRef.current?.removeRemoteTextTrack(track);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toRemove.forEach((track) => {
|
return;
|
||||||
playerRef.current?.removeRemoteTextTrack(track);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
const player = playerRef.current;
|
const player = playerRef.current;
|
||||||
if (!player || !subtitle.subtitleData || !subtitle.type) return;
|
if (!player || !subtitle.subtitleData || !subtitle.type) return;
|
||||||
@ -618,7 +615,6 @@ setDrawerOpenPlayback(false)
|
|||||||
(_, i) => (tracksInfo as any)[i]
|
(_, i) => (tracksInfo as any)[i]
|
||||||
);
|
);
|
||||||
for (const track of tracks) {
|
for (const track of tracks) {
|
||||||
|
|
||||||
if (track.kind === "subtitles") {
|
if (track.kind === "subtitles") {
|
||||||
track.mode = "showing"; // force display
|
track.mode = "showing"; // force display
|
||||||
}
|
}
|
||||||
@ -636,23 +632,21 @@ setDrawerOpenPlayback(false)
|
|||||||
return JSON.stringify(qortalVideoResource);
|
return JSON.stringify(qortalVideoResource);
|
||||||
}, [qortalVideoResource]);
|
}, [qortalVideoResource]);
|
||||||
|
|
||||||
|
|
||||||
const savedVideoRef = useRef<HTMLVideoElement | null>(null);
|
const savedVideoRef = useRef<HTMLVideoElement | null>(null);
|
||||||
|
|
||||||
useEffect(()=> {
|
useEffect(() => {
|
||||||
if(startPlay){
|
if (startPlay) {
|
||||||
useGlobalPlayerStore.getState().reset()
|
useGlobalPlayerStore.getState().reset();
|
||||||
|
|
||||||
}
|
}
|
||||||
}, [startPlay])
|
}, [startPlay]);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
// Save the video element while it's still mounted
|
// Save the video element while it's still mounted
|
||||||
const video = videoRef as any
|
const video = videoRef as any;
|
||||||
if (video.current) {
|
if (video.current) {
|
||||||
savedVideoRef.current = video.current;
|
savedVideoRef.current = video.current;
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!resourceUrl || !isReady || !videoLocactionStringified || !startPlay)
|
if (!resourceUrl || !isReady || !videoLocactionStringified || !startPlay)
|
||||||
@ -687,16 +681,15 @@ savedVideoRef.current = video.current;
|
|||||||
playerRef.current = videojs(ref.current, options, () => {
|
playerRef.current = videojs(ref.current, options, () => {
|
||||||
setIsPlayerInitialized(true);
|
setIsPlayerInitialized(true);
|
||||||
ref.current.tabIndex = -1; // Prevents focus entirely
|
ref.current.tabIndex = -1; // Prevents focus entirely
|
||||||
ref.current.style.outline = 'none'; // Backup
|
ref.current.style.outline = "none"; // Backup
|
||||||
playerRef.current?.poster("");
|
playerRef.current?.poster("");
|
||||||
playerRef.current?.playbackRate(playbackRate);
|
playerRef.current?.playbackRate(playbackRate);
|
||||||
playerRef.current?.volume(volume);
|
playerRef.current?.volume(volume);
|
||||||
if(videoLocationRef.current){
|
if (videoLocationRef.current) {
|
||||||
const savedProgress = getProgress(videoLocationRef.current);
|
const savedProgress = getProgress(videoLocationRef.current);
|
||||||
if (typeof savedProgress === "number") {
|
if (typeof savedProgress === "number") {
|
||||||
playerRef.current?.currentTime(savedProgress);
|
playerRef.current?.currentTime(savedProgress);
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
playerRef.current?.play();
|
playerRef.current?.play();
|
||||||
@ -711,20 +704,18 @@ savedVideoRef.current = video.current;
|
|||||||
(_, i) => (tracksInfo as any)[i]
|
(_, i) => (tracksInfo as any)[i]
|
||||||
);
|
);
|
||||||
for (const track of tracks) {
|
for (const track of tracks) {
|
||||||
|
if (track.kind === "subtitles" || track.kind === "captions") {
|
||||||
if (track.kind === 'subtitles' || track.kind === 'captions') {
|
if (track.mode === "showing") {
|
||||||
if (track.mode === 'showing') {
|
activeTrack = track;
|
||||||
activeTrack = track;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeTrack) {
|
if (activeTrack) {
|
||||||
|
setCurrentSubTrack(activeTrack.language || activeTrack.srclang);
|
||||||
setCurrentSubTrack(activeTrack.language || activeTrack.srclang)
|
|
||||||
} else {
|
} else {
|
||||||
setCurrentSubTrack(null)
|
setCurrentSubTrack(null);
|
||||||
console.log("No subtitle is currently showing");
|
console.log("No subtitle is currently showing");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -748,26 +739,26 @@ savedVideoRef.current = video.current;
|
|||||||
console.error("useEffect start player", error);
|
console.error("useEffect start player", error);
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
const video = savedVideoRef as any
|
const video = savedVideoRef as any;
|
||||||
const videoEl = video?.current!;
|
const videoEl = video?.current!;
|
||||||
const player = playerRef.current;
|
const player = playerRef.current;
|
||||||
|
|
||||||
const isPlaying = !player?.paused();
|
const isPlaying = !player?.paused();
|
||||||
|
|
||||||
if (videoEl && isPlaying && videoLocationRef.current) {
|
if (videoEl && isPlaying && videoLocationRef.current) {
|
||||||
const current = player?.currentTime?.();
|
const current = player?.currentTime?.();
|
||||||
const currentSource = player?.currentType();
|
const currentSource = player?.currentType();
|
||||||
|
|
||||||
useGlobalPlayerStore.getState().setVideoState({
|
useGlobalPlayerStore.getState().setVideoState({
|
||||||
videoSrc: videoEl.src,
|
videoSrc: videoEl.src,
|
||||||
currentTime: current ?? 0,
|
currentTime: current ?? 0,
|
||||||
isPlaying: true,
|
isPlaying: true,
|
||||||
mode: 'floating',
|
mode: "floating",
|
||||||
videoId: videoLocationRef.current,
|
videoId: videoLocationRef.current,
|
||||||
location: locationRef.current || "",
|
location: locationRef.current || "",
|
||||||
type: currentSource || 'video/mp4'
|
type: currentSource || "video/mp4",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
canceled = true;
|
canceled = true;
|
||||||
|
|
||||||
@ -800,10 +791,9 @@ savedVideoRef.current = video.current;
|
|||||||
player.off("ratechange", handleRateChange);
|
player.off("ratechange", handleRateChange);
|
||||||
};
|
};
|
||||||
}, [isPlayerInitialized]);
|
}, [isPlayerInitialized]);
|
||||||
const hideTimeoutRef = useRef<number | null>(null);
|
const hideTimeoutRef = useRef<number | null>(null);
|
||||||
|
|
||||||
|
const resetHideTimeout = () => {
|
||||||
const resetHideTimeout = () => {
|
|
||||||
setShowControlsMobile(true);
|
setShowControlsMobile(true);
|
||||||
if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
|
if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
|
||||||
hideTimeoutRef.current = setTimeout(() => {
|
hideTimeoutRef.current = setTimeout(() => {
|
||||||
@ -817,16 +807,16 @@ savedVideoRef.current = video.current;
|
|||||||
const container = containerRef.current;
|
const container = containerRef.current;
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
container.addEventListener('touchstart', handleInteraction);
|
container.addEventListener("touchstart", handleInteraction);
|
||||||
// container.addEventListener('mousemove', handleInteraction);
|
// container.addEventListener('mousemove', handleInteraction);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
container.removeEventListener('touchstart', handleInteraction);
|
container.removeEventListener("touchstart", handleInteraction);
|
||||||
// container.removeEventListener('mousemove', handleInteraction);
|
// container.removeEventListener('mousemove', handleInteraction);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
console.log('showControlsMobile', showControlsMobile)
|
console.log("showControlsMobile", showControlsMobile);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -865,11 +855,17 @@ savedVideoRef.current = video.current;
|
|||||||
onVolumeChange={onVolumeChangeHandler}
|
onVolumeChange={onVolumeChangeHandler}
|
||||||
controls={false}
|
controls={false}
|
||||||
/>
|
/>
|
||||||
<PlayBackMenu isFromDrawer={false} close={closePlaybackMenu} isOpen={isOpenPlaybackMenu} onSelect={onSelectPlaybackRate} playbackRate={playbackRate} />
|
<PlayBackMenu
|
||||||
|
isFromDrawer={false}
|
||||||
|
close={closePlaybackMenu}
|
||||||
|
isOpen={isOpenPlaybackMenu}
|
||||||
|
onSelect={onSelectPlaybackRate}
|
||||||
|
playbackRate={playbackRate}
|
||||||
|
/>
|
||||||
|
|
||||||
{isReady && !showControlsMobile && (
|
{isReady && !showControlsMobile && (
|
||||||
<VideoControlsBar
|
<VideoControlsBar
|
||||||
isVideoPlayerSmall={isVideoPlayerSmall}
|
isVideoPlayerSmall={isVideoPlayerSmall}
|
||||||
subtitleBtnRef={subtitleBtnRef}
|
subtitleBtnRef={subtitleBtnRef}
|
||||||
playbackRate={playbackRate}
|
playbackRate={playbackRate}
|
||||||
increaseSpeed={hotkeyHandlers.increaseSpeed}
|
increaseSpeed={hotkeyHandlers.increaseSpeed}
|
||||||
@ -896,78 +892,110 @@ savedVideoRef.current = video.current;
|
|||||||
toggleMute={toggleMute}
|
toggleMute={toggleMute}
|
||||||
openPlaybackMenu={openPlaybackMenu}
|
openPlaybackMenu={openPlaybackMenu}
|
||||||
togglePictureInPicture={togglePictureInPicture}
|
togglePictureInPicture={togglePictureInPicture}
|
||||||
|
setLocalProgress={setLocalProgress}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{timelineActions && Array.isArray(timelineActions) && (
|
||||||
|
<TimelineActionsComponent
|
||||||
|
seekTo={seekTo}
|
||||||
|
containerRef={containerRef}
|
||||||
|
progress={localProgress}
|
||||||
|
timelineActions={timelineActions}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{showControlsMobile && (
|
||||||
|
<MobileControls
|
||||||
|
setLocalProgress={setLocalProgress}
|
||||||
|
setProgressRelative={setProgressRelative}
|
||||||
|
toggleFullscreen={toggleFullscreen}
|
||||||
|
openPlaybackMenu={openPlaybackMenu}
|
||||||
|
openSubtitleManager={openSubtitleManager}
|
||||||
|
togglePlay={togglePlay}
|
||||||
|
isPlaying={isPlaying}
|
||||||
|
setShowControlsMobile={setShowControlsMobile}
|
||||||
|
duration={duration}
|
||||||
|
progress={localProgress}
|
||||||
|
playerRef={playerRef}
|
||||||
|
showControlsMobile={showControlsMobile}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{timelineActions && Array.isArray(timelineActions) && (
|
|
||||||
<TimelineActionsComponent seekTo={seekTo} containerRef={containerRef} progress={localProgress} timelineActions={timelineActions}/>
|
|
||||||
)}
|
|
||||||
{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}
|
|
||||||
close={closeSubtitleManager}
|
|
||||||
open={isOpenSubtitleManage}
|
|
||||||
qortalMetadata={qortalVideoResource}
|
|
||||||
onSelect={onSelectSubtitle}
|
|
||||||
currentSubTrack={currentSubTrack}
|
|
||||||
setDrawerOpenSubtitles={setDrawerOpenSubtitles}
|
|
||||||
isFromDrawer={false}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
|
{!isVideoPlayerSmall && (
|
||||||
|
<SubtitleManager
|
||||||
|
subtitleBtnRef={subtitleBtnRef}
|
||||||
|
close={closeSubtitleManager}
|
||||||
|
open={isOpenSubtitleManage}
|
||||||
|
qortalMetadata={qortalVideoResource}
|
||||||
|
onSelect={onSelectSubtitle}
|
||||||
|
currentSubTrack={currentSubTrack}
|
||||||
|
setDrawerOpenSubtitles={setDrawerOpenSubtitles}
|
||||||
|
isFromDrawer={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<ClickAwayListener onClickAway={() => setDrawerOpenSubtitles(false)}>
|
||||||
|
<Drawer
|
||||||
|
variant="persistent"
|
||||||
|
anchor="bottom"
|
||||||
|
open={drawerOpenSubtitles}
|
||||||
|
sx={{}}
|
||||||
|
slotProps={{
|
||||||
|
paper: {
|
||||||
|
sx: {
|
||||||
|
backgroundColor: alpha("#181818", 0.98),
|
||||||
|
borderRadius: 2,
|
||||||
|
width: "90%",
|
||||||
|
margin: "0 auto",
|
||||||
|
p: 1,
|
||||||
|
backgroundImage: "none",
|
||||||
|
mb: 1,
|
||||||
|
position: "absolute",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SubtitleManager
|
||||||
|
subtitleBtnRef={subtitleBtnRef}
|
||||||
|
close={closeSubtitleManager}
|
||||||
|
open={true}
|
||||||
|
qortalMetadata={qortalVideoResource}
|
||||||
|
onSelect={onSelectSubtitle}
|
||||||
|
currentSubTrack={currentSubTrack}
|
||||||
|
setDrawerOpenSubtitles={setDrawerOpenSubtitles}
|
||||||
|
isFromDrawer={true}
|
||||||
|
/>
|
||||||
|
</Drawer>
|
||||||
|
</ClickAwayListener>
|
||||||
|
<ClickAwayListener onClickAway={() => setDrawerOpenPlayback(false)}>
|
||||||
|
<Drawer
|
||||||
|
variant="persistent"
|
||||||
|
anchor="bottom"
|
||||||
|
open={drawerOpenPlayback}
|
||||||
|
sx={{}}
|
||||||
|
slotProps={{
|
||||||
|
paper: {
|
||||||
|
sx: {
|
||||||
|
backgroundColor: alpha("#181818", 0.98),
|
||||||
|
borderRadius: 2,
|
||||||
|
width: "90%",
|
||||||
|
margin: "0 auto",
|
||||||
|
p: 1,
|
||||||
|
backgroundImage: "none",
|
||||||
|
mb: 1,
|
||||||
|
position: "absolute",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PlayBackMenu
|
||||||
|
isFromDrawer
|
||||||
|
close={closePlaybackMenu}
|
||||||
|
isOpen={true}
|
||||||
|
onSelect={onSelectPlaybackRate}
|
||||||
|
playbackRate={playbackRate}
|
||||||
|
/>
|
||||||
|
</Drawer>
|
||||||
|
</ClickAwayListener>
|
||||||
</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>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -155,7 +155,7 @@ useEffect(() => {
|
|||||||
const aspectRatio = 0.75; // 300 / 400 = 3:4
|
const aspectRatio = 0.75; // 300 / 400 = 3:4
|
||||||
|
|
||||||
const maxWidthByScreen = screenWidth * 0.75;
|
const maxWidthByScreen = screenWidth * 0.75;
|
||||||
const maxWidthByHeight = (screenHeight * 0.2) / aspectRatio;
|
const maxWidthByHeight = (screenHeight * 0.3) / aspectRatio;
|
||||||
|
|
||||||
const maxWidth = savedWidthRef.current || Math.min(maxWidthByScreen, maxWidthByHeight);
|
const maxWidth = savedWidthRef.current || Math.min(maxWidthByScreen, maxWidthByHeight);
|
||||||
const maxHeight = savedHeightRef.current || maxWidth * aspectRatio;
|
const maxHeight = savedHeightRef.current || maxWidth * aspectRatio;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user