Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into HEAD

This commit is contained in:
vladimir.kuznetsov 2025-01-02 13:43:31 +07:00
commit af0fe754fc
114 changed files with 4051 additions and 3700 deletions

View file

@ -16,6 +16,32 @@ Button {
property string connectedButtonColor: AmneziaStyle.color.goldenApricot
property bool buttonActiveFocus: activeFocus && (Qt.platform.os !== "android" || SettingsController.isOnTv())
property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
implicitWidth: 190
implicitHeight: 190

View file

@ -14,7 +14,7 @@ DrawerType2 {
width: parent.width
height: parent.height
expandedContent: ColumnLayout {
expandedStateContent: ColumnLayout {
id: content
anchors.top: parent.top
@ -26,14 +26,6 @@ DrawerType2 {
root.expandedHeight = content.implicitHeight + 32
}
Connections {
target: root
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 24
@ -44,11 +36,6 @@ DrawerType2 {
headerText: qsTr("Add new connection")
}
Item {
id: focusItem
KeyNavigation.tab: ip.rightButton
}
LabelWithButtonType {
id: ip
Layout.fillWidth: true
@ -59,10 +46,8 @@ DrawerType2 {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardCredentials)
root.close()
root.closeTriggered()
}
KeyNavigation.tab: qrCode.rightButton
}
DividerType {}
@ -76,10 +61,8 @@ DrawerType2 {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
root.close()
root.closeTriggered()
}
KeyNavigation.tab: focusItem
}
DividerType {}

View file

@ -17,55 +17,15 @@ ListView {
property var rootWidth
property var selectedText
property bool a: true
width: rootWidth
height: menuContent.contentItem.height
height: contentItem.height
clip: true
interactive: false
snapMode: ListView.SnapToItem
property FlickableType parentFlickable
property var lastItemTabClicked
ScrollBar.vertical: ScrollBarType {}
property int currentFocusIndex: 0
activeFocusOnTab: true
onActiveFocusChanged: {
if (activeFocus) {
this.currentFocusIndex = 0
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
}
}
Keys.onTabPressed: {
if (currentFocusIndex < this.count - 1) {
currentFocusIndex += 1
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
} else {
currentFocusIndex = 0
if (lastItemTabClicked && typeof lastItemTabClicked === "function") {
lastItemTabClicked()
}
}
}
onVisibleChanged: {
if (visible) {
currentFocusIndex = 0
focusItem.forceActiveFocus()
}
}
Item {
id: focusItem
}
onCurrentFocusIndexChanged: {
if (parentFlickable) {
parentFlickable.ensureVisible(this.itemAtIndex(currentFocusIndex))
}
}
property bool isFocusable: true
ButtonGroup {
id: containersRadioButtonGroup
@ -75,12 +35,6 @@ ListView {
implicitWidth: rootWidth
implicitHeight: content.implicitHeight
onActiveFocusChanged: {
if (activeFocus) {
containerRadioButton.forceActiveFocus()
}
}
ColumnLayout {
id: content
@ -111,13 +65,13 @@ ListView {
}
if (checked) {
containersDropDown.close()
containersDropDown.closeTriggered()
ServersModel.setDefaultContainer(ServersModel.defaultIndex, proxyDefaultServerContainersModel.mapToSource(index))
} else {
ContainersModel.setProcessedContainerIndex(proxyDefaultServerContainersModel.mapToSource(index))
InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
containersDropDown.close()
containersDropDown.closeTriggered()
}
}

View file

@ -16,7 +16,7 @@ DrawerType2 {
anchors.fill: parent
expandedHeight: parent.height * 0.9
expandedContent: ColumnLayout {
expandedStateContent: ColumnLayout {
id: content
anchors.top: parent.top
@ -24,14 +24,6 @@ DrawerType2 {
anchors.right: parent.right
spacing: 0
Connections {
target: root
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 24
@ -43,11 +35,6 @@ DrawerType2 {
descriptionText: qsTr("Allows you to connect to some sites or applications through a VPN connection and bypass others")
}
Item {
id: focusItem
KeyNavigation.tab: splitTunnelingSwitch.visible ? splitTunnelingSwitch : siteBasedSplitTunnelingSwitch.rightButton
}
LabelWithButtonType {
id: splitTunnelingSwitch
Layout.fillWidth: true
@ -59,11 +46,9 @@ DrawerType2 {
descriptionText: qsTr("Enabled \nCan't be disabled for current server")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
KeyNavigation.tab: siteBasedSplitTunnelingSwitch.visible ? siteBasedSplitTunnelingSwitch.rightButton : focusItem
clickedFunction: function() {
// PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
// root.close()
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
root.closeTriggered()
}
}
@ -80,13 +65,9 @@ DrawerType2 {
descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
KeyNavigation.tab: appSplitTunnelingSwitch.visible ?
appSplitTunnelingSwitch.rightButton :
focusItem
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
root.close()
root.closeTriggered()
}
}
@ -103,11 +84,9 @@ DrawerType2 {
descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
KeyNavigation.tab: focusItem
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
root.close()
root.closeTriggered()
}
}

View file

@ -26,7 +26,7 @@ DrawerType2 {
id: installedAppsModel
}
expandedContent: Item {
expandedStateContent: Item {
id: container
implicitHeight: expandedHeight
@ -43,7 +43,7 @@ DrawerType2 {
BackButtonType {
backButtonImage: "qrc:/images/controls/arrow-left.svg"
backButtonFunction: function() {
root.close()
root.closeTriggered()
}
}
@ -69,6 +69,8 @@ DrawerType2 {
clip: true
interactive: true
property bool isFocusable: true
model: SortFilterProxyModel {
id: proxyInstalledAppsModel
sourceModel: installedAppsModel
@ -79,10 +81,7 @@ DrawerType2 {
}
}
ScrollBar.vertical: ScrollBar {
id: scrollBar
policy: ScrollBar.AlwaysOn
}
ScrollBar.vertical: ScrollBarType {}
ButtonGroup {
id: buttonGroup
@ -155,7 +154,7 @@ DrawerType2 {
PageController.showBusyIndicator(true)
AppSplitTunnelingController.addApps(installedAppsModel.getSelectedAppsInfo())
PageController.showBusyIndicator(false)
root.close()
root.closeTriggered()
}
}
}

View file

@ -20,7 +20,7 @@ DrawerType2 {
property var yesButtonFunction
property var noButtonFunction
expandedContent: ColumnLayout {
expandedStateContent: ColumnLayout {
id: content
anchors.top: parent.top
@ -33,14 +33,6 @@ DrawerType2 {
root.expandedHeight = content.implicitHeight + 32
}
Connections {
target: root
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}
Header2TextType {
Layout.fillWidth: true
Layout.topMargin: 16
@ -59,11 +51,6 @@ DrawerType2 {
text: descriptionText
}
Item {
id: focusItem
KeyNavigation.tab: yesButton
}
BasicButtonType {
id: yesButton
Layout.fillWidth: true
@ -78,8 +65,6 @@ DrawerType2 {
yesButtonFunction()
}
}
KeyNavigation.tab: noButton
}
BasicButtonType {
@ -102,8 +87,6 @@ DrawerType2 {
noButtonFunction()
}
}
KeyNavigation.tab: focusItem
}
}
}

View file

@ -11,7 +11,7 @@ import "../Config"
DrawerType2 {
id: root
expandedContent: Item {
expandedStateContent: Item {
id: container
implicitHeight: root.height * 0.9
@ -20,19 +20,6 @@ DrawerType2 {
root.expandedHeight = container.implicitHeight
}
Connections {
target: root
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@ -43,167 +30,148 @@ DrawerType2 {
BackButtonType {
id: backButton
Layout.fillWidth: true
backButtonImage: "qrc:/images/controls/arrow-left.svg"
backButtonFunction: function() { root.close() }
KeyNavigation.tab: listView
backButtonFunction: function() { root.closeTriggered() }
}
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: qsTr("Choose language")
}
}
FlickableType {
ListView {
id: listView
anchors.top: backButtonLayout.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
ColumnLayout {
id: content
property bool isFocusable: true
property int selectedIndex: LanguageModel.currentLanguageIndex
anchors.fill: parent
clip: true
reuseItems: true
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
ScrollBar.vertical: ScrollBarType {}
headerText: qsTr("Choose language")
}
model: LanguageModel
ListView {
id: listView
ButtonGroup {
id: buttonGroup
}
Layout.fillWidth: true
height: listView.contentItem.height
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
clip: true
interactive: false
ColumnLayout {
id: delegateContent
model: LanguageModel
currentIndex: LanguageModel.currentLanguageIndex
anchors.fill: parent
ButtonGroup {
id: buttonGroup
}
RadioButton {
id: radioButton
property int currentFocusIndex: 0
implicitWidth: parent.width
implicitHeight: radioButtonContent.implicitHeight
activeFocusOnTab: true
onActiveFocusChanged: {
if (activeFocus) {
this.currentFocusIndex = 0
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
}
}
hoverEnabled: true
Keys.onTabPressed: {
if (currentFocusIndex < this.count - 1) {
currentFocusIndex += 1
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
} else {
listViewFocusItem.forceActiveFocus()
focusItem.forceActiveFocus()
}
}
property bool isFocusable: true
Item {
id: listViewFocusItem
Keys.onTabPressed: {
root.forceActiveFocus()
FocusController.nextKeyTabItem()
}
}
onVisibleChanged: {
if (visible) {
listViewFocusItem.forceActiveFocus()
focusItem.forceActiveFocus()
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
}
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
onActiveFocusChanged: {
if (activeFocus) {
radioButton.forceActiveFocus()
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
indicator: Rectangle {
width: parent.width - 1
height: parent.height
color: radioButton.hovered ? AmneziaStyle.color.slateGray : AmneziaStyle.color.onyxBlack
border.color: radioButton.focus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.transparent
border.width: radioButton.focus ? 1 : 0
Behavior on color {
PropertyAnimation { duration: 200 }
}
Behavior on border.color {
PropertyAnimation { duration: 200 }
}
}
ColumnLayout {
id: delegateContent
RowLayout {
id: radioButtonContent
anchors.fill: parent
RadioButton {
id: radioButton
anchors.rightMargin: 16
anchors.leftMargin: 16
implicitWidth: parent.width
implicitHeight: radioButtonContent.implicitHeight
spacing: 0
hoverEnabled: true
z: 1
indicator: Rectangle {
width: parent.width - 1
height: parent.height
color: radioButton.hovered ? AmneziaStyle.color.slateGray : AmneziaStyle.color.onyxBlack
border.color: radioButton.focus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.transparent
border.width: radioButton.focus ? 1 : 0
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.bottomMargin: 20
Behavior on color {
PropertyAnimation { duration: 200 }
}
Behavior on border.color {
PropertyAnimation { duration: 200 }
}
}
text: languageName
}
RowLayout {
id: radioButtonContent
anchors.fill: parent
Image {
source: "qrc:/images/controls/check.svg"
visible: radioButton.checked
anchors.rightMargin: 16
anchors.leftMargin: 16
width: 24
height: 24
spacing: 0
z: 1
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 20
Layout.bottomMargin: 20
text: languageName
}
Image {
source: "qrc:/images/controls/check.svg"
visible: radioButton.checked
width: 24
height: 24
Layout.rightMargin: 8
}
}
ButtonGroup.group: buttonGroup
checked: listView.currentIndex === index
onClicked: {
listView.currentIndex = index
LanguageModel.changeLanguage(languageIndex)
root.close()
}
Layout.rightMargin: 8
}
}
Keys.onEnterPressed: radioButton.clicked()
Keys.onReturnPressed: radioButton.clicked()
ButtonGroup.group: buttonGroup
checked: listView.selectedIndex === index
onClicked: {
listView.selectedIndex = index
LanguageModel.changeLanguage(languageIndex)
root.closeTriggered()
}
}
}
Keys.onEnterPressed: radioButton.clicked()
Keys.onReturnPressed: radioButton.clicked()
}
}
}

View file

@ -0,0 +1,126 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import SortFilterProxyModel 0.2
import PageEnum 1.0
import ProtocolEnum 1.0
import ContainerProps 1.0
import ContainersModelFilters 1.0
import Style 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
ListView {
id: root
property int selectedIndex: ServersModel.defaultIndex
anchors.top: serversMenuHeader.bottom
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.topMargin: 16
model: ServersModel
ScrollBar.vertical: ScrollBarType {}
property bool isFocusable: true
Connections {
target: ServersModel
function onDefaultServerIndexChanged(serverIndex) {
root.selectedIndex = serverIndex
}
}
clip: true
reuseItems: true
delegate: Item {
id: menuContentDelegate
objectName: "menuContentDelegate"
property variant delegateData: model
property VerticalRadioButton serverRadioButtonProperty: serverRadioButton
implicitWidth: root.width
implicitHeight: serverRadioButtonContent.implicitHeight
ColumnLayout {
id: serverRadioButtonContent
objectName: "serverRadioButtonContent"
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 0
RowLayout {
objectName: "serverRadioButtonRowLayout"
Layout.fillWidth: true
VerticalRadioButton {
id: serverRadioButton
objectName: "serverRadioButton"
Layout.fillWidth: true
text: name
descriptionText: serverDescription
checked: index === root.selectedIndex
checkable: !ConnectionController.isConnected
ButtonGroup.group: serversRadioButtonGroup
onClicked: {
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Unable change server while there is an active connection"))
return
}
root.selectedIndex = index
ServersModel.defaultIndex = index
}
Keys.onEnterPressed: serverRadioButton.clicked()
Keys.onReturnPressed: serverRadioButton.clicked()
}
ImageButtonType {
id: serverInfoButton
objectName: "serverInfoButton"
image: "qrc:/images/controls/settings.svg"
imageColor: AmneziaStyle.color.paleGray
implicitWidth: 56
implicitHeight: 56
z: 1
onClicked: function() {
ServersModel.processedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
drawer.closeTriggered()
}
}
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 0
Layout.rightMargin: 0
}
}
}
}

View file

@ -20,47 +20,14 @@ ListView {
height: root.contentItem.height
clip: true
interactive: false
reuseItems: true
activeFocusOnTab: true
Keys.onTabPressed: {
if (currentIndex < this.count - 1) {
this.incrementCurrentIndex()
} else {
currentIndex = 0
lastItemTabClickedSignal()
}
}
onCurrentIndexChanged: {
if (visible) {
if (fl.contentHeight > fl.height) {
var item = this.currentItem
if (item.y < fl.height) {
fl.contentY = item.y
} else if (item.y + item.height > fl.contentY + fl.height) {
fl.contentY = item.y + item.height - fl.height
}
}
}
}
onVisibleChanged: {
if (visible) {
this.currentIndex = 0
}
}
property bool isFocusable: false
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
onActiveFocusChanged: {
if (activeFocus) {
containerRadioButton.rightButton.forceActiveFocus()
}
}
ColumnLayout {
id: delegateContent

View file

@ -36,17 +36,9 @@ DrawerType2 {
configFileName = "amnezia_config"
}
expandedContent: Item {
expandedStateContent: Item {
implicitHeight: root.expandedHeight
Connections {
target: root
enabled: !GC.isMobile()
function onOpened() {
header.forceActiveFocus()
}
}
Header2Type {
id: header
anchors.top: parent.top
@ -57,24 +49,27 @@ DrawerType2 {
anchors.rightMargin: 16
headerText: root.headerText
KeyNavigation.tab: shareButton
}
FlickableType {
ListView {
id: listView
anchors.top: header.bottom
anchors.bottom: parent.bottom
contentHeight: content.height + 32
anchors.left: parent.left
anchors.right: parent.right
ColumnLayout {
id: content
property bool isFocusable: true
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
ScrollBar.vertical: ScrollBarType {}
anchors.leftMargin: 16
anchors.rightMargin: 16
model: 1
clip: true
reuseItems: true
header: ColumnLayout {
width: listView.width
visible: root.contentVisible
@ -82,12 +77,12 @@ DrawerType2 {
id: shareButton
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Share")
leftImageSource: "qrc:/images/controls/share-2.svg"
KeyNavigation.tab: copyConfigTextButton
clickedFunc: function() {
var fileName = ""
if (GC.isMobile()) {
@ -111,6 +106,8 @@ DrawerType2 {
id: copyConfigTextButton
Layout.fillWidth: true
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
@ -124,14 +121,14 @@ DrawerType2 {
Keys.onReturnPressed: { copyConfigTextButton.clicked() }
Keys.onEnterPressed: { copyConfigTextButton.clicked() }
KeyNavigation.tab: copyNativeConfigStringButton.visible ? copyNativeConfigStringButton : showSettingsButton
}
BasicButtonType {
id: copyNativeConfigStringButton
Layout.fillWidth: true
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: false
@ -153,6 +150,8 @@ DrawerType2 {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
@ -164,10 +163,8 @@ DrawerType2 {
text: qsTr("Show connection settings")
clickedFunc: function() {
configContentDrawer.open()
configContentDrawer.openTriggered()
}
KeyNavigation.tab: header
}
DrawerType2 {
@ -178,30 +175,11 @@ DrawerType2 {
anchors.fill: parent
expandedHeight: parent.height * 0.9
onClosed: {
if (!GC.isMobile()) {
header.forceActiveFocus()
}
}
expandedContent: Item {
expandedStateContent: Item {
id: configContentContainer
implicitHeight: configContentDrawer.expandedHeight
Connections {
target: configContentDrawer
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
Connections {
target: copyNativeConfigStringButton
function onClicked() {
@ -231,9 +209,7 @@ DrawerType2 {
anchors.right: parent.right
anchors.topMargin: 16
backButtonFunction: function() { configContentDrawer.close() }
KeyNavigation.tab: focusItem
backButtonFunction: function() { configContentDrawer.closeTriggered() }
}
FlickableType {
@ -302,6 +278,10 @@ DrawerType2 {
}
}
}
}
delegate: ColumnLayout {
width: listView.width
Rectangle {
id: qrCodeContainer
@ -309,6 +289,8 @@ DrawerType2 {
Layout.fillWidth: true
Layout.preferredHeight: width
Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: ExportController.qrCodesCount > 0
@ -320,6 +302,32 @@ DrawerType2 {
source: ExportController.qrCodesCount ? ExportController.qrCodes[0] : ""
property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
Timer {
property int index: 0
interval: 1000
@ -346,6 +354,8 @@ DrawerType2 {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: ExportController.qrCodesCount > 0

View file

@ -39,8 +39,6 @@ Rectangle {
implicitWidth: (rootWidth - 32) / 2
text: "UDP"
KeyNavigation.tab: tcpButton
onClicked: {
root.currentIndex = 0
}