mirror of
https://github.com/captbaritone/webamp.git
synced 2026-08-03 15:34:25 +00:00
First draft of public API to configure window layout
This commit is contained in:
parent
dcaf517f86
commit
17f0a393f7
8 changed files with 140 additions and 46 deletions
|
|
@ -62,7 +62,7 @@ export async function getWebampConfig(
|
|||
soundCloudPlaylist: SoundCloud.SoundCloudPlaylist | null
|
||||
): Promise<Options & PrivateOptions> {
|
||||
let __butterchurnOptions;
|
||||
let __initialWindowLayout: WindowLayout | undefined;
|
||||
let windowLayout: WindowLayout | undefined;
|
||||
if (isButterchurnSupported()) {
|
||||
const startWithMilkdropHidden = skinUrl != null || screenshot;
|
||||
|
||||
|
|
@ -72,18 +72,30 @@ export async function getWebampConfig(
|
|||
startWithMilkdropHidden ||
|
||||
document.body.clientWidth < MIN_MILKDROP_WIDTH
|
||||
) {
|
||||
__initialWindowLayout = {
|
||||
[WINDOWS.MAIN]: { position: { x: 0, y: 0 } },
|
||||
[WINDOWS.EQUALIZER]: { position: { x: 0, y: 116 } },
|
||||
[WINDOWS.PLAYLIST]: { position: { x: 0, y: 232 }, size: [0, 0] },
|
||||
[WINDOWS.MILKDROP]: { position: { x: 0, y: 348 }, size: [0, 0] },
|
||||
windowLayout = {
|
||||
main: { position: { left: 0, top: 0 } },
|
||||
equalizer: { position: { left: 0, top: 116 } },
|
||||
playlist: {
|
||||
position: { left: 0, top: 232 },
|
||||
size: { extraHeight: 0, extraWidth: 0 },
|
||||
},
|
||||
milkdrop: {
|
||||
position: { left: 0, top: 348 },
|
||||
size: { extraHeight: 0, extraWidth: 0 },
|
||||
},
|
||||
};
|
||||
} else {
|
||||
__initialWindowLayout = {
|
||||
[WINDOWS.MAIN]: { position: { x: 0, y: 0 } },
|
||||
[WINDOWS.EQUALIZER]: { position: { x: 0, y: 116 } },
|
||||
[WINDOWS.PLAYLIST]: { position: { x: 0, y: 232 }, size: [0, 4] },
|
||||
[WINDOWS.MILKDROP]: { position: { x: 275, y: 0 }, size: [7, 12] },
|
||||
windowLayout = {
|
||||
main: { position: { left: 0, top: 0 } },
|
||||
equalizer: { position: { left: 0, top: 116 } },
|
||||
playlist: {
|
||||
position: { left: 0, top: 232 },
|
||||
size: { extraHeight: 4, extraWidth: 0 },
|
||||
},
|
||||
milkdrop: {
|
||||
position: { left: 275, top: 0 },
|
||||
size: { extraHeight: 12, extraWidth: 7 },
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -99,6 +111,7 @@ export async function getWebampConfig(
|
|||
? SoundCloud.tracksFromPlaylist(soundCloudPlaylist)
|
||||
: initialTracks,
|
||||
availableSkins,
|
||||
windowLayout,
|
||||
filePickers: [dropboxFilePicker],
|
||||
enableHotkeys: true,
|
||||
handleTrackDropEvent: (e) => {
|
||||
|
|
@ -120,7 +133,6 @@ export async function getWebampConfig(
|
|||
import(
|
||||
/* webpackChunkName: "music-metadata-browser" */ "music-metadata-browser/dist/index"
|
||||
),
|
||||
__initialWindowLayout,
|
||||
__initialState: screenshot ? screenshotInitialState : initialState,
|
||||
__butterchurnOptions,
|
||||
__customMiddlewares: [sentryMiddleware, loggerMiddleware],
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ export {
|
|||
stackWindows,
|
||||
toggleLlamaMode,
|
||||
setFocusedWindow,
|
||||
setWindowLayout,
|
||||
} from "./windows";
|
||||
export {
|
||||
play,
|
||||
|
|
|
|||
|
|
@ -16,13 +16,20 @@ import {
|
|||
|
||||
import { getPositionDiff, SizeDiff } from "../resizeUtils";
|
||||
import { applyDiff } from "../snapUtils";
|
||||
import { Action, Thunk, WindowId, WindowPositions, Dispatch } from "../types";
|
||||
import {
|
||||
Action,
|
||||
Thunk,
|
||||
WindowId,
|
||||
WindowPositions,
|
||||
Dispatch,
|
||||
WindowLayout,
|
||||
} from "../types";
|
||||
|
||||
// Dispatch an action and, if needed rearrange the windows to preserve
|
||||
// the existing edge relationship.
|
||||
//
|
||||
// Works by checking the edges before the action is dispatched. Then,
|
||||
// after disatching, calculating what position change would be required
|
||||
// after dispatching, calculating what position change would be required
|
||||
// to restore those relationships.
|
||||
function withWindowGraphIntegrity(action: Action): Thunk {
|
||||
return (dispatch, getState) => {
|
||||
|
|
@ -197,6 +204,45 @@ export function stackWindows(): Thunk {
|
|||
};
|
||||
}
|
||||
|
||||
export function setWindowLayout(layout?: WindowLayout): Thunk {
|
||||
return (dispatch) => {
|
||||
if (layout == null) {
|
||||
dispatch(stackWindows());
|
||||
return;
|
||||
}
|
||||
for (const id of ["playlist", "milkdrop"] as const) {
|
||||
const w = layout[id];
|
||||
if (w != null && w.size != null) {
|
||||
const { extraHeight: plusHeight, extraWidth: plusWidth } = w.size;
|
||||
dispatch(setWindowSize(id, [plusWidth, plusHeight]));
|
||||
}
|
||||
}
|
||||
for (const id of ["main", "playlist", "equalizer", "milkdrop"] as const) {
|
||||
const w = layout[id];
|
||||
if (w == null || w.closed) {
|
||||
dispatch(closeWindow(id));
|
||||
}
|
||||
}
|
||||
for (const id of ["main", "playlist", "equalizer"] as const) {
|
||||
if (layout[id]?.shadeMode) {
|
||||
dispatch({
|
||||
type: TOGGLE_WINDOW_SHADE_MODE,
|
||||
windowId: id,
|
||||
});
|
||||
}
|
||||
}
|
||||
dispatch(
|
||||
updateWindowPositions(
|
||||
Utils.objectMap(layout, (w) => ({
|
||||
x: w.position.left,
|
||||
y: w.position.top,
|
||||
})),
|
||||
false
|
||||
)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export function ensureWindowsAreOnScreen(): Thunk {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@ import {
|
|||
MediaStatus,
|
||||
LoadStyle,
|
||||
TimeMode,
|
||||
WindowId,
|
||||
} from "./types";
|
||||
import baseSkin from "./baseSkin.json";
|
||||
export const BANDS: Band[] = [
|
||||
60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000,
|
||||
];
|
||||
|
||||
export const WINDOWS = {
|
||||
export const WINDOWS: { [key: string]: WindowId } = {
|
||||
MAIN: "main",
|
||||
PLAYLIST: "playlist",
|
||||
EQUALIZER: "equalizer",
|
||||
|
|
|
|||
|
|
@ -15,10 +15,8 @@ import {
|
|||
import * as Utils from "../utils";
|
||||
import { WindowsSerializedStateV1 } from "../serializedStates/v1Types";
|
||||
|
||||
export type WindowPosition = Point;
|
||||
|
||||
export type WindowPositions = {
|
||||
[windowId: string]: WindowPosition;
|
||||
[windowId: string]: Point;
|
||||
};
|
||||
|
||||
export interface WebampWindow {
|
||||
|
|
@ -30,7 +28,7 @@ export interface WebampWindow {
|
|||
canShade: boolean;
|
||||
canDouble: boolean;
|
||||
hotkey?: string;
|
||||
position: WindowPosition;
|
||||
position: Point;
|
||||
}
|
||||
|
||||
export interface WindowInfo extends Box {
|
||||
|
|
@ -48,7 +46,7 @@ const defaultWindowsState: WindowsState = {
|
|||
focused: WINDOWS.MAIN,
|
||||
positionsAreRelative: true,
|
||||
genWindows: {
|
||||
// TODO: Remove static capabilites and derive them from ids/generic
|
||||
// TODO: Remove static capabilities and derive them from ids/generic
|
||||
[WINDOWS.MAIN]: {
|
||||
title: "Main Window",
|
||||
size: [0, 0],
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
* NOTE: This file must not import any other types
|
||||
*/
|
||||
|
||||
import { WindowId } from "../types";
|
||||
|
||||
export interface WindowsSerializedStateV1 {
|
||||
positionsAreRelative: boolean;
|
||||
genWindows: {
|
||||
|
|
@ -13,7 +15,7 @@ export interface WindowsSerializedStateV1 {
|
|||
position: { x: number; y: number };
|
||||
};
|
||||
};
|
||||
focused: string | null;
|
||||
focused: WindowId | null;
|
||||
}
|
||||
|
||||
export interface DisplaySerializedStateV1 {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import {
|
|||
WindowPositions as _WindowPositions,
|
||||
WebampWindow as _WebampWindow,
|
||||
WindowInfo as _WindowInfo,
|
||||
WindowPosition as _WindowPosition,
|
||||
} from "./reducers/windows";
|
||||
import { EqualizerState } from "./reducers/equalizer";
|
||||
import { NetworkState } from "./reducers/network";
|
||||
|
|
@ -22,7 +21,6 @@ import { Store as ReduxStore } from "redux";
|
|||
// Avoid warnings from Webpack: https://github.com/webpack/webpack/issues/7378
|
||||
export type WebampWindow = _WebampWindow;
|
||||
export type WindowInfo = _WindowInfo;
|
||||
export type WindowPosition = _WindowPosition;
|
||||
export type WindowPositions = _WindowPositions;
|
||||
|
||||
export interface Point {
|
||||
|
|
@ -149,7 +147,7 @@ export interface SkinGenExColors {
|
|||
listTextSelectedBackground: string;
|
||||
}
|
||||
|
||||
export type WindowId = string;
|
||||
export type WindowId = "main" | "playlist" | "equalizer" | "milkdrop";
|
||||
|
||||
// TODO: Fill these out once we actually use them.
|
||||
export type SkinData = {
|
||||
|
|
@ -659,6 +657,8 @@ export interface Options {
|
|||
*/
|
||||
availableSkins?: { url: string; name: string }[];
|
||||
|
||||
windowLayout?: WindowLayout;
|
||||
|
||||
/**
|
||||
* Should global hotkeys be enabled?
|
||||
*
|
||||
|
|
@ -671,7 +671,7 @@ export interface Options {
|
|||
*
|
||||
* These will appear in the "Options" menu under "Play".
|
||||
*
|
||||
* In the offical version, this option is used to provide a "Dropbox" file picker.
|
||||
* For example, this option can be used to provide a "Dropbox" file picker.
|
||||
*/
|
||||
filePickers?: [
|
||||
{
|
||||
|
|
@ -704,11 +704,63 @@ export interface Options {
|
|||
handleSaveListEvent?: (tracks: Track[]) => null | Promise<null>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the initial position and size of a the Winamp windows.
|
||||
*
|
||||
* Positions are specified in pixels from the top left corner of an imaginary
|
||||
* box. On initial render, the collection of visible windows will be centered
|
||||
* within the HTML element passed to `Webamp.renderWhenReady(element)`. In other
|
||||
* words, the positions given here will determine the _relative_ position of the
|
||||
* windows. The absolute position will be determined by the HTML element in
|
||||
* which Webamp is centered.
|
||||
*
|
||||
* Enabling "shade mode" for a window that supports it, will cause it to be
|
||||
* rendered minimized. Be default windows are not in shade mode.
|
||||
*
|
||||
* Windows which support resizing can have their size specified. If omitted,
|
||||
* they default to their small base size.
|
||||
*
|
||||
* Windows that are omitted will start closed. Enabling "closed" for a window
|
||||
* that supports it, will cause it to start closed.
|
||||
*/
|
||||
export type WindowLayout = {
|
||||
[windowId: string]: {
|
||||
size?: null | [number, number];
|
||||
main?: {
|
||||
position: WindowPosition;
|
||||
shadeMode?: boolean;
|
||||
closed?: boolean;
|
||||
};
|
||||
equalizer?: {
|
||||
position: WindowPosition;
|
||||
shadeMode?: boolean;
|
||||
closed?: boolean;
|
||||
};
|
||||
playlist?: {
|
||||
position: WindowPosition;
|
||||
shadeMode?: boolean;
|
||||
size?: WindowSize | null;
|
||||
closed?: boolean;
|
||||
};
|
||||
milkdrop?: {
|
||||
position: WindowPosition;
|
||||
size?: WindowSize | null;
|
||||
closed?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export type WindowPosition = { top: number; left: number };
|
||||
|
||||
/**
|
||||
* Resizable windows in Winamp have a base size and can be expanded in
|
||||
* increments based on the size of the skin sprite.
|
||||
*
|
||||
* To specify a window being larger than its base size, use `extraHeight` to
|
||||
* specify how many sprite increments to expand the window's height by, and
|
||||
* `extraWidth` to specify how many sprite increments to expand the window's
|
||||
* width by.
|
||||
*/
|
||||
export type WindowSize = {
|
||||
extraHeight: number;
|
||||
extraWidth: number;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import {
|
|||
Middleware,
|
||||
ButterchurnOptions,
|
||||
PartialState,
|
||||
WindowLayout,
|
||||
Options,
|
||||
MediaStatus,
|
||||
} from "./types";
|
||||
|
|
@ -22,7 +21,6 @@ import * as Selectors from "./selectors";
|
|||
import * as Actions from "./actionCreators";
|
||||
|
||||
import { LOAD_STYLE } from "./constants";
|
||||
import * as Utils from "./utils";
|
||||
import * as FileUtils from "./fileUtils";
|
||||
|
||||
import {
|
||||
|
|
@ -46,7 +44,6 @@ export interface PrivateOptions {
|
|||
requireMusicMetadata(): Promise<any>; // TODO: Type musicmetadata
|
||||
__initialState?: PartialState;
|
||||
__customMiddlewares?: Middleware[];
|
||||
__initialWindowLayout?: WindowLayout;
|
||||
__butterchurnOptions?: ButterchurnOptions;
|
||||
// This is used by https://winampify.io/ to proxy through to Spotify's API.
|
||||
__customMediaClass?: typeof Media; // This should have the same interface as Media
|
||||
|
|
@ -189,22 +186,7 @@ class Webamp {
|
|||
this.store.dispatch({ type: SET_AVAILABLE_SKINS, skins: availableSkins });
|
||||
}
|
||||
|
||||
const layout = options.__initialWindowLayout;
|
||||
if (layout == null) {
|
||||
this.store.dispatch(Actions.stackWindows());
|
||||
} else {
|
||||
Utils.objectForEach(layout, (w, windowId) => {
|
||||
if (w.size != null) {
|
||||
this.store.dispatch(Actions.setWindowSize(windowId, w.size));
|
||||
}
|
||||
});
|
||||
this.store.dispatch(
|
||||
Actions.updateWindowPositions(
|
||||
Utils.objectMap(layout, (w) => w.position),
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
this.store.dispatch(Actions.setWindowLayout(options.windowLayout));
|
||||
|
||||
if (enableHotkeys) {
|
||||
this._disposable.add(bindHotkeys(this.store.dispatch));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue