Improved play next behavior, now store a play next position, fixes #864

This commit is contained in:
emeric
2026-07-12 11:17:58 +02:00
parent fddf20a532
commit 8daa4a2e7b
2 changed files with 50 additions and 24 deletions
+41 -21
View File
@@ -152,6 +152,7 @@ namespace lms::ui
LmsApp->getDbSession().create<db::TrackListEntry>(entry->getTrack(), queue); LmsApp->getDbSession().create<db::TrackListEntry>(entry->getTrack(), queue);
} }
_entriesContainer->reset(); _entriesContainer->reset();
_nextPlayPos.reset();
addSome(); addSome();
}); });
@@ -234,6 +235,7 @@ namespace lms::ui
_entriesContainer->reset(); _entriesContainer->reset();
_trackPos.reset(); _trackPos.reset();
_nextPlayPos.reset();
updateInfo(); updateInfo();
} }
@@ -241,11 +243,12 @@ namespace lms::ui
{ {
updateCurrentTrack(false); updateCurrentTrack(false);
_trackPos.reset(); _trackPos.reset();
_nextPlayPos.reset();
_isTrackSelected = false; _isTrackSelected = false;
trackUnselected.emit(); trackUnselected.emit();
} }
void PlayQueue::loadTrack(std::size_t pos, bool play) void PlayQueue::loadTrack(std::size_t pos, bool play, ResetNextPlayPos resetNextPlayPos)
{ {
updateCurrentTrack(false); updateCurrentTrack(false);
@@ -269,6 +272,8 @@ namespace lms::ui
} }
_trackPos = pos; _trackPos = pos;
if (resetNextPlayPos.value())
_nextPlayPos.reset();
const db::Track::pointer track{ queue->getEntry(*_trackPos)->getTrack() }; const db::Track::pointer track{ queue->getEntry(*_trackPos)->getTrack() };
trackId = track->getId(); trackId = track->getId();
@@ -296,18 +301,23 @@ namespace lms::ui
void PlayQueue::playNext() void PlayQueue::playNext()
{ {
if (!_trackPos) advanceTrack(ResetNextPlayPos{ true });
{
loadTrack(0, true);
return;
}
loadTrack(*_trackPos + 1, true);
} }
void PlayQueue::onPlaybackEnded() void PlayQueue::onPlaybackEnded()
{ {
playNext(); advanceTrack(ResetNextPlayPos{ false });
}
void PlayQueue::advanceTrack(ResetNextPlayPos resetNextPlayPos)
{
if (!_trackPos)
{
loadTrack(0, true, resetNextPlayPos);
return;
}
loadTrack(*_trackPos + 1, true, resetNextPlayPos);
} }
std::size_t PlayQueue::getCount() std::size_t PlayQueue::getCount()
@@ -396,14 +406,14 @@ namespace lms::ui
_entriesContainer->setHasMore(); _entriesContainer->setHasMore();
} }
std::vector<db::TrackId> PlayQueue::getAndClearNextTracks() std::vector<db::TrackId> PlayQueue::getAndClearTracksFrom(std::size_t pos)
{ {
std::vector<db::TrackId> tracks; std::vector<db::TrackId> tracks;
auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; auto transaction{ LmsApp->getDbSession().createWriteTransaction() };
db::TrackList::pointer queue{ getQueue() }; db::TrackList::pointer queue{ getQueue() };
auto entries{ queue->getEntries(db::Range{ _trackPos ? *_trackPos + 1 : 0, getCapacity() }) }; auto entries{ queue->getEntries(db::Range{ pos, getCapacity() }) };
tracks.reserve(entries.size()); tracks.reserve(entries.size());
for (db::TrackListEntry::pointer& entry : entries) for (db::TrackListEntry::pointer& entry : entries)
{ {
@@ -411,16 +421,15 @@ namespace lms::ui
entry.remove(); entry.remove();
} }
if (_trackPos) if (pos == 0)
{
// entries may have been cleared
if (*_trackPos + 1 < _entriesContainer->getCount())
_entriesContainer->remove(*_trackPos + 1, _entriesContainer->getCount() - 1);
}
else
{ {
_entriesContainer->reset(); _entriesContainer->reset();
} }
else if (pos < _entriesContainer->getCount())
{
// entries may have been cleared
_entriesContainer->remove(pos, _entriesContainer->getCount() - 1);
}
return tracks; return tracks;
} }
@@ -432,9 +441,19 @@ namespace lms::ui
void PlayQueue::playNext(std::span<const db::TrackId> trackIds) void PlayQueue::playNext(std::span<const db::TrackId> trackIds)
{ {
std::vector<db::TrackId> nextTracks{ getAndClearNextTracks() }; const std::size_t defaultInsertPos{ _trackPos ? *_trackPos + 1 : 0 };
nextTracks.insert(std::cbegin(nextTracks), std::cbegin(trackIds), std::cend(trackIds)); if (!_nextPlayPos || *_nextPlayPos < defaultInsertPos)
playOrAddLast(nextTracks); _nextPlayPos = defaultInsertPos;
const std::size_t insertPos{ *_nextPlayPos };
std::vector<db::TrackId> tracksToInsert{ getAndClearTracksFrom(insertPos) };
tracksToInsert.insert(std::cbegin(tracksToInsert), std::cbegin(trackIds), std::cend(trackIds));
playOrAddLast(tracksToInsert);
// set after playOrAddLast: it may call loadTrack() (queue was empty), which resets _nextPlayPos
_nextPlayPos = insertPos + trackIds.size();
} }
void PlayQueue::playShuffled(std::span<const db::TrackId> trackIds) void PlayQueue::playShuffled(std::span<const db::TrackId> trackIds)
@@ -549,6 +568,7 @@ namespace lms::ui
else if (*_trackPos >= _entriesContainer->getCount()) else if (*_trackPos >= _entriesContainer->getCount())
_trackPos.reset(); _trackPos.reset();
} }
_nextPlayPos.reset();
_entriesContainer->remove(*entry); _entriesContainer->remove(*entry);
+9 -3
View File
@@ -27,6 +27,8 @@
#include <Wt/WTemplate.h> #include <Wt/WTemplate.h>
#include <Wt/WText.h> #include <Wt/WText.h>
#include "core/TaggedType.hpp"
#include "database/Object.hpp" #include "database/Object.hpp"
#include "database/objects/TrackId.hpp" #include "database/objects/TrackId.hpp"
#include "database/objects/TrackListId.hpp" #include "database/objects/TrackListId.hpp"
@@ -50,6 +52,8 @@ namespace lms::ui
public: public:
PlayQueue(); PlayQueue();
using ResetNextPlayPos = core::TaggedBool<struct ResetNextPlayPosTag>;
void play(std::span<const db::TrackId> trackIds); void play(std::span<const db::TrackId> trackIds);
void playNext(std::span<const db::TrackId> trackIds); void playNext(std::span<const db::TrackId> trackIds);
void playShuffled(std::span<const db::TrackId> trackIds); void playShuffled(std::span<const db::TrackId> trackIds);
@@ -85,7 +89,8 @@ namespace lms::ui
void clearTracks(); void clearTracks();
void enqueueTracks(std::span<const db::TrackId> trackIds); void enqueueTracks(std::span<const db::TrackId> trackIds);
std::vector<db::TrackId> getAndClearNextTracks(); std::vector<db::TrackId> getAndClearTracksFrom(std::size_t pos);
void advanceTrack(ResetNextPlayPos resetNextPlayPos);
void addSome(); void addSome();
void addEntry(const db::ObjectPtr<db::TrackListEntry>& entry); void addEntry(const db::ObjectPtr<db::TrackListEntry>& entry);
void enqueueRadioTracksIfNeeded(); void enqueueRadioTracksIfNeeded();
@@ -95,7 +100,7 @@ namespace lms::ui
bool isRepeatAllSet() const; bool isRepeatAllSet() const;
bool isRadioModeSet() const; bool isRadioModeSet() const;
void loadTrack(std::size_t pos, bool play); void loadTrack(std::size_t pos, bool play, ResetNextPlayPos resetNextPlayPos = ResetNextPlayPos{ true });
void stop(); void stop();
std::optional<float> getReplayGain(std::size_t pos, const db::ObjectPtr<db::Track>& track) const; std::optional<float> getReplayGain(std::size_t pos, const db::ObjectPtr<db::Track>& track) const;
@@ -114,7 +119,8 @@ namespace lms::ui
Wt::WText* _duration{}; Wt::WText* _duration{};
Wt::WCheckBox* _repeatBtn{}; Wt::WCheckBox* _repeatBtn{};
Wt::WCheckBox* _radioBtn{}; Wt::WCheckBox* _radioBtn{};
std::optional<std::size_t> _trackPos; // current track position, if set std::optional<std::size_t> _trackPos; // current track position, if set
std::optional<std::size_t> _nextPlayPos; // where the next "play next" insertion happens, if set
bool _isTrackSelected{}; bool _isTrackSelected{};
}; };