Copertine: validazione contenuto prima del caching (niente più HTML in cache), id fisso per il dettaglio, handler con sintassi moderna
This commit is contained in:
@@ -172,13 +172,14 @@ Page {
|
||||
|
||||
Component.onCompleted: {
|
||||
if (bookData.coverUrl && bookData.coverUrl.length > 0)
|
||||
apiClient.fetchImage(bookData.coverUrl, "detail:" + bookData.id)
|
||||
apiClient.fetchImage(bookData.coverUrl, "detailcover")
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: apiClient
|
||||
onImageReady: {
|
||||
if (id === "detail:" + bookData.id)
|
||||
// nota: parametro rinominato (imageId) — "id" è parola chiave QML e rompe il confronto
|
||||
onImageReady: function(imageId, localPath) {
|
||||
if (imageId === "detailcover")
|
||||
page.coverSource = localPath
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,9 +175,9 @@ Page {
|
||||
page.loadingMore = false
|
||||
page.errorMessage = message
|
||||
}
|
||||
onImageReady: {
|
||||
onImageReady: function(imageId, localPath) {
|
||||
for (var i = 0; i < feedModel.count; i++) {
|
||||
if (feedModel.get(i).coverId === id) {
|
||||
if (feedModel.get(i).coverId === imageId) {
|
||||
feedModel.setProperty(i, "coverSource", localPath)
|
||||
break
|
||||
}
|
||||
|
||||
+20
-2
@@ -127,6 +127,13 @@ void ApiClient::getFeed(const QString &url)
|
||||
});
|
||||
}
|
||||
|
||||
static bool looksLikeImage(const QByteArray &data)
|
||||
{
|
||||
// sniff dei magic byte per PNG/JPEG/GIF/WebP senza dipendere da QtGui
|
||||
return data.startsWith("\x89PNG") || data.startsWith("\xFF\xD8")
|
||||
|| data.startsWith("GIF8") || data.startsWith("RIFF");
|
||||
}
|
||||
|
||||
void ApiClient::fetchImage(const QString &url, const QString &id)
|
||||
{
|
||||
if (url.isEmpty()) {
|
||||
@@ -150,16 +157,27 @@ void ApiClient::fetchImage(const QString &url, const QString &id)
|
||||
}
|
||||
|
||||
QNetworkReply *reply = startGet(imageUrl);
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply, id, localPath]() {
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply, id, localPath, imageUrl]() {
|
||||
reply->deleteLater();
|
||||
const int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
if (reply->error() != QNetworkReply::NoError || status >= 400) {
|
||||
emit imageReady(id, QString());
|
||||
return;
|
||||
}
|
||||
const QByteArray body = reply->readAll();
|
||||
const QByteArray contentType = reply->header(
|
||||
QNetworkRequest::ContentTypeHeader).toByteArray();
|
||||
// non cachare risposte che non sono immagini (es. pagine HTML di errore 200)
|
||||
const bool isImage = contentType.startsWith("image/")
|
||||
|| (contentType.isEmpty() && looksLikeImage(body));
|
||||
if (!isImage) {
|
||||
qDebug() << "fetchImage: risposta non immagine scartata" << imageUrl;
|
||||
emit imageReady(id, QString());
|
||||
return;
|
||||
}
|
||||
QFile file(localPath);
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
file.write(reply->readAll());
|
||||
file.write(body);
|
||||
file.close();
|
||||
emit imageReady(id, localPath);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user