[UI/MOBILE] Can now play tracks from views

This commit is contained in:
emeric
2016-03-06 20:08:28 +01:00
parent 4e63d99e3e
commit 17f84c22bb
15 changed files with 95 additions and 76 deletions
+7 -8
View File
@@ -194,11 +194,9 @@ LmsApplication::handleAuthEvent(void)
this->root()->setOverflow(Wt::WContainerWidget::OverflowHidden);
setConfirmCloseMessage("Closing LMS. Are you sure?");
// Handle internal paths
// Create a Vertical layout: top is the nav bar, bottom is the contents
Wt::WVBoxLayout *layout = new Wt::WVBoxLayout(this->root());
// Create a navigation bar with a link to a web page.
Wt::WNavigationBar *navigation = new Wt::WNavigationBar();
navigation->setTitle("LMS", "https://github.com/epoupon/lms");
navigation->setResponsive(true);
@@ -219,19 +217,20 @@ LmsApplication::handleAuthEvent(void)
searchEdit->setWidth(150);
// TODO add a span with a search icon
Audio *audio;
menu->setInternalPathEnabled();
menu->setInternalBasePath("/");
Audio *audio;
if (agentIsMobile())
audio = new Mobile::Audio();
else
audio = new Desktop::Audio();
menu->addItem("Audio", audio);
menu->addItem("Audio", audio)->setPathComponent("audio");;
#if defined HAVE_VIDEO
menu->addItem("Video", new VideoWidget());
menu->addItem("Video", new VideoWidget())->setPathComponent("video");
#endif
menu->addItem("Settings", new Settings::Settings());
menu->addItem("Settings", new Settings::Settings())->setPathComponent("settings");
Wt::WPopupMenu *popup = new Wt::WPopupMenu();
popup->addItem("Logout");
+8 -15
View File
@@ -55,18 +55,6 @@ enum WidgetIdx
using namespace Database;
static void playTrack(AudioPlayer *audioPlayer, Database::Track::id_type trackId)
{
LMS_LOG(UI, DEBUG) << "Playing track id " << trackId;
Wt::Dbo::Transaction transaction(DboSession());
Track::pointer track = Track::getById(DboSession(), trackId);
if (track)
audioPlayer->loadTrack(track.id());
}
void
Audio::search(std::string text)
{
@@ -83,12 +71,12 @@ Audio::Audio(Wt::WContainerWidget *parent)
Wt::WStackedWidget *stack = new Wt::WStackedWidget(this);
// Same order as WidgetIdxXXX
stack->addWidget(new PreviewSearchView());
stack->addWidget(new PreviewSearchView(_playQueueEvents));
stack->addWidget(new ArtistSearchView());
stack->addWidget(new ReleaseSearchView());
stack->addWidget(new TrackSearchView());
stack->addWidget(new TrackSearchView(_playQueueEvents));
stack->addWidget(new ArtistView());
stack->addWidget(new ReleaseView());
stack->addWidget(new ReleaseView(_playQueueEvents));
wApp->internalPathChanged().connect(std::bind([=] (std::string path)
{
@@ -117,6 +105,11 @@ Audio::Audio(Wt::WContainerWidget *parent)
AudioPlayer* audioPlayer = new AudioPlayer();
footer->bindWidget("player", audioPlayer);
// Connect the events to the player
_playQueueEvents.trackPlay.connect(std::bind([=] (Database::Track::id_type id)
{
audioPlayer->loadTrack(id);
}, std::placeholders::_1));
}
} // namespace Mobile
+7 -3
View File
@@ -17,13 +17,15 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UI_AUDIO_MOBILE_HPP
#define UI_AUDIO_MOBILE_HPP
#pragma once
#include <Wt/WContainerWidget>
#include "audio/Audio.hpp"
#include "MobilePlayQueueEvents.hpp"
namespace UserInterface {
namespace Mobile {
@@ -35,9 +37,11 @@ class Audio : public UserInterface::Audio
void search(std::string text);
private:
PlayQueueEvents _playQueueEvents;
};
} // namespace Mobile
} // namespace UserInterface
#endif
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2016 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/WSignal>
#include "database/Types.hpp"
namespace UserInterface {
namespace Mobile {
struct PlayQueueEvents
{
Wt::Signal<Database::Track::id_type> trackPlay;
};
} // namespace Mobile
} // namespace UserInterface
+2 -2
View File
@@ -36,13 +36,13 @@ namespace Mobile {
using namespace Database;
PreviewSearchView::PreviewSearchView(Wt::WContainerWidget* parent)
PreviewSearchView::PreviewSearchView(PlayQueueEvents& events, Wt::WContainerWidget* parent)
{
const std::string pathPrefix = "/audio/search/preview";
ArtistSearch* artistSearch = new ArtistSearch("Artists", this);
ReleaseSearch* releaseSearch = new ReleaseSearch(this);
TrackSearch* trackSearch = new TrackSearch(this);
TrackSearch* trackSearch = new TrackSearch(events, this);
artistSearch->showMore().connect(std::bind([=]
{
+3 -1
View File
@@ -21,6 +21,8 @@
#include <Wt/WContainerWidget>
#include "MobilePlayQueueEvents.hpp"
namespace UserInterface {
namespace Mobile {
@@ -28,7 +30,7 @@ class PreviewSearchView : public Wt::WContainerWidget
{
public:
PreviewSearchView(Wt::WContainerWidget* parent = 0);
PreviewSearchView(PlayQueueEvents& events, Wt::WContainerWidget* parent = 0);
};
-1
View File
@@ -20,7 +20,6 @@
#pragma once
#include <Wt/WContainerWidget>
#include <Wt/WSignal>
#include <Wt/WText>
#include "database/SearchFilter.hpp"
+7 -26
View File
@@ -33,8 +33,9 @@ namespace Mobile {
using namespace Database;
ReleaseView::ReleaseView(Wt::WContainerWidget *parent)
: Wt::WContainerWidget(parent)
ReleaseView::ReleaseView(PlayQueueEvents& events, Wt::WContainerWidget *parent)
: Wt::WContainerWidget(parent),
_events(events)
{
Wt::WTemplate* wrapper = new Wt::WTemplate(this);
wrapper->setTemplateText(Wt::WString::tr("wa-trackview-wrapper"));
@@ -97,23 +98,6 @@ ReleaseView::search(SearchFilter filter, size_t nb)
addResults(nb);
}
static
std::vector<Track::pointer >
getTracks(SearchFilter filter, size_t offset, size_t nb, bool &moreResults)
{
std::vector<Track::pointer > tracks = Track::getByFilter(DboSession(), filter, offset, nb + 1);
if (tracks.size() == nb + 1)
{
moreResults = true;
tracks.pop_back();
}
else
moreResults = false;
return tracks;
}
static Wt::WString
getArtistNameFromRelease(Release::pointer release)
{
@@ -132,7 +116,7 @@ ReleaseView::addResults(size_t nb)
Wt::Dbo::Transaction transaction(DboSession());
bool moreResults;
std::vector<Track::pointer > tracks = getTracks(_filter, _nbTracks, nb, moreResults);
std::vector<Track::pointer> tracks = Track::getByFilter(DboSession(), _filter, _nbTracks, nb, moreResults);
for (Track::pointer track : tracks)
{
@@ -150,7 +134,7 @@ ReleaseView::addResults(size_t nb)
Wt::WImage *cover = new Wt::WImage();
cover->setStyleClass ("center-block img-responsive"); // TODO move to CSS?
cover->setImageLink(Wt::WLink (LmsApp->getImageResource()->getReleaseUrl(release.id(), 512)));
cover->setImageLink(Wt::WLink (SessionImageResource()->getReleaseUrl(release.id(), 512)));
releaseContainer->bindWidget("cover", cover);
releaseContainer->bindString("artist-name", getArtistNameFromRelease(release), Wt::PlainText);
@@ -191,16 +175,13 @@ ReleaseView::addResults(size_t nb)
trackRes->bindString("track-name", Wt::WString::fromUTF8(track->getName()), Wt::PlainText);
// TODO, display artist name for compilation releases?
std::string format = track->getDuration().total_seconds() < 3600 ? "%M:%S" : "%H:%M:%S";
trackRes->bindString("time", durationToString(track->getDuration(), format), Wt::PlainText);
Wt::WText *playBtn = new Wt::WText("Play", Wt::PlainText);
playBtn->setStyleClass("center-block"); // TODO move to CSS?
playBtn->clicked().connect(std::bind([=] {
_sigTrackPlay.emit(track.id());
_events.trackPlay.emit(track.id());
}));
trackRes->bindWidget("btn", playBtn);
trackRes->bindWidget("play-btn", playBtn);
_nbTracks++;
}
+4 -3
View File
@@ -22,6 +22,8 @@
#include <Wt/WContainerWidget>
#include <Wt/WSignal>
#include "MobilePlayQueueEvents.hpp"
namespace UserInterface {
namespace Mobile {
@@ -31,22 +33,21 @@ class ReleaseView : public Wt::WContainerWidget
static Wt::WLink getLink(Database::Release::id_type id);
ReleaseView(Wt::WContainerWidget *parent = 0);
ReleaseView(PlayQueueEvents& events, Wt::WContainerWidget *parent = 0);
void search(Database::SearchFilter filter, size_t nb);
// Slots
Wt::Signal<Database::Track::id_type>& trackPlay() { return _sigTrackPlay;}
Wt::Signal<void>& moreTracksSelected() { return _sigMoreTracksSelected;}
private:
Wt::Signal<Database::Track::id_type> _sigTrackPlay;
Wt::Signal<void> _sigMoreTracksSelected;
void clear(void);
void addResults(size_t nb);
PlayQueueEvents& _events;
Wt::WTemplate* _showMore;
Database::SearchFilter _filter;
+4 -3
View File
@@ -33,8 +33,9 @@ namespace Mobile {
using namespace Database;
TrackSearch::TrackSearch(Wt::WContainerWidget *parent)
: Wt::WContainerWidget(parent)
TrackSearch::TrackSearch(PlayQueueEvents& events, Wt::WContainerWidget *parent)
: Wt::WContainerWidget(parent),
_events(events)
{
Wt::WTemplate* t = new Wt::WTemplate(this);
t->setTemplateText(Wt::WString::tr("wa-track-search"));
@@ -97,7 +98,7 @@ TrackSearch::addResults(size_t nb)
Wt::WText *playBtn = new Wt::WText("Play", Wt::PlainText);
playBtn->setStyleClass("center-block"); // TODO move to CSS?
playBtn->clicked().connect(std::bind([=] {
_sigTrackPlay.emit(track.id());
_events.trackPlay.emit(track.id());
}));
res->bindWidget("btn", playBtn);
+4 -3
View File
@@ -25,6 +25,8 @@
#include "database/SearchFilter.hpp"
#include "database/Types.hpp"
#include "MobilePlayQueueEvents.hpp"
namespace UserInterface {
namespace Mobile {
@@ -32,22 +34,21 @@ class TrackSearch : public Wt::WContainerWidget
{
public:
TrackSearch(Wt::WContainerWidget *parent = 0);
TrackSearch(PlayQueueEvents& events, Wt::WContainerWidget *parent = 0);
void addResults(size_t nb);
void search(Database::SearchFilter filter, size_t nb);
// Slots
Wt::Signal<void>& showMore() { return _sigShowMore;}
Wt::Signal<Database::Track::id_type>& trackPlay() { return _sigTrackPlay;}
private:
Wt::Signal<void> _sigShowMore;
Wt::Signal<Database::Track::id_type> _sigTrackPlay;
void clear(void);
PlayQueueEvents& _events;
Wt::WTemplate* _showMore;
Database::SearchFilter _filter;
Wt::WContainerWidget* _contents;
+2 -2
View File
@@ -34,9 +34,9 @@ namespace Mobile {
using namespace Database;
TrackSearchView::TrackSearchView(Wt::WContainerWidget* parent)
TrackSearchView::TrackSearchView(PlayQueueEvents& events, Wt::WContainerWidget* parent)
{
TrackSearch* trackSearch = new TrackSearch(this);
TrackSearch* trackSearch = new TrackSearch(events, this);
trackSearch->showMore().connect(std::bind([=] {
trackSearch->addResults(SEARCH_NB_ITEMS);
}));
+2 -1
View File
@@ -20,6 +20,7 @@
#pragma once
#include <Wt/WContainerWidget>
#include <Wt/WSignal>
namespace UserInterface {
namespace Mobile {
@@ -28,7 +29,7 @@ class TrackSearchView : public Wt::WContainerWidget
{
public:
TrackSearchView(Wt::WContainerWidget* parent = 0);
TrackSearchView(PlayQueueEvents& events, Wt::WContainerWidget* parent = 0);
};
+9 -7
View File
@@ -55,6 +55,8 @@ Settings::Settings(Wt::WContainerWidget* parent)
Wt::WMenu *menu = new Wt::WMenu(contents, Wt::Vertical);
menu->setStyleClass("nav nav-pills nav-stacked submenu");
menu->setWidth(150);
menu->setInternalPathEnabled();
menu->setInternalBasePath("/settings/");
hLayout->addWidget(menu);
hLayout->addWidget(contents, 1);
@@ -68,22 +70,22 @@ Settings::Settings(Wt::WContainerWidget* parent)
userIsAdmin = CurrentUser()->isAdmin();
}
menu->addItem("Audio", new AudioFormView());
menu->addItem("Audio", new AudioFormView())->setPathComponent("audio");
if (userIsAdmin)
{
MediaDirectories* mediaDirectory = new MediaDirectories();
mediaDirectory->changed().connect(this, &Settings::handleDatabaseDirectoriesChanged);
menu->addItem("Media Folders", mediaDirectory);
MediaDirectories* mediaDirectories = new MediaDirectories();
mediaDirectories->changed().connect(this, &Settings::handleDatabaseDirectoriesChanged);
menu->addItem("Media Folders", mediaDirectories)->setPathComponent("mediadirectories");
DatabaseFormView* databaseFormView = new DatabaseFormView();
databaseFormView->changed().connect(this, &Settings::restartDatabaseUpdateService);
menu->addItem("Database", databaseFormView);
menu->addItem("Database", databaseFormView)->setPathComponent("database");
menu->addItem("Users", new Users());
menu->addItem("Users", new Users())->setPathComponent("users");
}
else
{
menu->addItem("Account", new AccountFormView(userId));
menu->addItem("Account", new AccountFormView(userId))->setPathComponent("account");
}
}