fix: lazy-load genre/playlist views and cap playlist search scrolling
Some checks failed
Build for Windows / build-windows (push) Has been cancelled
Some checks failed
Build for Windows / build-windows (push) Has been cancelled
- Defer eager-load scrollbar checks to next event loop iteration via QTimer::singleShot(0), fixing initial load not filling the viewport - Playlist search: eagerly fill viewport, then show "Load more playlists…" button instead of infinite scroll to avoid loading thousands of results - Increase search page size from 8 to 25 - Featured/discover playlists keep auto-scroll behavior unchanged Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,9 @@
|
|||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QScrollBar>
|
||||||
#include <QSignalBlocker>
|
#include <QSignalBlocker>
|
||||||
|
#include <QTimer>
|
||||||
#include <QTreeWidgetItem>
|
#include <QTreeWidgetItem>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
@@ -120,8 +122,18 @@ GenreBrowserView::GenreBrowserView(QobuzBackend *backend, PlayQueue *queue, QWid
|
|||||||
m_playlistList->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
|
m_playlistList->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
|
||||||
m_playlistList->header()->setStretchLastSection(false);
|
m_playlistList->header()->setStretchLastSection(false);
|
||||||
|
|
||||||
|
auto *playlistPage = new QWidget(this);
|
||||||
|
auto *playlistPageLayout = new QVBoxLayout(playlistPage);
|
||||||
|
playlistPageLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
playlistPageLayout->setSpacing(0);
|
||||||
|
playlistPageLayout->addWidget(m_playlistList, 1);
|
||||||
|
|
||||||
|
m_loadMorePlaylistsBtn = new QPushButton(tr("Load more playlists…"), this);
|
||||||
|
m_loadMorePlaylistsBtn->hide();
|
||||||
|
playlistPageLayout->addWidget(m_loadMorePlaylistsBtn);
|
||||||
|
|
||||||
m_resultsStack->addWidget(m_albumList);
|
m_resultsStack->addWidget(m_albumList);
|
||||||
m_resultsStack->addWidget(m_playlistList);
|
m_resultsStack->addWidget(playlistPage);
|
||||||
layout->addWidget(m_resultsStack, 1);
|
layout->addWidget(m_resultsStack, 1);
|
||||||
|
|
||||||
connect(m_backend, &QobuzBackend::genresLoaded,
|
connect(m_backend, &QobuzBackend::genresLoaded,
|
||||||
@@ -180,6 +192,12 @@ GenreBrowserView::GenreBrowserView(QobuzBackend *backend, PlayQueue *queue, QWid
|
|||||||
this, &GenreBrowserView::onAlbumScroll);
|
this, &GenreBrowserView::onAlbumScroll);
|
||||||
connect(m_playlistList->verticalScrollBar(), &QScrollBar::valueChanged,
|
connect(m_playlistList->verticalScrollBar(), &QScrollBar::valueChanged,
|
||||||
this, &GenreBrowserView::onPlaylistScroll);
|
this, &GenreBrowserView::onPlaylistScroll);
|
||||||
|
connect(m_loadMorePlaylistsBtn, &QPushButton::clicked, this, [this] {
|
||||||
|
m_loadMorePlaylistsBtn->hide();
|
||||||
|
requestPlaylistsPage(m_lastPlaylistGenreIds, m_lastPlaylistType,
|
||||||
|
m_lastPlaylistTags, m_lastPlaylistQuery,
|
||||||
|
m_playlistOffset, true);
|
||||||
|
});
|
||||||
|
|
||||||
m_kindCombo->setCurrentIndex(0);
|
m_kindCombo->setCurrentIndex(0);
|
||||||
refreshModeUi();
|
refreshModeUi();
|
||||||
@@ -391,9 +409,12 @@ void GenreBrowserView::onFeaturedAlbumsLoaded(const QJsonObject &result)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the viewport is not scrollable yet, eagerly fetch more pages.
|
// If the viewport is not scrollable yet, eagerly fetch more pages.
|
||||||
|
// Deferred: the scrollbar maximum isn't updated until after layout runs.
|
||||||
|
QTimer::singleShot(0, this, [this] {
|
||||||
QScrollBar *bar = m_albumList->verticalScrollBar();
|
QScrollBar *bar = m_albumList->verticalScrollBar();
|
||||||
if (bar && bar->maximum() == 0 && m_albumOffset < m_albumTotal)
|
if (bar && bar->maximum() == 0 && m_albumOffset < m_albumTotal)
|
||||||
requestAlbumsPage(m_lastAlbumGenreIds, m_lastAlbumType, m_albumOffset, true);
|
requestAlbumsPage(m_lastAlbumGenreIds, m_lastAlbumType, m_albumOffset, true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenreBrowserView::onFeaturedPlaylistsLoaded(const QJsonObject &result)
|
void GenreBrowserView::onFeaturedPlaylistsLoaded(const QJsonObject &result)
|
||||||
@@ -413,9 +434,11 @@ void GenreBrowserView::onFeaturedPlaylistsLoaded(const QJsonObject &result)
|
|||||||
m_playlistTotal = m_playlistOffset;
|
m_playlistTotal = m_playlistOffset;
|
||||||
m_loadingPlaylists = false;
|
m_loadingPlaylists = false;
|
||||||
|
|
||||||
|
QTimer::singleShot(0, this, [this] {
|
||||||
QScrollBar *bar = m_playlistList->verticalScrollBar();
|
QScrollBar *bar = m_playlistList->verticalScrollBar();
|
||||||
if (bar && bar->maximum() == 0 && m_playlistOffset < m_playlistTotal)
|
if (bar && bar->maximum() == 0 && m_playlistOffset < m_playlistTotal)
|
||||||
requestPlaylistsPage(m_lastPlaylistGenreIds, m_lastPlaylistType, m_lastPlaylistTags, m_lastPlaylistQuery, m_playlistOffset, true);
|
requestPlaylistsPage(m_lastPlaylistGenreIds, m_lastPlaylistType, m_lastPlaylistTags, m_lastPlaylistQuery, m_playlistOffset, true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenreBrowserView::onDiscoverPlaylistsLoaded(const QJsonObject &result)
|
void GenreBrowserView::onDiscoverPlaylistsLoaded(const QJsonObject &result)
|
||||||
@@ -435,9 +458,11 @@ void GenreBrowserView::onDiscoverPlaylistsLoaded(const QJsonObject &result)
|
|||||||
m_playlistTotal = m_playlistOffset;
|
m_playlistTotal = m_playlistOffset;
|
||||||
m_loadingPlaylists = false;
|
m_loadingPlaylists = false;
|
||||||
|
|
||||||
|
QTimer::singleShot(0, this, [this] {
|
||||||
QScrollBar *bar = m_playlistList->verticalScrollBar();
|
QScrollBar *bar = m_playlistList->verticalScrollBar();
|
||||||
if (bar && bar->maximum() == 0 && m_playlistOffset < m_playlistTotal)
|
if (bar && bar->maximum() == 0 && m_playlistOffset < m_playlistTotal)
|
||||||
requestPlaylistsPage(m_lastPlaylistGenreIds, m_lastPlaylistType, m_lastPlaylistTags, m_lastPlaylistQuery, m_playlistOffset, true);
|
requestPlaylistsPage(m_lastPlaylistGenreIds, m_lastPlaylistType, m_lastPlaylistTags, m_lastPlaylistQuery, m_playlistOffset, true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenreBrowserView::onPlaylistSearchLoaded(const QJsonObject &result)
|
void GenreBrowserView::onPlaylistSearchLoaded(const QJsonObject &result)
|
||||||
@@ -456,9 +481,25 @@ void GenreBrowserView::onPlaylistSearchLoaded(const QJsonObject &result)
|
|||||||
m_playlistTotal = m_playlistOffset;
|
m_playlistTotal = m_playlistOffset;
|
||||||
m_loadingPlaylists = false;
|
m_loadingPlaylists = false;
|
||||||
|
|
||||||
|
// Eagerly fill the viewport, then switch to a manual "Load more" button.
|
||||||
|
if (m_playlistOffset >= m_playlistTotal) {
|
||||||
|
m_loadMorePlaylistsBtn->hide();
|
||||||
|
m_searchViewportFilled = true;
|
||||||
|
} else if (!m_searchViewportFilled) {
|
||||||
|
QTimer::singleShot(0, this, [this] {
|
||||||
QScrollBar *bar = m_playlistList->verticalScrollBar();
|
QScrollBar *bar = m_playlistList->verticalScrollBar();
|
||||||
if (bar && bar->maximum() == 0 && m_playlistOffset < m_playlistTotal)
|
if (bar && bar->maximum() == 0 && m_playlistOffset < m_playlistTotal) {
|
||||||
requestPlaylistsPage(m_lastPlaylistGenreIds, m_lastPlaylistType, m_lastPlaylistTags, m_lastPlaylistQuery, m_playlistOffset, true);
|
requestPlaylistsPage(m_lastPlaylistGenreIds, m_lastPlaylistType,
|
||||||
|
m_lastPlaylistTags, m_lastPlaylistQuery,
|
||||||
|
m_playlistOffset, true);
|
||||||
|
} else {
|
||||||
|
m_searchViewportFilled = true;
|
||||||
|
m_loadMorePlaylistsBtn->setVisible(m_playlistOffset < m_playlistTotal);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
m_loadMorePlaylistsBtn->setVisible(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenreBrowserView::onSelectionChanged()
|
void GenreBrowserView::onSelectionChanged()
|
||||||
@@ -571,6 +612,9 @@ void GenreBrowserView::requestPlaylistsPage(const QString &genreIds, const QStri
|
|||||||
m_loadingPlaylists = false;
|
m_loadingPlaylists = false;
|
||||||
m_playlistOffset = 0;
|
m_playlistOffset = 0;
|
||||||
m_playlistTotal = 0;
|
m_playlistTotal = 0;
|
||||||
|
m_loadMorePlaylistsBtn->hide();
|
||||||
|
if (type == QStringLiteral("search"))
|
||||||
|
m_searchViewportFilled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_lastPlaylistGenreIds = genreIds;
|
m_lastPlaylistGenreIds = genreIds;
|
||||||
@@ -580,7 +624,7 @@ void GenreBrowserView::requestPlaylistsPage(const QString &genreIds, const QStri
|
|||||||
m_loadingPlaylists = true;
|
m_loadingPlaylists = true;
|
||||||
|
|
||||||
if (type == QStringLiteral("search")) {
|
if (type == QStringLiteral("search")) {
|
||||||
m_backend->searchPlaylists(query, 8, static_cast<quint32>(offset));
|
m_backend->searchPlaylists(query, 25, static_cast<quint32>(offset));
|
||||||
} else if (type.startsWith(QStringLiteral("discover-"))) {
|
} else if (type.startsWith(QStringLiteral("discover-"))) {
|
||||||
m_backend->discoverPlaylists(genreIds, tags, 25, static_cast<quint32>(offset));
|
m_backend->discoverPlaylists(genreIds, tags, 25, static_cast<quint32>(offset));
|
||||||
} else {
|
} else {
|
||||||
@@ -608,6 +652,9 @@ void GenreBrowserView::onAlbumScroll(int value)
|
|||||||
|
|
||||||
void GenreBrowserView::onPlaylistScroll(int value)
|
void GenreBrowserView::onPlaylistScroll(int value)
|
||||||
{
|
{
|
||||||
|
// Search results use a manual "Load more" button instead of infinite scroll.
|
||||||
|
if (m_lastPlaylistType == QStringLiteral("search"))
|
||||||
|
return;
|
||||||
if (m_loadingPlaylists)
|
if (m_loadingPlaylists)
|
||||||
return;
|
return;
|
||||||
if (m_playlistOffset >= m_playlistTotal)
|
if (m_playlistOffset >= m_playlistTotal)
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ private:
|
|||||||
QStackedWidget *m_resultsStack = nullptr;
|
QStackedWidget *m_resultsStack = nullptr;
|
||||||
AlbumListView *m_albumList = nullptr;
|
AlbumListView *m_albumList = nullptr;
|
||||||
QTreeWidget *m_playlistList = nullptr;
|
QTreeWidget *m_playlistList = nullptr;
|
||||||
|
QPushButton *m_loadMorePlaylistsBtn = nullptr;
|
||||||
|
bool m_searchViewportFilled = false;
|
||||||
BrowseMode m_mode = BrowseMode::Genres;
|
BrowseMode m_mode = BrowseMode::Genres;
|
||||||
bool m_genresLoaded = false;
|
bool m_genresLoaded = false;
|
||||||
int m_lastGenreComboIndex = 0;
|
int m_lastGenreComboIndex = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user