diff --git a/js/actionCreators/equalizer.ts b/js/actionCreators/equalizer.ts index 9d769730..5eb690ab 100644 --- a/js/actionCreators/equalizer.ts +++ b/js/actionCreators/equalizer.ts @@ -6,7 +6,7 @@ import { SET_BAND_VALUE, SET_EQ_AUTO, } from "../actionTypes"; -import { Band, Dispatchable } from "../types"; +import { Band, Thunk, Action } from "../types"; const BAND_SNAP_DISTANCE = 5; const BAND_MID_POINT_VALUE = 50; @@ -21,11 +21,11 @@ function _snapBandValue(value: number): number { return value; } -export function setEqBand(band: Band, value: number): Dispatchable { +export function setEqBand(band: Band, value: number): Action { return { type: SET_BAND_VALUE, band, value: _snapBandValue(value) }; } -function _setEqTo(value: number): Dispatchable { +function _setEqTo(value: number): Thunk { return dispatch => { Object.values(BANDS).forEach(band => { dispatch({ @@ -37,23 +37,23 @@ function _setEqTo(value: number): Dispatchable { }; } -export function setEqToMax(): Dispatchable { +export function setEqToMax(): Thunk { return _setEqTo(100); } -export function setEqToMid(): Dispatchable { +export function setEqToMid(): Thunk { return _setEqTo(50); } -export function setEqToMin(): Dispatchable { +export function setEqToMin(): Thunk { return _setEqTo(0); } -export function setPreamp(value: number): Dispatchable { +export function setPreamp(value: number): Action { return { type: SET_BAND_VALUE, band: "preamp", value: _snapBandValue(value) }; } -export function toggleEq(): Dispatchable { +export function toggleEq(): Thunk { return (dispatch, getState) => { if (getState().equalizer.on) { dispatch({ type: SET_EQ_OFF }); @@ -63,7 +63,7 @@ export function toggleEq(): Dispatchable { }; } -export function toggleEqAuto(): Dispatchable { +export function toggleEqAuto(): Thunk { return (dispatch, getState) => { dispatch({ type: SET_EQ_AUTO, value: !getState().equalizer.auto }); }; diff --git a/js/actionCreators/files.ts b/js/actionCreators/files.ts index 9bbfc7eb..a4524c5b 100644 --- a/js/actionCreators/files.ts +++ b/js/actionCreators/files.ts @@ -33,7 +33,7 @@ import LoadQueue from "../loadQueue"; import { removeAllTracks } from "./playlist"; import { setPreamp, setEqBand } from "./equalizer"; -import { LoadStyle, Dispatchable, Track, EqfPreset } from "../types"; +import { LoadStyle, Thunk, Track, EqfPreset, SkinData } from "../types"; // Lower is better const DURATION_VISIBLE_PRIORITY = 5; @@ -47,7 +47,7 @@ export function addTracksFromReferences( fileReferences: FileList, loadStyle: LoadStyle, atIndex: number | undefined -): Dispatchable { +): Thunk { const tracks: Track[] = Array.from(fileReferences).map(file => ({ blob: file, defaultName: file.name, @@ -61,7 +61,7 @@ export function loadFilesFromReferences( fileReferences: FileList, loadStyle: LoadStyle = LOAD_STYLE.PLAY, atIndex: number | undefined = undefined -): Dispatchable { +): Thunk { return dispatch => { if (fileReferences.length < 1) { return; @@ -79,9 +79,7 @@ export function loadFilesFromReferences( }; } -export function setSkinFromBlob( - arrayBuffer: Blob | Promise -): Dispatchable { +export function setSkinFromBlob(blob: Blob | Promise): Thunk { return async (dispatch, getState, { requireJSZip }) => { if (!requireJSZip) { alert("Webamp has not been configured to support custom skins."); @@ -98,8 +96,7 @@ export function setSkinFromBlob( return; } try { - const skinData = await skinParser(arrayBuffer, JSZip); - // @ts-ignore TODO: We still need to type skinParser. + const skinData = await skinParser(blob, JSZip); dispatch({ type: SET_SKIN_DATA, data: { @@ -110,7 +107,7 @@ export function setSkinFromBlob( skinRegion: skinData.region, skinGenLetterWidths: skinData.genLetterWidths, skinGenExColors: skinData.genExColors, - }, + } as SkinData, }); } catch (e) { console.error(e); @@ -120,7 +117,7 @@ export function setSkinFromBlob( }; } -export function setSkinFromUrl(url: string): Dispatchable { +export function setSkinFromUrl(url: string): Thunk { return async dispatch => { dispatch({ type: LOADING }); try { @@ -140,18 +137,18 @@ export function setSkinFromUrl(url: string): Dispatchable { // This function is private, since Winamp consumers can provide means for // opening files via other methods. Only use the file type specific // versions below, since they can defer to the user-defined behavior. -function _openFileDialog(accept: string | null): Dispatchable { +function _openFileDialog(accept: string | null): Thunk { return async dispatch => { const fileReferences = await promptForFileReferences({ accept }); dispatch(loadFilesFromReferences(fileReferences)); }; } -export function openEqfFileDialog(): Dispatchable { +export function openEqfFileDialog(): Thunk { return _openFileDialog(".eqf"); } -export function openMediaFileDialog(): Dispatchable { +export function openMediaFileDialog(): Thunk { return _openFileDialog(null); } @@ -159,7 +156,7 @@ export function openSkinFileDialog() { return _openFileDialog(".zip, .wsz"); } -export function fetchMediaDuration(url: string, id: number): Dispatchable { +export function fetchMediaDuration(url: string, id: number): Thunk { return (dispatch, getState) => { loadQueue.push( async () => { @@ -185,7 +182,7 @@ export function loadMedia( e: React.DragEvent, loadStyle: LoadStyle = LOAD_STYLE.NONE, atIndex = 0 -): Dispatchable { +): Thunk { const { files } = e.dataTransfer; return async (dispatch, getState, { handleTrackDropEvent }) => { if (handleTrackDropEvent) { @@ -204,7 +201,7 @@ export function loadMediaFiles( tracks: Track[], loadStyle: LoadStyle = LOAD_STYLE.NONE, atIndex = 0 -): Dispatchable { +): Thunk { return dispatch => { if (loadStyle === LOAD_STYLE.PLAY) { // I'm the worst. It just so happens that in every case that we autoPlay, @@ -222,7 +219,7 @@ export function loadMediaFile( track: Track, priority: LoadStyle = LOAD_STYLE.NONE, atIndex = 0 -): Dispatchable { +): Thunk { return dispatch => { const id = Utils.uniqueId(); const { defaultName, metaData, duration } = track; @@ -285,7 +282,7 @@ export function loadMediaFile( }; } -function queueFetchingMediaTags(id: number): Dispatchable { +function queueFetchingMediaTags(id: number): Thunk { return (dispatch, getState) => { const track = getTracks(getState())[id]; loadQueue.push( @@ -300,7 +297,7 @@ function queueFetchingMediaTags(id: number): Dispatchable { }; } -export function fetchMediaTags(file: string | Blob, id: number): Dispatchable { +export function fetchMediaTags(file: string | Blob, id: number): Thunk { return async (dispatch, getState, { requireMusicMetadata }) => { dispatch({ type: MEDIA_TAG_REQUEST_INITIALIZED, id }); @@ -332,7 +329,7 @@ export function fetchMediaTags(file: string | Blob, id: number): Dispatchable { }; } -export function setEqFromFileReference(fileReference: File): Dispatchable { +export function setEqFromFileReference(fileReference: File): Thunk { return async dispatch => { const arrayBuffer = await genArrayBufferFromFileReference(fileReference); const eqf = parser(arrayBuffer); @@ -341,7 +338,7 @@ export function setEqFromFileReference(fileReference: File): Dispatchable { }; } -export function setEqFromObject(preset: EqfPreset): Dispatchable { +export function setEqFromObject(preset: EqfPreset): Thunk { return dispatch => { dispatch(setPreamp(Utils.normalizeEqBand(preset.preamp))); BANDS.forEach(band => { @@ -351,7 +348,7 @@ export function setEqFromObject(preset: EqfPreset): Dispatchable { }; } -export function downloadPreset(): Dispatchable { +export function downloadPreset(): Thunk { return (dispatch, getState) => { const state = getState(); const data = getEqfData(state); @@ -362,7 +359,7 @@ export function downloadPreset(): Dispatchable { }; } -export function downloadHtmlPlaylist(): Dispatchable { +export function downloadHtmlPlaylist(): Thunk { return (dispatch, getState) => { const uri = getPlaylistURL(getState()); Utils.downloadURI(uri, "Winamp Playlist.html"); diff --git a/js/actionCreators/index.ts b/js/actionCreators/index.ts index 2ee51370..3bd58855 100644 --- a/js/actionCreators/index.ts +++ b/js/actionCreators/index.ts @@ -13,7 +13,7 @@ import { SET_MILKDROP_FULLSCREEN, } from "../actionTypes"; import { WINDOWS } from "../constants"; -import { Dispatchable } from "../types"; +import { Thunk, Action } from "../types"; import { SerializedStateV1 } from "../serializedStates/v1Types"; import * as Selectors from "../selectors"; import { ensureWindowsAreOnScreen, showWindow, hideWindow } from "./windows"; @@ -112,7 +112,7 @@ export { scheduleMilkdropMessage, } from "./milkdrop"; -export function close(): Dispatchable { +export function close(): Thunk { return dispatch => { // TODO: This could probably be improved by adding a "PREVENT_CLOSE" action // or something, but this works okay for now. @@ -128,41 +128,41 @@ export function close(): Dispatchable { }; } -export function open(): Dispatchable { +export function open(): Action { return { type: OPEN_WINAMP }; } -export function toggleVisualizerStyle(): Dispatchable { +export function toggleVisualizerStyle(): Action { return { type: TOGGLE_VISUALIZER_STYLE }; } -export function minimize(): Dispatchable { +export function minimize(): Action { return { type: MINIMIZE_WINAMP }; } -export function setFocus(input: string): Dispatchable { +export function setFocus(input: string): Action { return { type: SET_FOCUS, input }; } -export function unsetFocus(): Dispatchable { +export function unsetFocus(): Action { return { type: UNSET_FOCUS }; } export function loadSerializedState( // In the future this type should be the union of all versioned types. serializedState: SerializedStateV1 -): Dispatchable { +): Thunk { return dispatch => { dispatch({ type: LOAD_SERIALIZED_STATE, serializedState }); dispatch(ensureWindowsAreOnScreen()); }; } -export function loadDefaultSkin(): Dispatchable { +export function loadDefaultSkin(): Action { return { type: LOAD_DEFAULT_SKIN }; } -export function toggleMilkdropDesktop(): Dispatchable { +export function toggleMilkdropDesktop(): Thunk { return (dispatch, getState) => { if (Selectors.getMilkdropDesktopEnabled(getState())) { dispatch(showWindow(WINDOWS.MILKDROP)); @@ -174,10 +174,10 @@ export function toggleMilkdropDesktop(): Dispatchable { }; } -export function setMilkdropFullscreen(enabled: boolean): Dispatchable { +export function setMilkdropFullscreen(enabled: boolean): Action { return { type: SET_MILKDROP_FULLSCREEN, enabled }; } -export function toggleMilkdropFullscreen(): Dispatchable { +export function toggleMilkdropFullscreen(): Thunk { return (dispatch, getState) => { dispatch( setMilkdropFullscreen(!Selectors.getMilkdropFullscreenEnabled(getState())) diff --git a/js/actionCreators/media.ts b/js/actionCreators/media.ts index 25692163..acc65fdd 100644 --- a/js/actionCreators/media.ts +++ b/js/actionCreators/media.ts @@ -16,10 +16,10 @@ import { import { MEDIA_STATUS } from "../constants"; import { openMediaFileDialog } from "./"; -import { GetState, Dispatch, Dispatchable } from "../types"; +import { GetState, Dispatch, Thunk, Action } from "../types"; import * as Selectors from "../selectors"; -export function playTrack(id: number): Dispatchable { +export function playTrack(id: number): Thunk { return (dispatch, getState) => { const state = getState(); const isStopped = Selectors.getMediaStatus(state) === MEDIA_STATUS.STOPPED; @@ -31,7 +31,7 @@ export function playTrack(id: number): Dispatchable { }; } -export function play(): Dispatchable { +export function play(): Thunk { return (dispatch: Dispatch, getState: GetState) => { const state = getState(); if ( @@ -46,7 +46,7 @@ export function play(): Dispatchable { }; } -export function pause(): Dispatchable { +export function pause(): Thunk { return (dispatch, getState) => { const { status } = getState().media; if (status === MEDIA_STATUS.PLAYING) { @@ -57,11 +57,11 @@ export function pause(): Dispatchable { }; } -export function stop(): Dispatchable { +export function stop(): Action { return { type: STOP }; } -export function nextN(n: number): Dispatchable { +export function nextN(n: number): Thunk { return (dispatch, getState) => { const nextTrackId = Selectors.getNextTrackId(getState(), n); if (nextTrackId == null) { @@ -72,15 +72,15 @@ export function nextN(n: number): Dispatchable { }; } -export function next(): Dispatchable { +export function next(): Thunk { return nextN(1); } -export function previous(): Dispatchable { +export function previous(): Thunk { return nextN(-1); } -export function seekToTime(seconds: number): Dispatchable { +export function seekToTime(seconds: number): Thunk { return function(dispatch, getState) { const state = getState(); const duration = Selectors.getDuration(state); @@ -93,34 +93,32 @@ export function seekToTime(seconds: number): Dispatchable { }); }; } -export function seekForward(seconds: number): Dispatchable { +export function seekForward(seconds: number): Thunk { return function(dispatch, getState) { const timeElapsed = Selectors.getTimeElapsed(getState()); dispatch(seekToTime(timeElapsed + seconds)); }; } -export function seekBackward(seconds: number): Dispatchable { +export function seekBackward(seconds: number): Thunk { return seekForward(-seconds); } -export function setVolume(volume: number): Dispatchable { +export function setVolume(volume: number): Action { return { type: SET_VOLUME, volume: clamp(volume, 0, 100), }; } -export function adjustVolume(volumeDiff: number): Dispatchable { +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 -): Dispatchable { +export function scrollVolume(e: React.WheelEvent): Thunk { e.preventDefault(); return (dispatch, getState) => { const currentVolume = getState().media.volume; @@ -129,7 +127,7 @@ export function scrollVolume( }; } -export function setBalance(balance: number): Dispatchable { +export function setBalance(balance: number): Action { balance = clamp(balance, -100, 100); // The balance clips to the center if (Math.abs(balance) < 25) { @@ -141,14 +139,14 @@ export function setBalance(balance: number): Dispatchable { }; } -export function toggleRepeat(): Dispatchable { +export function toggleRepeat(): Action { return { type: TOGGLE_REPEAT }; } -export function toggleShuffle(): Dispatchable { +export function toggleShuffle(): Action { return { type: TOGGLE_SHUFFLE }; } -export function toggleTimeMode(): Dispatchable { +export function toggleTimeMode(): Action { return { type: TOGGLE_TIME_MODE }; } diff --git a/js/actionCreators/milkdrop.ts b/js/actionCreators/milkdrop.ts index 74f04d67..d8c8e611 100644 --- a/js/actionCreators/milkdrop.ts +++ b/js/actionCreators/milkdrop.ts @@ -11,11 +11,12 @@ import { } from "../actionTypes"; import * as Selectors from "../selectors"; import { - Dispatchable, TransitionType, Preset, ButterchurnOptions, StatePreset, + Thunk, + Action, } from "../types"; import * as FileUtils from "../fileUtils"; @@ -46,9 +47,7 @@ function normalizePresetTypes(preset: Preset): StatePreset { throw new Error("Invalid preset object"); } -export function initializePresets( - presetOptions: ButterchurnOptions -): Dispatchable { +export function initializePresets(presetOptions: ButterchurnOptions): Thunk { return async dispatch => { const { getPresets, importButterchurn } = presetOptions; importButterchurn().then(butterchurn => { @@ -61,7 +60,7 @@ export function initializePresets( }; } -export function loadPresets(presets: StatePreset[]): Dispatchable { +export function loadPresets(presets: StatePreset[]): Thunk { return (dispatch, getState) => { const state = getState(); const presetsLength = state.milkdrop.presets.length; @@ -76,7 +75,7 @@ export function loadPresets(presets: StatePreset[]): Dispatchable { }; } -export function appendPresetFileList(fileList: FileList): Dispatchable { +export function appendPresetFileList(fileList: FileList): Thunk { return async (dispatch, getState, { convertPreset }) => { const presets: StatePreset[] = Array.from(fileList) .map(file => { @@ -114,7 +113,7 @@ export function appendPresetFileList(fileList: FileList): Dispatchable { export function selectNextPreset( transitionType: TransitionType = TransitionType.DEFAULT -): Dispatchable { +): Thunk { return (dispatch, getState) => { const state = getState(); if (Selectors.getRandomizePresets(state)) { @@ -131,7 +130,7 @@ export function selectNextPreset( export function selectPreviousPreset( transitionType: TransitionType = TransitionType.DEFAULT -): Dispatchable { +): Thunk { return (dispatch, getState) => { const state = getState(); const { presetHistory } = state.milkdrop; @@ -147,7 +146,7 @@ export function selectPreviousPreset( export function selectRandomPreset( transitionType: TransitionType = TransitionType.DEFAULT -): Dispatchable { +): Thunk { return (dispatch, getState) => { const state = getState(); // TODO: Make this a selector. @@ -164,7 +163,7 @@ export function requestPresetAtIndex( index: number, transitionType: TransitionType, addToHistory: boolean -): Dispatchable { +): Thunk { return async (dispatch, getState) => { const state = getState(); const preset = state.milkdrop.presets[index]; @@ -187,22 +186,22 @@ export function requestPresetAtIndex( }; } -export function handlePresetDrop(e: React.DragEvent): Dispatchable { +export function handlePresetDrop(e: React.DragEvent): Thunk { return appendPresetFileList(e.dataTransfer.files); } -export function togglePresetOverlay(): Dispatchable { +export function togglePresetOverlay(): Action { return { type: TOGGLE_PRESET_OVERLAY }; } -export function toggleRandomizePresets(): Dispatchable { +export function toggleRandomizePresets(): Action { return { type: TOGGLE_RANDOMIZE_PRESETS }; } -export function togglePresetCycling(): Dispatchable { +export function togglePresetCycling(): Action { return { type: TOGGLE_PRESET_CYCLING }; } -export function scheduleMilkdropMessage(message: string): Dispatchable { +export function scheduleMilkdropMessage(message: string): Action { return { type: SCHEDULE_MILKDROP_MESSAGE, message }; } diff --git a/js/actionCreators/playlist.ts b/js/actionCreators/playlist.ts index c969c6ee..5973844a 100644 --- a/js/actionCreators/playlist.ts +++ b/js/actionCreators/playlist.ts @@ -12,9 +12,9 @@ import { SET_PLAYLIST_SCROLL_POSITION, DRAG_SELECTED, } from "../actionTypes"; -import { Dispatchable } from "../types"; +import { Thunk, Action } from "../types"; -export function cropPlaylist(): Dispatchable { +export function cropPlaylist(): Thunk { return (dispatch, getState) => { const state = getState(); if (Selectors.getSelectedTrackObjects(state).length === 0) { @@ -33,7 +33,7 @@ export function cropPlaylist(): Dispatchable { }; } -export function removeSelectedTracks(): Dispatchable { +export function removeSelectedTracks(): Thunk { return (dispatch, getState) => { dispatch({ type: REMOVE_TRACKS, @@ -44,7 +44,7 @@ export function removeSelectedTracks(): Dispatchable { }; } -export function removeAllTracks(): Dispatchable { +export function removeAllTracks(): Thunk { return dispatch => { // It's a bit funky that we need to do both of these. dispatch({ type: STOP }); @@ -52,15 +52,15 @@ export function removeAllTracks(): Dispatchable { }; } -export function reverseList(): Dispatchable { +export function reverseList(): Action { return { type: REVERSE_LIST }; } -export function randomizeList(): Dispatchable { +export function randomizeList(): Action { return { type: RANDOMIZE_LIST }; } -export function sortListByTitle(): Dispatchable { +export function sortListByTitle(): Thunk { return (dispatch, getState) => { const state = getState(); const tracks = Selectors.getTracks(state); @@ -71,11 +71,11 @@ export function sortListByTitle(): Dispatchable { }; } -export function setPlaylistScrollPosition(position: number): Dispatchable { +export function setPlaylistScrollPosition(position: number): Action { return { type: SET_PLAYLIST_SCROLL_POSITION, position }; } -export function scrollNTracks(n: number): Dispatchable { +export function scrollNTracks(n: number): Thunk { return (dispatch, getState) => { const state = getState(); const overflow = Selectors.getOverflowTrackCount(state); @@ -90,7 +90,7 @@ export function scrollNTracks(n: number): Dispatchable { export function scrollPlaylistByDelta( e: React.WheelEvent -): Dispatchable { +): Thunk { e.preventDefault(); return (dispatch, getState) => { const state = getState(); @@ -110,15 +110,15 @@ export function scrollPlaylistByDelta( }; } -export function scrollUpFourTracks(): Dispatchable { +export function scrollUpFourTracks(): Thunk { return scrollNTracks(-4); } -export function scrollDownFourTracks(): Dispatchable { +export function scrollDownFourTracks(): Thunk { return scrollNTracks(4); } -export function dragSelected(offset: number): Dispatchable { +export function dragSelected(offset: number): Thunk { return (dispatch, getState) => { const state = getState(); const tracks = Selectors.getTracks(state); diff --git a/js/actionCreators/windows.ts b/js/actionCreators/windows.ts index cfaaa87d..13c3a67d 100644 --- a/js/actionCreators/windows.ts +++ b/js/actionCreators/windows.ts @@ -17,13 +17,7 @@ import { import { getPositionDiff, SizeDiff } from "../resizeUtils"; import { applyDiff } from "../snapUtils"; -import { - Action, - Dispatchable, - WindowId, - WindowPositions, - Dispatch, -} from "../types"; +import { Action, Thunk, WindowId, WindowPositions, Dispatch } from "../types"; // Dispatch an action and, if needed rearrange the windows to preserve // the existing edge relationship. @@ -31,7 +25,7 @@ import { // Works by checking the edges before the action is dispatched. Then, // after disatching, calculating what position change would be required // to restore those relationships. -function withWindowGraphIntegrity(action: Action): Dispatchable { +function withWindowGraphIntegrity(action: Action): Thunk { return (dispatch, getState) => { const state = getState(); const graph = Selectors.getWindowGraph(state); @@ -61,70 +55,70 @@ function withWindowGraphIntegrity(action: Action): Dispatchable { }; } -export function toggleDoubleSizeMode(): Dispatchable { +export function toggleDoubleSizeMode(): Thunk { return withWindowGraphIntegrity({ type: TOGGLE_DOUBLESIZE_MODE }); } -export function toggleLlamaMode(): Dispatchable { +export function toggleLlamaMode(): Action { return { type: TOGGLE_LLAMA_MODE }; } -export function toggleEqualizerShadeMode(): Dispatchable { +export function toggleEqualizerShadeMode(): Thunk { return withWindowGraphIntegrity({ type: TOGGLE_WINDOW_SHADE_MODE, windowId: "equalizer", }); } -export function toggleMainWindowShadeMode(): Dispatchable { +export function toggleMainWindowShadeMode(): Thunk { return withWindowGraphIntegrity({ type: TOGGLE_WINDOW_SHADE_MODE, windowId: "main", }); } -export function togglePlaylistShadeMode(): Dispatchable { +export function togglePlaylistShadeMode(): Thunk { return withWindowGraphIntegrity({ type: TOGGLE_WINDOW_SHADE_MODE, windowId: "playlist", }); } -export function closeWindow(windowId: WindowId): Dispatchable { +export function closeWindow(windowId: WindowId): Action { return { type: CLOSE_WINDOW, windowId }; } -export function hideWindow(windowId: WindowId): Dispatchable { +export function hideWindow(windowId: WindowId): Action { return { type: SET_WINDOW_VISIBILITY, windowId, hidden: true }; } -export function showWindow(windowId: WindowId): Dispatchable { +export function showWindow(windowId: WindowId): Action { return { type: SET_WINDOW_VISIBILITY, windowId, hidden: false }; } -export function setFocusedWindow(window: WindowId): Dispatchable { +export function setFocusedWindow(window: WindowId): Action { return { type: SET_FOCUSED_WINDOW, window }; } export function setWindowSize( windowId: WindowId, size: [number, number] -): Dispatchable { +): Action { return { type: WINDOW_SIZE_CHANGED, windowId, size }; } -export function toggleWindow(windowId: WindowId): Dispatchable { +export function toggleWindow(windowId: WindowId): Action { return { type: TOGGLE_WINDOW, windowId }; } export function updateWindowPositions( positions: WindowPositions, absolute?: boolean -): Dispatchable { +): Action { return { type: UPDATE_WINDOW_POSITIONS, positions, absolute }; } -export function centerWindowsInContainer(container: HTMLElement): Dispatchable { +export function centerWindowsInContainer(container: HTMLElement): Thunk { return (dispatch, getState) => { if (!Selectors.getPositionsAreRelative(getState())) { return; @@ -135,7 +129,7 @@ export function centerWindowsInContainer(container: HTMLElement): Dispatchable { }; } -export function centerWindowsInView(): Dispatchable { +export function centerWindowsInView(): Thunk { return centerWindows({ left: window.scrollX, top: window.scrollY, @@ -149,7 +143,7 @@ export function centerWindows(box: { top: number; width: number; height: number; -}): Dispatchable { +}): Thunk { return (dispatch, getState) => { const state = getState(); const windowsInfo = Selectors.getWindowsInfo(state); @@ -188,18 +182,18 @@ export function centerWindows(box: { export function browserWindowSizeChanged(size: { height: number; width: number; -}) { +}): Thunk { return (dispatch: Dispatch) => { dispatch({ type: BROWSER_WINDOW_SIZE_CHANGED, ...size }); dispatch(ensureWindowsAreOnScreen()); }; } -export function resetWindowSizes(): Dispatchable { +export function resetWindowSizes(): Action { return { type: RESET_WINDOW_SIZES }; } -export function stackWindows(): Dispatchable { +export function stackWindows(): Thunk { return (dispatch, getState) => { dispatch( updateWindowPositions(Selectors.getStackedLayoutPositions(getState())) @@ -207,7 +201,7 @@ export function stackWindows(): Dispatchable { }; } -export function ensureWindowsAreOnScreen(): Dispatchable { +export function ensureWindowsAreOnScreen(): Thunk { return (dispatch, getState) => { const state = getState(); diff --git a/js/serialization.test.ts b/js/serialization.test.ts index 4e22a892..41cd714a 100644 --- a/js/serialization.test.ts +++ b/js/serialization.test.ts @@ -9,7 +9,7 @@ import { createStore, applyMiddleware } from "redux"; import thunk from "redux-thunk"; import { LOAD_SERIALIZED_STATE } from "./actionTypes"; import { SerializedStateV1 } from "./serializedStates/v1Types"; -import { Dispatchable, AppState } from "./types"; +import { AppState, Action } from "./types"; function fixturePath(name: string) { return path.join( @@ -29,7 +29,7 @@ function readFixture(name: string): SerializedStateV1 { interface SerializationTestParams { name: string; - action: Dispatchable; + action: Action; selector(state: AppState): T; expected: T; } @@ -132,6 +132,7 @@ describe("can serialize", () => { /* Equalizer */ testSerialization({ name: "equalizer on", + // @ts-ignore action: Actions.toggleEq(), selector: Selectors.getEqualizerEnabled, expected: false, @@ -139,6 +140,7 @@ describe("can serialize", () => { testSerialization({ name: "equalizer auto", + // @ts-ignore action: Actions.toggleEqAuto(), selector: Selectors.getEqualizerAuto, expected: true, @@ -161,6 +163,7 @@ describe("can serialize", () => { /* Display */ testSerialization({ name: "double mode", + // @ts-ignore action: Actions.toggleDoubleSizeMode(), selector: Selectors.getDoubled, expected: true, @@ -207,8 +210,9 @@ describe("can serialize", () => { testSerialization({ name: "window shade", + // @ts-ignore action: Actions.toggleEqualizerShadeMode(), - selector: state => Selectors.getWindowShade(state)("equalizer"), + selector: state => Boolean(Selectors.getWindowShade(state)("equalizer")), expected: true, }); diff --git a/js/types.ts b/js/types.ts index 02283829..87e80581 100644 --- a/js/types.ts +++ b/js/types.ts @@ -2,6 +2,7 @@ import { PlaylistState } from "./reducers/playlist"; import { SettingsState } from "./reducers/settings"; import { UserInputState } from "./reducers/userInput"; import { MediaState } from "./reducers/media"; +import { ThunkDispatch, ThunkAction } from "redux-thunk"; import { DisplayState } from "./reducers/display"; import { WindowsState, WindowPositions } from "./reducers/windows"; import { EqualizerState } from "./reducers/equalizer"; @@ -110,7 +111,7 @@ export interface SkinGenExColors { export type WindowId = string; // TODO: Fill these out once we actually use them. -type SkinData = { +export type SkinData = { skinImages: SkinImages; skinColors: string[]; skinPlaylistStyle: PlaylistStyle; @@ -661,19 +662,9 @@ export interface Extras { export type GetState = () => AppState; -export type Thunk = ( - dispatch: Dispatch, - getState: GetState, - extras: Extras -) => void | Promise; +export type Thunk = ThunkAction; -export type Dispatchable = Action | Thunk; - -export interface DispatchObject { - [prop: string]: (...args: any[]) => Dispatchable; -} - -export type Dispatch = (action: Dispatchable) => void; +export type Dispatch = ThunkDispatch; export type Reducer = (state: AppState, action: Action) => AppState; diff --git a/js/webampLazy.tsx b/js/webampLazy.tsx index 41217e3c..6ce750d3 100644 --- a/js/webampLazy.tsx +++ b/js/webampLazy.tsx @@ -10,6 +10,7 @@ import { Middleware, WindowPosition, ButterchurnOptions, + Action, } from "./types"; import getStore from "./store"; import App from "./components/App"; @@ -418,7 +419,7 @@ class Winamp { }); ReactDOM.render( - + store={this.store}>