From df99d463242a30e863a3c84253549a18e2170d45 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sun, 18 Jul 2021 20:00:24 -0300 Subject: miscellaneous improvements to selection restoring --- backend.js | 9 ++-- ui.js | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 156 insertions(+), 33 deletions(-) diff --git a/backend.js b/backend.js index e2213d5..e38fe2f 100644 --- a/backend.js +++ b/backend.js @@ -85,8 +85,9 @@ class QueuePlayer extends EventEmitter { this.player.on('printStatusLine', data => { if (this.playingTrack) { + const oldTimeData = this.timeData this.timeData = data - this.emit('received time data', data, this) + this.emit('received time data', data, oldTimeData, this) } }) @@ -368,7 +369,7 @@ class QueuePlayer extends EventEmitter { } - async play(item, startTime) { + async play(item, startTime = 0) { if (this.player === null) { throw new Error('Attempted to play before a player was loaded') } @@ -415,7 +416,7 @@ class QueuePlayer extends EventEmitter { this.timeData = null this.playingTrack = item - this.emit('playing', this.playingTrack, oldTrack, this) + this.emit('playing', this.playingTrack, oldTrack, startTime, this) await this.player.kill() if (this.playedTrackToEnd) { @@ -536,7 +537,7 @@ class QueuePlayer extends EventEmitter { const oldTrack = this.playingTrack this.playingTrack = null this.timeData = null - this.emit('playing', null, oldTrack, this) + this.emit('playing', null, oldTrack, 0, this) } } diff --git a/ui.js b/ui.js index bc7f68d..a5481c8 100644 --- a/ui.js +++ b/ui.js @@ -536,7 +536,7 @@ class AppElement extends FocusElement { this.updateQueueLengthLabel() } - async handlePlaying(track, oldTrack, queuePlayer) { + async handlePlaying(track, oldTrack, startTime, queuePlayer) { const PIE = this.getPlaybackInfoElementForQueuePlayer(queuePlayer) if (PIE) { PIE.updateTrack() @@ -544,6 +544,7 @@ class AppElement extends FocusElement { if (queuePlayer === this.SQP) { this.updateQueueLengthLabel() + this.queueListingElement.collapseTimestamps(oldTrack) if (track && this.queueListingElement.currentItem === oldTrack) { this.queueListingElement.selectAndShow(track) } @@ -553,12 +554,9 @@ class AppElement extends FocusElement { // the containing queue isn't of the selected queue player. const timestampData = track && this.getTimestampData(track) if (timestampData && queuePlayer === this.SQP) { - this.queueListingElement.expandTimestamps(track) - } - - const oldTimestampData = oldTrack && this.getTimestampData(oldTrack) - if (oldTimestampData && queuePlayer === this.SQP) { - this.queueListingElement.collapseTimestamps(oldTrack) + if (this.queueListingElement.currentItem === track) { + this.queueListingElement.selectTimestampAtSec(track, startTime) + } } if (track && this.enableAutoDJ) { @@ -573,7 +571,7 @@ class AppElement extends FocusElement { } } - handleReceivedTimeData(data, queuePlayer) { + handleReceivedTimeData(timeData, oldTimeData, queuePlayer) { const PIE = this.getPlaybackInfoElementForQueuePlayer(queuePlayer) if (PIE) { PIE.updateProgress() @@ -581,6 +579,7 @@ class AppElement extends FocusElement { if (queuePlayer === this.SQP) { this.updateQueueLengthLabel() + this.updateQueueSelection(timeData, oldTimeData) } } @@ -1920,11 +1919,11 @@ class AppElement extends FocusElement { const { playingTrack, timeData } = this.SQP const { items } = this.SQP.queueGrouplike const { - currentInput: selectedInput, + currentInput: currentInput, currentItem: selectedTrack } = this.queueListingElement - const isTimestamp = (selectedInput instanceof TimestampGrouplikeItemElement) + const isTimestamp = (currentInput instanceof TimestampGrouplikeItemElement) let trackRemainSec = 0 let trackPassedSec = 0 @@ -1962,7 +1961,7 @@ class AppElement extends FocusElement { durationSymbol = '' } else if ( selectedIndex === playingIndex && - (!isTimestamp || selectedInput.isCurrentTimestamp) + (!isTimestamp || currentInput.isCurrentTimestamp) ) { // Remaining length of the queue. if (timeData) { @@ -1975,7 +1974,7 @@ class AppElement extends FocusElement { durationSymbol = '' } else if ( selectedIndex < playingIndex || - (isTimestamp && selectedInput.data.timestamp <= trackPassedSec) + (isTimestamp && currentInput.data.timestamp <= trackPassedSec) ) { // Time since the selected track ended. durationRange = items.slice(selectedIndex + 1, playingIndex) @@ -1985,11 +1984,11 @@ class AppElement extends FocusElement { if (selectedIndex < playingIndex) { durationRange.unshift(items[selectedIndex]) } - durationAdd -= selectedInput.data.timestampEnd + durationAdd -= currentInput.data.timestampEnd } } else if ( selectedIndex > playingIndex || - (isTimestamp && selectedInput.data.timestamp > trackPassedSec) + (isTimestamp && currentInput.data.timestamp > trackPassedSec) ) { // Time until the selected track begins. if (timeData) { @@ -2005,7 +2004,7 @@ class AppElement extends FocusElement { durationAdd = 0 } if (isTimestamp) { - durationAdd += selectedInput.data.timestamp + durationAdd += currentInput.data.timestamp } durationSymbol = '+' } @@ -2041,7 +2040,7 @@ class AppElement extends FocusElement { let timestampPart if (isTimestamp && selectedIndex === playingIndex) { - const selectedTimestampIndex = timestampData.indexOf(selectedInput.data) + const selectedTimestampIndex = timestampData.indexOf(currentInput.data) const found = timestampData.findIndex(ts => ts.timestamp > trackPassedSec) const playingTimestampIndex = (found >= 0 ? found - 1 : 0) @@ -2081,6 +2080,53 @@ class AppElement extends FocusElement { this.queueTimeLabel.y = this.queuePane.contentH - 1 } + updateQueueSelection(timeData, oldTimeData) { + if (!timeData) { + return + } + + const { playingTrack } = this.SQP + const { form } = this.queueListingElement + const { currentInput } = form + + if (!currentInput || currentInput.item !== playingTrack) { + return + } + + const timestamps = this.getTimestampData(playingTrack) + + if (!timestamps) { + return + } + + const tsOld = oldTimeData && + this.getTimestampAtSec(playingTrack, oldTimeData.curSecTotal) + const tsNew = + this.getTimestampAtSec(playingTrack, timeData.curSecTotal) + + if ( + tsNew !== tsOld && + currentInput instanceof TimestampGrouplikeItemElement && + currentInput.data === tsOld + ) { + const index = form.inputs.findIndex(el => ( + el.item === playingTrack && + el instanceof TimestampGrouplikeItemElement && + el.data === tsNew + )) + + if (index === -1) { + return + } + + form.curIndex = index + if (form.isSelected) { + form.updateSelectedElement() + } + form.scrollSelectedElementIntoView() + } + } + get SQP() { // Just a convenient shorthand. return this.selectedQueuePlayer @@ -2336,6 +2382,14 @@ class GrouplikeListingElement extends Form { if (!ET.includes(item)) { this.expandedTimestamps.push(item) this.buildTimestampItems() + + if (this.currentItem === item) { + if (this.isSelected) { + this.form.selectInput(this.form.inputs[this.form.curIndex + 1]) + } else { + this.form.curIndex += 1 + } + } } } } @@ -2343,8 +2397,20 @@ class GrouplikeListingElement extends Form { collapseTimestamps(item) { const ET = this.expandedTimestamps // :alien: if (ET.includes(item)) { + const restore = (this.currentItem === item) + ET.splice(ET.indexOf(item), 1) this.buildTimestampItems() + + if (restore) { + const { form } = this + const index = form.inputs.findIndex(inp => inp.item === item) + form.curIndex = index + if (form.isSelected) { + form.updateSelectedElement() + } + form.scrollSelectedElementIntoView() + } } } @@ -2361,6 +2427,30 @@ class GrouplikeListingElement extends Form { return this.expandedTimestamps.includes(item) } + selectTimestampAtSec(item, sec) { + this.expandTimestamps(item) + + const { form } = this + let index = form.inputs.findIndex(el => ( + el.item === item && + el instanceof TimestampGrouplikeItemElement && + el.data.timestamp >= sec + )) + + if (index === -1) { + index = form.inputs.findIndex(el => el.item === item) + if (index === -1) { + return + } + } + + form.curIndex = index + if (form.isSelected) { + form.updateSelectedElement() + } + form.scrollSelectedElementIntoView() + } + updateTimestamps() { const ET = this.expandedTimestamps if (ET) { @@ -2368,13 +2458,43 @@ class GrouplikeListingElement extends Form { } } - buildTimestampItems(item) { - const form = this.form + restoreSelectedInput(restoreInput) { + const { form } = this + const { inputs, currentInput } = form + + if (currentInput === restoreInput) { + return + } + + let inputToSelect + + if (inputs.includes(restoreInput)) { + inputToSelect = restoreInput + } else if (restoreInput instanceof InteractiveGrouplikeItemElement) { + inputToSelect = inputs.find(input => + input.item === restoreInput.item && + input instanceof InteractiveGrouplikeItemElement + ) + } else if (restoreInput instanceof TimestampGrouplikeItemElement) { + inputToSelect = inputs.find(input => + input.data === restoreInput.data && + input instanceof TimestampGrouplikeItemElement + ) + } + + if (!inputToSelect) { + return + } + + form.curIndex = inputs.indexOf(inputToSelect) + if (form.isSelected) { + form.updateSelectedElement() + } + form.scrollSelectedElementIntoView() + } - // We're going to restore this selection later. It's kinda hacky and won't - // work if the selected input was itself a timestamp item, but that - // [extremely RFC voice] hopefully won't happen! - const selectedInput = this.form.inputs[this.form.curIndex] + buildTimestampItems(restoreInput = this.currentInput) { + const form = this.form // Clear up any existing timestamp items, since we're about to generate new // ones! @@ -2428,11 +2548,7 @@ class GrouplikeListingElement extends Form { } } - const index = form.inputs.indexOf(selectedInput) - if (index >= 0) { - form.selectInput(form.inputs.indexOf(selectedInput)) - } - + this.restoreSelectedInput(restoreInput) this.scheduleDrawWithoutPropertyChange() this.fixAllLayout() } @@ -2444,6 +2560,7 @@ class GrouplikeListingElement extends Form { this.commentLabel.text = this.grouplike.comment || '' + const restoreInput = this.form.currentInput const wasSelected = this.isSelected const form = this.form @@ -2504,11 +2621,12 @@ class GrouplikeListingElement extends Form { } } + this.buildTimestampItems(restoreInput) + // Just to make the selected-track-info bar fill right away (if it wasn't // already filled by a previous this.curIndex set). form.curIndex = form.curIndex - this.buildTimestampItems() this.fixAllLayout() } @@ -2643,7 +2761,7 @@ class GrouplikeListingElement extends Form { } get currentInput() { - return this.form.inputs[this.form.curIndex] || null + return this.form.currentInput } } @@ -2685,6 +2803,10 @@ class GrouplikeListingForm extends ListScrollForm { return Math.max(0, this.inputs.findIndex(el => el instanceof InteractiveGrouplikeItemElement)) } + get currentInput() { + return this.inputs[this.curIndex] + } + selectAndShow(item) { const index = this.inputs.findIndex(inp => inp.item === item) if (index >= 0) { -- cgit 1.3.0-6-gf8a5