« get me outta code hell

"Distribute" options - mtui - Music Text User Interface - user-friendly command line music player
about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlorrie <towerofnix@gmail.com>2018-12-21 10:58:28 -0400
committerFlorrie <towerofnix@gmail.com>2018-12-21 11:07:40 -0400
commit8438f8319149dae9f594a57eb0807ba2f8bba7d8 (patch)
tree23ebdb1525e6b6d2f23d6f7446ded2eb0e9133c9
parent4d1702b630b6f8f4893e35bb11f5bc6a342731a1 (diff)
"Distribute" options
E.g. to interweave two groups together.
-rw-r--r--todo.txt12
-rw-r--r--ui.js80
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 <group>)" 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?', [