feat(context menu): enable context menu on right click on video

This commit is contained in:
Botzy 2025-01-29 15:15:29 +02:00
parent 79a43ef444
commit 9a3be29a39
3 changed files with 63 additions and 11 deletions

View file

@ -9,7 +9,7 @@ const { useServices } = require('stremio/services');
const Option = require('./Option');
const styles = require('./styles');
const OptionsMenu = ({ className, stream, playbackDevices }) => {
const OptionsMenu = ({ className, stream, playbackDevices, style }) => {
const { t } = useTranslation();
const { core } = useServices();
const platform = usePlatform();
@ -70,7 +70,7 @@ const OptionsMenu = ({ className, stream, playbackDevices }) => {
event.nativeEvent.optionsMenuClosePrevented = true;
}, []);
return (
<div className={classnames(className, styles['options-menu-container'])} onMouseDown={onMouseDown}>
<div style={style} className={classnames(className, styles['options-menu-container'])} onMouseDown={onMouseDown}>
{
streamingUrl || downloadUrl ?
<Option
@ -112,7 +112,8 @@ const OptionsMenu = ({ className, stream, playbackDevices }) => {
OptionsMenu.propTypes = {
className: PropTypes.string,
stream: PropTypes.object,
playbackDevices: PropTypes.array
playbackDevices: PropTypes.array,
style: PropTypes.object,
};
module.exports = OptionsMenu;

View file

@ -61,9 +61,14 @@ const Player = ({ urlParams, queryParams }) => {
const [statisticsMenuOpen, , closeStatisticsMenu, toggleStatisticsMenu] = useBinaryState(false);
const [nextVideoPopupOpen, openNextVideoPopup, closeNextVideoPopup] = useBinaryState(false);
const [sideDrawerOpen, , closeSideDrawer, toggleSideDrawer] = useBinaryState(false);
const [contextMenuOpen, openContextMenu, closeContextMenu] = useBinaryState(false);
const [contextCoords, setContextCoords] = React.useState({
x: 0,
y: 0,
});
const menusOpen = React.useMemo(() => {
return optionsMenuOpen || subtitlesMenuOpen || audioMenuOpen || speedMenuOpen || statisticsMenuOpen || sideDrawerOpen;
return optionsMenuOpen || subtitlesMenuOpen || audioMenuOpen || speedMenuOpen || statisticsMenuOpen || sideDrawerOpen || contextMenuOpen;
}, [optionsMenuOpen, subtitlesMenuOpen, audioMenuOpen, speedMenuOpen, statisticsMenuOpen, sideDrawerOpen]);
const closeMenus = React.useCallback(() => {
@ -73,6 +78,7 @@ const Player = ({ urlParams, queryParams }) => {
closeSpeedMenu();
closeStatisticsMenu();
closeSideDrawer();
closeContextMenu();
}, []);
const overlayHidden = React.useMemo(() => {
@ -216,13 +222,17 @@ const Player = ({ urlParams, queryParams }) => {
}
}, [player.nextVideo]);
const onVideoClick = React.useCallback(() => {
if (video.state.paused !== null) {
if (video.state.paused) {
onPlayRequestedDebounced();
} else {
onPauseRequestedDebounced();
const onVideoClick = React.useCallback((e) => {
if (e.type === 'click') {
if (video.state.paused !== null) {
if (video.state.paused) {
onPlayRequestedDebounced();
} else {
onPauseRequestedDebounced();
}
}
} else if (e.type === 'contextmenu') {
onContextMenu(e);
}
}, [video.state.paused]);
@ -232,6 +242,28 @@ const Player = ({ urlParams, queryParams }) => {
toggleFullscreen();
}, [toggleFullscreen]);
const onContextMenu = React.useCallback((e) => {
e.preventDefault();
let baseFontSize = 14;
const { clientX, clientY } = event;
const { innerWidth, innerHeight } = window;
if (innerWidth > 1600) baseFontSize = 15;
if (innerWidth > 2200) baseFontSize = 16;
const menuWidth = 16 * baseFontSize;
const minMenuHeight = 9 * baseFontSize;
const adjustedX = clientX + menuWidth > innerWidth ? clientX - menuWidth : clientX;
const adjustedY = clientY + minMenuHeight > innerHeight ? clientY - minMenuHeight : clientY;
setContextCoords({
x: adjustedX,
y: adjustedY,
});
openContextMenu();
}, []);
const onContainerMouseDown = React.useCallback((event) => {
if (!event.nativeEvent.optionsMenuClosePrevented) {
closeOptionsMenu();
@ -250,6 +282,7 @@ const Player = ({ urlParams, queryParams }) => {
}
closeSideDrawer();
closeContextMenu();
}, []);
const onContainerMouseMove = React.useCallback((event) => {
@ -656,6 +689,24 @@ const Player = ({ urlParams, queryParams }) => {
:
null
}
{
contextMenuOpen ?
<OptionsMenu
style={
{
top: `${contextCoords.y}px`,
left: `${contextCoords.x}px`,
right: 'auto',
bottom: 'auto'
}
}
className={classnames(styles['layer'], styles['menu-layer'])}
stream={player.selected.stream}
playbackDevices={streamingServer.playbackDevices !== null && streamingServer.playbackDevices.type === 'Ready' ? streamingServer.playbackDevices.content : []}
/>
:
null
}
<HorizontalNavBar
className={classnames(styles['layer'], styles['nav-bar-layer'])}
title={player.title !== null ? player.title : ''}

View file

@ -7,7 +7,7 @@ const styles = require('./styles');
const Video = React.forwardRef(({ className, onClick, onDoubleClick }, ref) => {
return (
<div className={classnames(className, styles['video-container'])} onClick={onClick} onDoubleClick={onDoubleClick}>
<div className={classnames(className, styles['video-container'])} onClick={onClick} onContextMenu={onClick} onDoubleClick={onDoubleClick}>
<div ref={ref} className={styles['video']} />
</div>
);