Merge pull request #313 from Stremio/feat/player-videos-menu

feat(Player): implement videos menu
This commit is contained in:
Nikola Hristov 2022-11-02 20:49:11 +02:00 committed by GitHub
commit 8de2b494dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 111 additions and 6 deletions

View file

@ -29,6 +29,7 @@ const ControlBar = ({
onSeekRequested,
onToggleSubtitlesMenu,
onToggleInfoMenu,
onToggleVideosMenu,
...props
}) => {
const { chromecast } = useServices();
@ -40,6 +41,9 @@ const ControlBar = ({
const onInfoButtonMouseDown = React.useCallback((event) => {
event.nativeEvent.infoMenuClosePrevented = true;
}, []);
const onVideosButtonMouseDown = React.useCallback((event) => {
event.nativeEvent.videosMenuClosePrevented = true;
}, []);
const onPlayPauseButtonClick = React.useCallback(() => {
if (paused) {
if (typeof onPlayRequested === 'function') {
@ -72,6 +76,11 @@ const ControlBar = ({
onToggleInfoMenu();
}
}, [onToggleInfoMenu]);
const onVideosButtonClick = React.useCallback(() => {
if (typeof onToggleVideosMenu === 'function') {
onToggleVideosMenu();
}
}, [onToggleVideosMenu]);
const onChromecastButtonClick = React.useCallback(() => {
chromecast.transport.requestSession();
}, []);
@ -130,9 +139,14 @@ const ControlBar = ({
<Button className={classnames(styles['control-bar-button'], { 'disabled': (!Array.isArray(subtitlesTracks) || subtitlesTracks.length === 0) && (!Array.isArray(audioTracks) || audioTracks.length === 0) })} tabIndex={-1} onMouseDown={onSubtitlesButtonMouseDown} onClick={onSubtitlesButtonClick}>
<Icon className={styles['icon']} icon={'ic_sub'} />
</Button>
<Button className={classnames(styles['control-bar-button'], 'disabled')} tabIndex={-1}>
<Icon className={styles['icon']} icon={'ic_videos'} />
</Button>
{
metaItem?.content?.videos?.length > 0 ?
<Button className={styles['control-bar-button']} tabIndex={-1} onMouseDown={onVideosButtonMouseDown} onClick={onVideosButtonClick}>
<Icon className={styles['icon']} icon={'ic_videos'} />
</Button>
:
null
}
</div>
</div>
</div>
@ -156,7 +170,8 @@ ControlBar.propTypes = {
onVolumeChangeRequested: PropTypes.func,
onSeekRequested: PropTypes.func,
onToggleSubtitlesMenu: PropTypes.func,
onToggleInfoMenu: PropTypes.func
onToggleInfoMenu: PropTypes.func,
onToggleVideosMenu: PropTypes.func
};
module.exports = ControlBar;

View file

@ -11,6 +11,7 @@ const Icon = require('@stremio/stremio-icons/dom');
const BufferingLoader = require('./BufferingLoader');
const ControlBar = require('./ControlBar');
const InfoMenu = require('./InfoMenu');
const VideosMenu = require('./VideosMenu');
const SubtitlesMenu = require('./SubtitlesMenu');
const Video = require('./Video');
const usePlayer = require('./usePlayer');
@ -38,6 +39,7 @@ const Player = ({ urlParams, queryParams }) => {
const setImmersedDebounced = React.useCallback(debounce(setImmersed, 3000), []);
const [subtitlesMenuOpen, , closeSubtitlesMenu, toggleSubtitlesMenu] = useBinaryState(false);
const [infoMenuOpen, , closeInfoMenu, toggleInfoMenu] = useBinaryState(false);
const [videosMenuOpen, , closeVideosMenu, toggleVideosMenu] = useBinaryState(false);
const [error, setError] = React.useState(null);
const [videoState, setVideoState] = React.useReducer(
(videoState, nextVideoState) => ({ ...videoState, ...nextVideoState }),
@ -198,6 +200,9 @@ const Player = ({ urlParams, queryParams }) => {
if (!event.nativeEvent.infoMenuClosePrevented) {
closeInfoMenu();
}
if (!event.nativeEvent.videosMenuClosePrevented) {
closeVideosMenu();
}
}, []);
const onContainerMouseMove = React.useCallback((event) => {
setImmersed(false);
@ -318,6 +323,7 @@ const Player = ({ urlParams, queryParams }) => {
React.useEffect(() => {
if (player.metaItem === null || player.metaItem.type !== 'Ready') {
closeInfoMenu();
closeVideosMenu();
}
}, [player.metaItem]);
React.useEffect(() => {
@ -402,6 +408,7 @@ const Player = ({ urlParams, queryParams }) => {
}
case 'KeyS': {
closeInfoMenu();
closeVideosMenu();
if ((Array.isArray(videoState.subtitlesTracks) && videoState.subtitlesTracks.length > 0) ||
(Array.isArray(videoState.extraSubtitlesTracks) && videoState.extraSubtitlesTracks.length > 0) ||
(Array.isArray(videoState.audioTracks) && videoState.audioTracks.length > 0)) {
@ -412,15 +419,26 @@ const Player = ({ urlParams, queryParams }) => {
}
case 'KeyI': {
closeSubtitlesMenu();
closeVideosMenu();
if (player.metaItem !== null && player.metaItem.type === 'Ready') {
toggleInfoMenu();
}
break;
}
case 'KeyV': {
closeInfoMenu();
closeSubtitlesMenu();
if (player.metaItem !== null && player.metaItem.type === 'Ready') {
toggleVideosMenu();
}
break;
}
case 'Escape': {
closeSubtitlesMenu();
closeInfoMenu();
closeVideosMenu();
break;
}
}
@ -431,7 +449,7 @@ const Player = ({ urlParams, queryParams }) => {
return () => {
window.removeEventListener('keydown', onKeyDown);
};
}, [player.metaItem, settings.seekTimeDuration, routeFocused, subtitlesMenuOpen, infoMenuOpen, videoState.paused, videoState.time, videoState.volume, videoState.audioTracks, videoState.subtitlesTracks, videoState.extraSubtitlesTracks, toggleSubtitlesMenu, toggleInfoMenu]);
}, [player.metaItem, settings.seekTimeDuration, routeFocused, subtitlesMenuOpen, infoMenuOpen, videoState.paused, videoState.time, videoState.volume, videoState.audioTracks, videoState.subtitlesTracks, videoState.extraSubtitlesTracks, toggleSubtitlesMenu, toggleInfoMenu, toggleVideosMenu]);
React.useLayoutEffect(() => {
return () => {
setImmersedDebounced.cancel();
@ -440,7 +458,7 @@ const Player = ({ urlParams, queryParams }) => {
};
}, []);
return (
<div className={classnames(styles['player-container'], { [styles['immersed']]: immersed && !casting && videoState.paused !== null && !videoState.paused && !subtitlesMenuOpen && !infoMenuOpen })}
<div className={classnames(styles['player-container'], { [styles['immersed']]: immersed && !casting && videoState.paused !== null && !videoState.paused && !subtitlesMenuOpen && !infoMenuOpen && !videosMenuOpen })}
onMouseDown={onContainerMouseDown}
onMouseMove={onContainerMouseMove}
onMouseOver={onContainerMouseMove}
@ -516,6 +534,7 @@ const Player = ({ urlParams, queryParams }) => {
onSeekRequested={onSeekRequested}
onToggleSubtitlesMenu={toggleSubtitlesMenu}
onToggleInfoMenu={toggleInfoMenu}
onToggleVideosMenu={toggleVideosMenu}
onMouseMove={onBarMouseMove}
onMouseOver={onBarMouseMove}
/>
@ -557,6 +576,16 @@ const Player = ({ urlParams, queryParams }) => {
:
null
}
{
videosMenuOpen ?
<VideosMenu
className={classnames(styles['layer'], styles['menu-layer'])}
metaItem={player.metaItem !== null && player.metaItem.type === 'Ready' ? player.metaItem.content : null}
seriesInfo={player.seriesInfo}
/>
:
null
}
</div>
);
};

View file

@ -0,0 +1,51 @@
// Copyright (C) 2017-2022 Smart code 203358507
const React = require('react');
const PropTypes = require('prop-types');
const classnames = require('classnames');
const Video = require('../../MetaDetails/VideosList/Video');
const styles = require('./styles');
const VideosMenu = ({ className, metaItem, seriesInfo }) => {
const onMouseDown = React.useCallback((event) => {
event.nativeEvent.videosMenuClosePrevented = true;
}, []);
const videos = React.useMemo(() => {
return seriesInfo && typeof seriesInfo.season === 'number' && Array.isArray(metaItem.videos) ?
metaItem.videos.filter(({ season }) => season === seriesInfo.season)
:
metaItem.videos;
}, [metaItem, seriesInfo]);
return (
<div className={classnames(className, styles['videos-menu-container'])} onMouseDown={onMouseDown}>
{
videos.map((video, index) => (
<Video
key={index}
id={video.id}
title={video.title}
thumbnail={video.thumbnail}
episode={video.episode}
released={video.released}
upcoming={video.upcoming}
watched={video.watched}
progress={video.progress}
deepLinks={video.deepLinks}
scheduled={video.scheduled}
/>
))
}
</div>
);
};
VideosMenu.propTypes = {
className: PropTypes.string,
metaItem: PropTypes.object,
seriesInfo: PropTypes.shape({
season: PropTypes.number,
episode: PropTypes.number,
}),
};
module.exports = VideosMenu;

View file

@ -0,0 +1,5 @@
// Copyright (C) 2017-2022 Smart code 203358507
const VideosMenu = require('./VideosMenu');
module.exports = VideosMenu;

View file

@ -0,0 +1,5 @@
// Copyright (C) 2017-2022 Smart code 203358507
.videos-menu-container {
width: 30rem;
}