添加应用详情页面

This commit is contained in:
RigoLigoRLC 2021-09-19 20:22:36 +08:00
parent d2ab7cfbf7
commit 2b12c38f50
18 changed files with 473 additions and 17 deletions

@ -75,6 +75,7 @@ set(SOURCE_FILES
inc/page/spkpagebase.h gui/page/spkpagebase.cpp
inc/page/spkpageuitest.h gui/page/spkpageuitest.cpp
inc/page/spkpageapplist.h gui/page/spkpageapplist.cpp
inc/page/spkpageappdetails.h gui/page/spkpageappdetails.cpp
inc/spkstore.h src/spkstore.cpp
inc/spkuimsg.h src/spkuimsg.cpp

@ -40,4 +40,13 @@ C++ 规范要求的和第三方库有较大差异的除外。例如,`SpkUiMess
如非第三方代码,一般以 `Spk` 前缀标明。
实现 UI 的类都应归于 `SpkUi` 命名空间。
## 类定义
### 一般规则
Qt 类的 `Q_OBJECT` 应置于类定义最顶端。
`public` `protected``private` 等标签中只应该包含一类成员,
如单个 `public` 标签内只能包含方法,或成员。
信号、槽等不得与普通方法混合。
<!--TODO-->

@ -0,0 +1,182 @@
// SPDX-License-Identifier: GPL-3.0-only
#include "page/spkpageappdetails.h"
#include "spkutils.h"
namespace SpkUi
{
constexpr QSize SpkPageAppDetails::IconSize;
void SpkPageAppDetails::LoadAppResources(QString aPkgName, QString aIcon, QStringList aScreenshots,
QStringList aTags)
{
QPixmap pic;
// Load icon
auto res = RES->RequestResource(0, aPkgName, SpkResource::ResourceType::AppIcon, aIcon);
if(res.status == SpkResource::ResourceStatus::Ready)
{
if(pic.loadFromData(res.data))
mAppIcon->setPixmap(pic.scaled(IconSize,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation));
else
{
mAppIcon->setPixmap(QIcon::fromTheme("dialog-error").pixmap(SpkAppItem::IconSize_));
RES->PurgeCachedResource(aPkgName, SpkResource::ResourceType::AppIcon, 0);
}
}
// Load screenshots
if(aScreenshots.isEmpty())
return;
int shotId = 0;
for(auto &i : aScreenshots)
{
shotId++;
res = RES->RequestResource(shotId, aPkgName, SpkResource::ResourceType::AppScreenshot, aIcon,
shotId);
if(res.status == SpkResource::ResourceStatus::Ready)
{
if(pic.loadFromData(res.data))
;// TODO
else
{
// TODO
// mAppIcon->setPixmap(QIcon::fromTheme("dialog-error").pixmap(SpkAppItem::IconSize_));
RES->PurgeCachedResource(aPkgName, SpkResource::ResourceType::AppScreenshot, 0);
}
}
}
// TODO: tags
}
SpkPageAppDetails::SpkPageAppDetails(QWidget *parent) : SpkPageBase(parent)
{
mMainArea = new QScrollArea;
mMainArea->setWidgetResizable(true);
mMainArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
mLay4MainArea = new QVBoxLayout(this);
mLay4MainArea->addWidget(mMainArea);
mMainLay = new QVBoxLayout(mMainArea);
mMainLay->setSizeConstraint(QLayout::SetMinAndMaxSize);
mAppIcon = new QLabel;
mAppTitle = new QLabel;
mAppTitle->setObjectName("styDetTitle");
mAppDescription = new QLabel;
mAppDescription->setObjectName("styDetDesc");
mAppDescription->setWordWrap(true);
mAppShortDesc = new QLabel;
mAppShortDesc->setObjectName("styDetDesc");
mAppShortDesc->setWordWrap(true);
// NOTE: Seems Qt have trouble dealing with wrapped text here. Removing the following operations
// to mAppShortDesc will result in broken layout. Very possible that it's a Qt bug.
mAppShortDesc->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
mAppShortDesc->setMinimumWidth(100);
mVersion = new QLabel;
mPkgName = new QLabel;
mPkgName->setObjectName("styDetPkg");
mTitleLay = new QVBoxLayout;
mTitleLay->setAlignment(Qt::AlignTop);
mTitleLay->addWidget(mAppTitle);
mTitleLay->addWidget(mVersion);
mTitleLay->addWidget(mAppShortDesc);
mTitleLay->addWidget(mPkgName);
mTitleLay->setSpacing(0);
mIconTitleLay = new QHBoxLayout;
mIconTitleLay->setAlignment(Qt::AlignLeft);
mIconTitleLay->addWidget(mAppIcon);
mIconTitleLay->addSpacing(15);
mIconTitleLay->addLayout(mTitleLay);
mIconTitleWidget = new QWidget;
mIconTitleWidget->setLayout(mIconTitleLay);
mAuthor = new SpkDetailEntry;
mAuthor->SetTitle(tr("Author"));
mContributor = new SpkDetailEntry;
mContributor->SetTitle(tr("Contributor"));
mSite = new SpkDetailEntry;
mSite->SetTitle(tr("Website"));
mArch = new SpkDetailEntry;
mArch->SetTitle(tr("Architecture"));
mSize = new SpkDetailEntry;
mSize->SetTitle(tr("Size"));
mDetailLay = new SpkStretchLayout;
mDetailLay->setSpacing(12);
mDetailLay->addWidget(mAuthor);
mDetailLay->addWidget(mContributor);
mDetailLay->addWidget(mSize);
mDetailLay->addWidget(mArch);
mDetailLay->addWidget(mSite);
// mDetailWidget = new QWidget;
// mDetailWidget->setLayout(mDetailLay);
// mDetailWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
mMainLay->setAlignment(Qt::AlignTop);
mMainLay->addWidget(mIconTitleWidget);
mMainLay->addLayout(mDetailLay);
mMainLay->addWidget(mAppDescription);
// mMainLay->addStretch();
mWid4MainArea = new QWidget;
mWid4MainArea->setLayout(mMainLay);
mMainArea->setWidget(mWid4MainArea);
}
void SpkPageAppDetails::ResourceAcquisitionFinished(int id, ResourceResult result)
{
QPixmap icon;
if(!id)
{
// id == 0, icon
if(result.status == SpkResource::ResourceStatus::Ready)
{
if(icon.loadFromData(result.data))
mAppIcon->setPixmap(icon.scaled(SpkAppItem::IconSize_,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation));
else
mAppIcon->setPixmap(QIcon::fromTheme("dialog-error").pixmap(SpkAppItem::IconSize_));
}
else if(result.status == SpkResource::ResourceStatus::Failed)
{
mAppIcon->setPixmap(QIcon::fromTheme("dialog-error").pixmap(SpkAppItem::IconSize_));
RES->PurgeCachedResource(mPkgName->text(), SpkResource::ResourceType::AppIcon, 0);
}
}
else
{
// TODO: screenshots
}
}
void SpkPageAppDetails::Activated()
{
RES->Acquire(this, false);
}
SpkDetailEntry::SpkDetailEntry(QWidget *parent) : QWidget(parent)
{
setLayout(&mLay);
mLay.addWidget(&mTitle);
mLay.addWidget(&mField);
mTitle.setAlignment(Qt::AlignLeft);
mField.setAlignment(Qt::AlignRight);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
setMinimumWidth(300);
setAutoFillBackground(true);
}
}

@ -53,6 +53,7 @@ namespace SpkUi
auto item = new SpkAppItem(appId, this);
auto id = mAppItemList.size();
connect(item, &SpkAppItem::clicked, this, &SpkPageAppList::ApplicationClicked);
item->SetTitle(name);
item->SetDescription(description);
item->setProperty("pkg_name", pkgName);

@ -51,6 +51,18 @@ SpkUi::SpkPageUiTest::SpkPageUiTest(QWidget *parent) : QSplitter(parent)
"Phasellus finibus risus id aliquam pulvinar.");
AppItem->SetIcon(QIcon::fromTheme("dialog-information").pixmap(72, 72));
Detail1 = new SpkDetailEntry; Detail1->SetTitle("Foo"); Detail1->SetValue("1");
Detail2 = new SpkDetailEntry; Detail2->SetTitle("Foo"); Detail2->SetValue("1");
Detail3 = new SpkDetailEntry; Detail3->SetTitle("Foo"); Detail3->SetValue("1");
DetailsLay = new SpkStretchLayout;
DetailsLay->addWidget(Detail1);
DetailsLay->addWidget(Detail2);
DetailsLay->addWidget(Detail3);
DetailsWidget = new QWidget;
DetailsWidget->setLayout(DetailsLay);
PopupText = new QLineEdit(this);
PopupText->setObjectName("spk_pg_qsstest_poptext");
PopupText->setText("Hello, world");
@ -85,6 +97,7 @@ SpkUi::SpkPageUiTest::SpkPageUiTest(QWidget *parent) : QSplitter(parent)
VLayTestWidgets->addWidget(ShowPopup);
VLayTestWidgets->addWidget(ShowAbout);
VLayTestWidgets->addWidget(AppItem);
VLayTestWidgets->addWidget(DetailsWidget);
Group = new QGroupBox(this);
Group->setObjectName("spk_pg_qsstest_groupbox");

@ -50,3 +50,15 @@ void SpkAppItem::paintEvent(QPaintEvent *e)
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
void SpkAppItem::mousePressEvent(QMouseEvent *e)
{
mPressCond = true;
}
void SpkAppItem::mouseReleaseEvent(QMouseEvent *e)
{
if(mPressCond)
emit clicked(mAppId);
mPressCond = false;
}

@ -157,7 +157,7 @@ void SpkMainWindow::PopulateAppList(QJsonObject appData, QString &&keyword)
static auto err =
[](){
sErr("Received invalid application list data!");
SpkUiMessage::SendStoreNotification(tr("An invalid response was received. Please try again!"));
SpkUiMessage::SendStoreNotification(tr("Received an invalid response. Please try again!"));
return;
};
int pgCurrent, pgTotal, totalApps;
@ -178,7 +178,7 @@ void SpkMainWindow::PopulateAppList(QJsonObject appData, QString &&keyword)
auto apps = appData.value("data").toArray();
foreach(auto i, apps)
for(auto &&i : apps)
{
if(i.isObject())
{
@ -206,10 +206,112 @@ void SpkMainWindow::PopulateAppList(QJsonObject appData, QString &&keyword)
}
}
void SpkMainWindow::EnterAppDetails(int aAppId)
{
using namespace SpkUtils;
VerifySingleRequest(mAppDetailsGetReply);
QJsonObject reqData;
QJsonDocument reqDoc;
reqData.insert("application_id", QJsonValue(aAppId));
reqDoc.setObject(reqData);
mAppDetailsGetReply = STORE->SendApiRequest("application/get_application_detail", reqDoc);
DeleteReplyLater(mAppDetailsGetReply);
connect(mAppDetailsGetReply, &QNetworkReply::finished,
this, &SpkMainWindow::AppDetailsDataReceived);
setCursor(Qt::BusyCursor);
}
void SpkMainWindow::AppDetailsDataReceived()
{
QJsonValue retval;
if(!SpkUtils::VerifyReplyJson(mAppDetailsGetReply, retval) || !retval.isObject())
{
sErrPop(tr("Failed to open app details page! Type of retval: %1.").arg(retval.type()));
return;
}
SwitchToPage(SpkUi::PgAppList);
PopulateAppDetails(retval.toObject());
setCursor(Qt::ArrowCursor);
}
void SpkMainWindow::PopulateAppDetails(QJsonObject appDetails)
{
QString pkgName, author, contributor, site, iconPath, arch, version, details, shortDesc, name;
QStringList screenshots, tags;
int packageSize;
static auto err =
[](){
sErr("Received invalid application details!");
SpkUiMessage::SendStoreNotification(tr("Received an invalid response. Please try again!"));
return;
};
if(appDetails.contains("package") && appDetails.value("package").isString())
pkgName = appDetails.value("package").toString();
else return err();
if(appDetails.contains("application_name_zh") && appDetails.value("application_name_zh").isString())
name = appDetails.value("application_name_zh").toString();
else name = pkgName;
if(appDetails.contains("version") && appDetails.value("version").isString())
version = appDetails.value("version").toString();
else return err();
if(appDetails.contains("icons") && appDetails.value("icons").isString())
iconPath= appDetails.value("icons").toString();
if(appDetails.contains("author") && appDetails.value("author").isString())
author = appDetails.value("author").toString();
if(appDetails.contains("contributor") && appDetails.value("contributor").isString())
contributor = appDetails.value("contributor").toString();
if(appDetails.contains("website") && appDetails.value("website").isString())
site = appDetails.value("website").toString();
if(appDetails.contains("description") && appDetails.value("description").isString())
shortDesc = appDetails.value("description").toString();
if(appDetails.contains("more") && appDetails.value("more").isString())
details = appDetails.value("more").toString();
if(appDetails.contains("arch") && appDetails.value("arch").isString())
arch = appDetails.value("arch").toString();
if(appDetails.contains("size") && appDetails.value("size").isDouble())
packageSize = appDetails.value("size").toInt();
QJsonArray imgs;
if(appDetails.contains("img_urls") && appDetails.value("img_urls").isArray())
imgs = appDetails.value("img_urls").toArray();
if(!imgs.isEmpty())
for(auto &&i : imgs)
if(i.isString()) screenshots << i.toString();
QJsonArray tags_j;
if(appDetails.contains("tags") && appDetails.value("tags").isArray())
imgs = appDetails.value("tags").toArray();
if(!tags_j.isEmpty())
for(auto &&i : tags_j)
if(i.isString()) tags << i.toString();
// Details string has a strangely appended LF. IDK but still should remove it.
shortDesc = shortDesc.trimmed();
auto w = ui->PageAppDetails;
w->mPkgName->setText(pkgName);
w->mAppTitle->setText(name);
w->mAppShortDesc->setText(shortDesc);
w->mAppDescription->setText(details);
w->mAuthor->SetValue(author);
w->mContributor->SetValue(contributor);
w->mSite->SetValue(site);
w->mArch->SetValue(arch);
w->mSize->SetValue(SpkUtils::BytesToSize(packageSize));
w->mVersion->setText(version);
SwitchToPage(SpkUi::PgAppDetails);
ui->AppDetailsItem->setHidden(false);
ui->CategoryWidget->setCurrentItem(ui->AppDetailsItem);
w->LoadAppResources(pkgName, iconPath, screenshots, tags);
}
// ==================== Main Window Initialization ====================
void SpkMainWindow::Initialize()
{
connect(ui->SidebarMgr, &SpkUi::SpkSidebarSelector::SwitchToPage,
this, &SpkMainWindow::SwitchToPage);
connect(ui->SidebarMgr, &SpkUi::SpkSidebarSelector::SwitchToCategory,
this, &SpkMainWindow::EnterCategoryList);
connect(ui->PageAppList, &SpkUi::SpkPageAppList::SwitchListPage,
@ -218,6 +320,8 @@ void SpkMainWindow::Initialize()
this, &SpkMainWindow::SearchKeyword);
connect(ui->SearchEdit, &QLineEdit::returnPressed,
[=](){ emit SearchKeyword(ui->SearchEdit->text(), 1); });
connect(ui->PageAppList, &SpkUi::SpkPageAppList::ApplicationClicked,
this, &SpkMainWindow::EnterAppDetails);
}
// ==================== Main Widget Initialization ====================
@ -292,11 +396,28 @@ SpkUi::SpkMainWidget::SpkMainWidget(QWidget *parent) : QFrame(parent)
CategoryWidget->setColumnCount(1);
CategoryWidget->setHeaderHidden(true);
CategoryWidget->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
//============ Sidebar entries BEGIN ============
AppDetailsItem = new QTreeWidgetItem(QStringList(tr("App Details")));
AppDetailsItem->setData(0, SpkSidebarSelector::RoleItemIsCategory, false);
AppDetailsItem->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, SpkStackedPages::PgAppDetails);
CategoryParentItem = new QTreeWidgetItem(QStringList(tr("Categories")));
CategoryParentItem->setFlags(CategoryParentItem->flags().setFlag(Qt::ItemIsSelectable, false));
CategoryParentItem->setExpanded(true);
#ifndef NDEBUG
UiTestItem = new QTreeWidgetItem(QStringList(tr("UI TEST")));
UiTestItem->setData(0, SpkSidebarSelector::RoleItemIsCategory, false);
UiTestItem->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, SpkStackedPages::PgQssTest);
#endif
//============ Sidebar entries END ============
SidebarMgr->AddUnusableItem(CategoryParentItem);
CategoryWidget->addTopLevelItem(AppDetailsItem);
CategoryWidget->addTopLevelItem(CategoryParentItem);
CategoryWidget->addTopLevelItem(UiTestItem);
// Must be done after added into a view.
AppDetailsItem->setHidden(true); // Hide until we actually open up a Details page
CategoryParentItem->setExpanded(true);
// FIXMEIFPOSSIBLE: Fusion adds extra gradient.
// Details: https://forum.qt.io/topic/128190/fusion-style-kept-adding-an-extra-
@ -355,7 +476,7 @@ SpkUi::SpkMainWidget::SpkMainWidget(QWidget *parent) : QFrame(parent)
//============ Pages =============
// Red-Black tree based map will be able to sort things
// Red-Black tree based map will be able to sort things. Just for convenience of ordering pages.
QMap<SpkStackedPages, QWidget*> sorter;
// Initialize pages
@ -363,6 +484,10 @@ SpkUi::SpkMainWidget::SpkMainWidget(QWidget *parent) : QFrame(parent)
PageAppList->setProperty("spk_pageid", SpkStackedPages::PgAppList);
sorter[PgAppList] = PageAppList;
PageAppDetails = new SpkUi::SpkPageAppDetails(this);
PageAppDetails->setProperty("spk_pageid", SpkStackedPages::PgAppDetails);
sorter[PgAppDetails] = PageAppDetails;
#ifndef NDEBUG // If only in debug mode should we initialize QSS test page
PageQssTest = new SpkUi::SpkPageUiTest(this);
PageQssTest->setProperty("spk_pageid", SpkStackedPages::PgQssTest);

@ -26,7 +26,8 @@ const std::map<SpkUi::Qss::ColorSetIndex, const char *> SpkUi::Qss::ColorSet2Tok
{ TextOnSelection, "TXACC" },
{ TextOnGlobalBgnd, "TXGBG" },
{ TextOnControlsBgnd, "TXCBG" },
{ TextLighter, "TXL" },
{ TextLighter, "TXL1" },
{ TextEvenLighter, "TXL2" },
{ TextDisabled, "TXD" },
{ GlossyEdge, "GLS" },
{ ShadesEdge, "SHD" }
@ -51,6 +52,7 @@ const std::map<SpkUi::Qss::ColorSetIndex, QColor> SpkUi::Qss::DarkColorSet
{ TextOnGlobalBgnd, ColorTextOnBackground(0x282828) },
{ TextOnControlsBgnd, ColorTextOnBackground(0x282828) },
{ TextLighter, 0xd5d5d5 },
{ TextEvenLighter, 0x505050 },
{ TextDisabled, 0xbebebe },
{ GlossyEdge, 0x656565 },
{ ShadesEdge, 0x7b7b7b }
@ -75,6 +77,7 @@ const std::map<SpkUi::Qss::ColorSetIndex, QColor> SpkUi::Qss::LightColorSet
{ TextOnGlobalBgnd, ColorTextOnBackground(0xf8f8f8) },
{ TextOnControlsBgnd, ColorTextOnBackground(0xf8f8f8) },
{ TextLighter, 0x2a2a2a },
{ TextEvenLighter, 0xa0a0a0 },
{ TextDisabled, 0x8a8a8a },
{ GlossyEdge, 0xc5c5c5 },
{ ShadesEdge, 0x9d9d9d }

@ -21,7 +21,7 @@ QSize SpkStretchLayout::sizeHint() const
{
if(mItems.isEmpty())
return { 300, 300 };
auto w = geometry().width();
auto w = geometry().width() - spacing();
auto it = mItems.first();
int countPerLine = w / (it->minimumSize().width() + spacing());
int lines = ceil((double)mItems.size() / countPerLine);
@ -75,14 +75,16 @@ void SpkStretchLayout::setGeometry(const QRect &rect)
else // Stretch items.
size = QSize {(w / countPerLine - spc), itm->maximumSize().height() };
auto origin = geometry().topLeft();
QLayoutItem *o;
for(int i = 0; i < mItems.size(); i++)
{
o = mItems.at(i);
QRect geo;
geo.setSize(size);
geo.moveTo((i % countPerLine) * (size.width() + spc) + spc,
(i / countPerLine) * (size.height() + spacing()) + spc);
geo.moveTo((i % countPerLine) * (size.width() + spc) + spc + origin.x(),
(i / countPerLine) * (size.height() + spacing()) + spc + origin.y());
o->setGeometry(geo);
}
}

@ -0,0 +1,55 @@
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include <QLabel>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QFormLayout>
#include "page/spkpagebase.h"
#include "spkstretchlayout.h"
namespace SpkUi
{
class SpkDetailEntry;
class SpkPageAppDetails : public SpkPageBase
{
Q_OBJECT
public:
SpkPageAppDetails(QWidget *parent = nullptr);
void LoadAppResources(QString pkgName, QString icon, QStringList screenshots, QStringList tags);
private:
public slots:
void ResourceAcquisitionFinished(int id, ResourceResult result);
void Activated();
public:
static constexpr QSize IconSize { 144, 144 };
QScrollArea *mMainArea;
QWidget *mDetailWidget, *mIconTitleWidget, *mWid4MainArea;
QLabel *mAppTitle, *mAppIcon, *mAppDescription, *mAppShortDesc, *mPkgName, *mVersion;
SpkDetailEntry *mAuthor, *mContributor, *mSite, *mArch, *mSize;
SpkStretchLayout *mDetailLay;
QVBoxLayout *mMainLay, *mTitleLay, *mLay4MainArea;
QHBoxLayout *mIconTitleLay;
};
class SpkDetailEntry : public QWidget
{
Q_OBJECT
public:
SpkDetailEntry(QWidget *parent = nullptr);
void SetTitle(const QString &s) { mTitle.setText(s); }
void SetValue(const QString &s) { mField.setText(s); }
private:
QLabel mTitle, mField;
QHBoxLayout mLay;
};
}

@ -43,7 +43,7 @@ namespace SpkUi
QString mKeyword;
signals:
void ApplicationClicked(QString name, QString pkgName);
void ApplicationClicked(int appId);
void SwitchListPage(int categoryId, int page);
void SwitchSearchPage(QString keyword, int page);

@ -12,6 +12,8 @@
#include <QHBoxLayout>
#include <QSlider>
#include "spkappitem.h"
#include "spkstretchlayout.h"
#include "page/spkpageappdetails.h"
#include "spkloading.h"
@ -40,6 +42,9 @@ namespace SpkUi
QSlider *SlideV;
SpkLoading *Loading;
SpkAppItem *AppItem;
SpkStretchLayout *DetailsLay;
SpkDetailEntry *Detail1, *Detail2, *Detail3;
QWidget *DetailsWidget;
QLineEdit *PopupText;
QPushButton *ShowPopup,

@ -18,6 +18,8 @@ class SpkAppItem : public QWidget
protected:
void paintEvent(QPaintEvent *e);
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
public:
static constexpr int IconSize = 72;
@ -29,7 +31,11 @@ class SpkAppItem : public QWidget
ElidedLabel *mDescription;
int mAppId;
bool mPressCond;
QVBoxLayout *mLayText;
QHBoxLayout *mMainLay;
signals:
void clicked(int);
};

@ -16,6 +16,7 @@
#include "spkfocuslineedit.h"
#include "page/spkpageuitest.h"
#include "page/spkpageapplist.h"
#include "page/spkpageappdetails.h"
class QNetworkReply;
@ -25,6 +26,7 @@ namespace SpkUi
{
PgInvalid = -1,
PgAppList,
PgAppDetails,
PgQssTest // Must be at last
};
@ -86,7 +88,7 @@ namespace SpkUi
mLastSelectedItem = nullptr;
}
mLastCheckedBtn = b;
emit SwitchToPage(b->property("spk_pageno").toInt());
emit SwitchToPage(static_cast<SpkStackedPages>(b->property("spk_pageno").toInt()));
}
void TreeItemSelected(QTreeWidgetItem *item, int column)
{
@ -103,7 +105,8 @@ namespace SpkUi
if(item->data(column, RoleItemIsCategory).toBool())
emit SwitchToCategory(item->data(column, RoleItemCategoryPageId).toInt(), 0);
else
emit SwitchToPage(item->data(column, RoleItemCategoryPageId).toInt());
emit SwitchToPage(static_cast<SpkStackedPages>(
item->data(column, RoleItemCategoryPageId).toInt()));
}
void UnusableItemSelected(QTreeWidgetItem *i)
{
@ -120,7 +123,7 @@ namespace SpkUi
signals:
void SwitchToCategory(int aCategoryId, int aPage);
void SwitchToPage(int aPageId);
void SwitchToPage(SpkStackedPages aPageId);
};
class SpkMainWidget : public QFrame
@ -146,7 +149,9 @@ namespace SpkUi
QMap<int, QTreeWidgetItem> *CategoryItemMap;
SpkSidebarSelector *SidebarMgr;
QTreeWidgetItem *CategoryParentItem;
QTreeWidgetItem *CategoryParentItem,
*AppDetailsItem,
*UiTestItem;
// Title bar search bar
SpkFocusLineEdit *SearchEdit;
@ -156,6 +161,7 @@ namespace SpkUi
//Pages
SpkPageUiTest *PageQssTest;
SpkPageAppList *PageAppList;
SpkPageAppDetails *PageAppDetails;
};
}
@ -175,7 +181,8 @@ class SpkMainWindow : public SpkWindow
private:
QPointer<QNetworkReply> mCategoryGetReply,
mCategoryAppListGetReply;
mCategoryAppListGetReply,
mAppDetailsGetReply;
SpkUi::SpkStackedPages mCurrentPage = SpkUi::PgInvalid;
public slots:
@ -191,7 +198,11 @@ class SpkMainWindow : public SpkWindow
// Search a keyword (and switch pages)
void SearchKeyword(QString aKeyword, int aPage);
void SearchDataReceived();
// Enter the details page of an application (and switch pages)
void EnterAppDetails(int aAppId);
void AppDetailsDataReceived();
private:
void PopulateAppList(QJsonObject appData, QString &&keyword);
void PopulateAppDetails(QJsonObject appDetails);
};

@ -30,6 +30,7 @@ namespace SpkUi
TextOnGlobalBgnd,
TextOnControlsBgnd,
TextLighter,
TextEvenLighter,
TextDisabled,
GlossyEdge,
ShadesEdge,

@ -26,4 +26,5 @@ namespace SpkUtils
QString CutFileName(QString);
QString CutPath(QString);
QString BytesToSize(size_t s, int prec = 2);
}

@ -14,7 +14,8 @@
TXACC: Text on Selection/Activation
TXGBG: Text on Global background
TXCBG: Text on controls background
TXL: Text slightly lighter
TXL1: Text slightly lighter
TXL2: Text lighter even more
TXD: Text disabled
GLS: Glossy edge on controls
SHD: Shades edge on controls
@ -106,7 +107,7 @@ ElidedLabel
#styAboutDesc
{
color: TXL
color: TXL1
}
SpkAppItem
@ -126,12 +127,29 @@ SpkAppItem::hover
font-size: 17px;
}
#styDetTitle
{
font-weight: 600;
font-size: 36px;
}
#styAppItmDesc
{
color: TXL;
color: TXL1;
font-size: 12px;
}
#styDetDesc
{
color: TXL1;
font-size: 14px;
}
#styDetPkg
{
color: TXL2
}
#styChkBtn
{
border-width: 0px;

@ -88,3 +88,14 @@ QString SpkUtils::CutPath(QString path)
{
return path.section('/', 1, -2, QString::SectionIncludeLeadingSep);
}
QString SpkUtils::BytesToSize(size_t s, int prec)
{
if(s > (1 << 30))
return QString::number(double (s) / (1 << 30), 'f', prec) + " GB";
if(s > (1 << 20))
return QString::number(double (s) / (1 << 20), 'f', prec) + " MB";
if(s > (1 << 10))
return QString::number(double (s) / (1 << 10), 'f', prec) + " KB";
return QString::number(s) + " B";
}