From 8438f8319149dae9f594a57eb0807ba2f8bba7d8 Mon Sep 17 00:00:00 2001 From: Florrie Date: Fri, 21 Dec 2018 10:58:28 -0400 Subject: "Distribute" options E.g. to interweave two groups together. --- todo.txt | 12 ++++++++++ ui.js | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 84 insertions(+), 8 deletions(-) diff --git a/todo.txt b/todo.txt index dcd847f..530af15 100644 --- a/todo.txt +++ b/todo.txt @@ -145,3 +145,15 @@ TODO: The "Up (to )" and "(This group has no items)" elements are not quite buttons nor grouplike items. They should be more consistent with actual grouplike items (i.e. same behavior and appearance), and should be less buggy. (Done!) + +TODO: "Distribute" options in play/queue menu -- "don't distribute", "spread + (across queue?) evenly", "spread randomly". (Done!) + +TODO: Investigate how to make "distribute" options work better when the + currently-playing song is contained in the group to be distributed. + +TODO: The "distribute" options shouldn't show up when you've only got a track + selected! But imagine you already had a "distribute" option selected when + you open up the menu on a track. Is there a way to not mutate the index + of the whereControl in that case (until the user changes the option)? + Like the DS home screen. diff --git a/ui.js b/ui.js index 6f8b07a..3496d97 100644 --- a/ui.js +++ b/ui.js @@ -118,14 +118,18 @@ class AppElement extends FocusElement { } } - let afterItem = null - if (where === 'next') { - afterItem = this.playingTrack - } + if (where === 'next' || where === 'end') { + let afterItem = null + if (where === 'next') { + afterItem = this.playingTrack + } - this.queueGrouplikeItem(item, afterItem, { - movePlayingTrack: order === 'normal' - }) + this.queueGrouplikeItem(item, afterItem, { + movePlayingTrack: order === 'normal' + }) + } else if (where.startsWith('distribute-')) { + this.distributeQueueGrouplikeItem(item, where.slice('distribute-'.length)) + } if (play) { this.playGrouplikeItem(item) @@ -505,6 +509,64 @@ class AppElement extends FocusElement { return newTrack } + distributeQueueGrouplikeItem(grouplike, how = 'evenly') { + const queue = this.queueGrouplike + const newItems = flattenGrouplike(grouplike).items + + // Expressly do an initial pass and unqueue the items we want to queue - + // otherwise they would mess with the math we do afterwords. + for (const item of newItems) { + if (queue.items.includes(item)) { + /* + if (!movePlayingTrack && item === this.playingTrack) { + // NB: if uncommenting this code, splice item from newItems and do + // continue instead of return! + return + } + */ + queue.items.splice(queue.items.indexOf(item), 1) + } + } + + const distributeStart = queue.items.indexOf(this.playingTrack) + 1 + const distributeEnd = queue.items.length + const distributeSize = distributeEnd - distributeStart + + const queueItem = (item, insertIndex) => { + if (queue.items.includes(item)) { + /* + if (!movePlayingTrack && item === this.playingTrack) { + return + } + */ + queue.items.splice(queue.items.indexOf(item), 1) + } else { + offset++ + } + queue.items.splice(insertIndex, 0, item) + } + + if (how === 'evenly') { + let offset = 0 + for (const item of newItems) { + const insertIndex = distributeStart + Math.floor(offset) + queue.items.splice(insertIndex, 0, item) + offset++ + offset += distributeSize / newItems.length + } + } else if (how === 'randomly') { + const indexes = newItems.map(() => Math.floor(Math.random() * distributeSize)) + indexes.sort() + for (let i = 0; i < newItems.length; i++) { + const item = newItems[i] + const insertIndex = distributeStart + indexes[i] + i + queue.items.splice(insertIndex, 0, item) + } + } + + this.queueListingElement.buildItems() + } + unqueueGrouplikeItem(topItem) { // This function has support to unqueue groups - it removes all tracks in // the group recursively. (You can never unqueue a group itself from the @@ -1177,7 +1239,9 @@ class InteractiveGrouplikeItemElement extends BasicGrouplikeItemElement { this.whereControl = new InlineListPickerElement('Where?', [ {value: 'next', label: 'After current song'}, - {value: 'end', label: 'At end of queue'} + {value: 'end', label: 'At end of queue'}, + {value: 'distribute-evenly', label: 'Distributed across queue evenly'}, + {value: 'distribute-randomly', label: 'Distributed across queue randomly'} ]) this.orderControl = new InlineListPickerElement('Order?', [ -- cgit 1.3.0-6-gf8a5