« get me outta code hell

mtui - Music Text User Interface - user-friendly command line music player
about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--todo.txt2
-rw-r--r--ui.js48
3 files changed, 46 insertions, 5 deletions
diff --git a/README.md b/README.md
index d233c74..55f5e82 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,7 @@ playlist.json file (usually generated by http-music or downloaded from online).
 * <kbd>Tab</kbd> and <kbd><kbd>Shift</kbd>+<kbd>Tab</kbd></kbd> - switch between UI elements
 * <kbd>1</kbd> - focus the main track/group listing
 * <kbd>2</kbd> - focus the queue listing
+* <kbd>t</kbd> and <kbd>T</kbd> (shift+T) - switch between playlist tabs
 * <kbd>Enter</kbd> - play the selected track
 * <kbd><kbd>Shift</kbd>+<kbd>Up</kbd></kbd> or <kbd>p</kbd> - play previous track
 * <kbd><kbd>Shift</kbd>+<kbd>Down</kbd></kbd> or <kbd>n</kbd> - play next track
diff --git a/todo.txt b/todo.txt
index 658d9f0..41de08a 100644
--- a/todo.txt
+++ b/todo.txt
@@ -63,3 +63,5 @@ TODO: Inspect the inevitable memory issues that are absolutely 100% sure to
 TODO: Canceling the "enter a playlist source" dialog also stops the current song.
 
 TODO: Move TabberElement to tui-lib, at some point.
+
+TODO: Make PathElements selectable (again).
diff --git a/ui.js b/ui.js
index 43039e1..148d2a6 100644
--- a/ui.js
+++ b/ui.js
@@ -78,6 +78,7 @@ class AppElement extends FocusElement {
     this.setupDialog(this.openPlaylistDialog)
 
     this.openPlaylistDialog.on('source selected', source => this.handlePlaylistSource(source))
+    this.openPlaylistDialog.on('source selected (new tab)', source => this.handlePlaylistSource(source, true))
 
     this.alertDialog = new AlertDialog()
     this.setupDialog(this.alertDialog)
@@ -90,6 +91,7 @@ class AppElement extends FocusElement {
   newGrouplikeListing() {
     const grouplikeListing = new GrouplikeListingElement(this.recordStore)
     this.tabber.addTab(grouplikeListing)
+    this.tabber.selectTab(grouplikeListing)
 
     const handleSelectFromMain = item => {
       if (isGroup(item)) {
@@ -118,9 +120,11 @@ class AppElement extends FocusElement {
 
     // this.form.addInput(grouplikeListing.pathElement, false)
     grouplikeListing.pathElement.on('select', item => handleSelectFromPathElement(item))
+
+    return grouplikeListing
   }
 
-  async handlePlaylistSource(source) {
+  async handlePlaylistSource(source, newTab = false) {
     this.openPlaylistDialog.close()
     this.alertDialog.showMessage('Opening playlist...', false)
 
@@ -143,7 +147,13 @@ class AppElement extends FocusElement {
     this.root.select(this.form)
 
     grouplike = await processSmartPlaylist(grouplike)
-    this.tabber.currentElement.loadGrouplike(grouplike)
+
+    if (newTab) {
+      const grouplikeListing = this.newGrouplikeListing()
+      grouplikeListing.loadGrouplike(grouplike)
+    } else {
+      this.tabber.currentElement.loadGrouplike(grouplike)
+    }
   }
 
   openPlaylist(arg) {
@@ -232,6 +242,10 @@ class AppElement extends FocusElement {
       this.form.updateSelectedElement()
     } else if (keyBuf.equals(Buffer.from([15]))) { // ctrl-O
       this.openPlaylistDialog.open()
+    } else if (this.tabber.isSelected && keyBuf.equals(Buffer.from(['t'.charCodeAt(0)]))) {
+      this.tabber.nextTab()
+    } else if (this.tabber.isSelected && keyBuf.equals(Buffer.from(['T'.charCodeAt(0)]))) {
+      this.tabber.previousTab()
     } else {
       super.keyPressed(keyBuf)
     }
@@ -745,7 +759,6 @@ class GrouplikeItemElement extends Button {
   }
 
   keyPressed(keyBuf) {
-    // TODO: Helper function for this
     if (telc.isCaselessLetter(keyBuf, 'd')) {
       this.emit('download')
     } else if (telc.isCaselessLetter(keyBuf, 'q')) {
@@ -929,11 +942,20 @@ class OpenPlaylistDialog extends Dialog {
     this.button = new Button('Open')
     this.form.addInput(this.button)
 
+    this.buttonNewTab = new Button('..in New Tab')
+    this.form.addInput(this.buttonNewTab)
+
     this.button.on('pressed', () => {
       if (this.input.value) {
         this.emit('source selected', this.input.value)
       }
     })
+
+    this.buttonNewTab.on('pressed', () => {
+      if (this.input.value) {
+        this.emit('source selected (new tab)', this.input.value)
+      }
+    })
   }
 
   opened() {
@@ -946,7 +968,7 @@ class OpenPlaylistDialog extends Dialog {
     super.fixLayout()
 
     this.pane.w = Math.min(60, this.contentW)
-    this.pane.h = 5
+    this.pane.h = 6
     this.pane.centerInParent()
 
     this.label.centerInParent()
@@ -960,6 +982,9 @@ class OpenPlaylistDialog extends Dialog {
 
     this.button.centerInParent()
     this.button.y = 1
+
+    this.buttonNewTab.centerInParent()
+    this.buttonNewTab.y = 2
   }
 
   selected() {
@@ -1044,14 +1069,27 @@ class Tabber extends FocusElement {
     this.updateVisibleElement()
   }
 
+  selectTab(element) {
+    if (!this.tabberElements.includes(element)) {
+      throw new Error('That tab does not exist! (Perhaps it was removed, somehow, or was never added?)')
+    }
+
+    this.currentElementIndex = this.tabberElements.indexOf(element)
+    this.updateVisibleElement()
+  }
+
   updateVisibleElement() {
-    const len = this.tabberElements.length
+    const len = this.tabberElements.length - 1
     this.currentElementIndex = Math.min(len, Math.max(0, this.currentElementIndex))
 
     this.tabberElements.forEach((el, i) => {
       el.visible = (i === this.currentElementIndex)
     })
 
+    if (this.isSelected && this.currentElement) {
+      this.root.select(this.currentElement)
+    }
+
     this.fixLayout()
   }