feat: album/playlist header and playlist ownership filtering
- Add TrackContextHeader widget: shows album art (fetched via NAM), title, subtitle (artist/description), and metadata (year · tracks · duration) above the track list when an album or playlist is opened - Hide header for favorite tracks and search results - Store user ID in AppSettings on login - Only show "Delete playlist" for playlists the user owns - "Add to playlist" submenu only lists owned playlists - "Remove from this playlist" only appears when viewing an owned playlist Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ namespace List
|
||||
static constexpr int TypeRole = Qt::UserRole + 1;
|
||||
static constexpr int IdRole = Qt::UserRole + 2;
|
||||
static constexpr int NameRole = Qt::UserRole + 3;
|
||||
static constexpr int IsOwnerRole = Qt::UserRole + 4;
|
||||
|
||||
enum NodeType {
|
||||
NodeFavTracks,
|
||||
@@ -86,22 +87,28 @@ void Library::onUserPlaylistsLoaded(const QJsonObject &result)
|
||||
while (m_playlistsNode->childCount() > 0)
|
||||
delete m_playlistsNode->takeChild(0);
|
||||
|
||||
QVector<QPair<qint64, QString>> playlists;
|
||||
QVector<QPair<qint64, QString>> editablePlaylists;
|
||||
const qint64 myUserId = AppSettings::instance().userId();
|
||||
const QJsonArray items = result["items"].toArray();
|
||||
for (const auto &v : items) {
|
||||
const QJsonObject pl = v.toObject();
|
||||
const QString name = pl["name"].toString();
|
||||
const qint64 id = static_cast<qint64>(pl["id"].toDouble());
|
||||
const QJsonObject pl = v.toObject();
|
||||
const QString name = pl["name"].toString();
|
||||
const qint64 id = static_cast<qint64>(pl["id"].toDouble());
|
||||
const qint64 ownId = static_cast<qint64>(pl["owner"].toObject()["id"].toDouble());
|
||||
const bool isOwner = (myUserId > 0 && ownId == myUserId);
|
||||
|
||||
auto *item = new QTreeWidgetItem(m_playlistsNode, QStringList{name});
|
||||
item->setData(0, TypeRole, NodePlaylist);
|
||||
item->setData(0, IdRole, id);
|
||||
item->setData(0, NameRole, name);
|
||||
item->setData(0, TypeRole, NodePlaylist);
|
||||
item->setData(0, IdRole, id);
|
||||
item->setData(0, NameRole, name);
|
||||
item->setData(0, IsOwnerRole, isOwner);
|
||||
|
||||
playlists.append({id, name});
|
||||
// Only include playlists we can edit in the "Add to playlist" submenu
|
||||
if (isOwner)
|
||||
editablePlaylists.append({id, name});
|
||||
}
|
||||
|
||||
emit userPlaylistsChanged(playlists);
|
||||
emit userPlaylistsChanged(editablePlaylists);
|
||||
}
|
||||
|
||||
void Library::onContextMenuRequested(const QPoint &pos)
|
||||
@@ -128,21 +135,24 @@ void Library::onContextMenuRequested(const QPoint &pos)
|
||||
});
|
||||
|
||||
if (isPlaylistItem) {
|
||||
const qint64 plId = item->data(0, IdRole).toLongLong();
|
||||
const QString plName = item->data(0, NameRole).toString();
|
||||
const qint64 plId = item->data(0, IdRole).toLongLong();
|
||||
const QString plName = item->data(0, NameRole).toString();
|
||||
const bool isOwner = item->data(0, IsOwnerRole).toBool();
|
||||
|
||||
menu.addSeparator();
|
||||
auto *delPl = menu.addAction(tr("Delete \"%1\"…").arg(plName));
|
||||
connect(delPl, &QAction::triggered, this, [this, plId, plName] {
|
||||
const auto answer = QMessageBox::question(
|
||||
this,
|
||||
tr("Delete Playlist"),
|
||||
tr("Permanently delete \"%1\"? This cannot be undone.").arg(plName),
|
||||
QMessageBox::Yes | QMessageBox::Cancel,
|
||||
QMessageBox::Cancel);
|
||||
if (answer == QMessageBox::Yes)
|
||||
m_backend->deletePlaylist(plId);
|
||||
});
|
||||
if (isOwner) {
|
||||
menu.addSeparator();
|
||||
auto *delPl = menu.addAction(tr("Delete \"%1\"…").arg(plName));
|
||||
connect(delPl, &QAction::triggered, this, [this, plId, plName] {
|
||||
const auto answer = QMessageBox::question(
|
||||
this,
|
||||
tr("Delete Playlist"),
|
||||
tr("Permanently delete \"%1\"? This cannot be undone.").arg(plName),
|
||||
QMessageBox::Yes | QMessageBox::Cancel,
|
||||
QMessageBox::Cancel);
|
||||
if (answer == QMessageBox::Yes)
|
||||
m_backend->deletePlaylist(plId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
menu.exec(viewport()->mapToGlobal(pos));
|
||||
|
||||
Reference in New Issue
Block a user