amnezia-client/client/ui/qml/main2.qml
lunardunno 059257fc58
Merge branch 'dev' into check_sudo_permissions (#1441)
* refactoring: improved the performance of secure_settings

* bugfix: fixed textFields on PageSetupWizardCredentials

* bugfix: fixed scrolling by keys on PageSettingsApiServerInfo

* chore: hide site links for ios (#1374)

* chore: fixed log output with split tunneling info

* chore: hide "open logs folder" button for mobule platforms

* chore: fixed again log output with split tunneling info

* chore: bump version

* Install apparmor (#1379)

Install apparmor

* chore: returned the backup page for androidTV

* Enable PFS for Windows IKEv2

* refactoring: moved api info pages from ServerInfo

* refactoring: moved gateway interaction functions to a separate class

* bugfix: fixed storeEndpoint parsing

* chore: returned links for mobile platforms

* Update VPN protocol descriptions

* Update VPN description texts

* feature: added pages for subscription settings feature

* feature: added page for export api native configs

* feature: added error handling and minor ui fixes

* refactor: update ios build configuration to use automatic code signing and prebuilt OpenVPNAdapter framework

* feat: remove OpenVPNAdapter submodule

* feat: remove ios openvpn script and associated cmake configuration

* Update README.md

* Update README_RU.md

* Update README.md

fix link

* feature: added share vpn key to subscription settings page

* bugfix: fixed possible crush on android

* add timeouts in ipc client init

* apply timeouts only for Windows

* apply format to file

* refactoring: simplified the validity check of the config before connection

- improved project structure

* bugfix: fixed visability of share drawer

* feature: added 409 error handling from server response

* chore: fixed android build

* chore: fixed qr code display

* Rewrite timeouts using waitForSource

* feature: added error messages handler

* feature: added issued configs info parsing

* feature: added functionality to revoke api configs

* chore: added links to instructions

* chore: fixed qr code with vpnkey processing

* chore: fixed native config post processing

* chore: added link to android tv instruction

* change node to IpcProcessTun2SocksReplica

* chore: minor ui fixes

* Update Windows OpenSSL  (#1426)

* Update Windows OpenSSL to 3.0.16 and add shared library for QSslSocket plugin

* chore: update link to submodule 3rd-prebuild

---------

Co-authored-by: vladimir.kuznetsov <nethiuswork@gmail.com>

* chore: added 404 handling for revoke configs

- added revoke before remove api server for premium v2

* chore: added log to see proxy decrypt errors

* chore: minor ui fix

* chore: bump version

* bugfix: fixed mobile controllers initialization (#1436)

* bugfix: fixed mobile controllers initialization

* chore: bump version

* Merge pull request #1440 from amnezia-vpn/feature/subscription-settings-page

feature/subscription settings page

---------

Co-authored-by: vladimir.kuznetsov <nethiuswork@gmail.com>
Co-authored-by: pokamest <pokamest@gmail.com>
Co-authored-by: Mykola Baibuz <mykola.baibuz@gmail.com>
Co-authored-by: Yaroslav Yashin <yaroslav.yashin@gmail.com>
Co-authored-by: KsZnak <ksu@amnezia.org>
Co-authored-by: Cyril Anisimov <CyAn84@gmail.com>
2025-03-01 16:08:52 +04:00

288 lines
7.6 KiB
QML

import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Dialogs
import PageEnum 1.0
import Style 1.0
import "Config"
import "Controls2"
import "Components"
import "Pages2"
Window {
id: root
objectName: "mainWindow"
visible: true
width: GC.screenWidth
height: GC.screenHeight
minimumWidth: GC.isDesktop() ? 360 : 0
minimumHeight: GC.isDesktop() ? 640 : 0
maximumWidth: 600
maximumHeight: 800
color: AmneziaStyle.color.midnightBlack
onClosing: function() {
PageController.closeWindow()
}
title: "AmneziaVPN"
Item { // This item is needed for focus handling
id: defaultFocusItem
objectName: "defaultFocusItem"
focus: true
Keys.onPressed: function(event) {
switch (event.key) {
case Qt.Key_Tab:
case Qt.Key_Down:
case Qt.Key_Right:
FocusController.nextKeyTabItem()
break
case Qt.Key_Backtab:
case Qt.Key_Up:
case Qt.Key_Left:
FocusController.previousKeyTabItem()
break
default:
PageController.keyPressEvent(event.key)
event.accepted = true
}
}
}
Connections {
objectName: "pageControllerConnections"
target: PageController
function onRaiseMainWindow() {
root.show()
root.raise()
root.requestActivate()
}
function onHideMainWindow() {
root.hide()
}
function onShowErrorMessage(errorMessage) {
popupErrorMessage.text = errorMessage
popupErrorMessage.open()
}
function onShowNotificationMessage(message) {
popupNotificationMessage.text = message
popupNotificationMessage.closeButtonVisible = false
popupNotificationMessage.open()
popupNotificationTimer.start()
}
function onShowPassphraseRequestDrawer() {
privateKeyPassphraseDrawer.openTriggered()
}
function onGoToPageSettingsBackup() {
PageController.goToPage(PageEnum.PageSettingsBackup)
}
function onShowBusyIndicator(visible) {
busyIndicator.visible = visible
PageController.disableControls(visible)
}
}
Connections {
objectName: "settingsControllerConnections"
target: SettingsController
function onChangeSettingsFinished(finishedMessage) {
PageController.showNotificationMessage(finishedMessage)
}
}
PageStart {
objectName: "pageStart"
width: root.width
height: root.height
}
Item {
objectName: "popupNotificationItem"
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
implicitHeight: popupNotificationMessage.height
PopupType {
id: popupNotificationMessage
}
Timer {
id: popupNotificationTimer
interval: 3000
repeat: false
running: false
onTriggered: {
popupNotificationMessage.close()
}
}
}
Item {
objectName: "popupErrorMessageItem"
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
implicitHeight: popupErrorMessage.height
PopupType {
id: popupErrorMessage
}
}
Item {
objectName: "privateKeyPassphraseDrawerItem"
anchors.fill: parent
DrawerType2 {
id: privateKeyPassphraseDrawer
anchors.fill: parent
expandedHeight: root.height * 0.35
expandedStateContent: ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
anchors.leftMargin: 16
anchors.rightMargin: 16
Connections {
target: privateKeyPassphraseDrawer
function onOpened() {
passphrase.textField.text = ""
passphrase.textField.forceActiveFocus()
}
function onAboutToHide() {
if (passphrase.textField.text !== "") {
PageController.showBusyIndicator(true)
}
}
function onAboutToShow() {
PageController.showBusyIndicator(false)
}
}
TextFieldWithHeaderType {
id: passphrase
property bool hidePassword: true
Layout.fillWidth: true
headerText: qsTr("Private key passphrase")
textField.echoMode: hidePassword ? TextInput.Password : TextInput.Normal
buttonImageSource: hidePassword ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
clickedFunc: function() {
hidePassword = !hidePassword
}
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.paleGray
borderWidth: 1
text: qsTr("Save")
clickedFunc: function() {
privateKeyPassphraseDrawer.closeTriggered()
PageController.passphraseRequestDrawerClosed(passphrase.textField.text)
}
}
}
}
}
Item {
objectName: "questionDrawerItem"
anchors.fill: parent
QuestionDrawer {
id: questionDrawer
anchors.fill: parent
}
}
Item {
objectName: "busyIndicatorItem"
anchors.fill: parent
BusyIndicatorType {
id: busyIndicator
anchors.centerIn: parent
z: 1
}
}
function showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) {
questionDrawer.headerText = headerText
questionDrawer.descriptionText = descriptionText
questionDrawer.yesButtonText = yesButtonText
questionDrawer.noButtonText = noButtonText
questionDrawer.yesButtonFunction = function() {
questionDrawer.closeTriggered()
if (yesButtonFunction && typeof yesButtonFunction === "function") {
yesButtonFunction()
}
}
questionDrawer.noButtonFunction = function() {
questionDrawer.closeTriggered()
if (noButtonFunction && typeof noButtonFunction === "function") {
noButtonFunction()
}
}
questionDrawer.openTriggered()
}
FileDialog {
id: mainFileDialog
objectName: "mainFileDialog"
property bool isSaveMode: false
fileMode: isSaveMode ? FileDialog.SaveFile : FileDialog.OpenFile
onAccepted: SystemController.fileDialogClosed(true)
onRejected: SystemController.fileDialogClosed(false)
}
}