ContentManagerModel maintains the download state

This fixes the bugs related to pending download statuses being discarded
by filtering and similar operations that result in full update of the
ContentManagerModel.

Instead this commit leads to a new bug - completion of a download
is not always properly detected for very small (and thus instantaneous)
downloads. This is caused by library update events triggered by ZIM
directory monitoring (which notifies about a new ZIM file appearing
in the download directory) interfering with the download status update
signal.
This commit is contained in:
Veloman Yunkan 2023-12-13 21:33:11 +04:00
parent ef2131d7f3
commit c20eedf9f6
4 changed files with 26 additions and 6 deletions

View File

@ -136,6 +136,7 @@ std::shared_ptr<RowNode> ContentManagerModel::createNode(BookInfo bookItem, QMap
}, id, weakRoot)); }, id, weakRoot));
std::weak_ptr<RowNode> weakRowNodePtr = rowNodePtr; std::weak_ptr<RowNode> weakRowNodePtr = rowNodePtr;
const auto descNodePtr = std::make_shared<DescriptionNode>(DescriptionNode(bookItem["description"].toString(), weakRowNodePtr)); const auto descNodePtr = std::make_shared<DescriptionNode>(DescriptionNode(bookItem["description"].toString(), weakRowNodePtr));
rowNodePtr->appendChild(descNodePtr); rowNodePtr->appendChild(descNodePtr);
return rowNodePtr; return rowNodePtr;
} }
@ -144,7 +145,15 @@ void ContentManagerModel::setupNodes()
{ {
beginResetModel(); beginResetModel();
for (auto bookItem : m_data) { for (auto bookItem : m_data) {
rootNode->appendChild(createNode(bookItem, iconMap)); const auto rowNode = createNode(bookItem, iconMap);
// Restore download state during model updates (filtering, etc)
const auto downloadIter = m_downloads.constFind(rowNode->getBookId());
if ( downloadIter != m_downloads.constEnd() ) {
rowNode->setDownloadState(downloadIter.value());
}
rootNode->appendChild(rowNode);
} }
endResetModel(); endResetModel();
} }
@ -239,10 +248,16 @@ std::shared_ptr<RowNode> getSharedPointer(RowNode* ptr)
void ContentManagerModel::startDownload(QModelIndex index) void ContentManagerModel::startDownload(QModelIndex index)
{ {
auto node = getSharedPointer(static_cast<RowNode*>(index.internalPointer())); auto node = getSharedPointer(static_cast<RowNode*>(index.internalPointer()));
node->setDownloadState(new DownloadState); const auto bookId = node->getBookId();
QTimer *timer = node->getDownloadState()->getDownloadUpdateTimer(); const auto newDownload = std::make_shared<DownloadState>();
m_downloads[bookId] = newDownload;
node->setDownloadState(newDownload);
QTimer *timer = newDownload->getDownloadUpdateTimer();
connect(timer, &QTimer::timeout, this, [=]() { connect(timer, &QTimer::timeout, this, [=]() {
node->getDownloadState()->update(node->getBookId()); if ( ! newDownload->update(bookId) ) {
m_downloads.remove(bookId);
node->setDownloadState(nullptr);
}
emit dataChanged(index, index); emit dataChanged(index, index);
}); });
} }
@ -265,6 +280,7 @@ void ContentManagerModel::cancelDownload(QModelIndex index)
{ {
auto node = static_cast<RowNode*>(index.internalPointer()); auto node = static_cast<RowNode*>(index.internalPointer());
node->setDownloadState(nullptr); node->setDownloadState(nullptr);
m_downloads.remove(node->getBookId());
emit dataChanged(index, index); emit dataChanged(index, index);
} }

View File

@ -6,6 +6,7 @@
#include <QVariant> #include <QVariant>
#include <QIcon> #include <QIcon>
#include "thumbnaildownloader.h" #include "thumbnaildownloader.h"
#include "rownode.h"
#include <memory> #include <memory>
class RowNode; class RowNode;
@ -58,6 +59,7 @@ private: // data
int zimCount = 0; int zimCount = 0;
ThumbnailDownloader td; ThumbnailDownloader td;
QMap<QString, QByteArray> iconMap; QMap<QString, QByteArray> iconMap;
QMap<QString, std::shared_ptr<DownloadState>> m_downloads;
}; };
#endif // CONTENTMANAGERMODEL_H #endif // CONTENTMANAGERMODEL_H

View File

@ -33,7 +33,7 @@ QString convertToUnits(QString size)
} // unnamed namespace } // unnamed namespace
void DownloadState::update(QString id) bool DownloadState::update(QString id)
{ {
auto downloadInfos = KiwixApp::instance()->getContentManager()->updateDownloadInfos(id, {"status", "completedLength", "totalLength", "downloadSpeed"}); auto downloadInfos = KiwixApp::instance()->getContentManager()->updateDownloadInfos(id, {"status", "completedLength", "totalLength", "downloadSpeed"});
double percent = downloadInfos["completedLength"].toDouble() / downloadInfos["totalLength"].toDouble(); double percent = downloadInfos["completedLength"].toDouble() / downloadInfos["totalLength"].toDouble();
@ -51,7 +51,9 @@ void DownloadState::update(QString id)
// from another thread. // from another thread.
m_downloadUpdateTimer.reset(); m_downloadUpdateTimer.reset();
m_downloadInfo = {0, "", "", false}; m_downloadInfo = {0, "", "", false};
return false;
} }
return true;
} }
void DownloadState::pause() void DownloadState::pause()

View File

@ -24,7 +24,7 @@ public:
QTimer* getDownloadUpdateTimer() const { return m_downloadUpdateTimer.get(); } QTimer* getDownloadUpdateTimer() const { return m_downloadUpdateTimer.get(); }
void pause(); void pause();
void resume(); void resume();
void update(QString id); bool update(QString id);
protected: protected:
// This is non-NULL only for a pending (even if paused) download // This is non-NULL only for a pending (even if paused) download