mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-23 02:00:20 +07:00
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>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "../Controls2/TextTypes"
|
||||
|
||||
RowLayout {
|
||||
id: root
|
||||
|
||||
property string iconSource: ""
|
||||
property string titleText: ""
|
||||
property string bodyText: ""
|
||||
property bool accent: false
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: bodyLabel.implicitHeight
|
||||
|
||||
LabelTextType {
|
||||
id: bodyLabel
|
||||
width: parent.width
|
||||
text: root.bodyText
|
||||
color: root.accent ? AmneziaStyle.color.goldenApricot : AmneziaStyle.color.mutedGray
|
||||
font.pixelSize: 14
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: bodyLabel
|
||||
visible: root.accent && root.bodyText.length > 0
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
var t = root.bodyText.trim()
|
||||
if (t.startsWith("@")) {
|
||||
Qt.openUrlExternally("https://t.me/" + t.substring(1))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import "."
|
||||
|
||||
import Style 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property var benefitsModel: null
|
||||
|
||||
visible: benefitsModel && benefitsModel.rowCount() > 0
|
||||
|
||||
radius: 16
|
||||
color: AmneziaStyle.color.benefitsPanelBackground
|
||||
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: benefitsModel
|
||||
|
||||
delegate: BenefitRow {
|
||||
Layout.fillWidth: true
|
||||
iconSource: model.icon
|
||||
titleText: model.title
|
||||
bodyText: model.body
|
||||
accent: !!model.accent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,12 @@ ListViewType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: name
|
||||
descriptionText: serverDescription
|
||||
descriptionText: isServerFromGatewayApi && (isSubscriptionExpired || isSubscriptionExpiringSoon)
|
||||
? (isSubscriptionExpired ? qsTr("Subscription expired. Please renew.") : qsTr("Subscription expiring soon."))
|
||||
: serverDescription
|
||||
descriptionColor: isServerFromGatewayApi && (isSubscriptionExpired || isSubscriptionExpiringSoon)
|
||||
? (isSubscriptionExpired ? AmneziaStyle.color.vibrantRed : AmneziaStyle.color.goldenApricot)
|
||||
: AmneziaStyle.color.mutedGray
|
||||
|
||||
checked: index === root.selectedIndex
|
||||
checkable: !ConnectionController.isConnected
|
||||
@@ -126,18 +131,6 @@ ListViewType {
|
||||
}
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
visible: isServerFromGatewayApi && (isSubscriptionExpired || isSubscriptionExpiringSoon)
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 64
|
||||
Layout.bottomMargin: 8
|
||||
|
||||
text: isSubscriptionExpired ? qsTr("Subscription expired. Please renew.") : qsTr("Subscription expiring soon.")
|
||||
color: isSubscriptionExpired ? AmneziaStyle.color.vibrantRed : AmneziaStyle.color.goldenApricot
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
DividerType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 0
|
||||
|
||||
@@ -12,6 +12,13 @@ import "../Controls2/TextTypes"
|
||||
DrawerType2 {
|
||||
id: root
|
||||
|
||||
property bool isRenewalActionAvailable: false
|
||||
|
||||
onOpened: {
|
||||
isRenewalActionAvailable = ApiAccountInfoModel.data("isSubscriptionRenewalAvailable")
|
||||
&& !ApiAccountInfoModel.data("isInAppPurchase")
|
||||
}
|
||||
|
||||
expandedStateContent: ColumnLayout {
|
||||
id: content
|
||||
|
||||
@@ -43,6 +50,8 @@ DrawerType2 {
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
visible: root.isRenewalActionAvailable
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.rightMargin: 16
|
||||
@@ -53,6 +62,8 @@ DrawerType2 {
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
visible: root.isRenewalActionAvailable
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
@@ -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 billingPeriod: ""
|
||||
property string priceLabel: ""
|
||||
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.billingPeriod
|
||||
color: root.selected ? AmneziaStyle.color.goldenApricot : AmneziaStyle.color.paleGray
|
||||
font.pixelSize: 17
|
||||
font.weight: Font.DemiBold
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
LabelTextType {
|
||||
text: root.priceLabel
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "../Controls2/TextTypes"
|
||||
|
||||
ParagraphTextType {
|
||||
id: root
|
||||
|
||||
property string termsUrl: ""
|
||||
property string privacyUrl: ""
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
textFormat: Text.RichText
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
font.pixelSize: 12
|
||||
|
||||
text: 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(root.termsUrl)
|
||||
.arg(root.privacyUrl)
|
||||
.arg(AmneziaStyle.color.goldenApricotString)
|
||||
|
||||
onLinkActivated: function(link) {
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user