Compare commits

...

5 Commits

Author SHA1 Message Date
f28b5b1c50 remove text output debug 2019-12-22 19:28:58 +01:00
2e4cdbe67b Add more sentence ending punctuation 2019-12-22 19:28:33 +01:00
f87acd5514 Add paginated outputText 2019-12-22 19:24:29 +01:00
797ef6a1fa Add reselect devtools 2019-12-22 19:02:10 +01:00
247ba964ec remove console logging 2019-12-22 18:30:19 +01:00
10 changed files with 91 additions and 34 deletions

8
package-lock.json generated
View File

@ -9796,6 +9796,14 @@
"resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz", "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz",
"integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==" "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA=="
}, },
"reselect-tools": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/reselect-tools/-/reselect-tools-0.0.7.tgz",
"integrity": "sha512-+RGguS8ph21y04l6YwQwL+VfJ/c0qyZKCkhCd5ZwbNJ/lklsJml3CIim+uaG/t+7jYZQcwDW4bk5+VzTeuzwtw==",
"requires": {
"reselect": "4.0.0"
}
},
"resolve": { "resolve": {
"version": "1.13.1", "version": "1.13.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz",

View File

@ -24,7 +24,8 @@
"react-redux": "^7.1.3", "react-redux": "^7.1.3",
"redux": "^4.0.4", "redux": "^4.0.4",
"regenerator-runtime": "^0.13.3", "regenerator-runtime": "^0.13.3",
"reselect": "^4.0.0" "reselect": "^4.0.0",
"reselect-tools": "0.0.7"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.7.5", "@babel/core": "^7.7.5",

View File

@ -4,8 +4,7 @@ import { useSelector, useDispatch } from 'react-redux'
import { import {
selectHasNextSegment, selectHasNextSegment,
selectRunning, selectRunning,
selectInterval, selectInterval
selectCurrentSegment
} from '../store/selectors' } from '../store/selectors'
import { incrementSegment, stop, pause, start } from '../store/actions' import { incrementSegment, stop, pause, start } from '../store/actions'
import { FiPlay, FiPause, FiSquare } from 'react-icons/fi' import { FiPlay, FiPause, FiSquare } from 'react-icons/fi'
@ -17,8 +16,6 @@ export const PlayerControl = () => {
const running = useSelector(selectRunning) const running = useSelector(selectRunning)
const hasNext = useSelector(selectHasNextSegment) const hasNext = useSelector(selectHasNextSegment)
const interval = useSelector(selectInterval) const interval = useSelector(selectInterval)
const segment = useSelector(selectCurrentSegment)
console.log(interval, segment)
useInterval( useInterval(
() => { () => {

View File

@ -30,7 +30,9 @@ export const RsvpReader = () => {
<Options></Options> <Options></Options>
<TotalTime /> <TotalTime />
</div> </div>
<div className={styles.item}>{/* <TextOutput /> */}</div> <div className={styles.item}>
<TextOutput />
</div>
</div> </div>
) )
} }

View File

@ -1,5 +1,5 @@
.current { .current {
text-decoration: underline; background-color: yellow;
} }
.sentenceBeginning { .sentenceBeginning {

View File

@ -5,38 +5,45 @@ import classNames from 'classnames'
import { getNextSmallerNumber } from '../lib/array-util.js' import { getNextSmallerNumber } from '../lib/array-util.js'
import { import {
selectParsedText, selectParsedText,
selectCurrentSegmentIndex selectCurrentSegmentIndex,
selectDisplayMode,
selectSegmentWindow
} from '../store/selectors.js' } from '../store/selectors.js'
import styles from './TextOutput.css' import styles from './TextOutput.css'
export const TextOutput = () => { export const TextOutput = () => {
const { segments, sentences, words } = useSelector(selectParsedText) const { segments, offset } = useSelector(selectSegmentWindow)
const { sentences, words } = useSelector(selectParsedText)
const curSegment = useSelector(selectCurrentSegmentIndex) const curSegment = useSelector(selectCurrentSegmentIndex)
const mode = useSelector(selectDisplayMode)
return ( return (
<div> <>
{segments.map((segment, idx) => { <div>
const isCurrent = curSegment === idx {segments.map((segment, idx) => {
const isWordStart = words.includes(idx) idx = idx + offset
const wordBeginning = isWordStart const isCurrent = curSegment === idx
? idx const isWordStart = words.includes(idx)
: getNextSmallerNumber(idx, words) const wordBeginning = isWordStart
const isSentenceStart = sentences.includes(wordBeginning) ? idx
: getNextSmallerNumber(idx, words)
const isSentenceStart = sentences.includes(wordBeginning)
return ( return (
<span key={idx}> <span key={idx}>
{isWordStart && ' '} {isWordStart && ' '}
<span <span
className={classNames({ className={classNames({
[styles.current]: isCurrent, [styles.current]: isCurrent,
[styles.sentenceBeginning]: isSentenceStart [styles.sentenceBeginning]: isSentenceStart
})} })}
> >
{segment} {segment}
</span>
</span> </span>
</span> )
) })}
})} </div>
</div> </>
) )
} }

View File

@ -1,3 +1,5 @@
const sentenceEndings = '.!?:;'
/** /**
* Returns an object containing the segmented text and metainfo about word and * Returns an object containing the segmented text and metainfo about word and
* sentence beginnings * sentence beginnings
@ -24,7 +26,9 @@ export function parseText(text, maxLength) {
curIdx += fragments.length curIdx += fragments.length
// set flag if next word is sentence beginning // set flag if next word is sentence beginning
sentenceFlag = word.endsWith('.') sentenceFlag = sentenceEndings
.split('')
.some(ending => word.endsWith(ending))
} }
return { segments, words, sentences } return { segments, words, sentences }

View File

@ -1,8 +1,14 @@
import { createStore } from 'redux' import { createStore } from 'redux'
import { registerSelectors, getStateWith } from 'reselect-tools'
import { reducerFn, initialState } from './reducer' import { reducerFn, initialState } from './reducer'
import * as selectors from './selectors'
export const store = createStore( export const store = createStore(
reducerFn, reducerFn,
initialState, initialState,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
) )
registerSelectors(selectors)
getStateWith(() => store.getState())

View File

@ -15,7 +15,15 @@ export const initialState = {
wpm: 300, wpm: 300,
offset: -15, offset: -15,
running: false, running: false,
lang: 'en' lang: 'en',
textDisplay: {
mode: 'pagination',
options: {
pagination: { pageLength: 50 },
segments: { prev: 9, next: 40 },
sentences: { prev: 1, next: 8 }
}
}
} }
const reducer = { const reducer = {

View File

@ -11,9 +11,10 @@ const notNull = val => val != null
// parsedText selectors // parsedText selectors
export const selectMaxLength = state => state.maxLength export const selectMaxLength = state => state.maxLength
export const selectOriginalText = state => state.originalText
export const selectParsedText = createSelector( export const selectParsedText = createSelector(
state => state.originalText, selectOriginalText,
selectMaxLength, selectMaxLength,
(originalText, maxLength) => parseText(originalText, maxLength) (originalText, maxLength) => parseText(originalText, maxLength)
) )
@ -166,3 +167,26 @@ export const selectTotalTime = createSelector(selectIntervals, intervals =>
// player // player
export const selectRunning = state => state.running export const selectRunning = state => state.running
// text display
export const selectDisplayMode = state => state.textDisplay.mode
export const selectDisplayOptions = state => state.textDisplay.options
export const selectCurrentDisplayOptions = createSelector(
selectDisplayMode,
selectDisplayOptions,
(mode, options) => options[mode]
)
export const selectSegmentWindow = createSelector(
selectDisplayMode,
selectCurrentDisplayOptions,
selectCurrentSegmentIndex,
selectSegments,
(mode, options, idx, segments) => {
const page = Math.floor(idx / options.pageLength)
const start = page * options.pageLength
const end = page * options.pageLength + options.pageLength
return { offset: start, segments: segments.slice(start, end) }
}
)