diff --git a/TODO b/TODO index 7c6b2ae01..dd624b818 100644 --- a/TODO +++ b/TODO @@ -8,10 +8,6 @@ - Make QSortFilterProxyModel on the library obey hasChildren() - More columns in playlist -Last.fm: -- Artist/tag/etc. radio -- More types of radio - Long-term: - iPod diff --git a/src/lastfmservice.cpp b/src/lastfmservice.cpp index 9993cb01c..fe5dd91f6 100644 --- a/src/lastfmservice.cpp +++ b/src/lastfmservice.cpp @@ -2,6 +2,7 @@ #include "lastfmconfig.h" #include "radioitem.h" #include "song.h" +#include "lastfmstationdialog.h" #include #include @@ -21,9 +22,12 @@ LastFMService::LastFMService(QObject* parent) : RadioService(kServiceName, parent), tuner_(NULL), scrobbler_(NULL), + station_dialog_(new LastFMStationDialog), context_menu_(new QMenu), initial_tune_(false), scrobbling_enabled_(false), + artist_list_(NULL), + tag_list_(NULL), friends_list_(NULL), neighbours_list_(NULL) { @@ -44,13 +48,18 @@ LastFMService::LastFMService(QObject* parent) play_action_ = context_menu_->addAction(QIcon(":media-playback-start.png"), "Add to playlist", this, SLOT(AddToPlaylist())); context_menu_->addSeparator(); + add_artist_action_ = context_menu_->addAction(QIcon(":last.fm/icon_radio.png"), "Play artist radio...", this, SLOT(AddArtistRadio())); + add_tag_action_ = context_menu_->addAction(QIcon(":last.fm/icon_tag.png"), "Play tag radio...", this, SLOT(AddTagRadio())); context_menu_->addAction(QIcon(":configure.png"), "Configure Last.fm...", config_, SLOT(show())); + add_artist_action_->setEnabled(false); + add_tag_action_->setEnabled(false); } LastFMService::~LastFMService() { delete config_; + delete station_dialog_; delete context_menu_; } @@ -75,8 +84,6 @@ RadioItem* LastFMService::CreateRootItem(RadioItem* parent) { } void LastFMService::LazyPopulate(RadioItem *item) { - RadioItem* c = NULL; - switch (item->type) { case RadioItem::Type_Service: // Normal radio types @@ -85,16 +92,18 @@ void LastFMService::LazyPopulate(RadioItem *item) { CreateStationItem(Type_MyLoved, "My Loved Tracks", ":last.fm/loved_radio.png", item); CreateStationItem(Type_MyNeighbourhood, "My Neighbourhood", ":last.fm/neighbour_radio.png", item); - // Types that spawn a popup dialog - c = CreateStationItem(Type_ArtistRadio, "Artist radio...", - ":last.fm/icon_radio.png", item); - c->playable = false; - - c = CreateStationItem(Type_TagRadio, "Tag radio...", - ":last.fm/icon_tag.png", item); - c->playable = false; - // Types that have children + artist_list_ = new RadioItem(this, Type_ArtistRadio, "Artist radio", item); + artist_list_->icon = QIcon(":last.fm/icon_radio.png"); + artist_list_->lazy_loaded = true; + + tag_list_ = new RadioItem(this, Type_TagRadio, "Tag radio", item); + tag_list_->icon = QIcon(":last.fm/icon_tag.png"); + tag_list_->lazy_loaded = true; + + RestoreList("artists", Type_Artist, QIcon(":last.fm/icon_radio.png"), artist_list_); + RestoreList("tags", Type_Tag, QIcon(":last.fm/icon_tag.png"), tag_list_); + friends_list_ = new RadioItem(this, Type_MyFriends, "Friends", item); friends_list_->icon = QIcon(":last.fm/my_friends.png"); @@ -103,6 +112,9 @@ void LastFMService::LazyPopulate(RadioItem *item) { if (!IsAuthenticated()) config_->show(); + + add_artist_action_->setEnabled(true); + add_tag_action_->setEnabled(true); break; case Type_MyFriends: @@ -204,6 +216,12 @@ QUrl LastFMService::UrlForItem(const RadioItem* item) const { case Type_OtherUserNeighbourhood: return "lastfm://user/" + item->key + "/neighbours"; + + case Type_Artist: + return "lastfm://artist/" + item->key + "/similarartists"; + + case Type_Tag: + return "lastfm://globaltags/" + item->key; } return QUrl(); } @@ -220,6 +238,8 @@ QString LastFMService::TitleForItem(const RadioItem* item) const { case Type_OtherUserRadio: return item->key + "'s Library"; case Type_OtherUserLoved: return item->key + "'s Loved Tracks"; case Type_OtherUserNeighbourhood: return item->key + "'s Neighbour Radio"; + case Type_Artist: return "Similar artists to " + item->key; + case Type_Tag: return "Tag radio: " + item->key; } return QString(); } @@ -444,3 +464,62 @@ void LastFMService::RefreshNeighboursFinished() { void LastFMService::AddToPlaylist() { emit AddItemToPlaylist(context_item_); } + +void LastFMService::AddArtistRadio() { + AddArtistOrTag("artists", LastFMStationDialog::Artist, Type_Artist, QIcon(":last.fm/icon_radio.png"), artist_list_); +} + +void LastFMService::AddTagRadio() { + AddArtistOrTag("tags", LastFMStationDialog::Tag, Type_Tag, QIcon(":last.fm/icon_tag.png"), tag_list_); +} + +void LastFMService::AddArtistOrTag(const QString& name, + LastFMStationDialog::Type dialog_type, ItemType item_type, + const QIcon& icon, RadioItem* list) { + station_dialog_->SetType(dialog_type); + if (station_dialog_->exec() == QDialog::Rejected) + return; + + if (station_dialog_->content().isEmpty()) + return; + + RadioItem* item = new RadioItem(this, item_type, station_dialog_->content()); + item->icon = icon; + item->playable = true; + item->lazy_loaded = true; + item->InsertNotify(list); + emit AddItemToPlaylist(item); + + SaveList(name, list); +} + +void LastFMService::SaveList(const QString& name, RadioItem* list) const { + QSettings settings; + settings.beginGroup(kSettingsGroup); + + settings.beginWriteArray(name, list->children.count()); + for (int i=0 ; ichildren.count() ; ++i) { + settings.setArrayIndex(i); + settings.setValue("key", list->children[i]->key); + } + settings.endArray(); +} + +void LastFMService::RestoreList(const QString &name, ItemType item_type, + const QIcon& icon, RadioItem *list) { + QSettings settings; + settings.beginGroup(kSettingsGroup); + + list->ClearNotify(); + + int count = settings.beginReadArray(name); + for (int i=0 ; iicon = icon; + item->playable = true; + item->lazy_loaded = true; + } + settings.endArray(); +} diff --git a/src/lastfmservice.h b/src/lastfmservice.h index d72bc3a17..4a8097726 100644 --- a/src/lastfmservice.h +++ b/src/lastfmservice.h @@ -3,6 +3,7 @@ #include "radioservice.h" #include "song.h" +#include "lastfmstationdialog.h" #include @@ -37,6 +38,8 @@ class LastFMService : public RadioService { Type_OtherUserRadio, Type_OtherUserLoved, Type_OtherUserNeighbourhood, + Type_Artist, + Type_Tag, }; // RadioService @@ -80,6 +83,8 @@ class LastFMService : public RadioService { void TunerError(lastfm::ws::Error error); void AddToPlaylist(); + void AddArtistRadio(); + void AddTagRadio(); private: RadioItem* CreateStationItem(ItemType type, const QString& name, @@ -89,6 +94,12 @@ class LastFMService : public RadioService { lastfm::Track TrackFromSong(const Song& song) const; void RefreshFriends(); void RefreshNeighbours(); + void AddArtistOrTag(const QString& name, + LastFMStationDialog::Type dialog_type, ItemType item_type, + const QIcon& icon, RadioItem* list); + void SaveList(const QString& name, RadioItem* list) const; + void RestoreList(const QString &name, ItemType item_type, + const QIcon& icon, RadioItem *list); private: lastfm::RadioTuner* tuner_; @@ -96,9 +107,13 @@ class LastFMService : public RadioService { lastfm::Track last_track_; LastFMConfig* config_; + LastFMStationDialog* station_dialog_; QMenu* context_menu_; QAction* play_action_; + QAction* remove_action_; + QAction* add_artist_action_; + QAction* add_tag_action_; RadioItem* context_item_; QUrl last_url_; @@ -106,6 +121,8 @@ class LastFMService : public RadioService { bool scrobbling_enabled_; + RadioItem* artist_list_; + RadioItem* tag_list_; RadioItem* friends_list_; RadioItem* neighbours_list_; }; diff --git a/src/lastfmstationdialog.cpp b/src/lastfmstationdialog.cpp new file mode 100644 index 000000000..5575121bb --- /dev/null +++ b/src/lastfmstationdialog.cpp @@ -0,0 +1,18 @@ +#include "lastfmstationdialog.h" +#include "ui_lastfmstationdialog.h" + +LastFMStationDialog::LastFMStationDialog(QWidget* parent) + : QDialog(parent) +{ + ui_.setupUi(this); +} + +void LastFMStationDialog::SetType(Type type) { + ui_.type->setCurrentIndex(type); + ui_.content->clear(); + ui_.content->setFocus(Qt::OtherFocusReason); +} + +QString LastFMStationDialog::content() const { + return ui_.content->text(); +} diff --git a/src/lastfmstationdialog.h b/src/lastfmstationdialog.h new file mode 100644 index 000000000..7872a5544 --- /dev/null +++ b/src/lastfmstationdialog.h @@ -0,0 +1,26 @@ +#ifndef LASTFMSTATIONDIALOG_H +#define LASTFMSTATIONDIALOG_H + +#include + +#include "ui_lastfmstationdialog.h" + +class LastFMStationDialog : public QDialog { + Q_OBJECT + + public: + LastFMStationDialog(QWidget* parent = 0); + + enum Type { + Artist, + Tag, + }; + + void SetType(Type type); + QString content() const; + + private: + Ui::LastFMStationDialog ui_; +}; + +#endif // LASTFMSTATIONDIALOG_H diff --git a/src/lastfmstationdialog.ui b/src/lastfmstationdialog.ui new file mode 100644 index 000000000..846390359 --- /dev/null +++ b/src/lastfmstationdialog.ui @@ -0,0 +1,108 @@ + + + LastFMStationDialog + + + + 0 + 0 + 407 + 120 + + + + Play Artist or Tag + + + + + + Enter an <b>artist</b> or <b>tag</b> to start listening to Last.fm radio. + + + true + + + + + + + + + + Artist + + + + + Tag + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 7 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + LastFMStationDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + LastFMStationDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/src.pro b/src/src.pro index 3b15973eb..9351b4d3f 100644 --- a/src/src.pro +++ b/src/src.pro @@ -42,7 +42,8 @@ SOURCES += main.cpp \ busyindicator.cpp \ radioplaylistitem.cpp \ radioloadingindicator.cpp \ - radioview.cpp + radioview.cpp \ + lastfmstationdialog.cpp HEADERS += mainwindow.h \ player.h \ library.h \ @@ -84,12 +85,14 @@ HEADERS += mainwindow.h \ radiomimedata.h \ radioplaylistitem.h \ radioloadingindicator.h \ - radioview.h + radioview.h \ + lastfmstationdialog.h FORMS += mainwindow.ui \ libraryconfig.ui \ fileview.ui \ lastfmconfig.ui \ - radioloadingindicator.ui + radioloadingindicator.ui \ + lastfmstationdialog.ui RESOURCES += ../data/data.qrc OTHER_FILES += ../data/schema.sql \ ../data/mainwindow.css