diff --git a/src/components/bars/PlayerBar/index.tsx b/src/components/bars/PlayerBar/index.tsx index abc7445e..3c0d91b8 100644 --- a/src/components/bars/PlayerBar/index.tsx +++ b/src/components/bars/PlayerBar/index.tsx @@ -1,26 +1,21 @@ -import React, { FC, useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useState, VFC } from 'react'; import styles from './styles.module.scss'; import { Icon } from '~/components/input/Icon'; -import { PLAYER_STATES } from '~/redux/player/constants'; -import { connect } from 'react-redux'; -import { pick } from 'ramda'; -import { selectPlayer } from '~/redux/player/selectors'; -import * as PLAYER_ACTIONS from '~/redux/player/actions'; -import { IPlayerProgress, Player } from '~/utils/player'; +import { PlayerState } from '~/redux/player/constants'; import { path } from 'ramda'; +import { IPlayerProgress, Player } from '~/utils/player'; import { IFile } from '~/redux/types'; -const mapStateToProps = state => pick(['status', 'file'], selectPlayer(state)); -const mapDispatchToProps = { - playerPlay: PLAYER_ACTIONS.playerPlay, - playerPause: PLAYER_ACTIONS.playerPause, - playerSeek: PLAYER_ACTIONS.playerSeek, - playerStop: PLAYER_ACTIONS.playerStop, -}; +interface Props { + status: PlayerState; + file?: IFile; + playerPlay: () => void; + playerPause: () => void; + playerSeek: (pos: number) => void; + playerStop: () => void; +} -type IProps = ReturnType & typeof mapDispatchToProps & {}; - -const PlayerBarUnconnected: FC = ({ +const PlayerBar: VFC = ({ status, playerPlay, playerPause, @@ -31,7 +26,7 @@ const PlayerBarUnconnected: FC = ({ const [progress, setProgress] = useState({ progress: 0, current: 0, total: 0 }); const onClick = useCallback(() => { - if (status === PLAYER_STATES.PLAYING) return playerPause(); + if (status === PlayerState.PLAYING) return playerPause(); return playerPlay(); }, [playerPlay, playerPause, status]); @@ -61,7 +56,7 @@ const PlayerBarUnconnected: FC = ({ }; }, [onProgress]); - if (status === PLAYER_STATES.UNSET) return null; + if (status === PlayerState.UNSET) return null; const metadata: IFile['metadata'] = path(['metadata'], file); const title = @@ -73,7 +68,7 @@ const PlayerBarUnconnected: FC = ({
- {status === PLAYER_STATES.PLAYING ? : } + {status === PlayerState.PLAYING ? : }
@@ -93,7 +88,4 @@ const PlayerBarUnconnected: FC = ({ ); }; -export const PlayerBar = connect( - mapStateToProps, - mapDispatchToProps -)(PlayerBarUnconnected); +export { PlayerBar }; diff --git a/src/components/media/AudioPlayer/index.tsx b/src/components/media/AudioPlayer/index.tsx index 3364c191..6257837f 100644 --- a/src/components/media/AudioPlayer/index.tsx +++ b/src/components/media/AudioPlayer/index.tsx @@ -3,12 +3,12 @@ import { connect } from 'react-redux'; import { selectPlayer } from '~/redux/player/selectors'; import * as PLAYER_ACTIONS from '~/redux/player/actions'; import { IFile } from '~/redux/types'; -import { PLAYER_STATES } from '~/redux/player/constants'; import { IPlayerProgress, Player } from '~/utils/player'; import classNames from 'classnames'; import styles from './styles.module.scss'; import { Icon } from '~/components/input/Icon'; import { InputText } from '~/components/input/InputText'; +import { PlayerState } from '~/redux/player/constants'; const mapStateToProps = state => ({ player: selectPlayer(state), @@ -52,7 +52,7 @@ const AudioPlayerUnconnected = memo( if (isEditing) return; if (current && current.id === file.id) { - if (status === PLAYER_STATES.PLAYING) return playerPause(); + if (status === PlayerState.PLAYING) return playerPause(); return playerPlay(); } @@ -122,11 +122,7 @@ const AudioPlayerUnconnected = memo( )}
- {playing && status === PLAYER_STATES.PLAYING ? ( - - ) : ( - - )} + {playing && status === PlayerState.PLAYING ? : }
{isEditing ? ( diff --git a/src/containers/main/BottomContainer/index.tsx b/src/containers/main/BottomContainer/index.tsx index a0748775..e303fef0 100644 --- a/src/containers/main/BottomContainer/index.tsx +++ b/src/containers/main/BottomContainer/index.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react'; import styles from './styles.module.scss'; -import { PlayerBar } from '~/components/bars/PlayerBar'; +import { PlayerView } from '~/views/player/PlayerView'; type IProps = {}; @@ -8,7 +8,7 @@ const BottomContainer: FC = () => (
- +
diff --git a/src/redux/player/constants.ts b/src/redux/player/constants.ts index b05a9d94..9bd8d166 100644 --- a/src/redux/player/constants.ts +++ b/src/redux/player/constants.ts @@ -16,8 +16,8 @@ export const PLAYER_ACTIONS = { GET_YOUTUBE_INFO: `${prefix}GET_YOUTUBE_INFO`, }; -export const PLAYER_STATES = { - PLAYING: 'PLAYING', - PAUSED: 'PAUSED', - UNSET: 'UNSET', -}; +export enum PlayerState { + PLAYING = 'PLAYING', + PAUSED = 'PAUSED', + UNSET = 'UNSET', +} diff --git a/src/redux/player/reducer.ts b/src/redux/player/reducer.ts index c0ebba7e..1c478cf2 100644 --- a/src/redux/player/reducer.ts +++ b/src/redux/player/reducer.ts @@ -1,16 +1,16 @@ import { createReducer } from '~/utils/reducer'; import { PLAYER_HANDLERS } from './handlers'; -import { PLAYER_STATES } from './constants'; -import { IFile, IEmbed } from '../types'; +import { PlayerState } from './constants'; +import { IEmbed, IFile } from '../types'; export type IPlayerState = Readonly<{ - status: typeof PLAYER_STATES[keyof typeof PLAYER_STATES]; + status: PlayerState; file?: IFile; youtubes: Record; }>; const INITIAL_STATE: IPlayerState = { - status: PLAYER_STATES.UNSET, + status: PlayerState.UNSET, file: undefined, youtubes: {}, }; diff --git a/src/redux/player/sagas.ts b/src/redux/player/sagas.ts index 97c0a4a1..6e5ec204 100644 --- a/src/redux/player/sagas.ts +++ b/src/redux/player/sagas.ts @@ -1,11 +1,11 @@ -import { takeLatest, put, fork, race, take, delay, call, select } from 'redux-saga/effects'; -import { PLAYER_ACTIONS, PLAYER_STATES } from './constants'; +import { call, delay, fork, put, race, select, take, takeLatest } from 'redux-saga/effects'; +import { PLAYER_ACTIONS, PlayerState } from './constants'; import { - playerSetFile, - playerSeek, - playerSetStatus, playerGetYoutubeInfo, + playerSeek, playerSet, + playerSetFile, + playerSetStatus, } from './actions'; import { Player } from '~/utils/player'; import { getURL } from '~/utils/dom'; @@ -41,7 +41,7 @@ function seekSaga({ seek }: ReturnType) { } function* stoppedSaga() { - yield put(playerSetStatus(PLAYER_STATES.UNSET)); + yield put(playerSetStatus(PlayerState.UNSET)); yield put(playerSetFile(undefined)); } diff --git a/src/utils/hooks/player/usePlayer.ts b/src/utils/hooks/player/usePlayer.ts new file mode 100644 index 00000000..56aba1e8 --- /dev/null +++ b/src/utils/hooks/player/usePlayer.ts @@ -0,0 +1,17 @@ +import { useShallowSelect } from '~/utils/hooks/useShallowSelect'; +import { selectPlayer } from '~/redux/player/selectors'; +import { useCallback } from 'react'; +import { playerPause, playerPlay, playerSeek, playerStop } from '~/redux/player/actions'; +import { useDispatch } from 'react-redux'; + +export const usePlayer = () => { + const { status, file } = useShallowSelect(selectPlayer); + const dispatch = useDispatch(); + + const onPlayerPlay = useCallback(() => dispatch(playerPlay()), [dispatch]); + const onPlayerPause = useCallback(() => dispatch(playerPause()), [dispatch]); + const onPlayerSeek = useCallback((pos: number) => dispatch(playerSeek(pos)), [dispatch]); + const onPlayerStop = useCallback(() => dispatch(playerStop()), [dispatch]); + + return { status, file, onPlayerPlay, onPlayerSeek, onPlayerPause, onPlayerStop }; +}; diff --git a/src/utils/player.ts b/src/utils/player.ts index 82930dc4..67398a27 100644 --- a/src/utils/player.ts +++ b/src/utils/player.ts @@ -1,6 +1,6 @@ import { store } from '~/redux/store'; import { playerSetStatus, playerStopped } from '~/redux/player/actions'; -import { PLAYER_STATES } from '~/redux/player/constants'; +import { PlayerState } from '~/redux/player/constants'; type PlayerEventType = keyof HTMLMediaElementEventMap; @@ -81,10 +81,8 @@ export class PlayerClass { const Player = new PlayerClass(); -// Player.element.addEventListener('playprogress', ({ detail }: CustomEvent) => console.log(detail)); - -Player.on('play', () => store.dispatch(playerSetStatus(PLAYER_STATES.PLAYING))); -Player.on('pause', () => store.dispatch(playerSetStatus(PLAYER_STATES.PAUSED))); +Player.on('play', () => store.dispatch(playerSetStatus(PlayerState.PLAYING))); +Player.on('pause', () => store.dispatch(playerSetStatus(PlayerState.PAUSED))); Player.on('stop', () => store.dispatch(playerStopped())); Player.on('error', () => store.dispatch(playerStopped())); diff --git a/src/views/player/PlayerView/index.tsx b/src/views/player/PlayerView/index.tsx new file mode 100644 index 00000000..b7ba2824 --- /dev/null +++ b/src/views/player/PlayerView/index.tsx @@ -0,0 +1,22 @@ +import React, { VFC } from 'react'; +import { PlayerBar } from '~/components/bars/PlayerBar'; +import { usePlayer } from '~/utils/hooks/player/usePlayer'; + +interface PlayerViewProps {} + +const PlayerView: VFC = () => { + const { status, file, onPlayerSeek, onPlayerStop, onPlayerPause, onPlayerPlay } = usePlayer(); + + return ( + + ); +}; + +export { PlayerView };