Krita Source Code Documentation
Loading...
Searching...
No Matches
KisSupporterBundleWidget Class Reference

#include <KisSupporterBundleWidget.h>

+ Inheritance diagram for KisSupporterBundleWidget:

Public Member Functions

const KisSupporterBundlebundle () const
 
bool canImport () const
 
bool isProductOwned () const
 
 KisSupporterBundleWidget (KisSupporterBundlesFetcher *fetcher, const KisSupporterBundle &bundle, const QVector< KisSupporterProduct > &bundleProducts, QWidget *parent=nullptr)
 

Private Slots

void slotStartDownload ()
 
void slotUpdateDownloadProgress (qint64 bytesReceived, qint64 bytesTotal)
 

Private Member Functions

void addContentEntry (QStringList &outContentList, const QString &key, const std::function< QString(int)> &formatFn) const
 
void closeProgressDlg ()
 
void handleDownloadFinished (QNetworkReply *reply)
 
void showFinishedDownload (bool success, bool cancel, const QString &errorMessage)
 

Private Attributes

KisSupporterBundle m_bundle
 
bool m_canImport
 
QPointer< KisSupporterBundlesFetcherm_fetcher
 
bool m_productOwned {false}
 
QProgressDialog * m_progressDlg {nullptr}
 

Detailed Description

Definition at line 20 of file KisSupporterBundleWidget.h.

Constructor & Destructor Documentation

◆ KisSupporterBundleWidget()

KisSupporterBundleWidget::KisSupporterBundleWidget ( KisSupporterBundlesFetcher * fetcher,
const KisSupporterBundle & bundle,
const QVector< KisSupporterProduct > & bundleProducts,
QWidget * parent = nullptr )
explicit

Definition at line 17 of file KisSupporterBundleWidget.cpp.

21 : QWidget(parent)
22 , m_fetcher(fetcher)
24{
25 setupUi(this);
26
27 QStringList contentList;
28 addContentEntry(contentList, QStringLiteral("paintoppresets"), [](int count) {
29 return i18np("%1 brush preset", "%1 brush presets", count);
30 });
31 addContentEntry(contentList, QStringLiteral("brushes"), [](int count) {
32 return i18np("%1 brush tips", "%1 brush tips", count);
33 });
34 addContentEntry(contentList, QStringLiteral("patterns"), [](int count) {
35 return i18np("%1 texture patterns", "%1 texture patterns", count);
36 });
37 addContentEntry(contentList, QStringLiteral("workspaces"), [](int count) {
38 return i18np("%1 workspace layout", "%1 workspace layouts", count);
39 });
40
41 QStringList productList;
42 for (const KisSupporterProduct &product : bundleProducts) {
43 switch (product.availability) {
44 case KisSupporterProductAvailability::Missing:
45 // Product is neither available for purchase nor does the user own
46 // it, so we'll pretend like it doesn't exist.
47 break;
48 case KisSupporterProductAvailability::Available:
49 productList.append(product.title);
50 break;
51 case KisSupporterProductAvailability::Owned:
52 if (product.type == KisSupporterProductType::Subscription) {
53 productList.append(i18n("%1 (subscribed)").arg(product.title));
54 } else {
55 productList.append(i18n("%1 (owned)").arg(product.title));
56 }
57 m_productOwned = true;
58 break;
59 }
60 }
61
62 if (m_bundle.thumbnail.isNull()) {
63 m_lblPreview->hide();
64 } else {
65 m_lblPreview->setPixmap(m_bundle.thumbnail);
66 }
67
68 QString author = m_bundle.author.toHtmlEscaped();
69 if (!m_bundle.source.isEmpty()) {
70 author = QStringLiteral("<a href=\"%1\">%2</a>").arg(m_bundle.source.toHtmlEscaped(), author);
71 }
72 m_lblTitle->setText(QStringLiteral("<strong>%1</strong> by %2").arg(m_bundle.title.toHtmlEscaped(), author));
73 m_lblDescription->setText(m_bundle.description);
74
75 // The margins on this stuff is ginormous by default, cut that down.
76 QString productsText = QStringLiteral(
77 "<style>\n"
78 "ul { margin-top: 0px; margin-bottom: 4px; margin-left: -10px; }\n"
79 "li { margin: 0px; padding: 0px; }\n"
80 "</style>");
81 if (!contentList.isEmpty()) {
82 productsText.append(
83 i18nc("in-app purchases, prefix for a list of what a bundle contains", "Contains:").toHtmlEscaped());
84 productsText.append(QStringLiteral("<ul>"));
85 for (const QString &content : contentList) {
86 productsText.append(QStringLiteral("<li>%1</li>").arg(content.toHtmlEscaped()));
87 }
88 productsText.append(QStringLiteral("</ul>"));
89 }
90
91 if (productList.isEmpty()) {
92 productsText.append(i18nc("in-app purchases, a bundle that the user can't acquire", "Not available."));
93 } else {
94 productsText.append(
95 i18nc("in-app purchases, prefix for a list of which purchases make a bundle available", "Available with:")
96 .toHtmlEscaped());
97 productsText.append(QStringLiteral("<ul>"));
98 for (const QString &product : productList) {
99 productsText.append(QStringLiteral("<li>%1</li>").arg(product.toHtmlEscaped()));
100 }
101 productsText.append(QStringLiteral("</ul>"));
102 }
103
104 m_lblProducts->setText(productsText);
105
108 if (!m_canImport) {
109 m_stkDownload->setCurrentWidget(m_pgDone);
110 } else if (m_productOwned) {
111 m_stkDownload->setCurrentWidget(m_pgGet);
112 } else {
113 m_stkDownload->setCurrentWidget(m_pgSupport);
114 }
115
116 connect(m_btnGet, &QPushButton::clicked, this, &KisSupporterBundleWidget::slotStartDownload);
117
119 if (androidDonations) {
120 connect(m_btnSupport, &QPushButton::clicked, androidDonations, &KisAndroidDonations::slotStartDonationFlow);
121 } else {
122 m_btnSupport->setEnabled(false);
123 }
124}
static KisAndroidDonations * instance()
static KisStorageModel * instance()
bool canImportStorage(const QString &filename) const
const KisSupporterBundle & bundle() const
QPointer< KisSupporterBundlesFetcher > m_fetcher
void addContentEntry(QStringList &outContentList, const QString &key, const std::function< QString(int)> &formatFn) const

References addContentEntry(), KisSupporterBundle::author, KisStorageModel::canImportStorage(), KisSupporterBundle::description, KisSupporterBundle::fileName, KisStorageModel::instance(), KisAndroidDonations::instance(), m_bundle, m_canImport, m_productOwned, KisAndroidDonations::slotStartDonationFlow(), slotStartDownload(), KisSupporterBundle::source, KisSupporterBundle::thumbnail, and KisSupporterBundle::title.

Member Function Documentation

◆ addContentEntry()

void KisSupporterBundleWidget::addContentEntry ( QStringList & outContentList,
const QString & key,
const std::function< QString(int)> & formatFn ) const
private

Definition at line 163 of file KisSupporterBundleWidget.cpp.

166{
167 int count = m_bundle.resourceCountByMediaType.value(key, 0);
168 if (count > 0) {
169 outContentList.append(formatFn(count));
170 }
171}
QHash< QString, int > resourceCountByMediaType

References m_bundle, and KisSupporterBundle::resourceCountByMediaType.

◆ bundle()

const KisSupporterBundle & KisSupporterBundleWidget::bundle ( ) const
inline

Definition at line 29 of file KisSupporterBundleWidget.h.

30 {
31 return m_bundle;
32 }

References m_bundle.

◆ canImport()

bool KisSupporterBundleWidget::canImport ( ) const
inline

Definition at line 39 of file KisSupporterBundleWidget.h.

40 {
41 return m_canImport;
42 }

References m_canImport.

◆ closeProgressDlg()

void KisSupporterBundleWidget::closeProgressDlg ( )
private

Definition at line 247 of file KisSupporterBundleWidget.cpp.

248{
249 if (m_progressDlg) {
250 m_progressDlg->close();
251 m_progressDlg = nullptr;
252 }
253}

References m_progressDlg.

◆ handleDownloadFinished()

void KisSupporterBundleWidget::handleDownloadFinished ( QNetworkReply * reply)
private

Definition at line 173 of file KisSupporterBundleWidget.cpp.

174{
175 if (reply->error() == QNetworkReply::OperationCanceledError) {
176 showFinishedDownload(false, true, QString());
177 return;
178 }
179
180 QString errorMessage;
181 if (KisSupporterBundlesFetcher::hasNetworkReplyError(reply, errorMessage)) {
182 showFinishedDownload(false, false, errorMessage);
183 return;
184 }
185
187 QCoreApplication::processEvents();
188
189 QByteArray bytes = reply->readAll();
190 long long sizeInBytes = bytes.size();
191 if (sizeInBytes != m_bundle.sizeInBytes) {
192 warnResources << "Bundle" << m_bundle.fileName << "size of" << sizeInBytes << "does not match expected"
194 showFinishedDownload(false, false, i18n("Invalid bundle size"));
195 return;
196 }
197
198 QString hash = QCryptographicHash::hash(bytes, QCryptographicHash::Md5).toHex();
199 if (hash != bundle().checksum) {
200 warnResources << "Bundle" << m_bundle.fileName << "hash" << hash << "does not match expected"
202 showFinishedDownload(false, false, i18n("Invalid bundle checksum"));
203 return;
204 }
205
206 m_progressDlg->setLabelText(i18n("Activating bundle…"));
208 QCoreApplication::processEvents();
209
211 QGuiApplication::setOverrideCursor(Qt::WaitCursor);
212 bool importOk = storageModel->importStorageData(m_bundle.fileName, KisStorageModel::None, bytes);
213 QGuiApplication::restoreOverrideCursor();
214
215 if (!importOk) {
216 showFinishedDownload(false, false, i18n("Failed to import bundle"));
217 return;
218 }
219
220 showFinishedDownload(true, false, QString());
221}
bool importStorageData(const QString &filename, StorageImportOption importOption, const QByteArray &data) const
void showFinishedDownload(bool success, bool cancel, const QString &errorMessage)
void slotUpdateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
static bool hasNetworkReplyError(QNetworkReply *reply, QString &outErrorMessage)
#define warnResources
Definition kis_debug.h:85

References bundle(), KisSupporterBundle::checksum, KisSupporterBundle::fileName, KisSupporterBundlesFetcher::hasNetworkReplyError(), KisStorageModel::importStorageData(), KisStorageModel::instance(), m_bundle, m_progressDlg, KisStorageModel::None, showFinishedDownload(), KisSupporterBundle::sizeInBytes, slotUpdateDownloadProgress(), and warnResources.

◆ isProductOwned()

bool KisSupporterBundleWidget::isProductOwned ( ) const
inline

Definition at line 34 of file KisSupporterBundleWidget.h.

35 {
36 return m_productOwned;
37 }

References m_productOwned.

◆ showFinishedDownload()

void KisSupporterBundleWidget::showFinishedDownload ( bool success,
bool cancel,
const QString & errorMessage )
private

Definition at line 223 of file KisSupporterBundleWidget.cpp.

224{
225 if (success) {
226 m_btnGet->clearFocus(); // Prevent auto-scrolling to the next button.
228 m_canImport = false;
229 m_stkDownload->setCurrentWidget(m_pgDone);
230 } else if (cancel) {
232 m_btnGet->setEnabled(true);
233 m_stkDownload->setCurrentWidget(m_pgGet);
234 } else {
235 // Delay this a bit to avoid excessively fast retries and to make it
236 // clear to the user that a retry is actually happening. Otherwise the
237 // download progress bar may flash so quickly that it seems like it's
238 // not doing anything at all.
239 QTimer::singleShot(1000, [=] {
241 QMessageBox::warning(this, i18n("Download failed"), i18n("Bundle download failed: %1").arg(errorMessage));
242 m_stkDownload->setCurrentWidget(m_pgGet);
243 });
244 }
245}

References closeProgressDlg(), and m_canImport.

◆ slotStartDownload

void KisSupporterBundleWidget::slotStartDownload ( )
privateslot

Definition at line 126 of file KisSupporterBundleWidget.cpp.

127{
131
132 m_progressDlg = new QProgressDialog(this);
133 m_progressDlg->setAutoClose(false);
134 m_progressDlg->setAutoReset(false);
135 m_progressDlg->setModal(true);
136 m_progressDlg->setMinimumDuration(0);
137 m_progressDlg->setRange(0, 0);
138 m_progressDlg->setLabelText(i18n("Downloading bundle…"));
139 m_progressDlg->setWindowTitle(i18n("%1").arg(m_bundle.title));
140 m_progressDlg->show();
141
142 QNetworkReply *reply = m_fetcher->fetchBundle(m_bundle);
143 connect(reply, &QNetworkReply::downloadProgress, this, &KisSupporterBundleWidget::slotUpdateDownloadProgress);
144 connect(m_progressDlg, &QProgressDialog::canceled, reply, &QNetworkReply::abort);
145 connect(reply, &QNetworkReply::finished, this, [=] {
147 reply->deleteLater();
148 });
149}
void handleDownloadFinished(QNetworkReply *reply)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128

References handleDownloadFinished(), KIS_SAFE_ASSERT_RECOVER_RETURN, m_bundle, m_fetcher, m_productOwned, m_progressDlg, slotUpdateDownloadProgress(), and KisSupporterBundle::title.

◆ slotUpdateDownloadProgress

void KisSupporterBundleWidget::slotUpdateDownloadProgress ( qint64 bytesReceived,
qint64 bytesTotal )
privateslot

Definition at line 151 of file KisSupporterBundleWidget.cpp.

152{
153 if (m_progressDlg) {
154 if (bytesTotal <= 0) {
155 m_progressDlg->setRange(0, 0);
156 } else {
157 m_progressDlg->setRange(0, 100);
158 m_progressDlg->setValue(qRound(qreal(bytesTotal) / qreal(bytesReceived) * 100.0));
159 }
160 }
161}

References m_progressDlg.

Member Data Documentation

◆ m_bundle

KisSupporterBundle KisSupporterBundleWidget::m_bundle
private

Definition at line 58 of file KisSupporterBundleWidget.h.

◆ m_canImport

bool KisSupporterBundleWidget::m_canImport
private

Definition at line 60 of file KisSupporterBundleWidget.h.

◆ m_fetcher

QPointer<KisSupporterBundlesFetcher> KisSupporterBundleWidget::m_fetcher
private

Definition at line 56 of file KisSupporterBundleWidget.h.

◆ m_productOwned

bool KisSupporterBundleWidget::m_productOwned {false}
private

Definition at line 59 of file KisSupporterBundleWidget.h.

59{false};

◆ m_progressDlg

QProgressDialog* KisSupporterBundleWidget::m_progressDlg {nullptr}
private

Definition at line 57 of file KisSupporterBundleWidget.h.

57{nullptr};

The documentation for this class was generated from the following files: