Split the search view in order to workaround the scroll visibility issue

This commit is contained in:
emeric
2023-11-03 09:12:19 +01:00
parent e339a42883
commit 9ff1b215c2
3 changed files with 207 additions and 186 deletions
+13 -13
View File
@@ -3,29 +3,29 @@
<!--FORMS message blocks--> <!--FORMS message blocks-->
<message id="Lms.Explore.Search.template"> <message id="Lms.Explore.Search.template">
<ul class="nav nav-pills mb-3" id="myTab" role="tablist"> <div class="mb-3">
<li class="nav-item" role="presentation"> <ul class="nav nav-pills mb-3">
<button class="nav-link active" id="releases-tab" data-bs-toggle="tab" data-bs-target="#releases" type="button" role="tab" aria-controls="releases" aria-selected="true">${tr:Lms.Explore.releases}</button> <li class="nav-item">
${releases class="nav-link"}
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item">
<button class="nav-link" id="artists-tab" data-bs-toggle="tab" data-bs-target="#artists" type="button" role="tab" aria-controls="artists" aria-selected="false">${tr:Lms.Explore.artists}</button> ${artists class="nav-link"}
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item">
<button class="nav-link" id="tracks-tab" data-bs-toggle="tab" data-bs-target="#tracks" type="button" role="tab" aria-controls="tracks" aria-selected="false">${tr:Lms.Explore.tracks}</button> ${tracks class="nav-link"}
</li> </li>
</ul> </ul>
<div class="tab-content" id="myTabContent"> </div>
<div class="tab-pane show active" id="releases" role="tabpanel" aria-labelledby="releases-tab">${releases}</div> ${results}
<div class="tab-pane" id="artists" role="tabpanel" aria-labelledby="artists-tab"> </message>
<message id="Lms.Explore.Search.template.artists">
<div class="row mb-3"> <div class="row mb-3">
<div class="col-lg-3"> <div class="col-lg-3">
${link-type class="form-select"} ${link-type class="form-select"}
</div> </div>
</div> </div>
${artists} ${artists}
</div>
<div class="tab-pane" id="tracks" role="tabpanel" aria-labelledby="tracks-tab">${tracks}</div>
</div>
</message> </message>
</messages> </messages>
+69 -47
View File
@@ -19,6 +19,8 @@
#include "SearchView.hpp" #include "SearchView.hpp"
#include <Wt/WPushButton.h>
#include "services/database/Artist.hpp" #include "services/database/Artist.hpp"
#include "services/database/Release.hpp" #include "services/database/Release.hpp"
#include "services/database/Session.hpp" #include "services/database/Session.hpp"
@@ -36,32 +38,64 @@ using namespace Database;
namespace UserInterface namespace UserInterface
{ {
SearchView::SearchView(Filters& filters, PlayQueueController& playQueueController) SearchView::SearchView(Filters& filters, PlayQueueController& playQueueController)
: Wt::WTemplate {Wt::WString::tr("Lms.Explore.Search.template")} : Wt::WTemplate{ Wt::WString::tr("Lms.Explore.Search.template") }
, _playQueueController {playQueueController} , _playQueueController{ playQueueController }
, _filters {filters} , _filters{ filters }
, _artistCollector {filters, ArtistCollector::Mode::Search, getMaxCount(Mode::Artist)} , _artistCollector{ filters, ArtistCollector::Mode::Search, getMaxCount(Mode::Artist) }
, _releaseCollector {filters, ReleaseCollector::Mode::Search, getMaxCount(Mode::Release)} , _releaseCollector{ filters, ReleaseCollector::Mode::Search, getMaxCount(Mode::Release) }
, _trackCollector {filters, TrackCollector::Mode::Search, getMaxCount(Mode::Track)} , _trackCollector{ filters, TrackCollector::Mode::Search, getMaxCount(Mode::Track) }
{ {
addFunction("tr", &Wt::WTemplate::Functions::tr); addFunction("tr", &Wt::WTemplate::Functions::tr);
_artists = bindNew<InfiniteScrollingContainer>("artists", Wt::WString::tr("Lms.Explore.Artists.template.container")); _stack = bindNew<Wt::WStackedWidget>("results");
_artists->onRequestElements.connect([this] { addSomeArtists(); });
_artistLinkType = bindNew<Wt::WComboBox>("link-type"); // releases
_releases = _stack->addNew<InfiniteScrollingContainer>(Wt::WString::tr("Lms.Explore.Releases.template.container"));
_releases->onRequestElements.connect([this] { addSomeReleases(); });
// artists
{
Wt::WTemplate* artistResults{ _stack->addNew<Wt::WTemplate>(Wt::WString::tr("Lms.Explore.Search.template.artists")) };
_artistLinkType = artistResults->bindNew<Wt::WComboBox>("link-type");
_artistLinkType->setModel(ArtistListHelpers::createArtistLinkTypesModel()); _artistLinkType->setModel(ArtistListHelpers::createArtistLinkTypesModel());
_artistLinkType->changed().connect([this] _artistLinkType->changed().connect([this]
{ {
const std::optional<TrackArtistLinkType> linkType {static_cast<ArtistLinkTypesModel*>(_artistLinkType->model().get())->getValue(_artistLinkType->currentIndex())}; const std::optional<TrackArtistLinkType> linkType{ static_cast<ArtistLinkTypesModel*>(_artistLinkType->model().get())->getValue(_artistLinkType->currentIndex()) };
refreshView(linkType); refreshView(linkType);
}); });
_releases = bindNew<InfiniteScrollingContainer>("releases", Wt::WString::tr("Lms.Explore.Releases.template.container")); _artists = artistResults->bindNew<InfiniteScrollingContainer>("artists", Wt::WString::tr("Lms.Explore.Artists.template.container"));
_releases->onRequestElements.connect([this] { addSomeReleases(); }); _artists->onRequestElements.connect([this] { addSomeArtists(); });
}
_tracks = bindNew<InfiniteScrollingContainer>("tracks"); // Tracks
_tracks = _stack->addNew<InfiniteScrollingContainer>();
_tracks->onRequestElements.connect([this] { addSomeTracks(); }); _tracks->onRequestElements.connect([this] { addSomeTracks(); });
// Menu
auto bindMenuItem{ [this](std::size_t index, const std::string& var, const Wt::WString& title)
{
Wt::WPushButton* menuItem {bindNew<Wt::WPushButton>(var, title)};
menuItem->clicked().connect([=]
{
_stack->setCurrentIndex(index);
_currentActiveItem->removeStyleClass("active");
menuItem->addStyleClass("active");
_currentActiveItem = menuItem;
});
if (index == 0)
{
_currentActiveItem = menuItem;
_currentActiveItem->addStyleClass("active");
}
} };
bindMenuItem(0, "releases", Wt::WString::tr("Lms.Explore.releases"));
bindMenuItem(1, "artists", Wt::WString::tr("Lms.Explore.artists"));
bindMenuItem(2, "tracks", Wt::WString::tr("Lms.Explore.tracks"));
filters.updated().connect([=] filters.updated().connect([=]
{ {
refreshView(); refreshView();
@@ -74,31 +108,27 @@ namespace UserInterface
}); });
} }
std::size_t std::size_t SearchView::getBatchSize(Mode mode) const
SearchView::getBatchSize(Mode mode) const
{ {
auto it {_batchSizes.find(mode)}; auto it{ _batchSizes.find(mode) };
assert(it != _batchSizes.cend()); assert(it != _batchSizes.cend());
return it->second; return it->second;
} }
std::size_t std::size_t SearchView::getMaxCount(Mode mode) const
SearchView::getMaxCount(Mode mode) const
{ {
auto it {_maxCounts.find(mode)}; auto it{ _maxCounts.find(mode) };
assert(it != _maxCounts.cend()); assert(it != _maxCounts.cend());
return it->second; return it->second;
} }
void void SearchView::refreshView(std::optional<TrackArtistLinkType> linkType)
SearchView::refreshView(std::optional<TrackArtistLinkType> linkType)
{ {
_artistCollector.setArtistLinkType(linkType); _artistCollector.setArtistLinkType(linkType);
refreshView(); refreshView();
} }
void void SearchView::refreshView(const Wt::WString& searchText)
SearchView::refreshView(const Wt::WString& searchText)
{ {
_releaseCollector.setSearch(searchText.toUTF8()); _releaseCollector.setSearch(searchText.toUTF8());
_artistCollector.setSearch(searchText.toUTF8()); _artistCollector.setSearch(searchText.toUTF8());
@@ -106,68 +136,60 @@ namespace UserInterface
refreshView(); refreshView();
} }
void void SearchView::refreshView()
SearchView::refreshView()
{ {
_artists->reset(); _artists->reset();
_releases->reset(); _releases->reset();
_tracks->reset(); _tracks->reset();
addSomeArtists();
addSomeReleases();
addSomeTracks();
} }
void void SearchView::addSomeArtists()
SearchView::addSomeArtists()
{ {
using namespace Database; using namespace Database;
const Range range {_artists->getCount(), getBatchSize(Mode::Artist)}; const Range range{ _artists->getCount(), getBatchSize(Mode::Artist) };
const RangeResults<ArtistId> artistIds {_artistCollector.get(range)}; const RangeResults<ArtistId> artistIds{ _artistCollector.get(range) };
{ {
auto transaction {LmsApp->getDbSession().createSharedTransaction()}; auto transaction{ LmsApp->getDbSession().createSharedTransaction() };
for (const ArtistId artistId : artistIds.results) for (const ArtistId artistId : artistIds.results)
{ {
const Artist::pointer artist {Artist::find(LmsApp->getDbSession(), artistId)}; const Artist::pointer artist{ Artist::find(LmsApp->getDbSession(), artistId) };
_artists->add(ArtistListHelpers::createEntry(artist)); _artists->add(ArtistListHelpers::createEntry(artist));
} }
} }
} }
void void SearchView::addSomeReleases()
SearchView::addSomeReleases()
{ {
using namespace Database; using namespace Database;
const Range range {_releases->getCount(), getBatchSize(Mode::Release)}; const Range range{ _releases->getCount(), getBatchSize(Mode::Release) };
const RangeResults<ReleaseId> releaseIds {_releaseCollector.get(range)}; const RangeResults<ReleaseId> releaseIds{ _releaseCollector.get(range) };
{ {
auto transaction {LmsApp->getDbSession().createSharedTransaction()}; auto transaction{ LmsApp->getDbSession().createSharedTransaction() };
for (const ReleaseId releaseId : releaseIds.results) for (const ReleaseId releaseId : releaseIds.results)
{ {
const Release::pointer release {Release::find(LmsApp->getDbSession(), releaseId)}; const Release::pointer release{ Release::find(LmsApp->getDbSession(), releaseId) };
_releases->add(ReleaseListHelpers::createEntry(release)); _releases->add(ReleaseListHelpers::createEntry(release));
} }
} }
} }
void void SearchView::addSomeTracks()
SearchView::addSomeTracks()
{ {
using namespace Database; using namespace Database;
const Range range {_tracks->getCount(), getBatchSize(Mode::Track)}; const Range range{ _tracks->getCount(), getBatchSize(Mode::Track) };
const RangeResults<TrackId> trackIds {_trackCollector.get(range)}; const RangeResults<TrackId> trackIds{ _trackCollector.get(range) };
{ {
auto transaction {LmsApp->getDbSession().createSharedTransaction()}; auto transaction{ LmsApp->getDbSession().createSharedTransaction() };
for (const TrackId trackId : trackIds.results) for (const TrackId trackId : trackIds.results)
{ {
const Track::pointer track {Track::find(LmsApp->getDbSession(), trackId)}; const Track::pointer track{ Track::find(LmsApp->getDbSession(), trackId) };
_tracks->add(TrackListHelpers::createEntry(track, _playQueueController, _filters)); _tracks->add(TrackListHelpers::createEntry(track, _playQueueController, _filters));
} }
} }
+7 -8
View File
@@ -53,7 +53,7 @@ namespace UserInterface
Track, Track,
}; };
static constexpr Mode _defaultMode {Mode::Release}; static constexpr Mode _defaultMode{ Mode::Release };
static inline std::unordered_map<Mode, std::size_t> _batchSizes static inline std::unordered_map<Mode, std::size_t> _batchSizes
{ {
{Mode::Artist, 6}, {Mode::Artist, 6},
@@ -80,14 +80,13 @@ namespace UserInterface
ArtistCollector _artistCollector; ArtistCollector _artistCollector;
ReleaseCollector _releaseCollector; ReleaseCollector _releaseCollector;
TrackCollector _trackCollector; TrackCollector _trackCollector;
Wt::WStackedWidget* _stack{};
Wt::WWidget* _currentActiveItem {};
InfiniteScrollingContainer* _artists{};
InfiniteScrollingContainer* _releases{};
InfiniteScrollingContainer* _tracks{};
InfiniteScrollingContainer* _artists {}; Wt::WComboBox* _artistLinkType{};
InfiniteScrollingContainer* _releases {};
InfiniteScrollingContainer* _tracks {};
Wt::WComboBox* _artistLinkType {};
std::vector<InfiniteScrollingContainer*> _results;
}; };
} // namespace UserInterface } // namespace UserInterface