webamp/js/actionCreators/media.ts
Jordan Eldredge 67441f3c1b Change how actions are typed
If we want to use the new version of react-redux we need to be compatible with their types.

Sadly it does not seem to be possible to create a Dispatchable type which can be eiher a plain action or a thunk and still be compatible with react-redux's types becuase they use redux's Store type under the hood which assumes you have an object with a string type property.
2019-05-01 22:29:10 -07:00

152 lines
3.5 KiB
TypeScript

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<HTMLDivElement>): 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 };
}