diff --git a/src/list/tracks.cpp b/src/list/tracks.cpp index e9d0118..94835bd 100644 --- a/src/list/tracks.cpp +++ b/src/list/tracks.cpp @@ -347,7 +347,7 @@ void Tracks::onContextMenu(const QPoint &pos) m_model->data(index, TrackListModel::PlaylistTrackIdRole).toLongLong(); if (playlistTrackId > 0) { if (m_userPlaylists.isEmpty()) menu.addSeparator(); - auto *remFromPl = menu.addAction(tr("Remove from this playlist")); + auto *remFromPl = menu.addAction(QIcon(":/res/icons/list-remove.svg"), tr("Remove from this playlist")); const qint64 curPlaylistId = m_playlistId; const int curRow = index.row(); connect(remFromPl, &QAction::triggered, this, [this, curPlaylistId, playlistTrackId, curRow] { diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 8d106d4..fbe2474 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -347,6 +347,15 @@ void MainWindow::connectToolbarSignals() connect(m_toolBar, &MainToolBar::albumRequested, this, &MainWindow::onSearchAlbumSelected); connect(m_toolBar, &MainToolBar::artistRequested, this, &MainWindow::onSearchArtistSelected); + connect(m_toolBar, &MainToolBar::addToPlaylistRequested, + this, [this](qint64 trackId, qint64 playlistId) { + m_backend->addTrackToPlaylist(playlistId, trackId); + statusBar()->showMessage(tr("Adding track to playlist…"), 3000); + }); + connect(m_toolBar, &MainToolBar::favTrackRequested, + this, [this](qint64 trackId) { + m_backend->addFavTrack(trackId); + }); } void MainWindow::setupMenuBar() @@ -629,4 +638,5 @@ void MainWindow::onUserPlaylistsChanged(const QVector> &p m_userPlaylists = playlists; m_content->tracksList()->setUserPlaylists(playlists); m_sidePanel->searchTab()->setUserPlaylists(playlists); + m_toolBar->setUserPlaylists(playlists); } diff --git a/src/view/genrebrowser.cpp b/src/view/genrebrowser.cpp index 48ee078..b622581 100644 --- a/src/view/genrebrowser.cpp +++ b/src/view/genrebrowser.cpp @@ -723,16 +723,28 @@ void GenreBrowserView::onAlbumContextMenu(const QPoint &pos) const QString albumId = item->data(1, Qt::UserRole).toString(); const qint64 artistId = item->data(2, Qt::UserRole).toLongLong(); + const QString albumTitle = item->text(1); + const QString artistName = item->text(2); QMenu menu(this); - auto *openAlbum = menu.addAction(tr("Open Album")); + auto *openAlbum = menu.addAction( + QIcon(":/res/icons/view-media-album-cover.svg"), + tr("Open album: %1").arg(QString(albumTitle).replace(QLatin1Char('&'), QStringLiteral("&&")))); connect(openAlbum, &QAction::triggered, this, [this, albumId] { emit albumSelected(albumId); }); + auto *addFav = menu.addAction(QIcon(":/res/icons/starred-symbolic.svg"), tr("Add to favorites")); + connect(addFav, &QAction::triggered, this, [this, albumId] { + m_backend->addFavAlbum(albumId); + }); + if (artistId > 0) { - auto *openArtist = menu.addAction(tr("Open Artist")); + menu.addSeparator(); + auto *openArtist = menu.addAction( + QIcon(":/res/icons/view-media-artist.svg"), + tr("Open artist: %1").arg(QString(artistName).replace(QLatin1Char('&'), QStringLiteral("&&")))); connect(openArtist, &QAction::triggered, this, [this, artistId] { emit artistSelected(artistId); }); @@ -762,7 +774,8 @@ void GenreBrowserView::onPlaylistContextMenu(const QPoint &pos) return; QMenu menu(this); - auto *openPlaylist = menu.addAction(tr("Open Playlist")); + auto *openPlaylist = menu.addAction( + QIcon(":/res/icons/view-media-playlist.svg"), tr("Open playlist")); connect(openPlaylist, &QAction::triggered, this, [this, playlistId] { emit playlistSelected(playlistId); }); diff --git a/src/view/maintoolbar.cpp b/src/view/maintoolbar.cpp index ee691b3..e08bad3 100644 --- a/src/view/maintoolbar.cpp +++ b/src/view/maintoolbar.cpp @@ -41,16 +41,63 @@ MainToolBar::MainToolBar(QobuzBackend *backend, PlayQueue *queue, QWidget *paren connect(m_trackLabel, &QLabel::customContextMenuRequested, this, [this](const QPoint &pos) { if (m_currentTrack.isEmpty()) return; - QMenu menu(this); + + const qint64 trackId = static_cast(m_currentTrack["id"].toDouble()); const QString albumId = m_currentTrack["album"].toObject()["id"].toString(); + const QString albumTitle = m_currentTrack["album"].toObject()["title"].toString(); const qint64 artistId = static_cast( m_currentTrack["performer"].toObject()["id"].toDouble()); - if (!albumId.isEmpty()) - menu.addAction(tr("Go to Album"), this, [this, albumId] { emit albumRequested(albumId); }); - if (artistId > 0) - menu.addAction(tr("Go to Artist"), this, [this, artistId] { emit artistRequested(artistId); }); - if (!menu.isEmpty()) - menu.exec(m_trackLabel->mapToGlobal(pos)); + const QString artistName = m_currentTrack["performer"].toObject()["name"].toString(); + + QMenu menu(this); + + auto *playNext = menu.addAction(QIcon(":/res/icons/media-skip-forward.svg"), tr("Play next")); + auto *addQueue = menu.addAction(QIcon(":/res/icons/media-playlist-append.svg"), tr("Add to queue")); + menu.addSeparator(); + + auto *addFav = menu.addAction(QIcon(":/res/icons/starred-symbolic.svg"), tr("Add to favorites")); + connect(addFav, &QAction::triggered, this, [this, trackId] { + emit favTrackRequested(trackId); + }); + + if (!albumId.isEmpty() || artistId > 0) + menu.addSeparator(); + if (!albumId.isEmpty()) { + auto *openAlbum = menu.addAction( + QIcon(":/res/icons/view-media-album-cover.svg"), + tr("Open album: %1").arg(QString(albumTitle).replace(QLatin1Char('&'), QStringLiteral("&&")))); + connect(openAlbum, &QAction::triggered, this, [this, albumId] { + emit albumRequested(albumId); + }); + } + if (artistId > 0) { + auto *openArtist = menu.addAction( + QIcon(":/res/icons/view-media-artist.svg"), + tr("Open artist: %1").arg(QString(artistName).replace(QLatin1Char('&'), QStringLiteral("&&")))); + connect(openArtist, &QAction::triggered, this, [this, artistId] { + emit artistRequested(artistId); + }); + } + + if (!m_userPlaylists.isEmpty()) { + menu.addSeparator(); + auto *plMenu = menu.addMenu(QIcon(":/res/icons/media-playlist-append.svg"), tr("Add to playlist")); + for (const auto &pl : m_userPlaylists) { + auto *act = plMenu->addAction(QString(pl.second).replace(QLatin1Char('&'), QStringLiteral("&&"))); + connect(act, &QAction::triggered, this, [this, trackId, plId = pl.first] { + emit addToPlaylistRequested(trackId, plId); + }); + } + } + + connect(playNext, &QAction::triggered, this, [this] { + m_queue->playNext(m_currentTrack); + }); + connect(addQueue, &QAction::triggered, this, [this] { + m_queue->addToQueue(m_currentTrack); + }); + + menu.exec(m_trackLabel->mapToGlobal(pos)); }); addSeparator(); diff --git a/src/view/maintoolbar.hpp b/src/view/maintoolbar.hpp index cbaa950..3e3f4d2 100644 --- a/src/view/maintoolbar.hpp +++ b/src/view/maintoolbar.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include class MainToolBar : public QToolBar @@ -27,11 +28,15 @@ public: void setQueueToggleChecked(bool checked); void setSearchToggleChecked(bool checked); + void setUserPlaylists(const QVector> &playlists) { m_userPlaylists = playlists; } + signals: void searchToggled(bool visible); void queueToggled(bool visible); void albumRequested(const QString &albumId); void artistRequested(qint64 artistId); + void addToPlaylistRequested(qint64 trackId, qint64 playlistId); + void favTrackRequested(qint64 trackId); protected: void resizeEvent(QResizeEvent *event) override; @@ -93,5 +98,7 @@ private: qint64 m_pendingSeekStartedMs = 0; bool m_fetchingAutoplay = false; + QVector> m_userPlaylists; + void requestAutoplaySuggestions(); }; diff --git a/src/view/queuepanel.cpp b/src/view/queuepanel.cpp index 0722deb..5a4a478 100644 --- a/src/view/queuepanel.cpp +++ b/src/view/queuepanel.cpp @@ -225,8 +225,8 @@ void QueuePanel::onContextMenu(const QPoint &pos) const int idx = item->data(UpcomingIndexRole).toInt(); QMenu menu(this); - auto *removeAct = menu.addAction(tr("Remove from queue")); - auto *toTopAct = menu.addAction(tr("Move to top (play next)")); + auto *removeAct = menu.addAction(QIcon(":/res/icons/list-remove.svg"), tr("Remove from queue")); + auto *toTopAct = menu.addAction(QIcon(":/res/icons/go-up.svg"), tr("Move to top (play next)")); connect(removeAct, &QAction::triggered, this, [this, idx] { m_queue->removeUpcoming(idx); }); connect(toTopAct, &QAction::triggered, this, [this, idx] { m_queue->moveUpcomingToTop(idx); }); diff --git a/src/view/sidepanel/view.cpp b/src/view/sidepanel/view.cpp index c864fb8..5fb4097 100644 --- a/src/view/sidepanel/view.cpp +++ b/src/view/sidepanel/view.cpp @@ -241,12 +241,15 @@ void SearchTab::onTrackContextMenu(const QPoint &pos) QMenu menu(this); - auto *playNow = menu.addAction(tr("Play now")); - auto *playNext = menu.addAction(tr("Play next")); - auto *addQueue = menu.addAction(tr("Add to queue")); + auto *playNow = menu.addAction(QIcon(":/res/icons/media-playback-start.svg"), tr("Play now")); + auto *playNext = menu.addAction(QIcon(":/res/icons/media-skip-forward.svg"), tr("Play next")); + auto *addQueue = menu.addAction(QIcon(":/res/icons/media-playlist-append.svg"), tr("Add to queue")); menu.addSeparator(); - auto *addFav = menu.addAction(tr("Add to favorites")); + auto *favAction = menu.addAction(QIcon(":/res/icons/starred-symbolic.svg"), tr("Add to favorites")); + connect(favAction, &QAction::triggered, this, [this, trackId] { + m_backend->addFavTrack(trackId); + }); // Open album / artist const QString albumId = trackJson["album"].toObject()["id"].toString(); @@ -255,15 +258,20 @@ void SearchTab::onTrackContextMenu(const QPoint &pos) const QString artistName = trackJson["performer"].toObject()["name"].toString(); const QString albumTitle = trackJson["album"].toObject()["title"].toString(); - menu.addSeparator(); + if (!albumId.isEmpty() || artistId > 0) + menu.addSeparator(); if (!albumId.isEmpty()) { - auto *openAlbum = menu.addAction(tr("Go to album: %1").arg(QString(albumTitle).replace(QLatin1Char('&'), QStringLiteral("&&")))); + auto *openAlbum = menu.addAction( + QIcon(":/res/icons/view-media-album-cover.svg"), + tr("Open album: %1").arg(QString(albumTitle).replace(QLatin1Char('&'), QStringLiteral("&&")))); connect(openAlbum, &QAction::triggered, this, [this, albumId] { emit albumSelected(albumId); }); } if (artistId > 0) { - auto *openArtist = menu.addAction(tr("Go to artist: %1").arg(QString(artistName).replace(QLatin1Char('&'), QStringLiteral("&&")))); + auto *openArtist = menu.addAction( + QIcon(":/res/icons/view-media-artist.svg"), + tr("Open artist: %1").arg(QString(artistName).replace(QLatin1Char('&'), QStringLiteral("&&")))); connect(openArtist, &QAction::triggered, this, [this, artistId] { emit artistSelected(artistId); }); @@ -272,9 +280,9 @@ void SearchTab::onTrackContextMenu(const QPoint &pos) // Add to playlist submenu if (!m_userPlaylists.isEmpty()) { menu.addSeparator(); - auto *plMenu = menu.addMenu(tr("Add to playlist")); + auto *plMenu = menu.addMenu(QIcon(":/res/icons/media-playlist-append.svg"), tr("Add to playlist")); for (const auto &pl : m_userPlaylists) { - auto *act = plMenu->addAction(pl.second); + auto *act = plMenu->addAction(QString(pl.second).replace(QLatin1Char('&'), QStringLiteral("&&"))); connect(act, &QAction::triggered, this, [this, trackId, plId = pl.first] { emit addToPlaylistRequested(trackId, plId); }); @@ -294,9 +302,6 @@ void SearchTab::onTrackContextMenu(const QPoint &pos) connect(addQueue, &QAction::triggered, this, [this, trackJson] { m_queue->addToQueue(trackJson); }); - connect(addFav, &QAction::triggered, this, [this, trackId] { - m_backend->addFavTrack(trackId); - }); connect(info, &QAction::triggered, this, [this, trackJson] { showTrackInfo(trackJson); }); @@ -315,15 +320,17 @@ void SearchTab::onAlbumContextMenu(const QPoint &pos) QMenu menu(this); - auto *openAlbum = menu.addAction(tr("Open album")); - auto *addFav = menu.addAction(tr("Add to favorites")); + auto *openAlbum = menu.addAction(QIcon(":/res/icons/view-media-album-cover.svg"), tr("Open album")); + auto *addFav = menu.addAction(QIcon(":/res/icons/starred-symbolic.svg"), tr("Add to favorites")); const qint64 artistId = static_cast( albumJson["artist"].toObject()["id"].toDouble()); const QString artistName = albumJson["artist"].toObject()["name"].toString(); if (artistId > 0) { menu.addSeparator(); - auto *openArtist = menu.addAction(tr("Go to artist: %1").arg(QString(artistName).replace(QLatin1Char('&'), QStringLiteral("&&")))); + auto *openArtist = menu.addAction( + QIcon(":/res/icons/view-media-artist.svg"), + tr("Open artist: %1").arg(QString(artistName).replace(QLatin1Char('&'), QStringLiteral("&&")))); connect(openArtist, &QAction::triggered, this, [this, artistId] { emit artistSelected(artistId); });