Search on Spotify on the left/Internet tab directly, instead of Spotify magic playlist (like for Grooveshark)
- Next step: fix the "did you mean" widget which is visible to user when displayed
This commit is contained in:
parent
abe8d10b9c
commit
70429217c6
|
@ -19,6 +19,7 @@
|
||||||
#include "searchboxwidget.h"
|
#include "searchboxwidget.h"
|
||||||
#include "ui_searchboxwidget.h"
|
#include "ui_searchboxwidget.h"
|
||||||
#include "ui/iconloader.h"
|
#include "ui/iconloader.h"
|
||||||
|
#include "widgets/didyoumean.h"
|
||||||
|
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
@ -43,6 +44,13 @@ SearchBoxWidget::SearchBoxWidget(InternetService* service)
|
||||||
|
|
||||||
ui_->filter->setPlaceholderText(QString("Search on %1").arg(service_->name()));
|
ui_->filter->setPlaceholderText(QString("Search on %1").arg(service_->name()));
|
||||||
connect(ui_->filter, SIGNAL(textChanged(QString)), SIGNAL(TextChanged(QString)));
|
connect(ui_->filter, SIGNAL(textChanged(QString)), SIGNAL(TextChanged(QString)));
|
||||||
|
|
||||||
|
// FIXME: the "Did you mean" suggestion is displayed above the search box,
|
||||||
|
// but below the internet services tree, which makes it fairly unusuable for
|
||||||
|
// now :(
|
||||||
|
did_you_mean_ = new DidYouMean(ui_->filter, this);
|
||||||
|
connect(did_you_mean_, SIGNAL(Accepted(QString)),
|
||||||
|
ui_->filter, SLOT(setText(QString)));
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchBoxWidget::~SearchBoxWidget() {
|
SearchBoxWidget::~SearchBoxWidget() {
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
class InternetService;
|
class InternetService;
|
||||||
|
class DidYouMean;
|
||||||
class Ui_SearchBoxWidget;
|
class Ui_SearchBoxWidget;
|
||||||
|
|
||||||
class QActionGroup;
|
class QActionGroup;
|
||||||
|
@ -33,6 +34,8 @@ public:
|
||||||
SearchBoxWidget(InternetService* service);
|
SearchBoxWidget(InternetService* service);
|
||||||
~SearchBoxWidget();
|
~SearchBoxWidget();
|
||||||
|
|
||||||
|
DidYouMean* did_you_mean() { return did_you_mean_; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void TextChanged(const QString& text);
|
void TextChanged(const QString& text);
|
||||||
|
|
||||||
|
@ -46,6 +49,7 @@ private:
|
||||||
InternetService* service_;
|
InternetService* service_;
|
||||||
Ui_SearchBoxWidget* ui_;
|
Ui_SearchBoxWidget* ui_;
|
||||||
QMenu* menu_;
|
QMenu* menu_;
|
||||||
|
DidYouMean* did_you_mean_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SEARCHBOXWIDGET_H
|
#endif // SEARCHBOXWIDGET_H
|
||||||
|
|
|
@ -45,5 +45,7 @@ void SpotifySearchPlaylistType::Search(const QString& text, Playlist* playlist)
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifySearchPlaylistType::DidYouMeanClicked(const QString& text, Playlist* playlist) {
|
void SpotifySearchPlaylistType::DidYouMeanClicked(const QString& text, Playlist* playlist) {
|
||||||
service_->Search(text, playlist, true);
|
// TODO Dead-code now: we will probably remove the entire class later, if the
|
||||||
|
// new search looks pretty enough for everyone
|
||||||
|
//service_->Search(text, playlist, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "core/database.h"
|
#include "core/database.h"
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
|
#include "core/mergedproxymodel.h"
|
||||||
#include "core/player.h"
|
#include "core/player.h"
|
||||||
#include "core/taskmanager.h"
|
#include "core/taskmanager.h"
|
||||||
#include "core/timeconstants.h"
|
#include "core/timeconstants.h"
|
||||||
|
@ -17,8 +18,10 @@
|
||||||
#include "playlist/playlist.h"
|
#include "playlist/playlist.h"
|
||||||
#include "playlist/playlistcontainer.h"
|
#include "playlist/playlistcontainer.h"
|
||||||
#include "playlist/playlistmanager.h"
|
#include "playlist/playlistmanager.h"
|
||||||
|
#include "searchboxwidget.h"
|
||||||
#include "widgets/didyoumean.h"
|
#include "widgets/didyoumean.h"
|
||||||
#include "ui/iconloader.h"
|
#include "ui/iconloader.h"
|
||||||
|
#include "widgets/didyoumean.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
@ -47,8 +50,8 @@ SpotifyService::SpotifyService(Application* app, InternetModel* parent)
|
||||||
inbox_(NULL),
|
inbox_(NULL),
|
||||||
toplist_(NULL),
|
toplist_(NULL),
|
||||||
login_task_id_(0),
|
login_task_id_(0),
|
||||||
pending_search_playlist_(NULL),
|
|
||||||
context_menu_(NULL),
|
context_menu_(NULL),
|
||||||
|
search_box_(new SearchBoxWidget(this)),
|
||||||
search_delay_(new QTimer(this)),
|
search_delay_(new QTimer(this)),
|
||||||
login_state_(LoginState_OtherError),
|
login_state_(LoginState_OtherError),
|
||||||
bitrate_(pb::spotify::Bitrate320k),
|
bitrate_(pb::spotify::Bitrate320k),
|
||||||
|
@ -80,6 +83,7 @@ SpotifyService::SpotifyService(Application* app, InternetModel* parent)
|
||||||
search_delay_->setInterval(kSearchDelayMsec);
|
search_delay_->setInterval(kSearchDelayMsec);
|
||||||
search_delay_->setSingleShot(true);
|
search_delay_->setSingleShot(true);
|
||||||
connect(search_delay_, SIGNAL(timeout()), SLOT(DoSearch()));
|
connect(search_delay_, SIGNAL(timeout()), SLOT(DoSearch()));
|
||||||
|
connect(search_box_, SIGNAL(TextChanged(QString)), SLOT(Search(QString)));
|
||||||
}
|
}
|
||||||
|
|
||||||
SpotifyService::~SpotifyService() {
|
SpotifyService::~SpotifyService() {
|
||||||
|
@ -340,7 +344,9 @@ void SpotifyService::PlaylistsUpdated(const pb::spotify::Playlists& response) {
|
||||||
// Create starred and inbox playlists if they're not here already
|
// Create starred and inbox playlists if they're not here already
|
||||||
if (!search_) {
|
if (!search_) {
|
||||||
search_ = new QStandardItem(IconLoader::Load("edit-find"),
|
search_ = new QStandardItem(IconLoader::Load("edit-find"),
|
||||||
tr("Search Spotify (opens a new tab)"));
|
tr("Search results"));
|
||||||
|
search_->setToolTip(tr("Start typing something on the search box above to "
|
||||||
|
"fill this search results list"));
|
||||||
search_->setData(Type_SearchResults, InternetModel::Role_Type);
|
search_->setData(Type_SearchResults, InternetModel::Role_Type);
|
||||||
search_->setData(InternetModel::PlayBehaviour_DoubleClickAction,
|
search_->setData(InternetModel::PlayBehaviour_DoubleClickAction,
|
||||||
InternetModel::Role_PlayBehaviour);
|
InternetModel::Role_PlayBehaviour);
|
||||||
|
@ -494,6 +500,10 @@ PlaylistItem::Options SpotifyService::playlistitem_options() const {
|
||||||
return PlaylistItem::PauseDisabled | PlaylistItem::SeekDisabled;
|
return PlaylistItem::PauseDisabled | PlaylistItem::SeekDisabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWidget* SpotifyService::HeaderWidget() const {
|
||||||
|
return search_box_;
|
||||||
|
}
|
||||||
|
|
||||||
void SpotifyService::EnsureMenuCreated() {
|
void SpotifyService::EnsureMenuCreated() {
|
||||||
if (context_menu_)
|
if (context_menu_)
|
||||||
return;
|
return;
|
||||||
|
@ -502,8 +512,6 @@ void SpotifyService::EnsureMenuCreated() {
|
||||||
|
|
||||||
context_menu_->addActions(GetPlaylistActions());
|
context_menu_->addActions(GetPlaylistActions());
|
||||||
context_menu_->addSeparator();
|
context_menu_->addSeparator();
|
||||||
context_menu_->addAction(IconLoader::Load("edit-find"), tr("Search Spotify (opens a new tab)..."), this, SLOT(OpenSearchTab()));
|
|
||||||
context_menu_->addSeparator();
|
|
||||||
context_menu_->addAction(IconLoader::Load("configure"), tr("Configure Spotify..."), this, SLOT(ShowConfig()));
|
context_menu_->addAction(IconLoader::Load("configure"), tr("Configure Spotify..."), this, SLOT(ShowConfig()));
|
||||||
|
|
||||||
playlist_context_menu_ = new QMenu;
|
playlist_context_menu_ = new QMenu;
|
||||||
|
@ -514,6 +522,11 @@ void SpotifyService::EnsureMenuCreated() {
|
||||||
SLOT(SyncPlaylist()));
|
SLOT(SyncPlaylist()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpotifyService::ClearSearchResults() {
|
||||||
|
if (search_)
|
||||||
|
search_->removeRows(0, search_->rowCount());
|
||||||
|
}
|
||||||
|
|
||||||
void SpotifyService::SyncPlaylist() {
|
void SpotifyService::SyncPlaylist() {
|
||||||
QStandardItem* item = playlist_sync_action_->data().value<QStandardItem*>();
|
QStandardItem* item = playlist_sync_action_->data().value<QStandardItem*>();
|
||||||
Q_ASSERT(item);
|
Q_ASSERT(item);
|
||||||
|
@ -539,11 +552,18 @@ void SpotifyService::SyncPlaylist() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyService::Search(const QString& text, Playlist* playlist, bool now) {
|
void SpotifyService::Search(const QString& text, bool now) {
|
||||||
EnsureServerCreated();
|
EnsureServerCreated();
|
||||||
|
|
||||||
pending_search_ = text;
|
pending_search_ = text;
|
||||||
pending_search_playlist_ = playlist;
|
|
||||||
|
// If there is no text (e.g. user cleared search box), we don't need to do a
|
||||||
|
// real query that will return nothing: we can clear the playlist now
|
||||||
|
if (text.isEmpty()) {
|
||||||
|
search_delay_->stop();
|
||||||
|
ClearSearchResults();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (now) {
|
if (now) {
|
||||||
search_delay_->stop();
|
search_delay_->stop();
|
||||||
|
@ -577,13 +597,22 @@ void SpotifyService::SearchResults(const pb::spotify::SearchResponse& response)
|
||||||
|
|
||||||
qLog(Debug) << "Got" << songs.count() << "results";
|
qLog(Debug) << "Got" << songs.count() << "results";
|
||||||
|
|
||||||
pending_search_playlist_->Clear();
|
ClearSearchResults();
|
||||||
pending_search_playlist_->InsertSongs(songs);
|
|
||||||
|
|
||||||
const QString did_you_mean = QStringFromStdString(response.did_you_mean());
|
// Fill results list
|
||||||
if (!did_you_mean.isEmpty()) {
|
foreach(const Song& song, songs) {
|
||||||
app_->playlist_manager()->playlist_container()->did_you_mean()->Show(did_you_mean);
|
QStandardItem* child = CreateSongItem(song);
|
||||||
|
search_->appendRow(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QString did_you_mean_suggestion = QStringFromStdString(response.did_you_mean());
|
||||||
|
qLog(Debug) << "Did you mean suggestion: " << did_you_mean_suggestion;
|
||||||
|
if (!did_you_mean_suggestion.isEmpty()) {
|
||||||
|
search_box_->did_you_mean()->Show(did_you_mean_suggestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex index = model()->merged_model()->mapFromSource(search_->index());
|
||||||
|
ScrollToIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
SpotifyServer* SpotifyService::server() const {
|
SpotifyServer* SpotifyService::server() const {
|
||||||
|
@ -616,15 +645,7 @@ void SpotifyService::ShowContextMenu(const QPoint& global_pos) {
|
||||||
context_menu_->popup(global_pos);
|
context_menu_->popup(global_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyService::OpenSearchTab() {
|
|
||||||
app_->playlist_manager()->New(tr("Search Spotify"), SongList(),
|
|
||||||
SpotifySearchPlaylistType::kName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpotifyService::ItemDoubleClicked(QStandardItem* item) {
|
void SpotifyService::ItemDoubleClicked(QStandardItem* item) {
|
||||||
if (item == search_) {
|
|
||||||
OpenSearchTab();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpotifyService::DropMimeData(const QMimeData* data, const QModelIndex& index) {
|
void SpotifyService::DropMimeData(const QMimeData* data, const QModelIndex& index) {
|
||||||
|
|
|
@ -10,7 +10,9 @@
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
class DidYouMean;
|
||||||
class Playlist;
|
class Playlist;
|
||||||
|
class SearchBoxWidget;
|
||||||
class SpotifyServer;
|
class SpotifyServer;
|
||||||
|
|
||||||
class QMenu;
|
class QMenu;
|
||||||
|
@ -57,10 +59,10 @@ public:
|
||||||
void ItemDoubleClicked(QStandardItem* item);
|
void ItemDoubleClicked(QStandardItem* item);
|
||||||
void DropMimeData(const QMimeData* data, const QModelIndex& index);
|
void DropMimeData(const QMimeData* data, const QModelIndex& index);
|
||||||
PlaylistItem::Options playlistitem_options() const;
|
PlaylistItem::Options playlistitem_options() const;
|
||||||
|
QWidget* HeaderWidget() const;
|
||||||
|
|
||||||
void Logout();
|
void Logout();
|
||||||
void Login(const QString& username, const QString& password);
|
void Login(const QString& username, const QString& password);
|
||||||
void Search(const QString& text, Playlist* playlist, bool now = false);
|
|
||||||
Q_INVOKABLE void LoadImage(const QString& id);
|
Q_INVOKABLE void LoadImage(const QString& id);
|
||||||
|
|
||||||
SpotifyServer* server() const;
|
SpotifyServer* server() const;
|
||||||
|
@ -80,6 +82,7 @@ signals:
|
||||||
void ImageLoaded(const QString& id, const QImage& image);
|
void ImageLoaded(const QString& id, const QImage& image);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
void Search(const QString& text, bool now = false);
|
||||||
void ShowConfig();
|
void ShowConfig();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -89,6 +92,7 @@ private:
|
||||||
const google::protobuf::RepeatedPtrField<pb::spotify::Track>& tracks);
|
const google::protobuf::RepeatedPtrField<pb::spotify::Track>& tracks);
|
||||||
void FillPlaylist(QStandardItem* item, const pb::spotify::LoadPlaylistResponse& response);
|
void FillPlaylist(QStandardItem* item, const pb::spotify::LoadPlaylistResponse& response);
|
||||||
void EnsureMenuCreated();
|
void EnsureMenuCreated();
|
||||||
|
void ClearSearchResults();
|
||||||
|
|
||||||
QStandardItem* PlaylistBySpotifyIndex(int index) const;
|
QStandardItem* PlaylistBySpotifyIndex(int index) const;
|
||||||
bool DoPlaylistsDiffer(const pb::spotify::Playlists& response) const;
|
bool DoPlaylistsDiffer(const pb::spotify::Playlists& response) const;
|
||||||
|
@ -107,7 +111,6 @@ private slots:
|
||||||
void SyncPlaylistProgress(const pb::spotify::SyncPlaylistProgress& progress);
|
void SyncPlaylistProgress(const pb::spotify::SyncPlaylistProgress& progress);
|
||||||
void ToplistLoaded(const pb::spotify::BrowseToplistResponse& response);
|
void ToplistLoaded(const pb::spotify::BrowseToplistResponse& response);
|
||||||
|
|
||||||
void OpenSearchTab();
|
|
||||||
void DoSearch();
|
void DoSearch();
|
||||||
|
|
||||||
void SyncPlaylist();
|
void SyncPlaylist();
|
||||||
|
@ -130,12 +133,13 @@ private:
|
||||||
|
|
||||||
int login_task_id_;
|
int login_task_id_;
|
||||||
QString pending_search_;
|
QString pending_search_;
|
||||||
Playlist* pending_search_playlist_;
|
|
||||||
|
|
||||||
QMenu* context_menu_;
|
QMenu* context_menu_;
|
||||||
QMenu* playlist_context_menu_;
|
QMenu* playlist_context_menu_;
|
||||||
QAction* playlist_sync_action_;
|
QAction* playlist_sync_action_;
|
||||||
|
|
||||||
|
SearchBoxWidget* search_box_;
|
||||||
|
|
||||||
QTimer* search_delay_;
|
QTimer* search_delay_;
|
||||||
|
|
||||||
int inbox_sync_id_;
|
int inbox_sync_id_;
|
||||||
|
|
Loading…
Reference in New Issue