Do not attempt extra data fetch when hitting the end of a query

This commit is contained in:
emeric
2024-03-14 13:51:28 +01:00
parent a769909ebc
commit e4ad0a5406
19 changed files with 177 additions and 148 deletions
+8
View File
@@ -343,6 +343,14 @@ namespace lms::db
utils::execQuery(query, params.range, func); utils::execQuery(query, params.range, func);
} }
void Track::find(Session& session, const FindParameters& params, bool& moreResults, std::function<void(const Track::pointer&)> func)
{
session.checkReadTransaction();
auto query{ createQuery<Wt::Dbo::ptr<Track>>(session, params)};
utils::execQuery(query, params.range, moreResults, func);
}
RangeResults<TrackId> Track::findSimilarTrackIds(Session& session, const std::vector<TrackId>& tracks, std::optional<Range> range) RangeResults<TrackId> Track::findSimilarTrackIds(Session& session, const std::vector<TrackId>& tracks, std::optional<Range> range)
{ {
assert(!tracks.empty()); assert(!tracks.empty());
+6 -21
View File
@@ -142,25 +142,21 @@ namespace lms::db
TrackListEntry::pointer res; TrackListEntry::pointer res;
auto entries = getEntries(Range{ pos, 1 }); auto entries = getEntries(Range{ pos, 1 });
if (!entries.empty()) if (!entries.results.empty())
res = entries.front(); res = entries.results.front();
return res; return res;
} }
std::vector<TrackListEntry::pointer> TrackList::getEntries(std::optional<Range> range) const RangeResults<ObjectPtr<TrackListEntry>> TrackList::getEntries(std::optional<Range> range) const
{ {
assert(session()); assert(session());
auto entries{ auto query{session()->find<TrackListEntry>()
session()->find<TrackListEntry>()
.where("tracklist_id = ?").bind(getId()) .where("tracklist_id = ?").bind(getId())
.orderBy("id") .orderBy("id") };
.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()); return utils::execQuery<TrackListEntry::pointer>(query, range);
} }
TrackListEntry::pointer TrackList::getEntryByTrackAndDateTime(ObjectPtr<Track> track, const Wt::WDateTime& dateTime) const TrackListEntry::pointer TrackList::getEntryByTrackAndDateTime(ObjectPtr<Track> track, const Wt::WDateTime& dateTime) const
@@ -237,17 +233,6 @@ namespace lms::db
return res; return res;
} }
bool TrackList::hasTrack(TrackId trackId) const
{
assert(session());
Wt::Dbo::collection<TrackListEntry::pointer> res = session()->query<TrackListEntry::pointer>("SELECT p_e from tracklist_entry p_e INNER JOIN tracklist p ON p_e.tracklist_id = p.id")
.where("p_e.track_id = ?").bind(trackId)
.where("p.id = ?").bind(getId());
return res.size() > 0;
}
std::vector<Track::pointer> TrackList::getSimilarTracks(std::optional<std::size_t> offset, std::optional<std::size_t> size) const std::vector<Track::pointer> TrackList::getSimilarTracks(std::optional<std::size_t> offset, std::optional<std::size_t> size) const
{ {
assert(session()); assert(session());
+32 -5
View File
@@ -56,15 +56,20 @@ namespace lms::db::utils
{ {
res.range.offset = range->offset; res.range.offset = range->offset;
applyRange(query, Range{ range->offset, range->size + 1 }); applyRange(query, Range{ range->offset, range->size + 1 });
res.results.reserve(range->size);
} }
auto collection{ query.resultList() }; auto collection{ query.resultList() };
res.results.assign(collection.begin(), collection.end()); for (auto itResult{ collection.begin() }; itResult != collection.end(); ++itResult)
if (range && res.results.size() == static_cast<std::size_t>(range->size) + 1)
{ {
// TODO may optim by not actually requesting the last one if (range && res.results.size() == range->size)
res.moreResults = true; {
res.results.pop_back(); res.moreResults = true;
break;
}
res.results.push_back(std::move(*itResult));
} }
res.range.size = res.results.size(); res.range.size = res.results.size();
@@ -85,6 +90,28 @@ namespace lms::db::utils
} }
} }
template <typename ResultType, typename Query>
void execQuery(Query& query, std::optional<Range> range, bool& moreResults, std::function<void(const ResultType&)> func)
{
if (range)
applyRange(query, Range{ range->offset, range->size + 1 });
moreResults = false;
std::size_t count{};
for (const auto& res : query.resultList())
{
if (range && (count++ == static_cast<std::size_t>(range->size)))
{
moreResults = true;
break;
}
LMS_SCOPED_TRACE_DETAILED("Database", "ExecQueryResult");
func(res);
}
}
Wt::WDateTime normalizeDateTime(const Wt::WDateTime& dateTime); Wt::WDateTime normalizeDateTime(const Wt::WDateTime& dateTime);
} }
@@ -118,6 +118,7 @@ namespace lms::db
static RangeResults<TrackId> findIds(Session& session, const FindParameters& parameters); static RangeResults<TrackId> findIds(Session& session, const FindParameters& parameters);
static RangeResults<pointer> find(Session& session, const FindParameters& parameters); static RangeResults<pointer> find(Session& session, const FindParameters& parameters);
static void find(Session& session, const FindParameters& parameters, std::function<void(const Track::pointer&)> func); static void find(Session& session, const FindParameters& parameters, std::function<void(const Track::pointer&)> func);
static void find(Session& session, const FindParameters& parameters, bool& moreResults, std::function<void(const Track::pointer&)> func);
static RangeResults<PathResult> findPaths(Session& session, std::optional<Range> range = std::nullopt); static RangeResults<PathResult> findPaths(Session& session, std::optional<Range> range = std::nullopt);
static RangeResults<TrackId> findIdsTrackMBIDDuplicates(Session& session, std::optional<Range> range = std::nullopt); static RangeResults<TrackId> findIdsTrackMBIDDuplicates(Session& session, std::optional<Range> range = std::nullopt);
static RangeResults<TrackId> findIdsWithRecordingMBIDAndMissingFeatures(Session& session, std::optional<Range> range = std::nullopt); static RangeResults<TrackId> findIdsWithRecordingMBIDAndMissingFeatures(Session& session, std::optional<Range> range = std::nullopt);
@@ -85,7 +85,7 @@ namespace lms::db
bool isEmpty() const; bool isEmpty() const;
std::size_t getCount() const; std::size_t getCount() const;
ObjectPtr<TrackListEntry> getEntry(std::size_t pos) const; ObjectPtr<TrackListEntry> getEntry(std::size_t pos) const;
std::vector<ObjectPtr<TrackListEntry>> getEntries(std::optional<Range> range = {}) const; RangeResults<ObjectPtr<TrackListEntry>> getEntries(std::optional<Range> range = {}) const;
ObjectPtr<TrackListEntry> getEntryByTrackAndDateTime(ObjectPtr<Track> track, const Wt::WDateTime& dateTime) const; ObjectPtr<TrackListEntry> getEntryByTrackAndDateTime(ObjectPtr<Track> track, const Wt::WDateTime& dateTime) const;
std::vector<TrackId> getTrackIds() const; std::vector<TrackId> getTrackIds() const;
@@ -97,8 +97,6 @@ namespace lms::db
std::vector<ObjectPtr<Cluster>> getClusters() const; std::vector<ObjectPtr<Cluster>> getClusters() const;
std::vector<std::vector<ObjectPtr<Cluster>>> getClusterGroups(const std::vector<ClusterTypeId>& clusterTypeIds, std::size_t size) const; std::vector<std::vector<ObjectPtr<Cluster>>> getClusterGroups(const std::vector<ClusterTypeId>& clusterTypeIds, std::size_t size) const;
bool hasTrack(TrackId trackId) const;
// Ordered from most clusters in common // Ordered from most clusters in common
std::vector<ObjectPtr<Track>> getSimilarTracks(std::optional<std::size_t> offset = {}, std::optional<std::size_t> size = {}) const; std::vector<ObjectPtr<Track>> getSimilarTracks(std::optional<std::size_t> offset = {}, std::optional<std::size_t> size = {}) const;
+7 -7
View File
@@ -198,8 +198,8 @@ namespace lms::db::tests
{ {
auto transaction{ session.createReadTransaction() }; auto transaction{ session.createReadTransaction() };
auto entries{ trackList.get()->getEntries() }; auto entries{ trackList.get()->getEntries() };
ASSERT_EQ(entries.size(), 1); ASSERT_EQ(entries.results.size(), 1);
EXPECT_EQ(entries.front()->getTrack()->getId(), track1.getId()); EXPECT_EQ(entries.results.front()->getTrack()->getId(), track1.getId());
} }
{ {
@@ -210,16 +210,16 @@ namespace lms::db::tests
{ {
auto transaction{ session.createReadTransaction() }; auto transaction{ session.createReadTransaction() };
auto entries{ trackList.get()->getEntries() }; auto entries{ trackList.get()->getEntries() };
ASSERT_EQ(entries.size(), 2); ASSERT_EQ(entries.results.size(), 2);
EXPECT_EQ(entries[0]->getTrack()->getId(), track1.getId()); EXPECT_EQ(entries.results[0]->getTrack()->getId(), track1.getId());
EXPECT_EQ(entries[1]->getTrack()->getId(), track2.getId()); EXPECT_EQ(entries.results[1]->getTrack()->getId(), track2.getId());
} }
{ {
auto transaction{ session.createReadTransaction() }; auto transaction{ session.createReadTransaction() };
auto entries{ trackList.get()->getEntries(Range {1, 1}) }; auto entries{ trackList.get()->getEntries(Range {1, 1}) };
ASSERT_EQ(entries.size(), 1); ASSERT_EQ(entries.results.size(), 1);
EXPECT_EQ(entries[0]->getTrack()->getId(), track2.getId()); EXPECT_EQ(entries.results[0]->getTrack()->getId(), track2.getId());
} }
} }
} }
@@ -72,7 +72,7 @@ namespace lms::api::subsonic
Response::Node playlistNode{ createPlaylistNode(tracklist, context.dbSession) }; Response::Node playlistNode{ createPlaylistNode(tracklist, context.dbSession) };
auto entries{ tracklist->getEntries() }; auto entries{ tracklist->getEntries() };
for (const TrackListEntry::pointer& entry : entries) for (const TrackListEntry::pointer& entry : entries.results)
playlistNode.addArrayChild("entry", createSongNode(context, entry->getTrack(), user)); playlistNode.addArrayChild("entry", createSongNode(context, entry->getTrack(), user));
response.addNode("playlist", std::move(playlistNode)); response.addNode("playlist", std::move(playlistNode));
@@ -129,7 +129,7 @@ namespace lms::api::subsonic
Response::Node playlistNode{ createPlaylistNode(tracklist, context.dbSession) }; Response::Node playlistNode{ createPlaylistNode(tracklist, context.dbSession) };
auto entries{ tracklist->getEntries() }; auto entries{ tracklist->getEntries() };
for (const TrackListEntry::pointer& entry : entries) for (const TrackListEntry::pointer& entry : entries.results)
playlistNode.addArrayChild("entry", createSongNode(context, entry->getTrack(), user)); playlistNode.addArrayChild("entry", createSongNode(context, entry->getTrack(), user));
response.addNode("playlist", std::move(playlistNode)); response.addNode("playlist", std::move(playlistNode));
+9 -6
View File
@@ -148,10 +148,11 @@ namespace lms::ui
shuffleBtn->clicked().connect([this] shuffleBtn->clicked().connect([this]
{ {
{ {
// TODO write scope could be reduced
auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; auto transaction{ LmsApp->getDbSession().createWriteTransaction() };
db::TrackList::pointer queue{ getQueue() }; db::TrackList::pointer queue{ getQueue() };
auto entries{ queue->getEntries() }; auto entries{ queue->getEntries().results };
core::random::shuffleContainer(entries); core::random::shuffleContainer(entries);
queue.modify()->clear(); queue.modify()->clear();
@@ -430,9 +431,9 @@ namespace lms::ui
auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; auto transaction{ LmsApp->getDbSession().createWriteTransaction() };
db::TrackList::pointer queue{ getQueue() }; db::TrackList::pointer queue{ getQueue() };
std::vector<db::TrackListEntry::pointer> entries{ queue->getEntries(db::Range {_trackPos ? *_trackPos + 1 : 0, getCapacity()}) }; auto entries{ queue->getEntries(db::Range {_trackPos ? *_trackPos + 1 : 0, getCapacity()}) };
tracks.reserve(entries.size()); tracks.reserve(entries.results.size());
for (db::TrackListEntry::pointer entry : entries) for (db::TrackListEntry::pointer& entry : entries.results)
{ {
tracks.push_back(entry->getTrack()->getId()); tracks.push_back(entry->getTrack()->getId());
entry.remove(); entry.remove();
@@ -492,9 +493,11 @@ namespace lms::ui
auto transaction{ LmsApp->getDbSession().createReadTransaction() }; auto transaction{ LmsApp->getDbSession().createReadTransaction() };
const db::TrackList::pointer queue{ getQueue() }; const db::TrackList::pointer queue{ getQueue() };
const auto tracklistEntries{ queue->getEntries(db::Range {_entriesContainer->getCount(), _batchSize}) }; const auto entries{ queue->getEntries(db::Range {_entriesContainer->getCount(), _batchSize}) };
for (const db::TrackListEntry::pointer& tracklistEntry : tracklistEntries) for (const db::TrackListEntry::pointer& tracklistEntry : entries.results)
addEntry(tracklistEntry); addEntry(tracklistEntry);
_entriesContainer->setHasMore(entries.moreResults);
} }
void PlayQueue::addEntry(const db::TrackListEntry::pointer& tracklistEntry) void PlayQueue::addEntry(const db::TrackListEntry::pointer& tracklistEntry)
@@ -24,109 +24,94 @@
namespace lms::ui namespace lms::ui
{ {
InfiniteScrollingContainer::InfiniteScrollingContainer(const Wt::WString& text) InfiniteScrollingContainer::InfiniteScrollingContainer(const Wt::WString& text)
: Wt::WTemplate {text} : Wt::WTemplate{ text }
, _elements {bindNew<Wt::WContainerWidget>("elements")} , _elements{ bindNew<Wt::WContainerWidget>("elements") }
, _loadingIndicator {bindWidget<Wt::WTemplate>("loading-indicator", createLoadingIndicator())} , _loadingIndicator{ bindWidget<Wt::WTemplate>("loading-indicator", createLoadingIndicator()) }
{ {
reset(); reset();
} }
void void InfiniteScrollingContainer::clear()
InfiniteScrollingContainer::clear() {
{ assert(false);
assert(false); }
}
void void InfiniteScrollingContainer::reset()
InfiniteScrollingContainer::reset() {
{ _elements->clear();
_elements->clear(); setHasMore(true);
setHasMore(true); }
}
std::size_t std::size_t InfiniteScrollingContainer::getCount()
InfiniteScrollingContainer::getCount() {
{ return _elements->count();
return _elements->count(); }
}
void void InfiniteScrollingContainer::add(std::unique_ptr<Wt::WWidget> result)
InfiniteScrollingContainer::add(std::unique_ptr<Wt::WWidget> result) {
{ return _elements->addWidget(std::move(result));
return _elements->addWidget(std::move(result)); }
}
void void InfiniteScrollingContainer::setHasMore()
InfiniteScrollingContainer::setHasMore() {
{ setHasMore(true);
setHasMore(true); }
}
void void InfiniteScrollingContainer::setHasMore(bool hasMore)
InfiniteScrollingContainer::setHasMore(bool hasMore) {
{ if (hasMore)
if (hasMore) displayLoadingIndicator();
displayLoadingIndicator(); else
else hideLoadingIndicator();
hideLoadingIndicator(); }
}
void void InfiniteScrollingContainer::remove(Wt::WWidget& widget)
InfiniteScrollingContainer::remove(Wt::WWidget& widget) {
{ _elements->removeWidget(&widget);
_elements->removeWidget(&widget); }
}
void void InfiniteScrollingContainer::remove(std::size_t first, std::size_t last)
InfiniteScrollingContainer::remove(std::size_t first, std::size_t last) {
{ assert(last >= first);
assert(last >= first); assert(last < static_cast<std::size_t>(_elements->count()));
assert(last < static_cast<std::size_t>(_elements->count()));
// remove from end as API is quite uneffective (minimize moves) // remove from end as API is quite uneffective (minimize moves)
std::size_t i {last}; std::size_t i{ last };
while (Wt::WWidget* widget {_elements->widget(i)}) while (Wt::WWidget * widget{ _elements->widget(static_cast<int>(i)) })
{ {
_elements->removeWidget(widget); _elements->removeWidget(widget);
if (i-- == first) if (i-- == first)
break; break;
} }
} }
Wt::WWidget* Wt::WWidget* InfiniteScrollingContainer::getWidget(std::size_t pos) const
InfiniteScrollingContainer::getWidget(std::size_t pos) const {
{ return _elements->widget(static_cast<int>(pos));
return _elements->widget(pos); }
}
std::optional<std::size_t> std::optional<std::size_t> InfiniteScrollingContainer::getIndexOf(Wt::WWidget& widget) const
InfiniteScrollingContainer::getIndexOf(Wt::WWidget& widget) const {
{ return _elements->indexOf(&widget);
return _elements->indexOf(&widget); }
}
void void InfiniteScrollingContainer::displayLoadingIndicator()
InfiniteScrollingContainer::displayLoadingIndicator() {
{ _loadingIndicator = bindWidget<Wt::WTemplate>("loading-indicator", createLoadingIndicator());
_loadingIndicator = bindWidget<Wt::WTemplate>("loading-indicator", createLoadingIndicator()); _loadingIndicator->scrollVisibilityChanged().connect([this](bool visible)
_loadingIndicator->scrollVisibilityChanged().connect([this](bool visible) {
{ if (!visible)
if (!visible) return;
return;
const auto previousCount {_elements->count()}; onRequestElements.emit();
onRequestElements.emit(); });
setHasMore(previousCount != _elements->count()); }
});
}
void
InfiniteScrollingContainer::hideLoadingIndicator()
{
_loadingIndicator = nullptr;
bindEmpty("loading-indicator");
}
void InfiniteScrollingContainer::hideLoadingIndicator()
{
_loadingIndicator = nullptr;
bindEmpty("loading-indicator");
}
} }
@@ -57,11 +57,12 @@ namespace lms::ui
Wt::Signal<> onRequestElements; Wt::Signal<> onRequestElements;
void setHasMore(bool hasMore); // can be used to add elements afterwards
private: private:
void clear() override; void clear() override;
void displayLoadingIndicator(); void displayLoadingIndicator();
void hideLoadingIndicator(); void hideLoadingIndicator();
void setHasMore(bool hasMore); // can be used to add elements afterwards
Wt::WContainerWidget* _elements; Wt::WContainerWidget* _elements;
Wt::WTemplate* _loadingIndicator; Wt::WTemplate* _loadingIndicator;
+8 -9
View File
@@ -21,16 +21,15 @@
namespace lms::ui namespace lms::ui
{ {
std::unique_ptr<Wt::WTemplate> std::unique_ptr<Wt::WTemplate> createLoadingIndicator()
createLoadingIndicator() {
{ auto res {std::make_unique<Wt::WTemplate>(Wt::WString::tr("Lms.LoadingIndicator.template"))};
auto res {std::make_unique<Wt::WTemplate>(Wt::WString::tr("Lms.LoadingIndicator.template"))};
res->addFunction("tr", &Wt::WTemplate::Functions::tr); res->addFunction("tr", &Wt::WTemplate::Functions::tr);
res->setScrollVisibilityEnabled(true); res->setScrollVisibilityEnabled(true);
res->setScrollVisibilityMargin(200); res->setScrollVisibilityMargin(200);
return res; return res;
} }
} }
+6 -1
View File
@@ -332,12 +332,13 @@ namespace lms::ui
releaseContainer.container->add(releaseListHelpers::createEntryForArtist(release, artist)); releaseContainer.container->add(releaseListHelpers::createEntryForArtist(release, artist));
} }
} }
releaseContainer.container->setHasMore(false);
} }
bool Artist::addSomeNonReleaseTracks() bool Artist::addSomeNonReleaseTracks()
{ {
bool areTracksAdded{}; bool areTracksAdded{};
auto transaction{ LmsApp->getDbSession().createReadTransaction() };
const Range range{ static_cast<std::size_t>(_trackContainer->getCount()), _tracksBatchSize }; const Range range{ static_cast<std::size_t>(_trackContainer->getCount()), _tracksBatchSize };
@@ -348,6 +349,8 @@ namespace lms::ui
params.setSortMethod(TrackSortMethod::Name); params.setSortMethod(TrackSortMethod::Name);
params.setNonRelease(true); params.setNonRelease(true);
auto transaction{ LmsApp->getDbSession().createReadTransaction() };
const auto tracks{ Track::find(LmsApp->getDbSession(), params) }; const auto tracks{ Track::find(LmsApp->getDbSession(), params) };
for (const Track::pointer& track : tracks.results) for (const Track::pointer& track : tracks.results)
{ {
@@ -360,6 +363,8 @@ namespace lms::ui
areTracksAdded = true; areTracksAdded = true;
} }
_trackContainer->setHasMore(tracks.moreResults);
return areTracksAdded; return areTracksAdded;
} }
+2
View File
@@ -125,6 +125,8 @@ namespace lms::ui
_container->add(ArtistListHelpers::createEntry(artist)); _container->add(ArtistListHelpers::createEntry(artist));
} }
} }
_container->setHasMore(artistIds.moreResults);
} }
} // namespace lms::ui } // namespace lms::ui
+1 -1
View File
@@ -463,7 +463,7 @@ namespace lms::ui
auto isStarred{ [=] { return core::Service<feedback::IFeedbackService>::get()->isStarred(LmsApp->getUserId(), trackId); } }; auto isStarred{ [=] { return core::Service<feedback::IFeedbackService>::get()->isStarred(LmsApp->getUserId(), trackId); } };
Wt::WPushButton* starBtn{ entry->bindNew<Wt::WPushButton>("star", Wt::WString::tr(isStarred() ? "Lms.Explore.unstar" : "Lms.Explore.star")) }; Wt::WPushButton* starBtn{ entry->bindNew<Wt::WPushButton>("star", Wt::WString::tr(isStarred() ? "Lms.Explore.unstar" : "Lms.Explore.star")) };
starBtn->clicked().connect([=, this] starBtn->clicked().connect([=]
{ {
if (isStarred()) if (isStarred())
{ {
+2
View File
@@ -129,6 +129,8 @@ namespace lms::ui
_container->add(releaseListHelpers::createEntry(release)); _container->add(releaseListHelpers::createEntry(release));
} }
} }
_container->setHasMore(releaseIds.moreResults);
} }
std::vector<ReleaseId> Releases::getAllReleases() std::vector<ReleaseId> Releases::getAllReleases()
+6
View File
@@ -159,6 +159,8 @@ namespace lms::ui
_artists->add(ArtistListHelpers::createEntry(artist)); _artists->add(ArtistListHelpers::createEntry(artist));
} }
} }
_artists->setHasMore(artistIds.moreResults);
} }
void SearchView::addSomeReleases() void SearchView::addSomeReleases()
@@ -177,6 +179,8 @@ namespace lms::ui
_releases->add(releaseListHelpers::createEntry(release)); _releases->add(releaseListHelpers::createEntry(release));
} }
} }
_releases->setHasMore(releaseIds.moreResults);
} }
void SearchView::addSomeTracks() void SearchView::addSomeTracks()
@@ -196,5 +200,7 @@ namespace lms::ui
_tracks->add(TrackListHelpers::createEntry(track, _playQueueController, _filters)); _tracks->add(TrackListHelpers::createEntry(track, _playQueueController, _filters));
} }
} }
_tracks->setHasMore(trackIds.moreResults);
} }
} }
+4 -1
View File
@@ -188,10 +188,13 @@ namespace lms::ui
params.setSortMethod(db::TrackSortMethod::TrackList); params.setSortMethod(db::TrackSortMethod::TrackList);
params.setRange(db::Range{ static_cast<std::size_t>(_container->getCount()), _batchSize }); params.setRange(db::Range{ static_cast<std::size_t>(_container->getCount()), _batchSize });
db::Track::find(LmsApp->getDbSession(), params, [this](const Track::pointer& track) bool moreResults{};
db::Track::find(LmsApp->getDbSession(), params, moreResults, [this](const Track::pointer& track)
{ {
_container->add(TrackListHelpers::createEntry(track, _playQueueController, _filters)); _container->add(TrackListHelpers::createEntry(track, _playQueueController, _filters));
}); });
_container->setHasMore(moreResults);
} }
} // namespace lms::ui } // namespace lms::ui
+2
View File
@@ -121,6 +121,8 @@ namespace lms::ui
if (const TrackList::pointer trackList{ TrackList::find(LmsApp->getDbSession(), trackListId) }) if (const TrackList::pointer trackList{ TrackList::find(LmsApp->getDbSession(), trackListId) })
addTracklist(trackList); addTracklist(trackList);
} }
_container->setHasMore(trackListIds.moreResults);
} }
void TrackLists::addTracklist(const ObjectPtr<TrackList>& trackList) void TrackLists::addTracklist(const ObjectPtr<TrackList>& trackList)
+2
View File
@@ -128,6 +128,8 @@ namespace lms::ui
if (const Track::pointer track{ Track::find(LmsApp->getDbSession(), trackId) }) if (const Track::pointer track{ Track::find(LmsApp->getDbSession(), trackId) })
_container->add(TrackListHelpers::createEntry(track, _playQueueController, _filters)); _container->add(TrackListHelpers::createEntry(track, _playQueueController, _filters));
} }
_container->setHasMore(trackIds.moreResults);
} }
std::vector<db::TrackId> Tracks::getAllTracks() std::vector<db::TrackId> Tracks::getAllTracks()