Ott 700 play next prev episodes (#271)

* fix(700): fixed useObjectState hook types

* feat(700): added play prev/next episode buttons
keep-around/af30b88d367751c9e05a735e4a0467a96238ef47
Mirlan 5 years ago committed by GitHub
parent 53fe8601c4
commit 7c0a75d950
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      src/features/MultiSourcePlayer/hooks/index.tsx
  2. 32
      src/features/MultiSourcePlayer/hooks/usePlayingHandlers.tsx
  3. 18
      src/features/MultiSourcePlayer/index.tsx
  4. 12
      src/features/StreamPlayer/styled.tsx
  5. 14
      src/hooks/useObjectState.tsx

@ -55,6 +55,7 @@ export const useMultiSourcePlayer = ({
onProgressChange: onProgressChangeCallback, onProgressChange: onProgressChangeCallback,
resumeFrom, resumeFrom,
}: Props) => { }: Props) => {
const numberOfChapters = size(chapters)
const [ const [
{ {
activeChapterIndex, activeChapterIndex,
@ -69,10 +70,12 @@ export const useMultiSourcePlayer = ({
const videoRef = useRef<HTMLVideoElement>(null) const videoRef = useRef<HTMLVideoElement>(null)
const { const {
onReady, onReady,
playNextChapter,
playPrevChapter,
startPlaying, startPlaying,
stopPlaying, stopPlaying,
togglePlaying, togglePlaying,
} = usePlayingHandlers(setPlayerState) } = usePlayingHandlers(setPlayerState, numberOfChapters)
const { const {
selectedQuality, selectedQuality,
@ -105,16 +108,6 @@ export const useMultiSourcePlayer = ({
setSelectedQuality(quality) setSelectedQuality(quality)
} }
const playNextChapter = useCallback(() => {
const nextIndex = (activeChapterIndex + 1) % size(chapters)
setPlayerState({
activeChapterIndex: nextIndex,
loadedProgress: 0,
playedProgress: 0,
playing: nextIndex !== 0,
})
}, [activeChapterIndex, chapters, setPlayerState])
const onPlayerClick = (e: MouseEvent<HTMLDivElement>) => { const onPlayerClick = (e: MouseEvent<HTMLDivElement>) => {
if (e.target === videoRef.current) { if (e.target === videoRef.current) {
togglePlaying() togglePlaying()
@ -168,6 +161,8 @@ export const useMultiSourcePlayer = ({
activeSrc: getActiveChapterUrl(), activeSrc: getActiveChapterUrl(),
chapters, chapters,
duration, duration,
isFirstChapterPlaying: activeChapterIndex === 0,
isLastChapterPlaying: activeChapterIndex === numberOfChapters - 1,
loadedProgress, loadedProgress,
onError: handleError, onError: handleError,
onLoadedProgress, onLoadedProgress,
@ -177,6 +172,7 @@ export const useMultiSourcePlayer = ({
onQualitySelect, onQualitySelect,
onReady, onReady,
playNextChapter, playNextChapter,
playPrevChapter,
playedProgress, playedProgress,
playing, playing,
seek, seek,

@ -4,7 +4,10 @@ import { SetPartialState } from 'hooks'
import { PlayerState } from '.' import { PlayerState } from '.'
export const usePlayingHandlers = (setPlayerState: SetPartialState<PlayerState>) => { export const usePlayingHandlers = (
setPlayerState: SetPartialState<PlayerState>,
numberOfChapters: number,
) => {
const onReady = useCallback(() => { const onReady = useCallback(() => {
setPlayerState((state) => ( setPlayerState((state) => (
state.ready state.ready
@ -33,8 +36,35 @@ export const usePlayingHandlers = (setPlayerState: SetPartialState<PlayerState>)
)) ))
}, [setPlayerState]) }, [setPlayerState])
const playNextChapter = useCallback(() => {
setPlayerState((state) => {
if (!state.ready) return state
const isLastChapter = state.activeChapterIndex + 1 === numberOfChapters
return {
activeChapterIndex: isLastChapter ? 0 : state.activeChapterIndex + 1,
loadedProgress: 0,
playedProgress: 0,
playing: isLastChapter ? false : state.playing,
}
})
}, [numberOfChapters, setPlayerState])
const playPrevChapter = useCallback(() => {
setPlayerState((state) => {
if (!state.ready || state.activeChapterIndex === 0) return state
return {
activeChapterIndex: state.activeChapterIndex - 1,
loadedProgress: 0,
playedProgress: 0,
}
})
}, [setPlayerState])
return { return {
onReady, onReady,
playNextChapter,
playPrevChapter,
startPlaying, startPlaying,
stopPlaying, stopPlaying,
togglePlaying, togglePlaying,

@ -4,6 +4,8 @@ import {
Controls, Controls,
PlayStop, PlayStop,
Fullscreen, Fullscreen,
Next,
Prev,
} from 'features/StreamPlayer/styled' } from 'features/StreamPlayer/styled'
import { VideoPlayer } from 'features/VideoPlayer' import { VideoPlayer } from 'features/VideoPlayer'
@ -18,7 +20,9 @@ export const MultiSourcePlayer = (props: Props) => {
activeSrc, activeSrc,
chapters, chapters,
duration, duration,
isFirstChapterPlaying,
isFullscreen, isFullscreen,
isLastChapterPlaying,
loadedProgress, loadedProgress,
muted, muted,
onError, onError,
@ -34,6 +38,7 @@ export const MultiSourcePlayer = (props: Props) => {
playedProgress, playedProgress,
playing, playing,
playNextChapter, playNextChapter,
playPrevChapter,
seek, seek,
selectedQuality, selectedQuality,
togglePlaying, togglePlaying,
@ -64,7 +69,18 @@ export const MultiSourcePlayer = (props: Props) => {
onReady={onReady} onReady={onReady}
/> />
<Controls> <Controls>
<PlayStop onClick={togglePlaying} playing={playing} /> <Prev
disabled={isFirstChapterPlaying}
onClick={playPrevChapter}
/>
<PlayStop
playing={playing}
onClick={togglePlaying}
/>
<Next
disabled={isLastChapterPlaying}
onClick={playNextChapter}
/>
<VolumeBar <VolumeBar
value={volumeInPercent} value={volumeInPercent}
muted={muted} muted={muted}

@ -69,11 +69,21 @@ export const PlayStop = styled(ButtonBase)<PlayStopProps>`
)}; )};
` `
export const Prev = styled(ButtonBase)` type PrevProps = {
disabled?: boolean,
}
export const Prev = styled(ButtonBase)<PrevProps>`
width: 29px; width: 29px;
height: 28px; height: 28px;
margin-right: 19px; margin-right: 19px;
background-image: url(/images/player-prev.svg); background-image: url(/images/player-prev.svg);
${({ disabled }) => (
disabled
? 'opacity: 0.5;'
: ''
)}
` `
export const Next = styled(Prev)` export const Next = styled(Prev)`

@ -1,25 +1,25 @@
import type { Dispatch, SetStateAction } from 'react' import type { Dispatch } from 'react'
import { useCallback, useState } from 'react' import { useCallback, useState } from 'react'
import isFunction from 'lodash/isFunction' import isFunction from 'lodash/isFunction'
type Updater<T> = (prevState: T) => T type Updater<S> = (prevState: S) => Partial<S>
const isUpdater = <T extends object>(value: any): value is Updater<T> => ( const isUpdater = <S extends object>(value: any): value is Updater<S> => (
isFunction(value) isFunction(value)
) )
/** /**
* Дженерик для создания типа сеттера, получает тип стейта как параметр * Дженерик для создания типа сеттера, получает тип стейта как параметр
*/ */
export type SetPartialState<T> = Dispatch<SetStateAction<Partial<T>>> export type SetPartialState<S> = Dispatch<Partial<S> | Updater<S>>
/** /**
* Хук на основе useState с возможносьтю мержа стейта как в классовых компонентах * Хук на основе useState с возможносьтю мержа стейта как в классовых компонентах
*/ */
export const useObjectState = <T extends object>(initialState: T) => { export const useObjectState = <S extends object>(initialState: S) => {
const [state, setState] = useState(initialState) const [state, setState] = useState(initialState)
const setPlayerState: SetPartialState<T> = useCallback((newStateOrUpdater) => { const setPartialState: SetPartialState<S> = useCallback((newStateOrUpdater) => {
setState((oldState) => { setState((oldState) => {
const newState = isUpdater(newStateOrUpdater) const newState = isUpdater(newStateOrUpdater)
? newStateOrUpdater(oldState) ? newStateOrUpdater(oldState)
@ -32,5 +32,5 @@ export const useObjectState = <T extends object>(initialState: T) => {
}) })
}, []) }, [])
return [state, setPlayerState] as const return [state, setPartialState] as const
} }

Loading…
Cancel
Save