pragma ComponentBehavior: Bound import qs.components import qs.components.controls import qs.services import qs.config import qs.utils import Quickshell import QtQuick import QtQuick.Layouts ColumnLayout { id: root spacing: Appearance.spacing.small width: Config.bar.sizes.networkWidth StyledText { Layout.topMargin: Appearance.padding.normal Layout.rightMargin: Appearance.padding.small text: qsTr("Ethernet") font.weight: 500 } StyledText { Layout.topMargin: Appearance.spacing.small Layout.rightMargin: Appearance.padding.small text: qsTr("%1 devices available").arg(Network.ethernetDeviceCount || Network.ethernetDevices.length) color: Colours.palette.m3onSurfaceVariant font.pointSize: Appearance.font.size.small } Repeater { model: ScriptModel { values: [...Network.ethernetDevices].sort((a, b) => { if (a.connected !== b.connected) return b.connected - a.connected; return (a.interface || "").localeCompare(b.interface || ""); }).slice(0, 8) } RowLayout { id: ethernetItem required property var modelData readonly property bool loading: false Layout.fillWidth: true Layout.rightMargin: Appearance.padding.small spacing: Appearance.spacing.small opacity: 0 scale: 0.7 Component.onCompleted: { opacity = 1; scale = 1; } Behavior on opacity { Anim {} } Behavior on scale { Anim {} } MaterialIcon { text: "cable" color: ethernetItem.modelData.connected ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant } StyledText { Layout.leftMargin: Appearance.spacing.small / 2 Layout.rightMargin: Appearance.spacing.small / 2 Layout.fillWidth: true text: ethernetItem.modelData.interface || qsTr("Unknown") elide: Text.ElideRight font.weight: ethernetItem.modelData.connected ? 500 : 400 color: ethernetItem.modelData.connected ? Colours.palette.m3primary : Colours.palette.m3onSurface } StyledRect { id: connectBtn implicitWidth: implicitHeight implicitHeight: connectIcon.implicitHeight + Appearance.padding.small radius: Appearance.rounding.full color: Qt.alpha(Colours.palette.m3primary, ethernetItem.modelData.connected ? 1 : 0) CircularIndicator { anchors.fill: parent running: ethernetItem.loading } StateLayer { color: ethernetItem.modelData.connected ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface disabled: ethernetItem.loading function onClicked(): void { if (ethernetItem.modelData.connected && ethernetItem.modelData.connection) { Network.disconnectEthernet(ethernetItem.modelData.connection); } else { Network.connectEthernet(ethernetItem.modelData.connection || "", ethernetItem.modelData.interface || ""); } } } MaterialIcon { id: connectIcon anchors.centerIn: parent animate: true text: ethernetItem.modelData.connected ? "link_off" : "link" color: ethernetItem.modelData.connected ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface opacity: ethernetItem.loading ? 0 : 1 Behavior on opacity { Anim {} } } } } } StyledRect { Layout.topMargin: Appearance.spacing.small Layout.fillWidth: true implicitHeight: refreshBtn.implicitHeight + Appearance.padding.small * 2 radius: Appearance.rounding.full color: Colours.palette.m3primaryContainer StateLayer { color: Colours.palette.m3onPrimaryContainer disabled: Network.ethernetProcessRunning function onClicked(): void { Network.getEthernetDevices(); } } RowLayout { id: refreshBtn anchors.centerIn: parent spacing: Appearance.spacing.small opacity: Network.ethernetProcessRunning ? 0 : 1 MaterialIcon { id: refreshIcon animate: true text: "refresh" color: Colours.palette.m3onPrimaryContainer } StyledText { text: qsTr("Refresh devices") color: Colours.palette.m3onPrimaryContainer } Behavior on opacity { Anim {} } } CircularIndicator { anchors.centerIn: parent strokeWidth: Appearance.padding.small / 2 bgColour: "transparent" implicitHeight: parent.implicitHeight - Appearance.padding.smaller * 2 running: Network.ethernetProcessRunning } } }