webamp/js/reducers/display.ts
2018-10-12 23:28:38 -07:00

228 lines
6 KiB
TypeScript

import {
Action,
SkinImages,
Cursors,
SkinRegion,
GenLetterWidths,
PlaylistStyle,
SkinGenExColors,
DummyVizData
} from "../types";
import { createSelector } from "reselect";
import {
CLOSE_WINAMP,
SET_SKIN_DATA,
START_WORKING,
STEP_MARQUEE,
STOP_WORKING,
TOGGLE_DOUBLESIZE_MODE,
TOGGLE_LLAMA_MODE,
TOGGLE_VISUALIZER_STYLE,
SET_PLAYLIST_SCROLL_POSITION,
LOADED,
REGISTER_VISUALIZER,
SET_Z_INDEX,
DISABLE_MARQUEE,
SET_DUMMY_VIZ_DATA,
LOADING,
LOAD_SERIALIZED_STATE,
LOAD_DEFAULT_SKIN
} from "../actionTypes";
import { DEFAULT_SKIN, VISUALIZER_ORDER } from "../constants";
import { DisplaySerializedStateV1 } from "../serializedStates/v1Types";
export interface DisplayState {
additionalVisualizers: Array<string>;
visualizerStyle: number;
doubled: boolean;
llama: boolean;
disableMarquee: boolean;
marqueeStep: number;
skinImages: SkinImages;
skinCursors: Cursors | null;
skinRegion: SkinRegion;
skinGenLetterWidths: GenLetterWidths | null;
skinColors: string[]; // Theoretically this could be a tuple of a specific length
skinPlaylistStyle: PlaylistStyle | null;
skinGenExColors: SkinGenExColors;
working: boolean;
closed: boolean;
loading: boolean;
playlistScrollPosition: number;
zIndex: number;
dummyVizData: DummyVizData | null;
}
const defaultSkinGenExColors = {
itemBackground: "rgb(0,0,0)",
itemForeground: "rgb(0,255,0)",
windowBackground: "rgb(56,55,87)",
buttonText: "rgb(57,57,66)",
windowText: "rgb(255,255,255)",
divider: "rgb(117,116,139)",
playlistSelection: "rgb(0,0,198)",
listHeaderBackground: "rgb(72,72,120)",
listHeaderText: "rgb(255,255,255)",
listHeaderFrameTopAndLeft: "rgb(108,108,180)",
listHeaderFrameBottomAndRight: "rgb(36,36,60)",
listHeaderFramePressed: "rgb(18,18,30)",
listHeaderDeadArea: "rgb(36,36,60)",
scrollbarOne: "rgb(36,36,60)",
scrollbarTwo: "rgb(36,36,60)",
pressedScrollbarOne: "rgb(121,130,150)",
pressedScrollbarTwo: "rgb(78,88,110)",
scrollbarDeadArea: "rgb(36,36,60)",
listTextHighlighted: "rgb(0,198,255)",
listTextHighlightedBackground: "rgb(0,198,255)",
listTextSelected: "rgb(0,198,255)",
listTextSelectedBackground: "rgb(0,198,255)"
};
const defaultDisplayState = {
doubled: false,
marqueeStep: 0,
disableMarquee: false,
loading: true,
llama: false,
closed: false,
working: false,
skinImages: DEFAULT_SKIN.images,
skinColors: DEFAULT_SKIN.colors,
skinCursors: null,
skinPlaylistStyle: null,
skinRegion: {},
visualizerStyle: 0, // Index into VISUALIZER_ORDER
dummyVizData: null,
playlistScrollPosition: 0,
skinGenLetterWidths: null, // TODO: Get the default value for this?
skinGenExColors: defaultSkinGenExColors,
additionalVisualizers: [],
zIndex: 0
};
const display = (
state: DisplayState = defaultDisplayState,
action: Action
): DisplayState => {
switch (action.type) {
case LOAD_DEFAULT_SKIN:
const {
skinImages,
skinColors,
skinCursors,
skinPlaylistStyle,
skinRegion,
skinGenLetterWidths,
skinGenExColors
} = defaultDisplayState;
return {
...state,
skinImages,
skinColors,
skinCursors,
skinPlaylistStyle,
skinRegion,
skinGenLetterWidths,
skinGenExColors
};
case TOGGLE_DOUBLESIZE_MODE:
return { ...state, doubled: !state.doubled };
case TOGGLE_LLAMA_MODE:
return { ...state, llama: !state.llama };
case STEP_MARQUEE:
return state.disableMarquee
? state
: { ...state, marqueeStep: state.marqueeStep + 1 };
case DISABLE_MARQUEE:
return { ...state, disableMarquee: true };
case STOP_WORKING:
return { ...state, working: false };
case START_WORKING:
return { ...state, working: true };
case CLOSE_WINAMP:
return { ...state, closed: true };
case LOADING:
return { ...state, loading: true };
case LOADED:
return { ...state, loading: false };
case SET_SKIN_DATA:
const { data } = action;
return {
...state,
loading: false,
skinImages: data.skinImages,
skinColors: data.skinColors,
skinPlaylistStyle: data.skinPlaylistStyle,
skinCursors: data.skinCursors,
skinRegion: data.skinRegion,
skinGenLetterWidths: data.skinGenLetterWidths,
skinGenExColors: data.skinGenExColors || defaultSkinGenExColors
};
case TOGGLE_VISUALIZER_STYLE:
return {
...state,
visualizerStyle:
(state.visualizerStyle + 1) % getVisualizationOrder(state).length
};
case REGISTER_VISUALIZER:
return {
...state,
additionalVisualizers: [action.id, ...state.additionalVisualizers]
};
case SET_PLAYLIST_SCROLL_POSITION:
return { ...state, playlistScrollPosition: action.position };
case SET_Z_INDEX:
return { ...state, zIndex: action.zIndex };
case SET_DUMMY_VIZ_DATA:
return { ...state, dummyVizData: action.data };
case LOAD_SERIALIZED_STATE:
return { ...state, ...action.serializedState.display };
default:
return state;
}
};
export default display;
export const getSerializedState = (
state: DisplayState
): DisplaySerializedStateV1 => {
// My kingdom for a type-safe `_.pick`.
const {
visualizerStyle,
doubled,
llama,
marqueeStep,
skinImages,
skinCursors,
skinRegion,
skinGenLetterWidths,
skinColors,
skinPlaylistStyle
} = state;
return {
visualizerStyle,
doubled,
llama,
marqueeStep,
skinImages,
skinCursors,
skinRegion,
skinGenLetterWidths,
skinColors,
skinPlaylistStyle
};
};
export const getVisualizationOrder = (state: DisplayState): Array<string> => {
return [...state.additionalVisualizers, ...VISUALIZER_ORDER];
};
export const getVisualizerStyle = createSelector(
getVisualizationOrder,
state => state.visualizerStyle,
(visualizationOrder, visualizationStyle): string => {
return visualizationOrder[visualizationStyle];
}
);