Reverse, randomize, sort

This commit is contained in:
Jordan Eldredge 2017-11-18 13:42:04 -08:00
parent ee37da98b2
commit 308a1bcd3f
6 changed files with 113 additions and 14 deletions

View file

@ -4,7 +4,13 @@ import skinParser from "./skinParser";
import { BANDS } from "./constants";
import { getEqfData } from "./selectors";
import { clamp, base64FromArrayBuffer, downloadURI, normalize } from "./utils";
import {
clamp,
base64FromArrayBuffer,
downloadURI,
normalize,
sort
} from "./utils";
import {
CLOSE_WINAMP,
LOAD_AUDIO_FILE,
@ -25,7 +31,10 @@ import {
CLOSE_EQUALIZER_WINDOW,
REMOVE_TRACKS,
PLAY,
PAUSE
PAUSE,
REVERSE_LIST,
RANDOMIZE_LIST,
SET_TRACK_ORDER
} from "./actionTypes";
export function play() {
@ -247,3 +256,21 @@ export function removeSelectedTracks() {
});
};
}
export function reverseList() {
return { type: REVERSE_LIST };
}
export function randomizeList() {
return { type: RANDOMIZE_LIST };
}
export function sortListByTitle() {
return (dispatch, getState) => {
const state = getState();
const trackOrder = sort(state.playlist.trackOrder, i =>
state.tracks[i].title.toLowerCase()
);
return dispatch({ type: SET_TRACK_ORDER, trackOrder });
};
}

View file

@ -52,3 +52,6 @@ export const CROP_TRACKS = "CROP_TRACKS";
export const FILE_INFO = "FILE_INFO";
export const REMOVE_TRACKS = "REMOVE_TRACKS";
export const SET_AVALIABLE_SKINS = "SET_AVALIABLE_SKINS";
export const REVERSE_LIST = "REVERSE_LIST";
export const RANDOMIZE_LIST = "RANDOMIZE_LIST";
export const SET_TRACK_ORDER = "SET_TRACK_ORDER";

View file

@ -1,17 +1,35 @@
import React from "react";
import { connect } from "react-redux";
import { FILE_INFO } from "../../actionTypes";
import {
reverseList,
randomizeList,
sortListByTitle
} from "../../actionCreators";
import PlaylistMenu from "./PlaylistMenu";
import { ContextMenu, Hr, Node } from "../ContextMenu";
/* eslint-disable no-alert */
/* TODO: This should really be kitty-corner to the upper right hand corner of the MiscMenu */
const SortContextMenu = props => (
<ContextMenu style={{ width: "100%", height: "100%" }} top handle={<div />}>
<Node label="Sort list by title" onClick={props.sortListByTitle} />
<Hr />
<Node label="Reverse list" onClick={props.reverseList} />
<Node label="Randomize list" onClick={props.randomizeList} />
</ContextMenu>
);
const ConnectedSortcontextMenu = connect(null, {
reverseList,
randomizeList,
sortListByTitle
})(SortContextMenu);
const MiscMenu = () => (
<PlaylistMenu id="playlist-misc-menu">
<div
className="sort-list"
onClick={() => alert("Not supported in Winamp2-js")}
/>
{/* onClick={props.fileInfo} */}
<div className="sort-list" onClick={e => e.stopPropagation()}>
<ConnectedSortcontextMenu />
</div>
<div
className="file-info"
onClick={() => alert("Not supported in Winamp2-js")}
@ -23,7 +41,4 @@ const MiscMenu = () => (
</PlaylistMenu>
);
const mapDispatchToProps = {
fileInfo: () => ({ type: FILE_INFO })
};
export default connect(null, mapDispatchToProps)(MiscMenu);
export default MiscMenu;

View file

@ -7,7 +7,8 @@ import {
toggleShuffle,
openFileDialog,
seekForward,
seekBackward
seekBackward,
reverseList
} from "./actionCreators";
import {
@ -40,6 +41,9 @@ export default function(fileInput, { dispatch }) {
break;
case 76: // CTRL+L FIXME
break;
case 82: // CTRL+R
dispatch(reverseList());
break;
case 84: // CTRL+T
dispatch({ type: TOGGLE_TIME_MODE });
break;

View file

@ -45,9 +45,13 @@ import {
REMOVE_TRACKS,
SET_AVALIABLE_SKINS,
LOAD_AUDIO_FILE,
LOAD_AUDIO_URL
LOAD_AUDIO_URL,
REVERSE_LIST,
RANDOMIZE_LIST,
SET_TRACK_ORDER
} from "./actionTypes";
import { playlistEnabled } from "./config";
import { shuffle } from "./utils";
const mapObject = (obj, iteratee) =>
// TODO: Could return the original reference if no values change
@ -317,6 +321,20 @@ const playlist = (state = defaultPlaylistState, action) => {
...state,
trackOrder: state.trackOrder.filter(id => !action.ids.includes(id))
};
case REVERSE_LIST:
return {
...state,
trackOrder: [...state.trackOrder].reverse()
};
case RANDOMIZE_LIST:
return {
...state,
trackOrder: shuffle(state.trackOrder)
};
case SET_TRACK_ORDER:
const { trackOrder } = action;
return { ...state, trackOrder };
default:
return state;
}

View file

@ -114,3 +114,35 @@ export const segment = (min, max, value, newValues) => {
export const arraysAreEqual = (a, b) =>
a.length === b.length && a.every((value, i) => value === b[i]);
// https://bost.ocks.org/mike/shuffle/
// Shuffle an array in O(n)
export const shuffle = array => {
const sorted = [...array];
let m = sorted.length;
// While there remain elements to shuffle…
while (m) {
// Pick a remaining element…
const i = Math.floor(Math.random() * m--);
// And swap it with the current element.
const val = sorted[m];
sorted[m] = sorted[i];
sorted[i] = val;
}
return sorted;
};
export const sort = (array, iteratee) =>
array.sort((a, b) => {
const aKey = iteratee(a);
const bKey = iteratee(b);
if (aKey < bKey) {
return -1;
} else if (aKey > bKey) {
return 1;
}
return 0;
});