From bbf56232c37a587562ff8ad893bcb7563cb3a63b Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Mon, 17 Sep 2018 08:32:52 -0700 Subject: [PATCH] Type Selectors --- js/reducers/playlist.ts | 5 +- js/{selectors.js => selectors.ts} | 81 ++++++++++++++++++------------- js/types.ts | 18 +++++-- js/utils.ts | 5 +- 4 files changed, 69 insertions(+), 40 deletions(-) rename js/{selectors.js => selectors.ts} (75%) diff --git a/js/reducers/playlist.ts b/js/reducers/playlist.ts index 2e598469..daa7578d 100644 --- a/js/reducers/playlist.ts +++ b/js/reducers/playlist.ts @@ -271,8 +271,11 @@ export default playlist; export const getTrackDisplayName = ( state: PlaylistState, - id: number + id: number | null = null ): string | null => { + if (id == null) { + return null; + } const track = state.tracks[id]; if (track == null) { return null; diff --git a/js/selectors.js b/js/selectors.ts similarity index 75% rename from js/selectors.js rename to js/selectors.ts index 4adf00d1..812ee873 100644 --- a/js/selectors.js +++ b/js/selectors.ts @@ -1,3 +1,4 @@ +import { AppState, PlaylistTrack, WebampWindow, WindowId } from "./types"; import { createSelector } from "reselect"; import { denormalize, @@ -18,10 +19,10 @@ import * as fromPlaylist from "./reducers/playlist"; import * as fromDisplay from "./reducers/display"; import { generateGraph } from "./resizeUtils"; -export const getSliders = state => state.equalizer.sliders; +export const getSliders = (state: AppState) => state.equalizer.sliders; export const getEqfData = createSelector(getSliders, sliders => { - const preset = { + const preset: { [key: string]: number | string } = { name: "Entry1", preamp: denormalize(sliders.preamp) }; @@ -35,8 +36,8 @@ export const getEqfData = createSelector(getSliders, sliders => { return eqfData; }); -export const getTracks = state => state.playlist.tracks; -const getTrackOrder = state => state.playlist.trackOrder; +export const getTracks = (state: AppState) => state.playlist.tracks; +const getTrackOrder = (state: AppState) => state.playlist.trackOrder; export const getTrackCount = createSelector( getTrackOrder, @@ -52,7 +53,7 @@ export const getOrderedTracks = createSelector( const getOrderedTrackObjects = createSelector( getTracks, getOrderedTracks, - (tracks, trackOrder) => trackOrder.map(id => tracks[id]) + (tracks, trackOrder): PlaylistTrack[] => trackOrder.map(id => tracks[id]) ); export const getSelectedTrackObjects = createSelector( @@ -61,7 +62,7 @@ export const getSelectedTrackObjects = createSelector( ); // If a duration is `null`, it counts as zero, which seems fine enough. -const runningTimeFromTracks = tracks => +const runningTimeFromTracks = (tracks: PlaylistTrack[]) => tracks.reduce((time, track) => time + Number(track.duration), 0); const getTotalRunningTime = createSelector( @@ -83,17 +84,23 @@ export const getRunningTimeMessage = createSelector( ); // TODO: use slectors to get memoization -export const getCurrentTrackIndex = state => - state.playlist.trackOrder.indexOf(state.playlist.currentTrack); +export const getCurrentTrackIndex = (state: AppState): number => { + const { playlist } = state; + if (playlist.currentTrack == null) { + return -1; + } + return playlist.trackOrder.indexOf(playlist.currentTrack); +}; export const getCurrentTrackNumber = createSelector( getCurrentTrackIndex, currentTrackIndex => currentTrackIndex + 1 ); -export const getCurrentTrackId = state => state.playlist.currentTrack; +export const getCurrentTrackId = (state: AppState) => + state.playlist.currentTrack; -export const nextTrack = (state, n = 1) => { +export const nextTrack = (state: AppState, n = 1) => { const { playlist: { trackOrder }, media: { repeat } @@ -126,7 +133,7 @@ export const nextTrack = (state, n = 1) => { }; const BASE_WINDOW_HEIGHT = 58; -export const getNumberOfVisibleTracks = state => { +export const getNumberOfVisibleTracks = (state: AppState) => { const playlistSize = getWindowSize(state, "playlist"); return Math.floor( (BASE_WINDOW_HEIGHT + WINDOW_RESIZE_SEGMENT_HEIGHT * playlistSize[1]) / @@ -141,7 +148,7 @@ export const getOverflowTrackCount = createSelector( Math.max(0, trackCount - numberOfVisibleTracks) ); -const _getPlaylistScrollPosition = state => +const _getPlaylistScrollPosition = (state: AppState) => state.display.playlistScrollPosition; export const getPlaylistScrollPosition = createSelector( @@ -180,7 +187,7 @@ export const getVisibleTrackIds = createSelector( export const getTrackIsVisibleFunction = createSelector( getVisibleTrackIds, visibleTrackIds => { - return id => visibleTrackIds.includes(id); + return (id: number) => visibleTrackIds.includes(id); } ); @@ -190,17 +197,21 @@ export const getVisibleTracks = createSelector( (visibleTrackIds, tracks) => visibleTrackIds.map(id => tracks[id]) ); -export const getPlaylist = state => state.playlist; +export const getPlaylist = (state: AppState) => state.playlist; -export const getDuration = state => { - const currentTrack = state.playlist.tracks[state.playlist.currentTrack]; +export const getDuration = (state: AppState): number | null => { + const { playlist } = state; + if (playlist.currentTrack == null) { + return null; + } + const currentTrack = playlist.tracks[playlist.currentTrack]; return currentTrack && currentTrack.duration; }; -export const getTrackDisplayName = (state, trackId) => +export const getTrackDisplayName = (state: AppState, trackId: number | null) => fromPlaylist.getTrackDisplayName(getPlaylist(state), trackId); -export const getCurrentTrackDisplayName = state => { +export const getCurrentTrackDisplayName = (state: AppState) => { const id = getCurrentTrackId(state); return getTrackDisplayName(state, id); }; @@ -221,9 +232,13 @@ export const getMediaText = createSelector( `${minimalMediaText} (${getTimeStr(duration)}) *** ` ); -export const getNumberOfTracks = state => getTrackOrder(state).length; +export const getNumberOfTracks = (state: AppState) => + getTrackOrder(state).length; const getPlaylistDuration = createSelector(getTracks, tracks => - Object.values(tracks).reduce((total, track) => total + track.duration, 0) + Object.values(tracks).reduce( + (total, track) => total + (track.duration || 0), + 0 + ) ); export const getPlaylistURL = createSelector( @@ -248,14 +263,14 @@ export const getPlaylistURL = createSelector( }) ); -export function getWindowPositions(state) { +export function getWindowPositions(state: AppState) { return state.windows.positions; } const WINDOW_HEIGHT = 116; const SHADE_WINDOW_HEIGHT = 14; -function getWPixelSize(w, doubled) { +function getWPixelSize(w: WebampWindow, doubled: boolean) { const [width, height] = w.size; const doubledMultiplier = doubled && w.canDouble ? 2 : 1; const pix = { @@ -268,27 +283,27 @@ function getWPixelSize(w, doubled) { }; } -export function getWindowSize(state, windowId) { +export function getWindowSize(state: AppState, windowId: WindowId) { return state.windows.genWindows[windowId].size; } -export function getWindowOpen(state) { - return windowId => state.windows.genWindows[windowId].open; +export function getWindowOpen(state: AppState) { + return (windowId: WindowId) => state.windows.genWindows[windowId].open; } -export function getWindowShade(state, windowId) { +export function getWindowShade(state: AppState, windowId: WindowId) { return state.windows.genWindows[windowId].shade; } -export function getWindowHidden(state) { - return windowId => state.windows.genWindows[windowId].hidden; +export function getWindowHidden(state: AppState) { + return (windowId: WindowId) => state.windows.genWindows[windowId].hidden; } -export const getGenWindows = state => { +export const getGenWindows = (state: AppState) => { return state.windows.genWindows; }; -export function getDoubled(state) { +export function getDoubled(state: AppState) { return state.display.doubled; } @@ -300,7 +315,7 @@ export const getWindowSizes = createSelector( } ); -export function getWindowPixelSize(state, windowId) { +export function getWindowPixelSize(state: AppState, windowId: WindowId) { // Rather than compute it directly, we go via `getWindowSizes` // to take advantage of caching. return getWindowSizes(state)[windowId]; @@ -315,7 +330,7 @@ export const getWindowsInfo = createSelector( export const getWindowGraph = createSelector(getWindowsInfo, generateGraph); -export const getSkinPlaylistStyle = state => { +export const getSkinPlaylistStyle = (state: AppState) => { return ( state.display.skinPlaylistStyle || { normal: "#00FF00", @@ -327,5 +342,5 @@ export const getSkinPlaylistStyle = state => { ); }; -export const getVisualizerStyle = state => +export const getVisualizerStyle = (state: AppState) => fromDisplay.getVisualizerStyle(state.display); diff --git a/js/types.ts b/js/types.ts index 95e27aad..e98f6d0d 100644 --- a/js/types.ts +++ b/js/types.ts @@ -31,7 +31,7 @@ type SkinImages = { [sprite: string]: string }; // TODO: type these keys type SkinRegion = { [windowName: string]: string[] }; -type WindowId = string; +export type WindowId = string; // TODO: Fill these out once we actually use them. type SkinData = { @@ -43,6 +43,13 @@ type SkinData = { skinGenLetterWidths: GenLetterWidths; }; +interface WindowPosition { + x: number; + y: number; +} +export type WindowPositions = { + [windowId: string]: WindowPosition; +}; export type Action = | { type: "NETWORK_CONNECTED"; @@ -232,7 +239,7 @@ export type Action = } | { type: "UPDATE_WINDOW_POSITIONS"; - positions: {}; + positions: WindowPositions; } | { type: "CLICKED_TRACK"; @@ -361,7 +368,7 @@ export interface EqualizerState { sliders: Record; } -export interface Window { +export interface WebampWindow { title: string; size: [number, number]; open: boolean; @@ -376,8 +383,8 @@ export interface Window { export interface WindowState { focused: string; - genWindows: { [name: string]: Window }; - positions: {}; // TODO: Make this more strict + genWindows: { [name: string]: WebampWindow }; + positions: WindowPositions; } export type MediaTagRequestStatus = @@ -394,6 +401,7 @@ export interface PlaylistTrack { albumArtUrl: string | null; selected: boolean; mediaTagsRequestStatus: MediaTagRequestStatus; + duration: number | null; } export interface PlaylistState { diff --git a/js/utils.ts b/js/utils.ts index f64b6933..3abc6bec 100644 --- a/js/utils.ts +++ b/js/utils.ts @@ -51,7 +51,10 @@ export const getTimeObj = (time: number | null): Time => { }; }; -export const getTimeStr = (time: number, truncate: boolean = true): string => { +export const getTimeStr = ( + time: number | null, + truncate: boolean = true +): string => { if (time == null) { return ""; }