feat: add seamless lazy loading for genre and playlist views
Some checks failed
Build for Windows / build-windows (push) Has been cancelled
Some checks failed
Build for Windows / build-windows (push) Has been cancelled
Introduce paged loading with early prefetch for genre albums/playlists and playlist tracks, while preserving full-data behavior for deep shuffle and playlist play-all actions.
This commit is contained in:
@@ -109,6 +109,92 @@ void TrackListModel::setTracks(const QJsonArray &tracks,
|
||||
emit sortApplied();
|
||||
}
|
||||
|
||||
void TrackListModel::appendTracks(const QJsonArray &tracks,
|
||||
bool usePosition,
|
||||
bool useSequential)
|
||||
{
|
||||
if (tracks.isEmpty())
|
||||
return;
|
||||
|
||||
// Keep append path simple and stable: disc-header mode is handled by reset path.
|
||||
if (m_hasMultipleDiscs && !usePosition && !useSequential) {
|
||||
QJsonArray all = currentTracksJson();
|
||||
for (const QJsonValue &v : tracks)
|
||||
all.append(v);
|
||||
setTracks(all, usePosition, useSequential);
|
||||
return;
|
||||
}
|
||||
|
||||
int seq = 1;
|
||||
if (useSequential || usePosition) {
|
||||
for (const TrackItem &t : m_tracks)
|
||||
if (!t.isDiscHeader)
|
||||
++seq;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (parsed.isEmpty())
|
||||
return;
|
||||
|
||||
const int first = m_tracks.size();
|
||||
const int last = first + parsed.size() - 1;
|
||||
beginInsertRows({}, first, last);
|
||||
m_tracks += parsed;
|
||||
endInsertRows();
|
||||
|
||||
if (!m_hasMultipleDiscs && m_sortColumn >= 0) {
|
||||
emit layoutAboutToBeChanged();
|
||||
sortData(m_sortColumn, m_sortOrder);
|
||||
emit layoutChanged();
|
||||
emit sortApplied();
|
||||
}
|
||||
}
|
||||
|
||||
void TrackListModel::clear()
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
Reference in New Issue
Block a user