import { clamp } from "../utils"; import { SEEK_TO_PERCENT_COMPLETE, SET_BALANCE, SET_VOLUME, STOP, TOGGLE_REPEAT, TOGGLE_SHUFFLE, PLAY, PAUSE, PLAY_TRACK, TOGGLE_TIME_MODE, BUFFER_TRACK, IS_STOPPED, } from "../actionTypes"; import { MEDIA_STATUS } from "../constants"; import { openMediaFileDialog } from "./"; import { GetState, Dispatch, Thunk, Action } from "../types"; import * as Selectors from "../selectors"; export function playTrack(id: number): Thunk { return (dispatch, getState) => { const state = getState(); const isStopped = Selectors.getMediaStatus(state) === MEDIA_STATUS.STOPPED; if (isStopped) { dispatch({ type: BUFFER_TRACK, id }); } else { dispatch({ type: PLAY_TRACK, id }); } }; } export function play(): Thunk { return (dispatch: Dispatch, getState: GetState) => { const state = getState(); if ( state.media.status === MEDIA_STATUS.STOPPED && state.playlist.currentTrack == null && state.playlist.trackOrder.length === 0 ) { dispatch(openMediaFileDialog()); } else { dispatch({ type: PLAY }); } }; } export function pause(): Thunk { return (dispatch, getState) => { const { status } = getState().media; if (status === MEDIA_STATUS.PLAYING) { dispatch({ type: PAUSE }); } else { dispatch({ type: PLAY }); } }; } export function stop(): Action { return { type: STOP }; } export function nextN(n: number): Thunk { return (dispatch, getState) => { const nextTrackId = Selectors.getNextTrackId(getState(), n); if (nextTrackId == null) { dispatch({ type: IS_STOPPED }); return; } dispatch(playTrack(nextTrackId)); }; } export function next(): Thunk { return nextN(1); } export function previous(): Thunk { return nextN(-1); } export function seekToTime(seconds: number): Thunk { return function(dispatch, getState) { const state = getState(); const duration = Selectors.getDuration(state); if (duration == null) { return; } dispatch({ type: SEEK_TO_PERCENT_COMPLETE, percent: (seconds / duration) * 100, }); }; } export function seekForward(seconds: number): Thunk { return function(dispatch, getState) { const timeElapsed = Selectors.getTimeElapsed(getState()); dispatch(seekToTime(timeElapsed + seconds)); }; } export function seekBackward(seconds: number): Thunk { return seekForward(-seconds); } export function setVolume(volume: number): Action { return { type: SET_VOLUME, volume: clamp(volume, 0, 100), }; } export function adjustVolume(volumeDiff: number): Thunk { return (dispatch, getState) => { const currentVolume = getState().media.volume; return dispatch(setVolume(currentVolume + volumeDiff)); }; } export function scrollVolume(e: React.WheelEvent): Thunk { e.preventDefault(); return (dispatch, getState) => { const currentVolume = getState().media.volume; // Using pixels as percentage difference here is a bit arbirary, but... oh well. return dispatch(setVolume(currentVolume + e.deltaY)); }; } export function setBalance(balance: number): Action { balance = clamp(balance, -100, 100); // The balance clips to the center if (Math.abs(balance) < 25) { balance = 0; } return { type: SET_BALANCE, balance, }; } export function toggleRepeat(): Action { return { type: TOGGLE_REPEAT }; } export function toggleShuffle(): Action { return { type: TOGGLE_SHUFFLE }; } export function toggleTimeMode(): Action { return { type: TOGGLE_TIME_MODE }; }