From 7c0a75d950fa2164cb9c0368e542ba8a313cfb54 Mon Sep 17 00:00:00 2001 From: Mirlan Date: Thu, 31 Dec 2020 17:43:34 +0600 Subject: [PATCH] Ott 700 play next prev episodes (#271) * fix(700): fixed useObjectState hook types * feat(700): added play prev/next episode buttons --- .../MultiSourcePlayer/hooks/index.tsx | 18 ++++------- .../hooks/usePlayingHandlers.tsx | 32 ++++++++++++++++++- src/features/MultiSourcePlayer/index.tsx | 18 ++++++++++- src/features/StreamPlayer/styled.tsx | 12 ++++++- src/hooks/useObjectState.tsx | 14 ++++---- 5 files changed, 73 insertions(+), 21 deletions(-) diff --git a/src/features/MultiSourcePlayer/hooks/index.tsx b/src/features/MultiSourcePlayer/hooks/index.tsx index f8e3a8a1..f5658c32 100644 --- a/src/features/MultiSourcePlayer/hooks/index.tsx +++ b/src/features/MultiSourcePlayer/hooks/index.tsx @@ -55,6 +55,7 @@ export const useMultiSourcePlayer = ({ onProgressChange: onProgressChangeCallback, resumeFrom, }: Props) => { + const numberOfChapters = size(chapters) const [ { activeChapterIndex, @@ -69,10 +70,12 @@ export const useMultiSourcePlayer = ({ const videoRef = useRef(null) const { onReady, + playNextChapter, + playPrevChapter, startPlaying, stopPlaying, togglePlaying, - } = usePlayingHandlers(setPlayerState) + } = usePlayingHandlers(setPlayerState, numberOfChapters) const { selectedQuality, @@ -105,16 +108,6 @@ export const useMultiSourcePlayer = ({ 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) => { if (e.target === videoRef.current) { togglePlaying() @@ -168,6 +161,8 @@ export const useMultiSourcePlayer = ({ activeSrc: getActiveChapterUrl(), chapters, duration, + isFirstChapterPlaying: activeChapterIndex === 0, + isLastChapterPlaying: activeChapterIndex === numberOfChapters - 1, loadedProgress, onError: handleError, onLoadedProgress, @@ -177,6 +172,7 @@ export const useMultiSourcePlayer = ({ onQualitySelect, onReady, playNextChapter, + playPrevChapter, playedProgress, playing, seek, diff --git a/src/features/MultiSourcePlayer/hooks/usePlayingHandlers.tsx b/src/features/MultiSourcePlayer/hooks/usePlayingHandlers.tsx index 03e377b7..642f7094 100644 --- a/src/features/MultiSourcePlayer/hooks/usePlayingHandlers.tsx +++ b/src/features/MultiSourcePlayer/hooks/usePlayingHandlers.tsx @@ -4,7 +4,10 @@ import { SetPartialState } from 'hooks' import { PlayerState } from '.' -export const usePlayingHandlers = (setPlayerState: SetPartialState) => { +export const usePlayingHandlers = ( + setPlayerState: SetPartialState, + numberOfChapters: number, +) => { const onReady = useCallback(() => { setPlayerState((state) => ( state.ready @@ -33,8 +36,35 @@ export const usePlayingHandlers = (setPlayerState: SetPartialState) )) }, [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 { onReady, + playNextChapter, + playPrevChapter, startPlaying, stopPlaying, togglePlaying, diff --git a/src/features/MultiSourcePlayer/index.tsx b/src/features/MultiSourcePlayer/index.tsx index a802f2cd..4c6d5b30 100644 --- a/src/features/MultiSourcePlayer/index.tsx +++ b/src/features/MultiSourcePlayer/index.tsx @@ -4,6 +4,8 @@ import { Controls, PlayStop, Fullscreen, + Next, + Prev, } from 'features/StreamPlayer/styled' import { VideoPlayer } from 'features/VideoPlayer' @@ -18,7 +20,9 @@ export const MultiSourcePlayer = (props: Props) => { activeSrc, chapters, duration, + isFirstChapterPlaying, isFullscreen, + isLastChapterPlaying, loadedProgress, muted, onError, @@ -34,6 +38,7 @@ export const MultiSourcePlayer = (props: Props) => { playedProgress, playing, playNextChapter, + playPrevChapter, seek, selectedQuality, togglePlaying, @@ -64,7 +69,18 @@ export const MultiSourcePlayer = (props: Props) => { onReady={onReady} /> - + + + ` )}; ` -export const Prev = styled(ButtonBase)` +type PrevProps = { + disabled?: boolean, +} + +export const Prev = styled(ButtonBase)` width: 29px; height: 28px; margin-right: 19px; background-image: url(/images/player-prev.svg); + + ${({ disabled }) => ( + disabled + ? 'opacity: 0.5;' + : '' + )} ` export const Next = styled(Prev)` diff --git a/src/hooks/useObjectState.tsx b/src/hooks/useObjectState.tsx index 9e634d89..6b46897e 100644 --- a/src/hooks/useObjectState.tsx +++ b/src/hooks/useObjectState.tsx @@ -1,25 +1,25 @@ -import type { Dispatch, SetStateAction } from 'react' +import type { Dispatch } from 'react' import { useCallback, useState } from 'react' import isFunction from 'lodash/isFunction' -type Updater = (prevState: T) => T -const isUpdater = (value: any): value is Updater => ( +type Updater = (prevState: S) => Partial +const isUpdater = (value: any): value is Updater => ( isFunction(value) ) /** * Дженерик для создания типа сеттера, получает тип стейта как параметр */ -export type SetPartialState = Dispatch>> +export type SetPartialState = Dispatch | Updater> /** * Хук на основе useState с возможносьтю мержа стейта как в классовых компонентах */ -export const useObjectState = (initialState: T) => { +export const useObjectState = (initialState: S) => { const [state, setState] = useState(initialState) - const setPlayerState: SetPartialState = useCallback((newStateOrUpdater) => { + const setPartialState: SetPartialState = useCallback((newStateOrUpdater) => { setState((oldState) => { const newState = isUpdater(newStateOrUpdater) ? newStateOrUpdater(oldState) @@ -32,5 +32,5 @@ export const useObjectState = (initialState: T) => { }) }, []) - return [state, setPlayerState] as const + return [state, setPartialState] as const }