Removed the dedicated search view, as it is actually too limiting. Added a search field in the album/artists/tracks views. This makes search now work together with sort mode

This commit is contained in:
emeric
2024-05-01 15:21:48 +02:00
parent 971b6d9d08
commit dd5dfaa96e
29 changed files with 132 additions and 418 deletions
+30 -2
View File
@@ -32,9 +32,8 @@ namespace lms::db
Wt::Dbo::Query<ArtistId> createArtistsQuery(Session& session, const Listen::ArtistStatsFindParameters& params)
{
auto query{ session.getDboSession()->query<ArtistId>("SELECT a.id from artist a")
.join("track t ON t.id = t_a_l.track_id")
.join("track_artist_link t_a_l ON t_a_l.artist_id = a.id")
.join("listen l ON l.track_id = t.id") };
.join("listen l ON l.track_id = t_a_l.track_id") };
if (params.user.isValid())
query.where("l.user_id = ?").bind(params.user);
@@ -45,7 +44,10 @@ namespace lms::db
assert(!params.artist.isValid()); // poor check
if (params.library.isValid())
{
query.join("track t ON t.id = t_a_l.track_id");
query.where("t.media_library_id = ?").bind(params.library);
}
if (params.linkType)
query.where("t_a_l.type = ?").bind(*params.linkType);
@@ -69,6 +71,26 @@ namespace lms::db
query.where(oss.str());
}
if (!params.keywords.empty())
{
std::vector<std::string> clauses;
std::vector<std::string> sortClauses;
for (const std::string_view keyword : params.keywords)
{
clauses.push_back("a.name LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'");
query.bind("%" + utils::escapeLikeKeyword(keyword) + "%");
}
for (const std::string_view keyword : params.keywords)
{
sortClauses.push_back("a.sort_name LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'");
query.bind("%" + utils::escapeLikeKeyword(keyword) + "%");
}
query.where("(" + core::stringUtils::joinStrings(clauses, " AND ") + ") OR (" + core::stringUtils::joinStrings(sortClauses, " AND ") + ")");
}
return query;
}
@@ -114,6 +136,9 @@ namespace lms::db
query.where(oss.str());
}
for (std::string_view keyword : params.keywords)
query.where("r.name LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind("%" + utils::escapeLikeKeyword(keyword) + "%");
return query;
}
@@ -157,6 +182,9 @@ namespace lms::db
query.where(oss.str());
}
for (std::string_view keyword : params.keywords)
query.where("t.name LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind("%" + utils::escapeLikeKeyword(keyword) + "%");
return query;
}
}
@@ -70,6 +70,7 @@ namespace lms::db
UserId user;
std::optional<ScrobblingBackend> backend;
std::vector<ClusterId> clusters; // if non empty, entities that belong to these clusters
std::vector<std::string_view> keywords; // if non empty, name must match all of these keywords
std::optional<Range> range;
ArtistId artist; // if set, matching this artist
MediaLibraryId library;
@@ -77,6 +78,7 @@ namespace lms::db
StatsFindParameters& setUser(UserId _user) { user = _user; return *this; }
StatsFindParameters& setScrobblingBackend(std::optional<ScrobblingBackend> _backend) { backend = _backend; return *this; }
StatsFindParameters& setClusters(const std::vector<ClusterId>& _clusters) { clusters = _clusters; return *this; }
StatsFindParameters& setKeywords(const std::vector<std::string_view>& _keywords) { keywords = _keywords; return *this; }
StatsFindParameters& setRange(std::optional<Range> _range) { range = _range; return *this; }
StatsFindParameters& setArtist(ArtistId _artist) { artist = _artist; return *this; }
StatsFindParameters& setMediaLibrary(MediaLibraryId _library) { library = _library; return *this; }
@@ -92,8 +92,8 @@ namespace lms::db
UserId starringUser; // only releases starred by this user
std::optional<FeedbackBackend> feedbackBackend; // and for this backend
ArtistId artist; // only releases that involved this user
core::EnumSet<TrackArtistLinkType> trackArtistLinkTypes; // and for these link types
core::EnumSet<TrackArtistLinkType> excludedTrackArtistLinkTypes; // but not for these link types
core::EnumSet<TrackArtistLinkType> trackArtistLinkTypes; // and for these link types
core::EnumSet<TrackArtistLinkType> excludedTrackArtistLinkTypes; // but not for these link types
std::string releaseType; // If set, albums that has this release type
MediaLibraryId mediaLibrary; // If set, releases that has at least a track in this library
@@ -96,6 +96,7 @@ namespace lms::feedback
Artist::FindParameters searchParams;
searchParams.setStarringUser(params.user, *backend);
searchParams.setClusters(params.clusters);
searchParams.setKeywords(params.keywords);
searchParams.setLinkType(params.linkType);
searchParams.setSortMethod(params.sortMethod);
searchParams.setRange(params.range);
@@ -136,6 +137,7 @@ namespace lms::feedback
Release::FindParameters searchParams;
searchParams.setStarringUser(params.user, *backend);
searchParams.setClusters(params.clusters);
searchParams.setKeywords(params.keywords);
searchParams.setSortMethod(ReleaseSortMethod::StarredDateDesc);
searchParams.setRange(params.range);
searchParams.setMediaLibrary(params.library);
@@ -175,6 +177,7 @@ namespace lms::feedback
Track::FindParameters searchParams;
searchParams.setStarringUser(params.user, *backend);
searchParams.setClusters(params.clusters);
searchParams.setKeywords(params.keywords);
searchParams.setSortMethod(TrackSortMethod::StarredDateDesc);
searchParams.setRange(params.range);
searchParams.setMediaLibrary(params.library);
@@ -54,11 +54,13 @@ namespace lms::feedback
{
db::UserId user;
std::vector<db::ClusterId> clusters; // if non empty, at least one artist that belongs to these clusters
std::vector<std::string_view> keywords; // if non empty, name must match all of these keywords
std::optional<db::Range> range;
db::MediaLibraryId library;
FindParameters& setUser(const db::UserId _user) { user = _user; return *this; }
FindParameters& setClusters(std::span<const db::ClusterId> _clusters) { clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); return *this; }
FindParameters& setKeywords(const std::vector<std::string_view>& _keywords) { keywords = _keywords; return *this; }
FindParameters& setRange(std::optional<db::Range> _range) { range = _range; return *this; }
FindParameters& setMediaLibrary(db::MediaLibraryId _library) { library = _library; return *this; }
};
@@ -42,6 +42,7 @@ namespace lms::scrobbling
db::Listen::StatsFindParameters listenFindParams;
listenFindParams.setUser(params.user);
listenFindParams.setClusters(params.clusters);
listenFindParams.setKeywords(params.keywords);
listenFindParams.setRange(params.range);
listenFindParams.setMediaLibrary(params.library);
listenFindParams.setArtist(params.artist);
@@ -59,14 +59,16 @@ namespace lms::scrobbling
struct FindParameters
{
db::UserId user;
std::vector<db::ClusterId> clusters; // if non empty, at least one artist that belongs to these clusters
std::optional<db::Range> range;
db::MediaLibraryId library; // if set, match this library
db::ArtistId artist; // if set, match this artist
db::UserId user;
std::vector<db::ClusterId> clusters; // if non empty, at least one artist that belongs to these clusters
std::vector<std::string_view> keywords; // if non empty, name must match all of these keywords
std::optional<db::Range> range;
db::MediaLibraryId library; // if set, match this library
db::ArtistId artist; // if set, match this artist
FindParameters& setUser(const db::UserId _user) { user = _user; return *this; }
FindParameters& setClusters(std::span<const db::ClusterId> _clusters) { clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); return *this; }
FindParameters& setKeywords(const std::vector<std::string_view>& _keywords) { keywords = _keywords; return *this; }
FindParameters& setRange(std::optional<db::Range> _range) { range = _range; return *this; }
FindParameters& setMediaLibrary(db::MediaLibraryId _library) { library = _library; return *this; }
FindParameters& setArtist(db::ArtistId _artist) { artist = _artist; return *this; }
-1
View File
@@ -42,7 +42,6 @@ add_executable(lms
ui/explore/ReleasesView.cpp
ui/explore/ReleaseView.cpp
ui/explore/ReleaseTypes.cpp
ui/explore/SearchView.cpp
ui/explore/SortModeSelector.cpp
ui/explore/TrackArtistLinkTypeSelector.cpp
ui/explore/TrackCollector.cpp
-16
View File
@@ -97,7 +97,6 @@ namespace lms::ui
res->use(appRoot + "playqueue");
res->use(appRoot + "release");
res->use(appRoot + "releases");
res->use(appRoot + "search");
res->use(appRoot + "settings");
res->use(appRoot + "tracklist");
res->use(appRoot + "tracklists");
@@ -139,7 +138,6 @@ namespace lms::ui
{ "/artist", IdxExplore, false, std::nullopt },
{ "/releases", IdxExplore, false, Wt::WString::tr("Lms.Explore.releases") },
{ "/release", IdxExplore, false, std::nullopt },
{ "/search", IdxExplore, false, Wt::WString::tr("Lms.Explore.search") },
{ "/tracks", IdxExplore, false, Wt::WString::tr("Lms.Explore.tracks") },
{ "/tracklists", IdxExplore, false, Wt::WString::tr("Lms.Explore.tracklists") },
{ "/tracklist", IdxExplore, false, std::nullopt },
@@ -435,9 +433,6 @@ namespace lms::ui
logout->clicked().connect(this, &LmsApplication::logoutUser);
}
Wt::WLineEdit* searchEdit{ navbar->bindNew<Wt::WLineEdit>("search") };
searchEdit->setPlaceholderText(Wt::WString::tr("Lms.Explore.Search.search-placeholder"));
if (LmsApp->getUserType() == db::UserType::ADMIN)
{
navbar->setCondition("if-is-admin", true);
@@ -462,17 +457,6 @@ namespace lms::ui
_playQueue = mainStack->addWidget(std::move(playQueue));
mainStack->addNew<SettingsView>();
searchEdit->enterPressed().connect([this]
{
setInternalPath("/search", true);
});
searchEdit->textInput().connect([this, explore, searchEdit]
{
setInternalPath("/search", true);
explore->search(searchEdit->text());
});
// Admin stuff
if (getUserType() == db::UserType::ADMIN)
{
+6 -16
View File
@@ -54,6 +54,7 @@ namespace lms::ui
feedback::IFeedbackService::ArtistFindParameters params;
params.setUser(LmsApp->getUserId());
params.setClusters(filters.getClusters());
params.setKeywords(getSearchKeywords());
params.setMediaLibrary(filters.getMediaLibrary());
params.setLinkType(_linkType);
params.setSortMethod(ArtistSortMethod::StarredDateDesc);
@@ -67,6 +68,7 @@ namespace lms::ui
scrobbling::IScrobblingService::ArtistFindParameters params;
params.setUser(LmsApp->getUserId());
params.setClusters(filters.getClusters());
params.setKeywords(getSearchKeywords());
params.setMediaLibrary(filters.getMediaLibrary());
params.setLinkType(_linkType);
params.setRange(range);
@@ -80,6 +82,7 @@ namespace lms::ui
scrobbling::IScrobblingService::ArtistFindParameters params;
params.setUser(LmsApp->getUserId());
params.setClusters(filters.getClusters());
params.setKeywords(getSearchKeywords());
params.setMediaLibrary(filters.getMediaLibrary());
params.setLinkType(_linkType);
params.setRange(range);
@@ -92,6 +95,7 @@ namespace lms::ui
{
Artist::FindParameters params;
params.setClusters(filters.getClusters());
params.setKeywords(getSearchKeywords());
params.setMediaLibrary(filters.getMediaLibrary());
params.setLinkType(_linkType);
params.setSortMethod(ArtistSortMethod::LastWritten);
@@ -104,27 +108,12 @@ namespace lms::ui
break;
}
case Mode::Search:
{
Artist::FindParameters params;
params.setClusters(filters.getClusters());
params.setMediaLibrary(filters.getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setLinkType(_linkType);
params.setRange(range);
{
auto transaction{ LmsApp->getDbSession().createReadTransaction() };
artists = Artist::findIds(LmsApp->getDbSession(), params);
}
break;
}
case Mode::All:
{
Artist::FindParameters params;
params.setClusters(filters.getClusters());
params.setMediaLibrary(filters.getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setLinkType(_linkType);
params.setSortMethod(ArtistSortMethod::SortName);
params.setRange(range);
@@ -152,6 +141,7 @@ namespace lms::ui
Artist::FindParameters params;
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setLinkType(_linkType);
params.setSortMethod(ArtistSortMethod::Random);
params.setRange(Range{ 0, getMaxCount() });
+15 -1
View File
@@ -38,10 +38,18 @@ namespace lms::ui
using namespace db;
Artists::Artists(Filters& filters)
: Wt::WTemplate{ Wt::WString::tr("Lms.Explore.Artists.template") }
: Template{ Wt::WString::tr("Lms.Explore.Artists.template") }
, _artistCollector{ filters, _defaultSortMode, _maxCount }
{
addFunction("tr", &Wt::WTemplate::Functions::tr);
addFunction("id", &Wt::WTemplate::Functions::id);
Wt::WLineEdit* searEdit{ bindNew<Wt::WLineEdit>("search") };
searEdit->setPlaceholderText(Wt::WString::tr("Lms.Explore.Search.search-placeholder"));
searEdit->textInput().connect([this, searEdit]
{
refreshView(searEdit->text());
});
SortModeSelector* sortModeSelector{ bindNew<SortModeSelector>("sort-mode", _defaultSortMode) };
sortModeSelector->sortModeChanged.connect([this](ArtistCollector::Mode sortMode)
@@ -87,6 +95,12 @@ namespace lms::ui
refreshView();
}
void Artists::refreshView(const Wt::WString& searchText)
{
_artistCollector.setSearch(searchText.toUTF8());
refreshView();
}
void Artists::addSome()
{
const auto artistIds{ _artistCollector.get(Range {static_cast<std::size_t>(_container->getCount()), _batchSize}) };
+3 -1
View File
@@ -26,6 +26,7 @@
#include <Wt/WTemplate.h>
#include "database/Types.hpp"
#include "common/Template.hpp"
#include "ArtistCollector.hpp"
namespace lms::ui
@@ -33,7 +34,7 @@ namespace lms::ui
class Filters;
class InfiniteScrollingContainer;
class Artists : public Wt::WTemplate
class Artists : public Template
{
public:
Artists(Filters& filters);
@@ -42,6 +43,7 @@ namespace lms::ui
void refreshView();
void refreshView(ArtistCollector::Mode mode);
void refreshView(std::optional<db::TrackArtistLinkType> linkType);
void refreshView(const Wt::WString& searchText);
void addSome();
static constexpr std::size_t _batchSize{ 30 };
+4 -1
View File
@@ -59,7 +59,10 @@ namespace lms::ui
void DatabaseCollectorBase::setSearch(std::string_view searchText)
{
_searchText = searchText;
_searchKeywords = core::stringUtils::splitString(_searchText, ' ');
if (!searchText.empty())
_searchKeywords = core::stringUtils::splitString(_searchText, ' ');
else
_searchKeywords.clear();
}
} // ns UserInterface
@@ -45,7 +45,6 @@ namespace lms::ui
RecentlyPlayed,
RecentlyAdded,
MostPlayed,
Search,
All
};
-12
View File
@@ -27,7 +27,6 @@
#include "Filters.hpp"
#include "ReleasesView.hpp"
#include "ReleaseView.hpp"
#include "SearchView.hpp"
#include "TrackListView.hpp"
#include "TrackListsView.hpp"
#include "TracksView.hpp"
@@ -46,7 +45,6 @@ namespace lms::ui
IdxTrackList,
IdxReleases,
IdxRelease,
IdxSearch,
IdxTracks,
};
@@ -58,7 +56,6 @@ namespace lms::ui
{ "/tracklist", IdxTrackList },
{ "/releases", IdxReleases },
{ "/release", IdxRelease },
{ "/search", IdxSearch },
{ "/tracks", IdxTracks },
};
@@ -103,10 +100,6 @@ namespace lms::ui
auto release = std::make_unique<Release>(filters, _playQueueController);
contentsStack->addWidget(std::move(release));
auto search = std::make_unique<SearchView>(filters, _playQueueController);
_search = search.get();
contentsStack->addWidget(std::move(search));
auto tracks = std::make_unique<Tracks>(filters, _playQueueController);
contentsStack->addWidget(std::move(tracks));
@@ -117,9 +110,4 @@ namespace lms::ui
handleContentsPathChange(contentsStack);
}
void Explore::search(const Wt::WString& searchText)
{
_search->refreshView(searchText);
}
} // namespace lms::ui
-1
View File
@@ -34,7 +34,6 @@ namespace lms::ui
public:
Explore(Filters& filters, PlayQueue& playQueue);
void search(const Wt::WString& searchText);
PlayQueueController& getPlayQueueController() { return _playQueueController; }
private:
+6 -15
View File
@@ -53,6 +53,7 @@ namespace lms::ui
params.setUser(LmsApp->getUserId());
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setRange(range);
releases = feedbackService.findStarredReleases(params);
break;
@@ -64,6 +65,7 @@ namespace lms::ui
params.setUser(LmsApp->getUserId());
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setRange(range);
releases = scrobblingService.getRecentReleases(params);
@@ -76,6 +78,7 @@ namespace lms::ui
params.setUser(LmsApp->getUserId());
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setRange(range);
releases = scrobblingService.getTopReleases(params);
@@ -83,26 +86,12 @@ namespace lms::ui
}
case Mode::RecentlyAdded:
{
Release::FindParameters params;
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setSortMethod(ReleaseSortMethod::LastWritten);
params.setRange(range);
{
auto transaction{ LmsApp->getDbSession().createReadTransaction() };
releases = Release::findIds(LmsApp->getDbSession(), params);
}
break;
}
case Mode::Search:
{
Release::FindParameters params;
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setSortMethod(ReleaseSortMethod::LastWritten);
params.setRange(range);
{
@@ -118,6 +107,7 @@ namespace lms::ui
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setSortMethod(ReleaseSortMethod::Name);
params.setKeywords(getSearchKeywords());
params.setRange(range);
{
@@ -143,6 +133,7 @@ namespace lms::ui
Release::FindParameters params;
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setSortMethod(ReleaseSortMethod::Random);
params.setRange(Range{ 0, getMaxCount() });
+14
View File
@@ -19,6 +19,7 @@
#include "ReleasesView.hpp"
#include <Wt/WLineEdit.h>
#include <Wt/WPushButton.h>
#include "database/Release.hpp"
@@ -44,6 +45,13 @@ namespace lms::ui
addFunction("tr", &Wt::WTemplate::Functions::tr);
addFunction("id", &Wt::WTemplate::Functions::id);
Wt::WLineEdit* searEdit{ bindNew<Wt::WLineEdit>("search") };
searEdit->setPlaceholderText(Wt::WString::tr("Lms.Explore.Search.search-placeholder"));
searEdit->textInput().connect([this, searEdit]
{
refreshView(searEdit->text());
});
SortModeSelector* sortMode{ bindNew<SortModeSelector>("sort-mode", _defaultMode) };
sortMode->sortModeChanged.connect([this](ReleaseCollector::Mode sortMode)
{
@@ -98,6 +106,12 @@ namespace lms::ui
refreshView();
}
void Releases::refreshView(const Wt::WString& searchText)
{
_releaseCollector.setSearch(searchText.toUTF8());
refreshView();
}
void Releases::addSome()
{
const auto releaseIds{ _releaseCollector.get(Range {static_cast<std::size_t>(_container->getCount()), _batchSize}) };
+1
View File
@@ -38,6 +38,7 @@ namespace lms::ui
private:
void refreshView();
void refreshView(ReleaseCollector::Mode mode);
void refreshView(const Wt::WString& searchText);
void addSome();
std::vector<db::ReleaseId> getAllReleases();
-200
View File
@@ -1,200 +0,0 @@
/*
* Copyright (C) 2020 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SearchView.hpp"
#include <Wt/WPushButton.h>
#include "database/Artist.hpp"
#include "database/Release.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "common/InfiniteScrollingContainer.hpp"
#include "ArtistListHelpers.hpp"
#include "Filters.hpp"
#include "LmsApplication.hpp"
#include "ReleaseHelpers.hpp"
#include "TrackArtistLinkTypeSelector.hpp"
#include "TrackListHelpers.hpp"
namespace lms::ui
{
using namespace db;
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);
_stack = bindNew<Wt::WStackedWidget>("results");
_stack->setOverflow(Wt::Overflow::Visible); // wt makes it hidden by default
// 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")) };
TrackArtistLinkTypeSelector* linkTypeSelector{ artistResults->bindNew<TrackArtistLinkTypeSelector>("link-type", std::nullopt)};
linkTypeSelector->linkTypeChanged.connect([this](std::optional<TrackArtistLinkType> linkType)
{
refreshView(linkType);
});
_artists = artistResults->bindNew<InfiniteScrollingContainer>("artists", Wt::WString::tr("Lms.Explore.Artists.template.container"));
_artists->onRequestElements.connect([this] { addSomeArtists(); });
}
// Tracks
_tracks = _stack->addNew<InfiniteScrollingContainer>();
_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([this, menuItem, index]
{
_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([this]
{
refreshView();
});
}
std::size_t SearchView::getBatchSize(Mode mode) const
{
auto it{ _batchSizes.find(mode) };
assert(it != _batchSizes.cend());
return it->second;
}
std::size_t SearchView::getMaxCount(Mode mode) const
{
auto it{ _maxCounts.find(mode) };
assert(it != _maxCounts.cend());
return it->second;
}
void SearchView::refreshView(std::optional<TrackArtistLinkType> linkType)
{
_artistCollector.setArtistLinkType(linkType);
refreshView();
}
void SearchView::refreshView(const Wt::WString& searchText)
{
_releaseCollector.setSearch(searchText.toUTF8());
_artistCollector.setSearch(searchText.toUTF8());
_trackCollector.setSearch(searchText.toUTF8());
refreshView();
}
void SearchView::refreshView()
{
_artists->reset();
_releases->reset();
_tracks->reset();
}
void SearchView::addSomeArtists()
{
using namespace db;
const Range range{ _artists->getCount(), getBatchSize(Mode::Artist) };
const RangeResults<ArtistId> artistIds{ _artistCollector.get(range) };
{
auto transaction{ LmsApp->getDbSession().createReadTransaction() };
for (const ArtistId artistId : artistIds.results)
{
const Artist::pointer artist{ Artist::find(LmsApp->getDbSession(), artistId) };
if (artist)
_artists->add(ArtistListHelpers::createEntry(artist));
}
}
_artists->setHasMore(artistIds.moreResults);
}
void SearchView::addSomeReleases()
{
using namespace db;
const Range range{ _releases->getCount(), getBatchSize(Mode::Release) };
const RangeResults<ReleaseId> releaseIds{ _releaseCollector.get(range) };
{
auto transaction{ LmsApp->getDbSession().createReadTransaction() };
for (const ReleaseId releaseId : releaseIds.results)
{
const Release::pointer release{ Release::find(LmsApp->getDbSession(), releaseId) };
if (release)
_releases->add(releaseListHelpers::createEntry(release));
}
}
_releases->setHasMore(releaseIds.moreResults);
}
void SearchView::addSomeTracks()
{
using namespace db;
const Range range{ _tracks->getCount(), getBatchSize(Mode::Track) };
const RangeResults<TrackId> trackIds{ _trackCollector.get(range) };
{
auto transaction{ LmsApp->getDbSession().createReadTransaction() };
for (const TrackId trackId : trackIds.results)
{
const Track::pointer track{ Track::find(LmsApp->getDbSession(), trackId) };
if (track)
_tracks->add(TrackListHelpers::createEntry(track, _playQueueController, _filters));
}
}
_tracks->setHasMore(trackIds.moreResults);
}
}
-91
View File
@@ -1,91 +0,0 @@
/*
* Copyright (C) 2020 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <optional>
#include <unordered_map>
#include <Wt/WComboBox.h>
#include <Wt/WStackedWidget.h>
#include <Wt/WTemplate.h>
#include "database/Types.hpp"
#include "ArtistCollector.hpp"
#include "ReleaseCollector.hpp"
#include "TrackCollector.hpp"
namespace lms::ui
{
class InfiniteScrollingContainer;
class Filters;
class PlayQueueController;
class SearchView : public Wt::WTemplate
{
public:
SearchView(Filters& filters, PlayQueueController& playQueueController);
void refreshView(const Wt::WString& searchText);
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;
void refreshView();
void refreshView(std::optional<db::TrackArtistLinkType> linkType);
void addSomeArtists();
void addSomeReleases();
void addSomeTracks();
PlayQueueController& _playQueueController;
Filters& _filters;
ArtistCollector _artistCollector;
ReleaseCollector _releaseCollector;
TrackCollector _trackCollector;
Wt::WStackedWidget* _stack{};
Wt::WWidget* _currentActiveItem {};
InfiniteScrollingContainer* _artists{};
InfiniteScrollingContainer* _releases{};
InfiniteScrollingContainer* _tracks{};
};
} // namespace lms::ui
+6 -15
View File
@@ -55,6 +55,7 @@ namespace lms::ui
feedback::IFeedbackService::FindParameters params;
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setRange(range);
params.setUser(LmsApp->getUserId());
tracks = feedbackService.findStarredTracks(params);
@@ -67,6 +68,7 @@ namespace lms::ui
params.setUser(LmsApp->getUserId());
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setRange(range);
tracks = scrobblingService.getRecentTracks(params);
@@ -79,6 +81,7 @@ namespace lms::ui
params.setUser(LmsApp->getUserId());
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setRange(range);
tracks = scrobblingService.getTopTracks(params);
@@ -86,26 +89,12 @@ namespace lms::ui
}
case Mode::RecentlyAdded:
{
Track::FindParameters params;
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setSortMethod(TrackSortMethod::LastWritten);
params.setRange(range);
{
auto transaction{ LmsApp->getDbSession().createReadTransaction() };
tracks = Track::findIds(LmsApp->getDbSession(), params);
}
break;
}
case Mode::Search:
{
Track::FindParameters params;
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setSortMethod(TrackSortMethod::LastWritten);
params.setRange(range);
{
@@ -120,6 +109,7 @@ namespace lms::ui
Track::FindParameters params;
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setRange(range);
{
@@ -145,6 +135,7 @@ namespace lms::ui
Track::FindParameters params;
params.setClusters(getFilters().getClusters());
params.setMediaLibrary(getFilters().getMediaLibrary());
params.setKeywords(getSearchKeywords());
params.setSortMethod(TrackSortMethod::Random);
params.setRange(Range{ 0, getMaxCount() });
+14
View File
@@ -19,6 +19,7 @@
#include "TracksView.hpp"
#include <Wt/WLineEdit.h>
#include <Wt/WPushButton.h>
#include "database/Session.hpp"
@@ -45,6 +46,13 @@ namespace lms::ui
addFunction("tr", &Wt::WTemplate::Functions::tr);
addFunction("id", &Wt::WTemplate::Functions::id);
Wt::WLineEdit* searEdit{ bindNew<Wt::WLineEdit>("search") };
searEdit->setPlaceholderText(Wt::WString::tr("Lms.Explore.Search.search-placeholder"));
searEdit->textInput().connect([this, searEdit]
{
refreshView(searEdit->text());
});
SortModeSelector* sortMode{ bindNew<SortModeSelector>("sort-mode", _defaultMode) };
sortMode->sortModeChanged.connect([this](TrackCollector::Mode mode)
{
@@ -99,6 +107,12 @@ namespace lms::ui
refreshView();
}
void Tracks::refreshView(const Wt::WString& searchText)
{
_trackCollector.setSearch(searchText.toUTF8());
refreshView();
}
void Tracks::addSome()
{
auto transaction{ LmsApp->getDbSession().createReadTransaction() };
+1
View File
@@ -38,6 +38,7 @@ namespace lms::ui
private:
void refreshView();
void refreshView(TrackCollector::Mode mode);
void refreshView(const Wt::WString& searchText);
void addSome();
std::vector<db::TrackId> getAllTracks();