mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-08 14:33:23 +00:00
refactor: move plan and benefits into separate models
This commit is contained in:
@@ -91,6 +91,12 @@ void CoreController::initModels()
|
||||
m_apiServicesModel.reset(new ApiServicesModel(this));
|
||||
m_engine->rootContext()->setContextProperty("ApiServicesModel", m_apiServicesModel.get());
|
||||
|
||||
m_apiSubscriptionPlansModel.reset(new ApiSubscriptionPlansModel(this));
|
||||
m_engine->rootContext()->setContextProperty("ApiSubscriptionPlansModel", m_apiSubscriptionPlansModel.get());
|
||||
|
||||
m_apiBenefitsModel.reset(new ApiBenefitsModel(this));
|
||||
m_engine->rootContext()->setContextProperty("ApiBenefitsModel", m_apiBenefitsModel.get());
|
||||
|
||||
m_apiCountryModel.reset(new ApiCountryModel(this));
|
||||
m_engine->rootContext()->setContextProperty("ApiCountryModel", m_apiCountryModel.get());
|
||||
|
||||
@@ -151,7 +157,8 @@ void CoreController::initControllers()
|
||||
new ApiSettingsController(m_serversModel, m_apiAccountInfoModel, m_apiCountryModel, m_apiDevicesModel, m_settings));
|
||||
m_engine->rootContext()->setContextProperty("ApiSettingsController", m_apiSettingsController.get());
|
||||
|
||||
m_apiConfigsController.reset(new ApiConfigsController(m_serversModel, m_apiServicesModel, m_settings));
|
||||
m_apiConfigsController.reset(
|
||||
new ApiConfigsController(m_serversModel, m_apiServicesModel, m_apiSubscriptionPlansModel, m_apiBenefitsModel, m_settings));
|
||||
m_engine->rootContext()->setContextProperty("ApiConfigsController", m_apiConfigsController.get());
|
||||
connect(m_apiConfigsController.get(), &ApiConfigsController::subscriptionRefreshNeeded,
|
||||
this, [this]() { m_apiSettingsController->getAccountInfo(false); });
|
||||
|
||||
@@ -32,9 +32,11 @@
|
||||
#include "ui/models/protocols/ikev2ConfigModel.h"
|
||||
#endif
|
||||
#include "ui/models/api/apiAccountInfoModel.h"
|
||||
#include "ui/models/api/apiBenefitsModel.h"
|
||||
#include "ui/models/api/apiCountryModel.h"
|
||||
#include "ui/models/api/apiDevicesModel.h"
|
||||
#include "ui/models/api/apiServicesModel.h"
|
||||
#include "ui/models/api/apiSubscriptionPlansModel.h"
|
||||
#include "ui/models/appSplitTunnelingModel.h"
|
||||
#include "ui/models/clientManagementModel.h"
|
||||
#include "ui/models/protocols/awgConfigModel.h"
|
||||
@@ -133,6 +135,8 @@ private:
|
||||
QSharedPointer<ClientManagementModel> m_clientManagementModel;
|
||||
|
||||
QSharedPointer<ApiServicesModel> m_apiServicesModel;
|
||||
QSharedPointer<ApiSubscriptionPlansModel> m_apiSubscriptionPlansModel;
|
||||
QSharedPointer<ApiBenefitsModel> m_apiBenefitsModel;
|
||||
QSharedPointer<ApiCountryModel> m_apiCountryModel;
|
||||
QSharedPointer<ApiAccountInfoModel> m_apiAccountInfoModel;
|
||||
QSharedPointer<ApiDevicesModel> m_apiDevicesModel;
|
||||
|
||||
@@ -242,9 +242,22 @@ namespace
|
||||
|
||||
ApiConfigsController::ApiConfigsController(const QSharedPointer<ServersModel> &serversModel,
|
||||
const QSharedPointer<ApiServicesModel> &apiServicesModel,
|
||||
const QSharedPointer<ApiSubscriptionPlansModel> &subscriptionPlansModel,
|
||||
const QSharedPointer<ApiBenefitsModel> &benefitsModel,
|
||||
const std::shared_ptr<Settings> &settings, QObject *parent)
|
||||
: QObject(parent), m_serversModel(serversModel), m_apiServicesModel(apiServicesModel), m_settings(settings)
|
||||
: QObject(parent)
|
||||
, m_serversModel(serversModel)
|
||||
, m_apiServicesModel(apiServicesModel)
|
||||
, m_subscriptionPlansModel(subscriptionPlansModel)
|
||||
, m_benefitsModel(benefitsModel)
|
||||
, m_settings(settings)
|
||||
{
|
||||
connect(m_apiServicesModel.data(), &ApiServicesModel::serviceSelectionChanged, this, [this]() {
|
||||
const ApiServicesModel::ApiServicesData serviceData = m_apiServicesModel->selectedServiceData();
|
||||
m_subscriptionPlansModel->updateModel(serviceData.subscriptionPlansJson);
|
||||
m_benefitsModel->updateModel(serviceData.benefits, serviceData.serviceInfo.region, serviceData.serviceInfo.speed,
|
||||
serviceData.serviceInfo.price, serviceData.supportInfo);
|
||||
});
|
||||
}
|
||||
|
||||
bool ApiConfigsController::exportVpnKey(const QString &fileName)
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
#include <QObject>
|
||||
|
||||
#include "configurators/openvpn_configurator.h"
|
||||
#include "ui/models/api/apiBenefitsModel.h"
|
||||
#include "ui/models/api/apiServicesModel.h"
|
||||
#include "ui/models/api/apiSubscriptionPlansModel.h"
|
||||
#include "ui/models/servers_model.h"
|
||||
|
||||
class ApiConfigsController : public QObject
|
||||
@@ -12,7 +14,12 @@ class ApiConfigsController : public QObject
|
||||
Q_OBJECT
|
||||
public:
|
||||
ApiConfigsController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ApiServicesModel> &apiServicesModel,
|
||||
const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);
|
||||
const QSharedPointer<ApiSubscriptionPlansModel> &subscriptionPlansModel,
|
||||
const QSharedPointer<ApiBenefitsModel> &benefitsModel, const std::shared_ptr<Settings> &settings,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
Q_PROPERTY(ApiSubscriptionPlansModel *subscriptionPlansModel READ subscriptionPlansModel CONSTANT)
|
||||
Q_PROPERTY(ApiBenefitsModel *benefitsModel READ benefitsModel CONSTANT)
|
||||
|
||||
Q_PROPERTY(QList<QString> qrCodes READ getQrCodes NOTIFY vpnKeyExportReady)
|
||||
Q_PROPERTY(int qrCodesCount READ getQrCodesCount NOTIFY vpnKeyExportReady)
|
||||
@@ -38,6 +45,9 @@ public slots:
|
||||
|
||||
bool isConfigValid();
|
||||
|
||||
ApiSubscriptionPlansModel *subscriptionPlansModel() const { return m_subscriptionPlansModel.get(); }
|
||||
ApiBenefitsModel *benefitsModel() const { return m_benefitsModel.get(); }
|
||||
|
||||
void setCurrentProtocol(const QString &protocolName);
|
||||
bool isVlessProtocol();
|
||||
|
||||
@@ -67,6 +77,9 @@ private:
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
QSharedPointer<ApiServicesModel> m_apiServicesModel;
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
|
||||
QSharedPointer<ApiSubscriptionPlansModel> m_subscriptionPlansModel;
|
||||
QSharedPointer<ApiBenefitsModel> m_benefitsModel;
|
||||
};
|
||||
|
||||
#endif // APICONFIGSCONTROLLER_H
|
||||
#endif
|
||||
|
||||
166
client/ui/models/api/apiBenefitsModel.cpp
Normal file
166
client/ui/models/api/apiBenefitsModel.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#include "apiBenefitsModel.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <utility>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
|
||||
#include "core/api/apiDefs.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace configKey
|
||||
{
|
||||
constexpr char title[] = "title";
|
||||
constexpr char body[] = "body";
|
||||
constexpr char icon[] = "icon";
|
||||
constexpr char injectKey[] = "inject_key";
|
||||
constexpr char accent[] = "accent";
|
||||
|
||||
constexpr char region[] = "region";
|
||||
constexpr char speed[] = "speed";
|
||||
constexpr char price[] = "price";
|
||||
}
|
||||
|
||||
QString gatewayIconKeyToUrl(const QString &iconKey)
|
||||
{
|
||||
if (iconKey.startsWith(QLatin1String("qrc:"))) {
|
||||
return iconKey;
|
||||
}
|
||||
static const QHash<QString, QString> map = {
|
||||
{ QStringLiteral("globe-2"), QStringLiteral("qrc:/images/controls/globe-2.svg") },
|
||||
{ QStringLiteral("smartphone"), QStringLiteral("qrc:/images/controls/smartphone.svg") },
|
||||
{ QStringLiteral("gauge"), QStringLiteral("qrc:/images/controls/gauge.svg") },
|
||||
{ QStringLiteral("infinity"), QStringLiteral("qrc:/images/controls/infinity.svg") },
|
||||
{ QStringLiteral("tag"), QStringLiteral("qrc:/images/controls/tag.svg") },
|
||||
{ QStringLiteral("history"), QStringLiteral("qrc:/images/controls/history.svg") },
|
||||
{ QStringLiteral("info"), QStringLiteral("qrc:/images/controls/info.svg") },
|
||||
{ QStringLiteral("app"), QStringLiteral("qrc:/images/controls/app.svg") },
|
||||
{ QStringLiteral("download"), QStringLiteral("qrc:/images/controls/download.svg") },
|
||||
{ QStringLiteral("help-circle"), QStringLiteral("qrc:/images/controls/help-circle.svg") },
|
||||
};
|
||||
return map.value(iconKey, QStringLiteral("qrc:/images/controls/info.svg"));
|
||||
}
|
||||
}
|
||||
|
||||
ApiBenefitsModel::ApiBenefitsModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
int ApiBenefitsModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
return m_serviceBenefits.size();
|
||||
}
|
||||
|
||||
QVariant ApiBenefitsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() < 0 || index.row() >= m_serviceBenefits.size()) {
|
||||
return {};
|
||||
}
|
||||
const ServiceBenefitItem &item = m_serviceBenefits.at(index.row());
|
||||
switch (role) {
|
||||
case IconRole:
|
||||
return item.icon;
|
||||
case TitleRole:
|
||||
return item.title;
|
||||
case BodyRole:
|
||||
return item.body;
|
||||
case AccentRole:
|
||||
return item.accent;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> ApiBenefitsModel::roleNames() const
|
||||
{
|
||||
return {
|
||||
{ IconRole, "icon" },
|
||||
{ TitleRole, "title" },
|
||||
{ BodyRole, "body" },
|
||||
{ AccentRole, "accent" },
|
||||
};
|
||||
}
|
||||
|
||||
void ApiBenefitsModel::updateModel(const QJsonArray &benefits, const QString ®ion, const QString &speed,
|
||||
const QString &price, const QJsonObject &supportInfo)
|
||||
{
|
||||
beginResetModel();
|
||||
m_serviceBenefits.clear();
|
||||
for (const QJsonValue &benefitValue : benefits) {
|
||||
if (!benefitValue.isObject()) {
|
||||
continue;
|
||||
}
|
||||
const QJsonObject benefitObject = benefitValue.toObject();
|
||||
QString title = benefitObject.value(configKey::title).toString();
|
||||
QString body = benefitObject.value(configKey::body).toString();
|
||||
const QString iconKey = benefitObject.value(configKey::icon).toString();
|
||||
const QString injectKey = benefitObject.value(configKey::injectKey).toString();
|
||||
if (body.contains(QLatin1String("%1")) && !injectKey.isEmpty()) {
|
||||
QString injected = benefitInjectValue(injectKey, region, speed, price, supportInfo);
|
||||
if (injected.isEmpty()) {
|
||||
injected = QStringLiteral("—");
|
||||
}
|
||||
body = body.arg(injected);
|
||||
}
|
||||
if (title.isEmpty() && body.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
ServiceBenefitItem item;
|
||||
item.icon = gatewayIconKeyToUrl(iconKey);
|
||||
item.title = std::move(title);
|
||||
item.body = std::move(body);
|
||||
item.accent = benefitObject.value(configKey::accent).toBool();
|
||||
m_serviceBenefits.append(std::move(item));
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void ApiBenefitsModel::clear()
|
||||
{
|
||||
beginResetModel();
|
||||
m_serviceBenefits.clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QString ApiBenefitsModel::formatPriceForBenefit(const QString &rawPrice) const
|
||||
{
|
||||
if (rawPrice == QStringLiteral("free")) {
|
||||
return tr("Free");
|
||||
}
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
return tr("%1 $").arg(rawPrice);
|
||||
#else
|
||||
return tr("%1 $/month").arg(rawPrice);
|
||||
#endif
|
||||
}
|
||||
|
||||
QString ApiBenefitsModel::benefitInjectValue(const QString &injectKey, const QString ®ion, const QString &speed,
|
||||
const QString &price, const QJsonObject &supportInfo) const
|
||||
{
|
||||
if (injectKey == QLatin1String(configKey::region)) {
|
||||
return region.isEmpty() ? QStringLiteral("—") : region;
|
||||
}
|
||||
if (injectKey == QLatin1String(configKey::speed)) {
|
||||
return speed.isEmpty() ? QStringLiteral("—") : speed;
|
||||
}
|
||||
if (injectKey == QLatin1String(configKey::price)) {
|
||||
return formatPriceForBenefit(price);
|
||||
}
|
||||
|
||||
if (injectKey == apiDefs::key::telegram) {
|
||||
const QString handle = supportInfo.value(apiDefs::key::telegram).toString().trimmed();
|
||||
if (handle.isEmpty()) {
|
||||
return QStringLiteral("—");
|
||||
}
|
||||
if (handle.startsWith(QLatin1Char('@'))) {
|
||||
return handle;
|
||||
}
|
||||
return QLatin1Char('@') + handle;
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
49
client/ui/models/api/apiBenefitsModel.h
Normal file
49
client/ui/models/api/apiBenefitsModel.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef APIBENEFITSMODEL_H
|
||||
#define APIBENEFITSMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
class ApiBenefitsModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
IconRole = Qt::UserRole + 1,
|
||||
TitleRole,
|
||||
BodyRole,
|
||||
AccentRole
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
|
||||
explicit ApiBenefitsModel(QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
void updateModel(const QJsonArray &benefits, const QString ®ion, const QString &speed, const QString &price,
|
||||
const QJsonObject &supportInfo);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
struct ServiceBenefitItem
|
||||
{
|
||||
QString icon;
|
||||
QString title;
|
||||
QString body;
|
||||
bool accent = false;
|
||||
};
|
||||
|
||||
QVector<ServiceBenefitItem> m_serviceBenefits;
|
||||
|
||||
QString formatPriceForBenefit(const QString &rawPrice) const;
|
||||
QString benefitInjectValue(const QString &injectKey, const QString ®ion, const QString &speed, const QString &price,
|
||||
const QJsonObject &supportInfo) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -41,39 +41,6 @@ namespace
|
||||
constexpr char benefits[] = "benefits";
|
||||
}
|
||||
|
||||
QString iconUrlFromGatewayBenefitIcon(const QString &iconKey)
|
||||
{
|
||||
if (iconKey.startsWith(QLatin1String("qrc:"))) {
|
||||
return iconKey;
|
||||
}
|
||||
static const QHash<QString, QString> map = {
|
||||
{ QStringLiteral("globe-2"), QStringLiteral("qrc:/images/controls/globe-2.svg") },
|
||||
{ QStringLiteral("smartphone"), QStringLiteral("qrc:/images/controls/smartphone.svg") },
|
||||
{ QStringLiteral("gauge"), QStringLiteral("qrc:/images/controls/gauge.svg") },
|
||||
{ QStringLiteral("infinity"), QStringLiteral("qrc:/images/controls/infinity.svg") },
|
||||
{ QStringLiteral("tag"), QStringLiteral("qrc:/images/controls/tag.svg") },
|
||||
{ QStringLiteral("history"), QStringLiteral("qrc:/images/controls/history.svg") },
|
||||
{ QStringLiteral("info"), QStringLiteral("qrc:/images/controls/info.svg") },
|
||||
{ QStringLiteral("app"), QStringLiteral("qrc:/images/controls/app.svg") },
|
||||
{ QStringLiteral("download"), QStringLiteral("qrc:/images/controls/download.svg") },
|
||||
{ QStringLiteral("help-circle"), QStringLiteral("qrc:/images/controls/help-circle.svg") },
|
||||
};
|
||||
return map.value(iconKey, QStringLiteral("qrc:/images/controls/info.svg"));
|
||||
}
|
||||
|
||||
QVariantList jsonObjectArrayToVariantList(const QJsonArray &arr)
|
||||
{
|
||||
QVariantList list;
|
||||
list.reserve(arr.size());
|
||||
for (const QJsonValue &v : arr) {
|
||||
if (!v.isObject()) {
|
||||
continue;
|
||||
}
|
||||
list.append(v.toObject().toVariantMap());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
namespace serviceType
|
||||
{
|
||||
constexpr char amneziaFree[] = "amnezia-free";
|
||||
@@ -82,7 +49,9 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
ApiServicesModel::ApiServicesModel(QObject *parent) : QAbstractListModel(parent)
|
||||
ApiServicesModel::ApiServicesModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_selectedServiceIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -171,12 +140,6 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
case SubscriptionPlansRole: {
|
||||
return apiServiceData.subscriptionPlans;
|
||||
}
|
||||
case BenefitRowsRole: {
|
||||
return buildBenefitRows(apiServiceData);
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
@@ -201,12 +164,27 @@ void ApiServicesModel::updateModel(const QJsonObject &data)
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_services.isEmpty() && m_selectedServiceIndex >= m_services.size()) {
|
||||
m_selectedServiceIndex = 0;
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
|
||||
emit serviceSelectionChanged();
|
||||
}
|
||||
|
||||
void ApiServicesModel::setServiceIndex(const int index)
|
||||
{
|
||||
m_selectedServiceIndex = index;
|
||||
emit serviceSelectionChanged();
|
||||
}
|
||||
|
||||
ApiServicesModel::ApiServicesData ApiServicesModel::selectedServiceData() const
|
||||
{
|
||||
if (m_services.isEmpty() || m_selectedServiceIndex < 0 || m_selectedServiceIndex >= m_services.size()) {
|
||||
return {};
|
||||
}
|
||||
return m_services.at(m_selectedServiceIndex);
|
||||
}
|
||||
|
||||
QJsonObject ApiServicesModel::getSelectedServiceInfo()
|
||||
@@ -265,30 +243,14 @@ QVariant ApiServicesModel::getSelectedServiceData(const QString roleString)
|
||||
|
||||
int ApiServicesModel::serviceIndexForType(const QString &type) const
|
||||
{
|
||||
for (int i = 0; i < m_services.size(); ++i) {
|
||||
if (m_services.at(i).type == type) {
|
||||
return i;
|
||||
for (int serviceIndex = 0; serviceIndex < m_services.size(); ++serviceIndex) {
|
||||
if (m_services.at(serviceIndex).type == type) {
|
||||
return serviceIndex;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
QVariant ApiServicesModel::getServiceFieldForType(const QString &type, const QString &roleString) const
|
||||
{
|
||||
const int row = serviceIndexForType(type);
|
||||
if (row < 0) {
|
||||
return {};
|
||||
}
|
||||
const QModelIndex modelIndex = index(row);
|
||||
const auto roles = roleNames();
|
||||
for (auto it = roles.begin(); it != roles.end(); ++it) {
|
||||
if (QString(it.value()) == roleString) {
|
||||
return data(modelIndex, it.key());
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> ApiServicesModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
@@ -303,8 +265,6 @@ QHash<int, QByteArray> ApiServicesModel::roleNames() const
|
||||
roles[PriceRole] = "price";
|
||||
roles[EndDateRole] = "endDate";
|
||||
roles[OrderRole] = "order";
|
||||
roles[SubscriptionPlansRole] = "subscriptionPlans";
|
||||
roles[BenefitRowsRole] = "benefitRows";
|
||||
|
||||
return roles;
|
||||
}
|
||||
@@ -330,7 +290,7 @@ ApiServicesModel::ApiServicesData ApiServicesModel::getApiServicesData(const QJs
|
||||
serviceData.serviceInfo.description = serviceDescription.value(configKey::description).toString();
|
||||
serviceData.serviceInfo.features = serviceDescription.value(configKey::features).toString();
|
||||
|
||||
serviceData.subscriptionPlans = jsonObjectArrayToVariantList(serviceDescription.value(configKey::subscriptionPlans).toArray());
|
||||
serviceData.subscriptionPlansJson = serviceDescription.value(configKey::subscriptionPlans).toArray();
|
||||
serviceData.benefits = serviceDescription.value(configKey::benefits).toArray();
|
||||
|
||||
serviceData.supportInfo = data.value(apiDefs::key::supportInfo).toObject();
|
||||
@@ -353,75 +313,3 @@ ApiServicesModel::ApiServicesData ApiServicesModel::getApiServicesData(const QJs
|
||||
|
||||
return serviceData;
|
||||
}
|
||||
|
||||
QString ApiServicesModel::formatPriceForBenefit(const QString &rawPrice) const
|
||||
{
|
||||
if (rawPrice == QStringLiteral("free")) {
|
||||
return tr("Free");
|
||||
}
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
return tr("%1 $").arg(rawPrice);
|
||||
#else
|
||||
return tr("%1 $/month").arg(rawPrice);
|
||||
#endif
|
||||
}
|
||||
|
||||
QString ApiServicesModel::benefitInjectValue(const QString &injectKey, const ServiceInfo &info,
|
||||
const QJsonObject &supportInfo) const
|
||||
{
|
||||
if (injectKey == QLatin1String("region")) {
|
||||
return info.region.isEmpty() ? QStringLiteral("—") : info.region;
|
||||
}
|
||||
if (injectKey == QLatin1String("speed")) {
|
||||
return info.speed.isEmpty() ? QStringLiteral("—") : info.speed;
|
||||
}
|
||||
if (injectKey == QLatin1String("price")) {
|
||||
return formatPriceForBenefit(info.price);
|
||||
}
|
||||
|
||||
if (injectKey == apiDefs::key::telegram) {
|
||||
const QString handle = supportInfo.value(apiDefs::key::telegram).toString().trimmed();
|
||||
if (handle.isEmpty()) {
|
||||
return QStringLiteral("—");
|
||||
}
|
||||
if (handle.startsWith(QLatin1Char('@'))) {
|
||||
return handle;
|
||||
}
|
||||
return QLatin1Char('@') + handle;
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QVariantList ApiServicesModel::buildBenefitRows(const ApiServicesData &service) const
|
||||
{
|
||||
QVariantList out;
|
||||
for (const QJsonValue &v : service.benefits) {
|
||||
if (!v.isObject()) {
|
||||
continue;
|
||||
}
|
||||
const QJsonObject o = v.toObject();
|
||||
QString title = o.value(QStringLiteral("title")).toString();
|
||||
QString body = o.value(QStringLiteral("body")).toString();
|
||||
const QString iconKey = o.value(QStringLiteral("icon")).toString();
|
||||
const QString injectKey = o.value(QStringLiteral("inject_key")).toString();
|
||||
if (body.contains(QLatin1String("%1")) && !injectKey.isEmpty()) {
|
||||
QString injected = benefitInjectValue(injectKey, service.serviceInfo, service.supportInfo);
|
||||
if (injected.isEmpty()) {
|
||||
injected = QStringLiteral("—");
|
||||
}
|
||||
body = body.arg(injected);
|
||||
}
|
||||
if (title.isEmpty() && body.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
QVariantMap m;
|
||||
m.insert(QStringLiteral("icon"), iconUrlFromGatewayBenefitIcon(iconKey));
|
||||
m.insert(QStringLiteral("title"), title);
|
||||
m.insert(QStringLiteral("body"), body);
|
||||
if (o.value(QStringLiteral("accent")).toBool()) {
|
||||
m.insert(QStringLiteral("accent"), true);
|
||||
}
|
||||
out.append(m);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -4,59 +4,13 @@
|
||||
#include <QAbstractListModel>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QVariantList>
|
||||
#include <QVector>
|
||||
|
||||
class ApiServicesModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
NameRole = Qt::UserRole + 1,
|
||||
CardDescriptionRole,
|
||||
ServiceDescriptionRole,
|
||||
IsServiceAvailableRole,
|
||||
SpeedRole,
|
||||
TimeLimitRole,
|
||||
RegionRole,
|
||||
FeaturesRole,
|
||||
PriceRole,
|
||||
EndDateRole,
|
||||
OrderRole,
|
||||
SubscriptionPlansRole,
|
||||
BenefitRowsRole
|
||||
};
|
||||
|
||||
explicit ApiServicesModel(QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
public slots:
|
||||
void updateModel(const QJsonObject &data);
|
||||
|
||||
void setServiceIndex(const int index);
|
||||
|
||||
QJsonObject getSelectedServiceInfo();
|
||||
QString getSelectedServiceType();
|
||||
QString getSelectedServiceProtocol();
|
||||
QString getSelectedServiceName();
|
||||
QJsonArray getSelectedServiceCountries();
|
||||
|
||||
QString getCountryCode();
|
||||
|
||||
QString getStoreEndpoint();
|
||||
|
||||
QVariant getSelectedServiceData(const QString roleString);
|
||||
|
||||
Q_INVOKABLE int serviceIndexForType(const QString &type) const;
|
||||
Q_INVOKABLE QVariant getServiceFieldForType(const QString &type, const QString &roleString) const;
|
||||
|
||||
protected:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
private:
|
||||
struct ServiceInfo
|
||||
{
|
||||
QString name;
|
||||
@@ -91,16 +45,59 @@ private:
|
||||
|
||||
QJsonArray availableCountries;
|
||||
|
||||
QVariantList subscriptionPlans;
|
||||
QJsonArray subscriptionPlansJson;
|
||||
QJsonArray benefits;
|
||||
};
|
||||
|
||||
ApiServicesData getApiServicesData(const QJsonObject &data);
|
||||
enum Roles {
|
||||
NameRole = Qt::UserRole + 1,
|
||||
CardDescriptionRole,
|
||||
ServiceDescriptionRole,
|
||||
IsServiceAvailableRole,
|
||||
SpeedRole,
|
||||
TimeLimitRole,
|
||||
RegionRole,
|
||||
FeaturesRole,
|
||||
PriceRole,
|
||||
EndDateRole,
|
||||
OrderRole
|
||||
};
|
||||
|
||||
QVariantList buildBenefitRows(const ApiServicesData &service) const;
|
||||
QString benefitInjectValue(const QString &injectKey, const ServiceInfo &info,
|
||||
const QJsonObject &supportInfo) const;
|
||||
QString formatPriceForBenefit(const QString &rawPrice) const;
|
||||
explicit ApiServicesModel(QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
ApiServicesData selectedServiceData() const;
|
||||
|
||||
public slots:
|
||||
void updateModel(const QJsonObject &data);
|
||||
|
||||
void setServiceIndex(const int index);
|
||||
|
||||
QJsonObject getSelectedServiceInfo();
|
||||
QString getSelectedServiceType();
|
||||
QString getSelectedServiceProtocol();
|
||||
QString getSelectedServiceName();
|
||||
QJsonArray getSelectedServiceCountries();
|
||||
|
||||
QString getCountryCode();
|
||||
|
||||
QString getStoreEndpoint();
|
||||
|
||||
QVariant getSelectedServiceData(const QString roleString);
|
||||
|
||||
Q_INVOKABLE int serviceIndexForType(const QString &type) const;
|
||||
|
||||
signals:
|
||||
void serviceSelectionChanged();
|
||||
|
||||
protected:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
private:
|
||||
ApiServicesData getApiServicesData(const QJsonObject &data);
|
||||
|
||||
QString m_countryCode;
|
||||
QVector<ApiServicesData> m_services;
|
||||
@@ -108,4 +105,4 @@ private:
|
||||
int m_selectedServiceIndex;
|
||||
};
|
||||
|
||||
#endif // APISERVICESMODEL_H
|
||||
#endif
|
||||
|
||||
135
client/ui/models/api/apiSubscriptionPlansModel.cpp
Normal file
135
client/ui/models/api/apiSubscriptionPlansModel.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
#include "apiSubscriptionPlansModel.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QVariantMap>
|
||||
#include <utility>
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace configKey
|
||||
{
|
||||
constexpr char primaryLeft[] = "primary_left";
|
||||
constexpr char primaryRight[] = "primary_right";
|
||||
constexpr char subtitle[] = "subtitle";
|
||||
constexpr char recommended[] = "recommended";
|
||||
constexpr char checkoutUrl[] = "checkout_url";
|
||||
constexpr char serviceType[] = "service_type";
|
||||
constexpr char serviceProtocol[] = "service_protocol";
|
||||
|
||||
constexpr char primaryLeftCamel[] = "primaryLeft";
|
||||
constexpr char primaryRightCamel[] = "primaryRight";
|
||||
constexpr char checkoutUrlCamel[] = "checkoutUrl";
|
||||
constexpr char serviceTypeCamel[] = "serviceType";
|
||||
constexpr char serviceProtocolCamel[] = "serviceProtocol";
|
||||
}
|
||||
}
|
||||
|
||||
ApiSubscriptionPlansModel::ApiSubscriptionPlansModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
int ApiSubscriptionPlansModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
return m_subscriptionPlans.size();
|
||||
}
|
||||
|
||||
QVariant ApiSubscriptionPlansModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() < 0 || index.row() >= m_subscriptionPlans.size()) {
|
||||
return {};
|
||||
}
|
||||
const SubscriptionPlanItem &plan = m_subscriptionPlans.at(index.row());
|
||||
switch (role) {
|
||||
case PrimaryLeftRole:
|
||||
return plan.primaryLeft;
|
||||
case PrimaryRightRole:
|
||||
return plan.primaryRight;
|
||||
case SubtitleRole:
|
||||
return plan.subtitle;
|
||||
case RecommendedRole:
|
||||
return plan.recommended;
|
||||
case CheckoutUrlRole:
|
||||
return plan.checkoutUrl;
|
||||
case ServiceTypeRole:
|
||||
return plan.serviceType;
|
||||
case ServiceProtocolRole:
|
||||
return plan.serviceProtocol;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> ApiSubscriptionPlansModel::roleNames() const
|
||||
{
|
||||
return {
|
||||
{ PrimaryLeftRole, "primaryLeft" },
|
||||
{ PrimaryRightRole, "primaryRight" },
|
||||
{ SubtitleRole, "subtitle" },
|
||||
{ RecommendedRole, "recommended" },
|
||||
{ CheckoutUrlRole, "checkoutUrl" },
|
||||
{ ServiceTypeRole, "serviceType" },
|
||||
{ ServiceProtocolRole, "serviceProtocol" },
|
||||
};
|
||||
}
|
||||
|
||||
void ApiSubscriptionPlansModel::updateModel(const QJsonArray &arr)
|
||||
{
|
||||
beginResetModel();
|
||||
m_subscriptionPlans.clear();
|
||||
m_subscriptionPlans.reserve(arr.size());
|
||||
for (const QJsonValue &planValue : arr) {
|
||||
if (!planValue.isObject()) {
|
||||
continue;
|
||||
}
|
||||
const QJsonObject planObject = planValue.toObject();
|
||||
SubscriptionPlanItem subscriptionPlan;
|
||||
subscriptionPlan.primaryLeft = planObject.value(configKey::primaryLeft).toString();
|
||||
subscriptionPlan.primaryRight = planObject.value(configKey::primaryRight).toString();
|
||||
subscriptionPlan.subtitle = planObject.value(configKey::subtitle).toString();
|
||||
subscriptionPlan.recommended = planObject.value(configKey::recommended).toBool();
|
||||
subscriptionPlan.checkoutUrl = planObject.value(configKey::checkoutUrl).toString();
|
||||
subscriptionPlan.serviceType = planObject.value(configKey::serviceType).toString();
|
||||
subscriptionPlan.serviceProtocol = planObject.value(configKey::serviceProtocol).toString();
|
||||
m_subscriptionPlans.append(std::move(subscriptionPlan));
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void ApiSubscriptionPlansModel::clear()
|
||||
{
|
||||
beginResetModel();
|
||||
m_subscriptionPlans.clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QVariantMap ApiSubscriptionPlansModel::planAt(int row) const
|
||||
{
|
||||
if (row < 0 || row >= m_subscriptionPlans.size()) {
|
||||
return {};
|
||||
}
|
||||
const SubscriptionPlanItem &plan = m_subscriptionPlans.at(row);
|
||||
QVariantMap planMap;
|
||||
planMap.insert(QLatin1String(configKey::primaryLeftCamel), plan.primaryLeft);
|
||||
planMap.insert(QLatin1String(configKey::primaryRightCamel), plan.primaryRight);
|
||||
planMap.insert(QLatin1String(configKey::subtitle), plan.subtitle);
|
||||
planMap.insert(QLatin1String(configKey::recommended), plan.recommended);
|
||||
planMap.insert(QLatin1String(configKey::checkoutUrlCamel), plan.checkoutUrl);
|
||||
planMap.insert(QLatin1String(configKey::serviceTypeCamel), plan.serviceType);
|
||||
planMap.insert(QLatin1String(configKey::serviceProtocolCamel), plan.serviceProtocol);
|
||||
return planMap;
|
||||
}
|
||||
|
||||
int ApiSubscriptionPlansModel::recommendedRowIndex() const
|
||||
{
|
||||
for (int planIndex = 0; planIndex < m_subscriptionPlans.size(); ++planIndex) {
|
||||
if (m_subscriptionPlans.at(planIndex).recommended) {
|
||||
return planIndex;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
51
client/ui/models/api/apiSubscriptionPlansModel.h
Normal file
51
client/ui/models/api/apiSubscriptionPlansModel.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifndef APISUBSCRIPTIONPLANSMODEL_H
|
||||
#define APISUBSCRIPTIONPLANSMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QJsonArray>
|
||||
#include <QVector>
|
||||
|
||||
class ApiSubscriptionPlansModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
PrimaryLeftRole = Qt::UserRole + 1,
|
||||
PrimaryRightRole,
|
||||
SubtitleRole,
|
||||
RecommendedRole,
|
||||
CheckoutUrlRole,
|
||||
ServiceTypeRole,
|
||||
ServiceProtocolRole
|
||||
};
|
||||
Q_ENUM(Roles)
|
||||
|
||||
explicit ApiSubscriptionPlansModel(QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
void updateModel(const QJsonArray &arr);
|
||||
void clear();
|
||||
|
||||
Q_INVOKABLE QVariantMap planAt(int row) const;
|
||||
Q_INVOKABLE int recommendedRowIndex() const;
|
||||
|
||||
private:
|
||||
struct SubscriptionPlanItem
|
||||
{
|
||||
QString primaryLeft;
|
||||
QString primaryRight;
|
||||
QString subtitle;
|
||||
bool recommended = false;
|
||||
QString checkoutUrl;
|
||||
QString serviceType;
|
||||
QString serviceProtocol;
|
||||
};
|
||||
|
||||
QVector<SubscriptionPlanItem> m_subscriptionPlans;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -8,12 +8,12 @@ import Style 1.0
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property var benefitItems: []
|
||||
property var benefitsModel: null
|
||||
|
||||
visible: benefitItems && benefitItems.length > 0
|
||||
visible: benefitsModel && benefitsModel.rowCount() > 0
|
||||
|
||||
radius: 16
|
||||
color: "#1C1C1E"
|
||||
color: AmneziaStyle.color.benefitsPanelBackground
|
||||
implicitHeight: inner.implicitHeight + 24
|
||||
|
||||
ColumnLayout {
|
||||
@@ -26,14 +26,14 @@ Rectangle {
|
||||
spacing: 20
|
||||
|
||||
Repeater {
|
||||
model: root.benefitItems ? root.benefitItems.length : 0
|
||||
model: benefitsModel
|
||||
|
||||
delegate: BenefitRow {
|
||||
Layout.fillWidth: true
|
||||
iconSource: root.benefitItems[index].icon
|
||||
titleText: root.benefitItems[index].title
|
||||
bodyText: root.benefitItems[index].body
|
||||
accent: !!root.benefitItems[index].accent
|
||||
iconSource: model.icon
|
||||
titleText: model.title
|
||||
bodyText: model.body
|
||||
accent: !!model.accent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ QtObject {
|
||||
readonly property color onyxBlack: '#1C1D21'
|
||||
readonly property color midnightBlack: '#0E0E11'
|
||||
readonly property color goldenApricot: '#FBB26A'
|
||||
readonly property color benefitsPanelBackground: '#1C1C1E'
|
||||
readonly property color softViolet: '#A87BE2'
|
||||
readonly property color burntOrange: '#A85809'
|
||||
readonly property color mutedBrown: '#84603D'
|
||||
|
||||
@@ -16,28 +16,16 @@ PageType {
|
||||
property string freeHeaderName: ""
|
||||
property string freeHeaderDescription: ""
|
||||
property string freeFeaturesHtml: ""
|
||||
property var benefitRows: []
|
||||
|
||||
function syncFromModel() {
|
||||
root.freeHeaderName = String(ApiServicesModel.getSelectedServiceData("name"))
|
||||
root.freeHeaderDescription = String(ApiServicesModel.getSelectedServiceData("serviceDescription"))
|
||||
var text = ApiServicesModel.getSelectedServiceData("features")
|
||||
root.freeFeaturesHtml = String(text).replace("%1", LanguageModel.getCurrentSiteUrl("free")).replace("/free", "")
|
||||
|
||||
var rows = ApiServicesModel.getSelectedServiceData("benefitRows")
|
||||
root.benefitRows = rows !== undefined && rows !== null ? rows : []
|
||||
}
|
||||
|
||||
Component.onCompleted: syncFromModel()
|
||||
|
||||
Connections {
|
||||
target: ApiServicesModel
|
||||
|
||||
function onModelReset() {
|
||||
root.syncFromModel()
|
||||
}
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
@@ -97,7 +85,7 @@ PageType {
|
||||
Layout.rightMargin: 16
|
||||
Layout.bottomMargin: 24
|
||||
|
||||
benefitItems: root.benefitRows
|
||||
benefitsModel: ApiConfigsController.benefitsModel
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
@@ -106,7 +94,7 @@ PageType {
|
||||
Layout.rightMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
visible: root.freeFeaturesHtml.length > 0 && (!root.benefitRows || root.benefitRows.length === 0)
|
||||
visible: root.freeFeaturesHtml.length > 0 && ApiConfigsController.benefitsModel.rowCount() === 0
|
||||
|
||||
textFormat: Text.RichText
|
||||
text: root.freeFeaturesHtml
|
||||
@@ -138,7 +126,8 @@ PageType {
|
||||
text: {
|
||||
var termsUrl = LanguageModel.getCurrentSiteUrl()
|
||||
var privacyUrl = LanguageModel.getCurrentSiteUrl("policy")
|
||||
return qsTr("By continuing, you agree to the <a href=\"%1\" style=\"color: #FBB26A;\">Terms of Use</a> and <a href=\"%2\" style=\"color: #FBB26A;\">Privacy Policy</a>").arg(termsUrl).arg(privacyUrl)
|
||||
return qsTr("By continuing, you agree to the <a href=\"%1\" style=\"color: %3;\">Terms of Use</a> and <a href=\"%2\" style=\"color: %3;\">Privacy Policy</a>")
|
||||
.arg(termsUrl).arg(privacyUrl).arg(Qt.colorToString(AmneziaStyle.color.goldenApricot))
|
||||
}
|
||||
|
||||
onLinkActivated: function(link) {
|
||||
@@ -168,7 +157,8 @@ PageType {
|
||||
text: {
|
||||
var termsUrl = "https://www.apple.com/legal/internet-services/itunes/dev/stdeula/"
|
||||
var privacyUrl = LanguageModel.getCurrentSiteUrl("policy")
|
||||
return qsTr("By continuing, you agree to the <a href=\"%1\" style=\"color: #FBB26A;\">Terms of Use</a> and <a href=\"%2\" style=\"color: #FBB26A;\">Privacy Policy</a>").arg(termsUrl).arg(privacyUrl)
|
||||
return qsTr("By continuing, you agree to the <a href=\"%1\" style=\"color: %3;\">Terms of Use</a> and <a href=\"%2\" style=\"color: %3;\">Privacy Policy</a>")
|
||||
.arg(termsUrl).arg(privacyUrl).arg(Qt.colorToString(AmneziaStyle.color.goldenApricot))
|
||||
}
|
||||
|
||||
onLinkActivated: function(link) {
|
||||
|
||||
@@ -13,26 +13,15 @@ import "../Components"
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
property var subscriptionPlans: []
|
||||
property var benefitRows: []
|
||||
property int selectedPlanIndex: 0
|
||||
property string premiumFeaturesHtml: ""
|
||||
property string premiumHeaderName: ""
|
||||
property string premiumHeaderDescription: ""
|
||||
|
||||
readonly property var currentPlan: subscriptionPlans[selectedPlanIndex]
|
||||
readonly property var currentPlan: ApiConfigsController.subscriptionPlansModel.planAt(selectedPlanIndex)
|
||||
|
||||
function syncFromModel() {
|
||||
root.subscriptionPlans = ApiServicesModel.getSelectedServiceData("subscriptionPlans")
|
||||
root.benefitRows = ApiServicesModel.getSelectedServiceData("benefitRows")
|
||||
|
||||
root.selectedPlanIndex = 0
|
||||
for (var i = 0; i < root.subscriptionPlans.length; ++i) {
|
||||
if (root.subscriptionPlans[i].recommended) {
|
||||
root.selectedPlanIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
root.selectedPlanIndex = ApiConfigsController.subscriptionPlansModel.recommendedRowIndex()
|
||||
|
||||
root.premiumFeaturesHtml = String(ApiServicesModel.getSelectedServiceData("features")).replace("%1", LanguageModel.getCurrentSiteUrl("free")).replace("/free", "")
|
||||
root.premiumHeaderName = String(ApiServicesModel.getSelectedServiceData("name"))
|
||||
@@ -41,14 +30,6 @@ PageType {
|
||||
|
||||
Component.onCompleted: syncFromModel()
|
||||
|
||||
Connections {
|
||||
target: ApiServicesModel
|
||||
|
||||
function onModelReset() {
|
||||
root.syncFromModel()
|
||||
}
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
@@ -103,23 +84,21 @@ PageType {
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: subscriptionPlans.length
|
||||
model: ApiConfigsController.subscriptionPlansModel
|
||||
|
||||
delegate: SubscriptionPlanCard {
|
||||
required property int index
|
||||
|
||||
readonly property var plan: root.subscriptionPlans[index]
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.bottomMargin: index === root.subscriptionPlans.length - 1 ? 24 : 12
|
||||
Layout.bottomMargin: index === ApiConfigsController.subscriptionPlansModel.rowCount() - 1 ? 24 : 12
|
||||
|
||||
selected: root.selectedPlanIndex === index
|
||||
primaryLeft: String(plan.primary_left)
|
||||
primaryRight: String(plan.primary_right)
|
||||
subtitle: String(plan.subtitle)
|
||||
showRecommendedBadge: !!plan.recommended
|
||||
primaryLeft: String(model.primaryLeft)
|
||||
primaryRight: String(model.primaryRight)
|
||||
subtitle: String(model.subtitle)
|
||||
showRecommendedBadge: !!model.recommended
|
||||
recommendedText: qsTr("Recommended")
|
||||
|
||||
onSelectRequested: root.selectedPlanIndex = index
|
||||
@@ -162,7 +141,7 @@ PageType {
|
||||
Layout.rightMargin: 16
|
||||
Layout.bottomMargin: 24
|
||||
|
||||
benefitItems: root.benefitRows
|
||||
benefitsModel: ApiConfigsController.benefitsModel
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
@@ -197,7 +176,8 @@ PageType {
|
||||
text: {
|
||||
var termsUrl = LanguageModel.getCurrentSiteUrl()
|
||||
var privacyUrl = LanguageModel.getCurrentSiteUrl("policy")
|
||||
return qsTr("By continuing, you agree to the <a href=\"%1\" style=\"color: #FBB26A;\">Terms of Use</a> and <a href=\"%2\" style=\"color: #FBB26A;\">Privacy Policy</a>").arg(termsUrl).arg(privacyUrl)
|
||||
return qsTr("By continuing, you agree to the <a href=\"%1\" style=\"color: %3;\">Terms of Use</a> and <a href=\"%2\" style=\"color: %3;\">Privacy Policy</a>")
|
||||
.arg(termsUrl).arg(privacyUrl).arg(Qt.colorToString(AmneziaStyle.color.goldenApricot))
|
||||
}
|
||||
|
||||
onLinkActivated: function(link) {
|
||||
@@ -227,7 +207,8 @@ PageType {
|
||||
text: {
|
||||
var termsUrl = "https://www.apple.com/legal/internet-services/itunes/dev/stdeula/"
|
||||
var privacyUrl = LanguageModel.getCurrentSiteUrl("policy")
|
||||
return qsTr("By continuing, you agree to the <a href=\"%1\" style=\"color: #FBB26A;\">Terms of Use</a> and <a href=\"%2\" style=\"color: #FBB26A;\">Privacy Policy</a>").arg(termsUrl).arg(privacyUrl)
|
||||
return qsTr("By continuing, you agree to the <a href=\"%1\" style=\"color: %3;\">Terms of Use</a> and <a href=\"%2\" style=\"color: %3;\">Privacy Policy</a>")
|
||||
.arg(termsUrl).arg(privacyUrl).arg(Qt.colorToString(AmneziaStyle.color.goldenApricot))
|
||||
}
|
||||
|
||||
onLinkActivated: function(link) {
|
||||
@@ -259,7 +240,7 @@ PageType {
|
||||
if (!plan) {
|
||||
return qsTr("Continue")
|
||||
}
|
||||
return qsTr("Subscribe — %1 for %2").arg(String(plan.primary_left)).arg(String(plan.primary_right))
|
||||
return qsTr("Subscribe — %1 for %2").arg(String(plan.primaryLeft)).arg(String(plan.primaryRight))
|
||||
}
|
||||
|
||||
clickedFunc: function() {
|
||||
@@ -267,14 +248,14 @@ PageType {
|
||||
if (!plan) {
|
||||
return
|
||||
}
|
||||
if (plan.checkout_url) {
|
||||
Qt.openUrlExternally(plan.checkout_url)
|
||||
if (plan.checkoutUrl) {
|
||||
Qt.openUrlExternally(plan.checkoutUrl)
|
||||
PageController.closePage()
|
||||
PageController.closePage()
|
||||
return
|
||||
}
|
||||
if (plan.service_type) {
|
||||
var idx = ApiServicesModel.serviceIndexForType(plan.service_type)
|
||||
if (plan.serviceType) {
|
||||
var idx = ApiServicesModel.serviceIndexForType(plan.serviceType)
|
||||
if (idx < 0) {
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user