12 changed files with 186 additions and 4 deletions
@ -0,0 +1,3 @@ |
|||||||
|
export function LeftSideControls(props: {children: React.ReactNode}) { |
||||||
|
|
||||||
|
} |
@ -0,0 +1,82 @@ |
|||||||
|
import { useCallback, useRef, useState } from "react"; |
||||||
|
|
||||||
|
import { Icon, Icons } from "@/components/Icon"; |
||||||
|
import { |
||||||
|
makePercentage, |
||||||
|
makePercentageString, |
||||||
|
useProgressBar, |
||||||
|
} from "@/hooks/useProgressBar"; |
||||||
|
import { usePlayerStore } from "@/stores/player/store"; |
||||||
|
import { canChangeVolume } from "@/utils/detectFeatures"; |
||||||
|
|
||||||
|
import { useVolume } from "../hooks/useVolume"; |
||||||
|
|
||||||
|
interface Props { |
||||||
|
className?: string; |
||||||
|
} |
||||||
|
|
||||||
|
export function Volume(props: Props) { |
||||||
|
const ref = useRef<HTMLDivElement>(null); |
||||||
|
const setHovering = usePlayerStore((s) => s.setHoveringLeftControls); |
||||||
|
const hovering = usePlayerStore((s) => s.interface.leftControlHovering); |
||||||
|
const volume = usePlayerStore((s) => s.mediaPlaying.volume); |
||||||
|
const { setVolume, toggleMute } = useVolume(); |
||||||
|
|
||||||
|
const commitVolume = useCallback( |
||||||
|
(percentage) => { |
||||||
|
setVolume(percentage); |
||||||
|
}, |
||||||
|
[setVolume] |
||||||
|
); |
||||||
|
|
||||||
|
const { dragging, dragPercentage, dragMouseDown } = useProgressBar( |
||||||
|
ref, |
||||||
|
commitVolume, |
||||||
|
true |
||||||
|
); |
||||||
|
|
||||||
|
const handleClick = useCallback(() => { |
||||||
|
toggleMute(); |
||||||
|
}, [toggleMute]); |
||||||
|
|
||||||
|
const handleMouseEnter = useCallback(async () => { |
||||||
|
if (await canChangeVolume()) setHovering(true); |
||||||
|
}, [setHovering]); |
||||||
|
|
||||||
|
let percentage = makePercentage(volume * 100); |
||||||
|
if (dragging) percentage = makePercentage(dragPercentage); |
||||||
|
const percentageString = makePercentageString(percentage); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className={props.className} onMouseEnter={handleMouseEnter}> |
||||||
|
<div className="pointer-events-auto flex cursor-pointer items-center py-0"> |
||||||
|
<div className="px-4 text-2xl text-white" onClick={handleClick}> |
||||||
|
<Icon icon={percentage > 0 ? Icons.VOLUME : Icons.VOLUME_X} /> |
||||||
|
</div> |
||||||
|
<div |
||||||
|
className={`linear -ml-2 w-0 overflow-hidden transition-[width,opacity] duration-300 ${ |
||||||
|
hovering || dragging ? "!w-24 opacity-100" : "w-4 opacity-0" |
||||||
|
}`}
|
||||||
|
> |
||||||
|
<div |
||||||
|
ref={ref} |
||||||
|
className="flex h-10 w-20 items-center px-2" |
||||||
|
onMouseDown={dragMouseDown} |
||||||
|
onTouchStart={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-video-audio-set" |
||||||
|
style={{ |
||||||
|
width: percentageString, |
||||||
|
}} |
||||||
|
> |
||||||
|
<div className="absolute h-3 w-3 translate-x-1/2 rounded-full bg-white" /> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
import { useCallback, useEffect } from "react"; |
||||||
|
|
||||||
|
import { usePlayerStore } from "@/stores/player/store"; |
||||||
|
|
||||||
|
export function LeftSideControls(props: { children: React.ReactNode }) { |
||||||
|
const setHoveringLeftControls = usePlayerStore( |
||||||
|
(s) => s.setHoveringLeftControls |
||||||
|
); |
||||||
|
|
||||||
|
const mouseLeave = useCallback(() => { |
||||||
|
setHoveringLeftControls(false); |
||||||
|
}, [setHoveringLeftControls]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
return () => { |
||||||
|
setHoveringLeftControls(false); |
||||||
|
}; |
||||||
|
}, [setHoveringLeftControls]); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className="flex space-x-3 items-center" onMouseLeave={mouseLeave}> |
||||||
|
{props.children} |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
import { useCallback } from "react"; |
||||||
|
|
||||||
|
import { getStoredVolume } from "@/_oldvideo/components/hooks/volumeStore"; |
||||||
|
import { usePlayerStore } from "@/stores/player/store"; |
||||||
|
|
||||||
|
// TODO use new stored volume
|
||||||
|
|
||||||
|
export function useInitializePlayer() { |
||||||
|
const display = usePlayerStore((s) => s.display); |
||||||
|
|
||||||
|
const init = useCallback(() => { |
||||||
|
const storedVolume = getStoredVolume(); |
||||||
|
display?.setVolume(storedVolume); |
||||||
|
}, [display]); |
||||||
|
|
||||||
|
return { |
||||||
|
init, |
||||||
|
}; |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
import { |
||||||
|
getStoredVolume, |
||||||
|
setStoredVolume, |
||||||
|
} from "@/_oldvideo/components/hooks/volumeStore"; |
||||||
|
import { usePlayerStore } from "@/stores/player/store"; |
||||||
|
|
||||||
|
// TODO use new stored volume
|
||||||
|
|
||||||
|
export function useVolume() { |
||||||
|
const volume = usePlayerStore((s) => s.mediaPlaying.volume); |
||||||
|
const display = usePlayerStore((s) => s.display); |
||||||
|
|
||||||
|
const toggleVolume = (_isKeyboardEvent = false) => { |
||||||
|
// TODO use keyboard event
|
||||||
|
if (volume > 0) { |
||||||
|
setStoredVolume(volume); |
||||||
|
display?.setVolume(0); |
||||||
|
} else { |
||||||
|
const storedVolume = getStoredVolume(); |
||||||
|
if (storedVolume > 0) display?.setVolume(storedVolume); |
||||||
|
else display?.setVolume(1); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
return { |
||||||
|
toggleMute() { |
||||||
|
toggleVolume(); |
||||||
|
}, |
||||||
|
setVolume(vol: number) { |
||||||
|
setStoredVolume(vol); |
||||||
|
display?.setVolume(vol); |
||||||
|
}, |
||||||
|
}; |
||||||
|
} |
Loading…
Reference in new issue