mirror of
https://gitee.com/spark-store-project/spark-store
synced 2025-12-14 04:42:03 +08:00
下载页面雏形,修复SpkPopup(改用弹出),添加应用列表固定图标缓存
This commit is contained in:
@@ -69,6 +69,7 @@ set(SOURCE_FILES
|
|||||||
inc/spkloading.h gui/spkloading.cpp
|
inc/spkloading.h gui/spkloading.cpp
|
||||||
inc/spksidebartree.h gui/spksidebartree.cpp
|
inc/spksidebartree.h gui/spksidebartree.cpp
|
||||||
inc/spkappitem.h gui/spkappitem.cpp
|
inc/spkappitem.h gui/spkappitem.cpp
|
||||||
|
inc/spkdownloadentry.h gui/spkdownloadentry.cpp
|
||||||
inc/spkpopup.h gui/spkpopup.cpp
|
inc/spkpopup.h gui/spkpopup.cpp
|
||||||
inc/spkstretchlayout.h gui/spkstretchlayout.cpp
|
inc/spkstretchlayout.h gui/spkstretchlayout.cpp
|
||||||
inc/spkfocuslineedit.h
|
inc/spkfocuslineedit.h
|
||||||
@@ -77,6 +78,7 @@ set(SOURCE_FILES
|
|||||||
inc/page/spkpageuitest.h gui/page/spkpageuitest.cpp
|
inc/page/spkpageuitest.h gui/page/spkpageuitest.cpp
|
||||||
inc/page/spkpageapplist.h gui/page/spkpageapplist.cpp
|
inc/page/spkpageapplist.h gui/page/spkpageapplist.cpp
|
||||||
inc/page/spkpageappdetails.h gui/page/spkpageappdetails.cpp
|
inc/page/spkpageappdetails.h gui/page/spkpageappdetails.cpp
|
||||||
|
inc/page/spkpagedownloads.h gui/page/spkpagedownloads.cpp
|
||||||
|
|
||||||
inc/spkstore.h src/spkstore.cpp
|
inc/spkstore.h src/spkstore.cpp
|
||||||
inc/spkuimsg.h src/spkuimsg.cpp
|
inc/spkuimsg.h src/spkuimsg.cpp
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "page/spkpageappdetails.h"
|
#include "page/spkpageappdetails.h"
|
||||||
#include "spkutils.h"
|
#include "spkutils.h"
|
||||||
|
#include "spkappitem.h"
|
||||||
|
|
||||||
namespace SpkUi
|
namespace SpkUi
|
||||||
{
|
{
|
||||||
@@ -112,8 +113,8 @@ namespace SpkUi
|
|||||||
mAuthor->SetTitle(tr("Author"));
|
mAuthor->SetTitle(tr("Author"));
|
||||||
mContributor = new SpkDetailEntry;
|
mContributor = new SpkDetailEntry;
|
||||||
mContributor->SetTitle(tr("Contributor"));
|
mContributor->SetTitle(tr("Contributor"));
|
||||||
mSite = new SpkDetailEntry;
|
// mSite = new SpkDetailEntry;
|
||||||
mSite->SetTitle(tr("Website"));
|
// mSite->SetTitle(tr("Website"));
|
||||||
mArch = new SpkDetailEntry;
|
mArch = new SpkDetailEntry;
|
||||||
mArch->SetTitle(tr("Architecture"));
|
mArch->SetTitle(tr("Architecture"));
|
||||||
mSize = new SpkDetailEntry;
|
mSize = new SpkDetailEntry;
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ namespace SpkUi
|
|||||||
{
|
{
|
||||||
SpkPageAppList::SpkPageAppList(QWidget *parent) : SpkPageBase(parent)
|
SpkPageAppList::SpkPageAppList(QWidget *parent) : SpkPageBase(parent)
|
||||||
{
|
{
|
||||||
|
mLoadingIcon = new QPixmap(QIcon(":/icons/loading-icon.svg").pixmap(SpkAppItem::IconSize_));
|
||||||
|
mBrokenIcon = new QPixmap(QIcon(":/icons/broken-icon.svg").pixmap(SpkAppItem::IconSize_));
|
||||||
|
|
||||||
mAppsWidget = new QWidget;
|
mAppsWidget = new QWidget;
|
||||||
mAppsArea = new QScrollArea(this);
|
mAppsArea = new QScrollArea(this);
|
||||||
mMainLay = new QVBoxLayout(this);
|
mMainLay = new QVBoxLayout(this);
|
||||||
@@ -63,6 +66,7 @@ namespace SpkUi
|
|||||||
|
|
||||||
auto iconRes = RES->RequestResource(id, pkgName, SpkResource::ResourceType::AppIcon,
|
auto iconRes = RES->RequestResource(id, pkgName, SpkResource::ResourceType::AppIcon,
|
||||||
iconUrl, 0);
|
iconUrl, 0);
|
||||||
|
// TODO: cache scaled icons
|
||||||
QPixmap icon;
|
QPixmap icon;
|
||||||
if(iconRes.status == SpkResource::ResourceStatus::Ready)
|
if(iconRes.status == SpkResource::ResourceStatus::Ready)
|
||||||
{
|
{
|
||||||
@@ -72,13 +76,13 @@ namespace SpkUi
|
|||||||
Qt::SmoothTransformation));
|
Qt::SmoothTransformation));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
item->SetIcon(QIcon(":/icons/broken-icon.svg").pixmap(SpkAppItem::IconSize_));
|
item->SetIcon(*mBrokenIcon);
|
||||||
RES->PurgeCachedResource(pkgName, SpkResource::ResourceType::AppIcon, 0);
|
RES->PurgeCachedResource(pkgName, SpkResource::ResourceType::AppIcon, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO: prepare icons for loading entries
|
//TODO: [TEST] prepare icons for loading entries
|
||||||
// else
|
else
|
||||||
// item->SetIcon(QPixmap(":/icons/loading_icon.svg").scaled(SpkAppItem::IconSize_));
|
item->SetIcon(*mLoadingIcon);
|
||||||
|
|
||||||
mAppItemList.append(item);
|
mAppItemList.append(item);
|
||||||
mItemLay->addWidget(item);
|
mItemLay->addWidget(item);
|
||||||
@@ -110,11 +114,11 @@ namespace SpkUi
|
|||||||
Qt::IgnoreAspectRatio,
|
Qt::IgnoreAspectRatio,
|
||||||
Qt::SmoothTransformation));
|
Qt::SmoothTransformation));
|
||||||
else
|
else
|
||||||
item->SetIcon(QIcon(":/icons/broken-icon.svg").pixmap(SpkAppItem::IconSize_));
|
item->SetIcon(*mBrokenIcon);
|
||||||
}
|
}
|
||||||
else if(result.status == SpkResource::ResourceStatus::Failed)
|
else if(result.status == SpkResource::ResourceStatus::Failed)
|
||||||
{
|
{
|
||||||
item->SetIcon(QIcon(":/icons/broken-icon.svg").pixmap(SpkAppItem::IconSize_));
|
item->SetIcon(*mBrokenIcon);
|
||||||
RES->PurgeCachedResource(item->property("pkg_name").toString(),
|
RES->PurgeCachedResource(item->property("pkg_name").toString(),
|
||||||
SpkResource::ResourceType::AppIcon, 0);
|
SpkResource::ResourceType::AppIcon, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
29
gui/page/spkpagedownloads.cpp
Normal file
29
gui/page/spkpagedownloads.cpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include "page/spkpagedownloads.h"
|
||||||
|
#include "spkutils.h"
|
||||||
|
|
||||||
|
SpkUi::SpkPageDownloads::SpkPageDownloads(QWidget *parent) :
|
||||||
|
SpkPageBase(parent)
|
||||||
|
{
|
||||||
|
mMainLay = new QVBoxLayout(this);
|
||||||
|
mLayEntries = new QVBoxLayout;
|
||||||
|
mScrollWidget = new QWidget;
|
||||||
|
mScrollArea = new QScrollArea(this);
|
||||||
|
|
||||||
|
mScrollWidget->setLayout(mLayEntries);
|
||||||
|
mScrollArea->setWidget(mScrollWidget);
|
||||||
|
mScrollArea->setWidgetResizable(true);
|
||||||
|
mMainLay->addWidget(mScrollArea);
|
||||||
|
setLayout(mMainLay);
|
||||||
|
}
|
||||||
|
|
||||||
|
SpkUi::SpkPageDownloads::~SpkPageDownloads()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpkUi::SpkPageDownloads::DownloadProgress(qint64 downloadedBytes, qint64 totalBytes, int id)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
111
gui/spkdownloadentry.cpp
Normal file
111
gui/spkdownloadentry.cpp
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
|
||||||
|
#include "spkdownloadentry.h"
|
||||||
|
#include "spklogging.h"
|
||||||
|
|
||||||
|
constexpr QSize SpkDownloadEntry::IconSize;
|
||||||
|
|
||||||
|
SpkDownloadEntry::SpkDownloadEntry(QWidget *parent)
|
||||||
|
{
|
||||||
|
mIcon = new QLabel;
|
||||||
|
mAppName = new ElidedLabel;
|
||||||
|
mMessage = new QLabel;
|
||||||
|
mProgress = new QProgressBar;
|
||||||
|
mLoading = new SpkLoading;
|
||||||
|
mBtnDelete = new QPushButton;
|
||||||
|
mBtnActions = new QPushButton;
|
||||||
|
|
||||||
|
mLayInfo = new QVBoxLayout;
|
||||||
|
mLayMsgs = new QHBoxLayout;
|
||||||
|
mLayMain = new QHBoxLayout;
|
||||||
|
|
||||||
|
mLoading->setVisible(false);
|
||||||
|
mIcon->setFixedSize(IconSize);
|
||||||
|
mProgress->setRange(0, 1000);
|
||||||
|
|
||||||
|
mLayMsgs->addWidget(mAppName);
|
||||||
|
mLayMsgs->addStretch();
|
||||||
|
mLayMsgs->addWidget(mMessage);
|
||||||
|
|
||||||
|
mLayInfo->addLayout(mLayMsgs);
|
||||||
|
mLayInfo->addWidget(mProgress);
|
||||||
|
mLayInfo->setAlignment(Qt::AlignVCenter);
|
||||||
|
|
||||||
|
mLayMain->addWidget(mIcon);
|
||||||
|
mLayMain->addLayout(mLayInfo);
|
||||||
|
mLayMain->addWidget(mLoading);
|
||||||
|
mLayMain->addWidget(mBtnActions);
|
||||||
|
mLayMain->addWidget(mBtnDelete);
|
||||||
|
|
||||||
|
setLayout(mLayMain);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SpkDownloadEntry::~SpkDownloadEntry()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpkDownloadEntry::SetBasicInfo(QString name, QPixmap icon)
|
||||||
|
{
|
||||||
|
mAppName->setText(name);
|
||||||
|
mIcon->setPixmap(icon.scaled(IconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpkDownloadEntry::SetStatus(DownloadEntryStatus status)
|
||||||
|
{
|
||||||
|
switch(status)
|
||||||
|
{
|
||||||
|
case Waiting:
|
||||||
|
mMessage->setText(tr("Waiting for download"));
|
||||||
|
mProgress->setVisible(false);
|
||||||
|
mBtnActions->setVisible(false);
|
||||||
|
mBtnDelete->setVisible(true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Downloading:
|
||||||
|
mMessage->setText(tr(""));
|
||||||
|
mProgress->setVisible(true);
|
||||||
|
mBtnActions->setVisible(true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Paused:
|
||||||
|
mMessage->setText(tr("Paused"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Failed:
|
||||||
|
mMessage->setText(tr("Download Failed"));
|
||||||
|
mProgress->setVisible(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ToBeInstalled:
|
||||||
|
mMessage->setText(tr("Download Finished"));
|
||||||
|
mProgress->setVisible(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Installing:
|
||||||
|
mMessage->setText("");
|
||||||
|
mProgress->setVisible(false);
|
||||||
|
mLoading->setVisible(true);
|
||||||
|
mLoading->Begin();
|
||||||
|
|
||||||
|
case Installed:
|
||||||
|
mMessage->setText(tr("Installed"));
|
||||||
|
mLoading->End();
|
||||||
|
mLoading->setVisible(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InstallFailed:
|
||||||
|
mMessage->setText(tr("Install Failed"));
|
||||||
|
mLoading->End();
|
||||||
|
mLoading->setVisible(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Invalid:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpkDownloadEntry::SetProgress(int p)
|
||||||
|
{
|
||||||
|
mProgress->setValue(p);
|
||||||
|
}
|
||||||
@@ -435,8 +435,13 @@ SpkUi::SpkMainWidget::SpkMainWidget(QWidget *parent) : QFrame(parent)
|
|||||||
AppDetailsItem = new QTreeWidgetItem(QStringList(tr("App Details")));
|
AppDetailsItem = new QTreeWidgetItem(QStringList(tr("App Details")));
|
||||||
AppDetailsItem->setData(0, SpkSidebarSelector::RoleItemIsCategory, false);
|
AppDetailsItem->setData(0, SpkSidebarSelector::RoleItemIsCategory, false);
|
||||||
AppDetailsItem->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, SpkStackedPages::PgAppDetails);
|
AppDetailsItem->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, SpkStackedPages::PgAppDetails);
|
||||||
|
|
||||||
CategoryParentItem = new QTreeWidgetItem(QStringList(tr("Categories")));
|
CategoryParentItem = new QTreeWidgetItem(QStringList(tr("Categories")));
|
||||||
CategoryParentItem->setFlags(CategoryParentItem->flags().setFlag(Qt::ItemIsSelectable, false));
|
CategoryParentItem->setFlags(CategoryParentItem->flags().setFlag(Qt::ItemIsSelectable, false));
|
||||||
|
|
||||||
|
DownloadsItem = new QTreeWidgetItem(QStringList(tr("Downloads")));
|
||||||
|
DownloadsItem->setData(0, SpkSidebarSelector::RoleItemIsCategory, false);
|
||||||
|
DownloadsItem->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, SpkStackedPages::PgDownloads);
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
UiTestItem = new QTreeWidgetItem(QStringList(tr("UI TEST")));
|
UiTestItem = new QTreeWidgetItem(QStringList(tr("UI TEST")));
|
||||||
UiTestItem->setData(0, SpkSidebarSelector::RoleItemIsCategory, false);
|
UiTestItem->setData(0, SpkSidebarSelector::RoleItemIsCategory, false);
|
||||||
@@ -525,6 +530,10 @@ SpkUi::SpkMainWidget::SpkMainWidget(QWidget *parent) : QFrame(parent)
|
|||||||
PageAppDetails->setProperty("spk_pageid", SpkStackedPages::PgAppDetails);
|
PageAppDetails->setProperty("spk_pageid", SpkStackedPages::PgAppDetails);
|
||||||
sorter[PgAppDetails] = PageAppDetails;
|
sorter[PgAppDetails] = PageAppDetails;
|
||||||
|
|
||||||
|
PageDownloads = new SpkUi::SpkPageDownloads(this);
|
||||||
|
PageDownloads->setProperty("spk_pageid", SpkStackedPages::PgDownloads);
|
||||||
|
sorter[PgDownloads] = PageDownloads;
|
||||||
|
|
||||||
#ifndef NDEBUG // If only in debug mode should we initialize QSS test page
|
#ifndef NDEBUG // If only in debug mode should we initialize QSS test page
|
||||||
PageQssTest = new SpkUi::SpkPageUiTest(this);
|
PageQssTest = new SpkUi::SpkPageUiTest(this);
|
||||||
PageQssTest->setProperty("spk_pageid", SpkStackedPages::PgQssTest);
|
PageQssTest->setProperty("spk_pageid", SpkStackedPages::PgQssTest);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
#include "spkui_general.h"
|
#include "spkui_general.h"
|
||||||
|
#include "spkmainwindow.h"
|
||||||
#include "spkmsgbox.h"
|
#include "spkmsgbox.h"
|
||||||
#include "spkstore.h"
|
#include "spkstore.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
|
|
||||||
#include "spkmainwindow.h"
|
|
||||||
#include "spkpopup.h"
|
#include "spkpopup.h"
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
namespace SpkUi
|
namespace SpkUi
|
||||||
{
|
{
|
||||||
SpkPopup::SpkPopup(QWidget *parent, int aMillis) : QWidget(parent)
|
SpkPopup::SpkPopup(QWidget *parent, int aMillis) : QWidget(parent)
|
||||||
{
|
{
|
||||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
setAttribute(Qt::WA_TranslucentBackground);
|
setAttribute(Qt::WA_TranslucentBackground);
|
||||||
setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint);
|
setWindowFlags(Qt::FramelessWindowHint);
|
||||||
mText = new QLabel();
|
mText = new QLabel();
|
||||||
mText->setStyleSheet("border-radius: 11px;"
|
mText->setStyleSheet("border-radius: 11px;"
|
||||||
"background-color: rgba(0,0,0,150);"
|
"background-color: rgba(0,0,0,150);"
|
||||||
@@ -22,19 +23,33 @@ namespace SpkUi
|
|||||||
// Qt::WA_TranslucentBackground will cause the entire background of QLabel transparent.
|
// Qt::WA_TranslucentBackground will cause the entire background of QLabel transparent.
|
||||||
// Therefore we need a container (SpkPopup) with a transparent background as the canvas layer
|
// Therefore we need a container (SpkPopup) with a transparent background as the canvas layer
|
||||||
// of the actual displayed text.
|
// of the actual displayed text.
|
||||||
mAnimFadeIn = new QPropertyAnimation(this, "windowOpacity");
|
|
||||||
mAnimFadeOut = new QPropertyAnimation(this, "windowOpacity");
|
|
||||||
mAnim = new QSequentialAnimationGroup(this);
|
mAnim = new QSequentialAnimationGroup(this);
|
||||||
mAnimFadeIn->setStartValue(0);
|
|
||||||
mAnimFadeIn->setEndValue(1);
|
// Disabled as translucency doesn't work well on every platform
|
||||||
|
// mAnimFadeIn = new QPropertyAnimation(this, "windowOpacity");
|
||||||
|
// mAnimFadeOut = new QPropertyAnimation(this, "windowOpacity");
|
||||||
|
// mAnimFadeIn->setStartValue(0.0);
|
||||||
|
// mAnimFadeIn->setEndValue(1.0);
|
||||||
|
// mAnimFadeOut->setStartValue(1.0);
|
||||||
|
// mAnimFadeOut->setEndValue(0.0);
|
||||||
|
// Using moving animation instead
|
||||||
|
mAnimFadeIn = new QPropertyAnimation(this, "pos");
|
||||||
|
mAnimFadeOut = new QPropertyAnimation(this, "pos");
|
||||||
mAnimFadeIn->setDuration(250);
|
mAnimFadeIn->setDuration(250);
|
||||||
mAnimFadeOut->setStartValue(1);
|
|
||||||
mAnimFadeOut->setEndValue(0);
|
|
||||||
mAnimFadeOut->setDuration(250);
|
mAnimFadeOut->setDuration(250);
|
||||||
|
mAnimFadeIn->setEasingCurve(QEasingCurve::InQuad);
|
||||||
|
mAnimFadeOut->setEasingCurve(QEasingCurve::InQuad);
|
||||||
|
|
||||||
mAnim->addAnimation(mAnimFadeIn);
|
mAnim->addAnimation(mAnimFadeIn);
|
||||||
mAnim->addPause(aMillis);
|
mAnim->addPause(aMillis);
|
||||||
mAnim->addAnimation(mAnimFadeOut);
|
mAnim->addAnimation(mAnimFadeOut);
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
|
|
||||||
|
connect(mAnim, &QAnimationGroup::stateChanged,
|
||||||
|
[=](QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
|
||||||
|
{
|
||||||
|
qDebug() << "OldState" << oldState << "NewState" << newState;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpkPopup::Show(QString aText)
|
void SpkPopup::Show(QString aText)
|
||||||
@@ -44,11 +59,22 @@ namespace SpkUi
|
|||||||
QSize parentSize = parentWidget()->size();
|
QSize parentSize = parentWidget()->size();
|
||||||
mText->setText(aText);
|
mText->setText(aText);
|
||||||
adjustSize();
|
adjustSize();
|
||||||
move(QPoint((parentSize.width() - width()) / 2, parentSize.height() - height() - 30) +
|
move(QPoint((parentSize.width() - width()) / 2, parentSize.height() - height() - 30)/* +
|
||||||
parentWidget()->pos());
|
parentWidget()->pos()*/);
|
||||||
setMaximumWidth(parentSize.width() - 200);
|
setMaximumWidth(parentSize.width() - 200);
|
||||||
setWindowOpacity(1);
|
setWindowOpacity(1);
|
||||||
show();
|
show();
|
||||||
|
|
||||||
|
mAnimFadeIn->setStartValue(QPoint((parentSize.width() - width()) / 2,
|
||||||
|
parentSize.height() + height()));
|
||||||
|
mAnimFadeIn->setEndValue(QPoint((parentSize.width() - width()) / 2,
|
||||||
|
parentSize.height() - height() - 80));
|
||||||
|
mAnimFadeOut->setStartValue(QPoint((parentSize.width() - width()) / 2,
|
||||||
|
parentSize.height() - height() - 80));
|
||||||
|
mAnimFadeOut->setEndValue(QPoint((parentSize.width() - width()) / 2,
|
||||||
|
parentSize.height() + height()));
|
||||||
|
|
||||||
|
qDebug() << "Popup size " << size() << "position" << pos() << "parent size" << parentWidget()->size();
|
||||||
mAnim->start();
|
mAnim->start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ namespace SpkUi
|
|||||||
SpkStretchLayout *mItemLay;
|
SpkStretchLayout *mItemLay;
|
||||||
QList<SpkAppItem *> mAppItemList;
|
QList<SpkAppItem *> mAppItemList;
|
||||||
|
|
||||||
|
// Cached icons
|
||||||
|
QPixmap *mLoadingIcon,
|
||||||
|
*mBrokenIcon;
|
||||||
|
|
||||||
QIntValidator *mPageValidator;
|
QIntValidator *mPageValidator;
|
||||||
|
|
||||||
int mCategoryId, mCurrentPage;
|
int mCategoryId, mCurrentPage;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spkstore.h"
|
#include "spkstore.h"
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @note SpkDownloadMgr does NOT do download scheduling and other things; it's only a multithreaded
|
* @note SpkDownloadMgr does NOT do download scheduling and other things; it's only a multithreaded
|
||||||
@@ -68,6 +69,8 @@ class SpkDownloadMgr : public QObject
|
|||||||
QFile mDestFile;
|
QFile mDestFile;
|
||||||
QString mDestFolder, mCurrentRemotePath;
|
QString mDestFolder, mCurrentRemotePath;
|
||||||
RemoteFileInfo mCurrentRemoteFileInfo;
|
RemoteFileInfo mCurrentRemoteFileInfo;
|
||||||
|
QTimer mProgressEmitterTimer;
|
||||||
|
qint64 mDownloadedBytes;
|
||||||
|
|
||||||
int mCurrentDownloadId;
|
int mCurrentDownloadId;
|
||||||
int mActiveWorkerCount;
|
int mActiveWorkerCount;
|
||||||
@@ -88,6 +91,7 @@ class SpkDownloadMgr : public QObject
|
|||||||
private slots:
|
private slots:
|
||||||
void WorkerFinish();
|
void WorkerFinish();
|
||||||
void WorkerDownloadProgress(); ///< Be connected to ***QNetworkReply::readyRead***
|
void WorkerDownloadProgress(); ///< Be connected to ***QNetworkReply::readyRead***
|
||||||
|
void ProgressTimer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void LinkReplyWithMe(QNetworkReply*);
|
void LinkReplyWithMe(QNetworkReply*);
|
||||||
@@ -95,7 +99,7 @@ class SpkDownloadMgr : public QObject
|
|||||||
void TryScheduleFailureRetries(int i); ///< Try schedule on a specific task slot.
|
void TryScheduleFailureRetries(int i); ///< Try schedule on a specific task slot.
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void DownloadProgressed(qint64 bytes, qint64 total);
|
void DownloadProgressed(qint64 bytes, qint64 total, int id);
|
||||||
void DownloadStopped(TaskResult status, int id);
|
void DownloadStopped(TaskResult status, int id);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
52
inc/spkdownloadentry.h
Normal file
52
inc/spkdownloadentry.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QLabel>
|
||||||
|
#include "qt/elidedlabel.h"
|
||||||
|
#include "spkloading.h"
|
||||||
|
#include <QProgressBar>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
class SpkDownloadEntry : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SpkDownloadEntry(QWidget* parent = nullptr);
|
||||||
|
~SpkDownloadEntry();
|
||||||
|
|
||||||
|
static constexpr QSize IconSize { 64, 64 };
|
||||||
|
|
||||||
|
enum DownloadEntryStatus
|
||||||
|
{
|
||||||
|
Invalid = -1,
|
||||||
|
Waiting,
|
||||||
|
Downloading,
|
||||||
|
Paused,
|
||||||
|
Failed,
|
||||||
|
ToBeInstalled,
|
||||||
|
Installing,
|
||||||
|
Installed,
|
||||||
|
InstallFailed
|
||||||
|
};
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void SetBasicInfo(QString name, QPixmap icon);
|
||||||
|
void SetStatus(DownloadEntryStatus status);
|
||||||
|
void SetProgress(int);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLabel *mIcon, *mMessage;
|
||||||
|
ElidedLabel *mAppName;
|
||||||
|
QProgressBar *mProgress;
|
||||||
|
QPushButton *mBtnDelete,
|
||||||
|
*mBtnActions; // Actions include Retry Pause Install etc, one status at a time
|
||||||
|
SpkLoading *mLoading;
|
||||||
|
|
||||||
|
QHBoxLayout *mLayMsgs, *mLayMain;
|
||||||
|
QVBoxLayout *mLayInfo;
|
||||||
|
|
||||||
|
};
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "page/spkpageuitest.h"
|
#include "page/spkpageuitest.h"
|
||||||
#include "page/spkpageapplist.h"
|
#include "page/spkpageapplist.h"
|
||||||
#include "page/spkpageappdetails.h"
|
#include "page/spkpageappdetails.h"
|
||||||
|
#include "page/spkpagedownloads.h"
|
||||||
|
|
||||||
class QNetworkReply;
|
class QNetworkReply;
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ namespace SpkUi
|
|||||||
PgInvalid = -1,
|
PgInvalid = -1,
|
||||||
PgAppList,
|
PgAppList,
|
||||||
PgAppDetails,
|
PgAppDetails,
|
||||||
|
PgDownloads,
|
||||||
PgQssTest // Must be at last
|
PgQssTest // Must be at last
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -152,6 +154,7 @@ namespace SpkUi
|
|||||||
|
|
||||||
QTreeWidgetItem *CategoryParentItem,
|
QTreeWidgetItem *CategoryParentItem,
|
||||||
*AppDetailsItem,
|
*AppDetailsItem,
|
||||||
|
*DownloadsItem,
|
||||||
*UiTestItem;
|
*UiTestItem;
|
||||||
|
|
||||||
// Title bar search bar
|
// Title bar search bar
|
||||||
@@ -163,6 +166,7 @@ namespace SpkUi
|
|||||||
SpkPageUiTest *PageQssTest;
|
SpkPageUiTest *PageQssTest;
|
||||||
SpkPageAppList *PageAppList;
|
SpkPageAppList *PageAppList;
|
||||||
SpkPageAppDetails *PageAppDetails;
|
SpkPageAppDetails *PageAppDetails;
|
||||||
|
SpkPageDownloads *PageDownloads;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ class SpkResource : public QObject
|
|||||||
|
|
||||||
inline QString GetCachePath(const ResourceTask &task);
|
inline QString GetCachePath(const ResourceTask &task);
|
||||||
|
|
||||||
|
ResourceResult CacheLookup(QString pkgName, ResourceType type, QVariant info);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief When the resource context was changed, the new context needs to acquire the resource
|
* @brief When the resource context was changed, the new context needs to acquire the resource
|
||||||
* manager, so the resource manager can download resource for the new context.
|
* manager, so the resource manager can download resource for the new context.
|
||||||
|
|||||||
@@ -8,9 +8,10 @@
|
|||||||
#include <QtNetwork/QNetworkAccessManager>
|
#include <QtNetwork/QNetworkAccessManager>
|
||||||
|
|
||||||
#include "spklogging.h"
|
#include "spklogging.h"
|
||||||
#include "spkmainwindow.h"
|
|
||||||
#include "spkresource.h"
|
#include "spkresource.h"
|
||||||
|
|
||||||
|
class SpkMainWindow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief SpkStore class is the core of the store client side program, it is constructed first and
|
* @brief SpkStore class is the core of the store client side program, it is constructed first and
|
||||||
* handling all processing after the launch. All client side data should be held by it,
|
* handling all processing after the launch. All client side data should be held by it,
|
||||||
|
|||||||
@@ -15,5 +15,6 @@
|
|||||||
<file>icons/settings.svg</file>
|
<file>icons/settings.svg</file>
|
||||||
<file>icons/daynight-dark.svg</file>
|
<file>icons/daynight-dark.svg</file>
|
||||||
<file>icons/daynight.svg</file>
|
<file>icons/daynight.svg</file>
|
||||||
|
<file>icons/loading-icon.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
|
||||||
#include "spkdownload.h"
|
#include "spkdownload.h"
|
||||||
#include "spkutils.h"
|
#include "spkutils.h"
|
||||||
|
#include "spkui_general.h"
|
||||||
|
#include "spkpopup.h"
|
||||||
#include <QEventLoop>
|
#include <QEventLoop>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
SpkDownloadMgr::SpkDownloadMgr(QObject *parent)
|
SpkDownloadMgr::SpkDownloadMgr(QObject *parent)
|
||||||
{
|
{
|
||||||
@@ -18,6 +21,12 @@ SpkDownloadMgr::SpkDownloadMgr(QObject *parent)
|
|||||||
|
|
||||||
mCurrentDownloadId = -1;
|
mCurrentDownloadId = -1;
|
||||||
mActiveWorkerCount = 0;
|
mActiveWorkerCount = 0;
|
||||||
|
mDownloadedBytes = 0;
|
||||||
|
|
||||||
|
mProgressEmitterTimer.setInterval(800);
|
||||||
|
|
||||||
|
connect(&mProgressEmitterTimer, &QTimer::timeout,
|
||||||
|
this, &SpkDownloadMgr::ProgressTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
SpkDownloadMgr::~SpkDownloadMgr()
|
SpkDownloadMgr::~SpkDownloadMgr()
|
||||||
@@ -139,6 +148,8 @@ bool SpkDownloadMgr::StartNewDownload(QString path, int downloadId)
|
|||||||
i.Reply->setProperty("failCount", 0); // Used for fail retry algorithm
|
i.Reply->setProperty("failCount", 0); // Used for fail retry algorithm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mProgressEmitterTimer.start();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +161,27 @@ bool SpkDownloadMgr::PauseCurrentDownload()
|
|||||||
|
|
||||||
bool SpkDownloadMgr::CancelCurrentDownload()
|
bool SpkDownloadMgr::CancelCurrentDownload()
|
||||||
{
|
{
|
||||||
// UNIMPLEMENTED
|
// Don't proceed when no downloads are there
|
||||||
|
if(mCurrentDownloadId == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Terminate all workers
|
||||||
|
for(auto &i : mScheduledWorkers)
|
||||||
|
{
|
||||||
|
auto r = i.Reply;
|
||||||
|
r->blockSignals(true);
|
||||||
|
r->abort();
|
||||||
|
r->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminate and delete the temporary file
|
||||||
|
mDestFile.close();
|
||||||
|
if(!mDestFile.remove())
|
||||||
|
{
|
||||||
|
sErr(tr("SpkDownloadMgr: Cannot remove destination file %1 of a cancelled task")
|
||||||
|
.arg(mDestFile.fileName()));
|
||||||
|
SpkUi::Popup->Show(tr("The destination file of the cancelled task can't be deleted!"));
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,6 +209,9 @@ void SpkDownloadMgr::WorkerFinish()
|
|||||||
mScheduledWorkers.clear();
|
mScheduledWorkers.clear();
|
||||||
mFailureRetryQueue.clear();
|
mFailureRetryQueue.clear();
|
||||||
mCurrentDownloadId = -1;
|
mCurrentDownloadId = -1;
|
||||||
|
mDownloadedBytes = 0;
|
||||||
|
|
||||||
|
mProgressEmitterTimer.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -217,6 +251,12 @@ void SpkDownloadMgr::WorkerDownloadProgress()
|
|||||||
mDestFile.seek(worker.BeginOffset + worker.BytesRecvd);
|
mDestFile.seek(worker.BeginOffset + worker.BytesRecvd);
|
||||||
mDestFile.write(replyData);
|
mDestFile.write(replyData);
|
||||||
worker.BytesRecvd += replyData.size();
|
worker.BytesRecvd += replyData.size();
|
||||||
|
mDownloadedBytes += replyData.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpkDownloadMgr::ProgressTimer()
|
||||||
|
{
|
||||||
|
emit DownloadProgressed(mDownloadedBytes, mCurrentRemoteFileInfo.Size, mCurrentDownloadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpkDownloadMgr::LinkReplyWithMe(QNetworkReply *reply)
|
void SpkDownloadMgr::LinkReplyWithMe(QNetworkReply *reply)
|
||||||
|
|||||||
@@ -63,6 +63,18 @@ void SpkResource::ResourceDownloaded()
|
|||||||
|
|
||||||
ResourceResult ret;
|
ResourceResult ret;
|
||||||
ret.status = ResourceStatus::Ready;
|
ret.status = ResourceStatus::Ready;
|
||||||
|
|
||||||
|
if(reply->error() != QNetworkReply::NoError)
|
||||||
|
{
|
||||||
|
ret.status = ResourceStatus::Failed;
|
||||||
|
sWarn(tr("SpkResource: %1 cannot be downloaded, error code %2")
|
||||||
|
.arg(reply->url().toString())
|
||||||
|
.arg(reply->error()));
|
||||||
|
// Tell ResourceContext
|
||||||
|
if(!reply->property("outdated").toBool())
|
||||||
|
AcquisitionFinish(id, ret);
|
||||||
|
}
|
||||||
|
|
||||||
ret.data = reply->readAll();
|
ret.data = reply->readAll();
|
||||||
|
|
||||||
// Save cache to disk
|
// Save cache to disk
|
||||||
@@ -106,12 +118,13 @@ void SpkResource::Acquire(SpkPageBase *dest, bool stopOngoing, bool clearQueue)
|
|||||||
// And abort as requested.
|
// And abort as requested.
|
||||||
if(stopOngoing)
|
if(stopOngoing)
|
||||||
i->abort();
|
i->abort();
|
||||||
delete i;
|
mWorkingRequests.remove(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mWorkingRequests.clear();
|
||||||
|
|
||||||
if(stopOngoing)
|
if(stopOngoing)
|
||||||
{
|
{
|
||||||
mWorkingRequests.clear();
|
|
||||||
mRequestSemaphore->release(mMaximumConcurrent); // Release all semaphore users
|
mRequestSemaphore->release(mMaximumConcurrent); // Release all semaphore users
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +151,23 @@ ResourceResult SpkResource::LocateCachedResource(const ResourceTask &task)
|
|||||||
|
|
||||||
// If there is the desired file, then we return the resource in binary
|
// If there is the desired file, then we return the resource in binary
|
||||||
auto cacheFullPath = GetCachePath(task);
|
auto cacheFullPath = GetCachePath(task);
|
||||||
if(list.contains(SpkUtils::CutFileName(cacheFullPath)))
|
|
||||||
|
bool isCacheHit;
|
||||||
|
// Wildcard support
|
||||||
|
if(task.path == "*")
|
||||||
|
{
|
||||||
|
cacheFullPath.chop(1);
|
||||||
|
auto filterResult = list.filter(SpkUtils::CutFileName(cacheFullPath));
|
||||||
|
isCacheHit = !filterResult.isEmpty();
|
||||||
|
if(isCacheHit)
|
||||||
|
cacheFullPath = SpkUtils::CutPath(cacheFullPath) + '/' + filterResult[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
isCacheHit = list.contains(SpkUtils::CutFileName(cacheFullPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isCacheHit)
|
||||||
{
|
{
|
||||||
// qInfo() << "Cache hit:" << GetCachePath(task);
|
// qInfo() << "Cache hit:" << GetCachePath(task);
|
||||||
QFile cacheFile(cacheFullPath);
|
QFile cacheFile(cacheFullPath);
|
||||||
@@ -198,7 +227,13 @@ void SpkResource::PurgeCachedResource(const QString &aPkgName, SpkResource::Reso
|
|||||||
QString SpkResource::GetCachePath(const ResourceTask &task)
|
QString SpkResource::GetCachePath(const ResourceTask &task)
|
||||||
{
|
{
|
||||||
return mCacheDirectory + task.pkgName + '/' + ResourceName.value(task.type) + '.' +
|
return mCacheDirectory + task.pkgName + '/' + ResourceName.value(task.type) + '.' +
|
||||||
task.info.toString() + '.' + SpkUtils::CutFileName(task.path);
|
task.info.toString() + '.' + SpkUtils::CutFileName(task.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceResult SpkResource::CacheLookup(QString pkgName, ResourceType type, QVariant info)
|
||||||
|
{
|
||||||
|
ResourceTask task { .pkgName = pkgName, .path = "*", .type = type, .info = info, .id = -1 };
|
||||||
|
return LocateCachedResource(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QMap<SpkResource::ResourceType, QString> SpkResource::ResourceName
|
const QMap<SpkResource::ResourceType, QString> SpkResource::ResourceName
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "dtk/spkdtkplugin.h"
|
#include "dtk/spkdtkplugin.h"
|
||||||
#include "gitver.h"
|
#include "gitver.h"
|
||||||
|
#include "spkmainwindow.h"
|
||||||
#include "spkpopup.h"
|
#include "spkpopup.h"
|
||||||
#include "spkstore.h"
|
#include "spkstore.h"
|
||||||
#include "spkutils.h"
|
#include "spkutils.h"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonDocument>
|
||||||
#include "spkutils.h"
|
#include "spkutils.h"
|
||||||
|
|
||||||
void SpkUtils::VerifySingleRequest(QPointer<QNetworkReply> aReply)
|
void SpkUtils::VerifySingleRequest(QPointer<QNetworkReply> aReply)
|
||||||
|
|||||||
Reference in New Issue
Block a user