Files
DefaultVPN/client/ui/qml/Pages2/PageSettingsApiAvailableCountries.qml
vkamn 78f504e35c feat: new services description (#2412)
* feat: iap for apple now use storekit2

* fix: fixed error 101 on connection event

* feat: enhance StoreKit2Helper to handle entitlements and improve restore service from App Store functionality

* chore: add isInAppPurchase and isTestPurchase in primary config

* refactor: use end_date from primary config for renew ui

* fix: hide renew button for free

* fix: hide renew button for appstore purchases

* feat: add new premium info page

* feat: add new free info page

* chore: minor fixes

* refactor: move plan and benefits into separate models

* fix: fixed expired status when configs without an end date

* feat: add trial api support

* chore: add api message parsing for 422 error

* feat: move privacy policy and term of use to gateway

* feat: add iap support for new premium info page

* chore: minor fixes

* chore: minor fix

* chore: minor fixes

* feat: additional parsing for storekit subscription plans

* chore: minor codestyle fixes

* chore: simplify benefits

* chore: hide extend buttons on external premium

* feat: add trial error processing

* fix: remove wrong check from tiral handler

* chore: cleanup

---------

Co-authored-by: spectrum <yyy@amnezia.org>
2026-04-08 12:21:12 +08:00

238 lines
7.4 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Dialogs
import SortFilterProxyModel 0.2
import PageEnum 1.0
import Style 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
import "../Components"
PageType {
id: root
property var processedServer
property bool subscriptionExpired: false
property bool subscriptionExpiringSoon: false
property bool isSubscriptionRenewalAvailable: false
property bool isInAppPurchase: false
function updateSubscriptionState() {
root.subscriptionExpired = ServersModel.getProcessedServerData("isSubscriptionExpired")
root.subscriptionExpiringSoon = ServersModel.getProcessedServerData("isSubscriptionExpiringSoon")
root.isSubscriptionRenewalAvailable = ApiAccountInfoModel.data("isSubscriptionRenewalAvailable")
root.isInAppPurchase = ApiAccountInfoModel.data("isInAppPurchase")
}
Component.onCompleted: {
root.updateSubscriptionState()
}
Connections {
target: ServersModel
function onProcessedServerChanged() {
root.processedServer = proxyServersModel.get(0)
root.updateSubscriptionState()
}
}
Connections {
target: ApiAccountInfoModel
function onModelReset() {
root.updateSubscriptionState()
}
}
SortFilterProxyModel {
id: proxyServersModel
objectName: "proxyServersModel"
sourceModel: ServersModel
filters: [
ValueFilter {
roleName: "isCurrentlyProcessed"
value: true
}
]
Component.onCompleted: {
root.processedServer = proxyServersModel.get(0)
}
}
ListViewType {
id: menuContent
anchors.fill: parent
model: ApiCountryModel
currentIndex: 0
ButtonGroup {
id: containersRadioButtonGroup
}
header: ColumnLayout {
width: menuContent.width
spacing: 4
BackButtonType {
id: backButton
objectName: "backButton"
Layout.topMargin: 20 + SettingsController.safeAreaTopMargin
}
HeaderTypeWithButton {
id: headerContent
objectName: "headerContent"
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: root.subscriptionExpired || root.subscriptionExpiringSoon ? 0 : 4
actionButtonImage: "qrc:/images/controls/settings.svg"
headerText: root.processedServer.name
actionButtonFunction: function() {
PageController.showBusyIndicator(true)
let result = ApiSettingsController.getAccountInfo(false)
PageController.showBusyIndicator(false)
if (!result) {
return
}
PageController.goToPage(PageEnum.PageSettingsApiServerInfo)
}
}
ParagraphTextType {
visible: root.subscriptionExpired || root.subscriptionExpiringSoon
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.topMargin: 12
text: root.subscriptionExpired ? qsTr("Subscription expired") : qsTr("Subscription expiring soon")
color: root.subscriptionExpired ? AmneziaStyle.color.vibrantRed : AmneziaStyle.color.goldenApricot
}
BasicButtonType {
visible: (root.subscriptionExpired || root.subscriptionExpiringSoon)
&& root.isSubscriptionRenewalAvailable && !root.isInAppPurchase
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.topMargin: 28
Layout.bottomMargin: 0
defaultColor: AmneziaStyle.color.paleGray
hoveredColor: AmneziaStyle.color.lightGray
pressedColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.midnightBlack
text: qsTr("Renew subscription")
clickedFunc: function() {
ApiSettingsController.getRenewalLink()
}
}
ParagraphTextType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.topMargin: (root.subscriptionExpired || root.subscriptionExpiringSoon) ? 12 : 4
Layout.bottomMargin: 8
text: qsTr("Location for connection")
color: AmneziaStyle.color.mutedGray
}
}
delegate: ColumnLayout {
id: content
width: menuContent.width
height: content.implicitHeight
RowLayout {
VerticalRadioButton {
id: containerRadioButton
Layout.fillWidth: true
Layout.leftMargin: 16
text: countryName
ButtonGroup.group: containersRadioButtonGroup
imageSource: "qrc:/images/controls/download.svg"
checked: index === ApiCountryModel.currentIndex
checkable: !ConnectionController.isConnected
onClicked: {
if (ConnectionController.isConnectionInProgress) {
PageController.showNotificationMessage(qsTr("Unable change server location while trying to make an active connection"))
return
}
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Unable change server location while there is an active connection"))
return
}
if (index !== ApiCountryModel.currentIndex) {
PageController.showBusyIndicator(true)
var prevIndex = ApiCountryModel.currentIndex
ApiCountryModel.currentIndex = index
if (!ApiConfigsController.updateServiceFromGateway(ServersModel.defaultIndex, countryCode, countryName)) {
ApiCountryModel.currentIndex = prevIndex
}
PageController.showBusyIndicator(false)
}
}
Keys.onEnterPressed: {
if (checkable) {
checked = true
}
containerRadioButton.clicked()
}
Keys.onReturnPressed: {
if (checkable) {
checked = true
}
containerRadioButton.clicked()
}
}
Image {
Layout.rightMargin: 32
Layout.alignment: Qt.AlignRight
source: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg"
}
}
DividerType {
Layout.fillWidth: true
}
}
}
}