Files
amnezia-client/client/ui/qml/Pages2/PageSettingsSplitTunneling.qml
T

560 lines
17 KiB
QML
Raw Normal View History

2023-08-08 19:10:14 +05:00
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
2023-08-30 15:10:44 +05:00
import QtQuick.Dialogs
import QtCore
2023-08-08 19:10:14 +05:00
import SortFilterProxyModel 0.2
import PageEnum 1.0
import ProtocolEnum 1.0
import ContainerProps 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
import "../Components"
PageType {
id: root
2024-02-19 19:54:15 +05:00
property var isServerFromApi: ServersModel.getDefaultServerData("isServerFromApi")
2024-04-01 18:45:00 +07:00
defaultActiveFocusItem: searchField.textField
2024-04-18 17:54:55 +04:00
Item {
id: focusItem
KeyNavigation.tab: backButton
}
2024-04-06 22:29:51 +07:00
property bool pageEnabled
Component.onCompleted: {
2024-02-21 18:27:27 +07:00
if (ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Cannot change split tunneling settings during active connection"))
root.pageEnabled = false
} else if (ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && isServerFromApi) {
PageController.showNotificationMessage(qsTr("Default server does not support split tunneling function"))
2024-02-21 18:27:27 +07:00
root.pageEnabled = false
} else {
root.pageEnabled = true
}
}
2023-08-08 19:10:14 +05:00
Connections {
target: SitesController
function onFinished(message) {
PageController.showNotificationMessage(message)
}
function onErrorOccurred(errorMessage) {
PageController.showErrorMessage(errorMessage)
}
}
QtObject {
id: routeMode
property int allSites: 0
property int onlyForwardSites: 1
property int allExceptSites: 2
}
property list<QtObject> routeModesModel: [
onlyForwardSites,
allExceptSites
]
QtObject {
id: onlyForwardSites
2024-01-30 20:35:05 +02:00
property string name: qsTr("Only the sites listed here will be accessed through the VPN")
2023-08-08 19:10:14 +05:00
property int type: routeMode.onlyForwardSites
}
QtObject {
id: allExceptSites
2023-10-12 01:15:05 +01:00
property string name: qsTr("Addresses from the list should not be accessed via VPN")
2023-08-08 19:10:14 +05:00
property int type: routeMode.allExceptSites
}
function getRouteModesModelIndex() {
var currentRouteMode = SitesModel.routeMode
if ((routeMode.onlyForwardSites === currentRouteMode) || (routeMode.allSites === currentRouteMode)) {
return 0
} else if (routeMode.allExceptSites === currentRouteMode) {
return 1
}
}
ColumnLayout {
id: header
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
BackButtonType {
2024-04-18 17:54:55 +04:00
id: backButton
KeyNavigation.tab: switcher
2023-08-08 19:10:14 +05:00
}
RowLayout {
HeaderType {
enabled: root.pageEnabled
2023-08-08 19:10:14 +05:00
Layout.fillWidth: true
Layout.leftMargin: 16
2023-10-12 01:15:05 +01:00
headerText: qsTr("Split tunneling")
2023-08-08 19:10:14 +05:00
}
SwitcherType {
id: switcher
enabled: root.pageEnabled
2023-08-08 19:10:14 +05:00
Layout.fillWidth: true
Layout.rightMargin: 16
2024-04-18 17:54:55 +04:00
function onToggledFunc() {
SitesModel.toggleSplitTunneling(this.checked)
selector.text = root.routeModesModel[getRouteModesModelIndex()].name
2023-08-08 19:10:14 +05:00
}
2024-04-18 17:54:55 +04:00
checked: SitesModel.isTunnelingEnabled
onToggled: { onToggledFunc() }
Keys.onEnterPressed: { onToggledFunc() }
Keys.onReturnPressed: { onToggledFunc() }
KeyNavigation.tab: selector
2023-08-08 19:10:14 +05:00
}
}
DropDownType {
id: selector
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
drawerHeight: 0.4375
2024-02-16 15:24:06 +05:00
drawerParent: root
2023-08-08 19:10:14 +05:00
enabled: root.pageEnabled
2023-08-08 19:10:14 +05:00
headerText: qsTr("Mode")
2023-08-16 22:45:05 +05:00
listView: ListViewWithRadioButtonType {
2023-08-08 19:10:14 +05:00
rootWidth: root.width
model: root.routeModesModel
currentIndex: getRouteModesModelIndex()
clickedFunction: function() {
selector.text = selectedText
2024-02-16 15:24:06 +05:00
selector.close()
2023-08-08 19:10:14 +05:00
if (SitesModel.routeMode !== root.routeModesModel[currentIndex].type) {
SitesModel.routeMode = root.routeModesModel[currentIndex].type
}
}
Component.onCompleted: {
if (root.routeModesModel[currentIndex].type === SitesModel.routeMode) {
selector.text = selectedText
} else {
selector.text = root.routeModesModel[0].name
}
}
Connections {
target: SitesModel
function onRouteModeChanged() {
currentIndex = getRouteModesModelIndex()
}
}
}
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: {
return sites.count > 0 ?
sites :
searchField.textField
}
2023-08-08 19:10:14 +05:00
}
}
FlickableType {
2024-04-18 17:54:55 +04:00
id: fl
2023-08-08 19:10:14 +05:00
anchors.top: header.bottom
anchors.topMargin: 16
contentHeight: col.implicitHeight + addSiteButton.implicitHeight + addSiteButton.anchors.bottomMargin + addSiteButton.anchors.topMargin
2023-08-08 19:10:14 +05:00
enabled: root.pageEnabled
2023-08-08 19:10:14 +05:00
Column {
id: col
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
ListView {
id: sites
width: parent.width
height: sites.contentItem.height
2024-04-01 18:45:00 +07:00
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
}
}
]
}
2023-08-08 19:10:14 +05:00
clip: true
interactive: false
2024-04-18 17:54:55 +04:00
activeFocusOnTab: true
focus: true
Keys.onTabPressed: {
if (currentIndex < this.count - 1) {
this.incrementCurrentIndex()
} else {
currentIndex = 0
searchField.textField.forceActiveFocus()
}
fl.ensureVisible(currentItem)
}
2023-08-08 19:10:14 +05:00
delegate: Item {
implicitWidth: sites.width
implicitHeight: delegateContent.implicitHeight
2024-04-18 17:54:55 +04:00
onActiveFocusChanged: {
if (activeFocus) {
site.rightButton.forceActiveFocus()
}
}
2023-08-08 19:10:14 +05:00
ColumnLayout {
id: delegateContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelWithButtonType {
2024-04-18 17:54:55 +04:00
id: site
2023-08-08 19:10:14 +05:00
Layout.fillWidth: true
text: url
descriptionText: ip
rightImageSource: "qrc:/images/controls/trash.svg"
rightImageColor: "#D7D8DB"
clickedFunction: function() {
2024-02-16 15:24:06 +05:00
var headerText = qsTr("Remove ") + url + "?"
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
var yesButtonFunction = function() {
2024-04-01 18:45:00 +07:00
SitesController.removeSite(proxySitesModel.mapToSource(index))
2024-04-18 17:54:55 +04:00
if (!GC.isMobile()) {
site.rightButton.forceActiveFocus()
}
2023-08-08 19:10:14 +05:00
}
2024-02-16 15:24:06 +05:00
var noButtonFunction = function() {
2024-04-18 17:54:55 +04:00
if (!GC.isMobile()) {
site.rightButton.forceActiveFocus()
}
2023-08-08 19:10:14 +05:00
}
2024-02-16 15:24:06 +05:00
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
2023-08-08 19:10:14 +05:00
}
}
DividerType {}
}
}
}
2024-04-18 17:54:55 +04:00
2023-08-08 19:10:14 +05:00
}
}
Rectangle {
anchors.fill: addSiteButton
anchors.bottomMargin: -24
color: "#0E0E11"
opacity: 0.8
}
2023-08-08 19:10:14 +05:00
RowLayout {
id: addSiteButton
enabled: root.pageEnabled
2023-08-08 19:10:14 +05:00
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 24
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.bottomMargin: 24
TextFieldWithHeaderType {
2024-04-01 18:45:00 +07:00
id: searchField
2023-08-08 19:10:14 +05:00
Layout.fillWidth: true
2024-04-18 17:54:55 +04:00
rightButtonClickedOnEnter: true
2023-08-08 19:10:14 +05:00
2024-01-30 20:35:05 +02:00
textFieldPlaceholderText: qsTr("website or IP")
2023-08-08 19:10:14 +05:00
buttonImageSource: "qrc:/images/controls/plus.svg"
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: GC.isMobile() ? focusItem : addSiteButtonImage
2023-08-08 19:10:14 +05:00
clickedFunc: function() {
PageController.showBusyIndicator(true)
2023-08-08 19:10:14 +05:00
SitesController.addSite(textFieldText)
textFieldText = ""
PageController.showBusyIndicator(false)
2023-08-08 19:10:14 +05:00
}
}
ImageButtonType {
2024-04-18 17:54:55 +04:00
id: addSiteButtonImage
2023-08-08 19:10:14 +05:00
implicitWidth: 56
implicitHeight: 56
image: "qrc:/images/controls/more-vertical.svg"
imageColor: "#D7D8DB"
onClicked: function () {
moreActionsDrawer.open()
}
2024-04-18 17:54:55 +04:00
Keys.onReturnPressed: addSiteButtonImage.clicked()
Keys.onEnterPressed: addSiteButtonImage.clicked()
Keys.onTabPressed: lastItemTabClicked(focusItem)
2023-08-08 19:10:14 +05:00
}
}
2024-02-16 15:24:06 +05:00
DrawerType2 {
2023-08-08 19:10:14 +05:00
id: moreActionsDrawer
2024-02-16 15:24:06 +05:00
anchors.fill: parent
expandedHeight: parent.height * 0.4375
2023-08-08 19:10:14 +05:00
2024-04-18 17:54:55 +04:00
onClosed: {
if (root.defaultActiveFocusItem && !GC.isMobile()) {
root.defaultActiveFocusItem.forceActiveFocus()
}
}
2024-02-16 15:24:06 +05:00
expandedContent: ColumnLayout {
id: moreActionsDrawerContent
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
2023-08-08 19:10:14 +05:00
2024-04-18 17:54:55 +04:00
Connections {
target: moreActionsDrawer
function onOpened() {
focusItem1.forceActiveFocus()
}
function onActiveFocusChanged() {
if (!GC.isMobile()) {
focusItem1.forceActiveFocus()
}
}
}
Item {
id: focusItem1
KeyNavigation.tab: importSitesButton.rightButton
}
2024-02-16 15:24:06 +05:00
Header2Type {
Layout.fillWidth: true
Layout.margins: 16
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
headerText: qsTr("Import / Export Sites")
}
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
LabelWithButtonType {
2024-04-18 17:54:55 +04:00
id: importSitesButton
2024-02-16 15:24:06 +05:00
Layout.fillWidth: true
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
text: qsTr("Import")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
clickedFunction: function() {
importSitesDrawer.open()
2023-08-08 19:10:14 +05:00
}
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: exportSitesButton
2024-02-16 15:24:06 +05:00
}
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
DividerType {}
LabelWithButtonType {
2024-04-18 17:54:55 +04:00
id: exportSitesButton
2024-02-16 15:24:06 +05:00
Layout.fillWidth: true
text: qsTr("Save site list")
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: focusItem1
2024-02-16 15:24:06 +05:00
clickedFunction: function() {
var fileName = ""
if (GC.isMobile()) {
fileName = "amnezia_sites.json"
} else {
fileName = SystemController.getFileName(qsTr("Save sites"),
qsTr("Sites files (*.json)"),
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/amnezia_sites",
true,
".json")
}
if (fileName !== "") {
PageController.showBusyIndicator(true)
SitesController.exportSites(fileName)
moreActionsDrawer.close()
PageController.showBusyIndicator(false)
2023-08-08 19:10:14 +05:00
}
}
}
2024-02-16 15:24:06 +05:00
DividerType {}
2023-08-08 19:10:14 +05:00
}
}
2024-02-16 15:24:06 +05:00
DrawerType2 {
2023-08-08 19:10:14 +05:00
id: importSitesDrawer
2024-02-16 15:24:06 +05:00
anchors.fill: parent
expandedHeight: parent.height * 0.4375
2023-08-08 19:10:14 +05:00
2024-04-18 17:54:55 +04:00
onClosed: {
if (!GC.isMobile()) {
moreActionsDrawer.forceActiveFocus()
}
}
2024-02-16 15:24:06 +05:00
expandedContent: Item {
implicitHeight: importSitesDrawer.expandedHeight
2023-08-08 19:10:14 +05:00
2024-04-18 17:54:55 +04:00
Connections {
target: importSitesDrawer
enabled: !GC.isMobile()
function onOpened() {
focusItem2.forceActiveFocus()
}
}
Item {
id: focusItem2
KeyNavigation.tab: importSitesDrawerBackButton
}
2024-02-16 15:24:06 +05:00
BackButtonType {
id: importSitesDrawerBackButton
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: importSitesButton2
2024-02-16 15:24:06 +05:00
backButtonFunction: function() {
importSitesDrawer.close()
}
2023-08-08 19:10:14 +05:00
}
2024-02-16 15:24:06 +05:00
FlickableType {
anchors.top: importSitesDrawerBackButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
contentHeight: importSitesDrawerContent.height
2023-08-30 15:10:44 +05:00
2024-02-16 15:24:06 +05:00
ColumnLayout {
id: importSitesDrawerContent
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
Header2Type {
Layout.fillWidth: true
Layout.margins: 16
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
headerText: qsTr("Import a list of sites")
}
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
LabelWithButtonType {
2024-04-18 17:54:55 +04:00
id: importSitesButton2
2024-02-16 15:24:06 +05:00
Layout.fillWidth: true
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
text: qsTr("Replace site list")
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: importSitesButton3
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
qsTr("Sites files (*.json)"))
if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, true)
}
}
2023-08-08 19:10:14 +05:00
}
2024-02-16 15:24:06 +05:00
DividerType {}
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
LabelWithButtonType {
2024-04-18 17:54:55 +04:00
id: importSitesButton3
2024-02-16 15:24:06 +05:00
Layout.fillWidth: true
text: qsTr("Add imported sites to existing ones")
2024-04-18 17:54:55 +04:00
KeyNavigation.tab: focusItem2
2023-08-08 19:10:14 +05:00
2024-02-16 15:24:06 +05:00
clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
qsTr("Sites files (*.json)"))
if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, false)
}
}
2023-08-30 15:10:44 +05:00
}
2023-09-06 22:20:59 +05:00
2024-02-16 15:24:06 +05:00
function importSites(fileName, replaceExistingSites) {
PageController.showBusyIndicator(true)
SitesController.importSites(fileName, replaceExistingSites)
PageController.showBusyIndicator(false)
importSitesDrawer.close()
moreActionsDrawer.close()
}
2024-02-16 15:24:06 +05:00
DividerType {}
}
2023-08-08 19:10:14 +05:00
}
}
}
}