2023-01-09 21:51:24 +01:00
|
|
|
import { Icon, Icons } from "@/components/Icon";
|
|
|
|
import {
|
|
|
|
makePercentage,
|
|
|
|
makePercentageString,
|
|
|
|
useProgressBar,
|
|
|
|
} from "@/hooks/useProgressBar";
|
2023-01-10 19:53:55 +01:00
|
|
|
import { canChangeVolume } from "@/utils/detectFeatures";
|
|
|
|
import { useCallback, useEffect, useRef, useState } from "react";
|
2023-01-08 17:51:38 +01:00
|
|
|
import { useVideoPlayerState } from "../VideoContext";
|
|
|
|
|
2023-01-09 21:51:24 +01:00
|
|
|
interface Props {
|
|
|
|
className?: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function VolumeControl(props: Props) {
|
2023-01-08 17:51:38 +01:00
|
|
|
const { videoState } = useVideoPlayerState();
|
|
|
|
const ref = useRef<HTMLDivElement>(null);
|
2023-01-09 21:51:24 +01:00
|
|
|
const [storedVolume, setStoredVolume] = useState(1);
|
|
|
|
const [hoveredOnce, setHoveredOnce] = useState(false);
|
2023-01-08 17:51:38 +01:00
|
|
|
|
2023-01-09 21:51:24 +01:00
|
|
|
const commitVolume = useCallback(
|
|
|
|
(percentage) => {
|
|
|
|
videoState.setVolume(percentage);
|
|
|
|
setStoredVolume(percentage);
|
2023-01-08 17:51:38 +01:00
|
|
|
},
|
2023-01-09 21:51:24 +01:00
|
|
|
[videoState, setStoredVolume]
|
2023-01-08 17:51:38 +01:00
|
|
|
);
|
2023-01-09 21:51:24 +01:00
|
|
|
const { dragging, dragPercentage, dragMouseDown } = useProgressBar(
|
|
|
|
ref,
|
|
|
|
commitVolume,
|
|
|
|
true
|
|
|
|
);
|
|
|
|
|
2023-01-10 19:53:55 +01:00
|
|
|
useEffect(() => {
|
|
|
|
if (!videoState.leftControlHovering) setHoveredOnce(false);
|
|
|
|
}, [videoState, setHoveredOnce]);
|
|
|
|
|
2023-01-09 21:51:24 +01:00
|
|
|
const handleClick = useCallback(() => {
|
|
|
|
if (videoState.volume > 0) {
|
|
|
|
videoState.setVolume(0);
|
|
|
|
setStoredVolume(videoState.volume);
|
|
|
|
} else {
|
|
|
|
videoState.setVolume(storedVolume > 0 ? storedVolume : 1);
|
|
|
|
}
|
|
|
|
}, [videoState, setStoredVolume, storedVolume]);
|
|
|
|
|
2023-01-10 19:53:55 +01:00
|
|
|
const handleMouseEnter = useCallback(async () => {
|
|
|
|
if (await canChangeVolume()) setHoveredOnce(true);
|
2023-01-09 21:51:24 +01:00
|
|
|
}, [setHoveredOnce]);
|
|
|
|
|
|
|
|
let percentage = makePercentage(videoState.volume * 100);
|
|
|
|
if (dragging) percentage = makePercentage(dragPercentage);
|
|
|
|
const percentageString = makePercentageString(percentage);
|
2023-01-08 17:51:38 +01:00
|
|
|
|
|
|
|
return (
|
2023-01-09 21:51:24 +01:00
|
|
|
<div className={props.className}>
|
2023-01-08 17:51:38 +01:00
|
|
|
<div
|
2023-01-09 21:51:24 +01:00
|
|
|
className="pointer-events-auto flex cursor-pointer items-center"
|
|
|
|
onMouseEnter={handleMouseEnter}
|
|
|
|
>
|
|
|
|
<div className="px-4 text-2xl text-white" onClick={handleClick}>
|
|
|
|
<Icon icon={percentage > 0 ? Icons.VOLUME : Icons.VOLUME_X} />
|
|
|
|
</div>
|
|
|
|
<div
|
2023-01-10 19:53:55 +01:00
|
|
|
className={`linear -ml-2 w-0 overflow-hidden transition-[width,opacity] duration-300 ${
|
2023-01-10 00:27:04 +01:00
|
|
|
hoveredOnce ? "!w-24 opacity-100" : "w-4 opacity-0"
|
2023-01-09 21:51:24 +01:00
|
|
|
}`}
|
|
|
|
>
|
|
|
|
<div
|
|
|
|
ref={ref}
|
2023-01-10 00:27:04 +01:00
|
|
|
className="flex h-10 w-20 items-center px-2"
|
2023-01-09 21:51:24 +01:00
|
|
|
onMouseDown={dragMouseDown}
|
|
|
|
>
|
|
|
|
<div className="relative h-1 flex-1 rounded-full bg-gray-500 bg-opacity-50">
|
|
|
|
<div
|
|
|
|
className="absolute inset-y-0 left-0 flex items-center justify-end rounded-full bg-bink-500"
|
|
|
|
style={{
|
|
|
|
width: percentageString,
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<div className="absolute h-3 w-3 translate-x-1/2 rounded-full bg-white" />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2023-01-08 17:51:38 +01:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|