Added play next. fixes #289
This commit is contained in:
+2
-1
@@ -10,8 +10,9 @@
|
||||
${play-btn class="btn btn-primary"}
|
||||
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"/>
|
||||
<ul class="dropdown-menu">
|
||||
<li>${play-shuffled class="dropdown-item"}</li>
|
||||
<li>${play-next class="dropdown-item"}</li>
|
||||
<li>${play-last class="dropdown-item"}</li>
|
||||
<li>${play-shuffled class="dropdown-item"}</li>
|
||||
<li>${star class="dropdown-item"}</li>
|
||||
${<if-has-mbid>}
|
||||
<li><a href="${mbid-link}" target="_blank" class="dropdown-item">${tr:Lms.Explore.musicbrainz-artist}</a></li>
|
||||
|
||||
@@ -132,6 +132,7 @@
|
||||
<message id="Lms.Explore.musicbrainz-release">MusicBrainz Release</message>
|
||||
<message id="Lms.Explore.play">Play</message>
|
||||
<message id="Lms.Explore.play-last">Play last</message>
|
||||
<message id="Lms.Explore.play-next">Play next</message>
|
||||
<message id="Lms.Explore.play-shuffled">Play shuffled</message>
|
||||
<message id="Lms.Explore.random">Random</message>
|
||||
<message id="Lms.Explore.recently-added">Recently added</message>
|
||||
|
||||
@@ -132,6 +132,7 @@
|
||||
<message id="Lms.Explore.musicbrainz-release">MusicBrainz Release</message>
|
||||
<message id="Lms.Explore.play">Jouer</message>
|
||||
<message id="Lms.Explore.play-last">Jouer en dernier</message>
|
||||
<message id="Lms.Explore.play-next">Jouer ensuite</message>
|
||||
<message id="Lms.Explore.play-shuffled">Jouer aléatoirement</message>
|
||||
<message id="Lms.Explore.random">Aléatoire</message>
|
||||
<message id="Lms.Explore.recently-added">Ajoutés récemment</message>
|
||||
|
||||
@@ -132,6 +132,7 @@
|
||||
<message id="Lms.Explore.musicbrainz-release">Album MusicBrainz</message>
|
||||
|
||||
<message id="Lms.Explore.play-last">Aggiungi alla coda di riproduzione</message>
|
||||
|
||||
<message id="Lms.Explore.play-shuffled">Aggiungi alla coda di riproduzione mischiando</message>
|
||||
<message id="Lms.Explore.random">Casuali</message>
|
||||
<message id="Lms.Explore.recently-added">Aggiunti di recente</message>
|
||||
|
||||
@@ -132,6 +132,7 @@
|
||||
<message id="Lms.Explore.musicbrainz-release">MusicBrainz 专辑</message>
|
||||
<message id="Lms.Explore.play">播放</message>
|
||||
<message id="Lms.Explore.play-last">最后播放</message>
|
||||
|
||||
<message id="Lms.Explore.play-shuffled">随机播放</message>
|
||||
<message id="Lms.Explore.random">随机</message>
|
||||
<message id="Lms.Explore.recently-added">最近添加</message>
|
||||
|
||||
+4
-2
@@ -21,8 +21,9 @@
|
||||
${play-btn class="btn btn-primary"}
|
||||
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"/>
|
||||
<ul class="dropdown-menu">
|
||||
<li>${play-shuffled class="dropdown-item"}</li>
|
||||
<li>${play-next class="dropdown-item"}</li>
|
||||
<li>${play-last class="dropdown-item"}</li>
|
||||
<li>${play-shuffled class="dropdown-item"}</li>
|
||||
<li>${star class="dropdown-item"}</li>
|
||||
${<if-has-mbid>}
|
||||
<li><a href="${mbid-link}" target="_blank" class="dropdown-item">${tr:Lms.Explore.musicbrainz-release}</a></li>
|
||||
@@ -82,7 +83,8 @@
|
||||
<div class="dropdown d-inline-block">
|
||||
${more-btn data-bs-toggle="dropdown" aria-expanded="false" class="btn btn-sm btn-outline-secondary border-0"}
|
||||
<ul class="dropdown-menu" aria-labelledby="${id:more-btn}">
|
||||
<li>${play class="dropdown-item"}</li>
|
||||
<li class="d-block d-sm-none">${play class="dropdown-item"}</li>
|
||||
<li>${play-next class="dropdown-item"}</li>
|
||||
<li>${play-last class="dropdown-item"}</li>
|
||||
<li>${star class="dropdown-item"}</li>
|
||||
<li>${download class="dropdown-item"}</li>
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
${play-btn class="btn btn-primary"}
|
||||
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"/>
|
||||
<ul class="dropdown-menu">
|
||||
<li>${play-next class="dropdown-item"}</li>
|
||||
<li>${play-last class="dropdown-item"}</li>
|
||||
<li>${play-shuffled class="dropdown-item"}</li>
|
||||
</ul>
|
||||
|
||||
+3
-1
@@ -29,6 +29,7 @@
|
||||
${play-btn class="btn btn-primary"}
|
||||
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"/>
|
||||
<ul class="dropdown-menu">
|
||||
<li>${play-next class="dropdown-item"}</li>
|
||||
<li>${play-last class="dropdown-item"}</li>
|
||||
<li>${play-shuffled class="dropdown-item"}</li>
|
||||
</ul>
|
||||
@@ -69,7 +70,8 @@
|
||||
<div class="dropdown d-inline-block">
|
||||
${more-btn data-bs-toggle="dropdown" aria-expanded="false" class="btn btn-sm btn-outline-secondary border-0"}
|
||||
<ul class="dropdown-menu" aria-labelledby="${id:more-btn}">
|
||||
<li>${play class="dropdown-item"}</li>
|
||||
<li class="d-block d-sm-none">${play class="dropdown-item"}</li>
|
||||
<li>${play-next class="dropdown-item"}</li>
|
||||
<li>${play-last class="dropdown-item"}</li>
|
||||
<li>${star class="dropdown-item"}</li>
|
||||
<li>${download class="dropdown-item"}</li>
|
||||
|
||||
@@ -149,7 +149,7 @@ TrackList::getEntry(std::size_t pos) const
|
||||
{
|
||||
TrackListEntry::pointer res;
|
||||
|
||||
auto entries = getEntries(pos, 1);
|
||||
auto entries = getEntries(Range {pos, 1});
|
||||
if (!entries.empty())
|
||||
res = entries.front();
|
||||
|
||||
@@ -157,7 +157,7 @@ TrackList::getEntry(std::size_t pos) const
|
||||
}
|
||||
|
||||
std::vector<TrackListEntry::pointer>
|
||||
TrackList::getEntries(std::optional<std::size_t> offset, std::optional<std::size_t> size) const
|
||||
TrackList::getEntries(std::optional<Range> range) const
|
||||
{
|
||||
assert(session());
|
||||
|
||||
@@ -165,8 +165,8 @@ TrackList::getEntries(std::optional<std::size_t> offset, std::optional<std::size
|
||||
session()->find<TrackListEntry>()
|
||||
.where("tracklist_id = ?").bind(getId())
|
||||
.orderBy("id")
|
||||
.limit(size ? static_cast<int>(*size) : -1)
|
||||
.offset(offset ? static_cast<int>(*offset) : -1)
|
||||
.limit(range ? static_cast<int>(range->size) + 1 : -1)
|
||||
.offset(range ? static_cast<int>(range->offset) : -1)
|
||||
.resultList()};
|
||||
|
||||
return std::vector<TrackListEntry::pointer>(entries.begin(), entries.end());
|
||||
@@ -671,7 +671,7 @@ TrackListEntry::TrackListEntry(ObjectPtr<Track> track, ObjectPtr<TrackList> trac
|
||||
TrackListEntry::pointer
|
||||
TrackListEntry::create(Session& session, ObjectPtr<Track> track, ObjectPtr<TrackList> tracklist, const Wt::WDateTime& dateTime)
|
||||
{
|
||||
return session.getDboSession().add(std::unique_ptr<TrackListEntry>( new TrackListEntry {track, tracklist, dateTime}));
|
||||
return session.getDboSession().add(std::unique_ptr<TrackListEntry> {new TrackListEntry {track, tracklist, dateTime}});
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -90,7 +90,7 @@ class TrackList final : public Object<TrackList, TrackListId>
|
||||
bool isEmpty() const;
|
||||
std::size_t getCount() const;
|
||||
ObjectPtr<TrackListEntry> getEntry(std::size_t pos) const;
|
||||
std::vector<ObjectPtr<TrackListEntry>> getEntries(std::optional<std::size_t> offset = {}, std::optional<std::size_t> size = {}) const;
|
||||
std::vector<ObjectPtr<TrackListEntry>> getEntries(std::optional<Range> range = {}) const;
|
||||
ObjectPtr<TrackListEntry> getEntryByTrackAndDateTime(ObjectPtr<Track> track, const Wt::WDateTime& dateTime) const;
|
||||
|
||||
std::vector<ObjectPtr<Artist>> getArtists(const std::vector<ClusterId>& clusters, std::optional<TrackArtistLinkType> linkType, ArtistSortMethod sortMethod, std::optional<Range> range, bool& moreResults) const;
|
||||
@@ -144,7 +144,7 @@ class TrackList final : public Object<TrackList, TrackListId>
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<TrackListEntry>> _entries;
|
||||
};
|
||||
|
||||
class TrackListEntry : public Object<TrackListEntry, TrackListEntryId>
|
||||
class TrackListEntry final : public Object<TrackListEntry, TrackListEntryId>
|
||||
{
|
||||
public:
|
||||
TrackListEntry() = default;
|
||||
|
||||
@@ -479,3 +479,43 @@ TEST_F(DatabaseFixture, SingleTrackListSingleTrackWithCluster)
|
||||
EXPECT_EQ(trackLists.results.front(), trackList1.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackList_getEntries)
|
||||
{
|
||||
ScopedUser user {session, "MyUser"};
|
||||
ScopedTrackList trackList {session, "MyTrackList", TrackListType::Playlist, false, user.lockAndGet()};
|
||||
ScopedTrack track1 {session, "MyTrack"};
|
||||
ScopedTrack track2 {session, "MyTrack"};
|
||||
|
||||
{
|
||||
auto transaction {session.createUniqueTransaction()};
|
||||
session.create<TrackListEntry>(track1.get(), trackList.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction {session.createSharedTransaction()};
|
||||
auto entries {trackList.get()->getEntries()};
|
||||
ASSERT_EQ(entries.size(), 1);
|
||||
EXPECT_EQ(entries.front()->getTrack()->getId(), track1.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction {session.createUniqueTransaction()};
|
||||
session.create<TrackListEntry>(track2.get(), trackList.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction {session.createSharedTransaction()};
|
||||
auto entries {trackList.get()->getEntries()};
|
||||
ASSERT_EQ(entries.size(), 2);
|
||||
EXPECT_EQ(entries[0]->getTrack()->getId(), track1.getId());
|
||||
EXPECT_EQ(entries[1]->getTrack()->getId(), track2.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction {session.createSharedTransaction()};
|
||||
auto entries {trackList.get()->getEntries(Range {1, 1})};
|
||||
ASSERT_EQ(entries.size(), 1);
|
||||
EXPECT_EQ(entries[0]->getTrack()->getId(), track2.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,7 +506,7 @@ R"(function(current) {
|
||||
|
||||
_mediaPlayer->playbackEnded.connect([this]
|
||||
{
|
||||
_playQueue->playNext();
|
||||
_playQueue->onPlaybackEnded();
|
||||
});
|
||||
|
||||
_playQueue->trackSelected.connect([this] (Database::TrackId trackId, bool play, float replayGain)
|
||||
|
||||
+55
-11
@@ -270,6 +270,7 @@ PlayQueue::clearTracks()
|
||||
}
|
||||
|
||||
_entriesContainer->clear();
|
||||
_trackPos.reset();
|
||||
updateInfo();
|
||||
}
|
||||
|
||||
@@ -278,6 +279,7 @@ PlayQueue::stop()
|
||||
{
|
||||
updateCurrentTrack(false);
|
||||
_trackPos.reset();
|
||||
_isTrackSelected = false;
|
||||
trackUnselected.emit();
|
||||
}
|
||||
|
||||
@@ -318,6 +320,7 @@ PlayQueue::loadTrack(std::size_t pos, bool play)
|
||||
|
||||
enqueueRadioTracksIfNeeded();
|
||||
updateCurrentTrack(true);
|
||||
_isTrackSelected = true;
|
||||
trackSelected.emit(trackId, play, replayGain ? *replayGain : 0);
|
||||
}
|
||||
|
||||
@@ -345,6 +348,12 @@ PlayQueue::playNext()
|
||||
loadTrack(*_trackPos + 1, true);
|
||||
}
|
||||
|
||||
void
|
||||
PlayQueue::onPlaybackEnded()
|
||||
{
|
||||
playNext();
|
||||
}
|
||||
|
||||
std::size_t
|
||||
PlayQueue::getCount()
|
||||
{
|
||||
@@ -401,11 +410,9 @@ PlayQueue::updateCurrentTrack(bool selected)
|
||||
entry->toggleStyleClass("Lms-entry-playing", selected);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
void
|
||||
PlayQueue::enqueueTracks(const std::vector<Database::TrackId>& trackIds)
|
||||
{
|
||||
std::size_t nbTracksQueued {};
|
||||
|
||||
{
|
||||
auto transaction {LmsApp->getDbSession().createUniqueTransaction()};
|
||||
|
||||
@@ -415,22 +422,50 @@ PlayQueue::enqueueTracks(const std::vector<Database::TrackId>& trackIds)
|
||||
std::size_t nbTracksToEnqueue {queueSize + trackIds.size() > getCapacity() ? getCapacity() - queueSize : trackIds.size()};
|
||||
for (const Database::TrackId trackId : trackIds)
|
||||
{
|
||||
if (nbTracksToEnqueue == 0)
|
||||
break;
|
||||
|
||||
Database::Track::pointer track {Database::Track::find(LmsApp->getDbSession(), trackId)};
|
||||
if (!track)
|
||||
continue;
|
||||
|
||||
if (nbTracksQueued == nbTracksToEnqueue)
|
||||
break;
|
||||
|
||||
LmsApp->getDbSession().create<Database::TrackListEntry>(track, queue);
|
||||
nbTracksQueued++;
|
||||
nbTracksToEnqueue--;
|
||||
}
|
||||
}
|
||||
|
||||
updateInfo();
|
||||
addSome();
|
||||
}
|
||||
|
||||
return nbTracksQueued;
|
||||
std::vector<Database::TrackId>
|
||||
PlayQueue::getAndClearNextTracks()
|
||||
{
|
||||
std::vector<Database::TrackId> tracks;
|
||||
|
||||
auto transaction {LmsApp->getDbSession().createUniqueTransaction()};
|
||||
|
||||
Database::TrackList::pointer queue {getQueue()};
|
||||
std::vector<Database::TrackListEntry::pointer> entries {queue->getEntries(Database::Range {_trackPos ? *_trackPos + 1 : 0, getCapacity()})};
|
||||
tracks.reserve(entries.size());
|
||||
for (Database::TrackListEntry::pointer entry : entries)
|
||||
{
|
||||
tracks.push_back(entry->getTrack()->getId());
|
||||
entry.remove();
|
||||
}
|
||||
|
||||
if (_trackPos)
|
||||
{
|
||||
// entries may have been cleared
|
||||
if (*_trackPos + 1 < _entriesContainer->getCount())
|
||||
_entriesContainer->remove(*_trackPos + 1, _entriesContainer->getCount() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
_entriesContainer->clear();
|
||||
}
|
||||
|
||||
return tracks;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -439,6 +474,14 @@ PlayQueue::play(const std::vector<Database::TrackId>& trackIds)
|
||||
playAtIndex(trackIds, 0);
|
||||
}
|
||||
|
||||
void
|
||||
PlayQueue::playNext(const std::vector<Database::TrackId>& trackIds)
|
||||
{
|
||||
std::vector<Database::TrackId> nextTracks {getAndClearNextTracks()};
|
||||
nextTracks.insert(std::cbegin(nextTracks), std::cbegin(trackIds), std::cend(trackIds));
|
||||
playOrAddLast(nextTracks);
|
||||
}
|
||||
|
||||
void
|
||||
PlayQueue::playShuffled(const std::vector<Database::TrackId>& trackIds)
|
||||
{
|
||||
@@ -453,7 +496,7 @@ void
|
||||
PlayQueue::playOrAddLast(const std::vector<Database::TrackId>& trackIds)
|
||||
{
|
||||
enqueueTracks(trackIds);
|
||||
if (!_trackPos)
|
||||
if (!_isTrackSelected)
|
||||
loadTrack(0, true);
|
||||
}
|
||||
|
||||
@@ -471,7 +514,7 @@ PlayQueue::addSome()
|
||||
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
|
||||
|
||||
const Database::TrackList::pointer queue {getQueue()};
|
||||
const auto tracklistEntries {queue->getEntries(_entriesContainer->getCount(), _batchSize)};
|
||||
const auto tracklistEntries {queue->getEntries(Database::Range {_entriesContainer->getCount(), _batchSize})};
|
||||
for (const Database::TrackListEntry::pointer& tracklistEntry : tracklistEntries)
|
||||
addEntry(tracklistEntry);
|
||||
|
||||
@@ -491,7 +534,6 @@ PlayQueue::addEntry(const Database::TrackListEntry::pointer& tracklistEntry)
|
||||
entry->bindString("name", Wt::WString::fromUTF8(track->getName()), Wt::TextFormat::Plain);
|
||||
|
||||
const auto artists {track->getArtistIds({Database::TrackArtistLinkType::Artist})};
|
||||
LMS_LOG(UI, DEBUG) << "Found " << artists.size() << " artists!";
|
||||
if (!artists.empty())
|
||||
{
|
||||
entry->setCondition("if-has-artists", true);
|
||||
@@ -544,6 +586,8 @@ PlayQueue::addEntry(const Database::TrackListEntry::pointer& tracklistEntry)
|
||||
const std::optional<std::size_t> pos {_entriesContainer->getIndexOf(*entry)};
|
||||
if (pos && *_trackPos >= *pos)
|
||||
(*_trackPos)--;
|
||||
else if (*_trackPos >= _entriesContainer->getCount())
|
||||
_trackPos.reset();
|
||||
}
|
||||
|
||||
_entriesContainer->remove(*entry);
|
||||
|
||||
@@ -50,6 +50,7 @@ class PlayQueue : public Template
|
||||
PlayQueue();
|
||||
|
||||
void play(const std::vector<Database::TrackId>& trackIds);
|
||||
void playNext(const std::vector<Database::TrackId>& trackIds);
|
||||
void playShuffled(const std::vector<Database::TrackId>& trackIds);
|
||||
void playOrAddLast(const std::vector<Database::TrackId>& trackIds); // play if queue empty, otherwise just add last
|
||||
void playAtIndex(const std::vector<Database::TrackId>& trackIds, std::size_t index);
|
||||
@@ -69,6 +70,8 @@ class PlayQueue : public Template
|
||||
// Signal emitted when track count changed
|
||||
Wt::Signal<std::size_t> trackCountChanged;
|
||||
|
||||
void onPlaybackEnded();
|
||||
|
||||
std::size_t getCapacity() const { return _capacity; }
|
||||
std::size_t getCount();
|
||||
|
||||
@@ -80,7 +83,8 @@ class PlayQueue : public Template
|
||||
bool isFull() const;
|
||||
|
||||
void clearTracks();
|
||||
std::size_t enqueueTracks(const std::vector<Database::TrackId>& trackIds);
|
||||
void enqueueTracks(const std::vector<Database::TrackId>& trackIds);
|
||||
std::vector<Database::TrackId> getAndClearNextTracks();
|
||||
void addSome();
|
||||
void addEntry(const Database::ObjectPtr<Database::TrackListEntry>& entry);
|
||||
void enqueueRadioTracksIfNeeded();
|
||||
@@ -110,6 +114,7 @@ class PlayQueue : public Template
|
||||
Wt::WCheckBox* _repeatBtn {};
|
||||
Wt::WCheckBox* _radioBtn {};
|
||||
std::optional<std::size_t> _trackPos; // current track position, if set
|
||||
bool _isTrackSelected {};
|
||||
};
|
||||
|
||||
} // namespace UserInterface
|
||||
|
||||
@@ -65,6 +65,22 @@ namespace UserInterface
|
||||
_elements->removeWidget(&widget);
|
||||
}
|
||||
|
||||
void
|
||||
InfiniteScrollingContainer::remove(std::size_t first, std::size_t last)
|
||||
{
|
||||
assert(last >= first);
|
||||
assert(last < static_cast<std::size_t>(_elements->count()));
|
||||
|
||||
// remove from end as API is quite uneffective (minimize moves)
|
||||
std::size_t i {last};
|
||||
while (Wt::WWidget* widget {_elements->widget(i)})
|
||||
{
|
||||
_elements->removeWidget(widget);
|
||||
if (i-- == first)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Wt::WWidget*
|
||||
InfiniteScrollingContainer::getWidget(std::size_t pos) const
|
||||
{
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace UserInterface
|
||||
}
|
||||
|
||||
void remove(Wt::WWidget& widget);
|
||||
void remove(std::size_t first, std::size_t last);
|
||||
|
||||
Wt::WWidget* getWidget(std::size_t pos) const;
|
||||
std::optional<std::size_t> getIndexOf(Wt::WWidget& widget) const;
|
||||
|
||||
@@ -166,6 +166,11 @@ Artist::refreshView()
|
||||
{
|
||||
_playQueueController.processCommand(PlayQueueController::Command::PlayShuffled, {_artistId});
|
||||
});
|
||||
bindNew<Wt::WPushButton>("play-next", Wt::WString::tr("Lms.Explore.play-next"), Wt::TextFormat::Plain)
|
||||
->clicked().connect([=]
|
||||
{
|
||||
_playQueueController.processCommand(PlayQueueController::Command::PlayNext, {_artistId});
|
||||
});
|
||||
bindNew<Wt::WPushButton>("play-last", Wt::WString::tr("Lms.Explore.play-last"), Wt::TextFormat::Plain)
|
||||
->clicked().connect([=]
|
||||
{
|
||||
|
||||
@@ -138,6 +138,9 @@ namespace UserInterface
|
||||
case Command::Play:
|
||||
_playQueue.play(trackIds);
|
||||
break;
|
||||
case Command::PlayNext:
|
||||
_playQueue.playNext(trackIds);
|
||||
break;
|
||||
case Command::PlayShuffled:
|
||||
_playQueue.playShuffled(trackIds);
|
||||
break;
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace UserInterface
|
||||
enum class Command
|
||||
{
|
||||
Play,
|
||||
PlayNext,
|
||||
PlayOrAddLast,
|
||||
PlayShuffled,
|
||||
};
|
||||
|
||||
@@ -290,6 +290,12 @@ Release::refreshView()
|
||||
_playQueueController.processCommand(PlayQueueController::Command::PlayShuffled, {*releaseId});
|
||||
});
|
||||
|
||||
bindNew<Wt::WPushButton>("play-next", Wt::WString::tr("Lms.Explore.play-next"), Wt::TextFormat::Plain)
|
||||
->clicked().connect([=]
|
||||
{
|
||||
_playQueueController.processCommand(PlayQueueController::Command::PlayNext, {*releaseId});
|
||||
});
|
||||
|
||||
bindNew<Wt::WPushButton>("play-last", Wt::WString::tr("Lms.Explore.play-last"), Wt::TextFormat::Plain)
|
||||
->clicked().connect([=]
|
||||
{
|
||||
@@ -416,6 +422,11 @@ Release::refreshView()
|
||||
{
|
||||
_playQueueController.playTrackInRelease(trackId);
|
||||
});
|
||||
entry->bindNew<Wt::WPushButton>("play-next", Wt::WString::tr("Lms.Explore.play-next"))
|
||||
->clicked().connect([=]
|
||||
{
|
||||
_playQueueController.processCommand(PlayQueueController::Command::PlayNext, {trackId});
|
||||
});
|
||||
entry->bindNew<Wt::WPushButton>("play-last", Wt::WString::tr("Lms.Explore.play-last"))
|
||||
->clicked().connect([=]
|
||||
{
|
||||
|
||||
@@ -79,6 +79,11 @@ Releases::Releases(Filters& filters, PlayQueueController& playQueueController)
|
||||
{
|
||||
_playQueueController.processCommand(PlayQueueController::Command::PlayShuffled, getAllReleases());
|
||||
});
|
||||
bindNew<Wt::WPushButton>("play-next", Wt::WString::tr("Lms.Explore.play-next"), Wt::TextFormat::Plain)
|
||||
->clicked().connect([=]
|
||||
{
|
||||
_playQueueController.processCommand(PlayQueueController::Command::PlayNext, getAllReleases());
|
||||
});
|
||||
bindNew<Wt::WPushButton>("play-last", Wt::WString::tr("Lms.Explore.play-last"), Wt::TextFormat::Plain)
|
||||
->clicked().connect([=]
|
||||
{
|
||||
|
||||
@@ -205,6 +205,11 @@ namespace UserInterface::TrackListHelpers
|
||||
{
|
||||
playQueueController.processCommand(PlayQueueController::Command::Play, {trackId});
|
||||
});
|
||||
entry->bindNew<Wt::WPushButton>("play-next", Wt::WString::tr("Lms.Explore.play-next"))
|
||||
->clicked().connect([=, &playQueueController]
|
||||
{
|
||||
playQueueController.processCommand(PlayQueueController::Command::PlayNext, {trackId});
|
||||
});
|
||||
entry->bindNew<Wt::WPushButton>("play-last", Wt::WString::tr("Lms.Explore.play-last"))
|
||||
->clicked().connect([=, &playQueueController]
|
||||
{
|
||||
|
||||
@@ -80,6 +80,11 @@ Tracks::Tracks(Filters& filters, PlayQueueController& playQueueController)
|
||||
{
|
||||
_playQueueController.processCommand(PlayQueueController::Command::PlayShuffled, getAllTracks());
|
||||
});
|
||||
bindNew<Wt::WPushButton>("play-next", Wt::WString::tr("Lms.Explore.play-next"), Wt::TextFormat::Plain)
|
||||
->clicked().connect([=]
|
||||
{
|
||||
_playQueueController.processCommand(PlayQueueController::Command::PlayNext, getAllTracks());
|
||||
});
|
||||
bindNew<Wt::WPushButton>("play-last", Wt::WString::tr("Lms.Explore.play-last"), Wt::TextFormat::Plain)
|
||||
->clicked().connect([=]
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user