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:
parent
212e9b3a91
commit
6acaab0ffa
109 changed files with 4036 additions and 3700 deletions
|
@ -16,6 +16,32 @@ Button {
|
|||
property string connectedButtonColor: AmneziaStyle.color.goldenApricot
|
||||
property bool buttonActiveFocus: activeFocus && (Qt.platform.os !== "android" || SettingsController.isOnTv())
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
implicitWidth: 190
|
||||
implicitHeight: 190
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ DrawerType2 {
|
|||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
expandedContent: ColumnLayout {
|
||||
expandedStateContent: ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
|
@ -26,14 +26,6 @@ DrawerType2 {
|
|||
root.expandedHeight = content.implicitHeight + 32
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
|
@ -44,11 +36,6 @@ DrawerType2 {
|
|||
headerText: qsTr("Add new connection")
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: ip.rightButton
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: ip
|
||||
Layout.fillWidth: true
|
||||
|
@ -59,10 +46,8 @@ DrawerType2 {
|
|||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardCredentials)
|
||||
root.close()
|
||||
root.closeTriggered()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: qrCode.rightButton
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
@ -76,10 +61,8 @@ DrawerType2 {
|
|||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
|
||||
root.close()
|
||||
root.closeTriggered()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: focusItem
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
|
|
@ -17,55 +17,15 @@ ListView {
|
|||
property var rootWidth
|
||||
property var selectedText
|
||||
|
||||
property bool a: true
|
||||
|
||||
width: rootWidth
|
||||
height: menuContent.contentItem.height
|
||||
height: contentItem.height
|
||||
|
||||
clip: true
|
||||
interactive: false
|
||||
snapMode: ListView.SnapToItem
|
||||
|
||||
property FlickableType parentFlickable
|
||||
property var lastItemTabClicked
|
||||
ScrollBar.vertical: ScrollBarType {}
|
||||
|
||||
property int currentFocusIndex: 0
|
||||
|
||||
activeFocusOnTab: true
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
this.currentFocusIndex = 0
|
||||
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onTabPressed: {
|
||||
if (currentFocusIndex < this.count - 1) {
|
||||
currentFocusIndex += 1
|
||||
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
|
||||
} else {
|
||||
currentFocusIndex = 0
|
||||
if (lastItemTabClicked && typeof lastItemTabClicked === "function") {
|
||||
lastItemTabClicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
currentFocusIndex = 0
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
}
|
||||
|
||||
onCurrentFocusIndexChanged: {
|
||||
if (parentFlickable) {
|
||||
parentFlickable.ensureVisible(this.itemAtIndex(currentFocusIndex))
|
||||
}
|
||||
}
|
||||
property bool isFocusable: true
|
||||
|
||||
ButtonGroup {
|
||||
id: containersRadioButtonGroup
|
||||
|
@ -75,12 +35,6 @@ ListView {
|
|||
implicitWidth: rootWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
containerRadioButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
|
||||
|
@ -111,13 +65,13 @@ ListView {
|
|||
}
|
||||
|
||||
if (checked) {
|
||||
containersDropDown.close()
|
||||
containersDropDown.closeTriggered()
|
||||
ServersModel.setDefaultContainer(ServersModel.defaultIndex, proxyDefaultServerContainersModel.mapToSource(index))
|
||||
} else {
|
||||
ContainersModel.setProcessedContainerIndex(proxyDefaultServerContainersModel.mapToSource(index))
|
||||
InstallController.setShouldCreateServer(false)
|
||||
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
|
||||
containersDropDown.close()
|
||||
containersDropDown.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ DrawerType2 {
|
|||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.9
|
||||
|
||||
expandedContent: ColumnLayout {
|
||||
expandedStateContent: ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
|
@ -24,14 +24,6 @@ DrawerType2 {
|
|||
anchors.right: parent.right
|
||||
spacing: 0
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
|
@ -43,11 +35,6 @@ DrawerType2 {
|
|||
descriptionText: qsTr("Allows you to connect to some sites or applications through a VPN connection and bypass others")
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: splitTunnelingSwitch.visible ? splitTunnelingSwitch : siteBasedSplitTunnelingSwitch.rightButton
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: splitTunnelingSwitch
|
||||
Layout.fillWidth: true
|
||||
|
@ -59,11 +46,9 @@ DrawerType2 {
|
|||
descriptionText: qsTr("Enabled \nCan't be disabled for current server")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
KeyNavigation.tab: siteBasedSplitTunnelingSwitch.visible ? siteBasedSplitTunnelingSwitch.rightButton : focusItem
|
||||
|
||||
clickedFunction: function() {
|
||||
// PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||
// root.close()
|
||||
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,13 +65,9 @@ DrawerType2 {
|
|||
descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
KeyNavigation.tab: appSplitTunnelingSwitch.visible ?
|
||||
appSplitTunnelingSwitch.rightButton :
|
||||
focusItem
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||
root.close()
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,11 +84,9 @@ DrawerType2 {
|
|||
descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
KeyNavigation.tab: focusItem
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
|
||||
root.close()
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ DrawerType2 {
|
|||
id: installedAppsModel
|
||||
}
|
||||
|
||||
expandedContent: Item {
|
||||
expandedStateContent: Item {
|
||||
id: container
|
||||
|
||||
implicitHeight: expandedHeight
|
||||
|
@ -43,7 +43,7 @@ DrawerType2 {
|
|||
BackButtonType {
|
||||
backButtonImage: "qrc:/images/controls/arrow-left.svg"
|
||||
backButtonFunction: function() {
|
||||
root.close()
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,8 @@ DrawerType2 {
|
|||
clip: true
|
||||
interactive: true
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: proxyInstalledAppsModel
|
||||
sourceModel: installedAppsModel
|
||||
|
@ -79,10 +81,7 @@ DrawerType2 {
|
|||
}
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
id: scrollBar
|
||||
policy: ScrollBar.AlwaysOn
|
||||
}
|
||||
ScrollBar.vertical: ScrollBarType {}
|
||||
|
||||
ButtonGroup {
|
||||
id: buttonGroup
|
||||
|
@ -155,7 +154,7 @@ DrawerType2 {
|
|||
PageController.showBusyIndicator(true)
|
||||
AppSplitTunnelingController.addApps(installedAppsModel.getSelectedAppsInfo())
|
||||
PageController.showBusyIndicator(false)
|
||||
root.close()
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ DrawerType2 {
|
|||
property var yesButtonFunction
|
||||
property var noButtonFunction
|
||||
|
||||
expandedContent: ColumnLayout {
|
||||
expandedStateContent: ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
|
@ -33,14 +33,6 @@ DrawerType2 {
|
|||
root.expandedHeight = content.implicitHeight + 32
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Header2TextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
@ -59,11 +51,6 @@ DrawerType2 {
|
|||
text: descriptionText
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: yesButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: yesButton
|
||||
Layout.fillWidth: true
|
||||
|
@ -78,8 +65,6 @@ DrawerType2 {
|
|||
yesButtonFunction()
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: noButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
|
@ -102,8 +87,6 @@ DrawerType2 {
|
|||
noButtonFunction()
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: focusItem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import "../Config"
|
|||
DrawerType2 {
|
||||
id: root
|
||||
|
||||
expandedContent: Item {
|
||||
expandedStateContent: Item {
|
||||
id: container
|
||||
|
||||
implicitHeight: root.height * 0.9
|
||||
|
@ -20,19 +20,6 @@ DrawerType2 {
|
|||
root.expandedHeight = container.implicitHeight
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
|
@ -43,167 +30,148 @@ DrawerType2 {
|
|||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
backButtonImage: "qrc:/images/controls/arrow-left.svg"
|
||||
backButtonFunction: function() { root.close() }
|
||||
KeyNavigation.tab: listView
|
||||
backButtonFunction: function() { root.closeTriggered() }
|
||||
}
|
||||
|
||||
Header2Type {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
headerText: qsTr("Choose language")
|
||||
}
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
ListView {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButtonLayout.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
property bool isFocusable: true
|
||||
property int selectedIndex: LanguageModel.currentLanguageIndex
|
||||
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
reuseItems: true
|
||||
|
||||
Header2Type {
|
||||
id: header
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
ScrollBar.vertical: ScrollBarType {}
|
||||
|
||||
headerText: qsTr("Choose language")
|
||||
}
|
||||
model: LanguageModel
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
ButtonGroup {
|
||||
id: buttonGroup
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
height: listView.contentItem.height
|
||||
delegate: Item {
|
||||
implicitWidth: root.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
|
||||
clip: true
|
||||
interactive: false
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
|
||||
model: LanguageModel
|
||||
currentIndex: LanguageModel.currentLanguageIndex
|
||||
anchors.fill: parent
|
||||
|
||||
ButtonGroup {
|
||||
id: buttonGroup
|
||||
}
|
||||
RadioButton {
|
||||
id: radioButton
|
||||
|
||||
property int currentFocusIndex: 0
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: radioButtonContent.implicitHeight
|
||||
|
||||
activeFocusOnTab: true
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
this.currentFocusIndex = 0
|
||||
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
|
||||
}
|
||||
}
|
||||
hoverEnabled: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
if (currentFocusIndex < this.count - 1) {
|
||||
currentFocusIndex += 1
|
||||
this.itemAtIndex(currentFocusIndex).forceActiveFocus()
|
||||
} else {
|
||||
listViewFocusItem.forceActiveFocus()
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
property bool isFocusable: true
|
||||
|
||||
Item {
|
||||
id: listViewFocusItem
|
||||
Keys.onTabPressed: {
|
||||
root.forceActiveFocus()
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
listViewFocusItem.forceActiveFocus()
|
||||
focusItem.forceActiveFocus()
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: root.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
radioButton.forceActiveFocus()
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
indicator: Rectangle {
|
||||
width: parent.width - 1
|
||||
height: parent.height
|
||||
color: radioButton.hovered ? AmneziaStyle.color.slateGray : AmneziaStyle.color.onyxBlack
|
||||
border.color: radioButton.focus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.transparent
|
||||
border.width: radioButton.focus ? 1 : 0
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
Behavior on border.color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
|
||||
RowLayout {
|
||||
id: radioButtonContent
|
||||
anchors.fill: parent
|
||||
|
||||
RadioButton {
|
||||
id: radioButton
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: radioButtonContent.implicitHeight
|
||||
spacing: 0
|
||||
|
||||
hoverEnabled: true
|
||||
z: 1
|
||||
|
||||
indicator: Rectangle {
|
||||
width: parent.width - 1
|
||||
height: parent.height
|
||||
color: radioButton.hovered ? AmneziaStyle.color.slateGray : AmneziaStyle.color.onyxBlack
|
||||
border.color: radioButton.focus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.transparent
|
||||
border.width: radioButton.focus ? 1 : 0
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
Layout.bottomMargin: 20
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
Behavior on border.color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
text: languageName
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: radioButtonContent
|
||||
anchors.fill: parent
|
||||
Image {
|
||||
source: "qrc:/images/controls/check.svg"
|
||||
visible: radioButton.checked
|
||||
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
width: 24
|
||||
height: 24
|
||||
|
||||
spacing: 0
|
||||
|
||||
z: 1
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
Layout.bottomMargin: 20
|
||||
|
||||
text: languageName
|
||||
}
|
||||
|
||||
Image {
|
||||
source: "qrc:/images/controls/check.svg"
|
||||
visible: radioButton.checked
|
||||
|
||||
width: 24
|
||||
height: 24
|
||||
|
||||
Layout.rightMargin: 8
|
||||
}
|
||||
}
|
||||
|
||||
ButtonGroup.group: buttonGroup
|
||||
checked: listView.currentIndex === index
|
||||
|
||||
onClicked: {
|
||||
listView.currentIndex = index
|
||||
LanguageModel.changeLanguage(languageIndex)
|
||||
root.close()
|
||||
}
|
||||
Layout.rightMargin: 8
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: radioButton.clicked()
|
||||
Keys.onReturnPressed: radioButton.clicked()
|
||||
ButtonGroup.group: buttonGroup
|
||||
checked: listView.selectedIndex === index
|
||||
|
||||
onClicked: {
|
||||
listView.selectedIndex = index
|
||||
LanguageModel.changeLanguage(languageIndex)
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: radioButton.clicked()
|
||||
Keys.onReturnPressed: radioButton.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
126
client/ui/qml/Components/ServersListView.qml
Normal file
126
client/ui/qml/Components/ServersListView.qml
Normal file
|
@ -0,0 +1,126 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import ProtocolEnum 1.0
|
||||
import ContainerProps 1.0
|
||||
import ContainersModelFilters 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
|
||||
ListView {
|
||||
id: root
|
||||
|
||||
property int selectedIndex: ServersModel.defaultIndex
|
||||
|
||||
anchors.top: serversMenuHeader.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.topMargin: 16
|
||||
|
||||
model: ServersModel
|
||||
|
||||
ScrollBar.vertical: ScrollBarType {}
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Connections {
|
||||
target: ServersModel
|
||||
function onDefaultServerIndexChanged(serverIndex) {
|
||||
root.selectedIndex = serverIndex
|
||||
}
|
||||
}
|
||||
|
||||
clip: true
|
||||
reuseItems: true
|
||||
|
||||
delegate: Item {
|
||||
id: menuContentDelegate
|
||||
objectName: "menuContentDelegate"
|
||||
|
||||
property variant delegateData: model
|
||||
property VerticalRadioButton serverRadioButtonProperty: serverRadioButton
|
||||
|
||||
implicitWidth: root.width
|
||||
implicitHeight: serverRadioButtonContent.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: serverRadioButtonContent
|
||||
objectName: "serverRadioButtonContent"
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
objectName: "serverRadioButtonRowLayout"
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
VerticalRadioButton {
|
||||
id: serverRadioButton
|
||||
objectName: "serverRadioButton"
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: name
|
||||
descriptionText: serverDescription
|
||||
|
||||
checked: index === root.selectedIndex
|
||||
checkable: !ConnectionController.isConnected
|
||||
|
||||
ButtonGroup.group: serversRadioButtonGroup
|
||||
|
||||
onClicked: {
|
||||
if (ConnectionController.isConnected) {
|
||||
PageController.showNotificationMessage(qsTr("Unable change server while there is an active connection"))
|
||||
return
|
||||
}
|
||||
|
||||
root.selectedIndex = index
|
||||
|
||||
ServersModel.defaultIndex = index
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: serverRadioButton.clicked()
|
||||
Keys.onReturnPressed: serverRadioButton.clicked()
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: serverInfoButton
|
||||
objectName: "serverInfoButton"
|
||||
|
||||
image: "qrc:/images/controls/settings.svg"
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
implicitWidth: 56
|
||||
implicitHeight: 56
|
||||
|
||||
z: 1
|
||||
|
||||
onClicked: function() {
|
||||
ServersModel.processedIndex = index
|
||||
PageController.goToPage(PageEnum.PageSettingsServerInfo)
|
||||
drawer.closeTriggered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 0
|
||||
Layout.rightMargin: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,47 +20,14 @@ ListView {
|
|||
height: root.contentItem.height
|
||||
|
||||
clip: true
|
||||
interactive: false
|
||||
reuseItems: true
|
||||
|
||||
activeFocusOnTab: true
|
||||
Keys.onTabPressed: {
|
||||
if (currentIndex < this.count - 1) {
|
||||
this.incrementCurrentIndex()
|
||||
} else {
|
||||
currentIndex = 0
|
||||
lastItemTabClickedSignal()
|
||||
}
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
if (visible) {
|
||||
if (fl.contentHeight > fl.height) {
|
||||
var item = this.currentItem
|
||||
if (item.y < fl.height) {
|
||||
fl.contentY = item.y
|
||||
} else if (item.y + item.height > fl.contentY + fl.height) {
|
||||
fl.contentY = item.y + item.height - fl.height
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
this.currentIndex = 0
|
||||
}
|
||||
}
|
||||
property bool isFocusable: false
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: root.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
containerRadioButton.rightButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
|
||||
|
|
|
@ -36,17 +36,9 @@ DrawerType2 {
|
|||
configFileName = "amnezia_config"
|
||||
}
|
||||
|
||||
expandedContent: Item {
|
||||
expandedStateContent: Item {
|
||||
implicitHeight: root.expandedHeight
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
header.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Header2Type {
|
||||
id: header
|
||||
anchors.top: parent.top
|
||||
|
@ -57,24 +49,27 @@ DrawerType2 {
|
|||
anchors.rightMargin: 16
|
||||
|
||||
headerText: root.headerText
|
||||
|
||||
KeyNavigation.tab: shareButton
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
ListView {
|
||||
id: listView
|
||||
|
||||
anchors.top: header.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.height + 32
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
property bool isFocusable: true
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
ScrollBar.vertical: ScrollBarType {}
|
||||
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
model: 1
|
||||
|
||||
clip: true
|
||||
reuseItems: true
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
visible: root.contentVisible
|
||||
|
||||
|
@ -82,12 +77,12 @@ DrawerType2 {
|
|||
id: shareButton
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Share")
|
||||
leftImageSource: "qrc:/images/controls/share-2.svg"
|
||||
|
||||
KeyNavigation.tab: copyConfigTextButton
|
||||
|
||||
clickedFunc: function() {
|
||||
var fileName = ""
|
||||
if (GC.isMobile()) {
|
||||
|
@ -111,6 +106,8 @@ DrawerType2 {
|
|||
id: copyConfigTextButton
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
|
@ -124,14 +121,14 @@ DrawerType2 {
|
|||
|
||||
Keys.onReturnPressed: { copyConfigTextButton.clicked() }
|
||||
Keys.onEnterPressed: { copyConfigTextButton.clicked() }
|
||||
|
||||
KeyNavigation.tab: copyNativeConfigStringButton.visible ? copyNativeConfigStringButton : showSettingsButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: copyNativeConfigStringButton
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: false
|
||||
|
||||
|
@ -153,6 +150,8 @@ DrawerType2 {
|
|||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
|
@ -164,10 +163,8 @@ DrawerType2 {
|
|||
text: qsTr("Show connection settings")
|
||||
|
||||
clickedFunc: function() {
|
||||
configContentDrawer.open()
|
||||
configContentDrawer.openTriggered()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: header
|
||||
}
|
||||
|
||||
DrawerType2 {
|
||||
|
@ -178,30 +175,11 @@ DrawerType2 {
|
|||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.9
|
||||
|
||||
onClosed: {
|
||||
if (!GC.isMobile()) {
|
||||
header.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
expandedContent: Item {
|
||||
expandedStateContent: Item {
|
||||
id: configContentContainer
|
||||
|
||||
implicitHeight: configContentDrawer.expandedHeight
|
||||
|
||||
Connections {
|
||||
target: configContentDrawer
|
||||
enabled: !GC.isMobile()
|
||||
function onOpened() {
|
||||
focusItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusItem
|
||||
KeyNavigation.tab: backButton
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: copyNativeConfigStringButton
|
||||
function onClicked() {
|
||||
|
@ -231,9 +209,7 @@ DrawerType2 {
|
|||
anchors.right: parent.right
|
||||
anchors.topMargin: 16
|
||||
|
||||
backButtonFunction: function() { configContentDrawer.close() }
|
||||
|
||||
KeyNavigation.tab: focusItem
|
||||
backButtonFunction: function() { configContentDrawer.closeTriggered() }
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
|
@ -302,6 +278,10 @@ DrawerType2 {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
Rectangle {
|
||||
id: qrCodeContainer
|
||||
|
@ -309,6 +289,8 @@ DrawerType2 {
|
|||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: ExportController.qrCodesCount > 0
|
||||
|
||||
|
@ -320,6 +302,32 @@ DrawerType2 {
|
|||
|
||||
source: ExportController.qrCodesCount ? ExportController.qrCodes[0] : ""
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
Timer {
|
||||
property int index: 0
|
||||
interval: 1000
|
||||
|
@ -346,6 +354,8 @@ DrawerType2 {
|
|||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: ExportController.qrCodesCount > 0
|
||||
|
||||
|
|
|
@ -39,8 +39,6 @@ Rectangle {
|
|||
implicitWidth: (rootWidth - 32) / 2
|
||||
text: "UDP"
|
||||
|
||||
KeyNavigation.tab: tcpButton
|
||||
|
||||
onClicked: {
|
||||
root.currentIndex = 0
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue