Add volume control using scroll wheel from myzel, with flow errors fixed (#1638)

* created function

* removed console logs

* made volume change on mousewheel functional

* improved code

* added precise volume control

* updated behavior

* fixed error

* fix flow errors

Co-authored-by: myzel394 <50424412+Myzel394@users.noreply.github.com>
This commit is contained in:
mayeaux 2022-06-06 15:37:44 +02:00 committed by GitHub
parent c146ccc432
commit 8aaa820e2f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 100 additions and 14 deletions

View file

@ -6,6 +6,8 @@ import isUserTyping from 'util/detect-typing';
const SEEK_STEP_5 = 5; const SEEK_STEP_5 = 5;
const SEEK_STEP = 10; // time to seek in seconds const SEEK_STEP = 10; // time to seek in seconds
const VOLUME_CHANGE_ON_SCROLL = 0.05;
const PRECISE_VOLUME_CHANGE_ON_SCROLL = 0.01;
// check if active (clicked) element is part of video div, used for keyboard shortcuts (volume etc) // check if active (clicked) element is part of video div, used for keyboard shortcuts (volume etc)
function activeElementIsPartOfVideoElement() { function activeElementIsPartOfVideoElement() {
@ -14,24 +16,24 @@ function activeElementIsPartOfVideoElement() {
return videoElementParent.contains(activeElement); return videoElementParent.contains(activeElement);
} }
function volumeUp(event, playerRef) { function volumeUp(event, playerRef, checkIsActive = true, amount = 0.05) {
// dont run if video element is not active element (otherwise runs when scrolling using keypad) // dont run if video element is not active element (otherwise runs when scrolling using keypad)
const videoElementIsActive = activeElementIsPartOfVideoElement(); const videoElementIsActive = activeElementIsPartOfVideoElement();
const player = playerRef.current; const player = playerRef.current;
if (!player || !videoElementIsActive) return; if (!player || (checkIsActive && !videoElementIsActive)) return;
event.preventDefault(); event.preventDefault();
player.volume(player.volume() + 0.05); player.volume(player.volume() + amount);
OVERLAY.showVolumeverlay(player, Math.round(player.volume() * 100)); OVERLAY.showVolumeverlay(player, Math.round(player.volume() * 100));
player.userActive(true); player.userActive(true);
} }
function volumeDown(event, playerRef) { function volumeDown(event, playerRef, checkIsActive = true, amount = 0.05) {
// dont run if video element is not active element (otherwise runs when scrolling using keypad) // dont run if video element is not active element (otherwise runs when scrolling using keypad)
const videoElementIsActive = activeElementIsPartOfVideoElement(); const videoElementIsActive = activeElementIsPartOfVideoElement();
const player = playerRef.current; const player = playerRef.current;
if (!player || !videoElementIsActive) return; if (!player || (checkIsActive && !videoElementIsActive)) return;
event.preventDefault(); event.preventDefault();
player.volume(player.volume() - 0.05); player.volume(player.volume() - amount);
OVERLAY.showVolumeverlay(player, Math.round(player.volume() * 100)); OVERLAY.showVolumeverlay(player, Math.round(player.volume() * 100));
player.userActive(true); player.userActive(true);
} }
@ -94,7 +96,7 @@ function changePlaybackSpeed(shouldSpeedUp: boolean, playerRef) {
} }
} }
const VideoJsKeyboardShorcuts = ({ const VideoJsShorcuts = ({
playNext, playNext,
playPrevious, playPrevious,
toggleVideoTheaterMode, toggleVideoTheaterMode,
@ -163,15 +165,65 @@ const VideoJsKeyboardShorcuts = ({
if (e.keyCode === KEYCODES.NINE) seekVideo(90 / 100, playerRef, containerRef, true); if (e.keyCode === KEYCODES.NINE) seekVideo(90 / 100, playerRef, containerRef, true);
} }
var curried_function = function (playerRef: any, containerRef: any) { const handleVideoScrollWheel = (event, playerRef, containerRef) => {
// Handle precise volume control when scrolling over the video player while holding down the "SHIFT"-key
const player = playerRef.current;
const videoNode = containerRef.current && containerRef.current.querySelector('video');
if (!videoNode || !player || isUserTyping() || !event.shiftKey) return;
event.preventDefault();
const delta = event.deltaY;
if (delta > 0) {
volumeDown(event, playerRef, false, PRECISE_VOLUME_CHANGE_ON_SCROLL);
} else if (delta < 0) {
volumeUp(event, playerRef, false, PRECISE_VOLUME_CHANGE_ON_SCROLL);
}
};
const handleVolumeBarScrollWheel = (event, volumeElement, playerRef, containerRef) => {
// Handle generic and precise volume control when scrolling over the volume bar
const player = playerRef.current;
const videoNode = containerRef.current && containerRef.current.querySelector('video');
if (!volumeElement || !player || !videoNode || isUserTyping()) return;
event.preventDefault();
event.stopImmediatePropagation();
const delta = event.deltaY;
const changeAmount = event.shiftKey ? PRECISE_VOLUME_CHANGE_ON_SCROLL : VOLUME_CHANGE_ON_SCROLL;
if (delta > 0) {
volumeDown(event, playerRef, false, changeAmount);
} else if (delta < 0) {
volumeUp(event, playerRef, false, changeAmount);
}
};
const createKeyDownShortcutsHandler = function (playerRef: any, containerRef: any) {
return function curried_func(e: any) { return function curried_func(e: any) {
handleKeyDown(e, playerRef, containerRef); handleKeyDown(e, playerRef, containerRef);
}; };
}; };
const createVideoScrollShortcutsHandler = function (playerRef: any, containerRef: any) {
return function curried_func(e: any) {
handleVideoScrollWheel(e, playerRef, containerRef);
};
};
const createVolumePanelScrollShortcutsHandler = function (volumeElement: any, playerRef: any, containerRef: any) {
return function curried_func(e: any) {
handleVolumeBarScrollWheel(e, volumeElement, playerRef, containerRef);
};
};
return { return {
curried_function, createKeyDownShortcutsHandler,
createVideoScrollShortcutsHandler,
createVolumePanelScrollShortcutsHandler,
}; };
}; };
export default VideoJsKeyboardShorcuts; export default VideoJsShorcuts;

View file

@ -15,7 +15,7 @@ import events from './videojs-events';
import eventTracking from 'videojs-event-tracking'; import eventTracking from 'videojs-event-tracking';
import functions from './videojs-functions'; import functions from './videojs-functions';
import hlsQualitySelector from './plugins/videojs-hls-quality-selector/plugin'; import hlsQualitySelector from './plugins/videojs-hls-quality-selector/plugin';
import keyboardShorcuts from './videojs-keyboard-shortcuts'; import keyboardShorcuts from './videojs-shortcuts';
import LbryVolumeBarClass from './lbry-volume-bar'; import LbryVolumeBarClass from './lbry-volume-bar';
import Chromecast from './chromecast'; import Chromecast from './chromecast';
import playerjs from 'player.js'; import playerjs from 'player.js';
@ -103,6 +103,8 @@ type Props = {
activeLivestreamForChannel: any, activeLivestreamForChannel: any,
doToast: ({ message: string, linkText: string, linkTarget: string }) => void, doToast: ({ message: string, linkText: string, linkTarget: string }) => void,
}; };
const VIDEOJS_CONTROL_BAR_CLASS = 'ControlBar';
const VIDEOJS_VOLUME_PANEL_CLASS = 'VolumePanel';
const IS_IOS = platform.isIOS(); const IS_IOS = platform.isIOS();
const IS_MOBILE = platform.isMobile(); const IS_MOBILE = platform.isMobile();
@ -176,13 +178,22 @@ export default React.memo<Props>(function VideoJs(props: Props) {
const tapToUnmuteRef = useRef(); const tapToUnmuteRef = useRef();
const tapToRetryRef = useRef(); const tapToRetryRef = useRef();
const playerServerRef = useRef(); const playerServerRef = useRef();
const volumePanelRef = useRef();
const keyDownHandlerRef = useRef();
const videoScrollHandlerRef = useRef();
const volumePanelScrollHandlerRef = useRef();
const { url: livestreamVideoUrl } = activeLivestreamForChannel || {}; const { url: livestreamVideoUrl } = activeLivestreamForChannel || {};
const overrideNativeVhs = !platform.isIPhone(); const overrideNativeVhs = !platform.isIPhone();
const showQualitySelector = (!isLivestreamClaim && overrideNativeVhs) || livestreamVideoUrl; const showQualitySelector = (!isLivestreamClaim && overrideNativeVhs) || livestreamVideoUrl;
// initiate keyboard shortcuts // initiate keyboard shortcuts
const { curried_function } = keyboardShorcuts({ const {
createKeyDownShortcutsHandler,
createVideoScrollShortcutsHandler,
createVolumePanelScrollShortcutsHandler,
} = keyboardShorcuts({
isMobile, isMobile,
isLivestreamClaim, isLivestreamClaim,
toggleVideoTheaterMode, toggleVideoTheaterMode,
@ -370,7 +381,23 @@ export default React.memo<Props>(function VideoJs(props: Props) {
// Set reference in component state // Set reference in component state
playerRef.current = vjsPlayer; playerRef.current = vjsPlayer;
window.addEventListener('keydown', curried_function(playerRef, containerRef)); // volume control div, used for changing volume when scrolled over
volumePanelRef.current = playerRef.current
.getChild(VIDEOJS_CONTROL_BAR_CLASS)
.getChild(VIDEOJS_VOLUME_PANEL_CLASS)
.el();
const keyDownHandler = createKeyDownShortcutsHandler(playerRef, containerRef);
const videoScrollHandler = createVideoScrollShortcutsHandler(playerRef, containerRef);
const volumePanelHandler = createVolumePanelScrollShortcutsHandler(volumePanelRef, playerRef, containerRef);
window.addEventListener('keydown', keyDownHandler);
const containerDiv = containerRef.current;
containerDiv && containerDiv.addEventListener('wheel', videoScrollHandler);
if (volumePanelRef.current) volumePanelRef.current.addEventListener('wheel', volumePanelHandler);
keyDownHandlerRef.current = keyDownHandler;
videoScrollHandlerRef.current = videoScrollHandler;
volumePanelScrollHandlerRef.current = volumePanelHandler;
const controlBar = document.querySelector('.vjs-control-bar'); const controlBar = document.querySelector('.vjs-control-bar');
if (controlBar) { if (controlBar) {
@ -441,7 +468,14 @@ export default React.memo<Props>(function VideoJs(props: Props) {
// Cleanup // Cleanup
return () => { return () => {
window.removeEventListener('keydown', curried_function); window.removeEventListener('keydown', keyDownHandlerRef.current);
const containerDiv = containerRef.current;
// $FlowFixMe
containerDiv && containerDiv.removeEventListener('wheel', videoScrollHandlerRef.current);
if (volumePanelRef.current) {
volumePanelRef.current.removeEventListener('wheel', volumePanelScrollHandlerRef.current);
}
const player = playerRef.current; const player = playerRef.current;
if (player) { if (player) {