diff options
| author | ATMDA <atdma2600@gmail.com> | 2025-11-10 10:00:04 -0500 |
|---|---|---|
| committer | ATMDA <atdma2600@gmail.com> | 2025-11-10 10:00:04 -0500 |
| commit | 1debf488ee1ed24763a01c2e1bf5c3f4119de18f (patch) | |
| tree | 3eed720e275da1acef4af648640fb52c6c7d6f32 | |
| parent | launcher: python execution like calculator functionality (diff) | |
| download | caelestia-shell-1debf488ee1ed24763a01c2e1bf5c3f4119de18f.tar.gz caelestia-shell-1debf488ee1ed24763a01c2e1bf5c3f4119de18f.tar.bz2 caelestia-shell-1debf488ee1ed24763a01c2e1bf5c3f4119de18f.zip | |
controlcenter: ethernet panel (debug)
| -rw-r--r-- | modules/controlcenter/NavRail.qml | 9 | ||||
| -rw-r--r-- | modules/controlcenter/Panes.qml | 14 | ||||
| -rw-r--r-- | modules/controlcenter/Session.qml | 7 | ||||
| -rw-r--r-- | modules/controlcenter/ethernet/EthernetDetails.qml | 204 | ||||
| -rw-r--r-- | modules/controlcenter/ethernet/EthernetList.qml | 262 | ||||
| -rw-r--r-- | modules/controlcenter/ethernet/EthernetPane.qml | 156 | ||||
| -rw-r--r-- | modules/controlcenter/ethernet/EthernetSettings.qml | 155 | ||||
| -rw-r--r-- | services/Network.qml | 183 |
8 files changed, 983 insertions, 7 deletions
diff --git a/modules/controlcenter/NavRail.qml b/modules/controlcenter/NavRail.qml index 96bbb65..b4fbf94 100644 --- a/modules/controlcenter/NavRail.qml +++ b/modules/controlcenter/NavRail.qml @@ -158,8 +158,13 @@ Item { NavItem { Layout.topMargin: Appearance.spacing.large * 2 - icon: "network_manage" - label: "network" + icon: "cable" + label: "ethernet" + } + + NavItem { + icon: "wifi" + label: "wireless" } NavItem { diff --git a/modules/controlcenter/Panes.qml b/modules/controlcenter/Panes.qml index 5b1039c..4f4a337 100644 --- a/modules/controlcenter/Panes.qml +++ b/modules/controlcenter/Panes.qml @@ -1,5 +1,6 @@ pragma ComponentBehavior: Bound +import "ethernet" import "bluetooth" import "network" import "audio" @@ -26,27 +27,34 @@ ClippingRectangle { Pane { index: 0 - sourceComponent: NetworkPane { + sourceComponent: EthernetPane { session: root.session } } Pane { index: 1 - sourceComponent: BtPane { + sourceComponent: NetworkPane { session: root.session } } Pane { index: 2 - sourceComponent: AudioPane { + sourceComponent: BtPane { session: root.session } } Pane { index: 3 + sourceComponent: AudioPane { + session: root.session + } + } + + Pane { + index: 4 sourceComponent: AppearancePane { session: root.session } diff --git a/modules/controlcenter/Session.qml b/modules/controlcenter/Session.qml index 4ac09a4..f7c07e4 100644 --- a/modules/controlcenter/Session.qml +++ b/modules/controlcenter/Session.qml @@ -2,7 +2,7 @@ import Quickshell.Bluetooth import QtQuick QtObject { - readonly property list<string> panes: ["network", "bluetooth", "audio", "appearance"] + readonly property list<string> panes: ["ethernet", "wireless", "bluetooth", "audio", "appearance"] required property var root property bool floating: false @@ -12,6 +12,7 @@ QtObject { readonly property Bt bt: Bt {} readonly property Network network: Network {} + readonly property Ethernet ethernet: Ethernet {} onActiveChanged: activeIndex = panes.indexOf(active) onActiveIndexChanged: active = panes[activeIndex] @@ -29,4 +30,8 @@ QtObject { property bool showPasswordDialog: false property var pendingNetwork } + + component Ethernet: QtObject { + property var active + } } diff --git a/modules/controlcenter/ethernet/EthernetDetails.qml b/modules/controlcenter/ethernet/EthernetDetails.qml new file mode 100644 index 0000000..9be3ddc --- /dev/null +++ b/modules/controlcenter/ethernet/EthernetDetails.qml @@ -0,0 +1,204 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.components +import qs.components.controls +import qs.components.effects +import qs.components.containers +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Session session + readonly property var device: session.ethernet.active + + StyledFlickable { + anchors.fill: parent + + flickableDirection: Flickable.VerticalFlick + contentHeight: layout.height + + ColumnLayout { + id: layout + + anchors.left: parent.left + anchors.right: parent.right + spacing: Appearance.spacing.normal + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + animate: true + text: "cable" + font.pointSize: Appearance.font.size.extraLarge * 3 + font.bold: true + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + animate: true + text: root.device?.interface ?? qsTr("Unknown") + font.pointSize: Appearance.font.size.large + font.bold: true + } + + StyledText { + Layout.topMargin: Appearance.spacing.large + text: qsTr("Connection status") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + text: qsTr("Connection settings for this device") + color: Colours.palette.m3outline + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: deviceStatus.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: deviceStatus + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.larger + + Toggle { + label: qsTr("Connected") + checked: root.device?.connected ?? false + toggle.onToggled: { + if (checked) { + if (root.device?.connection) { + Network.connectEthernet(root.device.connection); + } + } else { + if (root.device?.connection) { + Network.disconnectEthernet(root.device.connection); + } + } + } + } + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.large + text: qsTr("Device properties") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + text: qsTr("Additional information") + color: Colours.palette.m3outline + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: deviceProps.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: deviceProps + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.small / 2 + + StyledText { + text: qsTr("Interface") + } + + StyledText { + text: root.device?.interface ?? qsTr("Unknown") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("Connection") + } + + StyledText { + text: root.device?.connection || qsTr("Not connected") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("State") + } + + StyledText { + text: root.device?.state ?? qsTr("Unknown") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + } + } + + } + } + + component Toggle: RowLayout { + required property string label + property alias checked: toggle.checked + property alias toggle: toggle + + Layout.fillWidth: true + spacing: Appearance.spacing.normal + + StyledText { + Layout.fillWidth: true + text: parent.label + } + + StyledSwitch { + id: toggle + + cLayer: 2 + } + } +} + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/controlcenter/ethernet/EthernetList.qml b/modules/controlcenter/ethernet/EthernetList.qml new file mode 100644 index 0000000..d239fc6 --- /dev/null +++ b/modules/controlcenter/ethernet/EthernetList.qml @@ -0,0 +1,262 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.components +import qs.components.controls +import qs.components.containers +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property Session session + + spacing: Appearance.spacing.small + + RowLayout { + spacing: Appearance.spacing.smaller + + StyledText { + text: qsTr("Settings") + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + + Item { + Layout.fillWidth: true + } + + ToggleButton { + toggled: !root.session.ethernet.active + icon: "settings" + accent: "Primary" + + function onClicked(): void { + if (root.session.ethernet.active) + root.session.ethernet.active = null; + else { + root.session.ethernet.active = view.model.get(0)?.modelData ?? null; + } + } + } + } + + RowLayout { + Layout.fillWidth: true + spacing: Appearance.spacing.small + + StyledText { + text: qsTr("Devices (%1)").arg(Network.ethernetDeviceCount || Network.ethernetDevices.length) + font.pointSize: Appearance.font.size.large + font.weight: 500 + } + } + + StyledText { + text: qsTr("All available ethernet devices") + color: Colours.palette.m3outline + } + + StyledListView { + id: view + + Layout.fillWidth: true + Layout.fillHeight: true + + model: Network.ethernetDevices + + spacing: Appearance.spacing.small / 2 + clip: true + + StyledScrollBar.vertical: StyledScrollBar { + flickable: view + } + + delegate: StyledRect { + required property var modelData + + anchors.left: parent.left + anchors.right: parent.right + + color: Qt.alpha(Colours.tPalette.m3surfaceContainer, root.session.ethernet.active === modelData ? Colours.tPalette.m3surfaceContainer.a : 0) + radius: Appearance.rounding.normal + border.width: root.session.ethernet.active === modelData ? 1 : 0 + border.color: Colours.palette.m3primary + + StateLayer { + function onClicked(): void { + root.session.ethernet.active = modelData; + } + } + + RowLayout { + id: rowLayout + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.normal + + spacing: Appearance.spacing.normal + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: icon.implicitHeight + Appearance.padding.normal * 2 + + radius: Appearance.rounding.normal + color: modelData.connected ? Colours.palette.m3primaryContainer : Colours.tPalette.m3surfaceContainerHigh + + MaterialIcon { + id: icon + + anchors.centerIn: parent + text: "cable" + font.pointSize: Appearance.font.size.large + fill: modelData.connected ? 1 : 0 + color: modelData.connected ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface + } + } + + StyledText { + Layout.fillWidth: true + + text: modelData.interface || qsTr("Unknown") + } + + StyledText { + text: modelData.connected ? qsTr("Connected") : qsTr("Disconnected") + color: modelData.connected ? Colours.palette.m3primary : Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + font.weight: modelData.connected ? 500 : 400 + } + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: connectIcon.implicitHeight + Appearance.padding.smaller * 2 + + radius: Appearance.rounding.full + color: Qt.alpha(Colours.palette.m3primaryContainer, modelData.connected ? 1 : 0) + + StateLayer { + function onClicked(): void { + if (modelData.connected && modelData.connection) { + Network.disconnectEthernet(modelData.connection); + } else if (modelData.connection) { + Network.connectEthernet(modelData.connection); + } + } + } + + MaterialIcon { + id: connectIcon + + anchors.centerIn: parent + text: modelData.connected ? "link_off" : "link" + color: modelData.connected ? Colours.palette.m3onPrimaryContainer : Colours.palette.m3onSurface + } + } + } + + implicitHeight: rowLayout.implicitHeight + Appearance.padding.normal * 2 + } + } + + component ToggleButton: StyledRect { + id: toggleBtn + + required property bool toggled + property string icon + property string label + property string accent: "Secondary" + + function onClicked(): void { + } + + Layout.preferredWidth: implicitWidth + (toggleStateLayer.pressed ? Appearance.padding.normal * 2 : toggled ? Appearance.padding.small * 2 : 0) + implicitWidth: toggleBtnInner.implicitWidth + Appearance.padding.large * 2 + implicitHeight: toggleBtnIcon.implicitHeight + Appearance.padding.normal * 2 + + radius: toggled || toggleStateLayer.pressed ? Appearance.rounding.small : Math.min(width, height) / 2 * Math.min(1, Appearance.rounding.scale) + color: toggled ? Colours.palette[`m3${accent.toLowerCase()}`] : Colours.palette[`m3${accent.toLowerCase()}Container`] + + StateLayer { + id: toggleStateLayer + + color: toggleBtn.toggled ? Colours.palette[`m3on${toggleBtn.accent}`] : Colours.palette[`m3on${toggleBtn.accent}Container`] + + function onClicked(): void { + toggleBtn.onClicked(); + } + } + + RowLayout { + id: toggleBtnInner + + anchors.centerIn: parent + spacing: Appearance.spacing.normal + + MaterialIcon { + id: toggleBtnIcon + + visible: !!text + fill: toggleBtn.toggled ? 1 : 0 + text: toggleBtn.icon + color: toggleBtn.toggled ? Colours.palette[`m3on${toggleBtn.accent}`] : Colours.palette[`m3on${toggleBtn.accent}Container`] + font.pointSize: Appearance.font.size.large + + Behavior on fill { + Anim {} + } + } + + Loader { + asynchronous: true + active: !!toggleBtn.label + visible: active + + sourceComponent: StyledText { + text: toggleBtn.label + color: toggleBtn.toggled ? Colours.palette[`m3on${toggleBtn.accent}`] : Colours.palette[`m3on${toggleBtn.accent}Container`] + } + } + } + + Behavior on radius { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + Behavior on Layout.preferredWidth { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + } +} + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/controlcenter/ethernet/EthernetPane.qml b/modules/controlcenter/ethernet/EthernetPane.qml new file mode 100644 index 0000000..fc3e1c0 --- /dev/null +++ b/modules/controlcenter/ethernet/EthernetPane.qml @@ -0,0 +1,156 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.components +import qs.components.effects +import qs.components.containers +import qs.config +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +RowLayout { + id: root + + required property Session session + + anchors.fill: parent + + spacing: 0 + + Item { + Layout.preferredWidth: Math.floor(parent.width * 0.4) + Layout.minimumWidth: 420 + Layout.fillHeight: true + + EthernetList { + anchors.fill: parent + anchors.margins: Appearance.padding.large + Appearance.padding.normal + anchors.leftMargin: Appearance.padding.large + anchors.rightMargin: Appearance.padding.large + Appearance.padding.normal / 2 + + session: root.session + } + + InnerBorder { + leftThickness: 0 + rightThickness: Appearance.padding.normal / 2 + } + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + + ClippingRectangle { + anchors.fill: parent + anchors.margins: Appearance.padding.normal + anchors.leftMargin: 0 + anchors.rightMargin: Appearance.padding.normal / 2 + + radius: rightBorder.innerRadius + color: "transparent" + + Loader { + id: loader + + property var pane: root.session.ethernet.active + property string paneId: pane ? (pane.interface || "") : "" + + anchors.fill: parent + anchors.margins: Appearance.padding.large * 2 + + opacity: 1 + scale: 1 + transformOrigin: Item.Center + + clip: false + asynchronous: true + sourceComponent: pane ? details : settings + + Behavior on paneId { + SequentialAnimation { + ParallelAnimation { + Anim { + target: loader + property: "opacity" + to: 0 + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + Anim { + target: loader + property: "scale" + to: 0.8 + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + } + PropertyAction {} + ParallelAnimation { + Anim { + target: loader + property: "opacity" + to: 1 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + Anim { + target: loader + property: "scale" + to: 1 + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + } + } + } + + onPaneChanged: { + paneId = pane ? (pane.interface || "") : ""; + } + } + } + + InnerBorder { + id: rightBorder + + leftThickness: Appearance.padding.normal / 2 + } + + Component { + id: settings + + StyledFlickable { + flickableDirection: Flickable.VerticalFlick + contentHeight: settingsInner.height + + EthernetSettings { + id: settingsInner + + anchors.left: parent.left + anchors.right: parent.right + session: root.session + } + } + } + + Component { + id: details + + EthernetDetails { + session: root.session + } + } + } + + component Anim: NumberAnimation { + target: loader + duration: Appearance.anim.durations.normal / 2 + easing.type: Easing.BezierSpline + } +} + + + + + + + + diff --git a/modules/controlcenter/ethernet/EthernetSettings.qml b/modules/controlcenter/ethernet/EthernetSettings.qml new file mode 100644 index 0000000..b780b55 --- /dev/null +++ b/modules/controlcenter/ethernet/EthernetSettings.qml @@ -0,0 +1,155 @@ +pragma ComponentBehavior: Bound + +import ".." +import qs.components +import qs.components.controls +import qs.components.effects +import qs.services +import qs.config +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property Session session + + spacing: Appearance.spacing.normal + + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + text: "cable" + font.pointSize: Appearance.font.size.extraLarge * 3 + font.bold: true + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("Ethernet settings") + font.pointSize: Appearance.font.size.large + font.bold: true + } + + StyledText { + Layout.topMargin: Appearance.spacing.large + text: qsTr("Ethernet devices") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledText { + text: qsTr("Available ethernet devices") + color: Colours.palette.m3outline + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: ethernetInfo.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: ethernetInfo + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.small / 2 + + StyledText { + text: qsTr("Total devices") + } + + StyledText { + text: qsTr("%1").arg(Network.ethernetDeviceCount || Network.ethernetDevices.length) + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("Connected devices") + } + + StyledText { + text: qsTr("%1").arg(Network.ethernetDevices.filter(d => d.connected).length) + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.small + } + } + } + + StyledText { + Layout.topMargin: Appearance.spacing.large + text: qsTr("Debug Info") + font.pointSize: Appearance.font.size.larger + font.weight: 500 + } + + StyledRect { + Layout.fillWidth: true + implicitHeight: debugInfo.implicitHeight + Appearance.padding.large * 2 + + radius: Appearance.rounding.normal + color: Colours.tPalette.m3surfaceContainer + + ColumnLayout { + id: debugInfo + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.large + + spacing: Appearance.spacing.small / 2 + + StyledText { + text: qsTr("Process running: %1").arg(Network.ethernetProcessRunning ? "Yes" : "No") + font.pointSize: Appearance.font.size.small + } + + StyledText { + text: qsTr("List length: %1").arg(Network.ethernetDevices.length) + font.pointSize: Appearance.font.size.small + } + + StyledText { + text: qsTr("Device count: %1").arg(Network.ethernetDeviceCount) + font.pointSize: Appearance.font.size.small + } + + StyledText { + Layout.topMargin: Appearance.spacing.normal + text: qsTr("Debug: %1").arg(Network.ethernetDebugInfo || "No info") + font.pointSize: Appearance.font.size.small + color: Colours.palette.m3outline + wrapMode: Text.Wrap + Layout.maximumWidth: parent.width + } + } + } +} + + + + + + + + + + + + + + + + + + + + + diff --git a/services/Network.qml b/services/Network.qml index 3ceadab..1dee367 100644 --- a/services/Network.qml +++ b/services/Network.qml @@ -7,11 +7,24 @@ import QtQuick Singleton { id: root + Component.onCompleted: { + // Trigger ethernet device detection after initialization + Qt.callLater(() => { + getEthernetDevices(); + }); + } + readonly property list<AccessPoint> networks: [] readonly property AccessPoint active: networks.find(n => n.active) ?? null property bool wifiEnabled: true readonly property bool scanning: rescanProc.running + property list<var> ethernetDevices: [] + readonly property var activeEthernet: ethernetDevices.find(d => d.connected) ?? null + property int ethernetDeviceCount: 0 + property string ethernetDebugInfo: "" + property bool ethernetProcessRunning: false + function enableWifi(enabled: bool): void { const cmd = enabled ? "on" : "off"; enableWifiProc.exec(["nmcli", "radio", "wifi", cmd]); @@ -70,11 +83,27 @@ Singleton { wifiStatusProc.running = true; } + function getEthernetDevices(): void { + getEthernetDevicesProc.running = true; + } + + + function connectEthernet(connectionName: string): void { + connectEthernetProc.exec(["nmcli", "connection", "up", connectionName]); + } + + function disconnectEthernet(connectionName: string): void { + disconnectEthernetProc.exec(["nmcli", "connection", "down", connectionName]); + } + Process { running: true command: ["nmcli", "m"] stdout: SplitParser { - onRead: getNetworks.running = true + onRead: { + getNetworks.running = true; + getEthernetDevices(); + } } } @@ -336,6 +365,158 @@ Singleton { } } + Process { + id: getEthernetDevicesProc + + running: false + command: ["nmcli", "-g", "DEVICE,TYPE,STATE,CONNECTION", "device", "status"] + environment: ({ + LANG: "C.UTF-8", + LC_ALL: "C.UTF-8" + }) + onRunningChanged: { + root.ethernetProcessRunning = running; + if (!running) { + // Process finished, update debug info + Qt.callLater(() => { + if (root.ethernetDebugInfo === "" || root.ethernetDebugInfo.includes("Process exited")) { + root.ethernetDebugInfo = "Process finished, waiting for output..."; + } + }); + } + } + onExited: { + Qt.callLater(() => { + const outputLength = ethernetStdout.text ? ethernetStdout.text.length : 0; + root.ethernetDebugInfo = "Process exited with code: " + exitCode + ", output length: " + outputLength; + if (outputLength > 0) { + // Output was captured, process it + const output = ethernetStdout.text.trim(); + root.ethernetDebugInfo = "Processing output from onExited, length: " + output.length + "\nOutput: " + output.substring(0, 200); + root.processEthernetOutput(output); + } else { + root.ethernetDebugInfo = "No output captured in onExited"; + } + }); + } + stdout: StdioCollector { + id: ethernetStdout + onStreamFinished: { + const output = text.trim(); + root.ethernetDebugInfo = "Output received in onStreamFinished! Length: " + output.length + ", First 100 chars: " + output.substring(0, 100); + + if (!output || output.length === 0) { + root.ethernetDebugInfo = "No output received (empty)"; + return; + } + + root.processEthernetOutput(output); + } + } + } + + function processEthernetOutput(output: string): void { + const PLACEHOLDER = "STRINGWHICHHOPEFULLYWONTBEUSED"; + const rep = new RegExp("\\\\:", "g"); + const rep2 = new RegExp(PLACEHOLDER, "g"); + + const lines = output.split("\n"); + root.ethernetDebugInfo = "Processing " + lines.length + " lines"; + + const allDevices = lines.map(d => { + const dev = d.replace(rep, PLACEHOLDER).split(":"); + return { + interface: dev[0]?.replace(rep2, ":") ?? "", + type: dev[1]?.replace(rep2, ":") ?? "", + state: dev[2]?.replace(rep2, ":") ?? "", + connection: dev[3]?.replace(rep2, ":") ?? "" + }; + }); + + root.ethernetDebugInfo = "All devices: " + allDevices.length + ", Types: " + allDevices.map(d => d.type).join(", "); + + const ethernetOnly = allDevices.filter(d => d.type === "ethernet"); + root.ethernetDebugInfo = "Ethernet devices found: " + ethernetOnly.length; + + const ethernetDevices = ethernetOnly.map(d => { + const state = d.state || ""; + const connected = state === "100 (connected)" || state === "connected" || state.startsWith("connected"); + return { + interface: d.interface, + type: d.type, + state: state, + connection: d.connection, + connected: connected, + ipAddress: "", + gateway: "", + dns: [], + subnet: "", + macAddress: "", + speed: "" + }; + }); + + root.ethernetDebugInfo = "Ethernet devices processed: " + ethernetDevices.length + ", First device: " + (ethernetDevices[0]?.interface || "none"); + + // Update the list - replace the entire array to ensure QML detects the change + // Create a new array and assign it to the property + const newDevices = []; + for (let i = 0; i < ethernetDevices.length; i++) { + newDevices.push(ethernetDevices[i]); + } + + // Replace the entire list + root.ethernetDevices = newDevices; + + // Force QML to detect the change by updating a property + root.ethernetDeviceCount = ethernetDevices.length; + + // Force QML to re-evaluate the list by accessing it + Qt.callLater(() => { + const count = root.ethernetDevices.length; + root.ethernetDebugInfo = "Final: Found " + ethernetDevices.length + " devices, List length: " + count + ", Parsed all: " + allDevices.length + ", Output length: " + output.length; + }); + } + + + Process { + id: connectEthernetProc + + onExited: { + getEthernetDevices(); + } + stdout: SplitParser { + onRead: getEthernetDevices() + } + stderr: StdioCollector { + onStreamFinished: { + const error = text.trim(); + if (error && error.length > 0 && !error.includes("successfully") && !error.includes("Connection activated")) { + console.warn("Ethernet connection error:", error); + } + } + } + } + + Process { + id: disconnectEthernetProc + + onExited: { + getEthernetDevices(); + } + stdout: SplitParser { + onRead: getEthernetDevices() + } + stderr: StdioCollector { + onStreamFinished: { + const error = text.trim(); + if (error && error.length > 0 && !error.includes("successfully") && !error.includes("disconnected")) { + console.warn("Ethernet disconnection error:", error); + } + } + } + } + component AccessPoint: QtObject { required property var lastIpcObject readonly property string ssid: lastIpcObject.ssid |