Krita Source Code Documentation
Loading...
Searching...
No Matches
KisSupporterBundlesDialog.cpp
Go to the documentation of this file.
1/*
2 * SPDX-License-Identifier: GPL-3.0-or-later
3 */
4
10#include <QFrame>
11#include <QTimer>
12#include <kis_assert.h>
13#include <kis_debug.h>
14
16 : QDialog(parent)
17 , m_fetcher(new KisSupporterBundlesFetcher(this))
18{
19 setupUi(this);
20 setWindowTitle(i18n("Supporter Bundles"));
21
22 QScroller *scroller = KisKineticScroller::createPreconfiguredScroller(m_scrBundles);
23 if (scroller) {
24 connect(scroller, &QScroller::stateChanged, this, [&](QScroller::State state) {
26 });
27 }
28
29 connect(m_fetcher,
31 this,
33 connect(m_btnRetry, &QPushButton::clicked, this, &KisSupporterBundlesDialog::fetchBundles);
34 connect(m_buttons, &QDialogButtonBox::rejected, this, &KisSupporterBundlesDialog::reject);
35
37}
38
39void KisSupporterBundlesDialog::slotFetchIndexDone(bool success, const QString &errorMessage)
40{
41 m_btnRetry->setEnabled(!success);
42 if (success) {
44 m_stack->setCurrentIndex(PAGE_BUNDLES);
45
47 if (androidDonations) {
48 connect(androidDonations,
50 this,
52 }
53
54 } else {
55 m_lblError->setText(i18n("<strong>Error:</strong> %1").arg(errorMessage.toHtmlEscaped()));
56 // Delay this a bit to avoid excessively fast retries and to make it
57 // clear to the user that a retry is actually happening. Otherwise the
58 // loading page may flash so quickly that it seems like it's not doing
59 // anything at all.
60 QTimer::singleShot(1000, [this] {
61 m_stack->setCurrentIndex(PAGE_ERROR);
62 });
63 }
64}
65
67{
68 while (!m_lytWdgBundles->isEmpty()) {
69 QLayoutItem *item = m_lytWdgBundles->takeAt(m_lytWdgBundles->count() - 1);
70 QWidget *widget = item->widget();
71 if (widget) {
72 widget->deleteLater();
73 }
74 delete item;
75 }
76
78
80 for (const KisSupporterBundle &bundle : m_fetcher->bundles()) {
81 // Gather the products that this bundle is associated with.
82 QVector<KisSupporterProduct> bundleProducts = getProductsForBundle(currentProducts, bundle);
83 // Only show bundles that the user could actually acquire, there's no
84 // point in dangling a bundle in front of their nose that they couldn't
85 // purchase any product for.
86 if (couldOwnAnyProduct(bundleProducts)) {
87 KisSupporterBundleWidget *bundleWidget = new KisSupporterBundleWidget(m_fetcher, bundle, bundleProducts);
88 bundleWidgets.append(bundleWidget);
89 } else {
90 dbgResources << "No products for bundle" << bundle.fileName;
91 }
92 }
93
94 if (bundleWidgets.isEmpty()) {
95 m_lytWdgBundles->addStretch();
96 QLabel *label = new QLabel(i18n("No supporter bundles available."));
97 label->setAlignment(Qt::AlignCenter);
98 label->setWordWrap(true);
99 m_lytWdgBundles->addWidget(label);
100 m_lytWdgBundles->addStretch();
101 } else {
102 std::sort(bundleWidgets.begin(), bundleWidgets.end(), &KisSupporterBundlesDialog::bundleWidgetLessThan);
103
104 // We've been asked to put this disclaimer here so that people don't
105 // contact the authors and complain about paywalling or something.
106 // Don't remove this message without discussing it with them.
107 QLabel *purchaseNoteLabel =
108 new QLabel(i18n("These bundles have been made available by their authors to help provide rewards for "
109 "supporting Krita's development. They do not receive compensation for purchases and may "
110 "make these bundles in other ways behind the links below."));
111 purchaseNoteLabel->setTextFormat(Qt::PlainText);
112 purchaseNoteLabel->setWordWrap(true);
113 m_lytWdgBundles->addWidget(purchaseNoteLabel);
114
115 for (KisSupporterBundleWidget *bundleWidget : bundleWidgets) {
116 QFrame *separator = new QFrame;
117 separator->setFrameShape(QFrame::HLine);
118 separator->setFrameShadow(QFrame::Sunken);
119 m_lytWdgBundles->addWidget(separator);
120 m_lytWdgBundles->addWidget(bundleWidget);
121 }
122 m_lytWdgBundles->addStretch();
123 }
124}
125
127{
128 if (!m_fetcher->isFetching()) {
129 m_stack->setCurrentIndex(PAGE_FETCHING);
130 m_btnRetry->setEnabled(false);
132 }
133}
134
141
144 const KisSupporterBundle &bundle)
145{
146 const QString prefix = QStringLiteral("p:");
147 QVector<KisSupporterProduct> bundleProducts;
148 dbgResources << "Bundle" << bundle.fileName << "tags:" << bundle.tags;
149 for (const QString &tag : bundle.tags) {
150 if (tag.startsWith(prefix)) {
151 const KisSupporterProduct *product = searchProductById(currentProducts, tag.mid(prefix.length()));
152 if (product) {
153 bundleProducts.append(*product);
154 }
155 }
156 }
157 return bundleProducts;
158}
159
162{
163 for (const KisSupporterProduct &product : currentProducts) {
164 if (product.id == id) {
165 return &product;
166 }
167 }
168 dbgResources << "No current product for id" << id;
169 return nullptr;
170}
171
173{
174 for (const KisSupporterProduct &product : bundleProducts) {
175 switch (product.availability) {
176 case KisSupporterProductAvailability::Missing:
177 break;
178 case KisSupporterProductAvailability::Available:
179 case KisSupporterProductAvailability::Owned:
180 return true;
181 }
182 }
183 return false;
184}
185
188{
189 bool aOwned = a->isProductOwned();
190 bool bOwned = b->isProductOwned();
191 if (aOwned && !bOwned) {
192 return true;
193 } else if (!aOwned && bOwned) {
194 return false;
195 }
196
197 bool aCanImport = a->canImport();
198 bool bCanImport = b->canImport();
199 if (aCanImport && !bCanImport) {
200 return true;
201 } else if (!aCanImport && bCanImport) {
202 return false;
203 }
204
205 return a->bundle().title.compare(b->bundle().title, Qt::CaseInsensitive) < 0;
206}
static KisAndroidDonations * instance()
QVector< KisSupporterProduct > getCurrentProducts() const
const KisSupporterBundle & bundle() const
KisSupporterBundlesFetcher * m_fetcher
static QVector< KisSupporterProduct > getProductsForBundle(const QVector< KisSupporterProduct > &currentProducts, const KisSupporterBundle &bundle)
static bool couldOwnAnyProduct(const QVector< KisSupporterProduct > &bundleProducts)
static bool bundleWidgetLessThan(const KisSupporterBundleWidget *a, const KisSupporterBundleWidget *b)
QVector< KisSupporterProduct > getCurrentProducts() const
static const KisSupporterProduct * searchProductById(const QVector< KisSupporterProduct > &currentProducts, const QString &id)
KisSupporterBundlesDialog(QWidget *parent=nullptr)
void slotFetchIndexDone(bool success, const QString &errorMessage)
void fetchIndexDone(bool success, const QString &errorMessage)
const QVector< KisSupporterBundle > & bundles() const
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define dbgResources
Definition kis_debug.h:43
KRITAWIDGETUTILS_EXPORT void updateCursor(QWidget *source, QScroller::State state)
KRITAWIDGETUTILS_EXPORT QScroller * createPreconfiguredScroller(QAbstractScrollArea *target)