Improved play next behavior, now store a play next position, fixes #864
This commit is contained in:
+41
-21
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -115,6 +120,7 @@ namespace lms::ui
|
|||||||
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{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user