mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-04-21 07:32:02 +00:00
refactor player menus
This commit is contained in:
parent
1ccca352d6
commit
89be4e8d16
12 changed files with 120 additions and 214 deletions
|
|
@ -3,33 +3,68 @@ const PropTypes = require('prop-types');
|
||||||
const classnames = require('classnames');
|
const classnames = require('classnames');
|
||||||
const Icon = require('stremio-icons/dom');
|
const Icon = require('stremio-icons/dom');
|
||||||
const { Button } = require('stremio/common');
|
const { Button } = require('stremio/common');
|
||||||
const InfoMenuButton = require('./InfoMenuButton');
|
|
||||||
const MuteButton = require('./MuteButton');
|
|
||||||
const PlayPauseButton = require('./PlayPauseButton');
|
|
||||||
const SeekBar = require('./SeekBar');
|
const SeekBar = require('./SeekBar');
|
||||||
const SubtitlesButton = require('./SubtitlesButton');
|
|
||||||
const VolumeSlider = require('./VolumeSlider');
|
const VolumeSlider = require('./VolumeSlider');
|
||||||
const styles = require('./styles');
|
const styles = require('./styles');
|
||||||
|
|
||||||
const ControlBar = ({
|
const ControlBar = ({
|
||||||
className,
|
className,
|
||||||
infoAvailable,
|
|
||||||
paused,
|
paused,
|
||||||
time,
|
time,
|
||||||
duration,
|
duration,
|
||||||
volume,
|
volume,
|
||||||
muted,
|
muted,
|
||||||
subtitlesTracks,
|
subtitlesTracks,
|
||||||
|
metaItem,
|
||||||
|
stream,
|
||||||
onPlayRequested,
|
onPlayRequested,
|
||||||
onPauseRequested,
|
onPauseRequested,
|
||||||
onMuteRequested,
|
onMuteRequested,
|
||||||
onUnmuteRequested,
|
onUnmuteRequested,
|
||||||
onVolumeChangeRequested,
|
onVolumeChangeRequested,
|
||||||
onSeekRequested,
|
onSeekRequested,
|
||||||
onToggleSubtitlesPicker,
|
onToggleSubtitlesMenu,
|
||||||
onToggleInfoMenu,
|
onToggleInfoMenu,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
|
const onSubtitlesButtonMouseDown = React.useCallback((event) => {
|
||||||
|
event.nativeEvent.subtitlesMenuClosePrevented = true;
|
||||||
|
}, []);
|
||||||
|
const onInfoButtonMouseDown = React.useCallback((event) => {
|
||||||
|
event.nativeEvent.infoMenuClosePrevented = true;
|
||||||
|
}, []);
|
||||||
|
const onPlayPauseButtonClick = React.useCallback(() => {
|
||||||
|
if (paused) {
|
||||||
|
if (typeof onPlayRequested === 'function') {
|
||||||
|
onPlayRequested();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (typeof onPauseRequested === 'function') {
|
||||||
|
onPauseRequested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [paused, onPlayRequested, onPauseRequested]);
|
||||||
|
const onMuteButtonClick = React.useCallback(() => {
|
||||||
|
if (muted) {
|
||||||
|
if (typeof onUnmuteRequested === 'function') {
|
||||||
|
onUnmuteRequested();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (typeof onMuteRequested === 'function') {
|
||||||
|
onMuteRequested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [muted, onMuteRequested, onUnmuteRequested]);
|
||||||
|
const onSubtitlesButtonClick = React.useCallback(() => {
|
||||||
|
if (typeof onToggleSubtitlesMenu === 'function') {
|
||||||
|
onToggleSubtitlesMenu();
|
||||||
|
}
|
||||||
|
}, [onToggleSubtitlesMenu]);
|
||||||
|
const onInfoButtonClick = React.useCallback(() => {
|
||||||
|
if (typeof onToggleInfoMenu === 'function') {
|
||||||
|
onToggleInfoMenu();
|
||||||
|
}
|
||||||
|
}, [onToggleInfoMenu]);
|
||||||
return (
|
return (
|
||||||
<div {...props} className={classnames(className, styles['control-bar-container'])}>
|
<div {...props} className={classnames(className, styles['control-bar-container'])}>
|
||||||
<SeekBar
|
<SeekBar
|
||||||
|
|
@ -39,19 +74,21 @@ const ControlBar = ({
|
||||||
onSeekRequested={onSeekRequested}
|
onSeekRequested={onSeekRequested}
|
||||||
/>
|
/>
|
||||||
<div className={styles['control-bar-buttons-container']}>
|
<div className={styles['control-bar-buttons-container']}>
|
||||||
<PlayPauseButton
|
<Button className={classnames(styles['control-bar-button'], { 'disabled': typeof paused !== 'boolean' })} title={paused ? 'Play' : 'Pause'} tabIndex={-1} onClick={onPlayPauseButtonClick}>
|
||||||
className={styles['control-bar-button']}
|
<Icon className={styles['icon']} icon={typeof paused !== 'boolean' || paused ? 'ic_play' : 'ic_pause'} />
|
||||||
paused={paused}
|
</Button>
|
||||||
onPlayRequested={onPlayRequested}
|
<Button className={classnames(styles['control-bar-button'], { 'disabled': typeof muted !== 'boolean' })} title={muted ? 'Unmute' : 'Mute'} tabIndex={-1} onClick={onMuteButtonClick}>
|
||||||
onPauseRequested={onPauseRequested}
|
<Icon
|
||||||
/>
|
className={styles['icon']}
|
||||||
<MuteButton
|
icon={
|
||||||
className={styles['control-bar-button']}
|
(typeof muted === 'boolean' && muted) ? 'ic_volume0' :
|
||||||
volume={volume}
|
(volume === null || isNaN(volume)) ? 'ic_volume3' :
|
||||||
muted={muted}
|
volume < 30 ? 'ic_volume1' :
|
||||||
onMuteRequested={onMuteRequested}
|
volume < 70 ? 'ic_volume2' :
|
||||||
onUnmuteRequested={onUnmuteRequested}
|
'ic_volume3'
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
<VolumeSlider
|
<VolumeSlider
|
||||||
className={styles['volume-slider']}
|
className={styles['volume-slider']}
|
||||||
volume={volume}
|
volume={volume}
|
||||||
|
|
@ -59,22 +96,19 @@ const ControlBar = ({
|
||||||
/>
|
/>
|
||||||
<div className={styles['spacing']} />
|
<div className={styles['spacing']} />
|
||||||
<Button className={classnames(styles['control-bar-button'], 'disabled')} tabIndex={-1}>
|
<Button className={classnames(styles['control-bar-button'], 'disabled')} tabIndex={-1}>
|
||||||
<Icon className={'icon'} icon={'ic_network'} />
|
<Icon className={styles['icon']} icon={'ic_network'} />
|
||||||
</Button>
|
</Button>
|
||||||
<InfoMenuButton
|
<Button className={classnames(styles['control-bar-button'], { 'disabled': typeof metaItem !== 'object' || metaItem === null || typeof stream !== 'object' || stream === null })} tabIndex={-1} onMouseDown={onInfoButtonMouseDown} onClick={onInfoButtonClick}>
|
||||||
className={classnames(styles['control-bar-button'], { 'disabled': !infoAvailable })}
|
<Icon className={styles['icon']} icon={'ic_info'} />
|
||||||
onToggleInfoMenu={onToggleInfoMenu}
|
|
||||||
/>
|
|
||||||
<Button className={classnames(styles['control-bar-button'], 'disabled')} tabIndex={-1}>
|
|
||||||
<Icon className={'icon'} icon={'ic_cast'} />
|
|
||||||
</Button>
|
</Button>
|
||||||
<SubtitlesButton
|
|
||||||
className={styles['control-bar-button']}
|
|
||||||
subtitlesTracks={subtitlesTracks}
|
|
||||||
onToggleSubtitlesPicker={onToggleSubtitlesPicker}
|
|
||||||
/>
|
|
||||||
<Button className={classnames(styles['control-bar-button'], 'disabled')} tabIndex={-1}>
|
<Button className={classnames(styles['control-bar-button'], 'disabled')} tabIndex={-1}>
|
||||||
<Icon className={'icon'} icon={'ic_videos'} />
|
<Icon className={styles['icon']} icon={'ic_cast'} />
|
||||||
|
</Button>
|
||||||
|
<Button className={classnames(styles['control-bar-button'], { 'disabled': !Array.isArray(subtitlesTracks) || subtitlesTracks.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>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -83,21 +117,22 @@ const ControlBar = ({
|
||||||
|
|
||||||
ControlBar.propTypes = {
|
ControlBar.propTypes = {
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
infoAvailable: PropTypes.bool,
|
paused: PropTypes.bool,
|
||||||
paused: PropTypes.any,
|
time: PropTypes.number,
|
||||||
time: PropTypes.any,
|
duration: PropTypes.number,
|
||||||
duration: PropTypes.any,
|
volume: PropTypes.number,
|
||||||
volume: PropTypes.any,
|
muted: PropTypes.bool,
|
||||||
muted: PropTypes.any,
|
subtitlesTracks: PropTypes.array,
|
||||||
subtitlesTracks: PropTypes.any,
|
metaItem: PropTypes.object,
|
||||||
onPlayRequested: PropTypes.any,
|
stream: PropTypes.object,
|
||||||
onPauseRequested: PropTypes.any,
|
onPlayRequested: PropTypes.func,
|
||||||
onMuteRequested: PropTypes.any,
|
onPauseRequested: PropTypes.func,
|
||||||
onUnmuteRequested: PropTypes.any,
|
onMuteRequested: PropTypes.func,
|
||||||
onVolumeChangeRequested: PropTypes.any,
|
onUnmuteRequested: PropTypes.func,
|
||||||
onSeekRequested: PropTypes.any,
|
onVolumeChangeRequested: PropTypes.func,
|
||||||
onToggleSubtitlesPicker: PropTypes.any,
|
onSeekRequested: PropTypes.func,
|
||||||
onToggleInfoMenu: PropTypes.any
|
onToggleSubtitlesMenu: PropTypes.func,
|
||||||
|
onToggleInfoMenu: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = ControlBar;
|
module.exports = ControlBar;
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
const React = require('react');
|
|
||||||
const PropTypes = require('prop-types');
|
|
||||||
const Icon = require('stremio-icons/dom');
|
|
||||||
const { Button } = require('stremio/common');
|
|
||||||
|
|
||||||
const InfoMenuButton = ({ className, onToggleInfoMenu }) => {
|
|
||||||
const onMouseDown = React.useCallback((event) => {
|
|
||||||
event.nativeEvent.infoMenuClosePrevented = true;
|
|
||||||
}, []);
|
|
||||||
const onClick = React.useCallback(() => {
|
|
||||||
if (typeof onToggleInfoMenu === 'function') {
|
|
||||||
onToggleInfoMenu();
|
|
||||||
}
|
|
||||||
}, [onToggleInfoMenu]);
|
|
||||||
return (
|
|
||||||
<Button className={className} tabIndex={-1} onMouseDown={onMouseDown} onClick={onClick}>
|
|
||||||
<Icon className={'icon'} icon={'ic_info'} />
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
InfoMenuButton.propTypes = {
|
|
||||||
className: PropTypes.string,
|
|
||||||
onToggleInfoMenu: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = InfoMenuButton;
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
const InfoMenuButton = require('./InfoMenuButton');
|
|
||||||
|
|
||||||
module.exports = InfoMenuButton;
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
const React = require('react');
|
|
||||||
const PropTypes = require('prop-types');
|
|
||||||
const classnames = require('classnames');
|
|
||||||
const Icon = require('stremio-icons/dom');
|
|
||||||
const { Button } = require('stremio/common');
|
|
||||||
|
|
||||||
const MuteButton = ({ className, muted, volume, onMuteRequested, onUnmuteRequested }) => {
|
|
||||||
const toggleMuted = React.useCallback(() => {
|
|
||||||
if (muted) {
|
|
||||||
if (typeof onUnmuteRequested === 'function') {
|
|
||||||
onUnmuteRequested();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (typeof onMuteRequested === 'function') {
|
|
||||||
onMuteRequested();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [muted, onMuteRequested, onUnmuteRequested]);
|
|
||||||
const icon = (typeof muted === 'boolean' && muted) ? 'ic_volume0' :
|
|
||||||
(volume === null || isNaN(volume)) ? 'ic_volume3' :
|
|
||||||
volume < 30 ? 'ic_volume1' :
|
|
||||||
volume < 70 ? 'ic_volume2' :
|
|
||||||
'ic_volume3';
|
|
||||||
return (
|
|
||||||
<Button className={classnames(className, { 'disabled': typeof muted !== 'boolean' })} title={muted ? 'Unmute' : 'Mute'} tabIndex={-1} onClick={toggleMuted}>
|
|
||||||
<Icon className={'icon'} icon={icon} />
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
MuteButton.propTypes = {
|
|
||||||
className: PropTypes.string,
|
|
||||||
muted: PropTypes.bool,
|
|
||||||
volume: PropTypes.number,
|
|
||||||
onMuteRequested: PropTypes.func,
|
|
||||||
onUnmuteRequested: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = MuteButton;
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
const MuteButton = require('./MuteButton');
|
|
||||||
|
|
||||||
module.exports = MuteButton;
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
const React = require('react');
|
|
||||||
const PropTypes = require('prop-types');
|
|
||||||
const classnames = require('classnames');
|
|
||||||
const Icon = require('stremio-icons/dom');
|
|
||||||
const { Button } = require('stremio/common');
|
|
||||||
|
|
||||||
const PlayPauseButton = ({ className, paused, onPlayRequested, onPauseRequested }) => {
|
|
||||||
const togglePaused = React.useCallback(() => {
|
|
||||||
if (paused) {
|
|
||||||
if (typeof onPlayRequested === 'function') {
|
|
||||||
onPlayRequested();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (typeof onPauseRequested === 'function') {
|
|
||||||
onPauseRequested();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [paused, onPlayRequested, onPauseRequested]);
|
|
||||||
return (
|
|
||||||
<Button className={classnames(className, { 'disabled': typeof paused !== 'boolean' })} title={paused ? 'Play' : 'Pause'} tabIndex={-1} onClick={togglePaused}>
|
|
||||||
<Icon
|
|
||||||
className={'icon'}
|
|
||||||
icon={typeof paused !== 'boolean' || paused ? 'ic_play' : 'ic_pause'}
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
PlayPauseButton.propTypes = {
|
|
||||||
className: PropTypes.string,
|
|
||||||
paused: PropTypes.bool,
|
|
||||||
onPlayRequested: PropTypes.func,
|
|
||||||
onPauseRequested: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = PlayPauseButton;
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
const PlayPauseButton = require('./PlayPauseButton');
|
|
||||||
|
|
||||||
module.exports = PlayPauseButton;
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
const React = require('react');
|
|
||||||
const PropTypes = require('prop-types');
|
|
||||||
const classnames = require('classnames');
|
|
||||||
const Icon = require('stremio-icons/dom');
|
|
||||||
const { Button } = require('stremio/common');
|
|
||||||
|
|
||||||
const SubtitlesButton = ({ className, subtitlesTracks, onToggleSubtitlesPicker }) => {
|
|
||||||
const onMouseDown = React.useCallback((event) => {
|
|
||||||
event.nativeEvent.subtitlesPickerClosePrevented = true;
|
|
||||||
}, []);
|
|
||||||
const onClick = React.useCallback(() => {
|
|
||||||
if (typeof onToggleSubtitlesPicker === 'function') {
|
|
||||||
onToggleSubtitlesPicker();
|
|
||||||
}
|
|
||||||
}, [onToggleSubtitlesPicker]);
|
|
||||||
return (
|
|
||||||
<Button className={classnames(className, { 'disabled': !Array.isArray(subtitlesTracks) || subtitlesTracks.length === 0 })} tabIndex={-1} onMouseDown={onMouseDown} onClick={onClick}>
|
|
||||||
<Icon className={'icon'} icon={'ic_sub'} />
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
SubtitlesButton.propTypes = {
|
|
||||||
className: PropTypes.string,
|
|
||||||
subtitlesTracks: PropTypes.array,
|
|
||||||
onToggleSubtitlesPicker: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = SubtitlesButton;
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
const SubtitlesButton = require('./SubtitlesButton');
|
|
||||||
|
|
||||||
module.exports = SubtitlesButton;
|
|
||||||
|
|
@ -21,12 +21,12 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&:global(.disabled) {
|
&:global(.disabled) {
|
||||||
:global(.icon) {
|
.icon {
|
||||||
fill: @color-surface;
|
fill: @color-surface;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.icon) {
|
.icon {
|
||||||
flex: none;
|
flex: none;
|
||||||
width: 3rem;
|
width: 3rem;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
|
|
|
||||||
|
|
@ -18,17 +18,26 @@ const Player = ({ urlParams }) => {
|
||||||
const { core } = useServices();
|
const { core } = useServices();
|
||||||
const [player, updateLibraryItemState, pushToLibrary] = usePlayer(urlParams);
|
const [player, updateLibraryItemState, pushToLibrary] = usePlayer(urlParams);
|
||||||
const [settings, updateSettings] = useSettings();
|
const [settings, updateSettings] = useSettings();
|
||||||
|
const stream = React.useMemo(() => {
|
||||||
|
return player.selected !== null ?
|
||||||
|
player.selected.stream
|
||||||
|
:
|
||||||
|
null;
|
||||||
|
}, [player]);
|
||||||
|
const metaItem = React.useMemo(() => {
|
||||||
|
return player.meta_resource !== null && player.meta_resource.content.type === 'Ready' ?
|
||||||
|
player.meta_resource.content.content
|
||||||
|
:
|
||||||
|
null;
|
||||||
|
}, [player]);
|
||||||
const routeFocused = useRouteFocused();
|
const routeFocused = useRouteFocused();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const [, , , toggleFullscreen] = useFullscreen();
|
const [, , , toggleFullscreen] = useFullscreen();
|
||||||
const [immersed, setImmersed] = React.useState(true);
|
const [immersed, setImmersed] = React.useState(true);
|
||||||
const setImmersedDebounced = React.useCallback(debounce(setImmersed, 3000), []);
|
const setImmersedDebounced = React.useCallback(debounce(setImmersed, 3000), []);
|
||||||
const [subtitlesPickerOpen, , closeSubtitlesPicker, toggleSubtitlesPicker] = useBinaryState(false);
|
const [subtitlesMenuOpen, , closeSubtitlesMenu, toggleSubtitlesMenu] = useBinaryState(false);
|
||||||
const [infoMenuOpen, , closeInfoMenu, toggleInfoMenu] = useBinaryState(false);
|
const [infoMenuOpen, , closeInfoMenu, toggleInfoMenu] = useBinaryState(false);
|
||||||
const [error, setError] = React.useState(null);
|
const [error, setError] = React.useState(null);
|
||||||
const infoAvailable = React.useMemo(() => {
|
|
||||||
return player.meta_resource !== null && player.meta_resource.content.type === 'Ready';
|
|
||||||
}, [player]);
|
|
||||||
const [videoState, setVideoState] = React.useReducer(
|
const [videoState, setVideoState] = React.useReducer(
|
||||||
(videoState, nextVideoState) => ({ ...videoState, ...nextVideoState }),
|
(videoState, nextVideoState) => ({ ...videoState, ...nextVideoState }),
|
||||||
{
|
{
|
||||||
|
|
@ -150,8 +159,8 @@ const Player = ({ urlParams }) => {
|
||||||
toggleFullscreen();
|
toggleFullscreen();
|
||||||
}, [toggleFullscreen]);
|
}, [toggleFullscreen]);
|
||||||
const onContainerMouseDown = React.useCallback((event) => {
|
const onContainerMouseDown = React.useCallback((event) => {
|
||||||
if (!event.nativeEvent.subtitlesPickerClosePrevented) {
|
if (!event.nativeEvent.subtitlesMenuClosePrevented) {
|
||||||
closeSubtitlesPicker();
|
closeSubtitlesMenu();
|
||||||
}
|
}
|
||||||
if (!event.nativeEvent.infoMenuClosePrevented) {
|
if (!event.nativeEvent.infoMenuClosePrevented) {
|
||||||
closeInfoMenu();
|
closeInfoMenu();
|
||||||
|
|
@ -239,7 +248,7 @@ const Player = ({ urlParams }) => {
|
||||||
const onKeyDown = (event) => {
|
const onKeyDown = (event) => {
|
||||||
switch (event.code) {
|
switch (event.code) {
|
||||||
case 'Space': {
|
case 'Space': {
|
||||||
if (!subtitlesPickerOpen && !infoMenuOpen && videoState.paused !== null) {
|
if (!subtitlesMenuOpen && !infoMenuOpen && videoState.paused !== null) {
|
||||||
if (videoState.paused) {
|
if (videoState.paused) {
|
||||||
onPlayRequested();
|
onPlayRequested();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -250,28 +259,28 @@ const Player = ({ urlParams }) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'ArrowRight': {
|
case 'ArrowRight': {
|
||||||
if (!subtitlesPickerOpen && !infoMenuOpen && videoState.time !== null) {
|
if (!subtitlesMenuOpen && !infoMenuOpen && videoState.time !== null) {
|
||||||
onSeekRequested(videoState.time + 15000);
|
onSeekRequested(videoState.time + 15000);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'ArrowLeft': {
|
case 'ArrowLeft': {
|
||||||
if (!subtitlesPickerOpen && !infoMenuOpen && videoState.time !== null) {
|
if (!subtitlesMenuOpen && !infoMenuOpen && videoState.time !== null) {
|
||||||
onSeekRequested(videoState.time - 15000);
|
onSeekRequested(videoState.time - 15000);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'ArrowUp': {
|
case 'ArrowUp': {
|
||||||
if (!subtitlesPickerOpen && !infoMenuOpen && videoState.volume !== null) {
|
if (!subtitlesMenuOpen && !infoMenuOpen && videoState.volume !== null) {
|
||||||
onVolumeChangeRequested(videoState.volume + 5);
|
onVolumeChangeRequested(videoState.volume + 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'ArrowDown': {
|
case 'ArrowDown': {
|
||||||
if (!subtitlesPickerOpen && !infoMenuOpen && videoState.volume !== null) {
|
if (!subtitlesMenuOpen && !infoMenuOpen && videoState.volume !== null) {
|
||||||
onVolumeChangeRequested(videoState.volume - 5);
|
onVolumeChangeRequested(videoState.volume - 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -279,18 +288,22 @@ const Player = ({ urlParams }) => {
|
||||||
}
|
}
|
||||||
case 'KeyS': {
|
case 'KeyS': {
|
||||||
closeInfoMenu();
|
closeInfoMenu();
|
||||||
toggleSubtitlesPicker();
|
if (Array.isArray(videoState.subtitlesTracks) && videoState.subtitlesTracks.length > 0) {
|
||||||
|
toggleSubtitlesMenu();
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'KeyM': {
|
case 'KeyM': {
|
||||||
closeSubtitlesPicker();
|
closeSubtitlesMenu();
|
||||||
if (infoAvailable) {
|
if (typeof metaItem === 'object' && metaItem !== null && typeof stream === 'object' && stream !== null) {
|
||||||
toggleInfoMenu();
|
toggleInfoMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'Escape': {
|
case 'Escape': {
|
||||||
closeSubtitlesPicker();
|
closeSubtitlesMenu();
|
||||||
closeInfoMenu();
|
closeInfoMenu();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -302,7 +315,7 @@ const Player = ({ urlParams }) => {
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('keydown', onKeyDown);
|
window.removeEventListener('keydown', onKeyDown);
|
||||||
};
|
};
|
||||||
}, [routeFocused, subtitlesPickerOpen, infoAvailable, infoMenuOpen, videoState.paused, videoState.time, videoState.volume, toggleSubtitlesPicker, toggleInfoMenu]);
|
}, [routeFocused, subtitlesMenuOpen, infoMenuOpen, stream, metaItem, videoState.paused, videoState.time, videoState.volume, videoState.subtitlesTracks, toggleSubtitlesMenu, toggleInfoMenu]);
|
||||||
React.useLayoutEffect(() => {
|
React.useLayoutEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
setImmersedDebounced.cancel();
|
setImmersedDebounced.cancel();
|
||||||
|
|
@ -311,7 +324,7 @@ const Player = ({ urlParams }) => {
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
return (
|
return (
|
||||||
<div className={classnames(styles['player-container'], { [styles['immersed']]: immersed && videoState.paused !== null && !videoState.paused && !subtitlesPickerOpen && !infoMenuOpen })}
|
<div className={classnames(styles['player-container'], { [styles['immersed']]: immersed && videoState.paused !== null && !videoState.paused && !subtitlesMenuOpen && !infoMenuOpen })}
|
||||||
onMouseDown={onContainerMouseDown}
|
onMouseDown={onContainerMouseDown}
|
||||||
onMouseMove={onContainerMouseMove}
|
onMouseMove={onContainerMouseMove}
|
||||||
onMouseOver={onContainerMouseMove}
|
onMouseOver={onContainerMouseMove}
|
||||||
|
|
@ -343,7 +356,7 @@ const Player = ({ urlParams }) => {
|
||||||
onDoubleClick={onVideoDoubleClick}
|
onDoubleClick={onVideoDoubleClick}
|
||||||
/>
|
/>
|
||||||
{
|
{
|
||||||
subtitlesPickerOpen || infoMenuOpen ?
|
subtitlesMenuOpen || infoMenuOpen ?
|
||||||
<div className={styles['layer']} />
|
<div className={styles['layer']} />
|
||||||
:
|
:
|
||||||
null
|
null
|
||||||
|
|
@ -370,20 +383,21 @@ const Player = ({ urlParams }) => {
|
||||||
volume={videoState.volume}
|
volume={videoState.volume}
|
||||||
muted={videoState.muted}
|
muted={videoState.muted}
|
||||||
subtitlesTracks={videoState.subtitlesTracks}
|
subtitlesTracks={videoState.subtitlesTracks}
|
||||||
infoAvailable={infoAvailable}
|
stream={stream}
|
||||||
|
metaItem={metaItem}
|
||||||
onPlayRequested={onPlayRequested}
|
onPlayRequested={onPlayRequested}
|
||||||
onPauseRequested={onPauseRequested}
|
onPauseRequested={onPauseRequested}
|
||||||
onMuteRequested={onMuteRequested}
|
onMuteRequested={onMuteRequested}
|
||||||
onUnmuteRequested={onUnmuteRequested}
|
onUnmuteRequested={onUnmuteRequested}
|
||||||
onVolumeChangeRequested={onVolumeChangeRequested}
|
onVolumeChangeRequested={onVolumeChangeRequested}
|
||||||
onSeekRequested={onSeekRequested}
|
onSeekRequested={onSeekRequested}
|
||||||
onToggleSubtitlesPicker={toggleSubtitlesPicker}
|
onToggleSubtitlesMenu={toggleSubtitlesMenu}
|
||||||
onToggleInfoMenu={toggleInfoMenu}
|
onToggleInfoMenu={toggleInfoMenu}
|
||||||
onMouseMove={onBarMouseMove}
|
onMouseMove={onBarMouseMove}
|
||||||
onMouseOver={onBarMouseMove}
|
onMouseOver={onBarMouseMove}
|
||||||
/>
|
/>
|
||||||
{
|
{
|
||||||
subtitlesPickerOpen ?
|
subtitlesMenuOpen ?
|
||||||
<SubtitlesPicker
|
<SubtitlesPicker
|
||||||
className={classnames(styles['layer'], styles['menu-layer'])}
|
className={classnames(styles['layer'], styles['menu-layer'])}
|
||||||
tracks={videoState.subtitlesTracks}
|
tracks={videoState.subtitlesTracks}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ const SubtitlesPicker = (props) => {
|
||||||
[];
|
[];
|
||||||
}, [props.tracks, selectedLanguage]);
|
}, [props.tracks, selectedLanguage]);
|
||||||
const onMouseDown = React.useCallback((event) => {
|
const onMouseDown = React.useCallback((event) => {
|
||||||
event.nativeEvent.subtitlesPickerClosePrevented = true;
|
event.nativeEvent.subtitlesMenuClosePrevented = true;
|
||||||
}, []);
|
}, []);
|
||||||
const languageOnClick = React.useCallback((event) => {
|
const languageOnClick = React.useCallback((event) => {
|
||||||
const trackId = Array.isArray(props.tracks) ?
|
const trackId = Array.isArray(props.tracks) ?
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue