Improve navigation cpp (#1061)

* add focusController class

* add more key handlers

* add focus navigation to qml

* fixed language selector

* add reverse focus change to FocusController

* add default focus item

* update transitions

* update pages

* add ListViewFocusController

* fix ListView navigation

* update CardType for using with focus navigation

* remove useless key navigation

* remove useless slots, logs, Drawer open and close

* fix reverse focus move on listView

* fix drawer radio buttons selection

* fix drawer layout and focus move

* fix PageSetupWizardProtocolSettings focus move

* fix back navigation on default focus item

* fix crashes after ListView navigation

* fix protocol settings focus move

* fix focus on users on page share

* clean up page share

* fix server rename

* fix page share default server selection

* refactor about page for correct focus move

* fix focus move on list views with header and-or footer

* minor fixes

* fix server list back button handler

* fix spawn signals on switch

* fix share details drawer

* fix drawer open close usage

* refactor listViewFocusController

* refactor focusController to make the logic more
straightforward

* fix focus on notification

* update config page for scrolling with tab

* fix crash on return with esc key

* fix focus navigation in dynamic delegate of list view

* fix focus move on qr code on share page

* refactor page logging settings for focus navigation

* update popup

* Bump version

* Add mandatory requirement for android.software.leanback.

* Fix importing files on TVs

* fix: add separate method for reading files to fix file reading on Android TV

* fix(android): add CHANGE_NETWORK_STATE permission for all Android versions

* Fix connection check for AWG/WG

* chore: minor fixes (#1235)

* fix: add a workaround to open files on Android TV due to lack of SAF

* fix: change the banner format for TV

* refactor: make TvFilePicker activity more sustainable

* fix: add the touch emulation method for Android TV

* fix: null uri processing

* fix: add the touch emulation method for Android TV

* fix: hide UI elements that use file saving

* chore: bump version code

* add `ScrollBarType`

* update initial config page

* refactor credentials setup page to handle the focus navigation

* add `setDelegateIndex` method to `listViewFocusController`

* fix focus behavior on new page/popup

* make minor fixes and clean up

* fix: get rid of the assign function call

* Scrollbar is on if the content is larger than a screen

* Fix selection in language change list

* Update select language list

* update logging settings page

* fix checked item in lists

* fix split tunneling settings

* make unchangable properties readonly

* refactor SwitcherType

* fix hide/unhide password

* `PageShare` readonly properties

* Fix list view focus moving on `PageShare`

* remove manual focus control on `PageShare`

* format `ListViewFocusController`

* format `FocusController`

* add `focusControl` with utility functions for
focus control

* refactor `listViewFocusController` acoording to `focusControl`

* refactor `focusConroller` according to `focusControl`

* add `printSectionName` method to `listViewController`

* remove arrow from `Close application` item

* fix focus movement in `ServersListView`

* `Restore from backup` is visible only on start screen

* `I have nothing` is visible only on start screen

* fix back button on `SelectLanguageDrawer`

* rename `focusControl` to `qmlUtils`

* fix `CMakeLists.txt`

* fix `ScrollBarType`

* fix `PageSetupWizardApiServicesList`

* fix focus movement on dynamic delegates in listView

* refactor `PageSetupWizardProtocols`

* remove comments and clean up

* fix `ListViewWithLabelsType`

* fix `PageProtocolCloakSettings`

* fix `PageSettingsAppSplitTunneling`

* fix `PageDevMenu`

* remove debug output from `FocusController`

* remove debug output from `ListViewFocusController`

* remove debug output from `focusControl`

* `focusControl` => `FocusControl`

---------

Co-authored-by: albexk <albexk@proton.me>
Co-authored-by: Nethius <nethiuswork@gmail.com>
This commit is contained in:
Cyril Anisimov 2024-12-31 04:16:52 +01:00 committed by GitHub
parent 212e9b3a91
commit 6acaab0ffa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
109 changed files with 4036 additions and 3700 deletions

View file

@ -16,40 +16,28 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
BackButtonType {
id: backButton
// KeyNavigation.tab: removeButton
}
}
FlickableType {
id: fl
anchors.top: backButtonLayout.bottom
ListView {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
anchors.right: parent.right
anchors.left: parent.left
ColumnLayout {
id: content
property bool isFocusable: true
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
ScrollBar.vertical: ScrollBarType {}
header: ColumnLayout {
width: listView.width
HeaderType {
id: header
@ -60,7 +48,14 @@ PageType {
headerText: "Dev menu"
}
}
model: 1
clip: true
spacing: 16
delegate: ColumnLayout {
width: listView.width
TextFieldWithHeaderType {
id: passwordTextField
@ -69,7 +64,6 @@ PageType {
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
parentFlickable: fl
headerText: qsTr("Gateway endpoint")
textFieldText: SettingsController.gatewayEndpoint
@ -86,17 +80,19 @@ PageType {
SettingsController.gatewayEndpoint = textFieldText
}
}
// KeyNavigation.tab: saveButton
}
}
footer: ColumnLayout {
width: listView.width
SwitcherType {
id: switcher
Layout.fillWidth: true
Layout.topMargin: 24
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.topMargin: 16
text: qsTr("Dev gateway environment")
checked: SettingsController.isDevGatewayEnv

View file

@ -19,13 +19,13 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Connections {
objectName: "pageControllerConnections"
target: PageController
function onRestorePageHomeState(isContainerInstalled) {
drawer.open()
drawer.openTriggered()
if (isContainerInstalled) {
containersDropDown.rootButtonClickedFunction()
}
@ -33,23 +33,22 @@ PageType {
}
Item {
objectName: "homeColumnItem"
anchors.fill: parent
anchors.bottomMargin: drawer.collapsedHeight
ColumnLayout {
objectName: "homeColumnLayout"
anchors.fill: parent
anchors.topMargin: 34
anchors.bottomMargin: 34
Item {
id: focusItem
KeyNavigation.tab: loggingButton.visible ?
loggingButton :
connectButton
}
BasicButtonType {
id: loggingButton
objectName: "loggingButton"
property bool isLoggingEnabled: SettingsController.isLoggingEnabled
Layout.alignment: Qt.AlignHCenter
@ -69,8 +68,6 @@ PageType {
Keys.onEnterPressed: loggingButton.clicked()
Keys.onReturnPressed: loggingButton.clicked()
KeyNavigation.tab: connectButton
onClicked: {
PageController.goToPage(PageEnum.PageSettingsLogging)
}
@ -78,13 +75,15 @@ PageType {
ConnectButton {
id: connectButton
objectName: "connectButton"
Layout.fillHeight: true
Layout.alignment: Qt.AlignCenter
KeyNavigation.tab: splitTunnelingButton
}
BasicButtonType {
id: splitTunnelingButton
objectName: "splitTunnelingButton"
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
Layout.bottomMargin: 34
@ -116,53 +115,37 @@ PageType {
Keys.onEnterPressed: splitTunnelingButton.clicked()
Keys.onReturnPressed: splitTunnelingButton.clicked()
KeyNavigation.tab: drawer
onClicked: {
homeSplitTunnelingDrawer.open()
homeSplitTunnelingDrawer.openTriggered()
}
HomeSplitTunnelingDrawer {
id: homeSplitTunnelingDrawer
parent: root
objectName: "homeSplitTunnelingDrawer"
onClosed: {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
parent: root
}
}
}
}
DrawerType2 {
id: drawer
objectName: "drawerProtocol"
anchors.fill: parent
onClosed: {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
collapsedStateContent: Item {
objectName: "ProtocolDrawerCollapsedContent"
collapsedContent: Item {
implicitHeight: Qt.platform.os !== "ios" ? root.height * 0.9 : screen.height * 0.77
Component.onCompleted: {
drawer.expandedHeight = implicitHeight
}
Connections {
target: drawer
enabled: !GC.isMobile()
function onActiveFocusChanged() {
if (drawer.activeFocus && !drawer.isOpened) {
collapsedButtonChevron.forceActiveFocus()
}
}
}
ColumnLayout {
id: collapsed
objectName: "collapsedColumnLayout"
anchors.left: parent.left
anchors.right: parent.right
@ -181,6 +164,8 @@ PageType {
}
RowLayout {
objectName: "rowLayout"
Layout.topMargin: 14
Layout.leftMargin: 24
Layout.rightMargin: 24
@ -189,9 +174,11 @@ PageType {
spacing: 0
Connections {
objectName: "drawerConnections"
target: drawer
function onEntered() {
if (drawer.isCollapsed) {
function onCursorEntered() {
if (drawer.isCollapsedStateActive) {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.hoveredColor
collapsedButtonHeader.opacity = 0.8
} else {
@ -199,8 +186,8 @@ PageType {
}
}
function onExited() {
if (drawer.isCollapsed) {
function onCursorExited() {
if (drawer.isCollapsedStateActive) {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 1
} else {
@ -209,7 +196,7 @@ PageType {
}
function onPressed(pressed, entered) {
if (drawer.isCollapsed) {
if (drawer.isCollapsedStateActive) {
collapsedButtonChevron.backgroundColor = pressed ? collapsedButtonChevron.pressedColor : entered ? collapsedButtonChevron.hoveredColor : collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 0.7
} else {
@ -220,6 +207,8 @@ PageType {
Header1TextType {
id: collapsedButtonHeader
objectName: "collapsedButtonHeader"
Layout.maximumWidth: drawer.width - 48 - 18 - 12
maximumLineCount: 2
@ -228,8 +217,6 @@ PageType {
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
KeyNavigation.tab: tabBar
Behavior on opacity {
PropertyAnimation { duration: 200 }
}
@ -237,10 +224,11 @@ PageType {
ImageButtonType {
id: collapsedButtonChevron
objectName: "collapsedButtonChevron"
Layout.leftMargin: 8
visible: drawer.isCollapsed
visible: drawer.isCollapsedStateActive()
hoverEnabled: false
image: "qrc:/images/controls/chevron-down.svg"
@ -255,18 +243,17 @@ PageType {
Keys.onEnterPressed: collapsedButtonChevron.clicked()
Keys.onReturnPressed: collapsedButtonChevron.clicked()
Keys.onTabPressed: lastItemTabClicked()
onClicked: {
if (drawer.isCollapsed) {
drawer.open()
if (drawer.isCollapsedStateActive()) {
drawer.openTriggered()
}
}
}
}
RowLayout {
objectName: "rowLayoutLabel"
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.topMargin: 8
Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 61 : 16
@ -305,18 +292,9 @@ PageType {
}
}
Connections {
target: drawer
enabled: !GC.isMobile()
function onIsCollapsedChanged() {
if (!drawer.isCollapsed) {
focusItem1.forceActiveFocus()
}
}
}
ColumnLayout {
id: serversMenuHeader
objectName: "serversMenuHeader"
anchors.top: collapsed.bottom
anchors.right: parent.right
@ -328,13 +306,9 @@ PageType {
visible: !ServersModel.isDefaultServerFromApi
Item {
id: focusItem1
KeyNavigation.tab: containersDropDown
}
DropDownType {
id: containersDropDown
objectName: "containersDropDown"
rootButtonImageColor: AmneziaStyle.color.midnightBlack
rootButtonBackgroundColor: AmneziaStyle.color.paleGray
@ -345,28 +319,29 @@ PageType {
rootButtonTextTopMargin: 8
rootButtonTextBottomMargin: 8
enabled: drawer.isOpened
text: ServersModel.defaultServerDefaultContainerName
textColor: AmneziaStyle.color.midnightBlack
headerText: qsTr("VPN protocol")
headerBackButtonImage: "qrc:/images/controls/arrow-left.svg"
rootButtonClickedFunction: function() {
containersDropDown.open()
containersDropDown.openTriggered()
}
drawerParent: root
KeyNavigation.tab: serversMenuContent
listView: HomeContainersListView {
id: containersListView
objectName: "containersListView"
rootWidth: root.width
onVisibleChanged: {
if (containersDropDown.visible && !GC.isMobile()) {
focusItem1.forceActiveFocus()
}
}
height: 500 // TODO: make calculated
Connections {
objectName: "rowLayoutConnections"
target: ServersModel
function onDefaultServerIndexChanged() {
@ -408,167 +383,21 @@ PageType {
ButtonGroup {
id: serversRadioButtonGroup
objectName: "serversRadioButtonGroup"
}
ListView {
ServersListView {
id: serversMenuContent
objectName: "serversMenuContent"
anchors.top: serversMenuHeader.bottom
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.topMargin: 16
model: ServersModel
currentIndex: ServersModel.defaultIndex
ScrollBar.vertical: ScrollBar {
id: scrollBar
policy: serversMenuContent.height >= serversMenuContent.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
}
activeFocusOnTab: true
focus: true
property int focusItemIndex: 0
onActiveFocusChanged: {
if (activeFocus) {
serversMenuContent.focusItemIndex = 0
serversMenuContent.itemAtIndex(focusItemIndex).forceActiveFocus()
}
}
onFocusItemIndexChanged: {
const focusedElement = serversMenuContent.itemAtIndex(focusItemIndex)
if (focusedElement) {
if (focusedElement.y + focusedElement.height > serversMenuContent.height) {
serversMenuContent.contentY = focusedElement.y + focusedElement.height - serversMenuContent.height
} else {
serversMenuContent.contentY = 0
}
}
}
Keys.onUpPressed: scrollBar.decrease()
Keys.onDownPressed: scrollBar.increase()
isFocusable: false
Connections {
target: drawer
enabled: !GC.isMobile()
function onIsCollapsedChanged() {
if (drawer.isCollapsed) {
const item = serversMenuContent.itemAtIndex(serversMenuContent.focusItemIndex)
if (item) { item.serverRadioButtonProperty.focus = false }
}
}
}
Connections {
target: ServersModel
function onDefaultServerIndexChanged(serverIndex) {
serversMenuContent.currentIndex = serverIndex
}
}
clip: true
delegate: Item {
id: menuContentDelegate
property variant delegateData: model
property VerticalRadioButton serverRadioButtonProperty: serverRadioButton
implicitWidth: serversMenuContent.width
implicitHeight: serverRadioButtonContent.implicitHeight
onActiveFocusChanged: {
if (activeFocus) {
serverRadioButton.forceActiveFocus()
}
}
ColumnLayout {
id: serverRadioButtonContent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 0
RowLayout {
Layout.fillWidth: true
VerticalRadioButton {
id: serverRadioButton
Layout.fillWidth: true
text: name
descriptionText: serverDescription
checked: index === serversMenuContent.currentIndex
checkable: !ConnectionController.isConnected
ButtonGroup.group: serversRadioButtonGroup
onClicked: {
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Unable change server while there is an active connection"))
return
}
serversMenuContent.currentIndex = index
ServersModel.defaultIndex = index
}
MouseArea {
anchors.fill: serverRadioButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
Keys.onTabPressed: serverInfoButton.forceActiveFocus()
Keys.onEnterPressed: serverRadioButton.clicked()
Keys.onReturnPressed: serverRadioButton.clicked()
}
ImageButtonType {
id: serverInfoButton
image: "qrc:/images/controls/settings.svg"
imageColor: AmneziaStyle.color.paleGray
implicitWidth: 56
implicitHeight: 56
z: 1
Keys.onTabPressed: {
if (serversMenuContent.focusItemIndex < serversMenuContent.count - 1) {
serversMenuContent.focusItemIndex++
serversMenuContent.itemAtIndex(serversMenuContent.focusItemIndex).forceActiveFocus()
} else {
focusItem1.forceActiveFocus()
serversMenuContent.contentY = 0
}
}
Keys.onEnterPressed: serverInfoButton.clicked()
Keys.onReturnPressed: serverInfoButton.clicked()
onClicked: function() {
ServersModel.processedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
drawer.close()
}
}
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 0
Layout.rightMargin: 0
}
// this item shouldn't be focused when drawer is closed
function onIsOpenedChanged() {
serversMenuContent.isFocusable = drawer.isOpened
}
}
}

View file

@ -16,18 +16,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.mtuTextField.textField
Item {
id: focusItem
onFocusChanged: {
if (activeFocus) {
fl.ensureVisible(focusItem)
}
}
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@ -39,229 +27,235 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview.currentItem.mtuTextField.textField
}
}
FlickableType {
id: fl
ListView {
id: listview
anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight + saveButton.implicitHeight + saveButton.anchors.bottomMargin + saveButton.anchors.topMargin
anchors.bottom: saveButton.top
Column {
id: content
width: parent.width
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
clip: true
ListView {
id: listview
property bool isFocusable: true
width: parent.width
height: listview.contentItem.height
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
clip: true
interactive: false
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
model: AwgConfigModel
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
delegate: Item {
id: delegateItem
implicitWidth: listview.width
implicitHeight: col.implicitHeight
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
property alias mtuTextField: mtuTextField
property bool isSaveButtonEnabled: mtuTextField.errorText === "" &&
junkPacketMaxSizeTextField.errorText === "" &&
junkPacketMinSizeTextField.errorText === "" &&
junkPacketCountTextField.errorText === ""
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
ColumnLayout {
id: col
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
model: AwgConfigModel
anchors.leftMargin: 16
anchors.rightMargin: 16
delegate: Item {
id: delegateItem
implicitWidth: listview.width
implicitHeight: col.implicitHeight
spacing: 0
property alias mtuTextField: mtuTextField
property bool isSaveButtonEnabled: mtuTextField.errorText === "" &&
junkPacketMaxSizeTextField.errorText === "" &&
junkPacketMinSizeTextField.errorText === "" &&
junkPacketCountTextField.errorText === ""
HeaderType {
Layout.fillWidth: true
ColumnLayout {
id: col
headerText: qsTr("AmneziaWG settings")
}
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
TextFieldWithHeaderType {
id: mtuTextField
Layout.fillWidth: true
Layout.topMargin: 40
anchors.leftMargin: 16
anchors.rightMargin: 16
headerText: qsTr("MTU")
textFieldText: clientMtu
textField.validator: IntValidator { bottom: 576; top: 65535 }
spacing: 0
textField.onEditingFinished: {
if (textFieldText !== clientMtu) {
clientMtu = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: junkPacketCountTextField.textField
}
HeaderType {
Layout.fillWidth: true
TextFieldWithHeaderType {
id: junkPacketCountTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("AmneziaWG settings")
}
headerText: "Jc - Junk packet count"
textFieldText: clientJunkPacketCount
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
TextFieldWithHeaderType {
id: mtuTextField
Layout.fillWidth: true
Layout.topMargin: 40
textField.onEditingFinished: {
if (textFieldText !== clientJunkPacketCount) {
clientJunkPacketCount = textFieldText
}
}
headerText: qsTr("MTU")
textFieldText: clientMtu
textField.validator: IntValidator { bottom: 576; top: 65535 }
checkEmptyText: true
KeyNavigation.tab: junkPacketMinSizeTextField.textField
}
TextFieldWithHeaderType {
id: junkPacketMinSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: "Jmin - Junk packet minimum size"
textFieldText: clientJunkPacketMinSize
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== clientJunkPacketMinSize) {
clientJunkPacketMinSize = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
}
TextFieldWithHeaderType {
id: junkPacketMaxSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: "Jmax - Junk packet maximum size"
textFieldText: clientJunkPacketMaxSize
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== clientJunkPacketMaxSize) {
clientJunkPacketMaxSize = textFieldText
}
}
checkEmptyText: true
Keys.onTabPressed: saveButton.forceActiveFocus()
}
Header2TextType {
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Server settings")
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 8
enabled: false
headerText: qsTr("Port")
textFieldText: port
}
TextFieldWithHeaderType {
id: initPacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "S1 - Init packet junk size"
textFieldText: serverInitPacketJunkSize
}
TextFieldWithHeaderType {
id: responsePacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "S2 - Response packet junk size"
textFieldText: serverResponsePacketJunkSize
}
TextFieldWithHeaderType {
id: initPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "H1 - Init packet magic header"
textFieldText: serverInitPacketMagicHeader
}
TextFieldWithHeaderType {
id: responsePacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "H2 - Response packet magic header"
textFieldText: serverResponsePacketMagicHeader
}
TextFieldWithHeaderType {
id: underloadPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
parentFlickable: fl
enabled: false
headerText: "H3 - Underload packet magic header"
textFieldText: serverUnderloadPacketMagicHeader
}
TextFieldWithHeaderType {
id: transportPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "H4 - Transport packet magic header"
textFieldText: serverTransportPacketMagicHeader
textField.onEditingFinished: {
if (textFieldText !== clientMtu) {
clientMtu = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: junkPacketCountTextField.textField
}
TextFieldWithHeaderType {
id: junkPacketCountTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: "Jc - Junk packet count"
textFieldText: clientJunkPacketCount
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== clientJunkPacketCount) {
clientJunkPacketCount = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: junkPacketMinSizeTextField.textField
}
TextFieldWithHeaderType {
id: junkPacketMinSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: "Jmin - Junk packet minimum size"
textFieldText: clientJunkPacketMinSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== clientJunkPacketMinSize) {
clientJunkPacketMinSize = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
}
TextFieldWithHeaderType {
id: junkPacketMaxSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: "Jmax - Junk packet maximum size"
textFieldText: clientJunkPacketMaxSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== clientJunkPacketMaxSize) {
clientJunkPacketMaxSize = textFieldText
}
}
checkEmptyText: true
}
Header2TextType {
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Server settings")
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 8
enabled: false
headerText: qsTr("Port")
textFieldText: port
}
TextFieldWithHeaderType {
id: initPacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "S1 - Init packet junk size"
textFieldText: serverInitPacketJunkSize
}
TextFieldWithHeaderType {
id: responsePacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "S2 - Response packet junk size"
textFieldText: serverResponsePacketJunkSize
}
TextFieldWithHeaderType {
id: initPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "H1 - Init packet magic header"
textFieldText: serverInitPacketMagicHeader
}
TextFieldWithHeaderType {
id: responsePacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "H2 - Response packet magic header"
textFieldText: serverResponsePacketMagicHeader
}
TextFieldWithHeaderType {
id: underloadPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "H3 - Underload packet magic header"
textFieldText: serverUnderloadPacketMagicHeader
}
TextFieldWithHeaderType {
id: transportPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: false
headerText: "H4 - Transport packet magic header"
textFieldText: serverTransportPacketMagicHeader
}
}
}
@ -283,7 +277,11 @@ PageType {
text: qsTr("Save")
Keys.onTabPressed: lastItemTabClicked(focusItem)
onActiveFocusChanged: {
if(activeFocus) {
listview.positionViewAtEnd()
}
}
clickedFunc: function() {
forceActiveFocus()

View file

@ -2,6 +2,8 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtCore
import SortFilterProxyModel 0.2
import PageEnum 1.0
@ -17,18 +19,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.portTextField.textField
Item {
id: focusItem
onFocusChanged: {
if (activeFocus) {
fl.ensureVisible(focusItem)
}
}
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@ -40,341 +30,357 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview.currentItem.portTextField.textField
}
}
FlickableType {
id: fl
ListView {
id: listview
anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
Column {
id: content
width: parent.width
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
property bool isFocusable: true
ListView {
id: listview
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
width: parent.width
height: listview.contentItem.height
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
clip: true
interactive: false
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
model: AwgConfigModel
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
delegate: Item {
id: delegateItem
implicitWidth: listview.width
implicitHeight: col.implicitHeight
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
property alias portTextField: portTextField
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
ColumnLayout {
id: col
clip: true
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
model: AwgConfigModel
anchors.leftMargin: 16
anchors.rightMargin: 16
delegate: Item {
id: delegateItem
implicitWidth: listview.width
implicitHeight: col.implicitHeight
spacing: 0
property alias portTextField: portTextField
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
HeaderType {
Layout.fillWidth: true
ColumnLayout {
id: col
headerText: qsTr("AmneziaWG settings")
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0
HeaderType {
Layout.fillWidth: true
headerText: qsTr("AmneziaWG settings")
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 40
enabled: delegateItem.isEnabled
headerText: qsTr("Port")
textFieldText: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
if (textFieldText !== port) {
port = textFieldText
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: mtuTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("MTU")
textFieldText: mtu
textField.validator: IntValidator { bottom: 576; top: 65535 }
textField.onEditingFinished: {
if (textFieldText === "") {
textFieldText = "0"
}
if (textFieldText !== mtu) {
mtu = textFieldText
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: junkPacketCountTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("Jc - Junk packet count")
textFieldText: serverJunkPacketCount
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText === "") {
textFieldText = "0"
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 40
if (textFieldText !== serverJunkPacketCount) {
serverJunkPacketCount = textFieldText
}
}
enabled: delegateItem.isEnabled
checkEmptyText: true
}
headerText: qsTr("Port")
textFieldText: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
parentFlickable: fl
TextFieldWithHeaderType {
id: junkPacketMinSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
textField.onEditingFinished: {
if (textFieldText !== port) {
port = textFieldText
}
headerText: qsTr("Jmin - Junk packet minimum size")
textFieldText: serverJunkPacketMinSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverJunkPacketMinSize) {
serverJunkPacketMinSize = textFieldText
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: junkPacketMaxSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("Jmax - Junk packet maximum size")
textFieldText: serverJunkPacketMaxSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverJunkPacketMaxSize) {
serverJunkPacketMaxSize = textFieldText
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: initPacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("S1 - Init packet junk size")
textFieldText: serverInitPacketJunkSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverInitPacketJunkSize) {
serverInitPacketJunkSize = textFieldText
}
}
checkEmptyText: true
onActiveFocusChanged: {
if(activeFocus) {
listview.positionViewAtEnd()
}
}
}
TextFieldWithHeaderType {
id: responsePacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("S2 - Response packet junk size")
textFieldText: serverResponsePacketJunkSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverResponsePacketJunkSize) {
serverResponsePacketJunkSize = textFieldText
}
}
checkEmptyText: true
onActiveFocusChanged: {
if(activeFocus) {
listview.positionViewAtEnd()
}
}
}
TextFieldWithHeaderType {
id: initPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("H1 - Init packet magic header")
textFieldText: serverInitPacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverInitPacketMagicHeader) {
serverInitPacketMagicHeader = textFieldText
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: responsePacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("H2 - Response packet magic header")
textFieldText: serverResponsePacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverResponsePacketMagicHeader) {
serverResponsePacketMagicHeader = textFieldText
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: transportPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("H4 - Transport packet magic header")
textFieldText: serverTransportPacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverTransportPacketMagicHeader) {
serverTransportPacketMagicHeader = textFieldText
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: underloadPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("H3 - Underload packet magic header")
textFieldText: serverUnderloadPacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverUnderloadPacketMagicHeader) {
serverUnderloadPacketMagicHeader = textFieldText
}
}
checkEmptyText: true
}
BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
enabled: underloadPacketMagicHeaderTextField.errorText === "" &&
transportPacketMagicHeaderTextField.errorText === "" &&
responsePacketMagicHeaderTextField.errorText === "" &&
initPacketMagicHeaderTextField.errorText === "" &&
responsePacketJunkSizeTextField.errorText === "" &&
initPacketJunkSizeTextField.errorText === "" &&
junkPacketMaxSizeTextField.errorText === "" &&
junkPacketMinSizeTextField.errorText === "" &&
junkPacketCountTextField.errorText === "" &&
portTextField.errorText === ""
text: qsTr("Save")
onActiveFocusChanged: {
if(activeFocus) {
listview.positionViewAtEnd()
}
}
clickedFunc: function() {
forceActiveFocus()
if (delegateItem.isEnabled) {
if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text,
transportPacketMagicHeaderTextField.textField.text,
responsePacketMagicHeaderTextField.textField.text,
initPacketMagicHeaderTextField.textField.text)) {
PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique"))
return
}
checkEmptyText: true
KeyNavigation.tab: junkPacketCountTextField.textField
}
TextFieldWithHeaderType {
id: junkPacketCountTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("Jc - Junk packet count")
textFieldText: serverJunkPacketCount
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText === "") {
textFieldText = "0"
}
if (textFieldText !== serverJunkPacketCount) {
serverJunkPacketCount = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: junkPacketMinSizeTextField.textField
}
TextFieldWithHeaderType {
id: junkPacketMinSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("Jmin - Junk packet minimum size")
textFieldText: serverJunkPacketMinSize
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== serverJunkPacketMinSize) {
serverJunkPacketMinSize = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
}
TextFieldWithHeaderType {
id: junkPacketMaxSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("Jmax - Junk packet maximum size")
textFieldText: serverJunkPacketMaxSize
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== serverJunkPacketMaxSize) {
serverJunkPacketMaxSize = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: initPacketJunkSizeTextField.textField
}
TextFieldWithHeaderType {
id: initPacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("S1 - Init packet junk size")
textFieldText: serverInitPacketJunkSize
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== serverInitPacketJunkSize) {
serverInitPacketJunkSize = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: responsePacketJunkSizeTextField.textField
}
TextFieldWithHeaderType {
id: responsePacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("S2 - Response packet junk size")
textFieldText: serverResponsePacketJunkSize
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== serverResponsePacketJunkSize) {
serverResponsePacketJunkSize = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: initPacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
id: initPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("H1 - Init packet magic header")
textFieldText: serverInitPacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== serverInitPacketMagicHeader) {
serverInitPacketMagicHeader = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: responsePacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
id: responsePacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("H2 - Response packet magic header")
textFieldText: serverResponsePacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== serverResponsePacketMagicHeader) {
serverResponsePacketMagicHeader = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: transportPacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
id: transportPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("H4 - Transport packet magic header")
textFieldText: serverTransportPacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
parentFlickable: fl
textField.onEditingFinished: {
if (textFieldText !== serverTransportPacketMagicHeader) {
serverTransportPacketMagicHeader = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: underloadPacketMagicHeaderTextField.textField
}
TextFieldWithHeaderType {
id: underloadPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
parentFlickable: fl
headerText: qsTr("H3 - Underload packet magic header")
textFieldText: serverUnderloadPacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textFieldText !== serverUnderloadPacketMagicHeader) {
serverUnderloadPacketMagicHeader = textFieldText
}
}
checkEmptyText: true
KeyNavigation.tab: saveRestartButton
}
BasicButtonType {
id: saveRestartButton
parentFlickable: fl
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
enabled: underloadPacketMagicHeaderTextField.errorText === "" &&
transportPacketMagicHeaderTextField.errorText === "" &&
responsePacketMagicHeaderTextField.errorText === "" &&
initPacketMagicHeaderTextField.errorText === "" &&
responsePacketJunkSizeTextField.errorText === "" &&
initPacketJunkSizeTextField.errorText === "" &&
junkPacketMaxSizeTextField.errorText === "" &&
junkPacketMinSizeTextField.errorText === "" &&
junkPacketCountTextField.errorText === "" &&
portTextField.errorText === ""
text: qsTr("Save")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()
if (delegateItem.isEnabled) {
if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text,
transportPacketMagicHeaderTextField.textField.text,
responsePacketMagicHeaderTextField.textField.text,
initPacketMagicHeaderTextField.textField.text)) {
PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique"))
return
}
if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
parseInt(responsePacketJunkSizeTextField.textField.text))) {
PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)"))
return
}
}
var headerText = qsTr("Save settings?")
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(AwgConfigModel.getConfig())
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
saveRestartButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
parseInt(responsePacketJunkSizeTextField.textField.text))) {
PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)"))
return
}
}
var headerText = qsTr("Save settings?")
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(AwgConfigModel.getConfig())
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
saveRestartButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
}

View file

@ -16,13 +16,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.trafficFromField.textField
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@ -34,7 +27,6 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview.currentItem.trafficFromField.textField
}
}
@ -56,11 +48,13 @@ PageType {
ListView {
id: listview
property int selectedIndex: 0
width: parent.width
height: listview.contentItem.height
clip: true
interactive: false
reuseItems: true
model: CloakConfigModel
@ -110,8 +104,6 @@ PageType {
}
}
}
KeyNavigation.tab: portTextField.textField
}
TextFieldWithHeaderType {
@ -130,8 +122,6 @@ PageType {
port = textFieldText
}
}
KeyNavigation.tab: cipherDropDown
}
DropDownType {
@ -143,7 +133,6 @@ PageType {
headerText: qsTr("Cipher")
drawerParent: root
KeyNavigation.tab: saveRestartButton
listView: ListViewWithRadioButtonType {
id: cipherListView
@ -161,7 +150,7 @@ PageType {
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.close()
cipherDropDown.closeTriggered()
}
Component.onCompleted: {
@ -169,7 +158,7 @@ PageType {
for (var i = 0; i < cipherListView.model.count; i++) {
if (cipherListView.model.get(i).name === cipherDropDown.text) {
currentIndex = i
selectedIndex = i
}
}
}
@ -184,7 +173,6 @@ PageType {
Layout.bottomMargin: 24
text: qsTr("Save")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()

View file

@ -17,18 +17,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.vpnAddressSubnetTextField.textField
Item {
id: focusItem
KeyNavigation.tab: backButton
onActiveFocusChanged: {
if (activeFocus) {
fl.ensureVisible(focusItem)
}
}
}
ColumnLayout {
id: backButtonLayout
@ -40,7 +28,6 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview.currentItem.vpnAddressSubnetTextField.textField
}
}
@ -104,7 +91,6 @@ PageType {
textFieldText: subnetAddress
parentFlickable: fl
KeyNavigation.tab: transportProtoSelector
textField.onEditingFinished: {
if (textFieldText !== subnetAddress) {
@ -132,8 +118,6 @@ PageType {
return transportProto === "tcp" ? 1 : 0
}
KeyNavigation.tab: portTextField.enabled ? portTextField.textField : autoNegotiateEncryprionSwitcher
onCurrentIndexChanged: {
if (transportProto === "tcp" && currentIndex === 0) {
transportProto = "udp"
@ -162,8 +146,6 @@ PageType {
port = textFieldText
}
}
KeyNavigation.tab: autoNegotiateEncryprionSwitcher
}
SwitcherType {
@ -181,10 +163,6 @@ PageType {
autoNegotiateEncryprion = checked
}
}
KeyNavigation.tab: hashDropDown.enabled ?
hashDropDown :
tlsAuthCheckBox
}
DropDownType {
@ -199,9 +177,6 @@ PageType {
drawerParent: root
parentFlickable: fl
KeyNavigation.tab: cipherDropDown.enabled ?
cipherDropDown :
tlsAuthCheckBox
listView: ListViewWithRadioButtonType {
id: hashListView
@ -224,7 +199,7 @@ PageType {
clickedFunction: function() {
hashDropDown.text = selectedText
hash = hashDropDown.text
hashDropDown.close()
hashDropDown.closeTriggered()
}
Component.onCompleted: {
@ -252,8 +227,6 @@ PageType {
drawerParent: root
parentFlickable: fl
KeyNavigation.tab: tlsAuthCheckBox
listView: ListViewWithRadioButtonType {
id: cipherListView
@ -275,7 +248,7 @@ PageType {
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.close()
cipherDropDown.closeTriggered()
}
Component.onCompleted: {
@ -320,8 +293,6 @@ PageType {
text: qsTr("TLS auth")
checked: tlsAuth
KeyNavigation.tab: blockDnsCheckBox
onCheckedChanged: {
if (checked !== tlsAuth) {
console.log("tlsAuth changed to: " + checked)
@ -339,8 +310,6 @@ PageType {
text: qsTr("Block DNS requests outside of VPN")
checked: blockDns
KeyNavigation.tab: additionalClientCommandsSwitcher
onCheckedChanged: {
if (checked !== blockDns) {
blockDns = checked
@ -355,9 +324,6 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 32
parentFlickable: fl
KeyNavigation.tab: additionalClientCommandsTextArea.visible ?
additionalClientCommandsTextArea.textArea :
additionalServerCommandsSwitcher
checked: additionalClientCommands !== ""
@ -376,7 +342,7 @@ PageType {
Layout.topMargin: 16
visible: additionalClientCommandsSwitcher.checked
KeyNavigation.tab: additionalServerCommandsSwitcher
parentFlickable: fl
textAreaText: additionalClientCommands
@ -394,9 +360,6 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 16
parentFlickable: fl
KeyNavigation.tab: additionalServerCommandsTextArea.visible ?
additionalServerCommandsTextArea.textArea :
saveRestartButton
checked: additionalServerCommands !== ""
@ -419,7 +382,6 @@ PageType {
textAreaText: additionalServerCommands
placeholderText: qsTr("Commands:")
parentFlickable: fl
KeyNavigation.tab: saveRestartButton
textArea.onEditingFinished: {
if (additionalServerCommands !== textAreaText) {
additionalServerCommands = textAreaText
@ -436,7 +398,6 @@ PageType {
text: qsTr("Save")
parentFlickable: fl
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()

View file

@ -19,13 +19,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: header
@ -37,7 +30,6 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listView
}
HeaderType {
@ -75,13 +67,6 @@ PageType {
activeFocusOnTab: true
focus: true
onActiveFocusChanged: {
if (focus) {
listView.currentIndex = 0
listView.currentItem.focusItem.forceActiveFocus()
}
}
delegate: Item {
implicitWidth: parent.width
implicitHeight: delegateContent.implicitHeight
@ -101,11 +86,9 @@ PageType {
text: qsTr("Show connection options")
clickedFunction: function() {
configContentDrawer.open()
configContentDrawer.openTriggered()
}
KeyNavigation.tab: removeButton
MouseArea {
anchors.fill: button
cursorShape: Qt.PointingHandCursor
@ -120,31 +103,12 @@ PageType {
expandedHeight: root.height * 0.9
onClosed: {
if (!GC.isMobile()) {
defaultActiveFocusItem.forceActiveFocus()
}
}
parent: root
anchors.fill: parent
expandedContent: Item {
expandedStateContent: Item {
implicitHeight: configContentDrawer.expandedHeight
Connections {
target: configContentDrawer
enabled: !GC.isMobile()
function onOpened() {
focusItem1.forceActiveFocus()
}
}
Item {
id: focusItem1
KeyNavigation.tab: backButton1
}
BackButtonType {
id: backButton1
@ -154,10 +118,8 @@ PageType {
anchors.topMargin: 16
backButtonFunction: function() {
configContentDrawer.close()
configContentDrawer.closeTriggered()
}
KeyNavigation.tab: focusItem1
}
FlickableType {
@ -226,7 +188,6 @@ PageType {
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
textColor: AmneziaStyle.color.vibrantRed
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunction: function() {
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")

View file

@ -16,15 +16,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview.currentItem.focusItemId.enabled ?
listview.currentItem.focusItemId.textField :
focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@ -36,9 +27,6 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview.currentItem.focusItemId.enabled ?
listview.currentItem.focusItemId.textField :
focusItem
}
}
@ -114,8 +102,6 @@ PageType {
port = textFieldText
}
}
KeyNavigation.tab: cipherDropDown
}
DropDownType {
@ -129,9 +115,9 @@ PageType {
headerText: qsTr("Cipher")
drawerParent: root
KeyNavigation.tab: saveRestartButton
listView: ListViewWithRadioButtonType {
id: cipherListView
rootWidth: root.width
@ -147,7 +133,7 @@ PageType {
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.close()
cipherDropDown.closeTriggered()
}
Component.onCompleted: {
@ -172,7 +158,6 @@ PageType {
enabled: isPortEditable | isCipherEditable
text: qsTr("Save")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()

View file

@ -150,8 +150,6 @@ PageType {
text: qsTr("Save")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()
var headerText = qsTr("Save settings?")

View file

@ -16,13 +16,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@ -34,7 +27,6 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview
}
}
@ -64,13 +56,6 @@ PageType {
model: WireGuardConfigModel
activeFocusOnTab: true
onActiveFocusChanged: {
if (activeFocus) {
listview.itemAtIndex(0)?.focusItemId.forceActiveFocus()
}
}
delegate: Item {
id: delegateItem
@ -109,8 +94,6 @@ PageType {
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
KeyNavigation.tab: saveButton
textField.onEditingFinished: {
if (textFieldText !== port) {
port = textFieldText
@ -120,6 +103,26 @@ PageType {
checkEmptyText: true
}
TextFieldWithHeaderType {
id: mtuTextField
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("MTU")
textFieldText: mtu
textField.validator: IntValidator { bottom: 576; top: 65535 }
textField.onEditingFinished: {
if (textFieldText === "") {
textFieldText = "0"
}
if (textFieldText !== mtu) {
mtu = textFieldText
}
}
checkEmptyText: true
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
@ -130,8 +133,6 @@ PageType {
text: qsTr("Save")
Keys.onTabPressed: lastItemTabClicked(focusItem)
onClicked: function() {
forceActiveFocus()

View file

@ -17,13 +17,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@ -35,7 +28,6 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview
}
}
@ -65,13 +57,6 @@ PageType {
model: XrayConfigModel
activeFocusOnTab: true
onActiveFocusChanged: {
if (activeFocus) {
listview.itemAtIndex(0)?.focusItemId.forceActiveFocus()
}
}
delegate: Item {
property alias focusItemId: textFieldWithHeaderType.textField
@ -103,8 +88,6 @@ PageType {
headerText: qsTr("Disguised as traffic from")
textFieldText: site
KeyNavigation.tab: basicButton
textField.onEditingFinished: {
if (textFieldText !== site) {
var tmpText = textFieldText
@ -128,8 +111,6 @@ PageType {
text: qsTr("Save")
Keys.onTabPressed: lastItemTabClicked(focusItem)
onClicked: {
forceActiveFocus()

View file

@ -16,13 +16,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@ -34,7 +27,6 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: removeButton
}
}
@ -72,8 +64,6 @@ PageType {
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
textColor: AmneziaStyle.color.vibrantRed
Keys.onTabPressed: root.lastItemTabClicked()
clickedFunction: function() {
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
var yesButtonText = qsTr("Continue")

View file

@ -16,8 +16,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Connections {
target: InstallController
@ -26,11 +24,6 @@ PageType {
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@ -42,7 +35,6 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview
}
}
@ -107,7 +99,6 @@ PageType {
Layout.topMargin: 32
parentFlickable: fl
KeyNavigation.tab: portLabel.rightButton
text: qsTr("Host")
descriptionText: ServersModel.getProcessedServerData("hostName")
@ -136,7 +127,6 @@ PageType {
descriptionOnTop: true
parentFlickable: fl
KeyNavigation.tab: usernameLabel.rightButton
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@ -160,7 +150,6 @@ PageType {
descriptionOnTop: true
parentFlickable: fl
KeyNavigation.tab: passwordLabel.eyeButton
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@ -184,14 +173,6 @@ PageType {
descriptionOnTop: true
parentFlickable: fl
eyeButton.KeyNavigation.tab: passwordLabel.rightButton
rightButton.Keys.onTabPressed: {
if (mountButton.visible) {
mountButton.forceActiveFocus()
} else {
detailedInstructionsButton.forceActiveFocus()
}
}
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@ -225,7 +206,6 @@ PageType {
borderWidth: 1
parentFlickable: fl
KeyNavigation.tab: detailedInstructionsButton
text: qsTr("Mount folder on device")
@ -290,7 +270,6 @@ PageType {
text: qsTr("Detailed instructions")
parentFlickable: fl
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
// Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")

View file

@ -17,8 +17,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: listview
Connections {
target: InstallController
@ -27,11 +25,6 @@ PageType {
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@ -43,7 +36,6 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: listview
}
}
@ -99,7 +91,6 @@ PageType {
Layout.topMargin: 32
parentFlickable: fl
KeyNavigation.tab: portLabel.rightButton
text: qsTr("Host")
descriptionText: ServersModel.getProcessedServerData("hostName")
@ -128,7 +119,6 @@ PageType {
descriptionOnTop: true
parentFlickable: fl
KeyNavigation.tab: usernameLabel.rightButton
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@ -152,7 +142,6 @@ PageType {
descriptionOnTop: true
parentFlickable: fl
KeyNavigation.tab: passwordLabel.eyeButton
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@ -176,8 +165,6 @@ PageType {
descriptionOnTop: true
parentFlickable: fl
eyeButton.KeyNavigation.tab: passwordLabel.rightButton
rightButton.KeyNavigation.tab: changeSettingsButton
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@ -200,13 +187,7 @@ PageType {
anchors.fill: parent
expandedHeight: root.height * 0.9
onClosed: {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
expandedContent: ColumnLayout {
expandedStateContent: ColumnLayout {
property string tempPort: port
property string tempUsername: username
property string tempPassword: password
@ -222,9 +203,6 @@ PageType {
Connections {
target: changeSettingsDrawer
function onOpened() {
if (!GC.isMobile()) {
drawerFocusItem.forceActiveFocus()
}
tempPort = port
tempUsername = username
tempPassword = password
@ -239,11 +217,6 @@ PageType {
}
}
Item {
id: drawerFocusItem
KeyNavigation.tab: portTextField.textField
}
HeaderType {
Layout.fillWidth: true
@ -268,8 +241,6 @@ PageType {
port = textFieldText
}
}
KeyNavigation.tab: usernameTextField.textField
}
TextFieldWithHeaderType {
@ -290,8 +261,6 @@ PageType {
username = textFieldText
}
}
KeyNavigation.tab: passwordTextField.textField
}
TextFieldWithHeaderType {
@ -322,8 +291,6 @@ PageType {
password = textFieldText
}
}
KeyNavigation.tab: saveButton
}
BasicButtonType {
@ -334,7 +301,6 @@ PageType {
Layout.bottomMargin: 24
text: qsTr("Change connection settings")
Keys.onTabPressed: lastItemTabClicked(drawerFocusItem)
clickedFunc: function() {
forceActiveFocus()
@ -356,7 +322,7 @@ PageType {
tempPort = portTextField.textFieldText
tempUsername = usernameTextField.textFieldText
tempPassword = passwordTextField.textFieldText
changeSettingsDrawer.close()
changeSettingsDrawer.closeTriggered()
}
}
}
@ -372,11 +338,10 @@ PageType {
Layout.rightMargin: 16
text: qsTr("Change connection settings")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()
changeSettingsDrawer.open()
changeSettingsDrawer.openTriggered()
}
}
}

View file

@ -17,8 +17,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Connections {
target: InstallController
@ -27,11 +25,6 @@ PageType {
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
@ -43,7 +36,6 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: websiteName.rightButton
}
}
@ -88,8 +80,6 @@ PageType {
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))

View file

@ -14,8 +14,6 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: header
FlickableType {
id: fl
anchors.top: parent.top
@ -39,8 +37,6 @@ PageType {
Layout.leftMargin: 16
headerText: qsTr("Settings")
KeyNavigation.tab: account.rightButton
}
LabelWithButtonType {
@ -55,8 +51,6 @@ PageType {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsServersList)
}
KeyNavigation.tab: connection.rightButton
}
DividerType {}
@ -72,8 +66,6 @@ PageType {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsConnection)
}
KeyNavigation.tab: application.rightButton
}
DividerType {}
@ -89,14 +81,13 @@ PageType {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsApplication)
}
KeyNavigation.tab: backup.rightButton
}
DividerType {}
LabelWithButtonType {
id: backup
visible: !SettingsController.isOnTv()
Layout.fillWidth: true
text: qsTr("Backup")
@ -106,11 +97,11 @@ PageType {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsBackup)
}
KeyNavigation.tab: about.rightButton
}
DividerType {}
DividerType {
visible: !SettingsController.isOnTv()
}
LabelWithButtonType {
id: about
@ -123,8 +114,6 @@ PageType {
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsAbout)
}
KeyNavigation.tab: close
}
DividerType {}
@ -138,8 +127,6 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/bug.svg"
// Keys.onTabPressed: lastItemTabClicked(header)
clickedFunction: function() {
PageController.goToPage(PageEnum.PageDevMenu)
}
@ -157,9 +144,7 @@ PageType {
text: qsTr("Close application")
leftImageSource: "qrc:/images/controls/x-circle.svg"
isLeftImageHoverEnabled: false
Keys.onTabPressed: lastItemTabClicked(header)
isLeftImageHoverEnabled: false
clickedFunction: function() {
PageController.closeApplication()

View file

@ -14,19 +14,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
onFocusChanged: {
if (focusItem.activeFocus) {
fl.contentY = 0
}
}
}
BackButtonType {
id: backButton
@ -35,21 +22,107 @@ PageType {
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: telegramButton
onActiveFocusChanged: {
if(backButton.enabled && backButton.activeFocus) {
listView.positionViewAtBeginning()
}
}
}
FlickableType {
id: fl
QtObject {
id: telegramGroup
readonly property string title: qsTr("Telegram group")
readonly property string description: qsTr("To discuss features")
readonly property string imageSource: "qrc:/images/controls/telegram.svg"
readonly property var handler: function() {
Qt.openUrlExternally(qsTr("https://t.me/amnezia_vpn_en"))
}
}
QtObject {
id: mail
readonly property string title: qsTr("support@amnezia.org")
readonly property string description: qsTr("For reviews and bug reports")
readonly property string imageSource: "qrc:/images/controls/mail.svg"
readonly property var handler: function() {
GC.copyToClipBoard(title)
PageController.showNotificationMessage(qsTr("Copied"))
}
}
QtObject {
id: github
readonly property string title: qsTr("GitHub")
readonly property string description: qsTr("Discover the source code")
readonly property string imageSource: "qrc:/images/controls/github.svg"
readonly property var handler: function() {
Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client"))
}
}
QtObject {
id: website
readonly property string title: qsTr("Website")
readonly property string description: qsTr("Visit official website")
readonly property string imageSource: "qrc:/images/controls/amnezia.svg"
readonly property var handler: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
}
}
property list<QtObject> contacts: [
telegramGroup,
mail,
github,
website
]
ListView {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
contentHeight: content.height
anchors.right: parent.right
anchors.left: parent.left
ColumnLayout {
id: content
property bool isFocusable: true
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
ScrollBar.vertical: ScrollBarType {}
model: contacts
clip: true
header: ColumnLayout {
width: listView.width
Image {
id: image
@ -96,81 +169,29 @@ PageType {
text: qsTr("Contacts")
}
}
delegate: ColumnLayout {
width: listView.width
LabelWithButtonType {
id: telegramButton
Layout.fillWidth: true
Layout.topMargin: 16
Layout.topMargin: 6
text: qsTr("Telegram group")
descriptionText: qsTr("To discuss features")
leftImageSource: "qrc:/images/controls/telegram.svg"
text: title
descriptionText: description
leftImageSource: imageSource
KeyNavigation.tab: mailButton
parentFlickable: fl
clickedFunction: function() {
Qt.openUrlExternally(qsTr("https://t.me/amnezia_vpn_en"))
}
clickedFunction: handler
}
DividerType {}
LabelWithButtonType {
id: mailButton
Layout.fillWidth: true
}
text: qsTr("support@amnezia.org")
descriptionText: qsTr("For reviews and bug reports")
leftImageSource: "qrc:/images/controls/mail.svg"
KeyNavigation.tab: githubButton
parentFlickable: fl
clickedFunction: function() {
GC.copyToClipBoard(text)
PageController.showNotificationMessage(qsTr("Copied"))
}
}
DividerType {}
LabelWithButtonType {
id: githubButton
Layout.fillWidth: true
text: qsTr("GitHub")
leftImageSource: "qrc:/images/controls/github.svg"
KeyNavigation.tab: websiteButton
parentFlickable: fl
clickedFunction: function() {
Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client"))
}
}
DividerType {}
LabelWithButtonType {
id: websiteButton
Layout.fillWidth: true
text: qsTr("Website")
leftImageSource: "qrc:/images/controls/amnezia.svg"
KeyNavigation.tab: checkUpdatesButton
parentFlickable: fl
clickedFunction: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
}
}
DividerType {}
footer: ColumnLayout {
width: listView.width
CaptionTextType {
Layout.fillWidth: true
@ -196,6 +217,7 @@ PageType {
BasicButtonType {
id: checkUpdatesButton
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 8
Layout.bottomMargin: 16
@ -209,35 +231,30 @@ PageType {
text: qsTr("Check for updates")
KeyNavigation.tab: privacyPolicyButton
parentFlickable: fl
clickedFunc: function() {
Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
}
}
BasicButtonType {
id: privacyPolicyButton
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: 16
Layout.topMargin: -15
implicitHeight: 25
id: privacyPolicyButton
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.goldenApricot
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: 16
Layout.topMargin: -15
implicitHeight: 25
text: qsTr("Privacy Policy")
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.goldenApricot
Keys.onTabPressed: lastItemTabClicked()
parentFlickable: fl
text: qsTr("Privacy Policy")
clickedFunc: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/policy")
}
clickedFunc: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/policy")
}
}
}
}

View file

@ -31,78 +31,74 @@ PageType {
id: containersRadioButtonGroup
}
delegate: Item {
delegate: ColumnLayout {
id: content
implicitWidth: parent.width
implicitHeight: content.implicitHeight
ColumnLayout {
id: content
RowLayout {
VerticalRadioButton {
id: containerRadioButton
anchors.fill: parent
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.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 (!InstallController.updateServiceFromApi(ServersModel.defaultIndex, countryCode, countryName)) {
ApiCountryModel.currentIndex = prevIndex
}
}
}
MouseArea {
anchors.fill: containerRadioButton
cursorShape: Qt.PointingHandCursor
enabled: 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
Layout.leftMargin: 16
text: countryName
ButtonGroup.group: containersRadioButtonGroup
imageSource: "qrc:/images/controls/download.svg"
checked: index === ApiCountryModel.currentIndex
checkable: !ConnectionController.isConnected
onClicked: {
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 (!InstallController.updateServiceFromApi(ServersModel.defaultIndex, countryCode, countryName)) {
ApiCountryModel.currentIndex = prevIndex
}
}
}
MouseArea {
anchors.fill: containerRadioButton
cursorShape: Qt.PointingHandCursor
enabled: 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
}
}
}

View file

@ -15,8 +15,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
FlickableType {
id: fl
anchors.top: parent.top
@ -32,11 +30,6 @@ PageType {
spacing: 0
Item {
id: focusItem
// KeyNavigation.tab: backButton
}
LabelWithImageType {
Layout.fillWidth: true
Layout.margins: 16
@ -111,9 +104,6 @@ PageType {
descriptionOnTop: true
// parentFlickable: fl
// KeyNavigation.tab: passwordLabel.eyeButton
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
@ -141,8 +131,6 @@ PageType {
text: qsTr("Reload API config")
// Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
var headerText = qsTr("Reload API config?")
var yesButtonText = qsTr("Continue")
@ -181,8 +169,6 @@ PageType {
text: qsTr("Remove from application")
// Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
var headerText = qsTr("Remove from application?")
var yesButtonText = qsTr("Continue")

View file

@ -21,8 +21,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
property bool pageEnabled
Component.onCompleted: {
@ -48,13 +46,15 @@ PageType {
QtObject {
id: onlyForwardApps
property string name: qsTr("Only the apps from the list should have access via VPN")
property int type: routeMode.onlyForwardApps
readonly property string name: qsTr("Only the apps from the list should have access via VPN")
readonly property int type: routeMode.onlyForwardApps
}
QtObject {
id: allExceptApps
property string name: qsTr("Apps from the list should not have access via VPN")
property int type: routeMode.allExceptApps
readonly property string name: qsTr("Apps from the list should not have access via VPN")
readonly property int type: routeMode.allExceptApps
}
function getRouteModesModelIndex() {
@ -66,11 +66,6 @@ PageType {
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: header
@ -82,7 +77,6 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: switcher
}
RowLayout {
@ -103,10 +97,6 @@ PageType {
enabled: root.pageEnabled
KeyNavigation.tab: selector.enabled ?
selector :
searchField.textField
checked: AppSplitTunnelingModel.isTunnelingEnabled
onToggled: {
AppSplitTunnelingModel.toggleSplitTunneling(checked)
@ -130,25 +120,23 @@ PageType {
enabled: Qt.platform.os === "android" && root.pageEnabled
KeyNavigation.tab: searchField.textField
listView: ListViewWithRadioButtonType {
rootWidth: root.width
model: root.routeModesModel
currentIndex: getRouteModesModelIndex()
selectedIndex: getRouteModesModelIndex()
clickedFunction: function() {
selector.text = selectedText
selector.close()
if (AppSplitTunnelingModel.routeMode !== root.routeModesModel[currentIndex].type) {
AppSplitTunnelingModel.routeMode = root.routeModesModel[currentIndex].type
selector.closeTriggered()
if (AppSplitTunnelingModel.routeMode !== root.routeModesModel[selectedIndex].type) {
AppSplitTunnelingModel.routeMode = root.routeModesModel[selectedIndex].type
}
}
Component.onCompleted: {
if (root.routeModesModel[currentIndex].type === AppSplitTunnelingModel.routeMode) {
if (root.routeModesModel[selectedIndex].type === AppSplitTunnelingModel.routeMode) {
selector.text = selectedText
} else {
selector.text = root.routeModesModel[0].name
@ -158,7 +146,7 @@ PageType {
Connections {
target: AppSplitTunnelingModel
function onRouteModeChanged() {
currentIndex = getRouteModesModelIndex()
selectedIndex = getRouteModesModelIndex()
}
}
}
@ -267,7 +255,6 @@ PageType {
textFieldPlaceholderText: qsTr("application name")
buttonImageSource: "qrc:/images/controls/plus.svg"
Keys.onTabPressed: lastItemTabClicked(focusItem)
rightButtonClickedOnEnter: true
clickedFunc: function() {
@ -281,7 +268,7 @@ PageType {
AppSplitTunnelingController.addApp(fileName)
}
} else if (Qt.platform.os === "android"){
installedAppDrawer.open()
installedAppDrawer.openTriggered()
}
PageController.showBusyIndicator(false)

View file

@ -14,19 +14,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
onFocusChanged: {
if (focusItem.activeFocus) {
fl.contentY = 0
}
}
}
BackButtonType {
id: backButton
@ -34,8 +21,6 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: GC.isMobile() ? switcher : switcherAutoStart
}
FlickableType {
@ -77,8 +62,8 @@ PageType {
}
}
KeyNavigation.tab: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted ?
labelWithButtonNotification.rightButton : labelWithButtonLanguage.rightButton
// KeyNavigation.tab: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted ?
// labelWithButtonNotification.rightButton : labelWithButtonLanguage.rightButton
parentFlickable: fl
}
@ -95,7 +80,6 @@ PageType {
descriptionText: qsTr("Enable notifications to show the VPN state in the status bar")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
KeyNavigation.tab: labelWithButtonLanguage.rightButton
parentFlickable: fl
clickedFunction: function() {
@ -117,7 +101,6 @@ PageType {
text: qsTr("Auto start")
descriptionText: qsTr("Launch the application every time the device is starts")
KeyNavigation.tab: switcherAutoConnect
parentFlickable: fl
checked: SettingsController.isAutoStartEnabled()
@ -142,7 +125,6 @@ PageType {
text: qsTr("Auto connect")
descriptionText: qsTr("Connect to VPN on app start")
KeyNavigation.tab: switcherStartMinimized
parentFlickable: fl
checked: SettingsController.isAutoConnectEnabled()
@ -167,7 +149,6 @@ PageType {
text: qsTr("Start minimized")
descriptionText: qsTr("Launch application minimized")
KeyNavigation.tab: labelWithButtonLanguage.rightButton
parentFlickable: fl
checked: SettingsController.isStartMinimizedEnabled()
@ -190,11 +171,10 @@ PageType {
descriptionText: LanguageModel.currentLanguageName
rightImageSource: "qrc:/images/controls/chevron-right.svg"
KeyNavigation.tab: labelWithButtonLogging.rightButton
parentFlickable: fl
clickedFunction: function() {
selectLanguageDrawer.open()
selectLanguageDrawer.openTriggered()
}
}
@ -208,7 +188,6 @@ PageType {
descriptionText: SettingsController.isLoggingEnabled ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
KeyNavigation.tab: labelWithButtonReset.rightButton
parentFlickable: fl
clickedFunction: function() {
@ -226,7 +205,6 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg"
textColor: AmneziaStyle.color.vibrantRed
Keys.onTabPressed: lastItemTabClicked()
parentFlickable: fl
clickedFunction: function() {
@ -245,12 +223,12 @@ PageType {
}
if (!GC.isMobile()) {
root.defaultActiveFocusItem.forceActiveFocus()
// root.defaultActiveFocusItem.forceActiveFocus()
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
root.defaultActiveFocusItem.forceActiveFocus()
// root.defaultActiveFocusItem.forceActiveFocus()
}
}
@ -267,11 +245,5 @@ PageType {
width: root.width
height: root.height
onClosed: {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
}
}

View file

@ -17,8 +17,6 @@ import "../Controls2/TextTypes"
PageType {
id: root
defaultActiveFocusItem: focusItem
Connections {
target: SettingsController
@ -36,11 +34,6 @@ PageType {
}
}
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@ -48,8 +41,6 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: makeBackupButton
}
FlickableType {
@ -93,6 +84,8 @@ PageType {
text: qsTr("Make a backup")
parentFlickable: fl
clickedFunc: function() {
var fileName = ""
if (GC.isMobile()) {
@ -111,8 +104,6 @@ PageType {
PageController.showNotificationMessage(qsTr("Backup file saved"))
}
}
KeyNavigation.tab: restoreBackupButton
}
BasicButtonType {
@ -129,6 +120,8 @@ PageType {
text: qsTr("Restore from backup")
parentFlickable: fl
clickedFunc: function() {
var filePath = SystemController.getFileName(qsTr("Open backup file"),
qsTr("Backup files (*.backup)"))
@ -136,8 +129,6 @@ PageType {
restoreBackup(filePath)
}
}
Keys.onTabPressed: lastItemTabClicked()
}
}
}

View file

@ -12,15 +12,8 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: focusItem
property bool isAppSplitTinnelingEnabled: Qt.platform.os === "windows" || Qt.platform.os === "android"
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@ -28,8 +21,6 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: amneziaDnsSwitch
}
FlickableType {
@ -67,8 +58,6 @@ PageType {
SettingsController.toggleAmneziaDns(checked)
}
}
KeyNavigation.tab: dnsServersButton.rightButton
}
DividerType {}
@ -81,11 +70,11 @@ PageType {
descriptionText: qsTr("When AmneziaDNS is not used or installed")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsDns)
}
KeyNavigation.tab: splitTunnelingButton.rightButton
}
DividerType {}
@ -98,19 +87,11 @@ PageType {
descriptionText: qsTr("Allows you to select which sites you want to access through the VPN")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
}
Keys.onTabPressed: {
if (splitTunnelingButton2.visible) {
return splitTunnelingButton2.rightButton.forceActiveFocus()
} else if (killSwitchSwitcher.visible) {
return killSwitchSwitcher.forceActiveFocus()
} else {
lastItemTabClicked()
}
}
}
DividerType {
@ -127,17 +108,11 @@ PageType {
descriptionText: qsTr("Allows you to use the VPN only for certain Apps")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
}
Keys.onTabPressed: {
if (killSwitchSwitcher.visible) {
return killSwitchSwitcher.forceActiveFocus()
} else {
lastItemTabClicked()
}
}
}
DividerType {
@ -154,6 +129,8 @@ PageType {
text: qsTr("KillSwitch")
descriptionText: qsTr("Disables your internet if your encrypted VPN connection drops out for any reason.")
parentFlickable: fl
checked: SettingsController.isKillSwitchEnabled()
checkable: !ConnectionController.isConnected
onCheckedChanged: {
@ -166,8 +143,6 @@ PageType {
PageController.showNotificationMessage(qsTr("Cannot change killSwitch settings during active connection"))
}
}
Keys.onTabPressed: lastItemTabClicked()
}
DividerType {

View file

@ -14,13 +14,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: primaryDns.textField
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@ -28,8 +21,6 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: root.defaultActiveFocusItem
}
FlickableType {
@ -80,8 +71,6 @@ PageType {
textField.validator: RegularExpressionValidator {
regularExpression: InstallController.ipAddressRegExp()
}
KeyNavigation.tab: secondaryDns.textField
}
TextFieldWithHeaderType {
@ -94,8 +83,6 @@ PageType {
textField.validator: RegularExpressionValidator {
regularExpression: InstallController.ipAddressRegExp()
}
KeyNavigation.tab: restoreDefaultButton
}
BasicButtonType {
@ -124,19 +111,17 @@ PageType {
PageController.showNotificationMessage(qsTr("Settings have been reset"))
if (!GC.isMobile()) {
defaultActiveFocusItem.forceActiveFocus()
// defaultActiveFocusItem.forceActiveFocus()
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
defaultActiveFocusItem.forceActiveFocus()
// defaultActiveFocusItem.forceActiveFocus()
}
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
KeyNavigation.tab: saveButton
}
BasicButtonType {
@ -155,8 +140,6 @@ PageType {
}
PageController.showNotificationMessage(qsTr("Settings saved"))
}
Keys.onTabPressed: lastItemTabClicked(focusItem)
}
}
}

View file

@ -16,13 +16,6 @@ import "../Controls2/TextTypes"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@ -30,23 +23,22 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: switcher
}
FlickableType {
id: fl
ListView {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
contentHeight: content.height
anchors.right: parent.right
anchors.left: parent.left
ColumnLayout {
id: content
property bool isFocusable: true
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
ScrollBar.vertical: ScrollBarType {}
header: ColumnLayout {
width: listView.width
HeaderType {
Layout.fillWidth: true
@ -60,6 +52,7 @@ PageType {
SwitcherType {
id: switcher
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
@ -68,7 +61,7 @@ PageType {
text: qsTr("Enable logs")
checked: SettingsController.isLoggingEnabled
//KeyNavigation.tab: openFolderButton
onCheckedChanged: {
if (checked !== SettingsController.isLoggingEnabled) {
SettingsController.isLoggingEnabled = checked
@ -79,7 +72,6 @@ PageType {
DividerType {}
LabelWithButtonType {
// id: labelWithButton2
Layout.fillWidth: true
Layout.topMargin: -8
@ -87,8 +79,6 @@ PageType {
leftImageSource: "qrc:/images/controls/trash.svg"
isSmallLeftImage: true
// KeyNavigation.tab: labelWithButton3
clickedFunction: function() {
var headerText = qsTr("Clear logs?")
var yesButtonText = qsTr("Continue")
@ -99,19 +89,28 @@ PageType {
SettingsController.clearLogs()
PageController.showBusyIndicator(false)
PageController.showNotificationMessage(qsTr("Logs have been cleaned up"))
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
}
model: logTypes
clip: true
reuseItems: true
snapMode: ListView.SnapOneItem
delegate: ColumnLayout {
id: delegateContent
width: listView.width
enabled: isVisible
ListItemTitleType {
Layout.fillWidth: true
@ -119,7 +118,7 @@ PageType {
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Client logs")
text: title
}
ParagraphTextType {
@ -129,11 +128,11 @@ PageType {
Layout.rightMargin: 16
color: AmneziaStyle.color.mutedGray
text: qsTr("AmneziaVPN logs")
text: description
}
LabelWithButtonType {
// id: labelWithButton2
Layout.fillWidth: true
Layout.topMargin: -8
Layout.bottomMargin: -8
@ -142,17 +141,12 @@ PageType {
leftImageSource: "qrc:/images/controls/folder-open.svg"
isSmallLeftImage: true
// KeyNavigation.tab: labelWithButton3
clickedFunction: function() {
SettingsController.openLogsFolder()
}
clickedFunction: openLogsHandler
}
DividerType {}
LabelWithButtonType {
// id: labelWithButton2
Layout.fillWidth: true
Layout.topMargin: -8
Layout.bottomMargin: -8
@ -161,114 +155,72 @@ PageType {
leftImageSource: "qrc:/images/controls/save.svg"
isSmallLeftImage: true
// KeyNavigation.tab: labelWithButton3
clickedFunction: function() {
var fileName = ""
if (GC.isMobile()) {
fileName = "AmneziaVPN.log"
} else {
fileName = SystemController.getFileName(qsTr("Save"),
qsTr("Logs files (*.log)"),
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/AmneziaVPN",
true,
".log")
}
if (fileName !== "") {
PageController.showBusyIndicator(true)
SettingsController.exportLogsFile(fileName)
PageController.showBusyIndicator(false)
PageController.showNotificationMessage(qsTr("Logs file saved"))
}
}
clickedFunction: exportLogsHandler
}
DividerType {}
}
}
ListItemTitleType {
visible: !GC.isMobile()
property list<QtObject> logTypes: [
clientLogs,
serviceLogs
]
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
QtObject {
id: clientLogs
text: qsTr("Service logs")
readonly property string title: qsTr("Client logs")
readonly property string description: qsTr("AmneziaVPN logs")
readonly property bool isVisible: true
readonly property var openLogsHandler: function() {
SettingsController.openLogsFolder()
}
readonly property var exportLogsHandler: function() {
var fileName = ""
if (GC.isMobile()) {
fileName = "AmneziaVPN.log"
} else {
fileName = SystemController.getFileName(qsTr("Save"),
qsTr("Logs files (*.log)"),
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/AmneziaVPN",
true,
".log")
}
ParagraphTextType {
visible: !GC.isMobile()
Layout.fillWidth: true
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
color: AmneziaStyle.color.mutedGray
text: qsTr("AmneziaVPN-service logs")
if (fileName !== "") {
PageController.showBusyIndicator(true)
SettingsController.exportLogsFile(fileName)
PageController.showBusyIndicator(false)
PageController.showNotificationMessage(qsTr("Logs file saved"))
}
}
}
LabelWithButtonType {
// id: labelWithButton2
QtObject {
id: serviceLogs
visible: !GC.isMobile()
Layout.fillWidth: true
Layout.topMargin: -8
Layout.bottomMargin: -8
text: qsTr("Open logs folder")
leftImageSource: "qrc:/images/controls/folder-open.svg"
isSmallLeftImage: true
// KeyNavigation.tab: labelWithButton3
clickedFunction: function() {
SettingsController.openServiceLogsFolder()
}
readonly property string title: qsTr("Service logs")
readonly property string description: qsTr("AmneziaVPN-service logs")
readonly property bool isVisible: !GC.isMobile()
readonly property var openLogsHandler: function() {
SettingsController.openServiceLogsFolder()
}
readonly property var exportLogsHandler: function() {
var fileName = ""
if (GC.isMobile()) {
fileName = "AmneziaVPN-service.log"
} else {
fileName = SystemController.getFileName(qsTr("Save"),
qsTr("Logs files (*.log)"),
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/AmneziaVPN-service",
true,
".log")
}
DividerType {
visible: !GC.isMobile()
}
LabelWithButtonType {
// id: labelWithButton2
visible: !GC.isMobile()
Layout.fillWidth: true
Layout.topMargin: -8
Layout.bottomMargin: -8
text: qsTr("Export logs")
leftImageSource: "qrc:/images/controls/save.svg"
isSmallLeftImage: true
// KeyNavigation.tab: labelWithButton3
clickedFunction: function() {
var fileName = ""
if (GC.isMobile()) {
fileName = "AmneziaVPN-service.log"
} else {
fileName = SystemController.getFileName(qsTr("Save"),
qsTr("Logs files (*.log)"),
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/AmneziaVPN-service",
true,
".log")
}
if (fileName !== "") {
PageController.showBusyIndicator(true)
SettingsController.exportServiceLogsFile(fileName)
PageController.showBusyIndicator(false)
PageController.showNotificationMessage(qsTr("Logs file saved"))
}
}
}
DividerType {
visible: !GC.isMobile()
if (fileName !== "") {
PageController.showBusyIndicator(true)
SettingsController.exportServiceLogsFile(fileName)
PageController.showBusyIndicator(false)
PageController.showNotificationMessage(qsTr("Logs file saved"))
}
}
}

View file

@ -100,8 +100,6 @@ PageType {
text: qsTr("Check the server for previously installed Amnezia services")
descriptionText: qsTr("Add them to the application if they were not displayed")
KeyNavigation.tab: labelWithButton2
clickedFunction: function() {
PageController.showBusyIndicator(true)
InstallController.scanServerForInstalledContainers()
@ -121,8 +119,6 @@ PageType {
text: qsTr("Reboot server")
textColor: AmneziaStyle.color.vibrantRed
KeyNavigation.tab: labelWithButton3
clickedFunction: function() {
var headerText = qsTr("Do you want to reboot the server?")
var descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?")
@ -162,16 +158,6 @@ PageType {
text: qsTr("Remove server from application")
textColor: AmneziaStyle.color.vibrantRed
Keys.onTabPressed: {
if (content.isServerWithWriteAccess) {
labelWithButton4.forceActiveFocus()
} else {
labelWithButton5.visible ?
labelWithButton5.forceActiveFocus() :
lastItemTabClickedSignal()
}
}
clickedFunction: function() {
var headerText = qsTr("Do you want to remove the server from application?")
var descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.")
@ -210,10 +196,6 @@ PageType {
text: qsTr("Clear server from Amnezia software")
textColor: AmneziaStyle.color.vibrantRed
Keys.onTabPressed: labelWithButton5.visible ?
labelWithButton5.forceActiveFocus() :
root.lastItemTabClickedSignal()
clickedFunction: function() {
var headerText = qsTr("Do you want to clear server from Amnezia software?")
var descriptionText = qsTr("All users whom you shared a connection with will no longer be able to connect to it.")
@ -253,8 +235,6 @@ PageType {
text: qsTr("Reset API config")
textColor: AmneziaStyle.color.vibrantRed
Keys.onTabPressed: root.lastItemTabClickedSignal()
clickedFunction: function() {
var headerText = qsTr("Do you want to reset API config?")
var descriptionText = ""

View file

@ -19,21 +19,19 @@ import "../Components"
PageType {
id: root
property int pageSettingsServerProtocols: 0
property int pageSettingsServerServices: 1
property int pageSettingsServerData: 2
property int pageSettingsApiServerInfo: 3
property int pageSettingsApiLanguageList: 4
readonly property int pageSettingsServerProtocols: 0
readonly property int pageSettingsServerServices: 1
readonly property int pageSettingsServerData: 2
readonly property int pageSettingsApiServerInfo: 3
readonly property int pageSettingsApiLanguageList: 4
property var processedServer
defaultActiveFocusItem: focusItem
Connections {
target: PageController
function onGoToPageSettingsServerServices() {
tabBar.currentIndex = root.pageSettingsServerServices
tabBar.setCurrentIndex(root.pageSettingsServerServices)
}
}
@ -62,21 +60,17 @@ PageType {
}
}
Item {
id: focusItem
//KeyNavigation.tab: header
}
ColumnLayout {
objectName: "mainLayout"
anchors.fill: parent
anchors.topMargin: 20
spacing: 4
BackButtonType {
id: backButton
Layout.topMargin: 20
KeyNavigation.tab: headerContent.actionButton
objectName: "backButton"
backButtonFunction: function() {
if (nestedStackView.currentIndex === root.pageSettingsApiServerInfo &&
@ -90,9 +84,12 @@ PageType {
HeaderType {
id: headerContent
objectName: "headerContent"
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 10
actionButtonImage: nestedStackView.currentIndex === root.pageSettingsApiLanguageList ? "qrc:/images/controls/settings.svg"
: "qrc:/images/controls/edit-3.svg"
@ -114,32 +111,25 @@ PageType {
}
}
KeyNavigation.tab: tabBar
actionButtonFunction: function() {
if (nestedStackView.currentIndex === root.pageSettingsApiLanguageList) {
nestedStackView.currentIndex = root.pageSettingsApiServerInfo
} else {
serverNameEditDrawer.open()
serverNameEditDrawer.openTriggered()
}
}
}
DrawerType2 {
id: serverNameEditDrawer
objectName: "serverNameEditDrawer"
parent: root
anchors.fill: parent
expandedHeight: root.height * 0.35
onClosed: {
if (!GC.isMobile()) {
headerContent.actionButton.forceActiveFocus()
}
}
expandedContent: ColumnLayout {
expandedStateContent: ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@ -147,19 +137,6 @@ PageType {
anchors.leftMargin: 16
anchors.rightMargin: 16
Connections {
target: serverNameEditDrawer
enabled: !GC.isMobile()
function onOpened() {
serverName.textField.forceActiveFocus()
}
}
Item {
id: focusItem1
KeyNavigation.tab: serverName.textField
}
TextFieldWithHeaderType {
id: serverName
@ -168,8 +145,6 @@ PageType {
textFieldText: root.processedServer.name
textField.maximumLength: 30
checkEmptyText: true
KeyNavigation.tab: saveButton
}
BasicButtonType {
@ -178,7 +153,6 @@ PageType {
Layout.fillWidth: true
text: qsTr("Save")
KeyNavigation.tab: focusItem1
clickedFunc: function() {
if (serverName.textFieldText === "") {
@ -188,7 +162,7 @@ PageType {
if (serverName.textFieldText !== root.processedServer.name) {
ServersModel.setProcessedServerData("name", serverName.textFieldText);
}
serverNameEditDrawer.close()
serverNameEditDrawer.closeTriggered()
}
}
}
@ -209,35 +183,27 @@ PageType {
visible: !ServersModel.getProcessedServerData("isServerFromGatewayApi")
activeFocusOnTab: true
onFocusChanged: {
if (activeFocus) {
protocolsTab.forceActiveFocus()
}
}
TabButtonType {
id: protocolsTab
visible: protocolsPage.installedProtocolsCount
width: protocolsPage.installedProtocolsCount ? undefined : 0
isSelected: tabBar.currentIndex === root.pageSettingsServerProtocols
isSelected: TabBar.tabBar.currentIndex === root.pageSettingsServerProtocols
text: qsTr("Protocols")
KeyNavigation.tab: servicesTab
Keys.onReturnPressed: tabBar.currentIndex = root.pageSettingsServerProtocols
Keys.onEnterPressed: tabBar.currentIndex = root.pageSettingsServerProtocols
Keys.onReturnPressed: TabBar.tabBar.setCurrentIndex(root.pageSettingsServerProtocols)
Keys.onEnterPressed: TabBar.tabBar.setCurrentIndex(root.pageSettingsServerProtocols)
}
TabButtonType {
id: servicesTab
visible: servicesPage.installedServicesCount
width: servicesPage.installedServicesCount ? undefined : 0
isSelected: tabBar.currentIndex === root.pageSettingsServerServices
isSelected: TabBar.tabBar.currentIndex === root.pageSettingsServerServices
text: qsTr("Services")
KeyNavigation.tab: dataTab
Keys.onReturnPressed: tabBar.currentIndex = root.pageSettingsServerServices
Keys.onEnterPressed: tabBar.currentIndex = root.pageSettingsServerServices
Keys.onReturnPressed: TabBar.tabBar.setCurrentIndex(root.pageSettingsServerServices)
Keys.onEnterPressed: TabBar.tabBar.setCurrentIndex(root.pageSettingsServerServices)
}
TabButtonType {
@ -245,22 +211,14 @@ PageType {
isSelected: tabBar.currentIndex === root.pageSettingsServerData
text: qsTr("Management")
Keys.onReturnPressed: tabBar.currentIndex = root.pageSettingsServerData
Keys.onEnterPressed: tabBar.currentIndex = root.pageSettingsServerData
Keys.onTabPressed: function() {
if (nestedStackView.currentIndex === root.pageSettingsServerProtocols) {
return protocolsPage
} else if (nestedStackView.currentIndex === root.pageSettingsServerProtocols) {
return servicesPage
} else {
return dataPage
}
}
Keys.onReturnPressed: TabBar.tabBar.setCurrentIndex(root.pageSettingsServerData)
Keys.onEnterPressed: TabBar.tabBar.setCurrentIndex(root.pageSettingsServerData)
}
}
StackLayout {
id: nestedStackView
Layout.fillWidth: true
currentIndex: ServersModel.getProcessedServerData("isServerFromGatewayApi") ?
@ -270,38 +228,27 @@ PageType {
PageSettingsServerProtocols {
id: protocolsPage
stackView: root.stackView
onLastItemTabClickedSignal: lastItemTabClicked(focusItem)
}
PageSettingsServerServices {
id: servicesPage
stackView: root.stackView
onLastItemTabClickedSignal: lastItemTabClicked(focusItem)
}
PageSettingsServerData {
id: dataPage
stackView: root.stackView
onLastItemTabClickedSignal: lastItemTabClicked(focusItem)
}
PageSettingsApiServerInfo {
id: apiInfoPage
stackView: root.stackView
// onLastItemTabClickedSignal: lastItemTabClicked(focusItem)
}
PageSettingsApiLanguageList {
id: apiLanguageListPage
stackView: root.stackView
// onLastItemTabClickedSignal: lastItemTabClicked(focusItem)
}
}
}
}

View file

@ -21,13 +21,6 @@ PageType {
property bool isClearCacheVisible: ServersModel.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ContainersModel.getProcessedContainerIndex())
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: header
@ -39,7 +32,6 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: protocols
}
HeaderType {
@ -57,30 +49,36 @@ PageType {
height: protocols.contentItem.height
clip: true
interactive: true
model: ProtocolsModel
property int currentFocusIndex: 0
activeFocusOnTab: true
onActiveFocusChanged: {
if (activeFocus) {
this.currentFocusIndex = 0
protocols.itemAtIndex(currentFocusIndex).focusItem.forceActiveFocus()
}
}
property bool isFocusable: true
Keys.onTabPressed: {
if (currentFocusIndex < this.count - 1) {
currentFocusIndex += 1
protocols.itemAtIndex(currentFocusIndex).focusItem.forceActiveFocus()
} else {
clearCacheButton.forceActiveFocus()
}
FocusController.nextKeyTabItem()
}
delegate: Item {
property var focusItem: clientSettings.rightButton
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
model: ProtocolsModel
delegate: Item {
implicitWidth: protocols.width
implicitHeight: delegateContent.implicitHeight
@ -160,109 +158,112 @@ PageType {
}
}
}
}
LabelWithButtonType {
id: clearCacheButton
footer: ColumnLayout {
width: header.width
Layout.fillWidth: true
LabelWithButtonType {
id: clearCacheButton
visible: root.isClearCacheVisible
KeyNavigation.tab: removeButton
Layout.fillWidth: true
text: qsTr("Clear profile")
visible: root.isClearCacheVisible
clickedFunction: function() {
var headerText = qsTr("Clear %1 profile?").arg(ContainersModel.getProcessedContainerName())
var descriptionText = qsTr("The connection configuration will be deleted for this device only")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
text: qsTr("Clear profile")
var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
var message = qsTr("Unable to clear %1 profile while there is an active connection").arg(ContainersModel.getProcessedContainerName())
PageController.showNotificationMessage(message)
return
clickedFunction: function() {
var headerText = qsTr("Clear %1 profile?").arg(ContainersModel.getProcessedContainerName())
var descriptionText = qsTr("The connection configuration will be deleted for this device only")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
var message = qsTr("Unable to clear %1 profile while there is an active connection").arg(ContainersModel.getProcessedContainerName())
PageController.showNotificationMessage(message)
return
}
PageController.showBusyIndicator(true)
InstallController.clearCachedProfile()
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
// if (!GC.isMobile()) {
// focusItem.forceActiveFocus()
// }
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
PageController.showBusyIndicator(true)
InstallController.clearCachedProfile()
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
MouseArea {
anchors.fill: clearCacheButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
MouseArea {
anchors.fill: clearCacheButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: root.isClearCacheVisible
}
LabelWithButtonType {
id: removeButton
Layout.fillWidth: true
visible: ServersModel.isProcessedServerHasWriteAccess()
Keys.onTabPressed: lastItemTabClicked(focusItem)
text: qsTr("Remove ")
textColor: AmneziaStyle.color.vibrantRed
clickedFunction: function() {
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
&& ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Cannot remove active container"))
} else
{
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeProcessedContainer()
}
visible: root.isClearCacheVisible
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
LabelWithButtonType {
id: removeButton
Layout.fillWidth: true
visible: ServersModel.isProcessedServerHasWriteAccess()
text: qsTr("Remove ")
textColor: AmneziaStyle.color.vibrantRed
clickedFunction: function() {
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
&& ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Cannot remove active container"))
} else
{
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeProcessedContainer()
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
MouseArea {
anchors.fill: removeButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
MouseArea {
anchors.fill: removeButton
cursorShape: Qt.PointingHandCursor
enabled: false
visible: ServersModel.isProcessedServerHasWriteAccess()
}
}
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: ServersModel.isProcessedServerHasWriteAccess()
}
}
}

View file

@ -21,53 +21,45 @@ PageType {
property var installedProtocolsCount
onFocusChanged: settingsContainersListView.forceActiveFocus()
signal lastItemTabClickedSignal()
function resetView() {
settingsContainersListView.positionViewAtBeginning()
}
FlickableType {
id: fl
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
SettingsContainersListView {
id: settingsContainersListView
Column {
id: content
anchors.fill: parent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Connections {
target: ServersModel
SettingsContainersListView {
id: settingsContainersListView
Connections {
target: ServersModel
function onProcessedServerIndexChanged() {
settingsContainersListView.updateContainersModelFilters()
}
}
function updateContainersModelFilters() {
if (ServersModel.isProcessedServerHasWriteAccess()) {
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters()
} else {
proxyContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters()
}
root.installedProtocolsCount = proxyContainersModel.count
}
model: SortFilterProxyModel {
id: proxyContainersModel
sourceModel: ContainersModel
sorters: [
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder },
RoleSorter { roleName: "installPageOrder"; sortOrder: Qt.AscendingOrder }
]
}
Component.onCompleted: updateContainersModelFilters()
function onProcessedServerIndexChanged() {
settingsContainersListView.updateContainersModelFilters()
}
}
function updateContainersModelFilters() {
if (ServersModel.isProcessedServerHasWriteAccess()) {
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessProtocolsListFilters()
} else {
proxyContainersModel.filters = ContainersModelFilters.getReadAccessProtocolsListFilters()
}
root.installedProtocolsCount = proxyContainersModel.count
}
model: SortFilterProxyModel {
id: proxyContainersModel
sourceModel: ContainersModel
sorters: [
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder },
RoleSorter { roleName: "installPageOrder"; sortOrder: Qt.AscendingOrder }
]
}
Component.onCompleted: {
settingsContainersListView.isFocusable = true
settingsContainersListView.interactive = true
updateContainersModelFilters()
}
}
}

View file

@ -21,52 +21,40 @@ PageType {
property var installedServicesCount
onFocusChanged: settingsContainersListView.forceActiveFocus()
signal lastItemTabClickedSignal()
SettingsContainersListView {
id: settingsContainersListView
FlickableType {
id: fl
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight
anchors.fill: parent
Column {
id: content
Connections {
target: ServersModel
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
SettingsContainersListView {
id: settingsContainersListView
Connections {
target: ServersModel
function onProcessedServerIndexChanged() {
settingsContainersListView.updateContainersModelFilters()
}
}
function updateContainersModelFilters() {
if (ServersModel.isProcessedServerHasWriteAccess()) {
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessServicesListFilters()
} else {
proxyContainersModel.filters = ContainersModelFilters.getReadAccessServicesListFilters()
}
root.installedServicesCount = proxyContainersModel.count
}
model: SortFilterProxyModel {
id: proxyContainersModel
sourceModel: ContainersModel
sorters: [
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder }
]
}
Component.onCompleted: updateContainersModelFilters()
function onProcessedServerIndexChanged() {
settingsContainersListView.updateContainersModelFilters()
}
}
function updateContainersModelFilters() {
if (ServersModel.isProcessedServerHasWriteAccess()) {
proxyContainersModel.filters = ContainersModelFilters.getWriteAccessServicesListFilters()
} else {
proxyContainersModel.filters = ContainersModelFilters.getReadAccessServicesListFilters()
}
root.installedServicesCount = proxyContainersModel.count
}
model: SortFilterProxyModel {
id: proxyContainersModel
sourceModel: ContainersModel
sorters: [
RoleSorter { roleName: "isInstalled"; sortOrder: Qt.DescendingOrder }
]
}
Component.onCompleted: {
settingsContainersListView.isFocusable = true
settingsContainersListView.interactive = true
updateContainersModelFilters()
}
}
}

View file

@ -18,13 +18,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
ColumnLayout {
id: header
@ -36,7 +29,6 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: servers
}
HeaderType {
@ -48,95 +40,64 @@ PageType {
}
}
FlickableType {
id: fl
ListView {
id: servers
objectName: "servers"
width: parent.width
anchors.top: header.bottom
anchors.topMargin: 16
contentHeight: col.implicitHeight
anchors.left: parent.left
anchors.right: parent.right
Column {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: 500
ListView {
id: servers
width: parent.width
height: servers.contentItem.height
property bool isFocusable: true
model: ServersModel
model: ServersModel
clip: true
interactive: false
clip: true
reuseItems: true
activeFocusOnTab: true
focus: true
Keys.onTabPressed: {
if (currentIndex < servers.count - 1) {
servers.incrementCurrentIndex()
} else {
servers.currentIndex = 0
focusItem.forceActiveFocus()
root.lastItemTabClicked()
}
delegate: Item {
implicitWidth: servers.width
implicitHeight: delegateContent.implicitHeight
fl.ensureVisible(this.currentItem)
}
ColumnLayout {
id: delegateContent
onVisibleChanged: {
if (visible) {
currentIndex = 0
}
}
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
delegate: Item {
implicitWidth: servers.width
implicitHeight: delegateContent.implicitHeight
LabelWithButtonType {
id: server
Layout.fillWidth: true
onFocusChanged: {
if (focus) {
server.rightButton.forceActiveFocus()
}
}
text: name
ColumnLayout {
id: delegateContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelWithButtonType {
id: server
Layout.fillWidth: true
text: name
parentFlickable: fl
descriptionText: {
var servicesNameString = ""
var servicesName = ServersModel.getAllInstalledServicesName(index)
for (var i = 0; i < servicesName.length; i++) {
servicesNameString += servicesName[i] + " · "
}
if (ServersModel.isServerFromApi(index)) {
return servicesNameString + serverDescription
} else {
return servicesNameString + hostName
}
}
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
ServersModel.processedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
}
descriptionText: {
var servicesNameString = ""
var servicesName = ServersModel.getAllInstalledServicesName(index)
for (var i = 0; i < servicesName.length; i++) {
servicesNameString += servicesName[i] + " · "
}
DividerType {}
if (ServersModel.isServerFromApi(index)) {
return servicesNameString + serverDescription
} else {
return servicesNameString + hostName
}
}
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
ServersModel.processedIndex = index
PageController.goToPage(PageEnum.PageSettingsServerInfo)
}
}
DividerType {}
}
}
}

View file

@ -23,13 +23,6 @@ PageType {
property var isServerFromTelegramApi: ServersModel.getDefaultServerData("isServerFromTelegramApi")
defaultActiveFocusItem: searchField.textField
Item {
id: focusItem
KeyNavigation.tab: backButton
}
property bool pageEnabled
Component.onCompleted: {
@ -99,7 +92,6 @@ PageType {
BackButtonType {
id: backButton
KeyNavigation.tab: switcher
}
RowLayout {
@ -129,8 +121,6 @@ PageType {
onToggled: { onToggledFunc() }
Keys.onEnterPressed: { onToggledFunc() }
Keys.onReturnPressed: { onToggledFunc() }
KeyNavigation.tab: selector
}
}
@ -154,18 +144,17 @@ PageType {
model: root.routeModesModel
currentIndex: getRouteModesModelIndex()
clickedFunction: function() {
selector.text = selectedText
selector.close()
if (SitesModel.routeMode !== root.routeModesModel[currentIndex].type) {
SitesModel.routeMode = root.routeModesModel[currentIndex].type
selector.closeTriggered()
if (SitesModel.routeMode !== root.routeModesModel[selectedIndex].type) {
SitesModel.routeMode = root.routeModesModel[selectedIndex].type
}
}
Component.onCompleted: {
if (root.routeModesModel[currentIndex].type === SitesModel.routeMode) {
if (root.routeModesModel[selectedIndex].type === SitesModel.routeMode) {
selector.text = selectedText
} else {
selector.text = root.routeModesModel[0].name
@ -175,128 +164,89 @@ PageType {
Connections {
target: SitesModel
function onRouteModeChanged() {
currentIndex = getRouteModesModelIndex()
selectedIndex = getRouteModesModelIndex()
}
}
}
KeyNavigation.tab: {
return sites.count > 0 ?
sites :
searchField.textField
}
}
}
FlickableType {
id: fl
ListView {
id: listView
anchors.top: header.bottom
anchors.topMargin: 16
contentHeight: col.implicitHeight + addSiteButton.implicitHeight + addSiteButton.anchors.bottomMargin + addSiteButton.anchors.topMargin
anchors.bottom: addSiteButton.top
width: parent.width
enabled: root.pageEnabled
Column {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
property bool isFocusable: true
ListView {
id: sites
width: parent.width
height: sites.contentItem.height
model: SortFilterProxyModel {
id: proxySitesModel
sourceModel: SitesModel
filters: [
AnyOf {
RegExpFilter {
roleName: "url"
pattern: ".*" + searchField.textField.text + ".*"
caseSensitivity: Qt.CaseInsensitive
}
RegExpFilter {
roleName: "ip"
pattern: ".*" + searchField.textField.text + ".*"
caseSensitivity: Qt.CaseInsensitive
}
}
]
}
clip: true
interactive: false
activeFocusOnTab: true
focus: true
Keys.onTabPressed: {
if (currentIndex < this.count - 1) {
this.incrementCurrentIndex()
} else {
currentIndex = 0
searchField.textField.forceActiveFocus()
model: SortFilterProxyModel {
id: proxySitesModel
sourceModel: SitesModel
filters: [
AnyOf {
RegExpFilter {
roleName: "url"
pattern: ".*" + searchField.textField.text + ".*"
caseSensitivity: Qt.CaseInsensitive
}
RegExpFilter {
roleName: "ip"
pattern: ".*" + searchField.textField.text + ".*"
caseSensitivity: Qt.CaseInsensitive
}
fl.ensureVisible(currentItem)
}
]
}
delegate: Item {
implicitWidth: sites.width
implicitHeight: delegateContent.implicitHeight
clip: true
onActiveFocusChanged: {
if (activeFocus) {
reuseItems: true
delegate: ColumnLayout {
id: delegateContent
width: listView.width
LabelWithButtonType {
id: site
Layout.fillWidth: true
text: url
descriptionText: ip
rightImageSource: "qrc:/images/controls/trash.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
var headerText = qsTr("Remove ") + url + "?"
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
SitesController.removeSite(proxySitesModel.mapToSource(index))
if (!GC.isMobile()) {
site.rightButton.forceActiveFocus()
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
site.rightButton.forceActiveFocus()
}
}
ColumnLayout {
id: delegateContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelWithButtonType {
id: site
Layout.fillWidth: true
text: url
descriptionText: ip
rightImageSource: "qrc:/images/controls/trash.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
var headerText = qsTr("Remove ") + url + "?"
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
SitesController.removeSite(proxySitesModel.mapToSource(index))
if (!GC.isMobile()) {
site.rightButton.forceActiveFocus()
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
site.rightButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
DividerType {}
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
DividerType {}
}
}
Rectangle {
anchors.fill: addSiteButton
anchors.bottomMargin: -24
@ -325,7 +275,6 @@ PageType {
textFieldPlaceholderText: qsTr("website or IP")
buttonImageSource: "qrc:/images/controls/plus.svg"
KeyNavigation.tab: GC.isMobile() ? focusItem : addSiteButtonImage
clickedFunc: function() {
PageController.showBusyIndicator(true)
@ -344,13 +293,11 @@ PageType {
imageColor: AmneziaStyle.color.paleGray
onClicked: function () {
moreActionsDrawer.open()
moreActionsDrawer.openTriggered()
}
Keys.onReturnPressed: addSiteButtonImage.clicked()
Keys.onEnterPressed: addSiteButtonImage.clicked()
Keys.onTabPressed: lastItemTabClicked(focusItem)
}
}
@ -360,38 +307,13 @@ PageType {
anchors.fill: parent
expandedHeight: parent.height * 0.4375
onClosed: {
if (root.defaultActiveFocusItem && !GC.isMobile()) {
root.defaultActiveFocusItem.forceActiveFocus()
}
}
expandedContent: ColumnLayout {
expandedStateContent: ColumnLayout {
id: moreActionsDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Connections {
target: moreActionsDrawer
function onOpened() {
focusItem1.forceActiveFocus()
}
function onActiveFocusChanged() {
if (!GC.isMobile()) {
focusItem1.forceActiveFocus()
}
}
}
Item {
id: focusItem1
KeyNavigation.tab: importSitesButton.rightButton
}
Header2Type {
Layout.fillWidth: true
Layout.margins: 16
@ -407,21 +329,18 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
importSitesDrawer.open()
importSitesDrawer.openTriggered()
}
KeyNavigation.tab: exportSitesButton
}
DividerType {}
LabelWithButtonType {
id: exportSitesButton
enabled: !SettingsController.isOnTv()
Layout.fillWidth: true
text: qsTr("Save site list")
KeyNavigation.tab: focusItem1
clickedFunction: function() {
var fileName = ""
if (GC.isMobile()) {
@ -436,13 +355,15 @@ PageType {
if (fileName !== "") {
PageController.showBusyIndicator(true)
SitesController.exportSites(fileName)
moreActionsDrawer.close()
moreActionsDrawer.closeTriggered()
PageController.showBusyIndicator(false)
}
}
}
DividerType {}
DividerType {
enabled: !SettingsController.isOnTv()
}
}
}
@ -452,28 +373,9 @@ PageType {
anchors.fill: parent
expandedHeight: parent.height * 0.4375
onClosed: {
if (!GC.isMobile()) {
moreActionsDrawer.forceActiveFocus()
}
}
expandedContent: Item {
expandedStateContent: Item {
implicitHeight: importSitesDrawer.expandedHeight
Connections {
target: importSitesDrawer
enabled: !GC.isMobile()
function onOpened() {
focusItem2.forceActiveFocus()
}
}
Item {
id: focusItem2
KeyNavigation.tab: importSitesDrawerBackButton
}
BackButtonType {
id: importSitesDrawerBackButton
@ -482,10 +384,8 @@ PageType {
anchors.right: parent.right
anchors.topMargin: 16
KeyNavigation.tab: importSitesButton2
backButtonFunction: function() {
importSitesDrawer.close()
importSitesDrawer.closeTriggered()
}
}
@ -516,7 +416,6 @@ PageType {
Layout.fillWidth: true
text: qsTr("Replace site list")
KeyNavigation.tab: importSitesButton3
clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
@ -533,7 +432,6 @@ PageType {
id: importSitesButton3
Layout.fillWidth: true
text: qsTr("Add imported sites to existing ones")
KeyNavigation.tab: focusItem2
clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
@ -548,8 +446,8 @@ PageType {
PageController.showBusyIndicator(true)
SitesController.importSites(fileName, replaceExistingSites)
PageController.showBusyIndicator(false)
importSitesDrawer.close()
moreActionsDrawer.close()
importSitesDrawer.closeTriggered()
moreActionsDrawer.closeTriggered()
}
DividerType {}

View file

@ -15,8 +15,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
FlickableType {
id: fl
anchors.top: parent.top
@ -32,15 +30,9 @@ PageType {
spacing: 0
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
Layout.topMargin: 20
// KeyNavigation.tab: fileButton.rightButton
}
HeaderType {

View file

@ -14,8 +14,6 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: focusItem
ColumnLayout {
id: header
@ -25,15 +23,9 @@ PageType {
spacing: 0
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
Layout.topMargin: 20
// KeyNavigation.tab: fileButton.rightButton
}
HeaderType {
@ -50,6 +42,7 @@ PageType {
ListView {
id: servicesListView
anchors.top: header.bottom
anchors.right: parent.right
anchors.left: parent.left
@ -57,16 +50,21 @@ PageType {
anchors.topMargin: 16
spacing: 0
currentIndex: 1
property bool isFocusable: true
clip: true
reuseItems: true
model: ApiServicesModel
ScrollBar.vertical: ScrollBar {}
ScrollBar.vertical: ScrollBarType {}
delegate: Item {
implicitWidth: servicesListView.width
implicitHeight: delegateContent.implicitHeight
enabled: isServiceAvailable
ColumnLayout {
id: delegateContent
@ -86,14 +84,15 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg"
enabled: isServiceAvailable
onClicked: {
if (isServiceAvailable) {
ApiServicesModel.setServiceIndex(index)
PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
}
}
Keys.onEnterPressed: clicked()
Keys.onReturnPressed: clicked()
}
}
}

View file

@ -25,31 +25,29 @@ PageType {
}
}
defaultActiveFocusItem: focusItem
ListView {
id: listView
FlickableType {
id: fl
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.height
anchors.fill: parent
ColumnLayout {
id: content
property bool isFocusable: true
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
ScrollBar.vertical: ScrollBarType {}
spacing: 0
model: variants
Item {
id: focusItem
KeyNavigation.tab: textKey.textField
}
clip: true
reuseItems: true
header: ColumnLayout {
width: listView.width
HeaderType {
property bool isVisible: SettingsController.getInstallationUuid() !== "" || PageController.isStartPageVisible()
id: moreButton
property bool isVisible: SettingsController.getInstallationUuid() !== "" || PageController.isStartPageVisible()
Layout.fillWidth: true
Layout.topMargin: 24
Layout.rightMargin: 16
@ -59,7 +57,7 @@ PageType {
actionButtonImage: isVisible ? "qrc:/images/controls/more-vertical.svg" : ""
actionButtonFunction: function() {
moreActionsDrawer.open()
moreActionsDrawer.openTriggered()
}
DrawerType2 {
@ -70,7 +68,7 @@ PageType {
anchors.fill: parent
expandedHeight: root.height * 0.5
expandedContent: ColumnLayout {
expandedStateContent: ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@ -130,6 +128,8 @@ PageType {
}
ParagraphTextType {
objectName: "insertKeyLabel"
Layout.fillWidth: true
Layout.topMargin: 32
Layout.rightMargin: 16
@ -153,8 +153,6 @@ PageType {
textField.text = ""
textField.paste()
}
KeyNavigation.tab: continueButton
}
BasicButtonType {
@ -168,7 +166,6 @@ PageType {
visible: textKey.textFieldText !== ""
text: qsTr("Continue")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
if (ImportController.extractConfigFromData(textKey.textFieldText)) {
@ -187,143 +184,129 @@ PageType {
color: AmneziaStyle.color.charcoalGray
text: qsTr("Other connection options")
}
}
delegate: ColumnLayout {
width: listView.width
CardWithIconsType {
id: apiInstalling
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("VPN by Amnezia")
bodyText: qsTr("Connect to classic paid and free VPN services from Amnezia")
visible: isVisible
headerText: title
bodyText: description
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/amnezia.svg"
leftImageSource: imageSource
onClicked: function() {
PageController.showBusyIndicator(true)
var result = InstallController.fillAvailableServices()
PageController.showBusyIndicator(false)
if (result) {
PageController.goToPage(PageEnum.PageSetupWizardApiServicesList)
}
}
onClicked: { handler() }
}
}
}
CardWithIconsType {
id: manualInstalling
property list<QtObject> variants: [
amneziaVpn,
selfHostVpn,
backupRestore,
fileOpen,
qrScan,
siteLink
]
QtObject {
id: amneziaVpn
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("Self-hosted VPN")
bodyText: qsTr("Configure Amnezia VPN on your own server")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/server.svg"
onClicked: {
PageController.goToPage(PageEnum.PageSetupWizardCredentials)
}
property string title: qsTr("VPN by Amnezia")
property string description: qsTr("Connect to classic paid and free VPN services from Amnezia")
property string imageSource: "qrc:/images/controls/amnezia.svg"
property bool isVisible: true
property var handler: function() {
PageController.showBusyIndicator(true)
var result = InstallController.fillAvailableServices()
PageController.showBusyIndicator(false)
if (result) {
PageController.goToPage(PageEnum.PageSetupWizardApiServicesList)
}
}
}
CardWithIconsType {
id: backupRestore
QtObject {
id: selfHostVpn
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
property string title: qsTr("Self-hosted VPN")
property string description: qsTr("Configure Amnezia VPN on your own server")
property string imageSource: "qrc:/images/controls/server.svg"
property bool isVisible: true
property var handler: function() {
PageController.goToPage(PageEnum.PageSetupWizardCredentials)
}
}
visible: PageController.isStartPageVisible()
QtObject {
id: backupRestore
headerText: qsTr("Restore from backup")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/archive-restore.svg"
onClicked: {
var filePath = SystemController.getFileName(qsTr("Open backup file"),
qsTr("Backup files (*.backup)"))
if (filePath !== "") {
PageController.showBusyIndicator(true)
SettingsController.restoreAppConfig(filePath)
PageController.showBusyIndicator(false)
}
}
property string title: qsTr("Restore from backup")
property string description: qsTr("")
property string imageSource: "qrc:/images/controls/archive-restore.svg"
property bool isVisible: PageController.isStartPageVisible()
property var handler: function() {
var filePath = SystemController.getFileName(qsTr("Open backup file"),
qsTr("Backup files (*.backup)"))
if (filePath !== "") {
PageController.showBusyIndicator(true)
SettingsController.restoreAppConfig(filePath)
PageController.showBusyIndicator(false)
}
}
}
CardWithIconsType {
id: openFile
QtObject {
id: fileOpen
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("File with connection settings")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/folder-search-2.svg"
onClicked: {
var nameFilter = !ServersModel.getServersCount() ? "Config or backup files (*.vpn *.ovpn *.conf *.json *.backup)" :
"Config files (*.vpn *.ovpn *.conf *.json)"
var fileName = SystemController.getFileName(qsTr("Open config file"), nameFilter)
if (fileName !== "") {
if (ImportController.extractConfigFromFile(fileName)) {
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
}
}
}
}
CardWithIconsType {
id: scanQr
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
visible: SettingsController.isCameraPresent()
headerText: qsTr("QR code")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/scan-line.svg"
onClicked: {
ImportController.startDecodingQr()
if (Qt.platform.os === "ios") {
PageController.goToPage(PageEnum.PageSetupWizardQrReader)
}
}
}
CardWithIconsType {
id: siteLink
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
visible: PageController.isStartPageVisible()
headerText: qsTr("I have nothing")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/help-circle.svg"
onClicked: {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
property string title: qsTr("File with connection settings")
property string description: qsTr("")
property string imageSource: "qrc:/images/controls/folder-search-2.svg"
property bool isVisible: true
property var handler: function() {
var nameFilter = !ServersModel.getServersCount() ? "Config or backup files (*.vpn *.ovpn *.conf *.json *.backup)" :
"Config files (*.vpn *.ovpn *.conf *.json)"
var fileName = SystemController.getFileName(qsTr("Open config file"), nameFilter)
if (fileName !== "") {
if (ImportController.extractConfigFromFile(fileName)) {
PageController.goToPage(PageEnum.PageSetupWizardViewConfig)
}
}
}
}
QtObject {
id: qrScan
property string title: qsTr("QR code")
property string description: qsTr("")
property string imageSource: "qrc:/images/controls/scan-line.svg"
property bool isVisible: SettingsController.isCameraPresent()
property var handler: function() {
ImportController.startDecodingQr()
if (Qt.platform.os === "ios") {
PageController.goToPage(PageEnum.PageSetupWizardQrReader)
}
}
}
QtObject {
id: siteLink
property string title: qsTr("I have nothing")
property string description: qsTr("")
property string imageSource: "qrc:/images/controls/help-circle.svg"
property bool isVisible: PageController.isStartPageVisible()
property var handler: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
}
}
}

View file

@ -13,13 +13,6 @@ import "../Controls2/TextTypes"
PageType {
id: root
defaultActiveFocusItem: hostname.textField
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@ -28,100 +21,133 @@ PageType {
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: hostname.textField
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
}
FlickableType {
id: fl
ListView {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
contentHeight: content.height
anchors.right: parent.right
anchors.left: parent.left
ColumnLayout {
id: content
property bool isFocusable: true
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
spacing: 16
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
ScrollBar.vertical: ScrollBarType {}
header: ColumnLayout {
width: listView.width
HeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("Configure your server")
}
}
model: inputFields
spacing: 16
clip: true
reuseItems: true
delegate: ColumnLayout {
property alias textField: _textField.textField
width: listView.width
TextFieldWithHeaderType {
id: hostname
id: _textField
Layout.fillWidth: true
headerText: qsTr("Server IP address [:port]")
textFieldPlaceholderText: qsTr("255.255.255.255:22")
Layout.leftMargin: 16
Layout.rightMargin: 16
textField.onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
}
property bool hidePassword: hideText
KeyNavigation.tab: username.textField
}
headerText: title
textField.echoMode: hideText ? TextInput.Password : TextInput.Normal
buttonImageSource: imageSource
textFieldPlaceholderText: placeholderText
textField.text: textFieldText
TextFieldWithHeaderType {
id: username
rightButtonClickedOnEnter: true
Layout.fillWidth: true
headerText: qsTr("SSH Username")
textFieldPlaceholderText: "root"
textField.onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
}
KeyNavigation.tab: secretData.textField
}
TextFieldWithHeaderType {
id: secretData
property bool hidePassword: true
Layout.fillWidth: true
headerText: qsTr("Password or SSH private key")
textField.echoMode: hidePassword ? TextInput.Password : TextInput.Normal
buttonImageSource: textFieldText !== "" ? (hidePassword ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg")
: ""
clickedFunc: function() {
hidePassword = !hidePassword
clickedFunc: function () {
clickedHandler()
}
textField.onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
var _currentIndex = listView.currentIndex
var _currentItem = listView.itemAtIndex(_currentIndex).children[0]
listView.model[_currentIndex].textFieldText = _currentItem.textFieldText.replace(/^\s+|\s+$/g, '')
}
KeyNavigation.tab: continueButton
textField.onTextChanged: {
var _currentIndex = listView.currentIndex
textFieldText = textField.text
if (_currentIndex === vars.secretDataIndex) {
buttonImageSource = textFieldText !== "" ? (hideText ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg") : ""
}
}
}
}
footer: ColumnLayout {
width: listView.width
BasicButtonType {
id: continueButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Continue")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
forceActiveFocus()
if (!isCredentialsFilled()) {
if (!root.isCredentialsFilled()) {
return
}
InstallController.setShouldCreateServer(true)
InstallController.setProcessedServerCredentials(hostname.textField.text, username.textField.text, secretData.textField.text)
var _hostname = listView.itemAtIndex(vars.hostnameIndex).children[0].textFieldText
var _username = listView.itemAtIndex(vars.usernameIndex).children[0].textFieldText
var _secretData = listView.itemAtIndex(vars.secretDataIndex).children[0].textFieldText
InstallController.setProcessedServerCredentials(_hostname, _username, _secretData)
PageController.showBusyIndicator(true)
var isConnectionOpened = InstallController.checkSshConnection()
@ -136,7 +162,10 @@ PageType {
LabelTextType {
Layout.fillWidth: true
Layout.topMargin: 12
Layout.topMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 16
text: qsTr("All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties")
}
@ -145,6 +174,8 @@ PageType {
id: siteLink
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("How to run your VPN server")
@ -163,21 +194,78 @@ PageType {
function isCredentialsFilled() {
var hasEmptyField = false
if (hostname.textFieldText === "") {
hostname.errorText = qsTr("Ip address cannot be empty")
var _hostname = listView.itemAtIndex(vars.hostnameIndex).children[0]
if (_hostname.textFieldText === "") {
_hostname.errorText = qsTr("Ip address cannot be empty")
hasEmptyField = true
} else if (!hostname.textField.acceptableInput) {
hostname.errorText = qsTr("Enter the address in the format 255.255.255.255:88")
} else if (!_hostname.textField.acceptableInput) {
_hostname.errorText = qsTr("Enter the address in the format 255.255.255.255:88")
}
if (username.textFieldText === "") {
username.errorText = qsTr("Login cannot be empty")
var _username = listView.itemAtIndex(vars.usernameIndex).children[0]
if (_username.textFieldText === "") {
_username.errorText = qsTr("Login cannot be empty")
hasEmptyField = true
}
if (secretData.textFieldText === "") {
secretData.errorText = qsTr("Password/private key cannot be empty")
var _secretData = listView.itemAtIndex(vars.secretDataIndex).children[0]
if (_secretData.textFieldText === "") {
_secretData.errorText = qsTr("Password/private key cannot be empty")
hasEmptyField = true
}
return !hasEmptyField
}
property list<QtObject> inputFields: [
hostname,
username,
secretData
]
QtObject {
id: hostname
property string title: qsTr("Server IP address [:port]")
readonly property string placeholderText: qsTr("255.255.255.255:22")
property string textFieldText: ""
property bool hideText: false
property string imageSource: ""
readonly property var clickedHandler: function() {
console.debug(">>> Server IP address text field was clicked!!!")
clicked()
}
}
QtObject {
id: username
property string title: qsTr("SSH Username")
readonly property string placeholderText: "root"
property string textFieldText: ""
property bool hideText: false
property string imageSource: ""
readonly property var clickedHandler: undefined
}
QtObject {
id: secretData
property string title: qsTr("Password or SSH private key")
readonly property string placeholderText: ""
property string textFieldText: ""
property bool hideText: true
property string imageSource: textFieldText !== "" ? (hideText ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg") : ""
readonly property var clickedHandler: function() {
hideText = !hideText
}
}
QtObject {
id: vars
readonly property int hostnameIndex: 0
readonly property int usernameIndex: 1
readonly property int secretDataIndex: 2
}
}

View file

@ -17,7 +17,6 @@ PageType {
id: root
property bool isEasySetup: true
defaultActiveFocusItem: focusItem
SortFilterProxyModel {
id: proxyContainersModel
@ -34,14 +33,6 @@ PageType {
}
}
Item {
id: focusItem
implicitWidth: 1
implicitHeight: 54
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@ -49,8 +40,6 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: continueButton
}
FlickableType {
@ -98,6 +87,8 @@ PageType {
property int containerDefaultPort
property int containerDefaultTransportProto
property bool isFocusable: true
delegate: Item {
implicitWidth: containers.width
implicitHeight: delegateContent.implicitHeight
@ -163,7 +154,7 @@ PageType {
implicitWidth: parent.width
text: qsTr("Continue")
KeyNavigation.tab: setupLaterButton
parentFlickable: fl
clickedFunc: function() {

View file

@ -49,6 +49,32 @@ PageType {
interactive: false
model: proxyContainersModel
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()
}
delegate: Item {
implicitWidth: processedContainerListView.width
implicitHeight: (delegateContent.implicitHeight > root.height) ? delegateContent.implicitHeight : root.height
@ -62,19 +88,12 @@ PageType {
anchors.rightMargin: 16
anchors.leftMargin: 16
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
Layout.topMargin: 20
Layout.rightMargin: -16
Layout.leftMargin: -16
KeyNavigation.tab: showDetailsButton
}
HeaderType {
@ -104,42 +123,19 @@ PageType {
KeyNavigation.tab: transportProtoSelector
clickedFunc: function() {
showDetailsDrawer.open()
showDetailsDrawer.openTriggered()
}
}
DrawerType2 {
id: showDetailsDrawer
parent: root
onClosed: {
if (!GC.isMobile()) {
defaultActiveFocusItem.forceActiveFocus()
}
}
anchors.fill: parent
expandedHeight: parent.height * 0.9
expandedContent: Item {
Connections {
target: showDetailsDrawer
enabled: !GC.isMobile()
function onOpened() {
focusItem2.forceActiveFocus()
}
}
expandedStateContent: Item {
implicitHeight: showDetailsDrawer.expandedHeight
Item {
id: focusItem2
KeyNavigation.tab: showDetailsBackButton
onFocusChanged: {
if (focusItem2.activeFocus) {
fl.contentY = 0
}
}
}
BackButtonType {
id: showDetailsBackButton
@ -148,10 +144,8 @@ PageType {
anchors.right: parent.right
anchors.topMargin: 16
KeyNavigation.tab: showDetailsCloseButton
backButtonFunction: function() {
showDetailsDrawer.close()
showDetailsDrawer.closeTriggered()
}
}
@ -205,10 +199,9 @@ PageType {
parentFlickable: fl
text: qsTr("Close")
Keys.onTabPressed: lastItemTabClicked(focusItem2)
clickedFunc: function() {
showDetailsDrawer.close()
showDetailsDrawer.closeTriggered()
}
}
}
@ -229,8 +222,6 @@ PageType {
Layout.fillWidth: true
rootWidth: root.width
KeyNavigation.tab: (port.visible && port.enabled) ? port.textField : installButton
}
TextFieldWithHeaderType {
@ -242,8 +233,6 @@ PageType {
headerText: qsTr("Port")
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
KeyNavigation.tab: installButton
}
Rectangle {
@ -259,8 +248,6 @@ PageType {
text: qsTr("Install")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
if (!port.textField.acceptableInput &&
ContainerProps.containerTypeToString(dockerContainer) !== "torwebsite" &&
@ -288,11 +275,6 @@ PageType {
var protocolSelectorVisible = ProtocolProps.defaultTransportProtoChangeable(defaultContainerProto)
transportProtoSelector.visible = protocolSelectorVisible
transportProtoHeader.visible = protocolSelectorVisible
if (port.visible && port.enabled)
defaultActiveFocusItem = port.textField
else
defaultActiveFocusItem = focusItem
}
}
}

View file

@ -15,13 +15,6 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
SortFilterProxyModel {
id: proxyContainersModel
sourceModel: ContainersModel
@ -41,126 +34,66 @@ PageType {
}
}
ColumnLayout {
id: backButtonLayout
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
BackButtonType {
id: backButton
KeyNavigation.tab: containers
}
}
FlickableType {
id: fl
anchors.top: backButtonLayout.bottom
ListView {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
contentHeight: content.implicitHeight + content.anchors.topMargin + content.anchors.bottomMargin
anchors.right: parent.right
anchors.left: parent.left
Column {
id: content
property bool isFocusable: true
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottomMargin: 20
ScrollBar.vertical: ScrollBarType {}
Item {
width: parent.width
height: header.implicitHeight
header: ColumnLayout {
width: listView.width
HeaderType {
id: header
HeaderType {
id: header
anchors.fill: parent
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 16
anchors.leftMargin: 16
anchors.rightMargin: 16
headerText: qsTr("VPN protocol")
descriptionText: qsTr("Choose the one with the highest priority for you. Later, you can install other protocols and additional services, such as DNS proxy and SFTP.")
}
}
width: parent.width
model: proxyContainersModel
clip: true
spacing: 0
reuseItems: true
snapMode: ListView.SnapToItem
headerText: qsTr("VPN protocol")
descriptionText: qsTr("Choose the one with the highest priority for you. Later, you can install other protocols and additional services, such as DNS proxy and SFTP.")
delegate: ColumnLayout {
width: listView.width
LabelWithButtonType {
Layout.fillWidth: true
text: name
descriptionText: description
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
ContainersModel.setProcessedContainerIndex(proxyContainersModel.mapToSource(index))
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
}
}
ListView {
id: containers
width: parent.width
height: containers.contentItem.height
// currentIndex: -1
clip: true
interactive: false
model: proxyContainersModel
function ensureCurrentItemVisible() {
if (currentIndex >= 0) {
if (currentItem.y < fl.contentY) {
fl.contentY = currentItem.y
} else if (currentItem.y + currentItem.height + header.height > fl.contentY + fl.height) {
fl.contentY = currentItem.y + currentItem.height + header.height - fl.height + 40 // 40 is a bottom margin
}
}
}
activeFocusOnTab: true
Keys.onTabPressed: {
if (currentIndex < this.count - 1) {
this.incrementCurrentIndex()
} else {
this.currentIndex = 0
focusItem.forceActiveFocus()
}
ensureCurrentItemVisible()
}
onVisibleChanged: {
if (visible) {
currentIndex = 0
}
}
delegate: Item {
implicitWidth: containers.width
implicitHeight: delegateContent.implicitHeight
onActiveFocusChanged: {
if (activeFocus) {
container.rightButton.forceActiveFocus()
}
}
ColumnLayout {
id: delegateContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelWithButtonType {
id: container
Layout.fillWidth: true
text: name
descriptionText: description
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
ContainersModel.setProcessedContainerIndex(proxyContainersModel.mapToSource(index))
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
}
}
DividerType {}
}
}
}
DividerType {}
}
}
}

View file

@ -14,8 +14,6 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: focusItem
ColumnLayout {
id: content
@ -32,11 +30,6 @@ PageType {
Layout.preferredHeight: 287
}
Item {
id: focusItem
KeyNavigation.tab: startButton
}
BasicButtonType {
id: startButton
Layout.fillWidth: true
@ -50,8 +43,6 @@ PageType {
clickedFunc: function() {
PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
}
Keys.onTabPressed: lastItemTabClicked(focusItem)
}
}
}

View file

@ -13,14 +13,6 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: textKey.textField
Item {
id: focusItem
KeyNavigation.tab: backButton
}
FlickableType {
id: fl
anchors.top: parent.top
@ -39,7 +31,6 @@ PageType {
BackButtonType {
id: backButton
Layout.topMargin: 20
KeyNavigation.tab: textKey.textField
}
HeaderType {
@ -67,8 +58,6 @@ PageType {
textField.text = ""
textField.paste()
}
KeyNavigation.tab: continueButton
}
}
}
@ -84,7 +73,6 @@ PageType {
anchors.bottomMargin: 32
text: qsTr("Continue")
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
if (ImportController.extractConfigFromData(textKey.textFieldText)) {

View file

@ -16,13 +16,6 @@ PageType {
property bool showContent: false
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@ -30,8 +23,6 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: showContentButton
}
Connections {
@ -107,7 +98,8 @@ PageType {
textColor: AmneziaStyle.color.goldenApricot
text: showContent ? qsTr("Collapse content") : qsTr("Show content")
KeyNavigation.tab: connectButton
parentFlickable: fl
clickedFunc: function() {
showContent = !showContent
@ -186,8 +178,6 @@ PageType {
anchors.rightMargin: 16
anchors.leftMargin: 16
Keys.onTabPressed: lastItemTabClicked(focusItem)
BasicButtonType {
id: connectButton
Layout.fillWidth: true

View file

@ -18,8 +18,6 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: clientNameTextField.textField
enum ConfigType {
AmneziaConnection,
OpenVpn,
@ -47,7 +45,7 @@ PageType {
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
shareConnectionDrawer.open()
shareConnectionDrawer.openTriggered()
shareConnectionDrawer.contentVisible = false
PageController.showBusyIndicator(true)
@ -104,7 +102,7 @@ PageType {
}
function onExportErrorOccurred(error) {
shareConnectionDrawer.close()
shareConnectionDrawer.closeTriggered()
PageController.showErrorMessage(error)
}
@ -119,38 +117,38 @@ PageType {
QtObject {
id: amneziaConnectionFormat
property string name: qsTr("For the AmneziaVPN app")
property var type: PageShare.ConfigType.AmneziaConnection
readonly property string name: qsTr("For the AmneziaVPN app")
readonly property int type: PageShare.ConfigType.AmneziaConnection
}
QtObject {
id: openVpnConnectionFormat
property string name: qsTr("OpenVPN native format")
property var type: PageShare.ConfigType.OpenVpn
readonly property string name: qsTr("OpenVPN native format")
readonly property int type: PageShare.ConfigType.OpenVpn
}
QtObject {
id: wireGuardConnectionFormat
property string name: qsTr("WireGuard native format")
property var type: PageShare.ConfigType.WireGuard
readonly property string name: qsTr("WireGuard native format")
readonly property int type: PageShare.ConfigType.WireGuard
}
QtObject {
id: awgConnectionFormat
property string name: qsTr("AmneziaWG native format")
property var type: PageShare.ConfigType.Awg
readonly property string name: qsTr("AmneziaWG native format")
readonly property int type: PageShare.ConfigType.Awg
}
QtObject {
id: shadowSocksConnectionFormat
property string name: qsTr("Shadowsocks native format")
property var type: PageShare.ConfigType.ShadowSocks
readonly property string name: qsTr("Shadowsocks native format")
readonly property int type: PageShare.ConfigType.ShadowSocks
}
QtObject {
id: cloakConnectionFormat
property string name: qsTr("Cloak native format")
property var type: PageShare.ConfigType.Cloak
readonly property string name: qsTr("Cloak native format")
readonly property int type: PageShare.ConfigType.Cloak
}
QtObject {
id: xrayConnectionFormat
property string name: qsTr("XRay native format")
property var type: PageShare.ConfigType.Xray
readonly property string name: qsTr("XRay native format")
readonly property int type: PageShare.ConfigType.Xray
}
FlickableType {
@ -172,16 +170,6 @@ PageType {
spacing: 0
Item {
id: focusItem
KeyNavigation.tab: header.actionButton
onFocusChanged: {
if (focusItem.activeFocus) {
a.contentY = 0
}
}
}
HeaderType {
id: header
Layout.fillWidth: true
@ -191,11 +179,9 @@ PageType {
actionButtonImage: "qrc:/images/controls/more-vertical.svg"
actionButtonFunction: function() {
shareFullAccessDrawer.open()
shareFullAccessDrawer.openTriggered()
}
KeyNavigation.tab: connectionRadioButton
DrawerType2 {
id: shareFullAccessDrawer
@ -203,13 +189,8 @@ PageType {
anchors.fill: parent
expandedHeight: root.height
onClosed: {
if (!GC.isMobile()) {
clientNameTextField.textField.forceActiveFocus()
}
}
expandedContent: ColumnLayout {
expandedStateContent: ColumnLayout {
id: shareFullAccessDrawerContent
anchors.top: parent.top
anchors.left: parent.left
@ -222,14 +203,6 @@ PageType {
shareFullAccessDrawer.expandedHeight = shareFullAccessDrawerContent.implicitHeight + 32
}
Connections {
target: shareFullAccessDrawer
enabled: !GC.isMobile()
function onOpened() {
focusItem.forceActiveFocus()
}
}
Header2Type {
Layout.fillWidth: true
Layout.bottomMargin: 16
@ -240,24 +213,17 @@ PageType {
descriptionText: qsTr("Use for your own devices, or share with those you trust to manage the server.")
}
Item {
id: focusItem
KeyNavigation.tab: shareFullAccessButton.rightButton
}
LabelWithButtonType {
id: shareFullAccessButton
Layout.fillWidth: true
text: qsTr("Share")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
KeyNavigation.tab: focusItem
clickedFunction: function() {
PageController.goToPage(PageEnum.PageShareFullAccess)
shareFullAccessDrawer.close()
shareFullAccessDrawer.closeTriggered()
}
}
}
}
@ -288,13 +254,8 @@ PageType {
implicitWidth: (root.width - 32) / 2
text: qsTr("Connection")
KeyNavigation.tab: usersRadioButton
onClicked: {
accessTypeSelector.currentIndex = 0
if (!GC.isMobile()) {
clientNameTextField.textField.forceActiveFocus()
}
}
}
@ -305,15 +266,12 @@ PageType {
implicitWidth: (root.width - 32) / 2
text: qsTr("Users")
KeyNavigation.tab: accessTypeSelector.currentIndex === 0 ? clientNameTextField.textField : serverSelector
onClicked: {
accessTypeSelector.currentIndex = 1
PageController.showBusyIndicator(true)
ExportController.updateClientManagementModel(ContainersModel.getProcessedContainerIndex(),
ServersModel.getProcessedServerCredentials())
PageController.showBusyIndicator(false)
focusItem.forceActiveFocus()
}
}
}
@ -342,9 +300,6 @@ PageType {
textField.maximumLength: 20
checkEmptyText: true
KeyNavigation.tab: serverSelector
}
DropDownType {
@ -385,19 +340,19 @@ PageType {
clickedFunction: function() {
handler()
if (serverSelector.currentIndex !== serverSelectorListView.currentIndex) {
serverSelector.currentIndex = serverSelectorListView.currentIndex
if (serverSelector.currentIndex !== serverSelectorListView.selectedIndex) {
serverSelector.currentIndex = serverSelectorListView.selectedIndex
serverSelector.severSelectorIndexChanged()
}
serverSelector.close()
serverSelector.closeTriggered()
}
Component.onCompleted: {
if (ServersModel.isDefaultServerHasWriteAccess() && ServersModel.getDefaultServerData("hasInstalledContainers")) {
serverSelectorListView.currentIndex = proxyServersModel.mapFromSource(ServersModel.defaultIndex)
serverSelectorListView.selectedIndex = proxyServersModel.mapFromSource(ServersModel.defaultIndex)
} else {
serverSelectorListView.currentIndex = 0
serverSelectorListView.selectedIndex = 0
}
serverSelectorListView.triggerCurrentItem()
@ -405,11 +360,9 @@ PageType {
function handler() {
serverSelector.text = selectedText
ServersModel.processedIndex = proxyServersModel.mapToSource(currentIndex)
ServersModel.processedIndex = proxyServersModel.mapToSource(selectedIndex)
}
}
KeyNavigation.tab: protocolSelector
}
DropDownType {
@ -445,12 +398,10 @@ PageType {
]
}
currentIndex: 0
clickedFunction: function() {
handler()
protocolSelector.close()
protocolSelector.closeTriggered()
}
Connections {
@ -458,7 +409,7 @@ PageType {
function onSeverSelectorIndexChanged() {
var defaultContainer = proxyContainersModel.mapFromSource(ServersModel.getProcessedServerData("defaultContainer"))
protocolSelectorListView.currentIndex = defaultContainer
protocolSelectorListView.selectedIndex = defaultContainer
protocolSelectorListView.triggerCurrentItem()
}
}
@ -473,7 +424,7 @@ PageType {
protocolSelector.text = selectedText
ContainersModel.setProcessedContainerIndex(proxyContainersModel.mapToSource(currentIndex))
ContainersModel.setProcessedContainerIndex(proxyContainersModel.mapToSource(selectedIndex))
fillConnectionTypeModel()
@ -488,7 +439,7 @@ PageType {
function fillConnectionTypeModel() {
root.connectionTypesModel = [amneziaConnectionFormat]
var index = proxyContainersModel.mapToSource(currentIndex)
var index = proxyContainersModel.mapToSource(selectedIndex)
if (index === ContainerProps.containerFromString("amnezia-openvpn")) {
root.connectionTypesModel.push(openVpnConnectionFormat)
@ -508,12 +459,6 @@ PageType {
}
}
}
KeyNavigation.tab: accessTypeSelector.currentIndex === 0 ?
exportTypeSelector :
isSearchBarVisible ?
searchTextField.textField :
usersHeader.actionButton
}
DropDownType {
@ -549,7 +494,7 @@ PageType {
clickedFunction: function() {
exportTypeSelector.text = selectedText
exportTypeSelector.currentIndex = currentIndex
exportTypeSelector.close()
exportTypeSelector.closeTriggered()
}
Component.onCompleted: {
@ -557,9 +502,6 @@ PageType {
exportTypeSelector.currentIndex = currentIndex
}
}
KeyNavigation.tab: shareButton
}
BasicButtonType {
@ -575,7 +517,6 @@ PageType {
text: qsTr("Share")
leftImageSource: "qrc:/images/controls/share-2.svg"
Keys.onTabPressed: lastItemTabClicked(focusItem)
parentFlickable: a
@ -584,7 +525,6 @@ PageType {
ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type)
}
}
}
Header2Type {
@ -600,11 +540,6 @@ PageType {
actionButtonFunction: function() {
root.isSearchBarVisible = true
}
Keys.onTabPressed: clientsListView.model.count > 0 ?
clientsListView.forceActiveFocus() :
lastItemTabClicked(focusItem)
}
RowLayout {
@ -618,35 +553,13 @@ PageType {
textFieldPlaceholderText: qsTr("Search")
Connections {
target: root
function onIsSearchBarVisibleChanged() {
if (root.isSearchBarVisible) {
searchTextField.textField.forceActiveFocus()
} else {
searchTextField.textFieldText = ""
if (!GC.isMobile()) {
usersHeader.actionButton.forceActiveFocus()
}
}
}
}
Keys.onEscapePressed: {
root.isSearchBarVisible = false
}
function navigateTo() {
if (GC.isMobile()) {
focusItem.forceActiveFocus()
return;
}
if (searchTextField.textFieldText === "") {
root.isSearchBarVisible = false
usersHeader.actionButton.forceActiveFocus()
} else {
closeSearchButton.forceActiveFocus()
}
}
@ -660,16 +573,6 @@ PageType {
image: "qrc:/images/controls/close.svg"
imageColor: AmneziaStyle.color.paleGray
Keys.onTabPressed: {
if (!GC.isMobile()) {
if (clientsListView.model.count > 0) {
clientsListView.forceActiveFocus()
} else {
lastItemTabClicked(focusItem)
}
}
}
function clickedFunc() {
root.isSearchBarVisible = false
}
@ -687,6 +590,8 @@ PageType {
visible: accessTypeSelector.currentIndex === 1
property bool isFocusable: true
model: SortFilterProxyModel {
id: proxyClientManagementModel
sourceModel: ClientManagementModel
@ -698,45 +603,12 @@ PageType {
}
clip: true
interactive: false
activeFocusOnTab: true
focus: true
Keys.onTabPressed: {
if (!GC.isMobile()) {
if (currentIndex < this.count - 1) {
this.incrementCurrentIndex()
currentItem.focusItem.forceActiveFocus()
} else {
this.currentIndex = 0
lastItemTabClicked(focusItem)
}
}
}
onActiveFocusChanged: {
if (focus && !GC.isMobile()) {
currentIndex = 0
currentItem.focusItem.forceActiveFocus()
}
}
onCurrentIndexChanged: {
if (currentItem) {
if (currentItem.y < a.contentY) {
a.contentY = currentItem.y
} else if (currentItem.y + currentItem.height + clientsListView.y > a.contentY + a.height) {
a.contentY = currentItem.y + clientsListView.y + currentItem.height - a.height
}
}
}
reuseItems: true
delegate: Item {
implicitWidth: clientsListView.width
implicitHeight: delegateContent.implicitHeight
property alias focusItem: clientFocusItem.rightButton
ColumnLayout {
id: delegateContent
@ -755,7 +627,7 @@ PageType {
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
clientInfoDrawer.open()
clientInfoDrawer.openTriggered()
}
}
@ -766,17 +638,11 @@ PageType {
parent: root
onClosed: {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
width: root.width
height: root.height
expandedContent: ColumnLayout {
id: expandedContent
expandedStateContent: ColumnLayout {
id: expandedStateContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@ -785,15 +651,7 @@ PageType {
anchors.rightMargin: 16
onImplicitHeightChanged: {
clientInfoDrawer.expandedHeight = expandedContent.implicitHeight + 32
}
Connections {
target: clientInfoDrawer
enabled: !GC.isMobile()
function onOpened() {
focusItem1.forceActiveFocus()
}
clientInfoDrawer.expandedHeight = expandedStateContent.implicitHeight + 32
}
Header2TextType {
@ -846,11 +704,6 @@ PageType {
text: qsTr("Allowed IPs: %1").arg(allowedIps)
}
Item {
id: focusItem1
KeyNavigation.tab: renameButton
}
BasicButtonType {
id: renameButton
Layout.fillWidth: true
@ -865,10 +718,8 @@ PageType {
text: qsTr("Rename")
KeyNavigation.tab: revokeButton
clickedFunc: function() {
clientNameEditDrawer.open()
clientNameEditDrawer.openTriggered()
}
DrawerType2 {
@ -879,13 +730,7 @@ PageType {
anchors.fill: parent
expandedHeight: root.height * 0.35
onClosed: {
if (!GC.isMobile()) {
focusItem1.forceActiveFocus()
}
}
expandedContent: ColumnLayout {
expandedStateContent: ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@ -893,19 +738,6 @@ PageType {
anchors.leftMargin: 16
anchors.rightMargin: 16
Connections {
target: clientNameEditDrawer
enabled: !GC.isMobile()
function onOpened() {
clientNameEditor.textField.forceActiveFocus()
}
}
Item {
id: focusItem2
KeyNavigation.tab: clientNameEditor.textField
}
TextFieldWithHeaderType {
id: clientNameEditor
Layout.fillWidth: true
@ -913,8 +745,6 @@ PageType {
textFieldText: clientName
textField.maximumLength: 20
checkEmptyText: true
KeyNavigation.tab: saveButton
}
BasicButtonType {
@ -923,7 +753,6 @@ PageType {
Layout.fillWidth: true
text: qsTr("Save")
KeyNavigation.tab: focusItem2
clickedFunc: function() {
if (clientNameEditor.textFieldText === "") {
@ -937,7 +766,7 @@ PageType {
ContainersModel.getProcessedContainerIndex(),
ServersModel.getProcessedServerCredentials())
PageController.showBusyIndicator(false)
clientNameEditDrawer.close()
clientNameEditDrawer.closeTriggered()
}
}
}
@ -958,7 +787,6 @@ PageType {
borderWidth: 1
text: qsTr("Revoke")
KeyNavigation.tab: focusItem1
clickedFunc: function() {
var headerText = qsTr("Revoke the config for a user - %1?").arg(clientName)
@ -967,12 +795,12 @@ PageType {
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
clientInfoDrawer.close()
clientInfoDrawer.closeTriggered()
root.revokeConfig(index)
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
focusItem1.forceActiveFocus()
// focusItem1.forceActiveFocus()
}
}
@ -991,18 +819,5 @@ PageType {
id: shareConnectionDrawer
anchors.fill: parent
onClosed: {
if (!GC.isMobile()) {
clientNameTextField.textField.forceActiveFocus()
}
}
}
MouseArea {
anchors.fill: parent
onPressed: function(mouse) {
forceActiveFocus()
mouse.accepted = false
}
}
}

View file

@ -18,13 +18,6 @@ import "../Config"
PageType {
id: root
defaultActiveFocusItem: focusItem
Item {
id: focusItem
KeyNavigation.tab: backButton
}
BackButtonType {
id: backButton
@ -32,8 +25,6 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
KeyNavigation.tab: serverSelector
}
FlickableType {
@ -85,8 +76,6 @@ PageType {
descriptionText: qsTr("Server")
headerText: qsTr("Server")
KeyNavigation.tab: shareButton
listView: ListViewWithRadioButtonType {
id: serverSelectorListView
@ -113,7 +102,7 @@ PageType {
shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text
serverSelector.close()
serverSelector.closeTriggered()
}
Component.onCompleted: {
@ -137,8 +126,6 @@ PageType {
text: qsTr("Share")
leftImageSource: "qrc:/images/controls/share-2.svg"
Keys.onTabPressed: lastItemTabClicked(focusItem)
clickedFunc: function() {
PageController.showBusyIndicator(true)
@ -153,7 +140,7 @@ PageType {
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
shareConnectionDrawer.open()
shareConnectionDrawer.openTriggered()
shareConnectionDrawer.contentVisible = true
PageController.showBusyIndicator(false)
@ -166,10 +153,5 @@ PageType {
id: shareConnectionDrawer
anchors.fill: parent
onClosed: {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
}
}

View file

@ -15,12 +15,12 @@ import "../Components"
PageType {
id: root
defaultActiveFocusItem: homeTabButton
property bool isControlsDisabled: false
property bool isTabBarDisabled: false
Connections {
objectName: "pageControllerConnection"
target: PageController
function onGoToPageHome() {
@ -90,19 +90,11 @@ PageType {
PageController.closePage()
}
}
function onForceTabBarActiveFocus() {
homeTabButton.focus = true
tabBar.forceActiveFocus()
}
function onForceStackActiveFocus() {
homeTabButton.focus = true
tabBarStackView.forceActiveFocus()
}
}
Connections {
objectName: "installControllerConnections"
target: InstallController
function onInstallationErrorOccurred(error) {
@ -165,6 +157,8 @@ PageType {
}
Connections {
objectName: "connectionControllerConnections"
target: ConnectionController
function onReconnectWithUpdatedContainer(message) {
@ -182,6 +176,8 @@ PageType {
}
Connections {
objectName: "importControllerConnections"
target: ImportController
function onImportErrorOccurred(error, goToPageHome) {
@ -196,6 +192,8 @@ PageType {
}
Connections {
objectName: "settingsControllerConnections"
target: SettingsController
function onLoggingDisableByWatcher() {
@ -218,6 +216,7 @@ PageType {
StackViewType {
id: tabBarStackView
objectName: "tabBarStackView"
anchors.top: parent.top
anchors.right: parent.right
@ -247,13 +246,28 @@ PageType {
}
Keys.onPressed: function(event) {
PageController.keyPressEvent(event.key)
event.accepted = true
console.debug(">>>> ", event.key, " Event is caught by StartPage")
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
}
}
}
TabBar {
id: tabBar
objectName: "tabBar"
anchors.right: parent.right
anchors.left: parent.left
@ -269,6 +283,8 @@ PageType {
enabled: !root.isControlsDisabled && !root.isTabBarDisabled
background: Shape {
objectName: "backgroundShape"
width: parent.width
height: parent.height
@ -289,6 +305,8 @@ PageType {
TabImageButtonType {
id: homeTabButton
objectName: "homeTabButton"
isSelected: tabBar.currentIndex === 0
image: "qrc:/images/controls/home.svg"
clickedFunc: function () {
@ -296,27 +314,26 @@ PageType {
ServersModel.processedIndex = ServersModel.defaultIndex
tabBar.currentIndex = 0
}
KeyNavigation.tab: shareTabButton
Keys.onEnterPressed: this.clicked()
Keys.onReturnPressed: this.clicked()
}
TabImageButtonType {
id: shareTabButton
objectName: "shareTabButton"
Connections {
target: ServersModel
function onModelReset() {
var hasServerWithWriteAccess = ServersModel.hasServerWithWriteAccess()
shareTabButton.visible = hasServerWithWriteAccess
shareTabButton.width = hasServerWithWriteAccess ? undefined : 0
if (!SettingsController.isOnTv()) {
var hasServerWithWriteAccess = ServersModel.hasServerWithWriteAccess()
shareTabButton.visible = hasServerWithWriteAccess
shareTabButton.width = hasServerWithWriteAccess ? undefined : 0
}
}
}
visible: ServersModel.hasServerWithWriteAccess()
width: ServersModel.hasServerWithWriteAccess() ? undefined : 0
visible: !SettingsController.isOnTv() && ServersModel.hasServerWithWriteAccess()
width: !SettingsController.isOnTv() && ServersModel.hasServerWithWriteAccess() ? undefined : 0
isSelected: tabBar.currentIndex === 1
image: "qrc:/images/controls/share-2.svg"
@ -324,32 +341,30 @@ PageType {
tabBarStackView.goToTabBarPage(PageEnum.PageShare)
tabBar.currentIndex = 1
}
KeyNavigation.tab: settingsTabButton
}
TabImageButtonType {
id: settingsTabButton
objectName: "settingsTabButton"
isSelected: tabBar.currentIndex === 2
image: "qrc:/images/controls/settings-2.svg"
clickedFunc: function () {
tabBarStackView.goToTabBarPage(PageEnum.PageSettings)
tabBar.currentIndex = 2
}
KeyNavigation.tab: plusTabButton
}
TabImageButtonType {
id: plusTabButton
objectName: "plusTabButton"
isSelected: tabBar.currentIndex === 3
image: "qrc:/images/controls/plus.svg"
clickedFunc: function () {
tabBarStackView.goToTabBarPage(PageEnum.PageSetupWizardConfigSource)
tabBar.currentIndex = 3
}
Keys.onTabPressed: PageController.forceStackActiveFocus()
}
}
}