mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-28 23:42:51 -05:00
net: switch to native VPN backend
This commit is contained in:
@@ -216,8 +216,8 @@ Item {
|
|||||||
Connections {
|
Connections {
|
||||||
target: NetworkService
|
target: NetworkService
|
||||||
|
|
||||||
function onCredentialsNeeded(token, ssid, setting, fields, hints, reason) {
|
function onCredentialsNeeded(token, ssid, setting, fields, hints, reason, connType, connName, vpnService) {
|
||||||
wifiPasswordModal.showFromPrompt(token, ssid, setting, fields, hints, reason)
|
wifiPasswordModal.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ DankModal {
|
|||||||
property var promptFields: []
|
property var promptFields: []
|
||||||
property string promptSetting: ""
|
property string promptSetting: ""
|
||||||
|
|
||||||
|
property bool isVpnPrompt: false
|
||||||
|
property string connectionName: ""
|
||||||
|
property string vpnServiceType: ""
|
||||||
|
property string connectionType: ""
|
||||||
|
|
||||||
function show(ssid) {
|
function show(ssid) {
|
||||||
wifiPasswordSSID = ssid
|
wifiPasswordSSID = ssid
|
||||||
wifiPasswordInput = ""
|
wifiPasswordInput = ""
|
||||||
@@ -32,6 +37,10 @@ DankModal {
|
|||||||
promptReason = ""
|
promptReason = ""
|
||||||
promptFields = []
|
promptFields = []
|
||||||
promptSetting = ""
|
promptSetting = ""
|
||||||
|
isVpnPrompt = false
|
||||||
|
connectionName = ""
|
||||||
|
vpnServiceType = ""
|
||||||
|
connectionType = ""
|
||||||
|
|
||||||
const network = NetworkService.wifiNetworks.find(n => n.ssid === ssid)
|
const network = NetworkService.wifiNetworks.find(n => n.ssid === ssid)
|
||||||
requiresEnterprise = network?.enterprise || false
|
requiresEnterprise = network?.enterprise || false
|
||||||
@@ -48,13 +57,18 @@ DankModal {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function showFromPrompt(token, ssid, setting, fields, hints, reason) {
|
function showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService) {
|
||||||
wifiPasswordSSID = ssid
|
|
||||||
isPromptMode = true
|
isPromptMode = true
|
||||||
promptToken = token
|
promptToken = token
|
||||||
promptReason = reason
|
promptReason = reason
|
||||||
promptFields = fields || []
|
promptFields = fields || []
|
||||||
promptSetting = setting || "802-11-wireless-security"
|
promptSetting = setting || "802-11-wireless-security"
|
||||||
|
connectionType = connType || "802-11-wireless"
|
||||||
|
connectionName = connName || ssid || ""
|
||||||
|
vpnServiceType = vpnService || ""
|
||||||
|
|
||||||
|
isVpnPrompt = (connectionType === "vpn" || connectionType === "wireguard")
|
||||||
|
wifiPasswordSSID = isVpnPrompt ? connectionName : ssid
|
||||||
|
|
||||||
requiresEnterprise = setting === "802-1x"
|
requiresEnterprise = setting === "802-1x"
|
||||||
|
|
||||||
@@ -163,7 +177,12 @@ DankModal {
|
|||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("Connect to Wi-Fi")
|
text: {
|
||||||
|
if (isVpnPrompt) {
|
||||||
|
return I18n.tr("Connect to VPN")
|
||||||
|
}
|
||||||
|
return I18n.tr("Connect to Wi-Fi")
|
||||||
|
}
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
@@ -175,6 +194,9 @@ DankModal {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: {
|
text: {
|
||||||
|
if (isVpnPrompt) {
|
||||||
|
return I18n.tr("Enter password for ") + wifiPasswordSSID
|
||||||
|
}
|
||||||
const prefix = requiresEnterprise ? I18n.tr("Enter credentials for ") : I18n.tr("Enter password for ")
|
const prefix = requiresEnterprise ? I18n.tr("Enter credentials for ") : I18n.tr("Enter password for ")
|
||||||
return prefix + wifiPasswordSSID
|
return prefix + wifiPasswordSSID
|
||||||
}
|
}
|
||||||
@@ -218,7 +240,7 @@ DankModal {
|
|||||||
color: Theme.surfaceHover
|
color: Theme.surfaceHover
|
||||||
border.color: usernameInput.activeFocus ? Theme.primary : Theme.outlineStrong
|
border.color: usernameInput.activeFocus ? Theme.primary : Theme.outlineStrong
|
||||||
border.width: usernameInput.activeFocus ? 2 : 1
|
border.width: usernameInput.activeFocus ? 2 : 1
|
||||||
visible: requiresEnterprise
|
visible: requiresEnterprise && !isVpnPrompt
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -271,7 +293,7 @@ DankModal {
|
|||||||
textColor: Theme.surfaceText
|
textColor: Theme.surfaceText
|
||||||
text: wifiPasswordInput
|
text: wifiPasswordInput
|
||||||
echoMode: showPasswordCheckbox.checked ? TextInput.Normal : TextInput.Password
|
echoMode: showPasswordCheckbox.checked ? TextInput.Normal : TextInput.Password
|
||||||
placeholderText: requiresEnterprise ? I18n.tr("Password") : ""
|
placeholderText: (requiresEnterprise && !isVpnPrompt) ? I18n.tr("Password") : ""
|
||||||
backgroundColor: "transparent"
|
backgroundColor: "transparent"
|
||||||
focus: !requiresEnterprise
|
focus: !requiresEnterprise
|
||||||
enabled: root.shouldBeVisible
|
enabled: root.shouldBeVisible
|
||||||
@@ -281,7 +303,9 @@ DankModal {
|
|||||||
onAccepted: () => {
|
onAccepted: () => {
|
||||||
if (isPromptMode) {
|
if (isPromptMode) {
|
||||||
const secrets = {}
|
const secrets = {}
|
||||||
if (promptSetting === "802-11-wireless-security") {
|
if (isVpnPrompt) {
|
||||||
|
if (passwordInput.text) secrets["password"] = passwordInput.text
|
||||||
|
} else if (promptSetting === "802-11-wireless-security") {
|
||||||
secrets["psk"] = passwordInput.text
|
secrets["psk"] = passwordInput.text
|
||||||
} else if (promptSetting === "802-1x") {
|
} else if (promptSetting === "802-1x") {
|
||||||
if (usernameInput.text) secrets["identity"] = usernameInput.text
|
if (usernameInput.text) secrets["identity"] = usernameInput.text
|
||||||
@@ -340,7 +364,7 @@ DankModal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
visible: requiresEnterprise
|
visible: requiresEnterprise && !isVpnPrompt
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 50
|
height: 50
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
@@ -372,7 +396,7 @@ DankModal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
visible: requiresEnterprise
|
visible: requiresEnterprise && !isVpnPrompt
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 50
|
height: 50
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
@@ -495,7 +519,12 @@ DankModal {
|
|||||||
height: 36
|
height: 36
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: connectArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary
|
color: connectArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary
|
||||||
enabled: requiresEnterprise ? (usernameInput.text.length > 0 && passwordInput.text.length > 0) : passwordInput.text.length > 0
|
enabled: {
|
||||||
|
if (isVpnPrompt) {
|
||||||
|
return passwordInput.text.length > 0
|
||||||
|
}
|
||||||
|
return requiresEnterprise ? (usernameInput.text.length > 0 && passwordInput.text.length > 0) : passwordInput.text.length > 0
|
||||||
|
}
|
||||||
opacity: enabled ? 1 : 0.5
|
opacity: enabled ? 1 : 0.5
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -518,7 +547,9 @@ DankModal {
|
|||||||
onClicked: () => {
|
onClicked: () => {
|
||||||
if (isPromptMode) {
|
if (isPromptMode) {
|
||||||
const secrets = {}
|
const secrets = {}
|
||||||
if (promptSetting === "802-11-wireless-security") {
|
if (isVpnPrompt) {
|
||||||
|
if (passwordInput.text) secrets["password"] = passwordInput.text
|
||||||
|
} else if (promptSetting === "802-11-wireless-security") {
|
||||||
secrets["psk"] = passwordInput.text
|
secrets["psk"] = passwordInput.text
|
||||||
} else if (promptSetting === "802-1x") {
|
} else if (promptSetting === "802-1x") {
|
||||||
if (usernameInput.text) secrets["identity"] = usernameInput.text
|
if (usernameInput.text) secrets["identity"] = usernameInput.text
|
||||||
|
|||||||
@@ -10,26 +10,26 @@ PluginComponent {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
Ref {
|
Ref {
|
||||||
service: VpnService
|
service: DMSNetworkService
|
||||||
}
|
}
|
||||||
|
|
||||||
ccWidgetIcon: VpnService.isBusy ? "sync" : (VpnService.connected ? "vpn_lock" : "vpn_key_off")
|
ccWidgetIcon: DMSNetworkService.isBusy ? "sync" : (DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off")
|
||||||
ccWidgetPrimaryText: "VPN"
|
ccWidgetPrimaryText: "VPN"
|
||||||
ccWidgetSecondaryText: {
|
ccWidgetSecondaryText: {
|
||||||
if (!VpnService.connected)
|
if (!DMSNetworkService.connected)
|
||||||
return "Disconnected"
|
return "Disconnected"
|
||||||
const names = VpnService.activeNames || []
|
const names = DMSNetworkService.activeNames || []
|
||||||
if (names.length <= 1)
|
if (names.length <= 1)
|
||||||
return names[0] || "Connected"
|
return names[0] || "Connected"
|
||||||
return names[0] + " +" + (names.length - 1)
|
return names[0] + " +" + (names.length - 1)
|
||||||
}
|
}
|
||||||
ccWidgetIsActive: VpnService.connected
|
ccWidgetIsActive: DMSNetworkService.connected
|
||||||
|
|
||||||
onCcWidgetToggled: {
|
onCcWidgetToggled: {
|
||||||
if (VpnService.connected) {
|
if (DMSNetworkService.connected) {
|
||||||
VpnService.disconnectAllActive()
|
DMSNetworkService.disconnectAllActive()
|
||||||
} else if (VpnService.profiles.length > 0) {
|
} else if (DMSNetworkService.profiles.length > 0) {
|
||||||
VpnService.connect(VpnService.profiles[0].uuid)
|
DMSNetworkService.connect(DMSNetworkService.profiles[0].uuid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,9 +52,9 @@ PluginComponent {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: {
|
text: {
|
||||||
if (!VpnService.connected)
|
if (!DMSNetworkService.connected)
|
||||||
return "Active: None"
|
return "Active: None"
|
||||||
const names = VpnService.activeNames || []
|
const names = DMSNetworkService.activeNames || []
|
||||||
if (names.length <= 1)
|
if (names.length <= 1)
|
||||||
return "Active: " + (names[0] || "VPN")
|
return "Active: " + (names[0] || "VPN")
|
||||||
return "Active: " + names[0] + " +" + (names.length - 1)
|
return "Active: " + names[0] + " +" + (names.length - 1)
|
||||||
@@ -72,7 +72,7 @@ PluginComponent {
|
|||||||
height: 28
|
height: 28
|
||||||
radius: 14
|
radius: 14
|
||||||
color: discAllArea.containsMouse ? Theme.errorHover : Theme.surfaceLight
|
color: discAllArea.containsMouse ? Theme.errorHover : Theme.surfaceLight
|
||||||
visible: VpnService.connected
|
visible: DMSNetworkService.connected
|
||||||
width: 110
|
width: 110
|
||||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ PluginComponent {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: VpnService.disconnectAllActive()
|
onClicked: DMSNetworkService.disconnectAllActive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,7 @@ PluginComponent {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: VpnService.profiles.length === 0 ? 120 : 0
|
height: DMSNetworkService.profiles.length === 0 ? 120 : 0
|
||||||
visible: height > 0
|
visible: height > 0
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
@@ -154,7 +154,7 @@ PluginComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: VpnService.profiles
|
model: DMSNetworkService.profiles
|
||||||
|
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
required property var modelData
|
required property var modelData
|
||||||
@@ -162,9 +162,9 @@ PluginComponent {
|
|||||||
width: parent ? parent.width : 300
|
width: parent ? parent.width : 300
|
||||||
height: 50
|
height: 50
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: rowArea.containsMouse ? Theme.primaryHoverLight : (VpnService.isActiveUuid(modelData.uuid) ? Theme.primaryPressed : Theme.surfaceLight)
|
color: rowArea.containsMouse ? Theme.primaryHoverLight : (DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primaryPressed : Theme.surfaceLight)
|
||||||
border.width: VpnService.isActiveUuid(modelData.uuid) ? 2 : 1
|
border.width: DMSNetworkService.isActiveUuid(modelData.uuid) ? 2 : 1
|
||||||
border.color: VpnService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.outlineLight
|
border.color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.outlineLight
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
@@ -174,9 +174,9 @@ PluginComponent {
|
|||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
name: VpnService.isActiveUuid(modelData.uuid) ? "vpn_lock" : "vpn_key_off"
|
name: DMSNetworkService.isActiveUuid(modelData.uuid) ? "vpn_lock" : "vpn_key_off"
|
||||||
size: Theme.iconSize - 4
|
size: Theme.iconSize - 4
|
||||||
color: VpnService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText
|
color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ PluginComponent {
|
|||||||
StyledText {
|
StyledText {
|
||||||
text: modelData.name
|
text: modelData.name
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: VpnService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText
|
color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -234,7 +234,7 @@ PluginComponent {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: VpnService.toggle(modelData.uuid)
|
onClicked: DMSNetworkService.toggle(modelData.uuid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,8 +143,8 @@ QtObject {
|
|||||||
"description": "VPN connections",
|
"description": "VPN connections",
|
||||||
"icon": "vpn_key",
|
"icon": "vpn_key",
|
||||||
"type": "builtin_plugin",
|
"type": "builtin_plugin",
|
||||||
"enabled": VpnService.available,
|
"enabled": DMSNetworkService.available,
|
||||||
"warning": !VpnService.available ? "VPN not available" : undefined,
|
"warning": !DMSNetworkService.available ? "VPN not available" : undefined,
|
||||||
"isBuiltinPlugin": true
|
"isBuiltinPlugin": true
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ DankPopout {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
Ref {
|
Ref {
|
||||||
service: VpnService
|
service: DMSNetworkService
|
||||||
}
|
}
|
||||||
|
|
||||||
property var triggerScreen: null
|
property var triggerScreen: null
|
||||||
@@ -161,11 +161,11 @@ DankPopout {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: {
|
text: {
|
||||||
if (!VpnService.connected) {
|
if (!DMSNetworkService.connected) {
|
||||||
return "Active: None";
|
return "Active: None";
|
||||||
}
|
}
|
||||||
|
|
||||||
const names = VpnService.activeNames || [];
|
const names = DMSNetworkService.activeNames || [];
|
||||||
if (names.length <= 1) {
|
if (names.length <= 1) {
|
||||||
return "Active: " + (names[0] || "VPN");
|
return "Active: " + (names[0] || "VPN");
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,7 @@ DankPopout {
|
|||||||
height: 28
|
height: 28
|
||||||
radius: 14
|
radius: 14
|
||||||
color: discAllArea.containsMouse ? Theme.errorHover : Theme.surfaceLight
|
color: discAllArea.containsMouse ? Theme.errorHover : Theme.surfaceLight
|
||||||
visible: VpnService.connected
|
visible: DMSNetworkService.connected
|
||||||
width: 130
|
width: 130
|
||||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
||||||
border.width: 0
|
border.width: 0
|
||||||
@@ -224,7 +224,7 @@ DankPopout {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: VpnService.disconnectAllActive()
|
onClicked: DMSNetworkService.disconnectAllActive()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -251,7 +251,7 @@ DankPopout {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: VpnService.profiles.length === 0 ? 120 : 0
|
height: DMSNetworkService.profiles.length === 0 ? 120 : 0
|
||||||
visible: height > 0
|
visible: height > 0
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
@@ -284,7 +284,7 @@ DankPopout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: VpnService.profiles
|
model: DMSNetworkService.profiles
|
||||||
|
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
required property var modelData
|
required property var modelData
|
||||||
@@ -292,9 +292,9 @@ DankPopout {
|
|||||||
width: parent ? parent.width : 300
|
width: parent ? parent.width : 300
|
||||||
height: 50
|
height: 50
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: rowArea.containsMouse ? Theme.primaryHoverLight : (VpnService.isActiveUuid(modelData.uuid) ? Theme.primaryPressed : Theme.surfaceLight)
|
color: rowArea.containsMouse ? Theme.primaryHoverLight : (DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primaryPressed : Theme.surfaceLight)
|
||||||
border.width: VpnService.isActiveUuid(modelData.uuid) ? 2 : 1
|
border.width: DMSNetworkService.isActiveUuid(modelData.uuid) ? 2 : 1
|
||||||
border.color: VpnService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.outlineLight
|
border.color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.outlineLight
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
@@ -304,9 +304,9 @@ DankPopout {
|
|||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
name: VpnService.isActiveUuid(modelData.uuid) ? "vpn_lock" : "vpn_key_off"
|
name: DMSNetworkService.isActiveUuid(modelData.uuid) ? "vpn_lock" : "vpn_key_off"
|
||||||
size: Theme.iconSize - 4
|
size: Theme.iconSize - 4
|
||||||
color: VpnService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText
|
color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,7 +317,7 @@ DankPopout {
|
|||||||
StyledText {
|
StyledText {
|
||||||
text: modelData.name
|
text: modelData.name
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: VpnService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText
|
color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -392,7 +392,7 @@ DankPopout {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: VpnService.toggle(modelData.uuid)
|
onClicked: DMSNetworkService.toggle(modelData.uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ BasePill {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
Ref {
|
Ref {
|
||||||
service: VpnService
|
service: DMSNetworkService
|
||||||
}
|
}
|
||||||
|
|
||||||
property var popoutTarget: null
|
property var popoutTarget: null
|
||||||
@@ -24,9 +24,9 @@ BasePill {
|
|||||||
DankIcon {
|
DankIcon {
|
||||||
id: icon
|
id: icon
|
||||||
|
|
||||||
name: VpnService.isBusy ? "sync" : (VpnService.connected ? "vpn_lock" : "vpn_key_off")
|
name: DMSNetworkService.isBusy ? "sync" : (DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off")
|
||||||
size: Theme.barIconSize(root.barThickness, -4)
|
size: Theme.barIconSize(root.barThickness, -4)
|
||||||
color: VpnService.connected ? Theme.primary : Theme.surfaceText
|
color: DMSNetworkService.connected ? Theme.primary : Theme.surfaceText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,10 +59,10 @@ BasePill {
|
|||||||
tooltipLoader.active = true
|
tooltipLoader.active = true
|
||||||
if (tooltipLoader.item) {
|
if (tooltipLoader.item) {
|
||||||
let tooltipText = ""
|
let tooltipText = ""
|
||||||
if (!VpnService.connected) {
|
if (!DMSNetworkService.connected) {
|
||||||
tooltipText = "VPN Disconnected"
|
tooltipText = "VPN Disconnected"
|
||||||
} else {
|
} else {
|
||||||
const names = VpnService.activeNames || []
|
const names = DMSNetworkService.activeNames || []
|
||||||
if (names.length <= 1) {
|
if (names.length <= 1) {
|
||||||
tooltipText = "VPN Connected • " + (names[0] || "")
|
tooltipText = "VPN Connected • " + (names[0] || "")
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -69,6 +69,24 @@ Singleton {
|
|||||||
property string wifiPassword: ""
|
property string wifiPassword: ""
|
||||||
property string forgetSSID: ""
|
property string forgetSSID: ""
|
||||||
|
|
||||||
|
property var vpnProfiles: []
|
||||||
|
property var vpnActive: []
|
||||||
|
property bool vpnAvailable: false
|
||||||
|
property bool vpnIsBusy: false
|
||||||
|
|
||||||
|
property alias profiles: root.vpnProfiles
|
||||||
|
property alias activeConnections: root.vpnActive
|
||||||
|
property var activeUuids: vpnActive.map(v => v.uuid).filter(u => !!u)
|
||||||
|
property var activeNames: vpnActive.map(v => v.name).filter(n => !!n)
|
||||||
|
property string activeUuid: activeUuids.length > 0 ? activeUuids[0] : ""
|
||||||
|
property string activeName: activeNames.length > 0 ? activeNames[0] : ""
|
||||||
|
property string activeDevice: vpnActive.length > 0 ? (vpnActive[0].device || "") : ""
|
||||||
|
property string activeState: vpnActive.length > 0 ? (vpnActive[0].state || "") : ""
|
||||||
|
property bool vpnConnected: activeUuids.length > 0
|
||||||
|
property alias available: root.vpnAvailable
|
||||||
|
property alias isBusy: root.vpnIsBusy
|
||||||
|
property alias connected: root.vpnConnected
|
||||||
|
|
||||||
property string networkInfoSSID: ""
|
property string networkInfoSSID: ""
|
||||||
property string networkInfoDetails: ""
|
property string networkInfoDetails: ""
|
||||||
property bool networkInfoLoading: false
|
property bool networkInfoLoading: false
|
||||||
@@ -94,7 +112,7 @@ Singleton {
|
|||||||
|
|
||||||
signal networksUpdated
|
signal networksUpdated
|
||||||
signal connectionChanged
|
signal connectionChanged
|
||||||
signal credentialsNeeded(string token, string ssid, string setting, var fields, var hints, string reason)
|
signal credentialsNeeded(string token, string ssid, string setting, var fields, var hints, string reason, string connType, string connName, string vpnService)
|
||||||
|
|
||||||
readonly property string socketPath: Quickshell.env("DMS_SOCKET")
|
readonly property string socketPath: Quickshell.env("DMS_SOCKET")
|
||||||
|
|
||||||
@@ -164,7 +182,11 @@ Singleton {
|
|||||||
credentialsReason = data.reason || "Credentials required"
|
credentialsReason = data.reason || "Credentials required"
|
||||||
credentialsRequested = true
|
credentialsRequested = true
|
||||||
|
|
||||||
credentialsNeeded(credentialsToken, credentialsSSID, credentialsSetting, credentialsFields, credentialsHints, credentialsReason)
|
const connType = data.connType || ""
|
||||||
|
const connName = data.name || data.connectionId || ""
|
||||||
|
const vpnService = data.vpnService || ""
|
||||||
|
|
||||||
|
credentialsNeeded(credentialsToken, credentialsSSID, credentialsSetting, credentialsFields, credentialsHints, credentialsReason, connType, connName, vpnService)
|
||||||
}
|
}
|
||||||
|
|
||||||
function addRef() {
|
function addRef() {
|
||||||
@@ -202,6 +224,7 @@ Singleton {
|
|||||||
const previousConnectingSSID = connectingSSID
|
const previousConnectingSSID = connectingSSID
|
||||||
|
|
||||||
backend = state.backend || ""
|
backend = state.backend || ""
|
||||||
|
vpnAvailable = networkAvailable && backend === "networkmanager"
|
||||||
networkStatus = state.networkStatus || "disconnected"
|
networkStatus = state.networkStatus || "disconnected"
|
||||||
primaryConnection = state.primaryConnection || ""
|
primaryConnection = state.primaryConnection || ""
|
||||||
|
|
||||||
@@ -244,6 +267,12 @@ Singleton {
|
|||||||
networksUpdated()
|
networksUpdated()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state.vpnProfiles) {
|
||||||
|
vpnProfiles = state.vpnProfiles
|
||||||
|
}
|
||||||
|
|
||||||
|
vpnActive = state.vpnActive || []
|
||||||
|
|
||||||
userPreference = state.preference || "auto"
|
userPreference = state.preference || "auto"
|
||||||
isConnecting = state.isConnecting || false
|
isConnecting = state.isConnecting || false
|
||||||
connectingSSID = state.connectingSSID || ""
|
connectingSSID = state.connectingSSID || ""
|
||||||
@@ -677,6 +706,122 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function refreshVpnProfiles() {
|
||||||
|
if (!vpnAvailable) return
|
||||||
|
|
||||||
|
DMSService.sendRequest("network.vpn.profiles", null, response => {
|
||||||
|
if (response.result) {
|
||||||
|
vpnProfiles = response.result
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshVpnActive() {
|
||||||
|
if (!vpnAvailable) return
|
||||||
|
|
||||||
|
DMSService.sendRequest("network.vpn.active", null, response => {
|
||||||
|
if (response.result) {
|
||||||
|
vpnActive = response.result
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectVpn(uuidOrName, singleActive = false) {
|
||||||
|
if (!vpnAvailable || vpnIsBusy) return
|
||||||
|
|
||||||
|
vpnIsBusy = true
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
uuidOrName: uuidOrName,
|
||||||
|
singleActive: singleActive
|
||||||
|
}
|
||||||
|
|
||||||
|
DMSService.sendRequest("network.vpn.connect", params, response => {
|
||||||
|
vpnIsBusy = false
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
ToastService.showError(I18n.tr("Failed to connect VPN"))
|
||||||
|
} else {
|
||||||
|
Qt.callLater(() => getState())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function connect(uuidOrName, singleActive = false) {
|
||||||
|
connectVpn(uuidOrName, singleActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
function disconnectVpn(uuidOrName) {
|
||||||
|
if (!vpnAvailable || vpnIsBusy) return
|
||||||
|
|
||||||
|
vpnIsBusy = true
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
uuidOrName: uuidOrName
|
||||||
|
}
|
||||||
|
|
||||||
|
DMSService.sendRequest("network.vpn.disconnect", params, response => {
|
||||||
|
vpnIsBusy = false
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
ToastService.showError(I18n.tr("Failed to disconnect VPN"))
|
||||||
|
} else {
|
||||||
|
Qt.callLater(() => getState())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function disconnect(uuidOrName) {
|
||||||
|
disconnectVpn(uuidOrName)
|
||||||
|
}
|
||||||
|
|
||||||
|
function disconnectAllVpns() {
|
||||||
|
if (!vpnAvailable || vpnIsBusy) return
|
||||||
|
|
||||||
|
vpnIsBusy = true
|
||||||
|
|
||||||
|
DMSService.sendRequest("network.vpn.disconnectAll", null, response => {
|
||||||
|
vpnIsBusy = false
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
ToastService.showError(I18n.tr("Failed to disconnect VPNs"))
|
||||||
|
} else {
|
||||||
|
Qt.callLater(() => getState())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function disconnectAllActive() {
|
||||||
|
disconnectAllVpns()
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleVpn(uuid) {
|
||||||
|
if (uuid) {
|
||||||
|
if (isActiveVpnUuid(uuid)) {
|
||||||
|
disconnectVpn(uuid)
|
||||||
|
} else {
|
||||||
|
connectVpn(uuid)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vpnProfiles.length > 0) {
|
||||||
|
connectVpn(vpnProfiles[0].uuid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle(uuid) {
|
||||||
|
toggleVpn(uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
function isActiveVpnUuid(uuid) {
|
||||||
|
return activeUuids && activeUuids.indexOf(uuid) !== -1
|
||||||
|
}
|
||||||
|
|
||||||
|
function isActiveUuid(uuid) {
|
||||||
|
return isActiveVpnUuid(uuid)
|
||||||
|
}
|
||||||
|
|
||||||
function refreshNetworkState() {
|
function refreshNetworkState() {
|
||||||
if (networkAvailable) {
|
if (networkAvailable) {
|
||||||
getState()
|
getState()
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ Singleton {
|
|||||||
|
|
||||||
signal networksUpdated
|
signal networksUpdated
|
||||||
signal connectionChanged
|
signal connectionChanged
|
||||||
signal credentialsNeeded(string token, string ssid, string setting, var fields, var hints, string reason)
|
signal credentialsNeeded(string token, string ssid, string setting, var fields, var hints, string reason, string connType, string connName, string vpnService)
|
||||||
|
|
||||||
property bool usingLegacy: false
|
property bool usingLegacy: false
|
||||||
property var activeService: null
|
property var activeService: null
|
||||||
|
|||||||
@@ -1,246 +0,0 @@
|
|||||||
pragma Singleton
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
|
|
||||||
// Minimal VPN controller backed by NetworkManager (nmcli + D-Bus monitor)
|
|
||||||
Singleton {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property int refCount: 0
|
|
||||||
|
|
||||||
onRefCountChanged: {
|
|
||||||
console.log("VpnService: refCount changed to", refCount)
|
|
||||||
if (refCount > 0 && !nmMonitor.running) {
|
|
||||||
console.log("VpnService: Starting nmMonitor")
|
|
||||||
nmMonitor.running = true
|
|
||||||
refreshAll()
|
|
||||||
} else if (refCount === 0 && nmMonitor.running) {
|
|
||||||
console.log("VpnService: Stopping nmMonitor")
|
|
||||||
nmMonitor.running = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// State
|
|
||||||
property bool available: true
|
|
||||||
property bool isBusy: false
|
|
||||||
property string errorMessage: ""
|
|
||||||
|
|
||||||
// Profiles discovered on the system
|
|
||||||
// [{ name, uuid, type }]
|
|
||||||
property var profiles: []
|
|
||||||
|
|
||||||
// Allow multiple active VPNs (set true to allow concurrent connections)
|
|
||||||
// Default: allow multiple, to align with NetworkManager capability
|
|
||||||
property bool singleActive: false
|
|
||||||
|
|
||||||
// Active VPN connections (may be multiple)
|
|
||||||
// Full list and convenience projections
|
|
||||||
property var activeConnections: [] // [{ name, uuid, device, state }]
|
|
||||||
property var activeUuids: []
|
|
||||||
property var activeNames: []
|
|
||||||
// Back-compat single values (first active if present)
|
|
||||||
property string activeUuid: activeUuids.length > 0 ? activeUuids[0] : ""
|
|
||||||
property string activeName: activeNames.length > 0 ? activeNames[0] : ""
|
|
||||||
property string activeDevice: activeConnections.length > 0 ? (activeConnections[0].device || "") : ""
|
|
||||||
property string activeState: activeConnections.length > 0 ? (activeConnections[0].state || "") : ""
|
|
||||||
property bool connected: activeUuids.length > 0
|
|
||||||
|
|
||||||
// Use implicit property notify signals (profilesChanged, activeUuidChanged, etc.)
|
|
||||||
|
|
||||||
function refreshAll() {
|
|
||||||
listProfiles()
|
|
||||||
refreshActive()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Monitor NetworkManager changes and refresh on activity
|
|
||||||
Process {
|
|
||||||
id: nmMonitor
|
|
||||||
command: ["gdbus", "monitor", "--system", "--dest", "org.freedesktop.NetworkManager"]
|
|
||||||
running: false
|
|
||||||
|
|
||||||
stdout: SplitParser {
|
|
||||||
splitMarker: "\n"
|
|
||||||
onRead: line => {
|
|
||||||
if (line.includes("ActiveConnection") || line.includes("PropertiesChanged") || line.includes("StateChanged")) {
|
|
||||||
refreshAll()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Query all VPN profiles
|
|
||||||
function listProfiles() {
|
|
||||||
getProfiles.running = true
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: getProfiles
|
|
||||||
command: ["bash", "-lc", "nmcli -t -f NAME,UUID,TYPE connection show | while IFS=: read -r name uuid type; do case \"$type\" in vpn) svc=$(nmcli -g vpn.service-type connection show uuid \"$uuid\" 2>/dev/null); echo \"$name:$uuid:$type:$svc\" ;; wireguard) echo \"$name:$uuid:$type:\" ;; *) : ;; esac; done"]
|
|
||||||
running: false
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
const lines = text.trim().length ? text.trim().split('\n') : []
|
|
||||||
const out = []
|
|
||||||
for (const line of lines) {
|
|
||||||
const parts = line.split(':')
|
|
||||||
if (parts.length >= 3 && (parts[2] === "vpn" || parts[2] === "wireguard")) {
|
|
||||||
const svc = parts.length >= 4 ? parts[3] : ""
|
|
||||||
out.push({ name: parts[0], uuid: parts[1], type: parts[2], serviceType: svc })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
root.profiles = out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Query active VPN connection
|
|
||||||
function refreshActive() {
|
|
||||||
getActive.running = true
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: getActive
|
|
||||||
command: ["nmcli", "-t", "-f", "NAME,UUID,TYPE,DEVICE,STATE", "connection", "show", "--active"]
|
|
||||||
running: false
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
const lines = text.trim().length ? text.trim().split('\n') : []
|
|
||||||
let act = []
|
|
||||||
for (const line of lines) {
|
|
||||||
const parts = line.split(':')
|
|
||||||
if (parts.length >= 5 && (parts[2] === "vpn" || parts[2] === "wireguard")) {
|
|
||||||
act.push({ name: parts[0], uuid: parts[1], device: parts[3], state: parts[4] })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
root.activeConnections = act
|
|
||||||
root.activeUuids = act.map(a => a.uuid).filter(u => !!u)
|
|
||||||
root.activeNames = act.map(a => a.name).filter(n => !!n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isActiveUuid(uuid) {
|
|
||||||
return root.activeUuids && root.activeUuids.indexOf(uuid) !== -1
|
|
||||||
}
|
|
||||||
|
|
||||||
function _looksLikeUuid(s) {
|
|
||||||
// Very loose check for UUID pattern
|
|
||||||
return s && s.indexOf('-') !== -1 && s.length >= 8
|
|
||||||
}
|
|
||||||
|
|
||||||
function connect(uuidOrName) {
|
|
||||||
if (root.isBusy) return
|
|
||||||
root.isBusy = true
|
|
||||||
root.errorMessage = ""
|
|
||||||
if (root.singleActive) {
|
|
||||||
// Bring down all active VPNs, then bring up the requested one
|
|
||||||
const isUuid = _looksLikeUuid(uuidOrName)
|
|
||||||
const escaped = ('' + uuidOrName).replace(/'/g, "'\\''")
|
|
||||||
const upCmd = isUuid ? `nmcli connection up uuid '${escaped}'` : `nmcli connection up id '${escaped}'`
|
|
||||||
const script = `set -e\n` +
|
|
||||||
`nmcli -t -f UUID,TYPE connection show --active | awk -F: '$2 ~ /^(vpn|wireguard)$/ {print $1}' | while read u; do [ -n \"$u\" ] && nmcli connection down uuid \"$u\" || true; done\n` +
|
|
||||||
upCmd + `\n`
|
|
||||||
vpnSwitch.command = ["bash", "-lc", script]
|
|
||||||
vpnSwitch.running = true
|
|
||||||
} else {
|
|
||||||
if (_looksLikeUuid(uuidOrName)) {
|
|
||||||
vpnUp.command = ["nmcli", "connection", "up", "uuid", uuidOrName]
|
|
||||||
} else {
|
|
||||||
vpnUp.command = ["nmcli", "connection", "up", "id", uuidOrName]
|
|
||||||
}
|
|
||||||
vpnUp.running = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function disconnect(uuidOrName) {
|
|
||||||
if (root.isBusy) return
|
|
||||||
root.isBusy = true
|
|
||||||
root.errorMessage = ""
|
|
||||||
if (_looksLikeUuid(uuidOrName)) {
|
|
||||||
vpnDown.command = ["nmcli", "connection", "down", "uuid", uuidOrName]
|
|
||||||
} else {
|
|
||||||
vpnDown.command = ["nmcli", "connection", "down", "id", uuidOrName]
|
|
||||||
}
|
|
||||||
vpnDown.running = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggle(uuid) {
|
|
||||||
if (uuid) {
|
|
||||||
if (isActiveUuid(uuid)) disconnect(uuid)
|
|
||||||
else connect(uuid)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (root.profiles.length > 0) {
|
|
||||||
connect(root.profiles[0].uuid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: vpnUp
|
|
||||||
running: false
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
root.isBusy = false
|
|
||||||
if (!text.toLowerCase().includes("successfully")) {
|
|
||||||
root.errorMessage = text.trim()
|
|
||||||
}
|
|
||||||
refreshAll()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onExited: exitCode => {
|
|
||||||
root.isBusy = false
|
|
||||||
if (exitCode !== 0 && root.errorMessage === "") {
|
|
||||||
root.errorMessage = "Failed to connect VPN"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: vpnDown
|
|
||||||
running: false
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
root.isBusy = false
|
|
||||||
if (!text.toLowerCase().includes("deactivated") && !text.toLowerCase().includes("successfully")) {
|
|
||||||
root.errorMessage = text.trim()
|
|
||||||
}
|
|
||||||
refreshAll()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onExited: exitCode => {
|
|
||||||
root.isBusy = false
|
|
||||||
if (exitCode !== 0 && root.errorMessage === "") {
|
|
||||||
root.errorMessage = "Failed to disconnect VPN"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function disconnectAllActive() {
|
|
||||||
if (root.isBusy) return
|
|
||||||
root.isBusy = true
|
|
||||||
const script = `nmcli -t -f UUID,TYPE connection show --active | awk -F: '$2 ~ /^(vpn|wireguard)$/ {print $1}' | while read u; do [ -n \"$u\" ] && nmcli connection down uuid \"$u\" || true; done`
|
|
||||||
vpnSwitch.command = ["bash", "-lc", script]
|
|
||||||
vpnSwitch.running = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sequenced down/up using a single shell for exclusive switch
|
|
||||||
Process {
|
|
||||||
id: vpnSwitch
|
|
||||||
running: false
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
root.isBusy = false
|
|
||||||
refreshAll()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onExited: exitCode => {
|
|
||||||
root.isBusy = false
|
|
||||||
if (exitCode !== 0 && root.errorMessage === "") {
|
|
||||||
root.errorMessage = "Failed to switch VPN"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user