mirror of
https://github.com/movie-web/movie-web.git
synced 2024-11-10 23:55:05 +01:00
Merge pull request #267 from JipFr/dev
Add volume adjusted bar for keyboard events, fix UI always being dismissed after single mousemove
This commit is contained in:
commit
d40076e950
@ -31,6 +31,7 @@ import { PictureInPictureAction } from "@/video/components/actions/PictureInPict
|
||||
import { CaptionRendererAction } from "./actions/CaptionRendererAction";
|
||||
import { SettingsAction } from "./actions/SettingsAction";
|
||||
import { DividerAction } from "./actions/DividerAction";
|
||||
import { VolumeAdjustedAction } from "./actions/VolumeAdjustedAction";
|
||||
|
||||
type Props = VideoPlayerBaseProps;
|
||||
|
||||
@ -91,6 +92,7 @@ export function VideoPlayer(props: Props) {
|
||||
<>
|
||||
<KeyboardShortcutsAction />
|
||||
<PageTitleAction />
|
||||
<VolumeAdjustedAction />
|
||||
<VideoPlayerError onGoBack={props.onGoBack}>
|
||||
<BackdropAction onBackdropChange={onBackdropChange}>
|
||||
<CenterPosition>
|
||||
|
@ -24,18 +24,16 @@ export function BackdropAction(props: BackdropActionProps) {
|
||||
const handleMouseMove = useCallback(() => {
|
||||
if (!moved) {
|
||||
setTimeout(() => {
|
||||
// If NOT a touch, set moved to true
|
||||
const isTouch = Date.now() - lastTouchEnd.current < 200;
|
||||
if (!isTouch) {
|
||||
setMoved(true);
|
||||
}
|
||||
if (!isTouch) setMoved(true);
|
||||
}, 20);
|
||||
return;
|
||||
}
|
||||
|
||||
// remove after all
|
||||
if (timeout.current) clearTimeout(timeout.current);
|
||||
timeout.current = setTimeout(() => {
|
||||
if (moved) setMoved(false);
|
||||
setMoved(false);
|
||||
timeout.current = null;
|
||||
}, 3000);
|
||||
}, [setMoved, moved]);
|
||||
|
@ -65,12 +65,12 @@ export function KeyboardShortcutsAction() {
|
||||
|
||||
// Decrease volume
|
||||
case "arrowdown":
|
||||
controls.setVolume(Math.max(mediaPlaying.volume - 0.1, 0));
|
||||
controls.setVolume(Math.max(mediaPlaying.volume - 0.1, 0), true);
|
||||
break;
|
||||
|
||||
// Increase volume
|
||||
case "arrowup":
|
||||
controls.setVolume(Math.min(mediaPlaying.volume + 0.1, 1));
|
||||
controls.setVolume(Math.min(mediaPlaying.volume + 0.1, 1), true);
|
||||
break;
|
||||
|
||||
// Do a barrel Roll!
|
||||
|
32
src/video/components/actions/VolumeAdjustedAction.tsx
Normal file
32
src/video/components/actions/VolumeAdjustedAction.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import { Icon, Icons } from "@/components/Icon";
|
||||
import { useVideoPlayerDescriptor } from "@/video/state/hooks";
|
||||
import { useInterface } from "@/video/state/logic/interface";
|
||||
import { useMediaPlaying } from "@/video/state/logic/mediaplaying";
|
||||
|
||||
export function VolumeAdjustedAction() {
|
||||
const descriptor = useVideoPlayerDescriptor();
|
||||
const videoInterface = useInterface(descriptor);
|
||||
const mediaPlaying = useMediaPlaying(descriptor);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
videoInterface.volumeChangedWithKeybind
|
||||
? "mt-10 scale-100 opacity-100"
|
||||
: "mt-5 scale-75 opacity-0",
|
||||
"absolute left-1/2 z-[100] flex -translate-x-1/2 items-center space-x-4 rounded-full bg-bink-300 bg-opacity-50 py-2 px-5 transition-all duration-100",
|
||||
].join(" ")}
|
||||
>
|
||||
<Icon
|
||||
icon={mediaPlaying.volume > 0 ? Icons.VOLUME : Icons.VOLUME_X}
|
||||
className="text-xl text-white"
|
||||
/>
|
||||
<div className="h-2 w-44 overflow-hidden rounded-full bg-denim-100">
|
||||
<div
|
||||
className="h-full rounded-r-full bg-bink-500 transition-[width] duration-100"
|
||||
style={{ width: `${mediaPlaying.volume * 100}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -32,6 +32,8 @@ function initPlayer(): VideoPlayerState {
|
||||
isFocused: false,
|
||||
leftControlHovering: false,
|
||||
popoutBounds: null,
|
||||
volumeChangedWithKeybind: false,
|
||||
volumeChangedWithKeybindDebounce: null,
|
||||
timeFormat: 0,
|
||||
},
|
||||
|
||||
|
@ -49,8 +49,20 @@ export function useControls(
|
||||
enterFullscreen() {
|
||||
state.stateProvider?.enterFullscreen();
|
||||
},
|
||||
setVolume(volume) {
|
||||
state.stateProvider?.setVolume(volume);
|
||||
setVolume(volume, isKeyboardEvent = false) {
|
||||
if (isKeyboardEvent) {
|
||||
if (state.interface.volumeChangedWithKeybindDebounce)
|
||||
clearTimeout(state.interface.volumeChangedWithKeybindDebounce);
|
||||
|
||||
state.interface.volumeChangedWithKeybind = true;
|
||||
updateInterface(descriptor, state);
|
||||
|
||||
state.interface.volumeChangedWithKeybindDebounce = setTimeout(() => {
|
||||
state.interface.volumeChangedWithKeybind = false;
|
||||
updateInterface(descriptor, state);
|
||||
}, 3e3);
|
||||
}
|
||||
state.stateProvider?.setVolume(volume, isKeyboardEvent);
|
||||
},
|
||||
startAirplay() {
|
||||
state.stateProvider?.startAirplay();
|
||||
|
@ -9,6 +9,7 @@ export type VideoInterfaceEvent = {
|
||||
isFocused: boolean;
|
||||
isFullscreen: boolean;
|
||||
popoutBounds: null | DOMRect;
|
||||
volumeChangedWithKeybind: boolean;
|
||||
timeFormat: VideoPlayerTimeFormat;
|
||||
};
|
||||
|
||||
@ -19,6 +20,7 @@ function getInterfaceFromState(state: VideoPlayerState): VideoInterfaceEvent {
|
||||
isFocused: state.interface.isFocused,
|
||||
isFullscreen: state.interface.isFullscreen,
|
||||
popoutBounds: state.interface.popoutBounds,
|
||||
volumeChangedWithKeybind: state.interface.volumeChangedWithKeybind,
|
||||
timeFormat: state.interface.timeFormat,
|
||||
};
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ export type VideoPlayerStateController = {
|
||||
setSeeking(active: boolean): void;
|
||||
exitFullscreen(): void;
|
||||
enterFullscreen(): void;
|
||||
setVolume(volume: number): void;
|
||||
setVolume(volume: number, isKeyboardEvent?: boolean): void;
|
||||
startAirplay(): void;
|
||||
setCaption(id: string, url: string): void;
|
||||
clearCaption(): void;
|
||||
|
@ -33,6 +33,8 @@ export type VideoPlayerState = {
|
||||
isFullscreen: boolean;
|
||||
popout: string | null; // id of current popout (eg source select, episode select)
|
||||
isFocused: boolean; // is the video player the users focus? (shortcuts only works when its focused)
|
||||
volumeChangedWithKeybind: boolean; // has the volume recently been adjusted with the up/down arrows recently?
|
||||
volumeChangedWithKeybindDebounce: NodeJS.Timeout | null; // debounce for the duration of the "volume changed thingamajig"
|
||||
leftControlHovering: boolean; // is the cursor hovered over the left side of player controls
|
||||
popoutBounds: null | DOMRect; // bounding box of current popout
|
||||
timeFormat: VideoPlayerTimeFormat; // Time format of the video player
|
||||
|
Loading…
Reference in New Issue
Block a user