3
0
mirror of https://github.com/Qortal/q-tube.git synced 2025-02-11 17:55:51 +00:00

Videoplayer updates:

VideoPlayer tooltips moved below buttons to avoid interfering with clicking on progress slider. Slider raised 2px and is thicker for the same reason.

Clicking on progress slider doesn't force the video to start playing.

Changed colors on Volume Slider so it is easier to see on Desktop and especially Mobile

Volume slider removed on mobile

Buggy feature that did picture in picture when leaving video while playing has been removed

If on Mobile, video title has bigger topMargin to prevent video clipping into it on some Mobile devices.
This commit is contained in:
Qortal Dev 2025-01-03 16:03:43 -07:00
parent 823365998a
commit c6605060db
7 changed files with 90 additions and 77 deletions

View File

@ -10,8 +10,7 @@ import {
ProgressSlider, ProgressSlider,
ReloadButton, ReloadButton,
VideoTime, VideoTime,
VolumeButton, VolumeControl,
VolumeSlider,
} from "./VideoControls.tsx"; } from "./VideoControls.tsx";
export const MobileControlsBar = () => { export const MobileControlsBar = () => {
@ -54,10 +53,6 @@ export const MobileControlsBar = () => {
}, },
}} }}
> >
<MenuItem>
<VolumeButton />
<VolumeSlider width={"100%"} />
</MenuItem>
<MenuItem> <MenuItem>
<ObjectFitButton /> <ObjectFitButton />
</MenuItem> </MenuItem>

View File

@ -1,4 +1,4 @@
import { IconButton, Slider, Typography } from "@mui/material"; import { Box, IconButton, Slider, Typography } from "@mui/material";
import { fontSizeExSmall, fontSizeSmall } from "../../../../constants/Misc.ts"; import { fontSizeExSmall, fontSizeSmall } from "../../../../constants/Misc.ts";
import { CustomFontTooltip } from "../../../../utils/CustomFontTooltip.tsx"; import { CustomFontTooltip } from "../../../../utils/CustomFontTooltip.tsx";
import { formatTime } from "../../../../utils/numberFunctions.ts"; import { formatTime } from "../../../../utils/numberFunctions.ts";
@ -18,7 +18,7 @@ import { useSignalEffect } from "@preact/signals-react";
export const PlayButton = () => { export const PlayButton = () => {
const { togglePlay, playing } = useVideoContext(); const { togglePlay, playing } = useVideoContext();
return ( return (
<CustomFontTooltip title="Pause/Play (Spacebar)" placement="top" arrow> <CustomFontTooltip title="Pause/Play (Spacebar)" placement="bottom" arrow>
<IconButton <IconButton
sx={{ sx={{
color: "white", color: "white",
@ -34,7 +34,7 @@ export const PlayButton = () => {
export const ReloadButton = () => { export const ReloadButton = () => {
const { reloadVideo } = useVideoContext(); const { reloadVideo } = useVideoContext();
return ( return (
<CustomFontTooltip title="Reload Video (R)" placement="top" arrow> <CustomFontTooltip title="Reload Video (R)" placement="bottom" arrow>
<IconButton <IconButton
sx={{ sx={{
color: "white", color: "white",
@ -57,7 +57,7 @@ export const ProgressSlider = () => {
max={videoRef.current?.duration || 100} max={videoRef.current?.duration || 100}
sx={{ sx={{
position: "absolute", position: "absolute",
bottom: "40px", bottom: "42px",
color: "#00abff", color: "#00abff",
padding: "0px", padding: "0px",
// prevents the slider from jumping up 20px in certain mobile conditions // prevents the slider from jumping up 20px in certain mobile conditions
@ -69,7 +69,8 @@ export const ProgressSlider = () => {
height: "16px", height: "16px",
}, },
"& .MuiSlider-thumb::after": { width: "20px", height: "20px" }, "& .MuiSlider-thumb::after": { width: "20px", height: "20px" },
"& .MuiSlider-rail": { opacity: 0.5 }, "& .MuiSlider-rail": { opacity: 0.5, height: "6px" },
"& .MuiSlider-track": { height: "6px", border: "0px" },
}} }}
/> />
); );
@ -81,7 +82,7 @@ export const VideoTime = () => {
return ( return (
<CustomFontTooltip <CustomFontTooltip
title="Seek video in 10% increments (0-9)" title="Seek video in 10% increments (0-9)"
placement="top" placement="bottom"
arrow arrow
> >
<Typography <Typography
@ -102,12 +103,12 @@ export const VideoTime = () => {
); );
}; };
export const VolumeButton = () => { const VolumeButton = () => {
const { isMuted, toggleMute } = useVideoContext(); const { isMuted, toggleMute } = useVideoContext();
return ( return (
<CustomFontTooltip <CustomFontTooltip
title="Toggle Mute (M), Raise (UP), Lower (DOWN)" title="Toggle Mute (M), Raise (UP), Lower (DOWN)"
placement="top" placement="bottom"
arrow arrow
> >
<IconButton <IconButton
@ -122,8 +123,13 @@ export const VolumeButton = () => {
); );
}; };
export const VolumeSlider = ({ width }: { width: string }) => { const VolumeSlider = ({ width }: { width: string }) => {
const { volume, onVolumeChange } = useVideoContext(); const { volume, onVolumeChange } = useVideoContext();
let color = "";
if (volume.value <= 0.5) color = "green";
else if (volume.value <= 0.75) color = "yellow";
else color = "red";
return ( return (
<Slider <Slider
value={volume.value} value={volume.value}
@ -134,18 +140,36 @@ export const VolumeSlider = ({ width }: { width: string }) => {
sx={{ sx={{
width, width,
marginRight: "10px", marginRight: "10px",
"& .MuiSlider-thumb::after": { width: "25px", height: "25px" }, color,
"& .MuiSlider-thumb": {
backgroundColor: "#fff",
width: "16px",
height: "16px",
},
"& .MuiSlider-thumb::after": { width: "16px", height: "16px" },
"& .MuiSlider-rail": { opacity: 0.5, height: "6px" },
"& .MuiSlider-track": { height: "6px", border: "0px" },
}} }}
/> />
); );
}; };
export const VolumeControl = ({ sliderWidth }: { sliderWidth: string }) => {
return (
<Box
sx={{ display: "flex", gap: "5px", alignItems: "center", width: "100%" }}
>
<VolumeButton />
<VolumeSlider width={sliderWidth} />
</Box>
);
};
export const PlaybackRate = () => { export const PlaybackRate = () => {
const { playbackRate, increaseSpeed, isScreenSmall } = useVideoContext(); const { playbackRate, increaseSpeed, isScreenSmall } = useVideoContext();
return ( return (
<CustomFontTooltip <CustomFontTooltip
title="Video Speed. Increase (+ or >), Decrease (- or <)" title="Video Speed. Increase (+ or >), Decrease (- or <)"
placement="top" placement="bottom"
arrow arrow
> >
<IconButton <IconButton
@ -170,7 +194,11 @@ export const PictureInPictureButton = () => {
return ( return (
<> <>
{!isFullscreen.value && ( {!isFullscreen.value && (
<CustomFontTooltip title="Picture in Picture (P)" placement="top" arrow> <CustomFontTooltip
title="Picture in Picture (P)"
placement="bottom"
arrow
>
<IconButton <IconButton
sx={{ sx={{
color: "white", color: "white",
@ -189,7 +217,7 @@ export const PictureInPictureButton = () => {
export const ObjectFitButton = () => { export const ObjectFitButton = () => {
const { toggleObjectFit } = useVideoContext(); const { toggleObjectFit } = useVideoContext();
return ( return (
<CustomFontTooltip title="Toggle Aspect Ratio (O)" placement="top" arrow> <CustomFontTooltip title="Toggle Aspect Ratio (O)" placement="bottom" arrow>
<IconButton <IconButton
sx={{ sx={{
color: "white", color: "white",
@ -206,7 +234,7 @@ export const ObjectFitButton = () => {
export const FullscreenButton = () => { export const FullscreenButton = () => {
const { toggleFullscreen } = useVideoContext(); const { toggleFullscreen } = useVideoContext();
return ( return (
<CustomFontTooltip title="Toggle Fullscreen (F)" placement="top" arrow> <CustomFontTooltip title="Toggle Fullscreen (F)" placement="bottom" arrow>
<IconButton <IconButton
sx={{ sx={{
color: "white", color: "white",

View File

@ -11,17 +11,15 @@ import {
ProgressSlider, ProgressSlider,
ReloadButton, ReloadButton,
VideoTime, VideoTime,
VolumeButton, VolumeControl,
VolumeSlider,
} from "./VideoControls.tsx"; } from "./VideoControls.tsx";
import { useSignalEffect } from "@preact/signals-react";
export const VideoControlsBar = () => { export const VideoControlsBar = () => {
const { from, canPlay, showControlsFullScreen, isScreenSmall, progress } = const { from, canPlay, showControlsFullScreen, isScreenSmall, progress } =
useVideoContext(); useVideoContext();
const showMobileControls = isScreenSmall && canPlay.value; const showMobileControls = isScreenSmall && canPlay.value;
const controlsHeight = "40px"; const controlsHeight = "42px";
const controlGroupSX = { const controlGroupSX = {
display: "flex", display: "flex",
gap: "5px", gap: "5px",
@ -46,8 +44,7 @@ export const VideoControlsBar = () => {
<ProgressSlider /> <ProgressSlider />
<VolumeButton /> <VolumeControl sliderWidth={"100px"} />
<VolumeSlider width={"100px"} />
<VideoTime /> <VideoTime />
</Box> </Box>

View File

@ -147,11 +147,6 @@ export const useVideoPlayerState = (props: VideoPlayerProps, ref: any) => {
if (!videoRef.current) return; if (!videoRef.current) return;
videoRef.current.currentTime = value as number; videoRef.current.currentTime = value as number;
progress.value = value as number; progress.value = value as number;
if (!playing.value) {
await videoRef.current.play();
playing.value = true;
}
}; };
const handleEnded = () => { const handleEnded = () => {
@ -198,9 +193,7 @@ export const useVideoPlayerState = (props: VideoPlayerProps, ref: any) => {
const target = event?.target; const target = event?.target;
if (target) { if (target) {
target.pause(); target.pause();
if (playing.value) { if (playing.value) playing.value = false;
playing.value = false;
}
} }
}; };

View File

@ -445,21 +445,21 @@ export const VideoPlayerGlobal: React.FC<VideoPlayerProps> = ({
} }
}; };
useEffect(() => { // useEffect(() => {
if (element) { // if (element) {
const oldElement = document.getElementById("videoPlayer"); // const oldElement = document.getElementById("videoPlayer");
if (oldElement && oldElement?.parentNode) { // if (oldElement && oldElement?.parentNode) {
oldElement?.parentNode.replaceChild(element, oldElement); // oldElement?.parentNode.replaceChild(element, oldElement);
videoRef.current = element; // videoRef.current = element;
setPlaying(true); // setPlaying(true);
setCanPlay(true); // setCanPlay(true);
setStartPlay(true); // setStartPlay(true);
//videoRef?.current?.addEventListener("click", () => {}); // //videoRef?.current?.addEventListener("click", () => {});
videoRef?.current?.addEventListener("timeupdate", updateProgress); // videoRef?.current?.addEventListener("timeupdate", updateProgress);
videoRef?.current?.addEventListener("ended", handleEnded); // videoRef?.current?.addEventListener("ended", handleEnded);
} // }
} // }
}, [element]); // }, [element]);
return ( return (
<VideoContainer <VideoContainer
@ -483,9 +483,9 @@ export const VideoPlayerGlobal: React.FC<VideoPlayerProps> = ({
}} }}
></CloseIcon> ></CloseIcon>
</div> </div>
<div onClick={togglePlay}> {/*<div onClick={togglePlay}>*/}
<VideoElement id="videoPlayer" /> {/* <VideoElement id="videoPlayer" />*/}
</div> {/*</div>*/}
<ControlsContainer <ControlsContainer
style={{ style={{
bottom: from === "create" ? "15px" : 0, bottom: from === "create" ? "15px" : 0,

View File

@ -121,7 +121,7 @@ export const VideoContent = () => {
color="textPrimary" color="textPrimary"
sx={{ sx={{
textAlign: "start", textAlign: "start",
marginTop: "10px", marginTop: isScreenSmall ? "20px" : "10px",
}} }}
> >
{videoData?.title} {videoData?.title}

View File

@ -228,30 +228,30 @@ const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
/> />
<EditVideo /> <EditVideo />
<EditPlaylist /> <EditPlaylist />
<Rnd {/*<Rnd*/}
onDragStart={onDragStart} {/* onDragStart={onDragStart}*/}
onDragStop={onDragStop} {/* onDragStop={onDragStop}*/}
style={{ {/* style={{*/}
display: videoPlaying ? "block" : "none", {/* display: videoPlaying ? "block" : "none",*/}
position: "fixed", {/* position: "fixed",*/}
height: "auto", {/* height: "auto",*/}
width: 350, {/* width: 350,*/}
zIndex: 1000, {/* zIndex: 1000,*/}
maxWidth: 800, {/* maxWidth: 800,*/}
}} {/* }}*/}
default={{ {/* default={{*/}
x: 0, {/* x: 0,*/}
y: 60, {/* y: 60,*/}
width: 350, {/* width: 350,*/}
height: "auto", {/* height: "auto",*/}
}} {/* }}*/}
// eslint-disable-next-line @typescript-eslint/no-empty-function {/* // eslint-disable-next-line @typescript-eslint/no-empty-function*/}
onDrag={() => {}} {/* onDrag={() => {}}*/}
> {/*>*/}
{videoPlaying && ( {/* {videoPlaying && (*/}
<VideoPlayerGlobal checkIfDrag={checkIfDrag} element={videoPlaying} /> {/* <VideoPlayerGlobal checkIfDrag={checkIfDrag} element={videoPlaying} />*/}
)} {/* )}*/}
</Rnd> {/*</Rnd>*/}
{children} {children}
</> </>