webamp/js/reducers/windows.ts
2018-10-10 22:15:08 -07:00

292 lines
7.1 KiB
TypeScript

import { Action, WindowId } from "../types";
import { WINDOWS } from "../constants";
import {
SET_FOCUSED_WINDOW,
TOGGLE_WINDOW,
CLOSE_WINDOW,
SET_WINDOW_VISIBILITY,
ADD_GEN_WINDOW,
UPDATE_WINDOW_POSITIONS,
WINDOW_SIZE_CHANGED,
TOGGLE_WINDOW_SHADE_MODE,
LOAD_SERIALIZED_STATE,
BROWSER_WINDOW_SIZE_CHANGED,
RESET_WINDOW_SIZES,
ENABLE_MEDIA_LIBRARY
} from "../actionTypes";
import * as Utils from "../utils";
import { WindowsSerializedStateV1 } from "../serializedStates/v1Types";
export interface WindowPosition {
x: number;
y: number;
}
export type WindowPositions = {
[windowId: string]: WindowPosition;
};
export interface WebampWindow {
title: string;
size: [number, number];
open: boolean;
hidden: boolean;
shade?: boolean;
canResize: boolean;
canShade: boolean;
canDouble: boolean;
generic: boolean;
hotkey?: string;
position: WindowPosition;
}
export interface WindowInfo {
key: WindowId;
height: number;
width: number;
x: number;
y: number;
}
export interface WindowsState {
focused: string;
genWindows: { [name: string]: WebampWindow };
browserWindowSize: { height: number; width: number };
positionsAreRelative: boolean;
}
const defaultWindowsState: WindowsState = {
focused: WINDOWS.MAIN,
positionsAreRelative: true,
genWindows: {
// TODO: Remove static capabilites and derive them from ids/generic
[WINDOWS.MAIN]: {
title: "Main Window",
size: [0, 0],
open: true,
hidden: false,
shade: false,
canResize: false,
canShade: true,
canDouble: true,
generic: false,
hotkey: "Alt+W",
position: { x: 0, y: 0 }
},
[WINDOWS.EQUALIZER]: {
title: "Equalizer",
size: [0, 0],
open: true,
hidden: false,
shade: false,
canResize: false,
canShade: true,
canDouble: true,
generic: false,
hotkey: "Alt+G",
position: { x: 0, y: 0 }
},
[WINDOWS.PLAYLIST]: {
title: "Playlist Editor",
size: [0, 0],
open: true,
hidden: false,
shade: false,
canResize: true,
canShade: true,
canDouble: false,
generic: false,
hotkey: "Alt+E",
position: { x: 0, y: 0 }
}
},
browserWindowSize: { width: 0, height: 0 }
};
const windows = (
state: WindowsState = defaultWindowsState,
action: Action
): WindowsState => {
switch (action.type) {
case ENABLE_MEDIA_LIBRARY:
return {
...state,
genWindows: {
...state.genWindows,
[WINDOWS.MEDIA_LIBRARY]: {
title: "Winamp Library",
size: [0, 0],
open: true,
hidden: false,
shade: false,
canResize: true,
canShade: false,
canDouble: false,
generic: false,
hotkey: "Alt+E",
position: { x: 0, y: 0 }
}
}
};
case SET_FOCUSED_WINDOW:
return { ...state, focused: action.window };
case TOGGLE_WINDOW_SHADE_MODE:
const { canShade } = state.genWindows[action.windowId];
if (!canShade) {
throw new Error(
`Tried to shade/unshade a window that cannot be shaded: ${
action.windowId
}`
);
}
return {
...state,
genWindows: {
...state.genWindows,
[action.windowId]: {
...state.genWindows[action.windowId],
shade: !state.genWindows[action.windowId].shade
}
}
};
case TOGGLE_WINDOW:
const windowState = state.genWindows[action.windowId];
return {
...state,
genWindows: {
...state.genWindows,
[action.windowId]: {
...windowState,
open: !windowState.open,
// Reset hidden state when opening window
hidden: windowState.open ? windowState.hidden : false
}
}
};
case CLOSE_WINDOW:
return {
...state,
genWindows: {
...state.genWindows,
[action.windowId]: {
...state.genWindows[action.windowId],
open: false
}
}
};
case SET_WINDOW_VISIBILITY:
return {
...state,
genWindows: {
...state.genWindows,
[action.windowId]: {
...state.genWindows[action.windowId],
hidden: action.hidden
}
}
};
case ADD_GEN_WINDOW:
return {
...state,
genWindows: {
...state.genWindows,
[action.windowId]: {
title: action.title,
open: action.open,
hidden: false,
size: [0, 0],
canShade: false,
canResize: true,
canDouble: false,
generic: true,
position: { x: 0, y: 0 }
}
}
};
case WINDOW_SIZE_CHANGED:
const { canResize } = state.genWindows[action.windowId];
if (!canResize) {
throw new Error(
`Tried to resize a window that cannot be resized: ${action.windowId}`
);
}
return {
...state,
genWindows: {
...state.genWindows,
[action.windowId]: {
...state.genWindows[action.windowId],
size: action.size
}
}
};
case UPDATE_WINDOW_POSITIONS:
return {
...state,
positionsAreRelative:
action.absolute === true ? false : state.positionsAreRelative,
genWindows: Utils.objectMap(state.genWindows, (w, windowId) => {
const newPosition = action.positions[windowId];
if (newPosition == null) {
return w;
}
return { ...w, position: newPosition };
})
};
case RESET_WINDOW_SIZES:
return {
...state,
genWindows: Utils.objectMap(state.genWindows, w => ({
...w,
// Not sure why TypeScript can't figure this out for itself.
size: [0, 0] as [number, number]
}))
};
case LOAD_SERIALIZED_STATE: {
const {
genWindows,
focused,
positionsAreRelative
} = action.serializedState.windows;
return {
...state,
positionsAreRelative,
genWindows: Utils.objectMap(state.genWindows, (w, windowId) => {
const serializedW = genWindows[windowId];
if (serializedW == null) {
return w;
}
return { ...w, ...serializedW };
}),
focused
};
}
case BROWSER_WINDOW_SIZE_CHANGED:
return {
...state,
browserWindowSize: { height: action.height, width: action.width }
};
default:
return state;
}
};
export function getSerializedState(
state: WindowsState
): WindowsSerializedStateV1 {
return {
positionsAreRelative: state.positionsAreRelative,
genWindows: Utils.objectMap(state.genWindows, w => {
return {
size: w.size,
open: w.open,
hidden: w.hidden,
shade: w.shade || false,
position: w.position
};
}),
focused: state.focused
};
}
export default windows;