From 6bd4240e5d63956676ba62234bf56d24087fa232 Mon Sep 17 00:00:00 2001 From: Alfred Melch Date: Fri, 13 Dec 2019 02:05:04 +0100 Subject: [PATCH] Working player --- src/components/Player.js | 26 +++++++++++++++++++++ src/components/PlayerControl.js | 40 +++++++++++++++++++++++++++++++++ src/components/RsvpOptions.js | 14 ++++++++++-- src/components/RsvpReader.js | 2 ++ src/store/actions.js | 4 ++++ src/store/reducer.js | 10 +++++++-- src/store/selectors.js | 12 ++++++++++ 7 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 src/components/Player.js create mode 100644 src/components/PlayerControl.js diff --git a/src/components/Player.js b/src/components/Player.js new file mode 100644 index 0000000..f63326d --- /dev/null +++ b/src/components/Player.js @@ -0,0 +1,26 @@ +import React, { useEffect, useState, useCallback } from 'react' + +export const PlayerControl = ({ interval, onTick, onStart, onStop }) => { + const dispatch = useDispatch() + const [isPlaying, setPlaying] = useState(false) + + const [handle, setHandle] = useState(null) + + useEffect(() => { + console.log('effect fired', isPlaying) + clearInterval(handle) + if (isPlaying) { + setHandle(setInterval(() => dispatch(incrementSegment()), 500)) + } + }, [handle, isPlaying]) + + return ( +
+ + + +
playing: {isPlaying.toString()}
+
interval: {handle}
+
+ ) +} diff --git a/src/components/PlayerControl.js b/src/components/PlayerControl.js new file mode 100644 index 0000000..31ac7ad --- /dev/null +++ b/src/components/PlayerControl.js @@ -0,0 +1,40 @@ +import React, { useEffect, useState, useCallback } from 'react' + +import { useSelector, useDispatch } from 'react-redux' +import { selectPlaying, hasNextSegment } from '../store/selectors' +import { start, stop, pause, incrementSegment } from '../store/actions' + +export const PlayerControl = ({ onTick }) => { + const dispatch = useDispatch() + const isPlaying = useSelector(selectPlaying) + const hasNext = useSelector(hasNextSegment) + const wpm = useSelector(state => state.wpm) + + const [handle, setHandle] = useState(null) + + useEffect(() => { + clearInterval(handle) + if (isPlaying) { + setHandle(setInterval(() => dispatch(incrementSegment()), 60000 / wpm)) + } + }, [isPlaying, wpm]) + + useEffect(() => { + if (!hasNext) dispatch(pause()) + }, [hasNext, dispatch]) + + return ( +
+ + {isPlaying && ( + + )}{' '} + {!isPlaying && ( + + )} +
playing: {isPlaying.toString()}
+
interval: {handle}
+
has next: {hasNext.toString()}
+
+ ) +} diff --git a/src/components/RsvpOptions.js b/src/components/RsvpOptions.js index 593f51f..5394ebd 100644 --- a/src/components/RsvpOptions.js +++ b/src/components/RsvpOptions.js @@ -1,11 +1,13 @@ import React from 'react' import { useSelector, useDispatch } from 'react-redux' -import { setMaxLength } from '../store/actions' +import { setMaxLength, setWpm } from '../store/actions' export const RsvpOptions = () => { - const maxLength = useSelector(state => state.maxLength) const dispatch = useDispatch() + const maxLength = useSelector(state => state.maxLength) + const wpm = useSelector(state => state.wpm) + return (
{ onChange={e => dispatch(setMaxLength(e.target.value))} /> {maxLength} + dispatch(setWpm(e.target.value))} + /> + {wpm}
) } diff --git a/src/components/RsvpReader.js b/src/components/RsvpReader.js index 7e1efd4..42095eb 100644 --- a/src/components/RsvpReader.js +++ b/src/components/RsvpReader.js @@ -5,6 +5,7 @@ import { TextOutput } from './TextOutput' import { MainControl } from './MainControl' import { RsvpSegment } from './RsvpSegment' import { RsvpOptions } from './RsvpOptions' +import { PlayerControl } from './PlayerControl' const FlexRow = styled.div` display: flex; @@ -25,6 +26,7 @@ export const RsvpReader = () => { + diff --git a/src/store/actions.js b/src/store/actions.js index 3f1cef8..bc082be 100644 --- a/src/store/actions.js +++ b/src/store/actions.js @@ -9,3 +9,7 @@ export const setMaxLength = length => ({ type: 'SET_MAX_LENGTH', payload: length }) +export const setWpm = wpm => ({ type: 'SET_WPM', payload: wpm }) +export const start = () => ({ type: 'START' }) +export const pause = () => ({ type: 'PAUSE' }) +export const stop = () => ({ type: 'STOP' }) diff --git a/src/store/reducer.js b/src/store/reducer.js index 7d9b4da..0cdabad 100644 --- a/src/store/reducer.js +++ b/src/store/reducer.js @@ -8,7 +8,9 @@ import { export const initialState = { originalText: 'Sample Text', curIdx: 0, - maxLength: 5 + maxLength: 5, + isPlaying: false, + wpm: 300 } const reducer = { @@ -24,7 +26,11 @@ const reducer = { DEC_WORD: state => ({ ...state, curIdx: selectPrevWord(state) }), INC_SENTENCE: state => ({ ...state, curIdx: selectNextSentence(state) }), DEC_SENTENCE: state => ({ ...state, curIdx: selectPrevSentence(state) }), - SET_MAX_LENGTH: (state, payload) => ({ ...state, maxLength: payload }) + SET_MAX_LENGTH: (state, payload) => ({ ...state, maxLength: payload }), + SET_WPM: (state, payload) => ({ ...state, wpm: payload }), + START: state => ({ ...state, isPlaying: true }), + PAUSE: state => ({ ...state, isPlaying: false }), + STOP: state => ({ ...state, isPlaying: false, curIdx: 0 }) } export const reducerFn = (state, { type, payload }) => { diff --git a/src/store/selectors.js b/src/store/selectors.js index 785f98b..fc5aef3 100644 --- a/src/store/selectors.js +++ b/src/store/selectors.js @@ -26,6 +26,14 @@ export const selectCurrentSegment = createSelector( (parsedText, curIdx) => parsedText.segments[curIdx] ) +export const hasNextSegment = createSelector( + selectSegments, + selectCurrentSegmentIndex, + (segments, idx) => { + return idx < segments.length - 1 + } +) + // next/prev words export const selectWords = createSelector( @@ -69,3 +77,7 @@ export const selectPrevSentence = createSelector( export const selectHasNextSentence = createSelector(selectNextSentence, Boolean) export const selectHasPrevSentence = createSelector(selectPrevSentence, Boolean) + +// player + +export const selectPlaying = state => state.isPlaying