1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-29 16:02:51 -05:00

enhancement: managed NetworkManager ethernet configurations connectio… (#473)

* enhancement: managed NetworkManager ethernet configurations connection from control panel

* server API minimal version
This commit is contained in:
Massimo Branchini
2025-10-17 14:05:42 +02:00
committed by GitHub
parent a804fb849e
commit b21f6e80b3
6 changed files with 497 additions and 31 deletions

View File

@@ -0,0 +1,162 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Modals.Common
import qs.Services
import qs.Widgets
DankModal {
id: root
property bool networkWiredInfoModalVisible: false
property string networkID: ""
property var networkData: null
function showNetworkInfo(id, data) {
networkID = id
networkData = data
networkWiredInfoModalVisible = true
open()
NetworkService.fetchWiredNetworkInfo(data.uuid)
}
function hideDialog() {
networkWiredInfoModalVisible = false
close()
networkID = ""
networkData = null
}
visible: networkWiredInfoModalVisible
width: 600
height: 500
enableShadow: true
onBackgroundClicked: hideDialog()
onVisibleChanged: {
if (!visible) {
networkID = ""
networkData = null
}
}
content: Component {
Item {
anchors.fill: parent
Column {
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingL
Row {
width: parent.width
Column {
width: parent.width - 40
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Network Information")
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: `Details for "${networkID}"`
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceTextMedium
width: parent.width
elide: Text.ElideRight
}
}
DankActionButton {
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
onClicked: root.hideDialog()
}
}
Rectangle {
id: detailsRect
width: parent.width
height: parent.height - 140
radius: Theme.cornerRadius
color: Theme.surfaceHover
border.color: Theme.outlineStrong
border.width: 1
clip: true
DankFlickable {
anchors.fill: parent
anchors.margins: Theme.spacingM
contentHeight: detailsText.contentHeight
StyledText {
id: detailsText
width: parent.width
text: NetworkService.networkWiredInfoDetails && NetworkService.networkWiredInfoDetails.replace(/\\n/g, '\n') || "No information available"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
wrapMode: Text.WordWrap
}
}
}
Item {
width: parent.width
height: 40
Rectangle {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
width: Math.max(70, closeText.contentWidth + Theme.spacingM * 2)
height: 36
radius: Theme.cornerRadius
color: closeArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary
StyledText {
id: closeText
anchors.centerIn: parent
text: I18n.tr("Close")
font.pixelSize: Theme.fontSizeMedium
color: Theme.background
font.weight: Font.Medium
}
MouseArea {
id: closeArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.hideDialog()
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}
}
}

View File

@@ -29,6 +29,22 @@ Rectangle {
NetworkService.removeRef() NetworkService.removeRef()
} }
property int currentPreferenceIndex: {
const pref = NetworkService.userPreference
const status = NetworkService.networkStatus
let index = 1
if (pref === "ethernet") {
index = 0
} else if (pref === "wifi") {
index = 1
} else {
index = status === "ethernet" ? 0 : 1
}
return index
}
Row { Row {
id: headerRow id: headerRow
anchors.left: parent.left anchors.left: parent.left
@@ -38,7 +54,7 @@ Rectangle {
anchors.rightMargin: Theme.spacingM anchors.rightMargin: Theme.spacingM
anchors.topMargin: Theme.spacingS anchors.topMargin: Theme.spacingS
height: 40 height: 40
StyledText { StyledText {
id: headerText id: headerText
text: I18n.tr("Network Settings") text: I18n.tr("Network Settings")
@@ -47,32 +63,16 @@ Rectangle {
font.weight: Font.Medium font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
Item { Item {
width: Math.max(0, parent.width - headerText.implicitWidth - preferenceControls.width - Theme.spacingM) width: Math.max(0, parent.width - headerText.implicitWidth - preferenceControls.width - Theme.spacingM)
height: parent.height height: parent.height
} }
DankButtonGroup { DankButtonGroup {
id: preferenceControls id: preferenceControls
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: NetworkService.ethernetConnected visible: true
property int currentPreferenceIndex: {
const pref = NetworkService.userPreference
const status = NetworkService.networkStatus
let index = 1
if (pref === "ethernet") {
index = 0
} else if (pref === "wifi") {
index = 1
} else {
index = status === "ethernet" ? 0 : 1
}
return index
}
model: ["Ethernet", "WiFi"] model: ["Ethernet", "WiFi"]
currentIndex: currentPreferenceIndex currentIndex: currentPreferenceIndex
@@ -92,7 +92,7 @@ Rectangle {
anchors.right: parent.right anchors.right: parent.right
anchors.margins: Theme.spacingM anchors.margins: Theme.spacingM
anchors.topMargin: Theme.spacingM anchors.topMargin: Theme.spacingM
visible: NetworkService.wifiToggling visible: currentPreferenceIndex === 1 && NetworkService.wifiToggling
height: visible ? 80 : 0 height: visible ? 80 : 0
Column { Column {
@@ -131,7 +131,7 @@ Rectangle {
anchors.right: parent.right anchors.right: parent.right
anchors.margins: Theme.spacingM anchors.margins: Theme.spacingM
anchors.topMargin: Theme.spacingM anchors.topMargin: Theme.spacingM
visible: !NetworkService.wifiEnabled && !NetworkService.wifiToggling visible: currentPreferenceIndex === 1 && !NetworkService.wifiEnabled && !NetworkService.wifiToggling
height: visible ? 120 : 0 height: visible ? 120 : 0
Column { Column {
@@ -179,7 +179,179 @@ Rectangle {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: NetworkService.toggleWifiRadio() onClicked: NetworkService.toggleWifiRadio()
} }
}
}
}
DankFlickable {
id: wiredContent
anchors.top: headerRow.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: Theme.spacingM
anchors.topMargin: Theme.spacingM
visible: currentPreferenceIndex === 0
contentHeight: wiredColumn.height
clip: true
Column {
id: wiredColumn
width: parent.width
spacing: Theme.spacingS
Repeater {
model: sortedNetworks
property var sortedNetworks: {
const currentUuid = NetworkService.ethernetConnectionUuid
const networks = NetworkService.wiredConnections
let sorted = [...networks]
sorted.sort((a, b) => {
if (a.isActive && !b.isActive) return -1
if (!a.isActive && b.isActive) return 1
return a.id.localeCompare(b.id)
})
return sorted
}
delegate: Rectangle {
required property var modelData
required property int index
width: parent.width
height: 50
radius: Theme.cornerRadius
color: wiredNetworkMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHighest
border.color: Theme.primary
border.width: 0
Row {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: Theme.spacingM
spacing: Theme.spacingS
DankIcon {
name: "lan"
size: Theme.iconSize - 4
color: modelData.isActive ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Column {
anchors.verticalCenter: parent.verticalCenter
width: 200
StyledText {
text: modelData.id || "Unknown Config"
font.pixelSize: Theme.fontSizeMedium
color: modelData.isActive ? Theme.primary : Theme.surfaceText
font.weight: modelData.isActive ? Font.Medium : Font.Normal
elide: Text.ElideRight
width: parent.width
}
}
}
DankActionButton {
id: wiredOptionsButton
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
iconName: "more_horiz"
buttonSize: 28
onClicked: {
if (wiredNetworkContextMenu.visible) {
wiredNetworkContextMenu.close()
} else {
wiredNetworkContextMenu.currentID = modelData.id
wiredNetworkContextMenu.currentUUID = modelData.uuid
wiredNetworkContextMenu.currentConnected = modelData.isActive
wiredNetworkContextMenu.popup(wiredOptionsButton, -wiredNetworkContextMenu.width + wiredOptionsButton.width, wiredOptionsButton.height + Theme.spacingXS)
}
}
}
MouseArea {
id: wiredNetworkMouseArea
anchors.fill: parent
anchors.rightMargin: wiredOptionsButton.width + Theme.spacingS
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: function(event) {
if (modelData.uuid !== NetworkService.ethernetConnectionUuid) {
NetworkService.connectToSpecificWiredConfig(modelData.uuid)
}
event.accepted = true
}
}
}
}
}
}
Menu {
id: wiredNetworkContextMenu
width: 150
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
property string currentID: ""
property string currentUUID: ""
property bool currentConnected: false
background: Rectangle {
color: Theme.popupBackground()
radius: Theme.cornerRadius
border.width: 0
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
}
MenuItem {
text: "Activate"
height: !wiredNetworkContextMenu.currentConnected ? 32 : 0
contentItem: StyledText {
text: parent.text
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
leftPadding: Theme.spacingS
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
radius: Theme.cornerRadius / 2
}
onTriggered: {
if (!networkContextMenu.currentConnected) {
NetworkService.connectToSpecificWiredConfig(wiredNetworkContextMenu.currentUUID)
}
}
}
MenuItem {
text: I18n.tr("Network Info")
height: wiredNetworkContextMenu.currentConnected ? 32 : 0
contentItem: StyledText {
text: parent.text
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
leftPadding: Theme.spacingS
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
radius: Theme.cornerRadius / 2
}
onTriggered: {
let networkData = NetworkService.getWiredNetworkInfo(wiredNetworkContextMenu.currentUUID)
networkWiredInfoModal.showNetworkInfo(wiredNetworkContextMenu.currentID, networkData)
} }
} }
} }
@@ -192,10 +364,10 @@ Rectangle {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.margins: Theme.spacingM anchors.margins: Theme.spacingM
anchors.topMargin: Theme.spacingM anchors.topMargin: Theme.spacingM
visible: NetworkService.wifiInterface && NetworkService.wifiEnabled && !NetworkService.wifiToggling visible: currentPreferenceIndex === 1 && NetworkService.wifiEnabled && !NetworkService.wifiToggling
contentHeight: wifiColumn.height contentHeight: wifiColumn.height
clip: true clip: true
Column { Column {
id: wifiColumn id: wifiColumn
width: parent.width width: parent.width
@@ -282,20 +454,20 @@ Rectangle {
spacing: Theme.spacingXS spacing: Theme.spacingXS
StyledText { StyledText {
text: modelData.ssid === NetworkService.currentWifiSSID ? "Connected" : (modelData.secured ? "Secured" : "Open") text: modelData.ssid === NetworkService.currentWifiSSID ? "Connected" : (modelData.secured ? "Secured" : "Open")
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
} }
StyledText { StyledText {
text: modelData.saved ? "Saved" : "" text: modelData.saved ? "Saved" : ""
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.primary color: Theme.primary
visible: text.length > 0 visible: text.length > 0
} }
StyledText { StyledText {
text: "• " + modelData.signal + "%" text: (modelData.saved ? "• " : "") + modelData.signal + "%"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
} }
@@ -449,6 +621,8 @@ Rectangle {
NetworkInfoModal { NetworkInfoModal {
id: networkInfoModal id: networkInfoModal
} }
NetworkWiredInfoModal {
id: networkWiredInfoModal
}
} }

View File

@@ -14,7 +14,7 @@ Singleton {
property bool dmsAvailable: false property bool dmsAvailable: false
property var capabilities: [] property var capabilities: []
property int apiVersion: 0 property int apiVersion: 0
readonly property int expectedApiVersion: 1 readonly property int expectedApiVersion: 5
property var availablePlugins: [] property var availablePlugins: []
property var installedPlugins: [] property var installedPlugins: []
property bool isConnected: false property bool isConnected: false

View File

@@ -20,6 +20,8 @@ Singleton {
property bool ethernetConnected: false property bool ethernetConnected: false
property string ethernetConnectionUuid: "" property string ethernetConnectionUuid: ""
property var wiredConnections: []
property string wifiIP: "" property string wifiIP: ""
property string wifiInterface: "" property string wifiInterface: ""
property bool wifiConnected: false property bool wifiConnected: false
@@ -73,6 +75,10 @@ Singleton {
property string networkInfoSSID: "" property string networkInfoSSID: ""
property string networkInfoDetails: "" property string networkInfoDetails: ""
property bool networkInfoLoading: false property bool networkInfoLoading: false
property string networkWiredInfoUUID: ""
property string networkWiredInfoDetails: ""
property bool networkWiredInfoLoading: false
signal networksUpdated signal networksUpdated
signal connectionChanged signal connectionChanged

View File

@@ -20,6 +20,8 @@ Singleton {
property bool ethernetConnected: false property bool ethernetConnected: false
property string ethernetConnectionUuid: "" property string ethernetConnectionUuid: ""
property var wiredConnections: []
property string wifiIP: "" property string wifiIP: ""
property string wifiInterface: "" property string wifiInterface: ""
property bool wifiConnected: false property bool wifiConnected: false
@@ -69,6 +71,10 @@ Singleton {
property string networkInfoSSID: "" property string networkInfoSSID: ""
property string networkInfoDetails: "" property string networkInfoDetails: ""
property bool networkInfoLoading: false property bool networkInfoLoading: false
property string networkWiredInfoUUID: ""
property string networkWiredInfoDetails: ""
property bool networkWiredInfoLoading: false
property int refCount: 0 property int refCount: 0
property bool stateInitialized: false property bool stateInitialized: false
@@ -179,6 +185,8 @@ Singleton {
ethernetConnected = state.ethernetConnected || false ethernetConnected = state.ethernetConnected || false
ethernetConnectionUuid = state.ethernetConnectionUuid || "" ethernetConnectionUuid = state.ethernetConnectionUuid || ""
wiredConnections = state.wiredConnections || []
wifiIP = state.wifiIP || "" wifiIP = state.wifiIP || ""
wifiInterface = state.wifiDevice || "" wifiInterface = state.wifiDevice || ""
wifiConnected = state.wifiConnected || false wifiConnected = state.wifiConnected || false
@@ -219,6 +227,31 @@ Singleton {
connectionChanged() connectionChanged()
} }
function connectToSpecificWiredConfig(uuid) {
if (!networkAvailable || isConnecting) return
isConnecting = true
connectionError = ""
connectionStatus = "connecting"
const params = { uuid: uuid }
DMSService.sendRequest("network.ethernet.connect.config", params, response => {
if (response.error) {
connectionError = response.error
lastConnectionError = response.error
connectionStatus = "failed"
ToastService.showError(`Failed to activate configuration`)
} else {
connectionError = ""
connectionStatus = "connected"
ToastService.showInfo(`Configuration activated`)
}
isConnecting = false
})
}
function scanWifi() { function scanWifi() {
if (!networkAvailable || isScanning || !wifiEnabled) return if (!networkAvailable || isScanning || !wifiEnabled) return
@@ -413,6 +446,61 @@ Singleton {
autoScan = false autoScan = false
autoRefreshEnabled = false autoRefreshEnabled = false
} }
function fetchWiredNetworkInfo(uuid) {
if (!networkAvailable) return
networkWiredInfoUUID = uuid
networkWiredInfoLoading = true
networkWiredInfoDetails = "Loading network information..."
DMSService.sendRequest("network.ethernet.info", { uuid: uuid }, response => {
networkWiredInfoLoading = false
if (response.error) {
networkWiredInfoDetails = "Failed to fetch network information"
} else if (response.result) {
formatWiredNetworkInfo(response.result)
}
})
}
function formatWiredNetworkInfo(info) {
let details = ""
if (!info) {
details = "Network information not found or network not available."
} else {
details += "Inteface: " + info.iface + "\\n"
details += "Driver: " + info.driver + "\\n"
details += "MAC Addr: " + info.hwAddr + "\\n"
details += "Speed: " + info.speed + " Mb/s\\n\\n"
details += "IPv4 informations:\\n"
for (const ip4 of info.IPv4s.ips) {
details += " IPv4 address: " + ip4 + "\\n"
}
details += " Gateway: " + info.IPv4s.gateway + "\\n"
details += " DNS: " + info.IPv4s.dns + "\\n"
if (info.IPv6s.ips) {
details += "\\nIPv6 informations:\\n"
for (const ip6 of info.IPv6s.ips) {
details += " IPv6 address: " + ip6 + "\\n"
}
if (info.IPv6s.gateway.length > 0) {
details += " Gateway: " + info.IPv6s.gateway + "\\n"
}
if (info.IPv6s.dns.length > 0) {
details += " DNS: " + info.IPv6s.dns + "\\n"
}
}
}
networkWiredInfoDetails = details
}
function fetchNetworkInfo(ssid) { function fetchNetworkInfo(ssid) {
if (!networkAvailable) return if (!networkAvailable) return
@@ -483,6 +571,17 @@ Singleton {
} }
} }
function getWiredNetworkInfo(uuid) {
const network = wiredConnections.find(n => n.uuid === uuid)
if (!network) {
return null
}
return {
"uuid": uuid,
}
}
function refreshNetworkState() { function refreshNetworkState() {
if (networkAvailable) { if (networkAvailable) {
getState() getState()

View File

@@ -19,6 +19,8 @@ Singleton {
property bool ethernetConnected: activeService?.ethernetConnected ?? false property bool ethernetConnected: activeService?.ethernetConnected ?? false
property string ethernetConnectionUuid: activeService?.ethernetConnectionUuid ?? "" property string ethernetConnectionUuid: activeService?.ethernetConnectionUuid ?? ""
property var wiredConnections: activeService?.wiredConnections ?? []
property string wifiIP: activeService?.wifiIP ?? "" property string wifiIP: activeService?.wifiIP ?? ""
property string wifiInterface: activeService?.wifiInterface ?? "" property string wifiInterface: activeService?.wifiInterface ?? ""
property bool wifiConnected: activeService?.wifiConnected ?? false property bool wifiConnected: activeService?.wifiConnected ?? false
@@ -57,6 +59,10 @@ Singleton {
property string networkInfoSSID: activeService?.networkInfoSSID ?? "" property string networkInfoSSID: activeService?.networkInfoSSID ?? ""
property string networkInfoDetails: activeService?.networkInfoDetails ?? "" property string networkInfoDetails: activeService?.networkInfoDetails ?? ""
property bool networkInfoLoading: activeService?.networkInfoLoading ?? false property bool networkInfoLoading: activeService?.networkInfoLoading ?? false
property string networkWiredInfoUUID: activeService?.networkWiredInfoUUID ?? ""
property string networkWiredInfoDetails: activeService?.networkWiredInfoDetails ?? ""
property bool networkWiredInfoLoading: activeService?.networkWiredInfoLoading ?? false
property int refCount: activeService?.refCount ?? 0 property int refCount: activeService?.refCount ?? 0
property bool stateInitialized: activeService?.stateInitialized ?? false property bool stateInitialized: activeService?.stateInitialized ?? false
@@ -221,6 +227,12 @@ Singleton {
} }
} }
function fetchWiredNetworkInfo(uuid) {
if (activeService && activeService.fetchWiredNetworkInfo) {
activeService.fetchWiredNetworkInfo(uuid)
}
}
function getNetworkInfo(ssid) { function getNetworkInfo(ssid) {
if (activeService && activeService.getNetworkInfo) { if (activeService && activeService.getNetworkInfo) {
return activeService.getNetworkInfo(ssid) return activeService.getNetworkInfo(ssid)
@@ -228,9 +240,22 @@ Singleton {
return null return null
} }
function getWiredNetworkInfo(uuid) {
if (activeService && activeService.getWiredNetworkInfo) {
return activeService.getWiredNetworkInfo(uuid)
}
return null
}
function refreshNetworkState() { function refreshNetworkState() {
if (activeService && activeService.refreshNetworkState) { if (activeService && activeService.refreshNetworkState) {
activeService.refreshNetworkState() activeService.refreshNetworkState()
} }
} }
function connectToSpecificWiredConfig(uuid) {
if (activeService && activeService.connectToSpecificWiredConfig) {
activeService.connectToSpecificWiredConfig(uuid)
}
}
} }