controlcenter: ethernet panel (debug)
This commit is contained in:
parent
47dfcf4baf
commit
1debf488ee
8 changed files with 983 additions and 7 deletions
|
|
@ -158,8 +158,13 @@ Item {
|
||||||
|
|
||||||
NavItem {
|
NavItem {
|
||||||
Layout.topMargin: Appearance.spacing.large * 2
|
Layout.topMargin: Appearance.spacing.large * 2
|
||||||
icon: "network_manage"
|
icon: "cable"
|
||||||
label: "network"
|
label: "ethernet"
|
||||||
|
}
|
||||||
|
|
||||||
|
NavItem {
|
||||||
|
icon: "wifi"
|
||||||
|
label: "wireless"
|
||||||
}
|
}
|
||||||
|
|
||||||
NavItem {
|
NavItem {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import "ethernet"
|
||||||
import "bluetooth"
|
import "bluetooth"
|
||||||
import "network"
|
import "network"
|
||||||
import "audio"
|
import "audio"
|
||||||
|
|
@ -26,27 +27,34 @@ ClippingRectangle {
|
||||||
|
|
||||||
Pane {
|
Pane {
|
||||||
index: 0
|
index: 0
|
||||||
sourceComponent: NetworkPane {
|
sourceComponent: EthernetPane {
|
||||||
session: root.session
|
session: root.session
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Pane {
|
Pane {
|
||||||
index: 1
|
index: 1
|
||||||
sourceComponent: BtPane {
|
sourceComponent: NetworkPane {
|
||||||
session: root.session
|
session: root.session
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Pane {
|
Pane {
|
||||||
index: 2
|
index: 2
|
||||||
sourceComponent: AudioPane {
|
sourceComponent: BtPane {
|
||||||
session: root.session
|
session: root.session
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Pane {
|
Pane {
|
||||||
index: 3
|
index: 3
|
||||||
|
sourceComponent: AudioPane {
|
||||||
|
session: root.session
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Pane {
|
||||||
|
index: 4
|
||||||
sourceComponent: AppearancePane {
|
sourceComponent: AppearancePane {
|
||||||
session: root.session
|
session: root.session
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import Quickshell.Bluetooth
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
readonly property list<string> panes: ["network", "bluetooth", "audio", "appearance"]
|
readonly property list<string> panes: ["ethernet", "wireless", "bluetooth", "audio", "appearance"]
|
||||||
|
|
||||||
required property var root
|
required property var root
|
||||||
property bool floating: false
|
property bool floating: false
|
||||||
|
|
@ -12,6 +12,7 @@ QtObject {
|
||||||
|
|
||||||
readonly property Bt bt: Bt {}
|
readonly property Bt bt: Bt {}
|
||||||
readonly property Network network: Network {}
|
readonly property Network network: Network {}
|
||||||
|
readonly property Ethernet ethernet: Ethernet {}
|
||||||
|
|
||||||
onActiveChanged: activeIndex = panes.indexOf(active)
|
onActiveChanged: activeIndex = panes.indexOf(active)
|
||||||
onActiveIndexChanged: active = panes[activeIndex]
|
onActiveIndexChanged: active = panes[activeIndex]
|
||||||
|
|
@ -29,4 +30,8 @@ QtObject {
|
||||||
property bool showPasswordDialog: false
|
property bool showPasswordDialog: false
|
||||||
property var pendingNetwork
|
property var pendingNetwork
|
||||||
}
|
}
|
||||||
|
|
||||||
|
component Ethernet: QtObject {
|
||||||
|
property var active
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
204
modules/controlcenter/ethernet/EthernetDetails.qml
Normal file
204
modules/controlcenter/ethernet/EthernetDetails.qml
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
262
modules/controlcenter/ethernet/EthernetList.qml
Normal file
262
modules/controlcenter/ethernet/EthernetList.qml
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
156
modules/controlcenter/ethernet/EthernetPane.qml
Normal file
156
modules/controlcenter/ethernet/EthernetPane.qml
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
155
modules/controlcenter/ethernet/EthernetSettings.qml
Normal file
155
modules/controlcenter/ethernet/EthernetSettings.qml
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -7,11 +7,24 @@ import QtQuick
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
// Trigger ethernet device detection after initialization
|
||||||
|
Qt.callLater(() => {
|
||||||
|
getEthernetDevices();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
readonly property list<AccessPoint> networks: []
|
readonly property list<AccessPoint> networks: []
|
||||||
readonly property AccessPoint active: networks.find(n => n.active) ?? null
|
readonly property AccessPoint active: networks.find(n => n.active) ?? null
|
||||||
property bool wifiEnabled: true
|
property bool wifiEnabled: true
|
||||||
readonly property bool scanning: rescanProc.running
|
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 {
|
function enableWifi(enabled: bool): void {
|
||||||
const cmd = enabled ? "on" : "off";
|
const cmd = enabled ? "on" : "off";
|
||||||
enableWifiProc.exec(["nmcli", "radio", "wifi", cmd]);
|
enableWifiProc.exec(["nmcli", "radio", "wifi", cmd]);
|
||||||
|
|
@ -70,11 +83,27 @@ Singleton {
|
||||||
wifiStatusProc.running = true;
|
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 {
|
Process {
|
||||||
running: true
|
running: true
|
||||||
command: ["nmcli", "m"]
|
command: ["nmcli", "m"]
|
||||||
stdout: SplitParser {
|
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 {
|
component AccessPoint: QtObject {
|
||||||
required property var lastIpcObject
|
required property var lastIpcObject
|
||||||
readonly property string ssid: lastIpcObject.ssid
|
readonly property string ssid: lastIpcObject.ssid
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue