From e8a55f10dd9749ad240b165e318db0a1d2f00a9a Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 1 Jun 2022 23:35:03 -0300 Subject: miscellaneous improvements to queue looping --- backend.js | 9 ++++--- todo.txt | 41 +++++++++++++++++++++++++++++ ui.js | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 117 insertions(+), 20 deletions(-) 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: " 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() -- cgit 1.3.0-6-gf8a5