feat: add new premium info page

This commit is contained in:
vkamn
2026-03-25 23:57:52 +08:00
parent ea645df7ec
commit 7da5f1c368
14 changed files with 624 additions and 51 deletions

View File

@@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 21V17C15 16.4696 15.2107 15.9609 15.5858 15.5858C15.9609 15.2107 16.4696 15 17 15H21" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7 4V6C7.21572 6.61347 7.62494 7.14024 8.16602 7.50096C8.7071 7.86168 9.35075 8.03682 10 8V8C10.5304 8 11.0391 8.21071 11.4142 8.58579C11.7893 8.96086 12 9.46957 12 10C12 10.5304 12.2107 11.0391 12.5858 11.4142C12.9609 11.7893 13.4696 12 14 12C14.5304 12 15.0391 11.7893 15.4142 11.4142C15.7893 11.0391 16 10.5304 16 10C16 9.46957 16.2107 8.96086 16.5858 8.58579C16.9609 8.21071 17.4696 8 18 8H21" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 11H5C5.53043 11 6.03914 11.2107 6.41421 11.5858C6.78929 11.9609 7 12.4696 7 13V14C7 14.5304 7.21071 15.0391 7.58579 15.4142C7.96086 15.7893 8.46957 16 9 16C9.53043 16 10.0391 16.2107 10.4142 16.5858C10.7893 16.9609 11 17.4696 11 18V22" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.1777 8C23.2737 8 23.2737 16 18.1777 16C13.0827 16 11.0447 8 5.43875 8C0.85375 8 0.85375 16 5.43875 16C11.0447 16 13.0828 8 18.1788 8H18.1777Z" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 342 B

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17 2H7C5.89543 2 5 2.89543 5 4V20C5 21.1046 5.89543 22 7 22H17C18.1046 22 19 21.1046 19 20V4C19 2.89543 18.1046 2 17 2Z" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 18H12.01" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 423 B

View File

@@ -27,10 +27,12 @@
<file>images/controls/folder-open.svg</file>
<file>images/controls/folder-search-2.svg</file>
<file>images/controls/gauge.svg</file>
<file>images/controls/globe-2.svg</file>
<file>images/controls/github.svg</file>
<file>images/controls/help-circle.svg</file>
<file>images/controls/history.svg</file>
<file>images/controls/home.svg</file>
<file>images/controls/infinity.svg</file>
<file>images/controls/info.svg</file>
<file>images/controls/mail.svg</file>
<file>images/controls/map-pin.svg</file>
@@ -55,6 +57,7 @@
<file>images/controls/settings-news.svg</file>
<file>images/controls/share-2.svg</file>
<file>images/controls/split-tunneling.svg</file>
<file>images/controls/smartphone.svg</file>
<file>images/controls/tag.svg</file>
<file>images/controls/telegram.svg</file>
<file>images/controls/text-cursor.svg</file>
@@ -133,6 +136,9 @@
<file>ui/qml/Components/HomeContainersListView.qml</file>
<file>ui/qml/Components/HomeSplitTunnelingDrawer.qml</file>
<file>ui/qml/Components/InstalledAppsDrawer.qml</file>
<file>ui/qml/Components/BenefitRow.qml</file>
<file>ui/qml/Components/BenefitsPanel.qml</file>
<file>ui/qml/Components/SubscriptionPlanCard.qml</file>
<file>ui/qml/Components/QuestionDrawer.qml</file>
<file>ui/qml/Components/SelectLanguageDrawer.qml</file>
<file>ui/qml/Components/SubscriptionExpiredDrawer.qml</file>
@@ -227,6 +233,7 @@
<file>ui/qml/Pages2/PageProtocolAwgClientSettings.qml</file>
<file>ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml</file>
<file>ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml</file>
<file>ui/qml/Pages2/PageSetupWizardApiPremium.qml</file>
<file>ui/qml/Pages2/PageSetupWizardApiServicesList.qml</file>
<file>ui/qml/Pages2/PageSetupWizardConfigSource.qml</file>
<file>ui/qml/Pages2/PageSetupWizardCredentials.qml</file>

View File

@@ -76,6 +76,8 @@ namespace PageLoader
PageShareFullAccess,
PageShareConnection,
PageSetupWizardApiPremiumInfo,
PageDevMenu
};
Q_ENUM_NS(PageEnum)

View File

@@ -1,6 +1,7 @@
#include "apiServicesModel.h"
#include <QDateTime>
#include <QJsonArray>
#include <QJsonObject>
#include "core/api/apiDefs.h"
@@ -34,6 +35,30 @@ namespace
constexpr char storeEndpoint[] = "store_endpoint";
constexpr char isAvailable[] = "is_available";
constexpr char subscriptionPlans[] = "subscription_plans";
constexpr char premiumBenefitCountriesTitle[] = "premium_benefit_countries_title";
constexpr char premiumBenefitCountriesBody[] = "premium_benefit_countries_body";
constexpr char premiumBenefitDevicesTitle[] = "premium_benefit_devices_title";
constexpr char premiumBenefitDevicesBody[] = "premium_benefit_devices_body";
constexpr char premiumBenefitVideoTitle[] = "premium_benefit_video_title";
constexpr char premiumBenefitVideoBody[] = "premium_benefit_video_body";
constexpr char premiumBenefitTrafficTitle[] = "premium_benefit_traffic_title";
constexpr char premiumBenefitTrafficBody[] = "premium_benefit_traffic_body";
}
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
@@ -124,11 +149,20 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
case OrderRole: {
if (serviceType == serviceType::amneziaPremium) {
return 0;
} else if (serviceType == serviceType::amneziaTrial) {
}
if (serviceType == serviceType::amneziaTrial) {
return 1;
} else if (serviceType == serviceType::amneziaFree) {
}
if (serviceType == serviceType::amneziaFree) {
return 2;
}
return QVariant();
}
case SubscriptionPlansRole: {
return apiServiceData.subscriptionPlans;
}
case PremiumBenefitPanelRowsRole: {
return ApiServicesModel::buildPremiumBenefitPanelRows(apiServiceData);
}
}
@@ -216,6 +250,32 @@ QVariant ApiServicesModel::getSelectedServiceData(const QString roleString)
return {};
}
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;
}
}
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;
@@ -230,6 +290,8 @@ QHash<int, QByteArray> ApiServicesModel::roleNames() const
roles[PriceRole] = "price";
roles[EndDateRole] = "endDate";
roles[OrderRole] = "order";
roles[SubscriptionPlansRole] = "subscriptionPlans";
roles[PremiumBenefitPanelRowsRole] = "premiumBenefitRows";
return roles;
}
@@ -255,6 +317,17 @@ 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.premiumBenefitCountriesTitle = serviceDescription.value(configKey::premiumBenefitCountriesTitle).toString();
serviceData.premiumBenefitCountriesBody = serviceDescription.value(configKey::premiumBenefitCountriesBody).toString();
serviceData.premiumBenefitDevicesTitle = serviceDescription.value(configKey::premiumBenefitDevicesTitle).toString();
serviceData.premiumBenefitDevicesBody = serviceDescription.value(configKey::premiumBenefitDevicesBody).toString();
serviceData.premiumBenefitVideoTitle = serviceDescription.value(configKey::premiumBenefitVideoTitle).toString();
serviceData.premiumBenefitVideoBody = serviceDescription.value(configKey::premiumBenefitVideoBody).toString();
serviceData.premiumBenefitTrafficTitle = serviceDescription.value(configKey::premiumBenefitTrafficTitle).toString();
serviceData.premiumBenefitTrafficBody = serviceDescription.value(configKey::premiumBenefitTrafficBody).toString();
serviceData.type = serviceType;
serviceData.protocol = serviceProtocol;
@@ -273,3 +346,30 @@ ApiServicesModel::ApiServicesData ApiServicesModel::getApiServicesData(const QJs
return serviceData;
}
QVariantList ApiServicesModel::buildPremiumBenefitPanelRows(const ApiServicesData &service)
{
const QStringList icons = { QStringLiteral("qrc:/images/controls/globe-2.svg"),
QStringLiteral("qrc:/images/controls/smartphone.svg"),
QStringLiteral("qrc:/images/controls/gauge.svg"),
QStringLiteral("qrc:/images/controls/infinity.svg") };
QVariantList out;
const auto appendRow = [&out, &icons](int iconIndex, const QString &title, const QString &body) {
if (title.isEmpty() && body.isEmpty()) {
return;
}
QVariantMap m;
m.insert(QStringLiteral("icon"), icons.at(iconIndex));
m.insert(QStringLiteral("title"), title);
m.insert(QStringLiteral("body"), body);
out.append(m);
};
appendRow(0, service.premiumBenefitCountriesTitle, service.premiumBenefitCountriesBody);
appendRow(1, service.premiumBenefitDevicesTitle, service.premiumBenefitDevicesBody);
appendRow(2, service.premiumBenefitVideoTitle, service.premiumBenefitVideoBody);
appendRow(3, service.premiumBenefitTrafficTitle, service.premiumBenefitTrafficBody);
return out;
}

View File

@@ -4,6 +4,7 @@
#include <QAbstractListModel>
#include <QJsonArray>
#include <QJsonObject>
#include <QVariantList>
class ApiServicesModel : public QAbstractListModel
{
@@ -21,7 +22,9 @@ public:
FeaturesRole,
PriceRole,
EndDateRole,
OrderRole
OrderRole,
SubscriptionPlansRole,
PremiumBenefitPanelRowsRole
};
explicit ApiServicesModel(QObject *parent = nullptr);
@@ -47,6 +50,9 @@ public slots:
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;
@@ -83,10 +89,22 @@ private:
Subscription subscription;
QJsonArray availableCountries;
QVariantList subscriptionPlans;
QString premiumBenefitCountriesTitle;
QString premiumBenefitCountriesBody;
QString premiumBenefitDevicesTitle;
QString premiumBenefitDevicesBody;
QString premiumBenefitVideoTitle;
QString premiumBenefitVideoBody;
QString premiumBenefitTrafficTitle;
QString premiumBenefitTrafficBody;
};
ApiServicesData getApiServicesData(const QJsonObject &data);
static QVariantList buildPremiumBenefitPanelRows(const ApiServicesData &service);
QString m_countryCode;
QVector<ApiServicesData> m_services;

View File

@@ -0,0 +1,46 @@
import QtQuick
import QtQuick.Layouts
import Style 1.0
import "../Controls2/TextTypes"
RowLayout {
id: root
property string iconSource: ""
property string titleText: ""
property string bodyText: ""
spacing: 12
Image {
Layout.alignment: Qt.AlignTop
Layout.preferredWidth: 22
Layout.preferredHeight: 22
source: root.iconSource
fillMode: Image.PreserveAspectFit
}
ColumnLayout {
Layout.fillWidth: true
spacing: 4
LabelTextType {
Layout.fillWidth: true
text: root.titleText
color: AmneziaStyle.color.paleGray
font.pixelSize: 16
font.weight: Font.DemiBold
wrapMode: Text.Wrap
}
LabelTextType {
Layout.fillWidth: true
text: root.bodyText
color: AmneziaStyle.color.mutedGray
font.pixelSize: 14
wrapMode: Text.Wrap
}
}
}

View File

@@ -0,0 +1,37 @@
import QtQuick
import QtQuick.Layouts
import "."
import Style 1.0
Rectangle {
id: root
property var benefitItems: []
radius: 16
color: "#1C1C1E"
implicitHeight: inner.implicitHeight + 24
ColumnLayout {
id: inner
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: 12
spacing: 20
Repeater {
model: root.benefitItems ? root.benefitItems.length : 0
delegate: BenefitRow {
Layout.fillWidth: true
iconSource: root.benefitItems[index].icon
titleText: root.benefitItems[index].title
bodyText: root.benefitItems[index].body
}
}
}
}

View File

@@ -0,0 +1,94 @@
import QtQuick
import QtQuick.Layouts
import Style 1.0
import "../Controls2/TextTypes"
Rectangle {
id: root
property bool selected: false
property string primaryLeft: ""
property string primaryRight: ""
property string subtitle: ""
property bool showRecommendedBadge: false
property string recommendedText: "Recommended"
signal selectRequested
implicitHeight: cardLayout.implicitHeight + 28
radius: 16
color: AmneziaStyle.color.transparent
border.width: selected ? 2 : 1
border.color: selected ? AmneziaStyle.color.goldenApricot : AmneziaStyle.color.charcoalGray
ColumnLayout {
id: cardLayout
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 8
RowLayout {
Layout.fillWidth: true
LabelTextType {
Layout.fillWidth: true
text: root.primaryLeft
color: root.selected ? AmneziaStyle.color.goldenApricot : AmneziaStyle.color.paleGray
font.pixelSize: 17
font.weight: Font.DemiBold
wrapMode: Text.Wrap
}
LabelTextType {
text: root.primaryRight
color: root.selected ? AmneziaStyle.color.goldenApricot : AmneziaStyle.color.paleGray
font.pixelSize: 17
font.weight: Font.DemiBold
}
}
RowLayout {
Layout.fillWidth: true
visible: root.subtitle.length > 0 || root.showRecommendedBadge
LabelTextType {
Layout.fillWidth: true
text: root.subtitle
color: AmneziaStyle.color.mutedGray
font.pixelSize: 13
wrapMode: Text.Wrap
}
Rectangle {
visible: root.showRecommendedBadge
Layout.alignment: Qt.AlignVCenter
radius: 10
color: AmneziaStyle.color.softViolet
implicitHeight: recLabel.implicitHeight + 8
implicitWidth: recLabel.implicitWidth + 16
LabelTextType {
id: recLabel
anchors.centerIn: parent
text: root.recommendedText
color: AmneziaStyle.color.midnightBlack
font.pixelSize: 11
font.weight: Font.Medium
}
}
}
}
MouseArea {
anchors.fill: parent
onClicked: root.selectRequested()
}
}

View File

@@ -13,6 +13,7 @@ QtObject {
readonly property color onyxBlack: '#1C1D21'
readonly property color midnightBlack: '#0E0E11'
readonly property color goldenApricot: '#FBB26A'
readonly property color softViolet: '#A87BE2'
readonly property color burntOrange: '#A85809'
readonly property color mutedBrown: '#84603D'
readonly property color richBrown: '#633303'

View File

@@ -0,0 +1,297 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Style 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
import "../Components"
PageType {
id: root
// ApiServicesModel selection is amnezia-premium (set in PageSetupWizardApiServicesList before navigation).
property var subscriptionPlans: []
property var benefitRows: []
property int selectedGatewayPlanIndex: 0
property string premiumFeaturesHtml: ""
property string premiumHeaderName: ""
property string premiumHeaderDescription: ""
readonly property var currentGatewayPlan: subscriptionPlans[selectedGatewayPlanIndex]
function syncFromModel() {
root.subscriptionPlans = ApiServicesModel.getSelectedServiceData("subscriptionPlans")
root.benefitRows = ApiServicesModel.getSelectedServiceData("premiumBenefitRows")
root.selectedGatewayPlanIndex = 0
for (var i = 0; i < root.subscriptionPlans.length; ++i) {
if (root.subscriptionPlans[i].recommended) {
root.selectedGatewayPlanIndex = i
break
}
}
root.premiumFeaturesHtml = String(ApiServicesModel.getSelectedServiceData("features")).replace("%1",
LanguageModel.getCurrentSiteUrl("free")).replace("/free", "")
root.premiumHeaderName = String(ApiServicesModel.getSelectedServiceData("name"))
root.premiumHeaderDescription = String(ApiServicesModel.getSelectedServiceData("serviceDescription"))
}
Component.onCompleted: syncFromModel()
Connections {
target: ApiServicesModel
function onModelReset() {
root.syncFromModel()
}
}
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: root.premiumHeaderName
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 {
model: subscriptionPlans.length
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
selected: root.selectedGatewayPlanIndex === index
primaryLeft: String(plan.primary_left)
primaryRight: String(plan.primary_right)
subtitle: String(plan.subtitle)
showRecommendedBadge: !!plan.recommended
recommendedText: qsTr("Recommended")
onSelectRequested: root.selectedGatewayPlanIndex = index
}
}
LabelTextType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 12
text: qsTr("Premium features")
color: AmneziaStyle.color.mutedGray
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 {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 24
benefitItems: root.benefitRows
}
ParagraphTextType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 16
visible: (Qt.platform.os === "ios" || IsMacOsNeBuild)
horizontalAlignment: Text.AlignHCenter
textFormat: Text.PlainText
color: AmneziaStyle.color.mutedGray
font.pixelSize: 12
text: qsTr("Charged to your Apple ID at confirmation. Renews automatically unless auto-renew is turned off at least 24 hours before period end. Manage in Apple ID settings.")
}
ParagraphTextType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 16
visible: !(Qt.platform.os === "ios" || IsMacOsNeBuild)
horizontalAlignment: Text.AlignHCenter
textFormat: Text.RichText
color: AmneziaStyle.color.mutedGray
font.pixelSize: 12
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)
}
onLinkActivated: function(link) {
Qt.openUrlExternally(link)
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
ParagraphTextType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 24
visible: (Qt.platform.os === "ios" || IsMacOsNeBuild)
horizontalAlignment: Text.AlignHCenter
textFormat: Text.RichText
color: AmneziaStyle.color.mutedGray
font.pixelSize: 12
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)
}
onLinkActivated: function(link) {
Qt.openUrlExternally(link)
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
}
}
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: {
var plan = root.currentGatewayPlan
if (!plan) {
return qsTr("Continue")
}
return qsTr("Subscribe — %1 for %2").arg(String(plan.primary_left)).arg(String(plan.primary_right))
}
clickedFunc: function() {
var plan = root.currentGatewayPlan
if (!plan) {
return
}
if (plan.checkout_url) {
Qt.openUrlExternally(plan.checkout_url)
PageController.closePage()
PageController.closePage()
return
}
if (plan.service_type) {
var idx = ApiServicesModel.serviceIndexForType(plan.service_type)
if (idx < 0) {
return
}
ApiServicesModel.setServiceIndex(idx)
PageController.showBusyIndicator(true)
var ok = ApiConfigsController.importService()
PageController.showBusyIndicator(false)
if (!ok) {
var endpoint = ApiServicesModel.getStoreEndpoint()
Qt.openUrlExternally(endpoint)
PageController.closePage()
PageController.closePage()
}
}
}
}
}

View File

@@ -97,22 +97,6 @@ PageType {
}
}
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: (Qt.platform.os === "ios" || IsMacOsNeBuild) && ApiServicesModel.getSelectedServiceType() === "amnezia-premium"
horizontalAlignment: Text.AlignHCenter
textFormat: Text.PlainText
color: AmneziaStyle.color.mutedGray
font.pixelSize: 12
text: qsTr("Charged to your Apple ID at confirmation. Renews automatically unless auto-renew is turned off at least 24 hours before period end. Manage in Apple ID settings.")
}
BasicButtonType {
id: continueButton
@@ -122,7 +106,7 @@ PageType {
Layout.leftMargin: 16
Layout.rightMargin: 16
text: ApiServicesModel.getSelectedServiceType() === "amnezia-premium" ? qsTr("Subscribe Now") : (ApiServicesModel.getSelectedServiceType() === "amnezia-trial" ? qsTr("Try Trial") : qsTr("Connect"))
text: ApiServicesModel.getSelectedServiceType() === "amnezia-trial" ? qsTr("Try Trial") : qsTr("Connect")
clickedFunc: function() {
PageController.showBusyIndicator(true)
@@ -138,36 +122,6 @@ PageType {
}
}
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 32
visible: (Qt.platform.os === "ios" || IsMacOsNeBuild) && ApiServicesModel.getSelectedServiceType() === "amnezia-premium"
horizontalAlignment: Text.AlignHCenter
textFormat: Text.RichText
color: AmneziaStyle.color.mutedGray
font.pixelSize: 12
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)
}
onLinkActivated: function(link) {
Qt.openUrlExternally(link)
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
}
}

View File

@@ -89,7 +89,11 @@ PageType {
onClicked: {
if (isServiceAvailable) {
ApiServicesModel.setServiceIndex(proxyApiServicesModel.mapToSource(index))
PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
if (ApiServicesModel.getSelectedServiceType() === "amnezia-premium") {
PageController.goToPage(PageEnum.PageSetupWizardApiPremiumInfo)
} else {
PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
}
}
}