refactor: reduce duplication and replace magic stack indices
- Extract parseTrackItem() static helper in TrackListModel to eliminate ~45 lines of duplicated JSON parsing between setTracks() and appendTracks() - Extract notifyFavChanged() helper to deduplicate addFavId/removeFavId loops - Add StackPage enum to MainContent replacing magic integers 0-5 with named constants (PageWelcome, PageTracks, PageAlbumList, etc.) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,56 @@ TrackListModel::TrackListModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{}
|
||||
|
||||
TrackItem TrackListModel::parseTrackItem(const QJsonObject &t,
|
||||
bool usePosition,
|
||||
bool useSequential,
|
||||
int &seq)
|
||||
{
|
||||
TrackItem item;
|
||||
item.id = static_cast<qint64>(t["id"].toDouble());
|
||||
item.playlistTrackId = static_cast<qint64>(t["playlist_track_id"].toDouble());
|
||||
item.discNumber = t["media_number"].toInt(1);
|
||||
item.duration = static_cast<qint64>(t["duration"].toDouble());
|
||||
item.streamable = t["streamable"].toBool(true);
|
||||
item.hiRes = t["hires_streamable"].toBool();
|
||||
item.raw = t;
|
||||
|
||||
// Combine title + version ("Melody" + "Vocal Remix" → "Melody (Vocal Remix)")
|
||||
const QString base = t["title"].toString();
|
||||
const QString version = t["version"].toString().trimmed();
|
||||
item.title = version.isEmpty() ? base
|
||||
: base + QStringLiteral(" (") + version + QLatin1Char(')');
|
||||
|
||||
if (useSequential) {
|
||||
item.number = seq++;
|
||||
} else if (usePosition) {
|
||||
const int pos = t["position"].toInt();
|
||||
item.number = pos > 0 ? pos : seq;
|
||||
++seq;
|
||||
} else {
|
||||
item.number = t["track_number"].toInt();
|
||||
}
|
||||
|
||||
const QJsonObject performer = t["performer"].toObject();
|
||||
item.artist = performer["name"].toString();
|
||||
if (item.artist.isEmpty()) {
|
||||
// album.artist.name may be a plain string or {display:"..."} object
|
||||
const QJsonValue n = t["album"].toObject()["artist"].toObject()["name"];
|
||||
item.artist = n.isObject() ? n.toObject()["display"].toString() : n.toString();
|
||||
}
|
||||
if (item.artist.isEmpty()) {
|
||||
// top_tracks format: artist.name.display
|
||||
const QJsonValue n = t["artist"].toObject()["name"];
|
||||
item.artist = n.isObject() ? n.toObject()["display"].toString() : n.toString();
|
||||
}
|
||||
|
||||
const QJsonObject album = t["album"].toObject();
|
||||
item.album = album["title"].toString();
|
||||
item.albumId = album["id"].toString();
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void TrackListModel::setTracks(const QJsonArray &tracks,
|
||||
bool usePosition,
|
||||
bool useSequential)
|
||||
@@ -22,52 +72,8 @@ void TrackListModel::setTracks(const QJsonArray &tracks,
|
||||
parsed.reserve(tracks.size());
|
||||
|
||||
int seq = 1;
|
||||
for (const QJsonValue &v : tracks) {
|
||||
const QJsonObject t = v.toObject();
|
||||
TrackItem item;
|
||||
item.id = static_cast<qint64>(t["id"].toDouble());
|
||||
item.playlistTrackId = static_cast<qint64>(t["playlist_track_id"].toDouble());
|
||||
item.discNumber = t["media_number"].toInt(1);
|
||||
item.duration = static_cast<qint64>(t["duration"].toDouble());
|
||||
item.streamable = t["streamable"].toBool(true);
|
||||
item.hiRes = t["hires_streamable"].toBool();
|
||||
item.raw = t;
|
||||
|
||||
// Combine title + version ("Melody" + "Vocal Remix" → "Melody (Vocal Remix)")
|
||||
const QString base = t["title"].toString();
|
||||
const QString version = t["version"].toString().trimmed();
|
||||
item.title = version.isEmpty() ? base
|
||||
: base + QStringLiteral(" (") + version + QLatin1Char(')');
|
||||
|
||||
if (useSequential) {
|
||||
item.number = seq++;
|
||||
} else if (usePosition) {
|
||||
const int pos = t["position"].toInt();
|
||||
item.number = pos > 0 ? pos : seq;
|
||||
++seq;
|
||||
} else {
|
||||
item.number = t["track_number"].toInt();
|
||||
}
|
||||
|
||||
const QJsonObject performer = t["performer"].toObject();
|
||||
item.artist = performer["name"].toString();
|
||||
if (item.artist.isEmpty()) {
|
||||
// album.artist.name may be a plain string or {display:"..."} object
|
||||
const QJsonValue n = t["album"].toObject()["artist"].toObject()["name"];
|
||||
item.artist = n.isObject() ? n.toObject()["display"].toString() : n.toString();
|
||||
}
|
||||
if (item.artist.isEmpty()) {
|
||||
// top_tracks format: artist.name.display
|
||||
const QJsonValue n = t["artist"].toObject()["name"];
|
||||
item.artist = n.isObject() ? n.toObject()["display"].toString() : n.toString();
|
||||
}
|
||||
|
||||
const QJsonObject album = t["album"].toObject();
|
||||
item.album = album["title"].toString();
|
||||
item.albumId = album["id"].toString();
|
||||
|
||||
parsed.append(item);
|
||||
}
|
||||
for (const QJsonValue &v : tracks)
|
||||
parsed.append(parseTrackItem(v.toObject(), usePosition, useSequential, seq));
|
||||
|
||||
// Multi-disc only makes sense for album context (not playlists / fav / search)
|
||||
int maxDisc = 1;
|
||||
@@ -134,49 +140,8 @@ void TrackListModel::appendTracks(const QJsonArray &tracks,
|
||||
|
||||
QVector<TrackItem> parsed;
|
||||
parsed.reserve(tracks.size());
|
||||
for (const QJsonValue &v : tracks) {
|
||||
const QJsonObject t = v.toObject();
|
||||
TrackItem item;
|
||||
item.id = static_cast<qint64>(t["id"].toDouble());
|
||||
item.playlistTrackId = static_cast<qint64>(t["playlist_track_id"].toDouble());
|
||||
item.discNumber = t["media_number"].toInt(1);
|
||||
item.duration = static_cast<qint64>(t["duration"].toDouble());
|
||||
item.streamable = t["streamable"].toBool(true);
|
||||
item.hiRes = t["hires_streamable"].toBool();
|
||||
item.raw = t;
|
||||
|
||||
const QString base = t["title"].toString();
|
||||
const QString version = t["version"].toString().trimmed();
|
||||
item.title = version.isEmpty() ? base
|
||||
: base + QStringLiteral(" (") + version + QLatin1Char(')');
|
||||
|
||||
if (useSequential) {
|
||||
item.number = seq++;
|
||||
} else if (usePosition) {
|
||||
const int pos = t["position"].toInt();
|
||||
item.number = pos > 0 ? pos : seq;
|
||||
++seq;
|
||||
} else {
|
||||
item.number = t["track_number"].toInt();
|
||||
}
|
||||
|
||||
const QJsonObject performer = t["performer"].toObject();
|
||||
item.artist = performer["name"].toString();
|
||||
if (item.artist.isEmpty()) {
|
||||
const QJsonValue n = t["album"].toObject()["artist"].toObject()["name"];
|
||||
item.artist = n.isObject() ? n.toObject()["display"].toString() : n.toString();
|
||||
}
|
||||
if (item.artist.isEmpty()) {
|
||||
const QJsonValue n = t["artist"].toObject()["name"];
|
||||
item.artist = n.isObject() ? n.toObject()["display"].toString() : n.toString();
|
||||
}
|
||||
|
||||
const QJsonObject album = t["album"].toObject();
|
||||
item.album = album["title"].toString();
|
||||
item.albumId = album["id"].toString();
|
||||
|
||||
parsed.append(item);
|
||||
}
|
||||
for (const QJsonValue &v : tracks)
|
||||
parsed.append(parseTrackItem(v.toObject(), usePosition, useSequential, seq));
|
||||
|
||||
if (parsed.isEmpty())
|
||||
return;
|
||||
@@ -210,6 +175,16 @@ void TrackListModel::removeTrack(int row)
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
void TrackListModel::notifyFavChanged(qint64 id)
|
||||
{
|
||||
for (int r = 0; r < m_tracks.size(); ++r) {
|
||||
if (m_tracks[r].id == id) {
|
||||
const auto idx = index(r, ColTitle);
|
||||
emit dataChanged(idx, idx, {Qt::DecorationRole});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TrackListModel::setFavIds(const QSet<qint64> &ids)
|
||||
{
|
||||
m_favIds = ids;
|
||||
@@ -221,23 +196,13 @@ void TrackListModel::setFavIds(const QSet<qint64> &ids)
|
||||
void TrackListModel::addFavId(qint64 id)
|
||||
{
|
||||
m_favIds.insert(id);
|
||||
for (int r = 0; r < m_tracks.size(); ++r) {
|
||||
if (m_tracks[r].id == id) {
|
||||
const auto idx = index(r, ColTitle);
|
||||
emit dataChanged(idx, idx, {Qt::DecorationRole});
|
||||
}
|
||||
}
|
||||
notifyFavChanged(id);
|
||||
}
|
||||
|
||||
void TrackListModel::removeFavId(qint64 id)
|
||||
{
|
||||
m_favIds.remove(id);
|
||||
for (int r = 0; r < m_tracks.size(); ++r) {
|
||||
if (m_tracks[r].id == id) {
|
||||
const auto idx = index(r, ColTitle);
|
||||
emit dataChanged(idx, idx, {Qt::DecorationRole});
|
||||
}
|
||||
}
|
||||
notifyFavChanged(id);
|
||||
}
|
||||
|
||||
void TrackListModel::setPlayingId(qint64 id)
|
||||
|
||||
Reference in New Issue
Block a user