codevise/pageflow

View on GitHub
entry_types/scrolled/package/src/frontend/MediaPlayer/usePlayerState.js

Summary

Maintainability
C
1 day
Test Coverage
import {useReducer, useMemo} from 'react';
import {createActions,
        PLAY, PLAYING, PLAY_FAILED, PAUSE, PAUSED, SCRUB_TO, SEEK_TO,
        FADE_OUT_AND_PAUSE, PLAY_AND_FADE_IN, CHANGE_VOLUME_FACTOR,
        PREBUFFER, PREBUFFERED, BUFFER_UNDERRUN, BUFFER_UNDERRUN_CONTINUE,
        WAITING, SEEKING, SEEKED, META_DATA_LOADED, DATA_LOADED, PROGRESS, TIME_UPDATE, ENDED,
        MOUSE_ENTERED, MOUSE_LEFT,
        MOUSE_ENTERED_CONTROLS, MOUSE_LEFT_CONTROLS,
        FOCUS_ENTERED_CONTROLS, FOCUS_LEFT_CONTROLS,
        USER_INTERACTION, USER_IDLE, SAVE_MEDIA_ELEMENT_ID, DISCARD_MEDIA_ELEMENT_ID} from './playerActions';

export function getInitialPlayerState(){
  return {
    isPlaying: false,
    shouldPlay: false,
    unplayed: true,
    dataLoaded: false,
    isLoading: true,
    playFailed: false,
    duration: 0,
    bufferedEnd: 0,
    shouldPrebuffer: true,
    fadeDuration: undefined,
    bufferUnderrun: undefined,
    scrubbingAt: undefined,
    currentTime: 0,
    mediaElementId: undefined,
    shouldSeekTo: undefined,
    userHovering: false,
    userHoveringControls: false,
    focusInsideControls: false,
    userIdle: false,
    volumeFactor: 1,
  };
}

export function playerStateReducer(state, action){
  switch(action.type){
    case PLAY:
      return {
        ...state,
        isLoading: true,
        shouldPlay: true,
        playFailed: false,
        unplayed: false,
        lastControlledVia: action.payload.via
      };
    case PLAYING:
      return {
        ...state,
        shouldPlay: true,
        isPlaying: true,
        userIdle: false
      };
    case PLAY_AND_FADE_IN:
      return {
        ...state,
        shouldPlay: true,
        fadeDuration: action.payload.fadeDuration,
        isLoading: true,
        lastControlledVia: action.payload.via
      };
    case FADE_OUT_AND_PAUSE:
      return {
        ...state,
        shouldPlay: false,
        fadeDuration: action.payload.fadeDuration,
        isLoading: false,
        lastControlledVia: action.payload.via
      };
    case PLAY_FAILED:
      return {
        ...state,
        shouldPlay: false,
        playFailed: true,
        fadeDuration: null,
        unplayed: true,
        isLoading: false
      };
    case PAUSE:
      return {
        ...state,
        shouldPlay: false,
        isLoading: false,
        fadeDuration: null,
        lastControlledVia: action.payload.via
      };
    case PAUSED:
      if (state.bufferUnderrun) {
        return {
          ...state,
          isPlaying: false
        };
      }
      else{
        return {
          ...state,
          shouldPlay: false,
          fadeDuration: null,
          isPlaying: false,
          isLoading: false
        };
      }
    case SCRUB_TO:
      return {
        ...state,
        scrubbingAt: action.payload.time
      };
    case SEEK_TO:
      return {
        ...state,
        shouldSeekTo: action.payload.time
      };
    case SEEKING:
      return {
        ...state,
        isLoading: true
      };
    case SEEKED:
      return {
        ...state,
        shouldSeekTo: undefined,
        scrubbingAt: undefined,
        isLoading: false
      };
    case META_DATA_LOADED:
      return {
        ...state,
        currentTime: action.payload.currentTime,
        duration: action.payload.duration
      };
    case DATA_LOADED:
      return {
        ...state,
        dataLoaded: true
      };
    case PROGRESS:
      return {
        ...state,
        bufferedEnd: action.payload.bufferedEnd
      };
    case TIME_UPDATE:
      return {
        ...state,
        currentTime: action.payload.currentTime,
        duration: action.payload.duration,
        isLoading: false
      };
    case ENDED:
      return {
        ...state,
        shouldPlay: false,
        isPlaying: false,
        unplayed: true,
        lastControlledVia: null
      };
    case WAITING:
      return {
        ...state,
        isLoading: true
      };
    case PREBUFFER:
      return {
        ...state,
        shouldPrebuffer: true
      };
    case PREBUFFERED:
      return {
        ...state,
        shouldPrebuffer: false
      };
    case BUFFER_UNDERRUN:
      return {
        ...state,
        bufferUnderrun: true
      };
    case BUFFER_UNDERRUN_CONTINUE:
      return {
        ...state,
        bufferUnderrun: false
      };
    case MOUSE_ENTERED:
      return {
        ...state,
        userHovering: true
      };
    case MOUSE_LEFT:
      return {
        ...state,
        userHovering: false
      };
    case MOUSE_ENTERED_CONTROLS:
      return {
        ...state,
        userHoveringControls: true
      };
    case MOUSE_LEFT_CONTROLS:
      return {
        ...state,
        userHoveringControls: false
      };
    case FOCUS_ENTERED_CONTROLS:
      return {
        ...state,
        focusInsideControls: true,
        userIdle: false
      };
    case FOCUS_LEFT_CONTROLS:
      return {
        ...state,
        focusInsideControls: false,
        userIdle: false
      };
    case USER_INTERACTION:
      if (!state.userIdle) {
        return state;
      }
      return {
        ...state,
        userIdle: false,
      };
    case USER_IDLE:
      return {
        ...state,
        userIdle: true,
      };
    case SAVE_MEDIA_ELEMENT_ID:
      return {
        ...state,
        mediaElementId: action.payload.id
      };
    case DISCARD_MEDIA_ELEMENT_ID:
      return {
        ...state,
        dataLoaded: false,
        isPlaying: false,
        mediaElementId: null
      };
     case CHANGE_VOLUME_FACTOR:
      return {
        ...state,
        volumeFactor: action.payload.volumeFactor,
        volumeFactorFadeDuration: action.payload.fadeDuration
      };
    default:
      return state;
  }
};

export function usePlayerState(){
  const [state, dispatch] = useReducer(playerStateReducer, getInitialPlayerState());
  const actions = useMemo(() => createActions(dispatch), [dispatch]);

  return [state, actions];
}