diff --git a/backend.js b/backend.js
index 36344be..59c4a48 100644
--- a/backend.js
+++ b/backend.js
@@ -338,9 +338,11 @@ class QueuePlayer extends EventEmitter {
}
}
- shuffleQueue() {
+ shuffleQueue(pastPlayingTrackOnly = true) {
const queue = this.queueGrouplike
- const index = queue.items.indexOf(this.playingTrack) + 1 // This is 0 if no track is playing
+ const index = (pastPlayingTrackOnly
+ ? queue.items.indexOf(this.playingTrack) + 1 // This is 0 if no track is playing
+ : 0)
const initialItems = queue.items.slice(0, index)
const remainingItems = queue.items.slice(index)
const newItems = initialItems.concat(shuffleArray(remainingItems))
@@ -517,8 +519,7 @@ class QueuePlayer extends EventEmitter {
this.playFirst()
return true
case 'shuffle':
- this.clearPlayingTrack()
- this.shuffleQueue()
+ this.shuffleQueue(false)
this.playFirst()
return true
case 'end':
diff --git a/todo.txt b/todo.txt
index a6ce5ef..b10c614 100644
--- a/todo.txt
+++ b/todo.txt
@@ -649,3 +649,44 @@ TODO: The "From: <downloaderArg>" text in the playback info element *does* cut
TODO: "Play later" has a slight chance of keeping the track in the same place,
which is accentuated when there's only a couple tracks left in the queue.
+
+TODO: "Loop mode" should be an option under the Queue menu, not Playback.
+ (Done!)
+
+TODO: "Loop mode" setting should be displayed in the queue's length label!
+ Probably on the same line as ex. "2 / 3", and only when the currently
+ playing track is selected.
+ (Done!)
+
+TODO: "Clear past current" and "clear up to current" should probably be visible
+ from the Queue menu!
+
+TODO: The queue length lebel is kinda busy, and doesn't fit everything so well
+ on thinner screens. That should get checked out!
+ (Done!)
+
+TODO: When the last track in the queue finishes playing and the queue is set to
+ shuffle, the currently selected index in the queue listing won't be moved
+ to the new first track (so, reset to zero). The cursor just ends up on
+ whatever track had been the last in the queue (which is obviously now in
+ some random location - even possibly the first track, but usually not).
+ I have a feeling this is the result of shuffling first - which updates
+ the selected index to go to wherever the last track ended up - and then
+ playing the first track, but not moving the cursor back to the start
+ because it's apparently not at the end anymore. But I could be totally
+ misremembering how this code works. :P --- Nope not even related LOL.
+ Good guess though! We don't even have to worry about that situation, with
+ the way selecting the new playing track works. It checks against the
+ track which *was* playing... but that was getting cleared to make the
+ shuffle work properly (applying to the whole queue instead of just the
+ stuff past the current track, which is nothing when you're at its end).
+ Now we just use a flag to ignore the current playback position. Since the
+ currently playing track is retained for the 'playing track' event, the
+ existing code does the rest of the work and selects the newly playing
+ track (whatever's been shuffled to the start) all on its own!
+ (Done!)
+
+TODO: Apparently pressing any key while the UI is booting up will make the
+ screen totally black and unresponsive (and apparently inactive) until the
+ screen is resized. I think we're interrupting a control sequence somehow,
+ and that isn't being handled very well?
diff --git a/ui.js b/ui.js
index 18652f5..dc9dab9 100644
--- a/ui.js
+++ b/ui.js
@@ -351,7 +351,6 @@ class AppElement extends FocusElement {
return [
{label: playingTrack ? `("${playingTrack.name}")` : '(No track playing.)'},
{divider: true},
- {element: this.loopModeControl},
{element: this.volumeSlider},
{divider: true},
playingTrack && {element: this.playingControl},
@@ -373,6 +372,8 @@ class AppElement extends FocusElement {
return [
{label: `(Queue - ${curIndex >= 0 ? `${curIndex + 1}/` : ''}${items.length} items.)`},
{divider: true},
+ {element: this.loopModeControl},
+ {divider: true},
items.length && {label: 'Shuffle', action: () => this.shuffleQueue()},
items.length && {label: 'Clear', action: () => this.clearQueue()}
]
@@ -406,7 +407,7 @@ class AppElement extends FocusElement {
getEnabled: () => this.config.canControlPlayback
})
- this.loopModeControl = new InlineListPickerElement('Loop mode', [
+ this.loopModeControl = new InlineListPickerElement('Loop queue?', [
{value: 'end', label: 'Don\'t loop'},
{value: 'loop', label: 'Loop (same order)'},
{value: 'shuffle', label: 'Loop (shuffle)'}
@@ -1973,7 +1974,7 @@ class AppElement extends FocusElement {
return
}
- const { playingTrack, timeData } = this.SQP
+ const { playingTrack, timeData, queueEndMode } = this.SQP
const { items } = this.SQP.queueGrouplike
const {
currentInput: currentInput,
@@ -2073,25 +2074,34 @@ class AppElement extends FocusElement {
const { duration: durationString } = getTimeStringsFromSec(0, durationTotal)
this.queueTimeLabel.text = `(${durationSymbol + durationString + approxSymbol})`
- let collapseExtraInfo = false
if (playingTrack) {
let trackPart
+ let trackPartShort
+ let trackPartReallyShort
{
const distance = Math.abs(selectedIndex - playingIndex)
let insertString
+ let insertStringShort
if (selectedIndex < playingIndex) {
insertString = ` (-${distance})`
- collapseExtraInfo = true
+ insertStringShort = `-${distance}`
} else if (selectedIndex > playingIndex) {
insertString = ` (+${distance})`
- collapseExtraInfo = true
+ insertStringShort = `+${distance}`
} else {
insertString = ''
+ insertStringShort = ''
}
trackPart = `${playingIndex + 1 + insertString} / ${items.length}`
+ trackPartShort = (insertString
+ ? `${playingIndex + 1 + insertStringShort}/${items.length}`
+ : `${playingIndex + 1}/${items.length}`)
+ trackPartReallyShort = (insertString
+ ? insertStringShort
+ : `#${playingIndex + 1}`)
}
let timestampPart
@@ -2106,10 +2116,8 @@ class AppElement extends FocusElement {
let insertString
if (selectedTimestampIndex < playingTimestampIndex) {
insertString = ` (-${distance})`
- collapseExtraInfo = true
} else if (selectedTimestampIndex > playingTimestampIndex) {
insertString = ` (+${distance})`
- collapseExtraInfo = true
} else {
insertString = ''
}
@@ -2117,19 +2125,66 @@ class AppElement extends FocusElement {
timestampPart = `${playingTimestampIndex + 1 + insertString} / ${timestampData.length}`
}
- if (timestampPart) {
- this.queueLengthLabel.text = `(${this.SQP.playSymbol} ${trackPart} : ${timestampPart})`
- } else {
- this.queueLengthLabel.text = `(${this.SQP.playSymbol} ${trackPart})`
+ let queueLoopPart
+ let queueLoopPartShort
+
+ if (selectedIndex === playingIndex) {
+ switch (queueEndMode) {
+ case 'loop':
+ queueLoopPart = 'Repeat'
+ queueLoopPartShort = 'R'
+ break
+ case 'shuffle':
+ queueLoopPart = 'Shuffle'
+ queueLoopPartShort = 'S'
+ break
+ case 'end':
+ default:
+ break
+ }
+ }
+
+ let partsTogether
+
+ const all = () => `(${this.SQP.playSymbol} ${partsTogether})`
+ const tooWide = () => all().length > this.queuePane.contentW
+
+ // goto irl
+ determineParts: {
+ if (timestampPart) {
+ if (queueLoopPart) {
+ partsTogether = `${trackPart} : ${timestampPart} »${queueLoopPartShort}`
+ } else {
+ partsTogether = `(${this.SQP.playSymbol} ${trackPart} : ${timestampPart})`
+ }
+ break determineParts
+ }
+
+ if (queueLoopPart) includeQueueLoop: {
+ partsTogether = `${trackPart} » ${queueLoopPart}`
+ if (tooWide()) {
+ partsTogether = `${trackPart} »${queueLoopPartShort}`
+ if (tooWide()) {
+ break includeQueueLoop
+ }
+ }
+ break determineParts
+ }
+
+ partsTogether = trackPart
+ if (tooWide()) {
+ partsTogether = trackPartShort
+ if (tooWide()) {
+ partsTogether = trackPartReallyShort
+ }
+ }
}
+
+ this.queueLengthLabel.text = all()
} else {
this.queueLengthLabel.text = `(${items.length})`
}
- if (this.SQP.loopQueueAtEnd) {
- this.queueLengthLabel.text += (collapseExtraInfo ? ` [L${unic.ELLIPSIS}]` : ` [Looping]`)
- }
-
// Layout stuff to position the length and time labels correctly.
this.queueLengthLabel.centerInParent()
this.queueTimeLabel.centerInParent()
|