feat: add trial api support

This commit is contained in:
vkamn
2026-03-26 20:03:18 +08:00
parent 041219187b
commit bae2dd452b
10 changed files with 225 additions and 84 deletions
+1
View File
@@ -234,6 +234,7 @@
<file>ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml</file> <file>ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml</file>
<file>ui/qml/Pages2/PageSetupWizardApiFreeInfo.qml</file> <file>ui/qml/Pages2/PageSetupWizardApiFreeInfo.qml</file>
<file>ui/qml/Pages2/PageSetupWizardApiPremiumInfo.qml</file> <file>ui/qml/Pages2/PageSetupWizardApiPremiumInfo.qml</file>
<file>ui/qml/Pages2/PageSetupWizardApiTrialEmail.qml</file>
<file>ui/qml/Pages2/PageSetupWizardApiServicesList.qml</file> <file>ui/qml/Pages2/PageSetupWizardApiServicesList.qml</file>
<file>ui/qml/Pages2/PageSetupWizardConfigSource.qml</file> <file>ui/qml/Pages2/PageSetupWizardConfigSource.qml</file>
<file>ui/qml/Pages2/PageSetupWizardCredentials.qml</file> <file>ui/qml/Pages2/PageSetupWizardCredentials.qml</file>
@@ -12,6 +12,7 @@
#include <QDebug> #include <QDebug>
#include <QEventLoop> #include <QEventLoop>
#include <QSet> #include <QSet>
#include <QVariantMap>
#include "platforms/ios/ios_controller.h" #include "platforms/ios/ios_controller.h"
@@ -459,7 +460,7 @@ bool ApiConfigsController::importService()
return importSerivceFromAppStore(); return importSerivceFromAppStore();
} }
} else if (m_apiServicesModel->getSelectedServiceType() == serviceType::amneziaFree) { } else if (m_apiServicesModel->getSelectedServiceType() == serviceType::amneziaFree) {
importServiceFromGateway(); importFreeFromGateway();
return true; return true;
} }
return false; return false;
@@ -675,7 +676,7 @@ bool ApiConfigsController::restoreSerivceFromAppStore()
return true; return true;
} }
bool ApiConfigsController::importServiceFromGateway() bool ApiConfigsController::importFreeFromGateway()
{ {
GatewayRequestData gatewayRequestData { QSysInfo::productType(), GatewayRequestData gatewayRequestData { QSysInfo::productType(),
QString(APP_VERSION), QString(APP_VERSION),
@@ -727,6 +728,72 @@ bool ApiConfigsController::importServiceFromGateway()
} }
} }
bool ApiConfigsController::importTrialFromGateway(const QString &email)
{
const QString trimmedEmail = email.trimmed();
if (trimmedEmail.isEmpty()) {
emit errorOccurred(ErrorCode::ApiConfigEmptyError);
return false;
}
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
QString(APP_VERSION),
m_settings->getAppLanguage().name().split("_").first(),
m_settings->getInstallationUuid(true),
m_apiServicesModel->getCountryCode(),
"",
m_apiServicesModel->getSelectedServiceType(),
m_apiServicesModel->getSelectedServiceProtocol(),
QJsonObject() };
if (m_serversModel->isServerFromApiAlreadyExists(gatewayRequestData.userCountryCode, gatewayRequestData.serviceType,
gatewayRequestData.serviceProtocol)) {
emit errorOccurred(ErrorCode::ApiConfigAlreadyAdded);
return false;
}
ProtocolData protocolData = generateProtocolData(gatewayRequestData.serviceProtocol);
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
appendProtocolDataToApiPayload(gatewayRequestData.serviceProtocol, protocolData, apiPayload);
apiPayload.insert(apiDefs::key::email, trimmedEmail);
QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/trial"), apiPayload, responseBody);
if (errorCode != ErrorCode::NoError) {
emit errorOccurred(errorCode);
return false;
}
QJsonObject responseObject = QJsonDocument::fromJson(responseBody).object();
QString key = responseObject.value(apiDefs::key::config).toString();
if (key.isEmpty()) {
qWarning().noquote() << "[Trial] trial response does not contain config field";
emit errorOccurred(ErrorCode::ApiConfigEmptyError);
return false;
}
key.replace(QStringLiteral("vpn://"), QString());
QByteArray configBytes = QByteArray::fromBase64(key.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
QByteArray uncompressed = qUncompress(configBytes);
if (!uncompressed.isEmpty()) {
configBytes = uncompressed;
}
if (configBytes.isEmpty()) {
qWarning().noquote() << "[Trial] trial response config payload is empty";
emit errorOccurred(ErrorCode::ApiConfigEmptyError);
return false;
}
QJsonObject configObject = QJsonDocument::fromJson(configBytes).object();
quint16 crc = qChecksum(QJsonDocument(configObject).toJson());
configObject.insert(config_key::crc, crc);
m_serversModel->addServer(configObject);
emit installServerFromApiFinished(tr("%1 installed successfully.").arg(m_apiServicesModel->getSelectedServiceName()));
return true;
}
bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const QString &newCountryCode, const QString &newCountryName, bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const QString &newCountryCode, const QString &newCountryName,
bool reloadServiceConfig) bool reloadServiceConfig)
{ {
@@ -18,9 +18,6 @@ public:
const QSharedPointer<ApiBenefitsModel> &benefitsModel, const std::shared_ptr<Settings> &settings, const QSharedPointer<ApiBenefitsModel> &benefitsModel, const std::shared_ptr<Settings> &settings,
QObject *parent = nullptr); 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(QList<QString> qrCodes READ getQrCodes NOTIFY vpnKeyExportReady)
Q_PROPERTY(int qrCodesCount READ getQrCodesCount NOTIFY vpnKeyExportReady) Q_PROPERTY(int qrCodesCount READ getQrCodesCount NOTIFY vpnKeyExportReady)
Q_PROPERTY(QString vpnKey READ getVpnKey NOTIFY vpnKeyExportReady) Q_PROPERTY(QString vpnKey READ getVpnKey NOTIFY vpnKeyExportReady)
@@ -36,7 +33,8 @@ public slots:
bool importService(); bool importService();
bool importSerivceFromAppStore(); bool importSerivceFromAppStore();
bool restoreSerivceFromAppStore(); bool restoreSerivceFromAppStore();
bool importServiceFromGateway(); bool importFreeFromGateway();
bool importTrialFromGateway(const QString &email);
bool updateServiceFromGateway(const int serverIndex, const QString &newCountryCode, const QString &newCountryName, bool updateServiceFromGateway(const int serverIndex, const QString &newCountryCode, const QString &newCountryName,
bool reloadServiceConfig = false); bool reloadServiceConfig = false);
bool updateServiceFromTelegram(const int serverIndex); bool updateServiceFromTelegram(const int serverIndex);
@@ -45,9 +43,6 @@ public slots:
bool isConfigValid(); bool isConfigValid();
ApiSubscriptionPlansModel *subscriptionPlansModel() const { return m_subscriptionPlansModel.get(); }
ApiBenefitsModel *benefitsModel() const { return m_benefitsModel.get(); }
void setCurrentProtocol(const QString &protocolName); void setCurrentProtocol(const QString &protocolName);
bool isVlessProtocol(); bool isVlessProtocol();
+1
View File
@@ -77,6 +77,7 @@ namespace PageLoader
PageShareConnection, PageShareConnection,
PageSetupWizardApiPremiumInfo, PageSetupWizardApiPremiumInfo,
PageSetupWizardApiTrialEmail,
PageDevMenu PageDevMenu
}; };
+2 -6
View File
@@ -45,7 +45,6 @@ namespace
{ {
constexpr char amneziaFree[] = "amnezia-free"; constexpr char amneziaFree[] = "amnezia-free";
constexpr char amneziaPremium[] = "amnezia-premium"; constexpr char amneziaPremium[] = "amnezia-premium";
constexpr char amneziaTrial[] = "amnezia-trial";
} }
} }
@@ -76,7 +75,7 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
} }
case CardDescriptionRole: { case CardDescriptionRole: {
auto speed = apiServiceData.serviceInfo.speed; auto speed = apiServiceData.serviceInfo.speed;
if (serviceType == serviceType::amneziaPremium || serviceType == serviceType::amneziaTrial) { if (serviceType == serviceType::amneziaPremium) {
return apiServiceData.serviceInfo.cardDescription.arg(speed); return apiServiceData.serviceInfo.cardDescription.arg(speed);
} else if (serviceType == serviceType::amneziaFree) { } else if (serviceType == serviceType::amneziaFree) {
QString description = apiServiceData.serviceInfo.cardDescription; QString description = apiServiceData.serviceInfo.cardDescription;
@@ -132,11 +131,8 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
if (serviceType == serviceType::amneziaPremium) { if (serviceType == serviceType::amneziaPremium) {
return 0; return 0;
} }
if (serviceType == serviceType::amneziaTrial) {
return 1;
}
if (serviceType == serviceType::amneziaFree) { if (serviceType == serviceType::amneziaFree) {
return 2; return 1;
} }
return QVariant(); return QVariant();
} }
@@ -14,13 +14,13 @@ namespace configKey
constexpr char subtitle[] = "subtitle"; constexpr char subtitle[] = "subtitle";
constexpr char recommended[] = "recommended"; constexpr char recommended[] = "recommended";
constexpr char checkoutUrl[] = "checkout_url"; constexpr char checkoutUrl[] = "checkout_url";
constexpr char serviceType[] = "service_type"; constexpr char isTrial[] = "is_trial";
constexpr char serviceProtocol[] = "service_protocol"; constexpr char serviceProtocol[] = "service_protocol";
constexpr char primaryLeftCamel[] = "primaryLeft"; constexpr char primaryLeftCamel[] = "primaryLeft";
constexpr char primaryRightCamel[] = "primaryRight"; constexpr char primaryRightCamel[] = "primaryRight";
constexpr char checkoutUrlCamel[] = "checkoutUrl"; constexpr char checkoutUrlCamel[] = "checkoutUrl";
constexpr char serviceTypeCamel[] = "serviceType"; constexpr char isTrialCamel[] = "isTrial";
constexpr char serviceProtocolCamel[] = "serviceProtocol"; constexpr char serviceProtocolCamel[] = "serviceProtocol";
} }
} }
@@ -55,8 +55,8 @@ QVariant ApiSubscriptionPlansModel::data(const QModelIndex &index, int role) con
return plan.recommended; return plan.recommended;
case CheckoutUrlRole: case CheckoutUrlRole:
return plan.checkoutUrl; return plan.checkoutUrl;
case ServiceTypeRole: case IsTrialRole:
return plan.serviceType; return plan.isTrial;
case ServiceProtocolRole: case ServiceProtocolRole:
return plan.serviceProtocol; return plan.serviceProtocol;
default: default:
@@ -72,7 +72,7 @@ QHash<int, QByteArray> ApiSubscriptionPlansModel::roleNames() const
{ SubtitleRole, "subtitle" }, { SubtitleRole, "subtitle" },
{ RecommendedRole, "recommended" }, { RecommendedRole, "recommended" },
{ CheckoutUrlRole, "checkoutUrl" }, { CheckoutUrlRole, "checkoutUrl" },
{ ServiceTypeRole, "serviceType" }, { IsTrialRole, "isTrial" },
{ ServiceProtocolRole, "serviceProtocol" }, { ServiceProtocolRole, "serviceProtocol" },
}; };
} }
@@ -93,7 +93,7 @@ void ApiSubscriptionPlansModel::updateModel(const QJsonArray &arr)
subscriptionPlan.subtitle = planObject.value(configKey::subtitle).toString(); subscriptionPlan.subtitle = planObject.value(configKey::subtitle).toString();
subscriptionPlan.recommended = planObject.value(configKey::recommended).toBool(); subscriptionPlan.recommended = planObject.value(configKey::recommended).toBool();
subscriptionPlan.checkoutUrl = planObject.value(configKey::checkoutUrl).toString(); subscriptionPlan.checkoutUrl = planObject.value(configKey::checkoutUrl).toString();
subscriptionPlan.serviceType = planObject.value(configKey::serviceType).toString(); subscriptionPlan.isTrial = planObject.value(configKey::isTrial).toBool();
subscriptionPlan.serviceProtocol = planObject.value(configKey::serviceProtocol).toString(); subscriptionPlan.serviceProtocol = planObject.value(configKey::serviceProtocol).toString();
m_subscriptionPlans.append(std::move(subscriptionPlan)); m_subscriptionPlans.append(std::move(subscriptionPlan));
} }
@@ -119,7 +119,7 @@ QVariantMap ApiSubscriptionPlansModel::planAt(int row) const
planMap.insert(QLatin1String(configKey::subtitle), plan.subtitle); planMap.insert(QLatin1String(configKey::subtitle), plan.subtitle);
planMap.insert(QLatin1String(configKey::recommended), plan.recommended); planMap.insert(QLatin1String(configKey::recommended), plan.recommended);
planMap.insert(QLatin1String(configKey::checkoutUrlCamel), plan.checkoutUrl); planMap.insert(QLatin1String(configKey::checkoutUrlCamel), plan.checkoutUrl);
planMap.insert(QLatin1String(configKey::serviceTypeCamel), plan.serviceType); planMap.insert(QLatin1String(configKey::isTrialCamel), plan.isTrial);
planMap.insert(QLatin1String(configKey::serviceProtocolCamel), plan.serviceProtocol); planMap.insert(QLatin1String(configKey::serviceProtocolCamel), plan.serviceProtocol);
return planMap; return planMap;
} }
@@ -16,7 +16,7 @@ public:
SubtitleRole, SubtitleRole,
RecommendedRole, RecommendedRole,
CheckoutUrlRole, CheckoutUrlRole,
ServiceTypeRole, IsTrialRole,
ServiceProtocolRole ServiceProtocolRole
}; };
Q_ENUM(Roles) Q_ENUM(Roles)
@@ -41,7 +41,7 @@ private:
QString subtitle; QString subtitle;
bool recommended = false; bool recommended = false;
QString checkoutUrl; QString checkoutUrl;
QString serviceType; bool isTrial = false;
QString serviceProtocol; QString serviceProtocol;
}; };
@@ -74,7 +74,7 @@ PageType {
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.bottomMargin: 12 Layout.bottomMargin: 12
text: qsTr("Available with Free") text: qsTr("Free features")
color: AmneziaStyle.color.mutedGray color: AmneziaStyle.color.mutedGray
font.pixelSize: 13 font.pixelSize: 13
} }
@@ -85,7 +85,7 @@ PageType {
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.bottomMargin: 24 Layout.bottomMargin: 24
benefitsModel: ApiConfigsController.benefitsModel benefitsModel: ApiBenefitsModel
} }
ParagraphTextType { ParagraphTextType {
@@ -94,7 +94,7 @@ PageType {
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.bottomMargin: 16 Layout.bottomMargin: 16
visible: root.freeFeaturesHtml.length > 0 && ApiConfigsController.benefitsModel.rowCount() === 0 visible: root.freeFeaturesHtml.length > 0 && ApiBenefitsModel.rowCount() === 0
textFormat: Text.RichText textFormat: Text.RichText
text: root.freeFeaturesHtml text: root.freeFeaturesHtml
@@ -127,7 +127,7 @@ PageType {
var termsUrl = LanguageModel.getCurrentSiteUrl() var termsUrl = LanguageModel.getCurrentSiteUrl()
var privacyUrl = LanguageModel.getCurrentSiteUrl("policy") var privacyUrl = LanguageModel.getCurrentSiteUrl("policy")
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>") 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)) .arg(termsUrl).arg(privacyUrl).arg("#FBB26A")
} }
onLinkActivated: function(link) { onLinkActivated: function(link) {
@@ -158,7 +158,7 @@ PageType {
var termsUrl = "https://www.apple.com/legal/internet-services/itunes/dev/stdeula/" var termsUrl = "https://www.apple.com/legal/internet-services/itunes/dev/stdeula/"
var privacyUrl = LanguageModel.getCurrentSiteUrl("policy") var privacyUrl = LanguageModel.getCurrentSiteUrl("policy")
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>") 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)) .arg(termsUrl).arg(privacyUrl).arg("#FBB26A")
} }
onLinkActivated: function(link) { onLinkActivated: function(link) {
@@ -185,7 +185,7 @@ PageType {
anchors.rightMargin: 16 anchors.rightMargin: 16
anchors.bottomMargin: 16 + SettingsController.safeAreaBottomMargin anchors.bottomMargin: 16 + SettingsController.safeAreaBottomMargin
text: ApiServicesModel.getSelectedServiceType() === "amnezia-trial" ? qsTr("Try Trial") : qsTr("Continue") text: qsTr("Continue")
clickedFunc: function() { clickedFunc: function() {
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
@@ -9,21 +9,20 @@ import "../Controls2"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
import "../Config" import "../Config"
import "../Components" import "../Components"
import PageEnum 1.0
PageType { PageType {
id: root id: root
property int selectedPlanIndex: 0 property int selectedPlanIndex: 0
property string premiumFeaturesHtml: ""
property string premiumHeaderName: "" property string premiumHeaderName: ""
property string premiumHeaderDescription: "" property string premiumHeaderDescription: ""
readonly property var currentPlan: ApiConfigsController.subscriptionPlansModel.planAt(selectedPlanIndex) readonly property var currentPlan: ApiSubscriptionPlansModel.planAt(selectedPlanIndex)
function syncFromModel() { function syncFromModel() {
root.selectedPlanIndex = ApiConfigsController.subscriptionPlansModel.recommendedRowIndex() root.selectedPlanIndex = ApiSubscriptionPlansModel.recommendedRowIndex()
root.premiumFeaturesHtml = String(ApiServicesModel.getSelectedServiceData("features")).replace("%1", LanguageModel.getCurrentSiteUrl("free")).replace("/free", "")
root.premiumHeaderName = String(ApiServicesModel.getSelectedServiceData("name")) root.premiumHeaderName = String(ApiServicesModel.getSelectedServiceData("name"))
root.premiumHeaderDescription = String(ApiServicesModel.getSelectedServiceData("serviceDescription")) root.premiumHeaderDescription = String(ApiServicesModel.getSelectedServiceData("serviceDescription"))
} }
@@ -72,27 +71,17 @@ PageType {
descriptionText: root.premiumHeaderDescription descriptionText: root.premiumHeaderDescription
} }
LabelTextType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 12
text: qsTr("Choose a plan")
color: AmneziaStyle.color.mutedGray
font.pixelSize: 13
}
Repeater { Repeater {
model: ApiConfigsController.subscriptionPlansModel model: ApiSubscriptionPlansModel
delegate: SubscriptionPlanCard { delegate: SubscriptionPlanCard {
required property int index required property int index
required property var model
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.bottomMargin: index === ApiConfigsController.subscriptionPlansModel.rowCount() - 1 ? 24 : 12 Layout.bottomMargin: index === ApiSubscriptionPlansModel.rowCount() - 1 ? 24 : 12
selected: root.selectedPlanIndex === index selected: root.selectedPlanIndex === index
primaryLeft: String(model.primaryLeft) primaryLeft: String(model.primaryLeft)
@@ -116,32 +105,13 @@ PageType {
font.pixelSize: 13 font.pixelSize: 13
} }
ParagraphTextType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 16
textFormat: Text.RichText
text: root.premiumFeaturesHtml
onLinkActivated: function(link) {
Qt.openUrlExternally(link)
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
BenefitsPanel { BenefitsPanel {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.bottomMargin: 24 Layout.bottomMargin: 24
benefitsModel: ApiConfigsController.benefitsModel benefitsModel: ApiBenefitsModel
} }
ParagraphTextType { ParagraphTextType {
@@ -177,7 +147,7 @@ PageType {
var termsUrl = LanguageModel.getCurrentSiteUrl() var termsUrl = LanguageModel.getCurrentSiteUrl()
var privacyUrl = LanguageModel.getCurrentSiteUrl("policy") var privacyUrl = LanguageModel.getCurrentSiteUrl("policy")
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>") 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)) .arg(termsUrl).arg(privacyUrl).arg("#FBB26A")
} }
onLinkActivated: function(link) { onLinkActivated: function(link) {
@@ -208,7 +178,7 @@ PageType {
var termsUrl = "https://www.apple.com/legal/internet-services/itunes/dev/stdeula/" var termsUrl = "https://www.apple.com/legal/internet-services/itunes/dev/stdeula/"
var privacyUrl = LanguageModel.getCurrentSiteUrl("policy") var privacyUrl = LanguageModel.getCurrentSiteUrl("policy")
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>") 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)) .arg(termsUrl).arg(privacyUrl).arg("#FBB26A")
} }
onLinkActivated: function(link) { onLinkActivated: function(link) {
@@ -248,27 +218,24 @@ PageType {
if (!plan) { if (!plan) {
return return
} }
if (plan.isTrial) {
PageController.goToPage(PageEnum.PageSetupWizardApiTrialEmail)
return
}
if (plan.checkoutUrl) { if (plan.checkoutUrl) {
Qt.openUrlExternally(plan.checkoutUrl) Qt.openUrlExternally(plan.checkoutUrl)
PageController.closePage() PageController.closePage()
PageController.closePage() PageController.closePage()
return return
} }
if (plan.serviceType) { PageController.showBusyIndicator(true)
var idx = ApiServicesModel.serviceIndexForType(plan.serviceType) var ok = ApiConfigsController.importService()
if (idx < 0) { PageController.showBusyIndicator(false)
return if (!ok) {
} var endpoint = ApiServicesModel.getStoreEndpoint()
ApiServicesModel.setServiceIndex(idx) Qt.openUrlExternally(endpoint)
PageController.showBusyIndicator(true) PageController.closePage()
var ok = ApiConfigsController.importService() PageController.closePage()
PageController.showBusyIndicator(false)
if (!ok) {
var endpoint = ApiServicesModel.getStoreEndpoint()
Qt.openUrlExternally(endpoint)
PageController.closePage()
PageController.closePage()
}
} }
} }
} }
@@ -0,0 +1,114 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import PageEnum 1.0
import Style 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
import "../Components"
PageType {
id: root
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20 + SettingsController.safeAreaTopMargin
onFocusChanged: {
if (activeFocus) {
flick.contentY = 0
}
}
}
FlickableType {
id: flick
anchors.top: backButton.bottom
anchors.bottom: continueButton.top
anchors.left: parent.left
anchors.right: parent.right
contentHeight: scrollColumn.implicitHeight + 24
ColumnLayout {
id: scrollColumn
width: flick.width
spacing: 0
BaseHeaderType {
Layout.fillWidth: true
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 24
headerText: qsTr("Create an account")
descriptionText: qsTr("To manage your subscription")
}
TextFieldWithHeaderType {
id: emailField
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 24
headerText: qsTr("Email")
textField.placeholderText: qsTr("Email")
textField.inputMethodHints: Qt.ImhEmailCharactersOnly
}
ParagraphTextType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 24
wrapMode: Text.WordWrap
color: AmneziaStyle.color.mutedGray
font.pixelSize: 12
text: qsTr("Additional details for this step can be described here.")
}
}
}
BasicButtonType {
id: continueButton
z: 2
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.leftMargin: 16
anchors.rightMargin: 16
anchors.bottomMargin: 16 + SettingsController.safeAreaBottomMargin
text: qsTr("Continue")
clickedFunc: function() {
var raw = emailField.textField.text.trim()
if (raw.length === 0 || raw.indexOf("@") < 0) {
PageController.showNotificationMessage(qsTr("Enter a valid email address"))
return
}
PageController.showBusyIndicator(true)
var ok = ApiConfigsController.importTrialFromGateway(raw)
PageController.showBusyIndicator(false)
if (ok) {
PageController.closePage()
PageController.closePage()
}
}
}
}