完善下载页面按钮的功能

This commit is contained in:
RigoLigoRLC 2022-02-19 19:30:10 +08:00
parent 8f32141726
commit d33e28b024
10 changed files with 218 additions and 33 deletions

View File

@ -163,8 +163,8 @@ namespace SpkUi
mBtnDownload = new QPushButton; mBtnDownload = new QPushButton;
mBtnDownload->setText(tr("Download")); mBtnDownload->setText(tr("Download"));
mBtnInstall = new QPushButton; // mBtnInstall = new QPushButton;
mBtnInstall->setText(tr("Install")); // mBtnInstall->setText(tr("Install"));
mBtnUninstall = new QPushButton; mBtnUninstall = new QPushButton;
mBtnUninstall->setText(tr("Uninstall")); mBtnUninstall->setText(tr("Uninstall"));
@ -177,7 +177,7 @@ namespace SpkUi
mBottomBarLay->addStretch(); mBottomBarLay->addStretch();
mBottomBarLay->addWidget(mBtnDownload); mBottomBarLay->addWidget(mBtnDownload);
mBottomBarLay->addWidget(mBtnInstall); // mBottomBarLay->addWidget(mBtnInstall);
mBottomBarLay->addWidget(mBtnUninstall); mBottomBarLay->addWidget(mBtnUninstall);
mBottomBarLay->addWidget(mBtnRequestUpdate); mBottomBarLay->addWidget(mBtnRequestUpdate);
mBottomBarLay->addWidget(mBtnReport); mBottomBarLay->addWidget(mBtnReport);

View File

@ -1,6 +1,8 @@
#include "page/spkpagedownloads.h" #include "page/spkpagedownloads.h"
#include "pkgs/spkpkgmgrbase.h"
#include "spkuimsg.h"
#include "spkutils.h" #include "spkutils.h"
SpkUi::SpkPageDownloads::SpkPageDownloads(QWidget *parent) : SpkUi::SpkPageDownloads::SpkPageDownloads(QWidget *parent) :
@ -27,6 +29,8 @@ SpkUi::SpkPageDownloads::SpkPageDownloads(QWidget *parent) :
connect(mDownloadMgr, &SpkDownloadMgr::DownloadStopped, connect(mDownloadMgr, &SpkDownloadMgr::DownloadStopped,
this, &SpkPageDownloads::DownloadStopped, Qt::QueuedConnection); this, &SpkPageDownloads::DownloadStopped, Qt::QueuedConnection);
connect(PKG, &SpkPkgMgrBase::ReportInstallResult,
this, &SpkPageDownloads::InstallationEnded);
} }
SpkUi::SpkPageDownloads::~SpkPageDownloads() SpkUi::SpkPageDownloads::~SpkPageDownloads()
@ -53,31 +57,24 @@ void SpkUi::SpkPageDownloads::AddDownloadTask(QString name, QString pkgName, QSt
// Add a new download entry into the UI // Add a new download entry into the UI
auto entry = new SpkDownloadEntry; auto entry = new SpkDownloadEntry;
auto iconData = RES->CacheLookup(pkgName, SpkResource::ResourceType::AppIcon, 0); auto iconData = RES->CacheLookup(pkgName, SpkResource::ResourceType::AppIcon, 0);
auto id = mNextDownloadId;
QPixmap icon; QPixmap icon;
if(iconData.status != SpkResource::ResourceStatus::Ready || !icon.loadFromData(iconData.data)) if(iconData.status != SpkResource::ResourceStatus::Ready || !icon.loadFromData(iconData.data))
icon.load(":/icons/broken-icon.svg"); icon.load(":/icons/broken-icon.svg");
entry->SetBasicInfo(name, icon); entry->SetBasicInfo(name, icon, mDownloadMgr->GetDestFilePath(path));
entry->SetStatus(SpkDownloadEntry::Waiting); entry->SetStatus(SpkDownloadEntry::Waiting);
auto id = mNextDownloadId; entry->setProperty("entryId", id);
entry->setProperty("path", path);
mNextDownloadId++; mNextDownloadId++;
mEntries[id] = entry; mEntries[id] = entry;
mLayEntries->addWidget(entry); mLayEntries->addWidget(entry);
if(mCurrentStatus != Idle) connect(entry, &SpkDownloadEntry::Action,
mWaitingDownloads.enqueue({ id, path }); // Queue download task for future this, &SpkPageDownloads::EntryAction);
else
{
mCurrentStatus = Waiting;
if(!mDownloadMgr->StartNewDownload(path, id)) // Initiate a download task when idle
{
// If fails to start then try next one. Emitting this signal causes
// SpkPageDownloads::DownloadStopped to be activated and thus tries next item in queue
emit mDownloadMgr->DownloadStopped(SpkDownloadMgr::FailNoVaibleServer, id);
}
}
NewDownloadTask(id, path);
} }
void SpkUi::SpkPageDownloads::DownloadStopped(SpkDownloadMgr::TaskResult status, int id) void SpkUi::SpkPageDownloads::DownloadStopped(SpkDownloadMgr::TaskResult status, int id)
@ -89,21 +86,34 @@ void SpkUi::SpkPageDownloads::DownloadStopped(SpkDownloadMgr::TaskResult status,
break; break;
case SpkDownloadMgr::FailCannotCreateFile: case SpkDownloadMgr::FailCannotCreateFile:
mEntries[id]->SetStatus(SpkDownloadEntry::Failed, mEntries[id]->SetStatus(SpkDownloadEntry::DownloadFailed,
tr("Cannot create download file. Download failed.")); tr("Cannot create download file. Download failed."));
break; break;
case SpkDownloadMgr::FailNoVaibleServer: case SpkDownloadMgr::FailNoVaibleServer:
mEntries[id]->SetStatus(SpkDownloadEntry::Failed, mEntries[id]->SetStatus(SpkDownloadEntry::DownloadFailed,
tr("Connection unstable or server failure. Download failed.")); tr("Connection unstable or server failure. Download failed."));
break; break;
case SpkDownloadMgr::FailCancel:
mEntries[id]->SetStatus(SpkDownloadEntry::DownloadFailed,
tr("This download was cancelled."));
break;
case SpkDownloadMgr::Fail: case SpkDownloadMgr::Fail:
mEntries[id]->SetStatus(SpkDownloadEntry::Failed, mEntries[id]->SetStatus(SpkDownloadEntry::DownloadFailed,
tr("Unknown error. Download failed.")); tr("Unknown error. Download failed."));
break; break;
} }
if(status == SpkDownloadMgr::Success)
SpkUiMessage::SendDesktopNotification(
tr("App \"%1\" downloaded, and ready to install.").arg(mEntries[id]->GetTaskName()));
else if(status != SpkDownloadMgr::FailCancel)
SpkUiMessage::SendDesktopNotification(
tr("Error occurred downloading \"%1\".").arg(mEntries[id]->GetTaskName()));
// Continue next download task // Continue next download task
if(!mWaitingDownloads.isEmpty()) if(!mWaitingDownloads.isEmpty())
{ {
@ -116,3 +126,85 @@ void SpkUi::SpkPageDownloads::DownloadStopped(SpkDownloadMgr::TaskResult status,
mCurrentStatus = Idle; mCurrentStatus = Idle;
} }
} }
void SpkUi::SpkPageDownloads::EntryAction(SpkDownloadEntry::EntryAction act)
{
SpkDownloadEntry *entry = static_cast<SpkDownloadEntry*>(sender());
auto id = entry->property("entryId").toInt();
switch(act)
{
case SpkDownloadEntry::AbortDownload:
mDownloadMgr->CancelCurrentDownload(); // Only one task at a time so simply abort download
break;
case SpkDownloadEntry::RetryDownload:
mLayEntries->removeWidget(entry); // Move to list tail
mLayEntries->addWidget(entry);
NewDownloadTask(id, entry->property("path").toString());
entry->SetStatus(SpkDownloadEntry::Waiting);
break;
case SpkDownloadEntry::StartInstall:
switch(PKG->ExecuteInstallation(entry->GetFilePath(), id))
{
case SpkPkgMgrBase::Succeeded:
entry->SetStatus(SpkDownloadEntry::Installing);
break;
case SpkPkgMgrBase::Failed:
entry->SetStatus(SpkDownloadEntry::InstallFailed,
tr("Failed to start installation."));
break;
default: break;
}
break;
case SpkDownloadEntry::RemoveEntry:
mLayEntries->removeWidget(entry);
mEntries.remove(id);
for(auto i = mWaitingDownloads.begin(); i != mWaitingDownloads.end(); i++)
{
if(i->first == id)
{
mWaitingDownloads.erase(i);
break;
}
}
entry->setVisible(false);
entry->deleteLater();
break;
}
}
void SpkUi::SpkPageDownloads::InstallationEnded(int id,
SpkPkgMgrBase::PkgInstallResult result,
int exitCode)
{
if(result == SpkPkgMgrBase::Succeeded)
{
mEntries[id]->SetStatus(SpkDownloadEntry::Installed);
}
else
{
mEntries[id]->SetStatus(SpkDownloadEntry::InstallFailed,
tr("Install failed, exit code: %1.").arg(exitCode));
}
}
void SpkUi::SpkPageDownloads::NewDownloadTask(int id, QString downloadPath)
{
if(mCurrentStatus != Idle)
mWaitingDownloads.enqueue({ id, downloadPath }); // Queue download task for future
else
{
mCurrentStatus = Waiting;
if(!mDownloadMgr->StartNewDownload(downloadPath, id)) // Initiate a download task when idle
{
// If fails to start then try next one. Emitting this signal causes
// SpkPageDownloads::DownloadStopped to be activated and thus tries next item in queue
emit mDownloadMgr->DownloadStopped(SpkDownloadMgr::FailNoVaibleServer, id);
}
}
}

View File

@ -40,6 +40,11 @@ SpkDownloadEntry::SpkDownloadEntry(QWidget *parent)
setLayout(mLayMain); setLayout(mLayMain);
connect(mBtnActions, &QPushButton::clicked, this, &SpkDownloadEntry::ActionButton);
connect(mBtnDelete, &QPushButton::clicked, this, &SpkDownloadEntry::DeleteButton);
mStatus = Invalid;
mLastReportTime = QTime::currentTime(); mLastReportTime = QTime::currentTime();
} }
@ -56,14 +61,16 @@ void SpkDownloadEntry::SetTotalBytes(qint64 total)
mLastReportTime = QTime::currentTime(); mLastReportTime = QTime::currentTime();
} }
void SpkDownloadEntry::SetBasicInfo(QString name, QPixmap icon) void SpkDownloadEntry::SetBasicInfo(QString name, QPixmap icon, QString filePath)
{ {
mAppName->setText(name); mAppName->setText(name);
mIcon->setPixmap(icon.scaled(IconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); mIcon->setPixmap(icon.scaled(IconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
mFilePath = filePath;
} }
void SpkDownloadEntry::SetStatus(DownloadEntryStatus status, QString msg) void SpkDownloadEntry::SetStatus(DownloadEntryStatus status, QString msg)
{ {
mStatus = status;
switch(status) switch(status)
{ {
case Waiting: case Waiting:
@ -71,31 +78,36 @@ void SpkDownloadEntry::SetStatus(DownloadEntryStatus status, QString msg)
mProgress->setVisible(false); mProgress->setVisible(false);
mBtnActions->setVisible(false); mBtnActions->setVisible(false);
mBtnDelete->setVisible(true); mBtnDelete->setVisible(true);
mBtnDelete->setText(tr("Cancel"));
break; break;
case Downloading: case Downloading:
mMessage->setText(tr("")); mMessage->setText(tr(""));
mProgress->setVisible(true); mProgress->setVisible(true);
mBtnActions->setVisible(true); mBtnActions->setVisible(false);
break; break;
case Paused: case DownloadFailed:
mMessage->setText(tr("Paused"));
break;
case Failed:
mMessage->setText(msg); mMessage->setText(msg);
mProgress->setVisible(false); mProgress->setVisible(false);
mBtnActions->setVisible(true);
mBtnActions->setText(tr("Retry"));
break; break;
case ToBeInstalled: case ToBeInstalled:
mMessage->setText(tr("Download Finished")); mMessage->setText(tr("Download Finished"));
mProgress->setVisible(false); mProgress->setVisible(false);
mBtnActions->setVisible(true);
mBtnDelete->setVisible(false);
mBtnActions->setText(tr("Install"));
break; break;
case Installing: case Installing:
mMessage->setText(""); mMessage->setText("");
mProgress->setVisible(false); mProgress->setVisible(false);
mBtnActions->setVisible(false);
mBtnDelete->setVisible(false);
mLoading->setVisible(true); mLoading->setVisible(true);
mLoading->Begin(); mLoading->Begin();
@ -103,12 +115,18 @@ void SpkDownloadEntry::SetStatus(DownloadEntryStatus status, QString msg)
mMessage->setText(tr("Installed")); mMessage->setText(tr("Installed"));
mLoading->End(); mLoading->End();
mLoading->setVisible(false); mLoading->setVisible(false);
mBtnDelete->setVisible(true);
mBtnDelete->setText(tr("Delete"));
break; break;
case InstallFailed: case InstallFailed:
mMessage->setText(msg.isEmpty() ? tr("Install Failed") : msg); mMessage->setText(msg.isEmpty() ? tr("Install Failed") : msg);
mLoading->End(); mLoading->End();
mLoading->setVisible(false); mLoading->setVisible(false);
mBtnActions->setVisible(true);
mBtnActions->setText(tr("Install"));
mBtnDelete->setVisible(true);
mBtnDelete->setText(tr("Cancel"));
break; break;
case Invalid: case Invalid:
@ -135,3 +153,42 @@ void SpkDownloadEntry::Progress(qint64 bytes)
mProgress->setValue(static_cast<int>(((double)bytes) / mTotalBytes * 1000)); mProgress->setValue(static_cast<int>(((double)bytes) / mTotalBytes * 1000));
mLastReportTime = now; mLastReportTime = now;
} }
void SpkDownloadEntry::ActionButton()
{
switch(mStatus)
{
case DownloadFailed:
emit Action(RetryDownload);
break;
case ToBeInstalled:
case InstallFailed:
emit Action(StartInstall);
break;
default:
break;
}
}
void SpkDownloadEntry::DeleteButton()
{
switch(mStatus)
{
case Waiting:
case DownloadFailed:
case Installed:
case InstallFailed:
case ToBeInstalled:
emit Action(RemoveEntry);
break;
case Downloading:
emit Action(AbortDownload);
break;
default:
break;
}
}

View File

@ -4,6 +4,7 @@
#include "spkdownload.h" #include "spkdownload.h"
#include "spkdownloadentry.h" #include "spkdownloadentry.h"
#include "page/spkpagebase.h" #include "page/spkpagebase.h"
#include "pkgs/spkpkgmgrbase.h"
namespace SpkUi namespace SpkUi
{ {
@ -22,7 +23,7 @@ namespace SpkUi
SpkDownloadMgr *mDownloadMgr; SpkDownloadMgr *mDownloadMgr;
QMap<uint, SpkDownloadEntry*> mEntries; QMap<uint, SpkDownloadEntry*> mEntries;
uint mNextDownloadId; uint mNextDownloadId;
QQueue<QPair<uint, QString>> mWaitingDownloads; QQueue<QPair<int, QString>> mWaitingDownloads;
enum { Idle, Waiting, Downloading } mCurrentStatus; enum { Idle, Waiting, Downloading } mCurrentStatus;
// UI // UI
@ -33,6 +34,11 @@ namespace SpkUi
private slots: private slots:
void DownloadProgress(qint64 downloadedBytes, qint64 totalBytes, int id); void DownloadProgress(qint64 downloadedBytes, qint64 totalBytes, int id);
void DownloadStopped(SpkDownloadMgr::TaskResult status, int id); void DownloadStopped(SpkDownloadMgr::TaskResult status, int id);
void EntryAction(SpkDownloadEntry::EntryAction);
void InstallationEnded(int id, SpkPkgMgrBase::PkgInstallResult, int exitCode);
private:
void NewDownloadTask(int id, QString downloadPath);
}; };
} }

View File

@ -27,6 +27,7 @@ class SpkDownloadMgr : public QObject
FailCannotCreateFile, ///< Failed because destination file cannot be created FailCannotCreateFile, ///< Failed because destination file cannot be created
FailNoVaibleServer, ///< Failed because no server provides file size or download stalled on FailNoVaibleServer, ///< Failed because no server provides file size or download stalled on
///< all of them ///< all of them
FailCancel, ///< User has cancelled the task
Fail Fail
}; };
@ -67,6 +68,8 @@ class SpkDownloadMgr : public QObject
*/ */
static RemoteFileInfo GetRemoteFileInfo(QUrl url); static RemoteFileInfo GetRemoteFileInfo(QUrl url);
QString GetDestFilePath(QString downloadPath);
private: private:
QList<QString> mServers; ///< Multithreaded download QList<QString> mServers; ///< Multithreaded download

View File

@ -26,8 +26,7 @@ class SpkDownloadEntry : public QWidget
Invalid = -1, Invalid = -1,
Waiting, Waiting,
Downloading, Downloading,
Paused, DownloadFailed,
Failed,
ToBeInstalled, ToBeInstalled,
Installing, Installing,
Installed, Installed,
@ -35,9 +34,23 @@ class SpkDownloadEntry : public QWidget
}; };
void SetTotalBytes(qint64 total); void SetTotalBytes(qint64 total);
void SetBasicInfo(QString name, QPixmap icon); void SetBasicInfo(QString name, QPixmap icon, QString filePath);
void SetStatus(DownloadEntryStatus status, QString msg = ""); void SetStatus(DownloadEntryStatus status, QString msg = "");
void Progress(qint64 bytes); void Progress(qint64 bytes);
QString GetTaskName() { return mAppName->text(); }
QString GetFilePath() { return mFilePath; }
enum EntryAction
{
AbortDownload,
RetryDownload,
StartInstall,
RemoveEntry
};
private slots:
void ActionButton();
void DeleteButton();
private: private:
QLabel *mIcon, *mMessage; QLabel *mIcon, *mMessage;
@ -54,4 +67,11 @@ class SpkDownloadEntry : public QWidget
qint64 mTotalBytes, mDownloadedBytes; qint64 mTotalBytes, mDownloadedBytes;
QTime mLastReportTime; QTime mLastReportTime;
QString mReadableTotalSize; QString mReadableTotalSize;
QString mFilePath;
DownloadEntryStatus mStatus;
signals:
void Action(EntryAction);
}; };

View File

@ -82,6 +82,7 @@ namespace SpkUi
void GoBack() void GoBack()
{ {
emit SwitchToCategory(mLastCategoryPage, 0); emit SwitchToCategory(mLastCategoryPage, 0);
mCategoryWidget->currentItem()->setSelected(false);
mLastCategoryItem->setSelected(true); mLastCategoryItem->setSelected(true);
} }

View File

@ -13,6 +13,7 @@
#define STORE (SpkStore::Instance) #define STORE (SpkStore::Instance)
#define CFG (SpkStore::Instance->mCfg) #define CFG (SpkStore::Instance->mCfg)
#define RES (SpkResource::Instance) #define RES (SpkResource::Instance)
#define PKG (SpkPkgMgrBase::Instance())
namespace SpkUtils namespace SpkUtils
{ {

View File

@ -71,6 +71,11 @@ SpkDownloadMgr::RemoteFileInfo SpkDownloadMgr::GetRemoteFileInfo(QUrl url)
return ret; return ret;
} }
QString SpkDownloadMgr::GetDestFilePath(QString downloadPath)
{
return mDestFolder + '/' + SpkUtils::CutFileName(downloadPath);
}
void SpkDownloadMgr::SetDestinationFolder(QString path) void SpkDownloadMgr::SetDestinationFolder(QString path)
{ {
QDir dir(path); QDir dir(path);
@ -122,7 +127,7 @@ bool SpkDownloadMgr::StartNewDownload(QString path, int downloadId)
sErr(tr("SpkDownloadMgr: Download directory %1 cannot be created.").arg(mDestFolder)); sErr(tr("SpkDownloadMgr: Download directory %1 cannot be created.").arg(mDestFolder));
return false; return false;
} }
mDestFile.setFileName(mDestFolder + '/' + SpkUtils::CutFileName(path)); mDestFile.setFileName(GetDestFilePath(path));
if(!mDestFile.open(QFile::ReadWrite)) if(!mDestFile.open(QFile::ReadWrite))
{ {
sNotify(tr("Cannot write to destination file, download cannot start.")); sNotify(tr("Cannot write to destination file, download cannot start."));

View File

@ -34,7 +34,7 @@ void SpkUiMessage::SendStoreNotification(QString s)
void SpkUiMessage::SetDesktopNotifyTimeout(int ms) void SpkUiMessage::SetDesktopNotifyTimeout(int ms)
{ {
if(!_notify) if(!_notify)
_notify = notify_notification_new("", "", ""); return;
notify_notification_set_timeout(_notify, ms); notify_notification_set_timeout(_notify, ms);
mTimeoutDesktop = ms; mTimeoutDesktop = ms;
} }