Add some spotify branding, display spotify login errors, add a button to the config dialog to download the blob, only make the config dialog try to login when it needs to, fix a bug where the Starred and Inbox items would sometimes not get created.

This commit is contained in:
David Sansome 2011-04-30 12:31:20 +00:00
parent 1c0a0f17dd
commit 70e6018b1e
12 changed files with 213 additions and 45 deletions

View File

@ -318,5 +318,6 @@
<file>icons/32x32/edit-find.png</file> <file>icons/32x32/edit-find.png</file>
<file>icons/48x48/edit-find.png</file> <file>icons/48x48/edit-find.png</file>
<file>schema/schema-33.sql</file> <file>schema/schema-33.sql</file>
<file>spotify-core-logo-128x128.png</file>
</qresource> </qresource>
</RCC> </RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -44,6 +44,14 @@ SpotifyBlobDownloader::~SpotifyBlobDownloader() {
delete progress_; delete progress_;
} }
bool SpotifyBlobDownloader::Prompt() {
QMessageBox::StandardButton ret = QMessageBox::question(NULL,
tr("Spotify plugin not installed"),
tr("An additional plugin is required to use Spotify in Clementine. Would you like to download and install it now?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
return ret == QMessageBox::Yes;
}
void SpotifyBlobDownloader::Start() { void SpotifyBlobDownloader::Start() {
qDeleteAll(replies_); qDeleteAll(replies_);
replies_.clear(); replies_.clear();

View File

@ -32,6 +32,8 @@ public:
QObject* parent = 0); QObject* parent = 0);
~SpotifyBlobDownloader(); ~SpotifyBlobDownloader();
static bool Prompt();
void Start(); void Start();
signals: signals:

View File

@ -33,20 +33,55 @@ SpotifyConfig::SpotifyConfig(QWidget *parent)
network_(new NetworkAccessManager(this)), network_(new NetworkAccessManager(this)),
ui_(new Ui_SpotifyConfig), ui_(new Ui_SpotifyConfig),
service_(RadioModel::Service<SpotifyService>()), service_(RadioModel::Service<SpotifyService>()),
needs_validation_(true) validated_(false)
{ {
ui_->setupUi(this); ui_->setupUi(this);
ui_->busy->hide(); ui_->busy->hide();
QFont bold_font(font());
bold_font.setBold(true);
ui_->blob_status->setFont(bold_font);
connect(ui_->download_blob, SIGNAL(clicked()), SLOT(DownloadBlob()));
connect(service_, SIGNAL(LoginFinished(bool)), SLOT(LoginFinished(bool))); connect(service_, SIGNAL(LoginFinished(bool)), SLOT(LoginFinished(bool)));
connect(service_, SIGNAL(BlobStateChanged()), SLOT(BlobStateChanged()));
BlobStateChanged();
} }
SpotifyConfig::~SpotifyConfig() { SpotifyConfig::~SpotifyConfig() {
delete ui_; delete ui_;
} }
void SpotifyConfig::BlobStateChanged() {
const bool installed = service_->IsBlobInstalled();
ui_->account_group->setEnabled(installed);
ui_->blob_status->setText(installed ? tr("Installed") : tr("Not installed"));
#ifdef Q_OS_LINUX
ui_->download_blob->setEnabled(!installed);
#else
ui_->download_blob->setEnabled(false);
#endif
}
void SpotifyConfig::DownloadBlob() {
service_->InstallBlob();
}
bool SpotifyConfig::NeedsValidation() const { bool SpotifyConfig::NeedsValidation() const {
// FIXME if (!service_->IsBlobInstalled()) {
return needs_validation_; return false;
}
if (ui_->username->text() == original_username_ &&
ui_->password->text() == original_password_) {
return false;
}
return !validated_;
} }
void SpotifyConfig::Validate() { void SpotifyConfig::Validate() {
@ -58,8 +93,12 @@ void SpotifyConfig::Load() {
QSettings s; QSettings s;
s.beginGroup(SpotifyService::kSettingsGroup); s.beginGroup(SpotifyService::kSettingsGroup);
ui_->username->setText(s.value("username").toString()); original_username_ = s.value("username").toString();
ui_->password->setText(s.value("password").toString()); original_password_ = s.value("password").toString();
ui_->username->setText(original_username_);
ui_->password->setText(original_password_);
validated_ = false;
} }
void SpotifyConfig::Save() { void SpotifyConfig::Save() {
@ -73,8 +112,7 @@ void SpotifyConfig::Save() {
} }
void SpotifyConfig::LoginFinished(bool success) { void SpotifyConfig::LoginFinished(bool success) {
qDebug() << Q_FUNC_INFO << success; validated_ = success;
needs_validation_ = !success;
ui_->busy->hide(); ui_->busy->hide();
emit ValidationComplete(success); emit ValidationComplete(success);
} }

View File

@ -44,6 +44,9 @@ public slots:
void Load(); void Load();
void Save(); void Save();
void BlobStateChanged();
void DownloadBlob();
private slots: private slots:
void LoginFinished(bool success); void LoginFinished(bool success);
@ -52,7 +55,9 @@ private:
Ui_SpotifyConfig* ui_; Ui_SpotifyConfig* ui_;
SpotifyService* service_; SpotifyService* service_;
bool needs_validation_; bool validated_;
QString original_username_;
QString original_password_;
}; };
#endif // SPOTIFYCONFIG_H #endif // SPOTIFYCONFIG_H

View File

@ -6,16 +6,16 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>448</width> <width>484</width>
<height>310</height> <height>384</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="account_group">
<property name="title"> <property name="title">
<string>Account details</string> <string>Account details</string>
</property> </property>
@ -69,6 +69,56 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Spotify plugin</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>For licensing reasons Spotify support is in a separate plugin.</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Plugin status:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="blob_status"/>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="download_blob">
<property name="text">
<string>Download...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item> <item>
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
@ -82,6 +132,45 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="minimumSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="pixmap">
<pixmap resource="../../data/data.qrc">:/spotify-core-logo-128x128.png</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<widget class="QWidget" name="busy" native="true"> <widget class="QWidget" name="busy" native="true">
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
@ -120,6 +209,8 @@
<header>widgets/busyindicator.h</header> <header>widgets/busyindicator.h</header>
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<resources/> <resources>
<include location="../../data/data.qrc"/>
</resources>
<connections/> <connections/>
</ui> </ui>

View File

@ -90,9 +90,7 @@ void SpotifyServer::HandleMessage(const protobuf::SpotifyMessage& message) {
const protobuf::LoginResponse& response = message.login_response(); const protobuf::LoginResponse& response = message.login_response();
logged_in_ = response.success(); logged_in_ = response.success();
if (!response.success()) { if (response.success()) {
qLog(Info) << QStringFromStdString(response.error());
} else {
// Send any messages that were queued before the client logged in // Send any messages that were queued before the client logged in
foreach (const protobuf::SpotifyMessage& message, queued_messages_) { foreach (const protobuf::SpotifyMessage& message, queued_messages_) {
SendMessage(message); SendMessage(message);
@ -100,7 +98,7 @@ void SpotifyServer::HandleMessage(const protobuf::SpotifyMessage& message) {
queued_messages_.clear(); queued_messages_.clear();
} }
emit LoginCompleted(response.success()); emit LoginCompleted(response.success(), QStringFromStdString(response.error()));
} else if (message.has_playlists_updated()) { } else if (message.has_playlists_updated()) {
emit PlaylistsUpdated(message.playlists_updated()); emit PlaylistsUpdated(message.playlists_updated());
} else if (message.has_load_playlist_response()) { } else if (message.has_load_playlist_response()) {

View File

@ -47,7 +47,7 @@ public:
int server_port() const; int server_port() const;
signals: signals:
void LoginCompleted(bool success); void LoginCompleted(bool success, const QString& error);
void PlaylistsUpdated(const protobuf::Playlists& playlists); void PlaylistsUpdated(const protobuf::Playlists& playlists);
void StarredLoaded(const protobuf::LoadPlaylistResponse& response); void StarredLoaded(const protobuf::LoadPlaylistResponse& response);

View File

@ -37,6 +37,7 @@ SpotifyService::SpotifyService(RadioModel* parent)
url_handler_(new SpotifyUrlHandler(this, this)), url_handler_(new SpotifyUrlHandler(this, this)),
blob_process_(NULL), blob_process_(NULL),
root_(NULL), root_(NULL),
search_(NULL),
starred_(NULL), starred_(NULL),
inbox_(NULL), inbox_(NULL),
login_task_id_(0), login_task_id_(0),
@ -46,14 +47,19 @@ SpotifyService::SpotifyService(RadioModel* parent)
// Build the search path for the binary blob. // Build the search path for the binary blob.
// Look for one distributed alongside clementine first, then check in the // Look for one distributed alongside clementine first, then check in the
// user's home directory for any that have been downloaded. // user's home directory for any that have been downloaded.
blob_path_ << QCoreApplication::applicationFilePath() + "-spotifyblob" CMAKE_EXECUTABLE_SUFFIX #ifdef Q_OS_MAC
<< QCoreApplication::applicationDirPath() + "/../PlugIns/clementine-spotifyblob" CMAKE_EXECUTABLE_SUFFIX; system_blob_path_ = QCoreApplication::applicationDirPath() +
"/../PlugIns/clementine-spotifyblob";
#else
system_blob_path_ = QCoreApplication::applicationFilePath() +
"-spotifyblob" CMAKE_EXECUTABLE_SUFFIX;
#endif
local_blob_version_ = QString("version%1-%2bit").arg(SPOTIFY_BLOB_VERSION).arg(sizeof(void*) * 8); local_blob_version_ = QString("version%1-%2bit").arg(SPOTIFY_BLOB_VERSION).arg(sizeof(void*) * 8);
local_blob_path_ = Utilities::GetConfigPath(Utilities::Path_LocalSpotifyBlob) + local_blob_path_ = Utilities::GetConfigPath(Utilities::Path_LocalSpotifyBlob) +
"/" + local_blob_version_ + "/blob"; "/" + local_blob_version_ + "/blob";
qLog(Debug) << "Spotify blob search path:" << blob_path_; qLog(Debug) << "Spotify system blob path:" << system_blob_path_;
qLog(Debug) << "Spotify local blob path:" << local_blob_path_; qLog(Debug) << "Spotify local blob path:" << local_blob_path_;
model()->player()->RegisterUrlHandler(url_handler_); model()->player()->RegisterUrlHandler(url_handler_);
@ -66,6 +72,11 @@ SpotifyService::SpotifyService(RadioModel* parent)
} }
SpotifyService::~SpotifyService() { SpotifyService::~SpotifyService() {
if (blob_process_ && blob_process_->state() == QProcess::Running) {
qLog(Info) << "Terminating blob process...";
blob_process_->terminate();
blob_process_->waitForFinished(1000);
}
} }
QStandardItem* SpotifyService::CreateRootItem() { QStandardItem* SpotifyService::CreateRootItem() {
@ -118,12 +129,16 @@ void SpotifyService::Login(const QString& username, const QString& password) {
EnsureServerCreated(username, password); EnsureServerCreated(username, password);
} }
void SpotifyService::LoginCompleted(bool success) { void SpotifyService::LoginCompleted(bool success, const QString& error) {
if (login_task_id_) { if (login_task_id_) {
model()->task_manager()->SetTaskFinished(login_task_id_); model()->task_manager()->SetTaskFinished(login_task_id_);
login_task_id_ = 0; login_task_id_ = 0;
} }
if (!success) {
QMessageBox::warning(NULL, tr("Spotify login error"), error, QMessageBox::Close);
}
emit LoginFinished(success); emit LoginFinished(success);
} }
@ -132,8 +147,6 @@ void SpotifyService::BlobProcessError(QProcess::ProcessError error) {
blob_process_->deleteLater(); blob_process_->deleteLater();
blob_process_ = NULL; blob_process_ = NULL;
emit StreamError("The Spotify process failed");
if (login_task_id_) { if (login_task_id_) {
model()->task_manager()->SetTaskFinished(login_task_id_); model()->task_manager()->SetTaskFinished(login_task_id_);
} }
@ -148,7 +161,7 @@ void SpotifyService::EnsureServerCreated(const QString& username,
delete server_; delete server_;
server_ = new SpotifyServer(this); server_ = new SpotifyServer(this);
connect(server_, SIGNAL(LoginCompleted(bool)), SLOT(LoginCompleted(bool))); connect(server_, SIGNAL(LoginCompleted(bool,QString)), SLOT(LoginCompleted(bool,QString)));
connect(server_, SIGNAL(PlaylistsUpdated(protobuf::Playlists)), connect(server_, SIGNAL(PlaylistsUpdated(protobuf::Playlists)),
SLOT(PlaylistsUpdated(protobuf::Playlists))); SLOT(PlaylistsUpdated(protobuf::Playlists)));
connect(server_, SIGNAL(InboxLoaded(protobuf::LoadPlaylistResponse)), connect(server_, SIGNAL(InboxLoaded(protobuf::LoadPlaylistResponse)),
@ -186,19 +199,15 @@ void SpotifyService::StartBlobProcess() {
QProcessEnvironment env(QProcessEnvironment::systemEnvironment()); QProcessEnvironment env(QProcessEnvironment::systemEnvironment());
// Look in the system search path first // Look in the system search path first
foreach (const QString& path, blob_path_) { if (QFile::exists(system_blob_path_)) {
if (QFile::exists(path)) { blob_path = system_blob_path_;
blob_path = path;
break;
}
} }
// Next look in the local path // Next look in the local path
const QString local_blob_dir = QFileInfo(local_blob_path_).path();
if (blob_path.isEmpty()) { if (blob_path.isEmpty()) {
if (QFile::exists(local_blob_path_)) { if (QFile::exists(local_blob_path_)) {
blob_path = local_blob_path_; blob_path = local_blob_path_;
env.insert("LD_LIBRARY_PATH", local_blob_dir); env.insert("LD_LIBRARY_PATH", QFileInfo(local_blob_path_).path());
} }
} }
@ -209,17 +218,8 @@ void SpotifyService::StartBlobProcess() {
} }
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
QMessageBox::StandardButton ret = QMessageBox::question(NULL, if (SpotifyBlobDownloader::Prompt()) {
tr("Spotify plugin not installed"), InstallBlob();
tr("An additional plugin is required to use Spotify in Clementine. Would you like to download and install it now?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if (ret == QMessageBox::Yes) {
// The downloader deletes itself when it finishes
SpotifyBlobDownloader* downloader = new SpotifyBlobDownloader(
local_blob_version_, local_blob_dir, this);
connect(downloader, SIGNAL(Finished()), SLOT(BlobDownloadFinished()));
downloader->Start();
} }
#endif #endif
@ -240,6 +240,20 @@ void SpotifyService::StartBlobProcess() {
blob_path, QStringList() << QString::number(server_->server_port())); blob_path, QStringList() << QString::number(server_->server_port()));
} }
bool SpotifyService::IsBlobInstalled() const {
return QFile::exists(system_blob_path_) ||
QFile::exists(local_blob_path_);
}
void SpotifyService::InstallBlob() {
// The downloader deletes itself when it finishes
SpotifyBlobDownloader* downloader = new SpotifyBlobDownloader(
local_blob_version_, QFileInfo(local_blob_path_).path(), this);
connect(downloader, SIGNAL(Finished()), SLOT(BlobDownloadFinished()));
connect(downloader, SIGNAL(Finished()), SIGNAL(BlobStateChanged()));
downloader->Start();
}
void SpotifyService::BlobDownloadFinished() { void SpotifyService::BlobDownloadFinished() {
EnsureServerCreated(); EnsureServerCreated();
} }

View File

@ -52,7 +52,11 @@ public:
SpotifyServer* server() const; SpotifyServer* server() const;
bool IsBlobInstalled() const;
void InstallBlob();
signals: signals:
void BlobStateChanged();
void LoginFinished(bool success); void LoginFinished(bool success);
void ImageLoaded(const QUrl& url, const QImage& image); void ImageLoaded(const QUrl& url, const QImage& image);
@ -72,7 +76,7 @@ private:
private slots: private slots:
void BlobProcessError(QProcess::ProcessError error); void BlobProcessError(QProcess::ProcessError error);
void LoginCompleted(bool success); void LoginCompleted(bool success, const QString& error);
void PlaylistsUpdated(const protobuf::Playlists& response); void PlaylistsUpdated(const protobuf::Playlists& response);
void InboxLoaded(const protobuf::LoadPlaylistResponse& response); void InboxLoaded(const protobuf::LoadPlaylistResponse& response);
void StarredLoaded(const protobuf::LoadPlaylistResponse& response); void StarredLoaded(const protobuf::LoadPlaylistResponse& response);
@ -90,9 +94,9 @@ private:
SpotifyServer* server_; SpotifyServer* server_;
SpotifyUrlHandler* url_handler_; SpotifyUrlHandler* url_handler_;
QString system_blob_path_;
QString local_blob_version_; QString local_blob_version_;
QString local_blob_path_; QString local_blob_path_;
QStringList blob_path_;
QProcess* blob_process_; QProcess* blob_process_;
QStandardItem* root_; QStandardItem* root_;

View File

@ -16,6 +16,7 @@
*/ */
#include "about.h" #include "about.h"
#include "config.h"
#include "ui_about.h" #include "ui_about.h"
#include <QCoreApplication> #include <QCoreApplication>
@ -77,6 +78,12 @@ QString About::MakeHtml() const {
ret += QString("<br /><a href=\"http://rainymood.com\">Rainy Mood</a>"); ret += QString("<br /><a href=\"http://rainymood.com\">Rainy Mood</a>");
ret += QString("<br /><a href=\"http://www.smitelli.com/?page=blog&p=54\">Scott Smitelli</a></p>"); ret += QString("<br /><a href=\"http://www.smitelli.com/?page=blog&p=54\">Scott Smitelli</a></p>");
#ifdef HAVE_SPOTIFY
ret += "<p>This product uses SPOTIFY(R) CORE but is not endorsed, certified "
"or otherwise approved in any way by Spotify. Spotify is the "
"registered trade mark of the Spotify Group.</p>";
#endif // HAVE_SPOTIFY
return ret; return ret;
} }