1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 21:42:51 -05:00

vpn: various state management fixes

This commit is contained in:
bbedward
2025-10-27 14:17:29 -04:00
parent f0a1cb6525
commit 033f96a4b0
8 changed files with 138 additions and 37 deletions

View File

@@ -134,6 +134,7 @@ Singleton {
property bool weatherEnabled: true property bool weatherEnabled: true
property string networkPreference: "auto" property string networkPreference: "auto"
property string vpnLastConnected: ""
property string iconTheme: "System Default" property string iconTheme: "System Default"
property var availableIconThemes: ["System Default"] property var availableIconThemes: ["System Default"]
@@ -1398,6 +1399,11 @@ Singleton {
saveSettings() saveSettings()
} }
function setVpnLastConnected(uuid) {
vpnLastConnected = uuid
saveSettings()
}
function setIconTheme(themeName) { function setIconTheme(themeName) {
iconTheme = themeName iconTheme = themeName
updateGtkIconTheme(themeName) updateGtkIconTheme(themeName)

View File

@@ -213,10 +213,26 @@ Item {
} }
} }
property string lastCredentialsToken: ""
property var lastCredentialsTime: 0
Connections { Connections {
target: NetworkService target: NetworkService
function onCredentialsNeeded(token, ssid, setting, fields, hints, reason, connType, connName, vpnService) { function onCredentialsNeeded(token, ssid, setting, fields, hints, reason, connType, connName, vpnService) {
const now = Date.now()
const timeSinceLastPrompt = now - lastCredentialsTime
if (wifiPasswordModal.shouldBeVisible && timeSinceLastPrompt < 1000) {
NetworkService.cancelCredentials(lastCredentialsToken)
lastCredentialsToken = token
lastCredentialsTime = now
wifiPasswordModal.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService)
return
}
lastCredentialsToken = token
lastCredentialsTime = now
wifiPasswordModal.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService) wifiPasswordModal.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService)
} }
} }

View File

@@ -13,6 +13,7 @@ PluginComponent {
service: DMSNetworkService service: DMSNetworkService
} }
ccWidgetIcon: DMSNetworkService.isBusy ? "sync" : (DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off") ccWidgetIcon: DMSNetworkService.isBusy ? "sync" : (DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off")
ccWidgetPrimaryText: "VPN" ccWidgetPrimaryText: "VPN"
ccWidgetSecondaryText: { ccWidgetSecondaryText: {
@@ -26,11 +27,7 @@ PluginComponent {
ccWidgetIsActive: DMSNetworkService.connected ccWidgetIsActive: DMSNetworkService.connected
onCcWidgetToggled: { onCcWidgetToggled: {
if (DMSNetworkService.connected) { DMSNetworkService.toggleVpn()
DMSNetworkService.disconnectAllActive()
} else if (DMSNetworkService.profiles.length > 0) {
DMSNetworkService.connect(DMSNetworkService.profiles[0].uuid)
}
} }
ccDetailContent: Component { ccDetailContent: Component {
@@ -62,10 +59,10 @@ PluginComponent {
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText color: Theme.surfaceText
font.weight: Font.Medium font.weight: Font.Medium
} elide: Text.ElideRight
wrapMode: Text.NoWrap
Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.maximumWidth: parent.width - 120
} }
Rectangle { Rectangle {
@@ -75,6 +72,7 @@ PluginComponent {
visible: DMSNetworkService.connected visible: DMSNetworkService.connected
width: 110 width: 110
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
opacity: DMSNetworkService.isBusy ? 0.5 : 1.0
Row { Row {
anchors.centerIn: parent anchors.centerIn: parent
@@ -98,7 +96,8 @@ PluginComponent {
id: discAllArea id: discAllArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor
enabled: !DMSNetworkService.isBusy
onClicked: DMSNetworkService.disconnectAllActive() onClicked: DMSNetworkService.disconnectAllActive()
} }
} }
@@ -165,6 +164,7 @@ PluginComponent {
color: rowArea.containsMouse ? Theme.primaryHoverLight : (DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primaryPressed : Theme.surfaceLight) color: rowArea.containsMouse ? Theme.primaryHoverLight : (DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primaryPressed : Theme.surfaceLight)
border.width: DMSNetworkService.isActiveUuid(modelData.uuid) ? 2 : 1 border.width: DMSNetworkService.isActiveUuid(modelData.uuid) ? 2 : 1
border.color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.outlineLight border.color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.outlineLight
opacity: DMSNetworkService.isBusy ? 0.5 : 1.0
RowLayout { RowLayout {
anchors.left: parent.left anchors.left: parent.left
@@ -183,11 +183,15 @@ PluginComponent {
Column { Column {
spacing: 2 spacing: 2
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
StyledText { StyledText {
text: modelData.name text: modelData.name
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText
elide: Text.ElideRight
wrapMode: Text.NoWrap
width: parent.width
} }
StyledText { StyledText {
@@ -233,7 +237,8 @@ PluginComponent {
id: rowArea id: rowArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor
enabled: !DMSNetworkService.isBusy
onClicked: DMSNetworkService.toggle(modelData.uuid) onClicked: DMSNetworkService.toggle(modelData.uuid)
} }
} }

View File

@@ -17,6 +17,15 @@ DankPopout {
service: DMSNetworkService service: DMSNetworkService
} }
property bool wasVisible: false
onShouldBeVisibleChanged: {
if (shouldBeVisible && !wasVisible) {
DMSNetworkService.getState()
}
wasVisible = shouldBeVisible
}
property var triggerScreen: null property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) { function setTriggerPosition(x, y, width, section, screen) {
@@ -175,11 +184,10 @@ DankPopout {
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText color: Theme.surfaceText
font.weight: Font.Medium font.weight: Font.Medium
} elide: Text.ElideRight
wrapMode: Text.NoWrap
Item {
Layout.fillWidth: true Layout.fillWidth: true
height: 1 Layout.maximumWidth: parent.width - 140
} }
// Removed Quick Connect for clarity // Removed Quick Connect for clarity
@@ -198,6 +206,7 @@ DankPopout {
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
border.width: 0 border.width: 0
border.color: Theme.outlineLight border.color: Theme.outlineLight
opacity: DMSNetworkService.isBusy ? 0.5 : 1.0
Row { Row {
anchors.centerIn: parent anchors.centerIn: parent
@@ -223,7 +232,8 @@ DankPopout {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor
enabled: !DMSNetworkService.isBusy
onClicked: DMSNetworkService.disconnectAllActive() onClicked: DMSNetworkService.disconnectAllActive()
} }
@@ -295,6 +305,7 @@ DankPopout {
color: rowArea.containsMouse ? Theme.primaryHoverLight : (DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primaryPressed : Theme.surfaceLight) color: rowArea.containsMouse ? Theme.primaryHoverLight : (DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primaryPressed : Theme.surfaceLight)
border.width: DMSNetworkService.isActiveUuid(modelData.uuid) ? 2 : 1 border.width: DMSNetworkService.isActiveUuid(modelData.uuid) ? 2 : 1
border.color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.outlineLight border.color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.outlineLight
opacity: DMSNetworkService.isBusy ? 0.5 : 1.0
RowLayout { RowLayout {
anchors.left: parent.left anchors.left: parent.left
@@ -313,11 +324,15 @@ DankPopout {
Column { Column {
spacing: 2 spacing: 2
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
StyledText { StyledText {
text: modelData.name text: modelData.name
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText color: DMSNetworkService.isActiveUuid(modelData.uuid) ? Theme.primary : Theme.surfaceText
elide: Text.ElideRight
wrapMode: Text.NoWrap
width: parent.width
} }
StyledText { StyledText {
@@ -391,7 +406,8 @@ DankPopout {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor
enabled: !DMSNetworkService.isBusy
onClicked: DMSNetworkService.toggle(modelData.uuid) onClicked: DMSNetworkService.toggle(modelData.uuid)
} }

View File

@@ -31,7 +31,7 @@ BasePill {
return "sync" return "sync"
} }
if (NetworkService.networkStatus === "ethernet") { if (NetworkService.networkStatus === "ethernet" || (NetworkService.networkStatus === "vpn" && NetworkService.ethernetConnected)) {
return "lan" return "lan"
} }
@@ -128,7 +128,7 @@ BasePill {
return "sync"; return "sync";
} }
if (NetworkService.networkStatus === "ethernet") { if (NetworkService.networkStatus === "ethernet" || (NetworkService.networkStatus === "vpn" && NetworkService.ethernetConnected)) {
return "lan"; return "lan";
} }

View File

@@ -25,10 +25,18 @@ BasePill {
DankIcon { DankIcon {
id: icon id: icon
name: DMSNetworkService.isBusy ? "sync" : (DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off") name: DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off"
size: Theme.barIconSize(root.barThickness, -4) size: Theme.barIconSize(root.barThickness, -4)
color: DMSNetworkService.connected ? Theme.primary : Theme.surfaceText color: DMSNetworkService.connected ? Theme.primary : Theme.surfaceText
opacity: DMSNetworkService.isBusy ? 0.5 : 1.0
anchors.centerIn: parent anchors.centerIn: parent
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Easing.InOutQuad
}
}
} }
} }
} }
@@ -44,8 +52,9 @@ BasePill {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
enabled: !DMSNetworkService.isBusy
onPressed: { onPressed: {
if (popoutTarget && popoutTarget.setTriggerPosition) { if (popoutTarget && popoutTarget.setTriggerPosition) {
const globalPos = root.visualContent.mapToGlobal(0, 0) const globalPos = root.visualContent.mapToGlobal(0, 0)
@@ -65,9 +74,15 @@ BasePill {
} else { } else {
const names = DMSNetworkService.activeNames || [] const names = DMSNetworkService.activeNames || []
if (names.length <= 1) { if (names.length <= 1) {
tooltipText = "VPN Connected • " + (names[0] || "") const name = names[0] || ""
const maxLength = 25
const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name
tooltipText = "VPN Connected • " + displayName
} else { } else {
tooltipText = "VPN Connected • " + names[0] + " +" + (names.length - 1) const name = names[0]
const maxLength = 20
const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name
tooltipText = "VPN Connected • " + displayName + " +" + (names.length - 1)
} }
} }

View File

@@ -73,6 +73,9 @@ Singleton {
property var vpnActive: [] property var vpnActive: []
property bool vpnAvailable: false property bool vpnAvailable: false
property bool vpnIsBusy: false property bool vpnIsBusy: false
property string lastConnectedVpnUuid: ""
property string pendingVpnUuid: ""
property var vpnBusyStartTime: 0
property alias profiles: root.vpnProfiles property alias profiles: root.vpnProfiles
property alias activeConnections: root.vpnActive property alias activeConnections: root.vpnActive
@@ -118,6 +121,7 @@ Singleton {
Component.onCompleted: { Component.onCompleted: {
root.userPreference = SettingsData.networkPreference root.userPreference = SettingsData.networkPreference
lastConnectedVpnUuid = SettingsData.vpnLastConnected || ""
if (socketPath && socketPath.length > 0) { if (socketPath && socketPath.length > 0) {
checkDMSCapabilities() checkDMSCapabilities()
} }
@@ -271,8 +275,41 @@ Singleton {
vpnProfiles = state.vpnProfiles vpnProfiles = state.vpnProfiles
} }
const previousVpnActive = vpnActive
vpnActive = state.vpnActive || [] vpnActive = state.vpnActive || []
if (vpnConnected && activeUuid) {
lastConnectedVpnUuid = activeUuid
SettingsData.setVpnLastConnected(activeUuid)
}
if (vpnIsBusy) {
const busyDuration = Date.now() - vpnBusyStartTime
const timeout = 30000
if (busyDuration > timeout) {
console.warn("DMSNetworkService: VPN operation timed out after", timeout, "ms")
vpnIsBusy = false
pendingVpnUuid = ""
vpnBusyStartTime = 0
} else if (pendingVpnUuid) {
const isPendingVpnActive = activeUuids.includes(pendingVpnUuid)
if (isPendingVpnActive) {
vpnIsBusy = false
pendingVpnUuid = ""
vpnBusyStartTime = 0
}
} else {
const previousCount = previousVpnActive ? previousVpnActive.length : 0
const currentCount = vpnActive ? vpnActive.length : 0
if (previousCount !== currentCount) {
vpnIsBusy = false
vpnBusyStartTime = 0
}
}
}
userPreference = state.preference || "auto" userPreference = state.preference || "auto"
isConnecting = state.isConnecting || false isConnecting = state.isConnecting || false
connectingSSID = state.connectingSSID || "" connectingSSID = state.connectingSSID || ""
@@ -726,10 +763,12 @@ Singleton {
}) })
} }
function connectVpn(uuidOrName, singleActive = false) { function connectVpn(uuidOrName, singleActive = true) {
if (!vpnAvailable || vpnIsBusy) return if (!vpnAvailable || vpnIsBusy) return
vpnIsBusy = true vpnIsBusy = true
pendingVpnUuid = uuidOrName
vpnBusyStartTime = Date.now()
const params = { const params = {
uuidOrName: uuidOrName, uuidOrName: uuidOrName,
@@ -737,12 +776,11 @@ Singleton {
} }
DMSService.sendRequest("network.vpn.connect", params, response => { DMSService.sendRequest("network.vpn.connect", params, response => {
vpnIsBusy = false
if (response.error) { if (response.error) {
vpnIsBusy = false
pendingVpnUuid = ""
vpnBusyStartTime = 0
ToastService.showError(I18n.tr("Failed to connect VPN")) ToastService.showError(I18n.tr("Failed to connect VPN"))
} else {
Qt.callLater(() => getState())
} }
}) })
} }
@@ -755,18 +793,18 @@ Singleton {
if (!vpnAvailable || vpnIsBusy) return if (!vpnAvailable || vpnIsBusy) return
vpnIsBusy = true vpnIsBusy = true
pendingVpnUuid = ""
vpnBusyStartTime = Date.now()
const params = { const params = {
uuidOrName: uuidOrName uuidOrName: uuidOrName
} }
DMSService.sendRequest("network.vpn.disconnect", params, response => { DMSService.sendRequest("network.vpn.disconnect", params, response => {
vpnIsBusy = false
if (response.error) { if (response.error) {
vpnIsBusy = false
vpnBusyStartTime = 0
ToastService.showError(I18n.tr("Failed to disconnect VPN")) ToastService.showError(I18n.tr("Failed to disconnect VPN"))
} else {
Qt.callLater(() => getState())
} }
}) })
} }
@@ -779,14 +817,12 @@ Singleton {
if (!vpnAvailable || vpnIsBusy) return if (!vpnAvailable || vpnIsBusy) return
vpnIsBusy = true vpnIsBusy = true
pendingVpnUuid = ""
DMSService.sendRequest("network.vpn.disconnectAll", null, response => { DMSService.sendRequest("network.vpn.disconnectAll", null, response => {
vpnIsBusy = false
if (response.error) { if (response.error) {
vpnIsBusy = false
ToastService.showError(I18n.tr("Failed to disconnect VPNs")) ToastService.showError(I18n.tr("Failed to disconnect VPNs"))
} else {
Qt.callLater(() => getState())
} }
}) })
} }
@@ -805,8 +841,14 @@ Singleton {
return return
} }
if (vpnProfiles.length > 0) { if (vpnConnected) {
connectVpn(vpnProfiles[0].uuid) disconnectAllVpns()
return
}
const targetUuid = lastConnectedVpnUuid || (vpnProfiles.length > 0 ? vpnProfiles[0].uuid : "")
if (targetUuid) {
connectVpn(targetUuid)
} }
} }

View File

@@ -47,6 +47,7 @@ Item {
"yaml": "\u{e8eb}", "yaml": "\u{e8eb}",
"yml": "\u{e8eb}", "yml": "\u{e8eb}",
"xml": "\u{F09EE}", "xml": "\u{F09EE}",
"sql": "\u{f1c0}",
// --- scripts / shells --- // --- scripts / shells ---
"sh": "\u{F08A9}", "sh": "\u{F08A9}",