webamp/js/components/MilkdropWindow/Presets.js
2018-06-11 21:28:41 -07:00

102 lines
2.8 KiB
JavaScript

function getRandomIndex(arr) {
return Math.floor(Math.random() * arr.length);
}
function getRandomValue(arr) {
return arr[getRandomIndex(arr)];
}
function getLast(arr) {
return arr[arr.length - 1];
}
/**
* Track a collection of async loaded presets
*
* Presets can be changed via `next`, `previous` or `selectIndex`. In each case,
* a promise is returned. If the promise resolves to `null` it means the
* selection was canceled by a subsequent request before it could be fulfilled.
* If the request is successful, the promise resolves to the selected preset.
*
* We assume a model where some portion of the preset are supplied at initialization
* and the remainder can be loaded async via the function `getRest`.
*/
export default class Presets {
constructor({ keys, initialPresets, getRest, randomize = true }) {
this._keys = keys; // Alphabetical list of preset names
this._presets = initialPresets; // Presets indexed by name
this._getRest = getRest; // An async function to get the rest of the presets
this._history = []; // Indexes into _keys
this._randomize = randomize;
// Initialize with a key that we already have.
const avaliableKeys = Object.keys(initialPresets);
const currentKey = randomize
? getRandomValue(avaliableKeys)
: avaliableKeys[0];
this._currentIndex = this._keys.indexOf(currentKey);
this._history.push(this._currentIndex);
}
toggleRandomize() {
this._randomize = !this._randomize;
}
setRandomize(val) {
this._randomize = val;
}
async next() {
let idx;
if (this._randomize || this._history.length === 0) {
idx = getRandomIndex(this._keys);
} else {
idx = (getLast(this._history) + 1) % this._keys.length;
}
this._history.push(idx);
return this._selectIndex(idx);
}
async previous() {
if (this._history.length > 1) {
this._history.pop();
return this._selectIndex(getLast(this._history));
}
// We are at the very beginning. There is no "previous" preset.
return Promise.resolve();
}
async selectIndex(idx) {
// The public version of this method must add to the history
this._history.push(idx);
return this._selectIndex(idx);
}
async _selectIndex(idx) {
const preset = this._presets[this._keys[idx]];
if (!preset) {
const rest = await this._getRest();
this._presets = Object.assign(this._presets, rest);
if (getLast(this._history) !== idx) {
// This selection must be obsolete. Return null so that
// the caller knows this request got canceled.
return null;
}
}
this._currentIndex = idx;
return this.getCurrent();
}
getKeys() {
return this._keys;
}
getCurrentIndex() {
return this._currentIndex;
}
getCurrent() {
// #matryoshka
return this._presets[this._keys[this._currentIndex]];
}
}