feature: fillswitch strict mode (#1333)
* Add allowed DNS list for killswitch * Windows killswitch strict mode backend part * Killswitch strict mode for Linux and MacOS * Windows fixes * feature: Add Kill Switch settings page with strict mode option * fix windows build after merge * Refresh killswitch mode when it toggled * Use HLM to store strictMode flag * Some Linux updates * feat: Enhance VerticalRadioButton with improved styling and disabled states * Refresh killSwitch state update * Fix build * refactor: Modularize header components * Change kill switch radio button styling * Fix strict kill switch mode handling * Refactor: Replace HeaderType with new Types for headers in QML pages * Remove deprecated HeaderType QML component * Refresh strict mode killswitch after global toggle change * Implement model, controller and UI for killswitch dns exceptions * Connect backend part and UI * Change label text to DNS exceptions * Remove HeaderType from PageSettingsApiDevices * Some pretty fixes * Fix problem with definition sequence of PageSettingsKillSwitchExceptions.pml elements * Add exclusion method for Windows firewall * Change ubuntu version in deploy script * Update ubuntu version in GH actions * Add confirmation popup for strict killswitch mode * Add qt standard path for build script * Add method to killswitch for expanding strickt mode exceptions list and fix allowTrafficTo() for Windows. Also Added cache in KillSwitch class for exceptions * Add insertion of gateway address to strict killswitch exceptions * Review fixes * buildfix and naming --------- Co-authored-by: aiamnezia <ai@amnezia.org>
This commit is contained in:
parent
5bd88ac2e9
commit
f6d7552b58
88 changed files with 1718 additions and 418 deletions
|
|
@ -56,7 +56,7 @@ PageType {
|
|||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ PageType {
|
|||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("AmneziaWG settings")
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("AmneziaWG settings")
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("Cloak settings")
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("OpenVPN settings")
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ PageType {
|
|||
id: backButton
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("Shadowsocks settings")
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("WG settings")
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
headerText: qsTr("WG settings")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
headerText: qsTr("XRay settings")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ PageType {
|
|||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
|
@ -217,7 +217,7 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("SOCKS5 settings")
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ PageType {
|
|||
Layout.topMargin: 20
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
HeaderTypeWithButton {
|
||||
id: headerContent
|
||||
objectName: "headerContent"
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ PageType {
|
|||
id: backButton
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ PageType {
|
|||
id: backButton
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ PageType {
|
|||
id: backButton
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ PageType {
|
|||
Layout.topMargin: 20
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
HeaderTypeWithButton {
|
||||
id: headerContent
|
||||
objectName: "headerContent"
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ PageType {
|
|||
id: backButton
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
|
|
|||
|
|
@ -79,29 +79,22 @@ PageType {
|
|||
id: backButton
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
HeaderTypeWithSwitcher {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("App split tunneling")
|
||||
headerText: qsTr("App split tunneling")
|
||||
|
||||
enabled: root.pageEnabled
|
||||
showSwitcher: true
|
||||
switcher {
|
||||
checked: AppSplitTunnelingModel.isTunnelingEnabled
|
||||
enabled: root.pageEnabled
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
id: switcher
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: root.pageEnabled
|
||||
|
||||
checked: AppSplitTunnelingModel.isTunnelingEnabled
|
||||
onToggled: {
|
||||
AppSplitTunnelingModel.toggleSplitTunneling(checked)
|
||||
selector.text = root.routeModesModel[getRouteModesModelIndex()].name
|
||||
}
|
||||
switcherFunction: function(checked) {
|
||||
AppSplitTunnelingModel.toggleSplitTunneling(checked)
|
||||
selector.text = root.routeModesModel[getRouteModesModelIndex()].name
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ PageType {
|
|||
|
||||
spacing: 16
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("Back up your configuration")
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ PageType {
|
|||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
|
@ -94,9 +94,7 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
visible: root.isAppSplitTinnelingEnabled
|
||||
}
|
||||
DividerType {}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: splitTunnelingButton2
|
||||
|
|
@ -119,29 +117,20 @@ PageType {
|
|||
visible: root.isAppSplitTinnelingEnabled
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
id: killSwitchSwitcher
|
||||
LabelWithButtonType {
|
||||
id: killSwitchButton
|
||||
visible: !GC.isMobile()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
text: qsTr("KillSwitch")
|
||||
descriptionText: qsTr("Disables your internet if your encrypted VPN connection drops out for any reason.")
|
||||
descriptionText: qsTr("Blocks network connections without VPN")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
checked: SettingsController.isKillSwitchEnabled()
|
||||
checkable: !ConnectionController.isConnected
|
||||
onCheckedChanged: {
|
||||
if (checked !== SettingsController.isKillSwitchEnabled()) {
|
||||
SettingsController.toggleKillSwitch(checked)
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
if (!checkable) {
|
||||
PageController.showNotificationMessage(qsTr("Cannot change KillSwitch settings during active connection"))
|
||||
}
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsKillSwitch)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ PageType {
|
|||
|
||||
spacing: 16
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("DNS servers")
|
||||
|
|
|
|||
123
client/ui/qml/Pages2/PageSettingsKillSwitch.qml
Normal file
123
client/ui/qml/Pages2/PageSettingsKillSwitch.qml
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Config"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.height
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
HeaderTypeWithSwitcher {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("KillSwitch")
|
||||
descriptionText: qsTr("Enable to ensure network traffic goes through a secure VPN tunnel, preventing accidental exposure of your IP and DNS queries if the connection drops")
|
||||
|
||||
showSwitcher: true
|
||||
switcher {
|
||||
checked: SettingsController.isKillSwitchEnabled
|
||||
enabled: !ConnectionController.isConnected
|
||||
}
|
||||
switcherFunction: function(checked) {
|
||||
if (!ConnectionController.isConnected) {
|
||||
SettingsController.isKillSwitchEnabled = checked
|
||||
} else {
|
||||
PageController.showNotificationMessage(qsTr("Cannot change killSwitch settings during active connection"))
|
||||
switcher.checked = SettingsController.isKillSwitchEnabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VerticalRadioButton {
|
||||
id: softKillSwitch
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected
|
||||
checked: !SettingsController.strictKillSwitchEnabled
|
||||
|
||||
text: qsTr("Soft KillSwitch")
|
||||
descriptionText: qsTr("Internet connection is blocked if VPN connection drops accidentally")
|
||||
|
||||
onClicked: function() {
|
||||
SettingsController.strictKillSwitchEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
VerticalRadioButton {
|
||||
id: strictKillSwitch
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected
|
||||
checked: SettingsController.strictKillSwitchEnabled
|
||||
|
||||
text: qsTr("Strict KillSwitch")
|
||||
descriptionText: qsTr("Internet connection is blocked even if VPN was turned off manually or not started")
|
||||
|
||||
onClicked: function() {
|
||||
var headerText = qsTr("Just a little heads-up")
|
||||
var descriptionText = qsTr("If you disconnect from VPN or the VPN connection drops while the Strict Kill Switch is turned on, your internet access will be disabled. To restore it, connect to VPN, change the Kill Switch mode or turn the Kill Switch off.")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
SettingsController.strictKillSwitchEnabled = true
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
LabelWithButtonType {
|
||||
Layout.topMargin: 32
|
||||
Layout.fillWidth: true
|
||||
|
||||
enabled: true
|
||||
text: qsTr("DNS Exceptions")
|
||||
descriptionText: qsTr("DNS servers from the list will remain accessible when Kill Switch is triggered")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsKillSwitchExceptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
302
client/ui/qml/Pages2/PageSettingsKillSwitchExceptions.qml
Normal file
302
client/ui/qml/Pages2/PageSettingsKillSwitchExceptions.qml
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import QtCore
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import ProtocolEnum 1.0
|
||||
import ContainerProps 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
import "../Components"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
property bool pageEnabled: true
|
||||
|
||||
ColumnLayout {
|
||||
id: header
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
}
|
||||
|
||||
BaseHeaderType {
|
||||
enabled: root.pageEnabled
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
|
||||
headerText: qsTr("DNS Exceptions")
|
||||
descriptionText: qsTr("DNS servers from the list will remain accessible when Kill Switch is triggered")
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
|
||||
anchors.top: header.bottom
|
||||
anchors.topMargin: 16
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
width: parent.width
|
||||
|
||||
enabled: root.pageEnabled
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
cacheBuffer: 200
|
||||
displayMarginBeginning: 40
|
||||
displayMarginEnd: 40
|
||||
|
||||
ScrollBar.vertical: ScrollBarType { }
|
||||
|
||||
footer: Item {
|
||||
width: listView.width
|
||||
height: addSitePanel.height
|
||||
}
|
||||
|
||||
footerPositioning: ListView.InlineFooter
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: dnsFilterModel
|
||||
sourceModel: AllowedDnsModel
|
||||
filters: [
|
||||
RegExpFilter {
|
||||
roleName: "ip"
|
||||
pattern: ".*" + addSitePanel.textField.text + ".*"
|
||||
caseSensitivity: Qt.CaseInsensitive
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
clip: true
|
||||
|
||||
reuseItems: true
|
||||
|
||||
delegate: ColumnLayout {
|
||||
id: delegateContent
|
||||
|
||||
width: listView.width
|
||||
|
||||
LabelWithButtonType {
|
||||
id: site
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: ip
|
||||
rightImageSource: "qrc:/images/controls/trash.svg"
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Delete ") + ip + "?"
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
AllowedDnsController.removeDns(dnsFilterModel.mapToSource(index))
|
||||
if (!GC.isMobile()) {
|
||||
site.rightButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
site.rightButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
}
|
||||
|
||||
AddSitePanel {
|
||||
id: addSitePanel
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
enabled: root.pageEnabled
|
||||
placeholderText: qsTr("IPv4 address")
|
||||
|
||||
onAddClicked: function(text) {
|
||||
PageController.showBusyIndicator(true)
|
||||
AllowedDnsController.addDns(text)
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
|
||||
onMoreClicked: {
|
||||
moreActionsDrawer.openTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
DrawerType2 {
|
||||
id: moreActionsDrawer
|
||||
|
||||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.4375
|
||||
|
||||
expandedStateContent: ColumnLayout {
|
||||
id: moreActionsDrawerContent
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
headerText: qsTr("Import / Export addresses")
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: importSitesButton
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Import")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
importSitesDrawer.openTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: exportSitesButton
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Save address list")
|
||||
|
||||
clickedFunction: function() {
|
||||
var fileName = ""
|
||||
if (GC.isMobile()) {
|
||||
fileName = "amnezia_killswitch_exceptions.json"
|
||||
} else {
|
||||
fileName = SystemController.getFileName(qsTr("Save addresses"),
|
||||
qsTr("Address files (*.json)"),
|
||||
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/amnezia_killswitch_exceptions",
|
||||
true,
|
||||
".json")
|
||||
}
|
||||
if (fileName !== "") {
|
||||
PageController.showBusyIndicator(true)
|
||||
AllowedDnsController.exportDns(fileName)
|
||||
moreActionsDrawer.closeTriggered()
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
}
|
||||
|
||||
DrawerType2 {
|
||||
id: importSitesDrawer
|
||||
|
||||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.4375
|
||||
|
||||
expandedStateContent: Item {
|
||||
implicitHeight: importSitesDrawer.expandedHeight
|
||||
|
||||
BackButtonType {
|
||||
id: importSitesDrawerBackButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 16
|
||||
|
||||
backButtonFunction: function() {
|
||||
importSitesDrawer.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
anchors.top: importSitesDrawerBackButton.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
contentHeight: importSitesDrawerContent.height
|
||||
|
||||
ColumnLayout {
|
||||
id: importSitesDrawerContent
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
headerText: qsTr("Import address list")
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: importSitesButton2
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Replace address list")
|
||||
|
||||
clickedFunction: function() {
|
||||
var fileName = SystemController.getFileName(qsTr("Open address file"),
|
||||
qsTr("Address files (*.json)"))
|
||||
if (fileName !== "") {
|
||||
importSitesDrawerContent.importSites(fileName, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: importSitesButton3
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Add imported addresses to existing ones")
|
||||
|
||||
clickedFunction: function() {
|
||||
var fileName = SystemController.getFileName(qsTr("Open address file"),
|
||||
qsTr("Address files (*.json)"))
|
||||
if (fileName !== "") {
|
||||
importSitesDrawerContent.importSites(fileName, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function importSites(fileName, replaceExistingSites) {
|
||||
PageController.showBusyIndicator(true)
|
||||
AllowedDnsController.importDns(fileName, replaceExistingSites)
|
||||
PageController.showBusyIndicator(false)
|
||||
importSitesDrawer.closeTriggered()
|
||||
moreActionsDrawer.closeTriggered()
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ PageType {
|
|||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ PageType {
|
|||
objectName: "backButton"
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
HeaderTypeWithButton {
|
||||
id: headerContent
|
||||
objectName: "headerContent"
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ PageType {
|
|||
id: backButton
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ PageType {
|
|||
id: backButton
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
|
|
|||
|
|
@ -94,33 +94,22 @@ PageType {
|
|||
id: backButton
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
HeaderType {
|
||||
enabled: root.pageEnabled
|
||||
HeaderTypeWithSwitcher {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
|
||||
headerText: qsTr("Split tunneling")
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
id: switcher
|
||||
|
||||
enabled: root.pageEnabled
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
|
||||
function onToggledFunc() {
|
||||
SitesModel.toggleSplitTunneling(this.checked)
|
||||
selector.text = root.routeModesModel[getRouteModesModelIndex()].name
|
||||
}
|
||||
headerText: qsTr("Split tunneling")
|
||||
|
||||
enabled: root.pageEnabled
|
||||
showSwitcher: true
|
||||
switcher {
|
||||
checked: SitesModel.isTunnelingEnabled
|
||||
onToggled: { onToggledFunc() }
|
||||
Keys.onEnterPressed: { onToggledFunc() }
|
||||
Keys.onReturnPressed: { onToggledFunc() }
|
||||
enabled: root.pageEnabled
|
||||
}
|
||||
switcherFunction: function(checked) {
|
||||
SitesModel.toggleSplitTunneling(checked)
|
||||
selector.text = root.routeModesModel[getRouteModesModelIndex()].name
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ PageType {
|
|||
Layout.topMargin: 20
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.rightMargin: 16
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ PageType {
|
|||
Layout.topMargin: 20
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.rightMargin: 16
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ PageType {
|
|||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
HeaderType {
|
||||
HeaderTypeWithButton {
|
||||
id: moreButton
|
||||
|
||||
property bool isVisible: SettingsController.getInstallationUuid() !== "" || PageController.isStartPageVisible()
|
||||
|
|
@ -76,7 +76,7 @@ PageType {
|
|||
anchors.right: parent.right
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ PageType {
|
|||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ PageType {
|
|||
|
||||
spacing: 16
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
|
||||
implicitWidth: parent.width
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ PageType {
|
|||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ PageType {
|
|||
Layout.leftMargin: -16
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ PageType {
|
|||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ PageType {
|
|||
Layout.topMargin: 20
|
||||
}
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ PageType {
|
|||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
headerText: qsTr("New connection")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
HeaderTypeWithButton {
|
||||
id: header
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ PageType {
|
|||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue