Double-click on radio items to play
This commit is contained in:
parent
939e4b5264
commit
92db175819
1
TODO
1
TODO
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
Last.fm:
|
Last.fm:
|
||||||
- Artist/tag/etc. radio
|
- Artist/tag/etc. radio
|
||||||
- Double click from radio list
|
|
||||||
- More types of radio
|
- More types of radio
|
||||||
|
|
||||||
Long-term:
|
Long-term:
|
||||||
|
|
|
@ -145,34 +145,33 @@ void LastFMService::AuthenticateReplyFinished() {
|
||||||
emit AuthenticationComplete(true);
|
emit AuthenticationComplete(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<RadioItem::PlaylistData> LastFMService::DataForItem(RadioItem* item) {
|
QUrl LastFMService::UrlForItem(const RadioItem* item) const {
|
||||||
QList<RadioItem::PlaylistData> ret;
|
switch (item->type) {
|
||||||
|
case Type_MyRecommendations:
|
||||||
|
return "lastfm://user/" + lastfm::ws::Username + "/recommended";
|
||||||
|
|
||||||
|
case Type_MyLoved:
|
||||||
|
return "lastfm://user/" + lastfm::ws::Username + "/loved";
|
||||||
|
|
||||||
|
case Type_MyNeighbourhood:
|
||||||
|
return "lastfm://user/" + lastfm::ws::Username + "/neighbours";
|
||||||
|
|
||||||
|
case Type_MyRadio:
|
||||||
|
return "lastfm://user/" + lastfm::ws::Username + "/library";
|
||||||
|
}
|
||||||
|
return QUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LastFMService::TitleForItem(const RadioItem* item) const {
|
||||||
const QString user(lastfm::ws::Username);
|
const QString user(lastfm::ws::Username);
|
||||||
|
|
||||||
switch (item->type) {
|
switch (item->type) {
|
||||||
case Type_MyRecommendations:
|
case Type_MyRecommendations: return user + "'s Recommended Radio";
|
||||||
ret << RadioItem::PlaylistData(user + "'s Recommended Radio",
|
case Type_MyLoved: return user + "'s Loved Tracks";
|
||||||
"lastfm://user/" + lastfm::ws::Username + "/recommended");
|
case Type_MyNeighbourhood: return user + "'s Neighbour Radio";
|
||||||
break;
|
case Type_MyRadio: return user + "'s Library";
|
||||||
|
|
||||||
case Type_MyLoved:
|
|
||||||
ret << RadioItem::PlaylistData(user + "'s Loved Tracks",
|
|
||||||
"lastfm://user/" + lastfm::ws::Username + "/loved");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Type_MyNeighbourhood:
|
|
||||||
ret << RadioItem::PlaylistData(user + "'s Neighbour Radio",
|
|
||||||
"lastfm://user/" + lastfm::ws::Username + "/neighbours");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Type_MyRadio:
|
|
||||||
ret << RadioItem::PlaylistData(user + "'s Library",
|
|
||||||
"lastfm://user/" + lastfm::ws::Username + "/library");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
return QString();
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LastFMService::StartLoading(const QUrl& url) {
|
void LastFMService::StartLoading(const QUrl& url) {
|
||||||
|
|
|
@ -33,13 +33,19 @@ class LastFMService : public RadioService {
|
||||||
// RadioService
|
// RadioService
|
||||||
RadioItem* CreateRootItem(RadioItem* parent);
|
RadioItem* CreateRootItem(RadioItem* parent);
|
||||||
void LazyPopulate(RadioItem *item);
|
void LazyPopulate(RadioItem *item);
|
||||||
QList<RadioItem::PlaylistData> DataForItem(RadioItem* item);
|
|
||||||
|
QUrl UrlForItem(const RadioItem* item) const;
|
||||||
|
QString TitleForItem(const RadioItem* item) const;
|
||||||
|
|
||||||
void ShowContextMenu(RadioItem *item, const QPoint &global_pos);
|
void ShowContextMenu(RadioItem *item, const QPoint &global_pos);
|
||||||
|
|
||||||
void StartLoading(const QUrl& url);
|
void StartLoading(const QUrl& url);
|
||||||
void LoadNext(const QUrl& url);
|
void LoadNext(const QUrl& url);
|
||||||
|
|
||||||
bool IsPauseAllowed() const { return false; }
|
bool IsPauseAllowed() const { return false; }
|
||||||
bool ShowLastFmControls() const { return true; }
|
bool ShowLastFmControls() const { return true; }
|
||||||
|
|
||||||
|
// Last.fm specific stuff
|
||||||
bool IsAuthenticated() const;
|
bool IsAuthenticated() const;
|
||||||
bool IsScrobblingEnabled() const { return scrobbling_enabled_; }
|
bool IsScrobblingEnabled() const { return scrobbling_enabled_; }
|
||||||
void Authenticate(const QString& username, const QString& password);
|
void Authenticate(const QString& username, const QString& password);
|
||||||
|
|
|
@ -157,6 +157,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
connect(radio_model_, SIGNAL(StreamReady(QUrl,QUrl)), player_, SLOT(StreamReady(QUrl,QUrl)));
|
connect(radio_model_, SIGNAL(StreamReady(QUrl,QUrl)), player_, SLOT(StreamReady(QUrl,QUrl)));
|
||||||
connect(radio_model_, SIGNAL(StreamMetadataFound(QUrl,Song)), playlist_, SLOT(SetStreamMetadata(QUrl,Song)));
|
connect(radio_model_, SIGNAL(StreamMetadataFound(QUrl,Song)), playlist_, SLOT(SetStreamMetadata(QUrl,Song)));
|
||||||
connect(radio_model_->GetLastFMService(), SIGNAL(ScrobblingEnabledChanged(bool)), SLOT(ScrobblingEnabledChanged(bool)));
|
connect(radio_model_->GetLastFMService(), SIGNAL(ScrobblingEnabledChanged(bool)), SLOT(ScrobblingEnabledChanged(bool)));
|
||||||
|
connect(ui_.radio_view, SIGNAL(doubleClicked(QModelIndex)), SLOT(RadioDoubleClick(QModelIndex)));
|
||||||
|
|
||||||
// Tray icon
|
// Tray icon
|
||||||
QMenu* tray_menu = new QMenu(this);
|
QMenu* tray_menu = new QMenu(this);
|
||||||
|
@ -360,3 +361,11 @@ void MainWindow::Love() {
|
||||||
radio_model_->GetLastFMService()->Love();
|
radio_model_->GetLastFMService()->Love();
|
||||||
ui_.action_love->setEnabled(false);
|
ui_.action_love->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::RadioDoubleClick(const QModelIndex& index) {
|
||||||
|
QModelIndex first_song = playlist_->InsertRadioStations(
|
||||||
|
QList<RadioItem*>() << radio_model_->IndexToItem(index));
|
||||||
|
|
||||||
|
if (first_song.isValid() && player_->GetState() != Engine::Playing)
|
||||||
|
player_->PlayAt(first_song.row());
|
||||||
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ class MainWindow : public QMainWindow {
|
||||||
|
|
||||||
void UpdateTrackPosition();
|
void UpdateTrackPosition();
|
||||||
|
|
||||||
|
void RadioDoubleClick(const QModelIndex& index);
|
||||||
void ScrobblingEnabledChanged(bool value);
|
void ScrobblingEnabledChanged(bool value);
|
||||||
void Love();
|
void Love();
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,7 @@ bool Playlist::dropMimeData(const QMimeData* data, Qt::DropAction action, int ro
|
||||||
InsertSongs(song_data->songs, row);
|
InsertSongs(song_data->songs, row);
|
||||||
} else if (const RadioMimeData* radio_data = qobject_cast<const RadioMimeData*>(data)) {
|
} else if (const RadioMimeData* radio_data = qobject_cast<const RadioMimeData*>(data)) {
|
||||||
// Dragged from the Radio pane
|
// Dragged from the Radio pane
|
||||||
InsertRadioStations(radio_data->services, radio_data->urls(), radio_data->titles, row);
|
InsertRadioStations(radio_data->items, row);
|
||||||
} else if (data->hasFormat(kRowsMimetype)) {
|
} else if (data->hasFormat(kRowsMimetype)) {
|
||||||
// Dragged from the playlist
|
// Dragged from the playlist
|
||||||
// Rearranging it is tricky...
|
// Rearranging it is tricky...
|
||||||
|
@ -245,17 +245,15 @@ QModelIndex Playlist::InsertSongs(const SongList& songs, int after) {
|
||||||
return InsertItems(items, after);
|
return InsertItems(items, after);
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex Playlist::InsertRadioStations(const QList<RadioService*>& services,
|
QModelIndex Playlist::InsertRadioStations(const QList<RadioItem*>& items, int after) {
|
||||||
const QList<QUrl>& urls,
|
QList<PlaylistItem*> playlist_items;
|
||||||
const QStringList& titles, int after) {
|
foreach (RadioItem* item, items) {
|
||||||
Q_ASSERT(services.count() == urls.count());
|
if (!item->playable)
|
||||||
Q_ASSERT(services.count() == titles.count());
|
continue;
|
||||||
|
|
||||||
QList<PlaylistItem*> items;
|
playlist_items << new RadioPlaylistItem(item->service, item->Url(), item->Title());
|
||||||
for (int i=0 ; i<services.count() ; ++i) {
|
|
||||||
items << new RadioPlaylistItem(services[i], urls[i], titles[i]);
|
|
||||||
}
|
}
|
||||||
return InsertItems(items, after);
|
return InsertItems(playlist_items, after);
|
||||||
}
|
}
|
||||||
|
|
||||||
QMimeData* Playlist::mimeData(const QModelIndexList& indexes) const {
|
QMimeData* Playlist::mimeData(const QModelIndexList& indexes) const {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "playlistitem.h"
|
#include "playlistitem.h"
|
||||||
#include "song.h"
|
#include "song.h"
|
||||||
|
#include "radioitem.h"
|
||||||
|
|
||||||
class RadioService;
|
class RadioService;
|
||||||
|
|
||||||
|
@ -62,9 +63,7 @@ class Playlist : public QAbstractListModel {
|
||||||
// Changing the playlist
|
// Changing the playlist
|
||||||
QModelIndex InsertItems(const QList<PlaylistItem*>& items, int after = -1);
|
QModelIndex InsertItems(const QList<PlaylistItem*>& items, int after = -1);
|
||||||
QModelIndex InsertSongs(const SongList& items, int after = -1);
|
QModelIndex InsertSongs(const SongList& items, int after = -1);
|
||||||
QModelIndex InsertRadioStations(const QList<RadioService*>& services,
|
QModelIndex InsertRadioStations(const QList<RadioItem*>& items, int after = -1);
|
||||||
const QList<QUrl>& urls,
|
|
||||||
const QStringList& titles, int after = -1);
|
|
||||||
QModelIndex InsertPaths(QList<QUrl> urls, int after = -1);
|
QModelIndex InsertPaths(QList<QUrl> urls, int after = -1);
|
||||||
void StopAfter(int row);
|
void StopAfter(int row);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "radioitem.h"
|
#include "radioitem.h"
|
||||||
|
#include "radioservice.h"
|
||||||
|
|
||||||
RadioItem::RadioItem(RadioService* _service, int type, const QString& key,
|
RadioItem::RadioItem(RadioService* _service, int type, const QString& key,
|
||||||
RadioItem* parent)
|
RadioItem* parent)
|
||||||
|
@ -7,3 +8,11 @@ RadioItem::RadioItem(RadioService* _service, int type, const QString& key,
|
||||||
playable(false)
|
playable(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QUrl RadioItem::Url() const {
|
||||||
|
return service->UrlForItem(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString RadioItem::Title() const {
|
||||||
|
return service->TitleForItem(this);
|
||||||
|
}
|
||||||
|
|
|
@ -15,16 +15,12 @@ class RadioItem : public SimpleTreeItem<RadioItem> {
|
||||||
Type_Service,
|
Type_Service,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PlaylistData {
|
|
||||||
PlaylistData(const QString& _title, const QUrl& _url) : title(_title), url(_url) {}
|
|
||||||
|
|
||||||
QString title;
|
|
||||||
QUrl url;
|
|
||||||
};
|
|
||||||
|
|
||||||
RadioItem(RadioService* _service, int type, const QString& key = QString::null,
|
RadioItem(RadioService* _service, int type, const QString& key = QString::null,
|
||||||
RadioItem* parent = NULL);
|
RadioItem* parent = NULL);
|
||||||
|
|
||||||
|
QUrl Url() const;
|
||||||
|
QString Title() const;
|
||||||
|
|
||||||
QIcon icon;
|
QIcon icon;
|
||||||
RadioService* service;
|
RadioService* service;
|
||||||
bool playable;
|
bool playable;
|
||||||
|
|
|
@ -3,14 +3,13 @@
|
||||||
|
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
|
|
||||||
class RadioService;
|
class RadioItem;
|
||||||
|
|
||||||
class RadioMimeData : public QMimeData {
|
class RadioMimeData : public QMimeData {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QList<RadioService*> services;
|
QList<RadioItem*> items;
|
||||||
QList<QString> titles;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RADIOMIMEDATA_H
|
#endif // RADIOMIMEDATA_H
|
||||||
|
|
|
@ -85,20 +85,15 @@ QStringList RadioModel::mimeTypes() const {
|
||||||
|
|
||||||
QMimeData* RadioModel::mimeData(const QModelIndexList& indexes) const {
|
QMimeData* RadioModel::mimeData(const QModelIndexList& indexes) const {
|
||||||
QList<QUrl> urls;
|
QList<QUrl> urls;
|
||||||
QList<RadioService*> services;
|
QList<RadioItem*> items;
|
||||||
QStringList titles;
|
|
||||||
|
|
||||||
foreach (const QModelIndex& index, indexes) {
|
foreach (const QModelIndex& index, indexes) {
|
||||||
RadioItem* item = IndexToItem(index);
|
RadioItem* item = IndexToItem(index);
|
||||||
if (!item || !item->service || !item->playable)
|
if (!item || !item->service || !item->playable)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
QList<RadioItem::PlaylistData> item_data(item->service->DataForItem(item));
|
items << item;
|
||||||
foreach (const RadioItem::PlaylistData& data, item_data) {
|
urls << item->service->UrlForItem(item);
|
||||||
urls << data.url;
|
|
||||||
services << item->service;
|
|
||||||
titles << data.title;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (urls.isEmpty())
|
if (urls.isEmpty())
|
||||||
|
@ -106,8 +101,7 @@ QMimeData* RadioModel::mimeData(const QModelIndexList& indexes) const {
|
||||||
|
|
||||||
RadioMimeData* data = new RadioMimeData;
|
RadioMimeData* data = new RadioMimeData;
|
||||||
data->setUrls(urls);
|
data->setUrls(urls);
|
||||||
data->services = services;
|
data->items = items;
|
||||||
data->titles = titles;
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,9 @@ class RadioService : public QObject {
|
||||||
virtual RadioItem* CreateRootItem(RadioItem* parent) = 0;
|
virtual RadioItem* CreateRootItem(RadioItem* parent) = 0;
|
||||||
virtual void LazyPopulate(RadioItem* item) = 0;
|
virtual void LazyPopulate(RadioItem* item) = 0;
|
||||||
|
|
||||||
virtual QList<RadioItem::PlaylistData> DataForItem(RadioItem* item) = 0;
|
virtual QUrl UrlForItem(const RadioItem* item) const = 0;
|
||||||
|
virtual QString TitleForItem(const RadioItem* item) const = 0;
|
||||||
|
|
||||||
virtual void ShowContextMenu(RadioItem* item, const QPoint& global_pos) {
|
virtual void ShowContextMenu(RadioItem* item, const QPoint& global_pos) {
|
||||||
Q_UNUSED(item); Q_UNUSED(global_pos); }
|
Q_UNUSED(item); Q_UNUSED(global_pos); }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue