From 89be4e8d1648f1891f73e66bd5a5e679b87a9cae Mon Sep 17 00:00:00 2001 From: nklhrstv Date: Tue, 31 Mar 2020 18:19:39 +0300 Subject: [PATCH] refactor player menus --- src/routes/Player/ControlBar/ControlBar.js | 129 +++++++++++------- .../InfoMenuButton/InfoMenuButton.js | 27 ---- .../Player/ControlBar/InfoMenuButton/index.js | 3 - .../ControlBar/MuteButton/MuteButton.js | 39 ------ .../Player/ControlBar/MuteButton/index.js | 3 - .../PlayPauseButton/PlayPauseButton.js | 36 ----- .../ControlBar/PlayPauseButton/index.js | 3 - .../SubtitlesButton/SubtitlesButton.js | 29 ---- .../ControlBar/SubtitlesButton/index.js | 3 - src/routes/Player/ControlBar/styles.less | 4 +- src/routes/Player/Player.js | 56 +++++--- .../Player/SubtitlesPicker/SubtitlesPicker.js | 2 +- 12 files changed, 120 insertions(+), 214 deletions(-) delete mode 100644 src/routes/Player/ControlBar/InfoMenuButton/InfoMenuButton.js delete mode 100644 src/routes/Player/ControlBar/InfoMenuButton/index.js delete mode 100644 src/routes/Player/ControlBar/MuteButton/MuteButton.js delete mode 100644 src/routes/Player/ControlBar/MuteButton/index.js delete mode 100644 src/routes/Player/ControlBar/PlayPauseButton/PlayPauseButton.js delete mode 100644 src/routes/Player/ControlBar/PlayPauseButton/index.js delete mode 100644 src/routes/Player/ControlBar/SubtitlesButton/SubtitlesButton.js delete mode 100644 src/routes/Player/ControlBar/SubtitlesButton/index.js diff --git a/src/routes/Player/ControlBar/ControlBar.js b/src/routes/Player/ControlBar/ControlBar.js index 1b00b5903..7d11ba108 100644 --- a/src/routes/Player/ControlBar/ControlBar.js +++ b/src/routes/Player/ControlBar/ControlBar.js @@ -3,33 +3,68 @@ const PropTypes = require('prop-types'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); const { Button } = require('stremio/common'); -const InfoMenuButton = require('./InfoMenuButton'); -const MuteButton = require('./MuteButton'); -const PlayPauseButton = require('./PlayPauseButton'); const SeekBar = require('./SeekBar'); -const SubtitlesButton = require('./SubtitlesButton'); const VolumeSlider = require('./VolumeSlider'); const styles = require('./styles'); const ControlBar = ({ className, - infoAvailable, paused, time, duration, volume, muted, subtitlesTracks, + metaItem, + stream, onPlayRequested, onPauseRequested, onMuteRequested, onUnmuteRequested, onVolumeChangeRequested, onSeekRequested, - onToggleSubtitlesPicker, + onToggleSubtitlesMenu, onToggleInfoMenu, ...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 (
- - + +
- - - + +
@@ -83,21 +117,22 @@ const ControlBar = ({ ControlBar.propTypes = { className: PropTypes.string, - infoAvailable: PropTypes.bool, - paused: PropTypes.any, - time: PropTypes.any, - duration: PropTypes.any, - volume: PropTypes.any, - muted: PropTypes.any, - subtitlesTracks: PropTypes.any, - onPlayRequested: PropTypes.any, - onPauseRequested: PropTypes.any, - onMuteRequested: PropTypes.any, - onUnmuteRequested: PropTypes.any, - onVolumeChangeRequested: PropTypes.any, - onSeekRequested: PropTypes.any, - onToggleSubtitlesPicker: PropTypes.any, - onToggleInfoMenu: PropTypes.any + paused: PropTypes.bool, + time: PropTypes.number, + duration: PropTypes.number, + volume: PropTypes.number, + muted: PropTypes.bool, + subtitlesTracks: PropTypes.array, + metaItem: PropTypes.object, + stream: PropTypes.object, + onPlayRequested: PropTypes.func, + onPauseRequested: PropTypes.func, + onMuteRequested: PropTypes.func, + onUnmuteRequested: PropTypes.func, + onVolumeChangeRequested: PropTypes.func, + onSeekRequested: PropTypes.func, + onToggleSubtitlesMenu: PropTypes.func, + onToggleInfoMenu: PropTypes.func }; module.exports = ControlBar; diff --git a/src/routes/Player/ControlBar/InfoMenuButton/InfoMenuButton.js b/src/routes/Player/ControlBar/InfoMenuButton/InfoMenuButton.js deleted file mode 100644 index 2062a2bdd..000000000 --- a/src/routes/Player/ControlBar/InfoMenuButton/InfoMenuButton.js +++ /dev/null @@ -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 ( - - ); -}; - -InfoMenuButton.propTypes = { - className: PropTypes.string, - onToggleInfoMenu: PropTypes.func -}; - -module.exports = InfoMenuButton; diff --git a/src/routes/Player/ControlBar/InfoMenuButton/index.js b/src/routes/Player/ControlBar/InfoMenuButton/index.js deleted file mode 100644 index 6dfeff76d..000000000 --- a/src/routes/Player/ControlBar/InfoMenuButton/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const InfoMenuButton = require('./InfoMenuButton'); - -module.exports = InfoMenuButton; diff --git a/src/routes/Player/ControlBar/MuteButton/MuteButton.js b/src/routes/Player/ControlBar/MuteButton/MuteButton.js deleted file mode 100644 index 7e3c2b0b5..000000000 --- a/src/routes/Player/ControlBar/MuteButton/MuteButton.js +++ /dev/null @@ -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 ( - - ); -}; - -MuteButton.propTypes = { - className: PropTypes.string, - muted: PropTypes.bool, - volume: PropTypes.number, - onMuteRequested: PropTypes.func, - onUnmuteRequested: PropTypes.func -}; - -module.exports = MuteButton; diff --git a/src/routes/Player/ControlBar/MuteButton/index.js b/src/routes/Player/ControlBar/MuteButton/index.js deleted file mode 100644 index 3bc5c743b..000000000 --- a/src/routes/Player/ControlBar/MuteButton/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const MuteButton = require('./MuteButton'); - -module.exports = MuteButton; diff --git a/src/routes/Player/ControlBar/PlayPauseButton/PlayPauseButton.js b/src/routes/Player/ControlBar/PlayPauseButton/PlayPauseButton.js deleted file mode 100644 index 34d9bbd7f..000000000 --- a/src/routes/Player/ControlBar/PlayPauseButton/PlayPauseButton.js +++ /dev/null @@ -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 ( - - ); -}; - -PlayPauseButton.propTypes = { - className: PropTypes.string, - paused: PropTypes.bool, - onPlayRequested: PropTypes.func, - onPauseRequested: PropTypes.func -}; - -module.exports = PlayPauseButton; diff --git a/src/routes/Player/ControlBar/PlayPauseButton/index.js b/src/routes/Player/ControlBar/PlayPauseButton/index.js deleted file mode 100644 index cdaf43c88..000000000 --- a/src/routes/Player/ControlBar/PlayPauseButton/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const PlayPauseButton = require('./PlayPauseButton'); - -module.exports = PlayPauseButton; diff --git a/src/routes/Player/ControlBar/SubtitlesButton/SubtitlesButton.js b/src/routes/Player/ControlBar/SubtitlesButton/SubtitlesButton.js deleted file mode 100644 index 891247025..000000000 --- a/src/routes/Player/ControlBar/SubtitlesButton/SubtitlesButton.js +++ /dev/null @@ -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 ( - - ); -}; - -SubtitlesButton.propTypes = { - className: PropTypes.string, - subtitlesTracks: PropTypes.array, - onToggleSubtitlesPicker: PropTypes.func -}; - -module.exports = SubtitlesButton; diff --git a/src/routes/Player/ControlBar/SubtitlesButton/index.js b/src/routes/Player/ControlBar/SubtitlesButton/index.js deleted file mode 100644 index 53fd48771..000000000 --- a/src/routes/Player/ControlBar/SubtitlesButton/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const SubtitlesButton = require('./SubtitlesButton'); - -module.exports = SubtitlesButton; diff --git a/src/routes/Player/ControlBar/styles.less b/src/routes/Player/ControlBar/styles.less index 5fa5ae688..8dd80785f 100644 --- a/src/routes/Player/ControlBar/styles.less +++ b/src/routes/Player/ControlBar/styles.less @@ -21,12 +21,12 @@ align-items: center; &:global(.disabled) { - :global(.icon) { + .icon { fill: @color-surface; } } - :global(.icon) { + .icon { flex: none; width: 3rem; height: 2rem; diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index fcc1d0f73..4bd2f9390 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -18,17 +18,26 @@ const Player = ({ urlParams }) => { const { core } = useServices(); const [player, updateLibraryItemState, pushToLibrary] = usePlayer(urlParams); 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 toast = useToast(); const [, , , toggleFullscreen] = useFullscreen(); const [immersed, setImmersed] = React.useState(true); 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 [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( (videoState, nextVideoState) => ({ ...videoState, ...nextVideoState }), { @@ -150,8 +159,8 @@ const Player = ({ urlParams }) => { toggleFullscreen(); }, [toggleFullscreen]); const onContainerMouseDown = React.useCallback((event) => { - if (!event.nativeEvent.subtitlesPickerClosePrevented) { - closeSubtitlesPicker(); + if (!event.nativeEvent.subtitlesMenuClosePrevented) { + closeSubtitlesMenu(); } if (!event.nativeEvent.infoMenuClosePrevented) { closeInfoMenu(); @@ -239,7 +248,7 @@ const Player = ({ urlParams }) => { const onKeyDown = (event) => { switch (event.code) { case 'Space': { - if (!subtitlesPickerOpen && !infoMenuOpen && videoState.paused !== null) { + if (!subtitlesMenuOpen && !infoMenuOpen && videoState.paused !== null) { if (videoState.paused) { onPlayRequested(); } else { @@ -250,28 +259,28 @@ const Player = ({ urlParams }) => { break; } case 'ArrowRight': { - if (!subtitlesPickerOpen && !infoMenuOpen && videoState.time !== null) { + if (!subtitlesMenuOpen && !infoMenuOpen && videoState.time !== null) { onSeekRequested(videoState.time + 15000); } break; } case 'ArrowLeft': { - if (!subtitlesPickerOpen && !infoMenuOpen && videoState.time !== null) { + if (!subtitlesMenuOpen && !infoMenuOpen && videoState.time !== null) { onSeekRequested(videoState.time - 15000); } break; } case 'ArrowUp': { - if (!subtitlesPickerOpen && !infoMenuOpen && videoState.volume !== null) { + if (!subtitlesMenuOpen && !infoMenuOpen && videoState.volume !== null) { onVolumeChangeRequested(videoState.volume + 5); } break; } case 'ArrowDown': { - if (!subtitlesPickerOpen && !infoMenuOpen && videoState.volume !== null) { + if (!subtitlesMenuOpen && !infoMenuOpen && videoState.volume !== null) { onVolumeChangeRequested(videoState.volume - 5); } @@ -279,18 +288,22 @@ const Player = ({ urlParams }) => { } case 'KeyS': { closeInfoMenu(); - toggleSubtitlesPicker(); + if (Array.isArray(videoState.subtitlesTracks) && videoState.subtitlesTracks.length > 0) { + toggleSubtitlesMenu(); + } + break; } case 'KeyM': { - closeSubtitlesPicker(); - if (infoAvailable) { + closeSubtitlesMenu(); + if (typeof metaItem === 'object' && metaItem !== null && typeof stream === 'object' && stream !== null) { toggleInfoMenu(); } + break; } case 'Escape': { - closeSubtitlesPicker(); + closeSubtitlesMenu(); closeInfoMenu(); break; } @@ -302,7 +315,7 @@ const Player = ({ urlParams }) => { return () => { 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(() => { return () => { setImmersedDebounced.cancel(); @@ -311,7 +324,7 @@ const Player = ({ urlParams }) => { }; }, []); return ( -
{ onDoubleClick={onVideoDoubleClick} /> { - subtitlesPickerOpen || infoMenuOpen ? + subtitlesMenuOpen || infoMenuOpen ?
: null @@ -370,20 +383,21 @@ const Player = ({ urlParams }) => { volume={videoState.volume} muted={videoState.muted} subtitlesTracks={videoState.subtitlesTracks} - infoAvailable={infoAvailable} + stream={stream} + metaItem={metaItem} onPlayRequested={onPlayRequested} onPauseRequested={onPauseRequested} onMuteRequested={onMuteRequested} onUnmuteRequested={onUnmuteRequested} onVolumeChangeRequested={onVolumeChangeRequested} onSeekRequested={onSeekRequested} - onToggleSubtitlesPicker={toggleSubtitlesPicker} + onToggleSubtitlesMenu={toggleSubtitlesMenu} onToggleInfoMenu={toggleInfoMenu} onMouseMove={onBarMouseMove} onMouseOver={onBarMouseMove} /> { - subtitlesPickerOpen ? + subtitlesMenuOpen ? { []; }, [props.tracks, selectedLanguage]); const onMouseDown = React.useCallback((event) => { - event.nativeEvent.subtitlesPickerClosePrevented = true; + event.nativeEvent.subtitlesMenuClosePrevented = true; }, []); const languageOnClick = React.useCallback((event) => { const trackId = Array.isArray(props.tracks) ?