Changed the add button to a contextual menu
This commit is contained in:
@@ -39,7 +39,6 @@ namespace Av
|
||||
static constexpr std::size_t _chunkSize {262144};
|
||||
const std::filesystem::path _trackPath;
|
||||
Transcoder _transcoder;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ add_executable(lms
|
||||
ui/explore/Explore.cpp
|
||||
ui/explore/Filters.cpp
|
||||
ui/explore/ReleaseListHelpers.cpp
|
||||
ui/explore/ReleasePopup.cpp
|
||||
ui/explore/ReleasesView.cpp
|
||||
ui/explore/ReleaseView.cpp
|
||||
ui/explore/SearchView.cpp
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include "database/User.hpp"
|
||||
#include "explore/Explore.hpp"
|
||||
#include "explore/Filters.hpp"
|
||||
#include "explore/SearchView.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Service.hpp"
|
||||
#include "utils/String.hpp"
|
||||
@@ -308,6 +307,13 @@ LmsApplication::createCluster(Database::Cluster::pointer cluster, bool canDelete
|
||||
return res;
|
||||
}
|
||||
|
||||
Wt::WPopupMenu*
|
||||
LmsApplication::createPopupMenu()
|
||||
{
|
||||
_popupMenu = std::make_unique<Wt::WPopupMenu>();
|
||||
return _popupMenu.get();
|
||||
}
|
||||
|
||||
void
|
||||
LmsApplication::handleException(LmsApplicationException& e)
|
||||
{
|
||||
@@ -334,7 +340,6 @@ enum IdxRoot
|
||||
{
|
||||
IdxExplore = 0,
|
||||
IdxPlayQueue,
|
||||
IdxSearch,
|
||||
IdxSettings,
|
||||
IdxAdminDatabase,
|
||||
IdxAdminUsers,
|
||||
@@ -355,9 +360,9 @@ handlePathChange(Wt::WStackedWidget* stack, bool isAdmin)
|
||||
{ "/artist", IdxExplore, false },
|
||||
{ "/releases", IdxExplore, false },
|
||||
{ "/release", IdxExplore, false },
|
||||
{ "/search", IdxExplore, false },
|
||||
{ "/tracks", IdxExplore, false },
|
||||
{ "/playqueue", IdxPlayQueue, false },
|
||||
{ "/search", IdxSearch, false },
|
||||
{ "/settings", IdxSettings, false },
|
||||
{ "/admin/database", IdxAdminDatabase, true },
|
||||
{ "/admin/users", IdxAdminUsers, true },
|
||||
@@ -471,7 +476,6 @@ LmsApplication::createHome()
|
||||
|
||||
Explore* explore = mainStack->addNew<Explore>(filters);
|
||||
_playQueue = mainStack->addNew<PlayQueue>();
|
||||
auto* search {mainStack->addNew<SearchView>(filters)};
|
||||
mainStack->addNew<SettingsView>();
|
||||
|
||||
searchEdit->enterPressed().connect([=]
|
||||
@@ -482,7 +486,7 @@ LmsApplication::createHome()
|
||||
searchEdit->textInput().connect([=]
|
||||
{
|
||||
setInternalPath("/search", true);
|
||||
search->refreshView(searchEdit->text().toUTF8());
|
||||
explore->search(searchEdit->text());
|
||||
});
|
||||
|
||||
// Admin stuff
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <optional>
|
||||
|
||||
#include <Wt/WApplication.h>
|
||||
#include <Wt/WPopupMenu.h>
|
||||
|
||||
#include "database/Db.hpp"
|
||||
#include "database/Session.hpp"
|
||||
@@ -101,6 +102,7 @@ class LmsApplication : public Wt::WApplication
|
||||
static Wt::WLink createReleaseLink(Wt::Dbo::ptr<Database::Release> release);
|
||||
static std::unique_ptr<Wt::WAnchor> createReleaseAnchor(Wt::Dbo::ptr<Database::Release> release, bool addText = true);
|
||||
static std::unique_ptr<Wt::WText> createCluster(Wt::Dbo::ptr<Database::Cluster> cluster, bool canDelete = false);
|
||||
Wt::WPopupMenu* createPopupMenu();
|
||||
|
||||
MediaPlayer& getMediaPlayer() const { return *_mediaPlayer; }
|
||||
PlayQueue& getPlayQueue() const { return *_playQueue; }
|
||||
@@ -124,17 +126,18 @@ class LmsApplication : public Wt::WApplication
|
||||
|
||||
void createHome();
|
||||
|
||||
Wt::Signal<> _preQuit;
|
||||
Database::Session _dbSession;
|
||||
LmsApplicationGroupContainer& _appGroups;
|
||||
Events _events;
|
||||
std::optional<Database::IdType> _userId;
|
||||
std::optional<bool> _userAuthStrong;
|
||||
Wt::Signal<> _preQuit;
|
||||
Database::Session _dbSession;
|
||||
LmsApplicationGroupContainer& _appGroups;
|
||||
Events _events;
|
||||
std::optional<Database::IdType> _userId;
|
||||
std::optional<bool> _userAuthStrong;
|
||||
std::shared_ptr<AudioTranscodeResource> _audioTranscodeResource;
|
||||
std::shared_ptr<AudioFileResource> _audioFileResource;
|
||||
std::shared_ptr<ImageResource> _imageResource;
|
||||
MediaPlayer* _mediaPlayer {};
|
||||
PlayQueue* _playQueue {};
|
||||
std::shared_ptr<AudioFileResource> _audioFileResource;
|
||||
std::shared_ptr<ImageResource> _imageResource;
|
||||
MediaPlayer* _mediaPlayer {};
|
||||
PlayQueue* _playQueue {};
|
||||
std::unique_ptr<Wt::WPopupMenu> _popupMenu {};
|
||||
};
|
||||
|
||||
|
||||
|
||||
+44
-15
@@ -209,6 +209,13 @@ PlayQueue::getTrackList() const
|
||||
return Database::TrackList::getById(LmsApp->getDbSession(), _tracklistId);
|
||||
}
|
||||
|
||||
bool
|
||||
PlayQueue::isFull() const
|
||||
{
|
||||
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
|
||||
return getTrackList()->getCount() == _nbMaxEntries;
|
||||
}
|
||||
|
||||
void
|
||||
PlayQueue::clearTracks()
|
||||
{
|
||||
@@ -321,55 +328,77 @@ PlayQueue::updateCurrentTrack(bool selected)
|
||||
entry->bindString("is-selected", selected ? "Lms-playqueue-selected" : "");
|
||||
}
|
||||
|
||||
void
|
||||
std::size_t
|
||||
PlayQueue::enqueueTracks(const std::vector<Database::IdType>& trackIds)
|
||||
{
|
||||
std::size_t nbTracksQueued {};
|
||||
|
||||
{
|
||||
auto transaction {LmsApp->getDbSession().createUniqueTransaction()};
|
||||
|
||||
auto tracklist = getTrackList();
|
||||
auto tracklist {getTrackList()};
|
||||
|
||||
std::size_t nbTracksToEnqueue {tracklist->getCount() + trackIds.size() > _nbMaxEntries ? _nbMaxEntries - tracklist->getCount() : trackIds.size()};
|
||||
for (Database::IdType trackId : trackIds)
|
||||
{
|
||||
Database::Track::pointer track {Database::Track::getById(LmsApp->getDbSession(), trackId)};
|
||||
if (!track)
|
||||
continue;
|
||||
|
||||
if (nbTracksQueued == nbTracksToEnqueue)
|
||||
break;
|
||||
|
||||
Database::TrackListEntry::create(LmsApp->getDbSession(), track, tracklist);
|
||||
nbTracksQueued++;
|
||||
}
|
||||
}
|
||||
|
||||
updateInfo();
|
||||
addSome();
|
||||
}
|
||||
|
||||
void
|
||||
PlayQueue::enqueueTrack(Database::IdType trackId)
|
||||
{
|
||||
enqueueTracks({trackId});
|
||||
return nbTracksQueued;
|
||||
}
|
||||
|
||||
void
|
||||
PlayQueue::processTracks(PlayQueueAction action, const std::vector<Database::IdType>& trackIds)
|
||||
{
|
||||
std::size_t nbAddedTracks {};
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case PlayQueueAction::AddLast:
|
||||
enqueueTracks(trackIds);
|
||||
LmsApp->notifyMsg(MsgType::Info, Wt::WString::trn("Lms.PlayQueue.nb-tracks-added", trackIds.size()).arg(trackIds.size()), std::chrono::milliseconds(2000));
|
||||
break;
|
||||
|
||||
case PlayQueueAction::AddNext:
|
||||
case PlayQueueAction::PlayLast:
|
||||
nbAddedTracks = enqueueTracks(trackIds);
|
||||
if (!_trackPos)
|
||||
loadTrack(0, true);
|
||||
break;
|
||||
|
||||
case PlayQueueAction::Play:
|
||||
clearTracks();
|
||||
enqueueTracks(trackIds);
|
||||
nbAddedTracks = enqueueTracks(trackIds);
|
||||
loadTrack(0, true);
|
||||
|
||||
LmsApp->notifyMsg(MsgType::Info, Wt::WString::trn("Lms.PlayQueue.nb-tracks-playing", trackIds.size()).arg(trackIds.size()), std::chrono::milliseconds(2000));
|
||||
break;
|
||||
|
||||
case PlayQueueAction::PlayShuffled:
|
||||
{
|
||||
clearTracks();
|
||||
{
|
||||
std::vector<Database::IdType> shuffledTrackIds {trackIds};
|
||||
Random::shuffleContainer(shuffledTrackIds);
|
||||
nbAddedTracks = enqueueTracks(shuffledTrackIds);
|
||||
}
|
||||
loadTrack(0, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nbAddedTracks > 0)
|
||||
LmsApp->notifyMsg(MsgType::Info, Wt::WString::trn("Lms.PlayQueue.nb-tracks-added", nbAddedTracks).arg(nbAddedTracks), std::chrono::milliseconds(2000));
|
||||
|
||||
if (isFull())
|
||||
LmsApp->notifyMsg(MsgType::Warning, Wt::WString::tr("Lms.PlayQueue.playqueue-full"), std::chrono::milliseconds(2000));
|
||||
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -60,10 +60,10 @@ class PlayQueue : public Wt::WTemplate
|
||||
|
||||
private:
|
||||
Wt::Dbo::ptr<Database::TrackList> getTrackList() const;
|
||||
bool isFull() const;
|
||||
|
||||
void clearTracks();
|
||||
void enqueueTracks(const std::vector<Database::IdType>& trackIds);
|
||||
void enqueueTrack(Database::IdType trackId);
|
||||
std::size_t enqueueTracks(const std::vector<Database::IdType>& trackIds);
|
||||
void addSome();
|
||||
void enqueueRadioTrack();
|
||||
void updateInfo();
|
||||
@@ -80,6 +80,8 @@ class PlayQueue : public Wt::WTemplate
|
||||
void addRadioTrackFromClusters();
|
||||
std::optional<float> getReplayGain(std::size_t pos, const Wt::Dbo::ptr<Database::Track>& track) const;
|
||||
|
||||
static inline constexpr std::size_t _nbMaxEntries {1000};
|
||||
|
||||
bool _repeatAll {};
|
||||
bool _radioMode {};
|
||||
bool _mediaPlayerSettingsLoaded {};
|
||||
|
||||
@@ -19,15 +19,22 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <Wt/WSignal.h>
|
||||
|
||||
#include "database/Types.hpp"
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
|
||||
enum class PlayQueueAction
|
||||
{
|
||||
Play,
|
||||
AddNext,
|
||||
AddLast,
|
||||
PlayLast,
|
||||
PlayShuffled,
|
||||
};
|
||||
|
||||
using PlayQueueActionSignal = Wt::Signal<PlayQueueAction, const std::vector<Database::IdType>&>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -115,11 +115,24 @@ Artist::refreshView()
|
||||
}
|
||||
|
||||
{
|
||||
Wt::WText* addBtn = bindNew<Wt::WText>("add-btn", Wt::WString::tr("Lms.Explore.template.add-btn"), Wt::TextFormat::XHTML);
|
||||
Wt::WText* moreBtn = bindNew<Wt::WText>("more-btn", Wt::WString::tr("Lms.Explore.template.more-btn"), Wt::TextFormat::XHTML);
|
||||
|
||||
addBtn->clicked().connect([=]
|
||||
moreBtn->clicked().connect([=]
|
||||
{
|
||||
artistsAction.emit(PlayQueueAction::AddLast, {*artistId});
|
||||
Wt::WPopupMenu* popup {LmsApp->createPopupMenu()};
|
||||
|
||||
popup->addItem(Wt::WString::tr("Lms.Explore.play-shuffled"))
|
||||
->triggered().connect(this, [=]
|
||||
{
|
||||
artistsAction.emit(PlayQueueAction::PlayShuffled, {*artistId});
|
||||
});
|
||||
popup->addItem(Wt::WString::tr("Lms.Explore.play-last"))
|
||||
->triggered().connect(this, [=]
|
||||
{
|
||||
artistsAction.emit(PlayQueueAction::PlayLast, {*artistId});
|
||||
});
|
||||
|
||||
popup->exec(moreBtn);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -135,6 +148,10 @@ Artist::refreshView()
|
||||
void
|
||||
Artist::refreshSimilarArtists(const std::vector<Database::IdType>& similarArtistsId)
|
||||
{
|
||||
if (similarArtistsId.empty())
|
||||
return;
|
||||
|
||||
setCondition("if-has-similar-artists", true);
|
||||
Wt::WContainerWidget* similarArtistsContainer {bindNew<Wt::WContainerWidget>("similar-artists")};
|
||||
|
||||
for (Database::IdType artistId : similarArtistsId)
|
||||
|
||||
@@ -42,7 +42,7 @@ class Artist : public Wt::WTemplate
|
||||
public:
|
||||
Artist(Filters* filters);
|
||||
|
||||
Wt::Signal<PlayQueueAction, const std::vector<Database::IdType>&> artistsAction;
|
||||
PlayQueueActionSignal artistsAction;
|
||||
|
||||
private:
|
||||
void refreshView();
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "Filters.hpp"
|
||||
#include "ReleasesView.hpp"
|
||||
#include "ReleaseView.hpp"
|
||||
#include "SearchView.hpp"
|
||||
#include "TracksView.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
@@ -50,6 +51,7 @@ handleContentsPathChange(Wt::WStackedWidget* stack)
|
||||
IdxArtist,
|
||||
IdxReleases,
|
||||
IdxRelease,
|
||||
IdxSearch,
|
||||
IdxTracks,
|
||||
};
|
||||
|
||||
@@ -59,6 +61,7 @@ handleContentsPathChange(Wt::WStackedWidget* stack)
|
||||
{ "/artist", IdxArtist },
|
||||
{ "/releases", IdxReleases },
|
||||
{ "/release", IdxRelease },
|
||||
{ "/search", IdxSearch },
|
||||
{ "/tracks", IdxTracks },
|
||||
};
|
||||
|
||||
@@ -100,6 +103,11 @@ Explore::Explore(Filters* filters)
|
||||
release->tracksAction.connect(this, &Explore::handleTracksAction);
|
||||
contentsStack->addWidget(std::move(release));
|
||||
|
||||
auto search = std::make_unique<SearchView>(_filters);
|
||||
search->tracksAction.connect(this, &Explore::handleTracksAction);
|
||||
_search = search.get();
|
||||
contentsStack->addWidget(std::move(search));
|
||||
|
||||
auto tracks = std::make_unique<Tracks>(_filters);
|
||||
tracks->tracksAction.connect(this, &Explore::handleTracksAction);
|
||||
contentsStack->addWidget(std::move(tracks));
|
||||
@@ -112,6 +120,12 @@ Explore::Explore(Filters* filters)
|
||||
handleContentsPathChange(contentsStack);
|
||||
}
|
||||
|
||||
void
|
||||
Explore::search(const Wt::WString& searchText)
|
||||
{
|
||||
_search->refreshView(searchText);
|
||||
}
|
||||
|
||||
static
|
||||
std::vector<Database::IdType>
|
||||
getArtistsTracks(Database::Session& session, const std::vector<Database::IdType>& artistsId, const std::set<Database::IdType>&)
|
||||
|
||||
@@ -27,13 +27,16 @@
|
||||
namespace UserInterface {
|
||||
|
||||
class Filters;
|
||||
class SearchView;
|
||||
|
||||
class Explore : public Wt::WTemplate
|
||||
{
|
||||
public:
|
||||
Explore(Filters* filters);
|
||||
|
||||
Wt::Signal<PlayQueueAction, const std::vector<Database::IdType>&> tracksAction;
|
||||
void search(const Wt::WString& searchText);
|
||||
|
||||
PlayQueueActionSignal tracksAction;
|
||||
|
||||
private:
|
||||
|
||||
@@ -42,6 +45,7 @@ class Explore : public Wt::WTemplate
|
||||
void handleTracksAction(PlayQueueAction action, const std::vector<Database::IdType>& tracksId);
|
||||
|
||||
Filters* _filters {};
|
||||
SearchView* _search {};
|
||||
};
|
||||
|
||||
} // namespace UserInterface
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 "ReleasePopup.hpp"
|
||||
|
||||
#include "LmsApplication.hpp"
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
|
||||
void
|
||||
displayReleasePopupMenu(Wt::WInteractWidget& target,
|
||||
Database::IdType releaseId,
|
||||
PlayQueueActionSignal& releasesAction)
|
||||
{
|
||||
Wt::WPopupMenu* popup {LmsApp->createPopupMenu()};
|
||||
|
||||
popup->addItem(Wt::WString::tr("Lms.Explore.play-shuffled"))
|
||||
->triggered().connect(&target, [&releasesAction, releaseId]
|
||||
{
|
||||
releasesAction.emit(PlayQueueAction::PlayShuffled, {releaseId});
|
||||
});
|
||||
popup->addItem(Wt::WString::tr("Lms.Explore.play-last"))
|
||||
->triggered().connect(&target, [&releasesAction, releaseId]
|
||||
{
|
||||
releasesAction.emit(PlayQueueAction::PlayLast, {releaseId});
|
||||
});
|
||||
|
||||
popup->popup(&target);
|
||||
}
|
||||
|
||||
} // namespace UserInterface
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 <Wt/WWidget.h>
|
||||
#include <Wt/WSignal.h>
|
||||
|
||||
#include "database/Types.hpp"
|
||||
#include "PlayQueueAction.hpp"
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
void displayReleasePopupMenu(Wt::WInteractWidget& target,
|
||||
Database::IdType releaseId,
|
||||
PlayQueueActionSignal& releasesAction);
|
||||
} // namespace UserInterface
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <Wt/WAnchor.h>
|
||||
#include <Wt/WApplication.h>
|
||||
#include <Wt/WImage.h>
|
||||
#include <Wt/WPopupMenu.h>
|
||||
#include <Wt/WTemplate.h>
|
||||
#include <Wt/WText.h>
|
||||
|
||||
@@ -39,6 +38,7 @@
|
||||
#include "LmsApplicationException.hpp"
|
||||
#include "MediaPlayer.hpp"
|
||||
#include "ReleaseListHelpers.hpp"
|
||||
#include "ReleasePopup.hpp"
|
||||
#include "TrackStringUtils.hpp"
|
||||
|
||||
using namespace Database;
|
||||
@@ -157,10 +157,10 @@ Release::refreshView()
|
||||
}
|
||||
|
||||
{
|
||||
Wt::WText* addBtn {bindNew<Wt::WText>("add-btn", Wt::WString::tr("Lms.Explore.template.add-btn"), Wt::TextFormat::XHTML)};
|
||||
addBtn->clicked().connect([=]
|
||||
Wt::WText* moreBtn {bindNew<Wt::WText>("more-btn", Wt::WString::tr("Lms.Explore.template.more-btn"), Wt::TextFormat::XHTML)};
|
||||
moreBtn->clicked().connect([=]
|
||||
{
|
||||
releasesAction.emit(PlayQueueAction::AddLast, {*releaseId});
|
||||
displayReleasePopupMenu(*moreBtn, *releaseId, releasesAction);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -237,10 +237,18 @@ Release::refreshView()
|
||||
tracksAction.emit(PlayQueueAction::Play, {trackId});
|
||||
});
|
||||
|
||||
Wt::WText* addBtn {entry->bindNew<Wt::WText>("add-btn", Wt::WString::tr("Lms.Explore.template.add-btn"), Wt::TextFormat::XHTML)};
|
||||
addBtn->clicked().connect([=]()
|
||||
Wt::WText* moreBtn {entry->bindNew<Wt::WText>("more-btn", Wt::WString::tr("Lms.Explore.template.more-btn"), Wt::TextFormat::XHTML)};
|
||||
moreBtn->clicked().connect([=]()
|
||||
{
|
||||
tracksAction.emit(PlayQueueAction::AddLast, {trackId});
|
||||
Wt::WPopupMenu* popup {LmsApp->createPopupMenu()};
|
||||
|
||||
popup->addItem(Wt::WString::tr("Lms.Explore.play-last"))
|
||||
->triggered().connect(moreBtn, [=]
|
||||
{
|
||||
tracksAction.emit(PlayQueueAction::PlayLast, {trackId});
|
||||
});
|
||||
|
||||
popup->popup(moreBtn);
|
||||
});
|
||||
|
||||
entry->bindString("duration", trackDurationToString(track->getDuration()), Wt::TextFormat::Plain);
|
||||
@@ -306,6 +314,10 @@ Release::refreshLinks(const Database::Release::pointer& release)
|
||||
void
|
||||
Release::refreshSimilarReleases(const std::vector<Database::IdType>& similarReleasesId)
|
||||
{
|
||||
if (similarReleasesId.empty())
|
||||
return;
|
||||
|
||||
setCondition("if-has-similar-releases", true);
|
||||
auto* similarReleasesContainer {bindNew<Wt::WContainerWidget>("similar-releases")};
|
||||
|
||||
for (Database::IdType id : similarReleasesId)
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Wt/WSignal.h>
|
||||
#include <Wt/WTemplate.h>
|
||||
|
||||
#include "database/Types.hpp"
|
||||
@@ -39,11 +38,8 @@ namespace UserInterface
|
||||
public:
|
||||
Release(Filters* filters);
|
||||
|
||||
Wt::Signal<PlayQueueAction, const std::vector<Database::IdType>&> releasesAction;
|
||||
Wt::Signal<PlayQueueAction, const std::vector<Database::IdType>&> tracksAction;
|
||||
|
||||
Wt::Signal<Wt::WWidget&, Database::IdType> createReleaseActionMenu;
|
||||
Wt::Signal<Wt::WWidget&, Database::IdType> createTrackActionMenu;
|
||||
PlayQueueActionSignal releasesAction;
|
||||
PlayQueueActionSignal tracksAction;
|
||||
|
||||
private:
|
||||
void refreshView();
|
||||
|
||||
@@ -72,10 +72,23 @@ _filters {filters}
|
||||
{
|
||||
releasesAction.emit(PlayQueueAction::Play, getAllReleases());
|
||||
});
|
||||
Wt::WText* addBtn {bindNew<Wt::WText>("add-btn", Wt::WString::tr("Lms.Explore.template.add-btn"), Wt::TextFormat::XHTML)};
|
||||
addBtn->clicked().connect([this]
|
||||
Wt::WText* moreBtn {bindNew<Wt::WText>("more-btn", Wt::WString::tr("Lms.Explore.template.more-btn"), Wt::TextFormat::XHTML)};
|
||||
moreBtn->clicked().connect([=]
|
||||
{
|
||||
releasesAction.emit(PlayQueueAction::AddLast, getAllReleases());
|
||||
Wt::WPopupMenu* popup {LmsApp->createPopupMenu()};
|
||||
|
||||
popup->addItem(Wt::WString::tr("Lms.Explore.play-shuffled"))
|
||||
->triggered().connect([this]
|
||||
{
|
||||
releasesAction.emit(PlayQueueAction::PlayShuffled, getAllReleases());
|
||||
});
|
||||
popup->addItem(Wt::WString::tr("Lms.Explore.play-last"))
|
||||
->triggered().connect([this]
|
||||
{
|
||||
releasesAction.emit(PlayQueueAction::PlayLast, getAllReleases());
|
||||
});
|
||||
|
||||
popup->popup(moreBtn);
|
||||
});
|
||||
|
||||
_container = bindNew<Wt::WContainerWidget>("releases");
|
||||
|
||||
@@ -41,7 +41,7 @@ class Releases : public Wt::WTemplate
|
||||
public:
|
||||
Releases(Filters* filters);
|
||||
|
||||
Wt::Signal<PlayQueueAction, const std::vector<Database::IdType>&> releasesAction;
|
||||
PlayQueueActionSignal releasesAction;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -51,9 +51,9 @@ namespace UserInterface
|
||||
}
|
||||
|
||||
void
|
||||
SearchView::refreshView(const std::string& searchText)
|
||||
SearchView::refreshView(const Wt::WString& searchText)
|
||||
{
|
||||
_keywords = StringUtils::splitString(searchText, " ");
|
||||
_keywords = StringUtils::splitString(searchText.toUTF8(), " ");
|
||||
refreshView();
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace UserInterface
|
||||
auto* container {bindNew<Wt::WContainerWidget>("tracks")};
|
||||
|
||||
for (const Database::Track::pointer& track : tracks)
|
||||
container->addWidget(TrackListHelpers::createEntry(track));
|
||||
container->addWidget(TrackListHelpers::createEntry(track, tracksAction));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
#include <Wt/WTemplate.h>
|
||||
|
||||
#include "PlayQueueAction.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
|
||||
class Filters;
|
||||
@@ -33,7 +35,9 @@ class SearchView : public Wt::WTemplate
|
||||
public:
|
||||
SearchView(Filters* filters);
|
||||
|
||||
void refreshView(const std::string& searchText);
|
||||
PlayQueueActionSignal tracksAction;
|
||||
|
||||
void refreshView(const Wt::WString& searchText);
|
||||
|
||||
private:
|
||||
void refreshView();
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "resource/ImageResource.hpp"
|
||||
#include "LmsApplication.hpp"
|
||||
#include "MediaPlayer.hpp"
|
||||
#include "PlayQueue.hpp"
|
||||
#include "TrackStringUtils.hpp"
|
||||
|
||||
using namespace Database;
|
||||
@@ -38,7 +37,7 @@ using namespace Database;
|
||||
namespace UserInterface::TrackListHelpers
|
||||
{
|
||||
std::unique_ptr<Wt::WTemplate>
|
||||
createEntry(const Wt::Dbo::ptr<Database::Track>& track)
|
||||
createEntry(const Wt::Dbo::ptr<Database::Track>& track, PlayQueueActionSignal& tracksAction)
|
||||
{
|
||||
auto entry {std::make_unique<Wt::WTemplate>(Wt::WString::tr("Lms.Explore.Tracks.template.entry"))};
|
||||
auto* entryPtr {entry.get()};
|
||||
@@ -89,15 +88,23 @@ namespace UserInterface::TrackListHelpers
|
||||
entry->bindString("duration", trackDurationToString(track->getDuration()), Wt::TextFormat::Plain);
|
||||
|
||||
Wt::WText* playBtn = entry->bindNew<Wt::WText>("play-btn", Wt::WString::tr("Lms.Explore.template.play-btn"), Wt::TextFormat::XHTML);
|
||||
playBtn->clicked().connect([=]
|
||||
playBtn->clicked().connect([trackId, &tracksAction]
|
||||
{
|
||||
LmsApp->getPlayQueue().processTracks(PlayQueueAction::Play, {trackId});
|
||||
tracksAction.emit(PlayQueueAction::Play, {trackId});
|
||||
});
|
||||
|
||||
Wt::WText* addBtn = entry->bindNew<Wt::WText>("add-btn", Wt::WString::tr("Lms.Explore.template.add-btn"), Wt::TextFormat::XHTML);
|
||||
addBtn->clicked().connect([=]
|
||||
Wt::WText* moreBtn = entry->bindNew<Wt::WText>("more-btn", Wt::WString::tr("Lms.Explore.template.more-btn"), Wt::TextFormat::XHTML);
|
||||
moreBtn->clicked().connect([=, &tracksAction]
|
||||
{
|
||||
LmsApp->getPlayQueue().processTracks(PlayQueueAction::AddLast, {trackId});
|
||||
Wt::WPopupMenu* popup {LmsApp->createPopupMenu()};
|
||||
|
||||
popup->addItem(Wt::WString::tr("Lms.Explore.play-last"))
|
||||
->triggered().connect(moreBtn, [=, &tracksAction]
|
||||
{
|
||||
tracksAction.emit(PlayQueueAction::PlayLast, {trackId});
|
||||
});
|
||||
|
||||
popup->popup(moreBtn);
|
||||
});
|
||||
|
||||
LmsApp->getMediaPlayer().trackLoaded.connect(entryPtr, [=] (Database::IdType loadedTrackId)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include <Wt/WTemplate.h>
|
||||
#include "PlayQueueAction.hpp"
|
||||
|
||||
namespace Database
|
||||
{
|
||||
@@ -30,6 +31,6 @@ namespace Database
|
||||
|
||||
namespace UserInterface::TrackListHelpers
|
||||
{
|
||||
std::unique_ptr<Wt::WTemplate> createEntry(const Wt::Dbo::ptr<Database::Track>& track);
|
||||
std::unique_ptr<Wt::WTemplate> createEntry(const Wt::Dbo::ptr<Database::Track>& track, PlayQueueActionSignal& tracksAction);
|
||||
} // namespace UserInterface
|
||||
|
||||
|
||||
@@ -32,9 +32,8 @@
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "resource/ImageResource.hpp"
|
||||
|
||||
#include "common/LoadingIndicator.hpp"
|
||||
#include "resource/ImageResource.hpp"
|
||||
#include "Filters.hpp"
|
||||
#include "LmsApplication.hpp"
|
||||
#include "MediaPlayer.hpp"
|
||||
@@ -76,10 +75,23 @@ _filters {filters}
|
||||
tracksAction.emit(PlayQueueAction::Play, getAllTracks());
|
||||
});
|
||||
|
||||
Wt::WText* addBtn = bindNew<Wt::WText>("add-btn", Wt::WString::tr("Lms.Explore.template.add-btn"), Wt::TextFormat::XHTML);
|
||||
addBtn->clicked().connect([=]
|
||||
Wt::WText* moreBtn = bindNew<Wt::WText>("more-btn", Wt::WString::tr("Lms.Explore.template.more-btn"), Wt::TextFormat::XHTML);
|
||||
moreBtn->clicked().connect([=]
|
||||
{
|
||||
tracksAction.emit(PlayQueueAction::AddLast, getAllTracks());
|
||||
Wt::WPopupMenu* popup {LmsApp->createPopupMenu()};
|
||||
|
||||
popup->addItem(Wt::WString::tr("Lms.Explore.play-shuffled"))
|
||||
->triggered().connect(this, [this]
|
||||
{
|
||||
tracksAction.emit(PlayQueueAction::PlayShuffled, getAllTracks());
|
||||
});
|
||||
popup->addItem(Wt::WString::tr("Lms.Explore.play-last"))
|
||||
->triggered().connect(this, [this]
|
||||
{
|
||||
tracksAction.emit(PlayQueueAction::PlayLast, getAllTracks());
|
||||
});
|
||||
|
||||
popup->popup(moreBtn);
|
||||
});
|
||||
|
||||
_tracksContainer = bindNew<Wt::WContainerWidget>("tracks");
|
||||
@@ -219,7 +231,7 @@ Tracks::addSome()
|
||||
bool moreResults;
|
||||
for (const Track::pointer& track : getTracks(Range {static_cast<std::size_t>(_tracksContainer->count()), batchSize}, moreResults))
|
||||
{
|
||||
_tracksContainer->addWidget(TrackListHelpers::createEntry(track));
|
||||
_tracksContainer->addWidget(TrackListHelpers::createEntry(track, tracksAction));
|
||||
}
|
||||
|
||||
if (moreResults)
|
||||
|
||||
@@ -40,7 +40,7 @@ class Tracks : public Wt::WTemplate
|
||||
public:
|
||||
Tracks(Filters* filters);
|
||||
|
||||
Wt::Signal<PlayQueueAction, const std::vector<Database::IdType>&> tracksAction;
|
||||
PlayQueueActionSignal tracksAction;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user