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
+137 -115
View File
@@ -19,6 +19,8 @@
#include "SearchView.hpp"
#include <Wt/WPushButton.h>
#include "services/database/Artist.hpp"
#include "services/database/Release.hpp"
#include "services/database/Session.hpp"
@@ -35,142 +37,162 @@ using namespace Database;
namespace UserInterface
{
SearchView::SearchView(Filters& filters, PlayQueueController& playQueueController)
: Wt::WTemplate {Wt::WString::tr("Lms.Explore.Search.template")}
, _playQueueController {playQueueController}
, _filters {filters}
, _artistCollector {filters, ArtistCollector::Mode::Search, getMaxCount(Mode::Artist)}
, _releaseCollector {filters, ReleaseCollector::Mode::Search, getMaxCount(Mode::Release)}
, _trackCollector {filters, TrackCollector::Mode::Search, getMaxCount(Mode::Track)}
{
addFunction("tr", &Wt::WTemplate::Functions::tr);
SearchView::SearchView(Filters& filters, PlayQueueController& playQueueController)
: Wt::WTemplate{ Wt::WString::tr("Lms.Explore.Search.template") }
, _playQueueController{ playQueueController }
, _filters{ filters }
, _artistCollector{ filters, ArtistCollector::Mode::Search, getMaxCount(Mode::Artist) }
, _releaseCollector{ filters, ReleaseCollector::Mode::Search, getMaxCount(Mode::Release) }
, _trackCollector{ filters, TrackCollector::Mode::Search, getMaxCount(Mode::Track) }
{
addFunction("tr", &Wt::WTemplate::Functions::tr);
_artists = bindNew<InfiniteScrollingContainer>("artists", Wt::WString::tr("Lms.Explore.Artists.template.container"));
_artists->onRequestElements.connect([this] { addSomeArtists(); });
_stack = bindNew<Wt::WStackedWidget>("results");
_artistLinkType = bindNew<Wt::WComboBox>("link-type");
_artistLinkType->setModel(ArtistListHelpers::createArtistLinkTypesModel());
_artistLinkType->changed().connect([this]
{
const std::optional<TrackArtistLinkType> linkType {static_cast<ArtistLinkTypesModel*>(_artistLinkType->model().get())->getValue(_artistLinkType->currentIndex())};
refreshView(linkType);
});
// releases
_releases = _stack->addNew<InfiniteScrollingContainer>(Wt::WString::tr("Lms.Explore.Releases.template.container"));
_releases->onRequestElements.connect([this] { addSomeReleases(); });
_releases = bindNew<InfiniteScrollingContainer>("releases", 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")) };
_tracks = bindNew<InfiniteScrollingContainer>("tracks");
_tracks->onRequestElements.connect([this] { addSomeTracks(); });
_artistLinkType = artistResults->bindNew<Wt::WComboBox>("link-type");
_artistLinkType->setModel(ArtistListHelpers::createArtistLinkTypesModel());
_artistLinkType->changed().connect([this]
{
const std::optional<TrackArtistLinkType> linkType{ static_cast<ArtistLinkTypesModel*>(_artistLinkType->model().get())->getValue(_artistLinkType->currentIndex()) };
refreshView(linkType);
});
filters.updated().connect([=]
{
refreshView();
});
_artists = artistResults->bindNew<InfiniteScrollingContainer>("artists", Wt::WString::tr("Lms.Explore.Artists.template.container"));
_artists->onRequestElements.connect([this] { addSomeArtists(); });
}
LmsApp->getScannerEvents().scanComplete.connect(this, [this](const Scanner::ScanStats& stats)
{
if (stats.nbChanges())
_artistLinkType->setModel(ArtistListHelpers::createArtistLinkTypesModel());
});
}
// Tracks
_tracks = _stack->addNew<InfiniteScrollingContainer>();
_tracks->onRequestElements.connect([this] { addSomeTracks(); });
std::size_t
SearchView::getBatchSize(Mode mode) const
{
auto it {_batchSizes.find(mode)};
assert(it != _batchSizes.cend());
return it->second;
}
// 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;
});
std::size_t
SearchView::getMaxCount(Mode mode) const
{
auto it {_maxCounts.find(mode)};
assert(it != _maxCounts.cend());
return it->second;
}
if (index == 0)
{
_currentActiveItem = menuItem;
_currentActiveItem->addStyleClass("active");
}
} };
void
SearchView::refreshView(std::optional<TrackArtistLinkType> linkType)
{
_artistCollector.setArtistLinkType(linkType);
refreshView();
}
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"));
void
SearchView::refreshView(const Wt::WString& searchText)
{
_releaseCollector.setSearch(searchText.toUTF8());
_artistCollector.setSearch(searchText.toUTF8());
_trackCollector.setSearch(searchText.toUTF8());
refreshView();
}
filters.updated().connect([=]
{
refreshView();
});
void
SearchView::refreshView()
{
_artists->reset();
_releases->reset();
_tracks->reset();
LmsApp->getScannerEvents().scanComplete.connect(this, [this](const Scanner::ScanStats& stats)
{
if (stats.nbChanges())
_artistLinkType->setModel(ArtistListHelpers::createArtistLinkTypesModel());
});
}
addSomeArtists();
addSomeReleases();
addSomeTracks();
}
std::size_t SearchView::getBatchSize(Mode mode) const
{
auto it{ _batchSizes.find(mode) };
assert(it != _batchSizes.cend());
return it->second;
}
void
SearchView::addSomeArtists()
{
using namespace Database;
std::size_t SearchView::getMaxCount(Mode mode) const
{
auto it{ _maxCounts.find(mode) };
assert(it != _maxCounts.cend());
return it->second;
}
const Range range {_artists->getCount(), getBatchSize(Mode::Artist)};
const RangeResults<ArtistId> artistIds {_artistCollector.get(range)};
{
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
void SearchView::refreshView(std::optional<TrackArtistLinkType> linkType)
{
_artistCollector.setArtistLinkType(linkType);
refreshView();
}
for (const ArtistId artistId : artistIds.results)
{
const Artist::pointer artist {Artist::find(LmsApp->getDbSession(), artistId)};
_artists->add(ArtistListHelpers::createEntry(artist));
}
}
}
void SearchView::refreshView(const Wt::WString& searchText)
{
_releaseCollector.setSearch(searchText.toUTF8());
_artistCollector.setSearch(searchText.toUTF8());
_trackCollector.setSearch(searchText.toUTF8());
refreshView();
}
void
SearchView::addSomeReleases()
{
using namespace Database;
void SearchView::refreshView()
{
_artists->reset();
_releases->reset();
_tracks->reset();
}
const Range range {_releases->getCount(), getBatchSize(Mode::Release)};
const RangeResults<ReleaseId> releaseIds {_releaseCollector.get(range)};
{
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
void SearchView::addSomeArtists()
{
using namespace Database;
for (const ReleaseId releaseId : releaseIds.results)
{
const Release::pointer release {Release::find(LmsApp->getDbSession(), releaseId)};
_releases->add(ReleaseListHelpers::createEntry(release));
}
}
}
const Range range{ _artists->getCount(), getBatchSize(Mode::Artist) };
const RangeResults<ArtistId> artistIds{ _artistCollector.get(range) };
{
auto transaction{ LmsApp->getDbSession().createSharedTransaction() };
void
SearchView::addSomeTracks()
{
using namespace Database;
for (const ArtistId artistId : artistIds.results)
{
const Artist::pointer artist{ Artist::find(LmsApp->getDbSession(), artistId) };
_artists->add(ArtistListHelpers::createEntry(artist));
}
}
}
const Range range {_tracks->getCount(), getBatchSize(Mode::Track)};
const RangeResults<TrackId> trackIds {_trackCollector.get(range)};
void SearchView::addSomeReleases()
{
using namespace Database;
{
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
const Range range{ _releases->getCount(), getBatchSize(Mode::Release) };
const RangeResults<ReleaseId> releaseIds{ _releaseCollector.get(range) };
{
auto transaction{ LmsApp->getDbSession().createSharedTransaction() };
for (const TrackId trackId : trackIds.results)
{
const Track::pointer track {Track::find(LmsApp->getDbSession(), trackId)};
_tracks->add(TrackListHelpers::createEntry(track, _playQueueController, _filters));
}
}
}
for (const ReleaseId releaseId : releaseIds.results)
{
const Release::pointer release{ Release::find(LmsApp->getDbSession(), releaseId) };
_releases->add(ReleaseListHelpers::createEntry(release));
}
}
}
void SearchView::addSomeTracks()
{
using namespace Database;
const Range range{ _tracks->getCount(), getBatchSize(Mode::Track) };
const RangeResults<TrackId> trackIds{ _trackCollector.get(range) };
{
auto transaction{ LmsApp->getDbSession().createSharedTransaction() };
for (const TrackId trackId : trackIds.results)
{
const Track::pointer track{ Track::find(LmsApp->getDbSession(), trackId) };
_tracks->add(TrackListHelpers::createEntry(track, _playQueueController, _filters));
}
}
}
} // namespace UserInterface
+48 -49
View File
@@ -33,62 +33,61 @@
namespace UserInterface
{
class InfiniteScrollingContainer;
class Filters;
class PlayQueueController;
class InfiniteScrollingContainer;
class Filters;
class PlayQueueController;
class SearchView : public Wt::WTemplate
{
public:
SearchView(Filters& filters, PlayQueueController& playQueueController);
class SearchView : public Wt::WTemplate
{
public:
SearchView(Filters& filters, PlayQueueController& playQueueController);
void refreshView(const Wt::WString& searchText);
void refreshView(const Wt::WString& searchText);
private:
// same order as in the menu
enum class Mode
{
Artist,
Release,
Track,
};
private:
// same order as in the menu
enum class Mode
{
Artist,
Release,
Track,
};
static constexpr Mode _defaultMode {Mode::Release};
static inline std::unordered_map<Mode, std::size_t> _batchSizes
{
{Mode::Artist, 6},
{Mode::Release, 6},
{Mode::Track, 6},
};
static inline std::unordered_map<Mode, std::size_t> _maxCounts
{
{Mode::Artist, 1000},
{Mode::Release, 504},
{Mode::Track, 500},
};
std::size_t getBatchSize(Mode mode) const;
std::size_t getMaxCount(Mode mode) const;
static constexpr Mode _defaultMode{ Mode::Release };
static inline std::unordered_map<Mode, std::size_t> _batchSizes
{
{Mode::Artist, 6},
{Mode::Release, 6},
{Mode::Track, 6},
};
static inline std::unordered_map<Mode, std::size_t> _maxCounts
{
{Mode::Artist, 1000},
{Mode::Release, 504},
{Mode::Track, 500},
};
std::size_t getBatchSize(Mode mode) const;
std::size_t getMaxCount(Mode mode) const;
void refreshView();
void refreshView(std::optional<Database::TrackArtistLinkType> linkType);
void addSomeArtists();
void addSomeReleases();
void addSomeTracks();
void refreshView();
void refreshView(std::optional<Database::TrackArtistLinkType> linkType);
void addSomeArtists();
void addSomeReleases();
void addSomeTracks();
PlayQueueController& _playQueueController;
Filters& _filters;
ArtistCollector _artistCollector;
ReleaseCollector _releaseCollector;
TrackCollector _trackCollector;
PlayQueueController& _playQueueController;
Filters& _filters;
ArtistCollector _artistCollector;
ReleaseCollector _releaseCollector;
TrackCollector _trackCollector;
Wt::WStackedWidget* _stack{};
Wt::WWidget* _currentActiveItem {};
InfiniteScrollingContainer* _artists{};
InfiniteScrollingContainer* _releases{};
InfiniteScrollingContainer* _tracks{};
InfiniteScrollingContainer* _artists {};
InfiniteScrollingContainer* _releases {};
InfiniteScrollingContainer* _tracks {};
Wt::WComboBox* _artistLinkType {};
std::vector<InfiniteScrollingContainer*> _results;
};
Wt::WComboBox* _artistLinkType{};
};
} // namespace UserInterface