mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-08 14:33:23 +00:00
* fix: prevent disabled SwitcherType from toggling via keyboard * fix: disabled vless option toggle while connection is active
531 lines
18 KiB
QML
531 lines
18 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 list<QtObject> labelsModel: [
|
||
statusObject,
|
||
endDateObject,
|
||
deviceCountObject
|
||
]
|
||
|
||
QtObject {
|
||
id: statusObject
|
||
|
||
readonly property string title: qsTr("Subscription Status")
|
||
readonly property string contentKey: "subscriptionStatus"
|
||
readonly property string objectImageSource: "qrc:/images/controls/info.svg"
|
||
readonly property bool isRichText: true
|
||
}
|
||
|
||
QtObject {
|
||
id: endDateObject
|
||
|
||
readonly property string title: qsTr("Valid Until")
|
||
readonly property string contentKey: "endDate"
|
||
readonly property string objectImageSource: "qrc:/images/controls/history.svg"
|
||
readonly property bool isRichText: false
|
||
}
|
||
|
||
QtObject {
|
||
id: deviceCountObject
|
||
|
||
readonly property string title: qsTr("Active Connections")
|
||
readonly property string contentKey: "connectedDevices"
|
||
readonly property string objectImageSource: "qrc:/images/controls/monitor.svg"
|
||
readonly property bool isRichText: false
|
||
}
|
||
|
||
property var processedServer
|
||
|
||
property bool isSubscriptionExpired: false
|
||
property bool isSubscriptionExpiringSoon: false
|
||
property bool isSubscriptionRenewalAvailable: false
|
||
property bool isInAppPurchase: false
|
||
|
||
function updateSubscriptionState() {
|
||
root.isSubscriptionExpired = ApiAccountInfoModel.data("isSubscriptionExpired")
|
||
root.isSubscriptionExpiringSoon = ApiAccountInfoModel.data("isSubscriptionExpiringSoon")
|
||
root.isSubscriptionRenewalAvailable = ApiAccountInfoModel.data("isSubscriptionRenewalAvailable")
|
||
root.isInAppPurchase = ApiAccountInfoModel.data("isInAppPurchase")
|
||
}
|
||
|
||
Component.onCompleted: {
|
||
root.updateSubscriptionState()
|
||
}
|
||
|
||
Connections {
|
||
target: ApiAccountInfoModel
|
||
|
||
function onModelReset() {
|
||
root.updateSubscriptionState()
|
||
}
|
||
}
|
||
|
||
Connections {
|
||
target: ServersModel
|
||
|
||
function onProcessedServerChanged() {
|
||
root.processedServer = proxyServersModel.get(0)
|
||
}
|
||
}
|
||
|
||
SortFilterProxyModel {
|
||
id: proxyServersModel
|
||
objectName: "proxyServersModel"
|
||
|
||
sourceModel: ServersModel
|
||
filters: [
|
||
ValueFilter {
|
||
roleName: "isCurrentlyProcessed"
|
||
value: true
|
||
}
|
||
]
|
||
|
||
Component.onCompleted: {
|
||
root.processedServer = proxyServersModel.get(0)
|
||
}
|
||
}
|
||
|
||
ListViewType {
|
||
id: listView
|
||
|
||
anchors.fill: parent
|
||
|
||
model: labelsModel
|
||
|
||
header: ColumnLayout {
|
||
width: listView.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.isSubscriptionExpired || root.isSubscriptionExpiringSoon ? 0 : 10
|
||
|
||
actionButtonImage: "qrc:/images/controls/edit-3.svg"
|
||
|
||
headerText: root.processedServer.name
|
||
|
||
actionButtonFunction: function() {
|
||
serverNameEditDrawer.openTriggered()
|
||
}
|
||
}
|
||
|
||
ParagraphTextType {
|
||
visible: root.isSubscriptionExpired || root.isSubscriptionExpiringSoon
|
||
|
||
Layout.fillWidth: true
|
||
Layout.leftMargin: 16
|
||
Layout.rightMargin: 16
|
||
Layout.topMargin: 12
|
||
|
||
text: root.isSubscriptionExpired
|
||
? qsTr("Subscription expired")
|
||
: qsTr("Subscription expiring soon")
|
||
|
||
color: root.isSubscriptionExpired
|
||
? AmneziaStyle.color.vibrantRed
|
||
: AmneziaStyle.color.goldenApricot
|
||
}
|
||
|
||
ParagraphTextType {
|
||
visible: ApiAccountInfoModel.data("serviceDescription") !== ""
|
||
|
||
Layout.fillWidth: true
|
||
Layout.leftMargin: 16
|
||
Layout.rightMargin: 16
|
||
Layout.topMargin: 16
|
||
Layout.bottomMargin: root.isSubscriptionExpired || root.isSubscriptionExpiringSoon ? 0 : 10
|
||
|
||
text: ApiAccountInfoModel.data("serviceDescription")
|
||
color: AmneziaStyle.color.mutedGray
|
||
}
|
||
|
||
BasicButtonType {
|
||
visible: (root.isSubscriptionExpired || root.isSubscriptionExpiringSoon)
|
||
&& root.isSubscriptionRenewalAvailable && !root.isInAppPurchase
|
||
|
||
Layout.fillWidth: true
|
||
Layout.leftMargin: 16
|
||
Layout.rightMargin: 16
|
||
Layout.topMargin: 8
|
||
Layout.bottomMargin: 8
|
||
|
||
text: qsTr("Renew subscription")
|
||
|
||
defaultColor: AmneziaStyle.color.paleGray
|
||
hoveredColor: AmneziaStyle.color.lightGray
|
||
pressedColor: AmneziaStyle.color.mutedGray
|
||
textColor: AmneziaStyle.color.midnightBlack
|
||
|
||
clickedFunc: function() {
|
||
ApiSettingsController.getRenewalLink()
|
||
}
|
||
}
|
||
}
|
||
|
||
delegate: ColumnLayout {
|
||
width: listView.width
|
||
spacing: 0
|
||
|
||
Connections {
|
||
target: ApiAccountInfoModel
|
||
|
||
function onModelReset() {
|
||
delegateItem.rightText = ApiAccountInfoModel.data(contentKey)
|
||
}
|
||
}
|
||
|
||
LabelWithImageType {
|
||
id: delegateItem
|
||
|
||
Layout.fillWidth: true
|
||
Layout.margins: 16
|
||
|
||
imageSource: objectImageSource
|
||
leftText: title
|
||
rightText: ApiAccountInfoModel.data(contentKey)
|
||
rightTextFormat: isRichText ? Text.RichText : Text.PlainText
|
||
|
||
visible: rightText !== ""
|
||
}
|
||
}
|
||
|
||
footer: ColumnLayout {
|
||
id: footer
|
||
|
||
width: listView.width
|
||
spacing: 0
|
||
|
||
readonly property bool isVisibleForAmneziaFree: ApiAccountInfoModel.data("isComponentVisible")
|
||
|
||
BasicButtonType {
|
||
visible: !root.isSubscriptionExpired && !root.isSubscriptionExpiringSoon
|
||
&& root.isSubscriptionRenewalAvailable && !root.isInAppPurchase
|
||
|
||
Layout.alignment: Qt.AlignHCenter
|
||
Layout.topMargin: 16
|
||
Layout.bottomMargin: 16
|
||
|
||
implicitHeight: 25
|
||
|
||
defaultColor: AmneziaStyle.color.transparent
|
||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||
pressedColor: AmneziaStyle.color.sheerWhite
|
||
textColor: AmneziaStyle.color.goldenApricot
|
||
leftImageSource: "qrc:/images/controls/refresh-cw.svg"
|
||
leftImageColor: AmneziaStyle.color.goldenApricot
|
||
|
||
text: qsTr("Renew subscription")
|
||
|
||
clickedFunc: function() {
|
||
ApiSettingsController.getRenewalLink()
|
||
}
|
||
}
|
||
|
||
DividerType {
|
||
visible: !root.isSubscriptionExpired && !root.isSubscriptionExpiringSoon
|
||
&& root.isSubscriptionRenewalAvailable && !root.isInAppPurchase
|
||
}
|
||
|
||
SwitcherType {
|
||
id: switcher
|
||
|
||
readonly property bool isVlessProtocol: ApiConfigsController.isVlessProtocol()
|
||
readonly property bool isProtocolSwitchBlocked: ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
|
||
|
||
Layout.fillWidth: true
|
||
Layout.topMargin: 24
|
||
Layout.rightMargin: 16
|
||
Layout.leftMargin: 16
|
||
|
||
visible: ApiAccountInfoModel.data("isProtocolSelectionSupported")
|
||
enabled: !switcher.isProtocolSwitchBlocked
|
||
|
||
text: qsTr("Use VLESS protocol")
|
||
checked: switcher.isVlessProtocol
|
||
onToggled: function() {
|
||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||
PageController.showNotificationMessage(qsTr("Cannot change protocol during active connection"))
|
||
} else {
|
||
PageController.showBusyIndicator(true)
|
||
ApiConfigsController.setCurrentProtocol(switcher.isVlessProtocol ? "awg" : "vless")
|
||
ApiConfigsController.updateServiceFromGateway(ServersModel.processedIndex, "", "", true)
|
||
PageController.showBusyIndicator(false)
|
||
}
|
||
}
|
||
}
|
||
|
||
DividerType {
|
||
visible: footer.isVisibleForAmneziaFree
|
||
}
|
||
|
||
WarningType {
|
||
id: warning
|
||
|
||
Layout.topMargin: 24
|
||
Layout.rightMargin: 16
|
||
Layout.leftMargin: 16
|
||
Layout.fillWidth: true
|
||
|
||
backGroundColor: AmneziaStyle.color.translucentRichBrown
|
||
|
||
textString: qsTr("Configurations have been updated for some countries. Download and install the updated configuration files")
|
||
|
||
iconPath: "qrc:/images/controls/alert-circle.svg"
|
||
|
||
visible: {
|
||
for (let i = 0; i < ApiCountryModel.count; ++i) {
|
||
if (ApiCountryModel.get(i).isWorkerExpired)
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
|
||
LabelWithButtonType {
|
||
id: vpnKey
|
||
|
||
Layout.fillWidth: true
|
||
Layout.topMargin: warning.visible ? 16 : 0
|
||
|
||
visible: footer.isVisibleForAmneziaFree
|
||
|
||
text: qsTr("Subscription Key")
|
||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||
|
||
clickedFunction: function() {
|
||
PageController.goToPage(PageEnum.PageSettingsApiSubscriptionKey)
|
||
PageController.showBusyIndicator(true)
|
||
|
||
ApiConfigsController.prepareVpnKeyExport()
|
||
|
||
PageController.showBusyIndicator(false)
|
||
}
|
||
}
|
||
|
||
DividerType {
|
||
visible: footer.isVisibleForAmneziaFree
|
||
}
|
||
|
||
LabelWithButtonType {
|
||
Layout.fillWidth: true
|
||
|
||
visible: footer.isVisibleForAmneziaFree
|
||
|
||
text: qsTr("Configuration Files")
|
||
|
||
descriptionText: qsTr("Manage configuration files")
|
||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||
|
||
clickedFunction: function() {
|
||
ApiSettingsController.updateApiCountryModel()
|
||
PageController.goToPage(PageEnum.PageSettingsApiNativeConfigs)
|
||
}
|
||
}
|
||
|
||
DividerType {
|
||
visible: footer.isVisibleForAmneziaFree
|
||
}
|
||
|
||
LabelWithButtonType {
|
||
Layout.fillWidth: true
|
||
|
||
visible: footer.isVisibleForAmneziaFree
|
||
|
||
text: qsTr("Active Devices")
|
||
|
||
descriptionText: qsTr("Manage currently connected devices")
|
||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||
|
||
clickedFunction: function() {
|
||
ApiSettingsController.updateApiDevicesModel()
|
||
PageController.goToPage(PageEnum.PageSettingsApiDevices)
|
||
}
|
||
}
|
||
|
||
DividerType {
|
||
visible: footer.isVisibleForAmneziaFree
|
||
}
|
||
|
||
LabelWithButtonType {
|
||
Layout.fillWidth: true
|
||
Layout.topMargin: footer.isVisibleForAmneziaFree ? 0 : 32
|
||
|
||
text: qsTr("Support")
|
||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||
|
||
clickedFunction: function() {
|
||
PageController.goToPage(PageEnum.PageSettingsApiSupport)
|
||
}
|
||
}
|
||
|
||
DividerType {}
|
||
|
||
LabelWithButtonType {
|
||
Layout.fillWidth: true
|
||
|
||
visible: footer.isVisibleForAmneziaFree
|
||
|
||
text: qsTr("How to connect on another device")
|
||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||
|
||
clickedFunction: function() {
|
||
PageController.goToPage(PageEnum.PageSettingsApiInstructions)
|
||
}
|
||
}
|
||
|
||
DividerType {
|
||
visible: footer.isVisibleForAmneziaFree
|
||
}
|
||
|
||
BasicButtonType {
|
||
id: resetButton
|
||
Layout.alignment: Qt.AlignHCenter
|
||
Layout.topMargin: 24
|
||
Layout.bottomMargin: 16
|
||
Layout.leftMargin: 8
|
||
implicitHeight: 32
|
||
|
||
defaultColor: "transparent"
|
||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||
pressedColor: AmneziaStyle.color.sheerWhite
|
||
textColor: AmneziaStyle.color.vibrantRed
|
||
|
||
text: qsTr("Reload API config")
|
||
|
||
clickedFunc: function() {
|
||
var headerText = qsTr("Reload API config?")
|
||
var yesButtonText = qsTr("Continue")
|
||
var noButtonText = qsTr("Cancel")
|
||
|
||
var yesButtonFunction = function() {
|
||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||
PageController.showNotificationMessage(qsTr("Cannot reload API config during active connection"))
|
||
} else {
|
||
PageController.showBusyIndicator(true)
|
||
ApiConfigsController.updateServiceFromGateway(ServersModel.processedIndex, "", "", true)
|
||
PageController.showBusyIndicator(false)
|
||
}
|
||
}
|
||
var noButtonFunction = function() {
|
||
}
|
||
|
||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||
}
|
||
}
|
||
|
||
BasicButtonType {
|
||
id: revokeButton
|
||
Layout.alignment: Qt.AlignHCenter
|
||
Layout.bottomMargin: 16
|
||
Layout.leftMargin: 8
|
||
implicitHeight: 32
|
||
|
||
visible: footer.isVisibleForAmneziaFree
|
||
|
||
defaultColor: "transparent"
|
||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||
pressedColor: AmneziaStyle.color.sheerWhite
|
||
textColor: AmneziaStyle.color.vibrantRed
|
||
|
||
text: qsTr("Unlink this device")
|
||
|
||
clickedFunc: function() {
|
||
var headerText = qsTr("Are you sure you want to unlink this device?")
|
||
var descriptionText = qsTr("This will unlink the device from your subscription. You can reconnect it anytime by pressing \"Reload API config\" in subscription settings on device.")
|
||
var yesButtonText = qsTr("Continue")
|
||
var noButtonText = qsTr("Cancel")
|
||
|
||
var yesButtonFunction = function() {
|
||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||
PageController.showNotificationMessage(qsTr("Cannot unlink device during active connection"))
|
||
} else {
|
||
PageController.showBusyIndicator(true)
|
||
if (ApiConfigsController.deactivateDevice(false)) {
|
||
ApiSettingsController.getAccountInfo(true)
|
||
}
|
||
PageController.showBusyIndicator(false)
|
||
}
|
||
}
|
||
var noButtonFunction = function() {
|
||
}
|
||
|
||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||
}
|
||
}
|
||
|
||
BasicButtonType {
|
||
id: removeButton
|
||
Layout.alignment: Qt.AlignHCenter
|
||
Layout.bottomMargin: 16
|
||
Layout.leftMargin: 8
|
||
implicitHeight: 32
|
||
|
||
defaultColor: "transparent"
|
||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||
pressedColor: AmneziaStyle.color.sheerWhite
|
||
textColor: AmneziaStyle.color.vibrantRed
|
||
|
||
text: qsTr("Remove from application")
|
||
|
||
clickedFunc: function() {
|
||
var headerText = qsTr("Remove from application?")
|
||
var yesButtonText = qsTr("Continue")
|
||
var noButtonText = qsTr("Cancel")
|
||
|
||
var yesButtonFunction = function() {
|
||
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
|
||
PageController.showNotificationMessage(qsTr("Cannot remove server during active connection"))
|
||
} else {
|
||
PageController.showBusyIndicator(true)
|
||
InstallController.removeProcessedServer()
|
||
PageController.showBusyIndicator(false)
|
||
}
|
||
}
|
||
var noButtonFunction = function() {
|
||
}
|
||
|
||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
RenameServerDrawer {
|
||
id: serverNameEditDrawer
|
||
|
||
anchors.fill: parent
|
||
expandedHeight: parent.height * 0.35
|
||
|
||
serverNameText: root.processedServer.name
|
||
}
|
||
}
|