Skip to content
This repository has been archived by the owner on May 24, 2021. It is now read-only.

Commit

Permalink
Merge pull request #492 from alexander-heimbuch/chore/refactor-store
Browse files Browse the repository at this point in the history
chore(store): Refactor store and effects
  • Loading branch information
alexander-heimbuch authored Jan 14, 2018
2 parents e1114ab + 5b670b4 commit c6262cd
Show file tree
Hide file tree
Showing 211 changed files with 2,494 additions and 2,621 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"normalize.css": "6.0.0",
"query-string": "4.3.1",
"redux": "3.5.2",
"redux-actions": "^2.2.1",
"revue": "3.0.0",
"scroll-into-view": "^1.9.1",
"scroll-into-view-if-needed": "^1.2.8",
Expand Down
54 changes: 54 additions & 0 deletions src/effects/chapters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { get } from 'lodash'
import { getOr, compose } from 'lodash/fp'

import { currentChapter, currentChapterIndex } from 'utils/chapters'
import { handleActions } from 'utils/effects'

import actions from 'store/actions'

import { PREVIOUS_CHAPTER, NEXT_CHAPTER, SET_CHAPTER, SET_PLAYTIME, UPDATE_PLAYTIME } from 'store/types'

const chapterIndexFromState = compose(
currentChapterIndex,
getOr([], 'chapters')
)

const currentChapterFromState = compose(
currentChapter,
getOr([], 'chapters')
)

const chapterUpdate = ({ dispatch }, { payload }, state) => {
const ghost = get(state, 'ghost', {})

!ghost.active && dispatch(actions.updateChapter(payload))
}

export default handleActions({
[PREVIOUS_CHAPTER]: ({ dispatch }, action, state) => {
const index = chapterIndexFromState(state)
const current = currentChapterFromState(state)

dispatch(actions.updatePlaytime(index === 0 ? 0 : current.start))
},

[NEXT_CHAPTER]: ({ dispatch }, action, state) => {
const index = chapterIndexFromState(state)
const duration = get(state, 'duration', 0)
const playtime = get(state, 'playtime', 0)
const chapters = get(state, 'chapters', [])
const current = currentChapterFromState(state)

const chapterStart = (index === chapters.length - 1 && playtime >= current.start) ? duration : current.start

dispatch(actions.updatePlaytime(chapterStart))
},

[SET_CHAPTER]: ({ dispatch }, action, state) => {
const current = currentChapterFromState(state)
dispatch(actions.updatePlaytime(current.start))
},

[SET_PLAYTIME]: chapterUpdate,
[UPDATE_PLAYTIME]: chapterUpdate
})
File renamed without changes.
96 changes: 96 additions & 0 deletions src/effects/components/episode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { get, noop } from 'lodash'

import actions from 'store/actions'
import { INIT, LOADING, LOADED, PLAY, PAUSE, IDLE, SET_TRANSCRIPTS, END, NETWORK_EMPTY, NETWORK_NO_SOURCE, ERROR_MISSING_AUDIO_FILES } from 'store/types'

import { handleActions } from 'utils/effects'

const hasChapters = chapters => chapters.length > 0
const hasMeta = (show, episode) => episode.poster || show.poster || show.title || episode.title || episode.subtitle
const hasFiles = files => files.length > 0

const networkError = ({ dispatch }) => {
dispatch(actions.toggleInfo(false))
dispatch(actions.toggleError(true))
dispatch(actions.showRetryButton())
dispatch(actions.toggleProgressBar(false))
dispatch(actions.toggleChapterControls(false))
dispatch(actions.toggleSteppersControls(false))
}

export default handleActions({
[INIT]: ({ dispatch }, action, state) => {
const chapters = get(state, 'chapters', [])
const downloadFiles = get(state, 'download.files', [])
const episode = get(state, 'episode', {})
const show = get(state, 'show', {})
const runtime = get(state, 'runtime', {})

// Tabs
if (hasChapters(chapters)) {
dispatch(actions.toggleComponentTab('chapters', true))
}

if (hasFiles(downloadFiles)) {
dispatch(actions.toggleComponentTab('download', true))
}

// Meta
if (hasMeta(show, episode)) {
dispatch(actions.toggleInfo(true))
}

// Audio Modifiers
if (runtime.platform === 'desktop') {
dispatch(actions.toggleVolumeSlider(true))
}

// Everything else without conditions
dispatch(actions.toggleComponentTab('share', true))
dispatch(actions.toggleComponentTab('info', true))
dispatch(actions.toggleComponentTab('audio', true))
dispatch(actions.toggleRateSlider(true))
dispatch(actions.toggleInfoPoster(true))
},

[LOADING]: ({ dispatch }) => dispatch(actions.showLoadingButton()),

[LOADED]: ({ dispatch }, { payload }) => payload.paused ? dispatch(actions.showPauseButton()) : dispatch(actions.showPlayingButton()),

[PLAY]: ({ dispatch }) => {
// Default behaviour
dispatch(actions.showPlayingButton())
dispatch(actions.toggleProgressBar(true))
dispatch(actions.toggleChapterControls(true))
dispatch(actions.toggleSteppersControls(true))

// Error Fallbacks
dispatch(actions.toggleInfo(true))
dispatch(actions.toggleError(false))
},

[PAUSE]: ({ dispatch }) => dispatch(actions.showPauseButton()),

[IDLE]: ({ dispatch }) => {
dispatch(actions.showPauseButton())
dispatch(actions.toggleChapterControls(true))
dispatch(actions.toggleSteppersControls(true))
dispatch(actions.toggleProgressBar(true))
},

[SET_TRANSCRIPTS]: ({ dispatch }, { payload }) => payload.length > 0 ? dispatch(actions.toggleComponentTab('transcripts', true)) : noop,

[END]: ({ dispatch }) => dispatch(actions.showReplayButton()),

[NETWORK_EMPTY]: networkError,
[NETWORK_NO_SOURCE]: networkError,

[ERROR_MISSING_AUDIO_FILES]: ({ dispatch }) => {
dispatch(actions.toggleInfo(false))
dispatch(actions.toggleError(true))
dispatch(actions.toggleButtonControl(false))
dispatch(actions.toggleProgressBar(false))
dispatch(actions.toggleChapterControls(false))
dispatch(actions.toggleSteppersControls(false))
}
})
File renamed without changes.
62 changes: 62 additions & 0 deletions src/effects/components/live.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { get } from 'lodash'

import { handleActions } from 'utils/effects'

import actions from 'store/actions'
import { INIT, LOADING, LOADED, PAUSE, PLAY, IDLE, NETWORK_EMPTY, NETWORK_NO_SOURCE, ERROR_MISSING_AUDIO_FILES } from 'store/types'

const hasMeta = (show, episode) => episode.poster || show.poster || show.title || episode.title || episode.subtitle

export default handleActions({
[INIT]: ({ dispatch }, action, state) => {
const episode = get(state, 'episode', {})
const show = get(state, 'show', {})
const runtime = get(state, 'runtime', {})

// Meta
if (hasMeta(show, episode)) {
dispatch(actions.toggleInfo(true))
}

// Audio Modifiers
if (runtime.platform === 'desktop') {
dispatch(actions.toggleVolumeSlider(true))
}

// Everything else without conditions
dispatch(actions.toggleComponentTab('info', true))
dispatch(actions.toggleComponentTab('audio', true))
dispatch(actions.toggleInfoPoster(true))
dispatch(actions.showPauseButton())
},

[LOADING]: ({ dispatch }) => dispatch(actions.showLoadingButton()),
[LOADED]: ({ dispatch }, { payload }) => payload.paused ? dispatch(actions.showPauseButton()) : dispatch(actions.showPlayingButton()),

[PLAY]: ({ dispatch }) => {
// Default behaviour
dispatch(actions.showPlayingButton())

// Error Fallbacks
dispatch(actions.toggleInfo(true))
dispatch(actions.toggleError(false))
},

[PAUSE]: ({ dispatch }) => dispatch(actions.showPauseButton()),

[IDLE]: ({ dispatch }) => {
dispatch(actions.showPauseButton())
dispatch(actions.toggleChapterControls(true))
dispatch(actions.toggleSteppersControls(true))
dispatch(actions.toggleProgressBar(true))
},

[NETWORK_EMPTY]: ({ dispatch }) => dispatch(actions.showRetryButton()),
[NETWORK_NO_SOURCE]: ({ dispatch }) => dispatch(actions.showRetryButton()),

[ERROR_MISSING_AUDIO_FILES]: ({ dispatch }) => {
dispatch(actions.toggleInfo(false))
dispatch(actions.toggleError(true))
dispatch(actions.toggleButtonControl(false))
}
})
20 changes: 10 additions & 10 deletions src/store/effects/index.js → src/effects/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { compose } from 'lodash/fp'
import storage from 'utils/storage'
import keyhandler from 'utils/keyboard'

import { hasProperty, effect } from 'utils/effects'
import { hasProperty, conditionalEffect } from 'utils/effects'
import { callWith } from 'utils/helper'

import playerEffectsFactory from './player'
Expand All @@ -15,7 +15,7 @@ import volumeEffects from './volume'
import urlEffects from './url'
import transcriptEffects from './transcripts'

import mediaPlayer from '../../media'
import mediaPlayer from '../media'

const storageEffects = storageEffectsFactory(storage)
const keyboardEffects = keyboardEffectsFactory(keyhandler)
Expand All @@ -24,14 +24,14 @@ const playerEffects = playerEffectsFactory(mediaPlayer)
const dispatcherEffects = [keyboardEffects]

let actionEffects = [
compose(effect(chapterEffects), hasProperty('chapters')),
effect(playerEffects),
effect(storageEffects),
effect(quantileEffects),
effect(volumeEffects),
effect(componentsEffects),
effect(urlEffects),
compose(effect(transcriptEffects), hasProperty('transcripts'))
compose(conditionalEffect(chapterEffects), hasProperty('chapters')),
conditionalEffect(playerEffects),
conditionalEffect(storageEffects),
conditionalEffect(quantileEffects),
conditionalEffect(volumeEffects),
conditionalEffect(componentsEffects),
conditionalEffect(urlEffects),
compose(conditionalEffect(transcriptEffects), hasProperty('transcripts'))
]

export default store => {
Expand Down
2 changes: 1 addition & 1 deletion src/store/effects/keyboard.js → src/effects/keyboard.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { get } from 'lodash'
import { currentChapter, currentChapterIndex } from 'utils/chapters'

import actions from '../actions'
import actions from 'store/actions'

let modifier = 0

Expand Down
File renamed without changes.
66 changes: 66 additions & 0 deletions src/effects/player.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { get, noop } from 'lodash'
import { compose, map } from 'lodash/fp'

import { handleActions } from 'utils/effects'
import { secondsToMilliseconds, millisecondsToSeconds } from 'utils/time'

import actions from 'store/actions'

import { INIT, UI_PLAY, UI_PAUSE, UI_RESTART, UPDATE_PLAYTIME, SET_VOLUME, SET_RATE, MUTE, UNMUTE, LOAD } from 'store/types'

let playerActions = {
setPlaytime: noop,
play: noop,
pause: noop,
restart: noop,
setVolume: noop,
setRate: noop,
mute: noop,
unmute: noop,
load: noop
}

export default mediaPlayer => handleActions({
[INIT]: ({ dispatch }, { payload }) => {
const audioFiles = get(payload, 'audio', [])

if (audioFiles.length === 0) {
dispatch(actions.errorMissingAudioFiles())
return
}

const player = mediaPlayer(audioFiles)

playerActions = player.actions

// register events
player.events.onPlaytimeUpdate(compose(dispatch, actions.setPlaytime, secondsToMilliseconds))
player.events.onDurationChange(compose(dispatch, actions.setDuration, secondsToMilliseconds))
player.events.onBufferChange(compose(dispatch, actions.setBuffer, map(([start, stop]) => [secondsToMilliseconds(start), secondsToMilliseconds(stop)])))
player.events.onPlay(compose(dispatch, actions.playEvent))
player.events.onPause(compose(dispatch, actions.pauseEvent))
player.events.onLoaded(compose(dispatch, actions.loaded))
player.events.onError(compose(dispatch, actions.errorLoad))
player.events.onBuffering(compose(dispatch, actions.loading))
player.events.onEnd(compose(dispatch, actions.endEvent))
},

[UI_PLAY]: (store, actions, { playtime }) => {
playerActions.setPlaytime(millisecondsToSeconds(playtime))
playerActions.play()
},

[UI_PAUSE]: () => playerActions.pause(),

[UI_RESTART]: () => {
playerActions.play()
playerActions.restart()
},

[UPDATE_PLAYTIME]: (store, { payload }) => playerActions.setPlaytime(millisecondsToSeconds(payload)),
[SET_VOLUME]: (store, { payload }) => playerActions.setVolume(payload),
[SET_RATE]: (store, { payload }) => playerActions.setRate(payload),
[MUTE]: () => playerActions.mute(),
[UNMUTE]: () => playerActions.unmute(),
[LOAD]: () => playerActions.load()
})
File renamed without changes.
24 changes: 24 additions & 0 deletions src/effects/quantiles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import actions from 'store/actions'
import { SET_PLAYTIME, NEXT_CHAPTER, PREVIOUS_CHAPTER, UPDATE_PLAYTIME } from 'store/types'

import { handleActions } from 'utils/effects'

let startTime = null

const resetStarttime = () => {
startTime = null
}

export default handleActions({
[SET_PLAYTIME]: ({ dispatch }, { payload }) => {
if (!startTime) {
startTime = payload
}

dispatch(actions.setQuantile(startTime, payload))
},

[NEXT_CHAPTER]: resetStarttime,
[PREVIOUS_CHAPTER]: resetStarttime,
[UPDATE_PLAYTIME]: resetStarttime
})
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ let store

test.beforeEach(t => {
store = {
dispatch: sinon.stub()
dispatch: sinon.stub(),
getState: () => {}
}
})

Expand Down
Loading

0 comments on commit c6262cd

Please sign in to comment.