From 28771e12d560aa9be8b5d178e63ab0e641b4c9b8 Mon Sep 17 00:00:00 2001 From: joren Date: Tue, 31 Mar 2026 11:17:23 +0200 Subject: [PATCH] fix: lazy-load genre/playlist views and cap playlist search scrolling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- src/view/genrebrowser.cpp | 75 +++++++++++++++++++++++++++++++-------- src/view/genrebrowser.hpp | 2 ++ 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/view/genrebrowser.cpp b/src/view/genrebrowser.cpp index de5a670..5c9e476 100644 --- a/src/view/genrebrowser.cpp +++ b/src/view/genrebrowser.cpp @@ -9,7 +9,9 @@ #include #include #include +#include #include +#include #include #include @@ -120,8 +122,18 @@ GenreBrowserView::GenreBrowserView(QobuzBackend *backend, PlayQueue *queue, QWid m_playlistList->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents); 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_playlistList); + m_resultsStack->addWidget(playlistPage); layout->addWidget(m_resultsStack, 1); connect(m_backend, &QobuzBackend::genresLoaded, @@ -180,6 +192,12 @@ GenreBrowserView::GenreBrowserView(QobuzBackend *backend, PlayQueue *queue, QWid this, &GenreBrowserView::onAlbumScroll); connect(m_playlistList->verticalScrollBar(), &QScrollBar::valueChanged, 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); refreshModeUi(); @@ -391,9 +409,12 @@ void GenreBrowserView::onFeaturedAlbumsLoaded(const QJsonObject &result) } // If the viewport is not scrollable yet, eagerly fetch more pages. - QScrollBar *bar = m_albumList->verticalScrollBar(); - if (bar && bar->maximum() == 0 && m_albumOffset < m_albumTotal) - requestAlbumsPage(m_lastAlbumGenreIds, m_lastAlbumType, m_albumOffset, true); + // Deferred: the scrollbar maximum isn't updated until after layout runs. + QTimer::singleShot(0, this, [this] { + QScrollBar *bar = m_albumList->verticalScrollBar(); + if (bar && bar->maximum() == 0 && m_albumOffset < m_albumTotal) + requestAlbumsPage(m_lastAlbumGenreIds, m_lastAlbumType, m_albumOffset, true); + }); } void GenreBrowserView::onFeaturedPlaylistsLoaded(const QJsonObject &result) @@ -413,9 +434,11 @@ void GenreBrowserView::onFeaturedPlaylistsLoaded(const QJsonObject &result) m_playlistTotal = m_playlistOffset; m_loadingPlaylists = false; - QScrollBar *bar = m_playlistList->verticalScrollBar(); - if (bar && bar->maximum() == 0 && m_playlistOffset < m_playlistTotal) - requestPlaylistsPage(m_lastPlaylistGenreIds, m_lastPlaylistType, m_lastPlaylistTags, m_lastPlaylistQuery, m_playlistOffset, true); + QTimer::singleShot(0, this, [this] { + QScrollBar *bar = m_playlistList->verticalScrollBar(); + if (bar && bar->maximum() == 0 && m_playlistOffset < m_playlistTotal) + requestPlaylistsPage(m_lastPlaylistGenreIds, m_lastPlaylistType, m_lastPlaylistTags, m_lastPlaylistQuery, m_playlistOffset, true); + }); } void GenreBrowserView::onDiscoverPlaylistsLoaded(const QJsonObject &result) @@ -435,9 +458,11 @@ void GenreBrowserView::onDiscoverPlaylistsLoaded(const QJsonObject &result) m_playlistTotal = m_playlistOffset; m_loadingPlaylists = false; - QScrollBar *bar = m_playlistList->verticalScrollBar(); - if (bar && bar->maximum() == 0 && m_playlistOffset < m_playlistTotal) - requestPlaylistsPage(m_lastPlaylistGenreIds, m_lastPlaylistType, m_lastPlaylistTags, m_lastPlaylistQuery, m_playlistOffset, true); + QTimer::singleShot(0, this, [this] { + QScrollBar *bar = m_playlistList->verticalScrollBar(); + if (bar && bar->maximum() == 0 && m_playlistOffset < m_playlistTotal) + requestPlaylistsPage(m_lastPlaylistGenreIds, m_lastPlaylistType, m_lastPlaylistTags, m_lastPlaylistQuery, m_playlistOffset, true); + }); } void GenreBrowserView::onPlaylistSearchLoaded(const QJsonObject &result) @@ -456,9 +481,25 @@ void GenreBrowserView::onPlaylistSearchLoaded(const QJsonObject &result) m_playlistTotal = m_playlistOffset; m_loadingPlaylists = false; - QScrollBar *bar = m_playlistList->verticalScrollBar(); - if (bar && bar->maximum() == 0 && m_playlistOffset < m_playlistTotal) - requestPlaylistsPage(m_lastPlaylistGenreIds, m_lastPlaylistType, m_lastPlaylistTags, m_lastPlaylistQuery, m_playlistOffset, true); + // 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(); + if (bar && bar->maximum() == 0 && m_playlistOffset < m_playlistTotal) { + 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() @@ -571,6 +612,9 @@ void GenreBrowserView::requestPlaylistsPage(const QString &genreIds, const QStri m_loadingPlaylists = false; m_playlistOffset = 0; m_playlistTotal = 0; + m_loadMorePlaylistsBtn->hide(); + if (type == QStringLiteral("search")) + m_searchViewportFilled = false; } m_lastPlaylistGenreIds = genreIds; @@ -580,7 +624,7 @@ void GenreBrowserView::requestPlaylistsPage(const QString &genreIds, const QStri m_loadingPlaylists = true; if (type == QStringLiteral("search")) { - m_backend->searchPlaylists(query, 8, static_cast(offset)); + m_backend->searchPlaylists(query, 25, static_cast(offset)); } else if (type.startsWith(QStringLiteral("discover-"))) { m_backend->discoverPlaylists(genreIds, tags, 25, static_cast(offset)); } else { @@ -608,6 +652,9 @@ void GenreBrowserView::onAlbumScroll(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) return; if (m_playlistOffset >= m_playlistTotal) diff --git a/src/view/genrebrowser.hpp b/src/view/genrebrowser.hpp index 6ce384b..d2d8887 100644 --- a/src/view/genrebrowser.hpp +++ b/src/view/genrebrowser.hpp @@ -70,6 +70,8 @@ private: QStackedWidget *m_resultsStack = nullptr; AlbumListView *m_albumList = nullptr; QTreeWidget *m_playlistList = nullptr; + QPushButton *m_loadMorePlaylistsBtn = nullptr; + bool m_searchViewportFilled = false; BrowseMode m_mode = BrowseMode::Genres; bool m_genresLoaded = false; int m_lastGenreComboIndex = 0;