Files
noctalia-shell/Modules/Panels/Network/NetworkPanel.qml
T

948 lines
44 KiB
QML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import "../Settings/Tabs/Connections" as WifiPrefs
import qs.Commons
import qs.Modules.MainScreen
import qs.Modules.Panels.Settings
import qs.Services.Networking
import qs.Services.System
import qs.Services.UI
import qs.Widgets
SmartPanel {
id: root
preferredWidth: Math.round(440 * Style.uiScaleRatio)
preferredHeight: Math.round(500 * Style.uiScaleRatio)
// Info panel collapsed by default, view mode persisted in settings
// Ethernet details UI state (mirrors WiFi info behavior)
property bool ethernetInfoExpanded: false
property bool ethernetDetailsGrid: (Settings.data.network.wifiDetailsViewMode === "grid")
property int ipVersion: 4
// Unified panel view mode: "wifi" | "ethernet" (persisted)
property string panelViewMode: "wifi"
property bool panelViewPersistEnabled: false
onPanelViewModeChanged: {
// Persist last view (only after restored the initial value)
if (panelViewPersistEnabled) {
Settings.data.network.networkPanelView = panelViewMode;
}
if (panelViewMode === "wifi") {
ethernetInfoExpanded = false;
if (Settings.data.network.wifiEnabled && !NetworkService.scanning) {
NetworkService.scan();
}
} else {
if (NetworkService.ethernetConnected) {
NetworkService.refreshActiveEthernetDetails();
} else {
NetworkService.refreshEthernet();
}
}
}
// Effectively visible tracking
readonly property bool effectivelyVisible: root.visible && Window.window && Window.window.visible
onEffectivelyVisibleChanged: {
if (effectivelyVisible) {
SystemStatService.registerComponent("network-panel");
NetworkService.scan();
// Preload active WiFi details so Info shows instantly
NetworkService.refreshActiveWifiDetails();
// Also fetch Ethernet details if connected
NetworkService.refreshActiveEthernetDetails();
} else {
SystemStatService.unregisterComponent("network-panel");
}
}
onOpened: {
// Restore last view if valid, otherwise choose what's available (prefer WiFi when both exist)
if (Settings.data.network.networkPanelView) {
const last = Settings.data.network.networkPanelView;
if (last === "ethernet" && NetworkService.hasEthernet()) {
panelViewMode = "ethernet";
} else {
panelViewMode = "wifi";
}
} else {
if (!Settings.data.network.wifiEnabled && NetworkService.hasEthernet()) {
panelViewMode = "ethernet";
} else {
panelViewMode = "wifi";
}
}
panelViewPersistEnabled = true;
}
panelContent: Rectangle {
color: "transparent"
property real contentPreferredHeight: Math.min(root.preferredHeight, mainColumn.implicitHeight + Style.margin2L)
ColumnLayout {
id: mainColumn
anchors.fill: parent
anchors.margins: Style.marginL
spacing: Style.marginM
// Header
NBox {
Layout.fillWidth: true
Layout.preferredHeight: header.implicitHeight + Style.margin2M
ColumnLayout {
id: header
anchors.fill: parent
anchors.margins: Style.marginM
spacing: Style.marginM
RowLayout {
NIcon {
id: modeIcon
icon: panelViewMode === "wifi" ? (Settings.data.network.wifiEnabled ? "wifi" : "wifi-off") : (NetworkService.hasEthernet() ? (NetworkService.ethernetConnected ? "ethernet" : "ethernet") : "ethernet-off")
pointSize: Style.fontSizeXXL
color: {
if (panelViewMode === "wifi") {
return Settings.data.network.wifiEnabled ? Color.mPrimary : Color.mOnSurfaceVariant;
} else {
return NetworkService.ethernetConnected ? Color.mPrimary : Color.mOnSurfaceVariant;
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onClicked: {
if (panelViewMode === "wifi") {
if (NetworkService.hasEthernet()) {
panelViewMode = "ethernet";
} else {
TooltipService.show(parent, I18n.tr("wifi.panel.no-ethernet-devices"));
}
} else {
panelViewMode = "wifi";
}
}
onEntered: TooltipService.show(parent, panelViewMode === "wifi" ? I18n.tr("common.wifi") : I18n.tr("common.ethernet"))
onExited: TooltipService.hide()
}
}
NLabel {
label: panelViewMode === "wifi" ? I18n.tr("common.wifi") : I18n.tr("common.ethernet")
Layout.fillWidth: true
}
NToggle {
id: wifiSwitch
visible: panelViewMode === "wifi"
checked: Settings.data.network.wifiEnabled
enabled: !Settings.data.network.airplaneModeEnabled && NetworkService.wifiAvailable
onToggled: checked => NetworkService.setWifiEnabled(checked)
baseSize: Style.baseWidgetSize * 0.7 // Slightly smaller
}
NIconButton {
icon: "settings"
tooltipText: I18n.tr("tooltips.open-settings")
baseSize: Style.baseWidgetSize * 0.8
onClicked: SettingsPanelService.openToTab(SettingsPanel.Tab.Connections, 0, screen)
}
NIconButton {
icon: "close"
tooltipText: I18n.tr("common.close")
baseSize: Style.baseWidgetSize * 0.8
onClicked: root.close()
}
}
// Mode switch (WiFi / Ethernet)
NTabBar {
id: modeTabBar
visible: NetworkService.hasEthernet()
margins: Style.marginS
Layout.fillWidth: true
spacing: Style.marginM
distributeEvenly: true
currentIndex: root.panelViewMode === "wifi" ? 0 : 1
onCurrentIndexChanged: {
root.panelViewMode = (currentIndex === 0) ? "wifi" : "ethernet";
}
NTabButton {
text: I18n.tr("common.wifi")
tabIndex: 0
checked: modeTabBar.currentIndex === 0
}
NTabButton {
text: I18n.tr("common.ethernet")
tabIndex: 1
checked: modeTabBar.currentIndex === 1
}
}
}
}
// Unified scrollable content (WiFi or Ethernet view)
ColumnLayout {
id: wifiSectionContainer
visible: true
Layout.fillWidth: true
spacing: Style.marginM
// Error message
Rectangle {
visible: panelViewMode === "wifi" && NetworkService.lastError.length > 0
Layout.fillWidth: true
Layout.preferredHeight: errorRow.implicitHeight + Style.margin2M
color: Qt.alpha(Color.mError, 0.1)
radius: Style.radiusS
border.width: Style.borderS
border.color: Color.mError
RowLayout {
id: errorRow
anchors.fill: parent
anchors.margins: Style.marginM
spacing: Style.marginS
NIcon {
icon: "warning"
pointSize: Style.fontSizeL
color: Color.mError
}
NText {
text: NetworkService.lastError
color: Color.mError
pointSize: Style.fontSizeS
wrapMode: Text.Wrap
Layout.fillWidth: true
}
NIconButton {
icon: "close"
baseSize: Style.baseWidgetSize * 0.6
onClicked: NetworkService.lastError = ""
}
}
}
// Unified scrollable content
NScrollView {
id: contentScroll
Layout.fillWidth: true
Layout.fillHeight: true
horizontalPolicy: ScrollBar.AlwaysOff
verticalPolicy: ScrollBar.AsNeeded
reserveScrollbarSpace: false
gradientColor: Color.mSurface
ColumnLayout {
id: contentColumn
width: contentScroll.availableWidth
spacing: Style.marginM
// WiFi disabled state
NBox {
id: disabledBox
visible: panelViewMode === "wifi" && !Settings.data.network.wifiEnabled
Layout.fillWidth: true
Layout.preferredHeight: disabledColumn.implicitHeight + Style.margin2M
ColumnLayout {
id: disabledColumn
anchors.fill: parent
anchors.margins: Style.marginM
spacing: Style.marginL
Item {
Layout.fillHeight: true
}
NIcon {
icon: "wifi-off"
pointSize: 48
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
NText {
text: I18n.tr("wifi.panel.disabled")
pointSize: Style.fontSizeL
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
NText {
text: I18n.tr("wifi.panel.enable-message")
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
horizontalAlignment: Text.AlignHCenter
Layout.fillWidth: true
wrapMode: Text.WordWrap
}
Item {
Layout.fillHeight: true
}
}
}
// Scanning state (show when no networks and we haven't had any yet)
NBox {
id: scanningBox
visible: panelViewMode === "wifi" && Settings.data.network.wifiEnabled && Object.keys(NetworkService.networks).length === 0 && NetworkService.scanning
Layout.fillWidth: true
Layout.preferredHeight: scanningColumn.implicitHeight + Style.margin2M
ColumnLayout {
id: scanningColumn
anchors.fill: parent
anchors.margins: Style.marginM
spacing: Style.marginL
Item {
Layout.fillHeight: true
}
NBusyIndicator {
running: visible && root.effectivelyVisible
color: Color.mPrimary
size: Style.baseWidgetSize
Layout.alignment: Qt.AlignHCenter
}
NText {
text: I18n.tr("wifi.panel.searching")
pointSize: Style.fontSizeM
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
Item {
Layout.fillHeight: true
}
}
}
// Empty state when no networks (only show after we've had networks before, meaning a real empty result)
NBox {
id: emptyBox
visible: panelViewMode === "wifi" && Settings.data.network.wifiEnabled && !NetworkService.scanning && Object.keys(NetworkService.networks).length === 0 && !NetworkService.scanning
Layout.fillWidth: true
Layout.preferredHeight: emptyColumn.implicitHeight + Style.margin2M
ColumnLayout {
id: emptyColumn
anchors.fill: parent
anchors.margins: Style.marginM
spacing: Style.marginL
Item {
Layout.fillHeight: true
}
NIcon {
icon: "search"
pointSize: 48
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
NText {
text: I18n.tr("wifi.panel.no-networks")
pointSize: Style.fontSizeL
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
Item {
Layout.fillHeight: true
}
}
}
// Networks list container (WiFi)
ColumnLayout {
id: networksList
visible: panelViewMode === "wifi" && Settings.data.network.wifiEnabled && Object.keys(NetworkService.networks).length > 0
width: parent.width
spacing: Style.marginM
WifiPrefs.WifiSubTab {
showOnlyLists: true
}
}
// Ethernet view
NBox {
id: ethernetSection
visible: panelViewMode === "ethernet"
Layout.fillWidth: true
Layout.preferredHeight: ethernetColumn.implicitHeight + Style.margin2M
ColumnLayout {
id: ethernetColumn
anchors.fill: parent
anchors.margins: Style.marginM
spacing: Style.marginM
// Section label
NLabel {
label: I18n.tr("wifi.panel.available-interfaces")
visible: (NetworkService.ethernetInterfaces && NetworkService.ethernetInterfaces.length > 0)
}
// Empty state when no Ethernet devices
ColumnLayout {
id: emptyEthColumn
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
Layout.preferredHeight: emptyEthColumn.implicitHeight + Style.margin2M
visible: !(NetworkService.ethernetInterfaces && NetworkService.ethernetInterfaces.length > 0)
spacing: Style.marginL
Item {
Layout.fillHeight: true
}
NIcon {
icon: "ethernet-off"
pointSize: 48
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
NText {
text: I18n.tr("wifi.panel.no-ethernet-devices")
pointSize: Style.fontSizeL
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
}
Item {
Layout.fillHeight: true
}
}
// Interfaces list
ColumnLayout {
id: ethIfacesList
visible: NetworkService.ethernetInterfaces && NetworkService.ethernetInterfaces.length > 0
width: parent.width
spacing: Style.marginXS
Repeater {
model: NetworkService.ethernetInterfaces || []
delegate: NBox {
id: ethItem
function getContentColors(defaultColors = [Color.mSurface, Color.mOnSurface]) {
if (modelData.connected) {
return [Color.mPrimary, Color.mOnPrimary];
}
return defaultColors;
}
Layout.fillWidth: true
Layout.leftMargin: Style.marginXS
Layout.rightMargin: Style.marginXS
implicitHeight: ethItemColumn.implicitHeight + Style.margin2M
radius: Style.radiusM
color: ethItem.getContentColors()[0]
ColumnLayout {
id: ethItemColumn
width: parent.width - Style.margin2M
x: Style.marginM
y: Style.marginM
spacing: Style.marginS
// Main row matching WiFi card style
// Click handling for the whole header row is provided by a sibling MouseArea
// anchored to this row (defined right after this RowLayout).
RowLayout {
id: ethHeaderRow
Layout.fillWidth: true
spacing: Style.marginS
NIcon {
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
horizontalAlignment: Text.AlignLeft
icon: NetworkService.getIcon(true)
pointSize: Style.fontSizeXXL
color: ethItem.getContentColors()[1]
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
NText {
text: modelData.connectionName || modelData.ifname
pointSize: Style.fontSizeM
font.weight: modelData.connected ? Style.fontWeightBold : Style.fontWeightMedium
color: ethItem.getContentColors()[1]
elide: Text.ElideRight
Layout.fillWidth: true
}
RowLayout {
spacing: Style.marginXS
NText {
text: {
if (modelData.connected) {
switch (NetworkService.networkConnectivity) {
case "full":
return I18n.tr("common.connected");
case "limited":
case "unknown":
return I18n.tr("wifi.panel.internet-limited");
case "portal":
return I18n.tr("wifi.panel.action-required");
default:
return NetworkService.networkConnectivity;
}
}
return I18n.tr("common.disconnected");
}
pointSize: Style.fontSizeXXS
color: (!modelData.connected || NetworkService.networkConnectivity === "limited" || NetworkService.networkConnectivity === "portal" || NetworkService.networkConnectivity === "unknown") ? Color.mError : ethItem.getContentColors()[1]
}
// Network speed indicators (visible when connected and speed > 0)
RowLayout {
visible: (modelData.connected && NetworkService.networkConnectivity === "full") && (SystemStatService.rxSpeed > 0 || SystemStatService.txSpeed > 0)
spacing: 2
Layout.leftMargin: Style.marginXS
Layout.fillWidth: false
NIcon {
visible: SystemStatService.rxSpeed > 0
icon: "arrow-down"
pointSize: Style.fontSizeXXS
color: Qt.alpha(ethItem.getContentColors()[1], Style.opacityHeavy)
}
NText {
visible: SystemStatService.rxSpeed > 0
text: SystemStatService.formatSpeed(SystemStatService.rxSpeed)
pointSize: Style.fontSizeXXS
color: Qt.alpha(ethItem.getContentColors()[1], Style.opacityHeavy)
elide: Text.ElideNone
}
Item {
visible: SystemStatService.rxSpeed > 0 && SystemStatService.txSpeed > 0
width: Style.marginXS
height: 1
}
NIcon {
visible: SystemStatService.txSpeed > 0
icon: "arrow-up"
pointSize: Style.fontSizeXXS
color: Qt.alpha(ethItem.getContentColors()[1], Style.opacityHeavy)
}
NText {
visible: SystemStatService.txSpeed > 0
text: SystemStatService.formatSpeed(SystemStatService.txSpeed)
pointSize: Style.fontSizeXXS
color: Qt.alpha(ethItem.getContentColors()[1], Style.opacityHeavy)
elide: Text.ElideNone
}
}
}
}
// Info button on the right
NIconButton {
icon: "info"
tooltipText: I18n.tr("common.info")
baseSize: Style.baseWidgetSize * 0.75
colorBg: Color.mSurfaceVariant
colorFg: Color.mOnSurface
colorBorder: "transparent"
colorBorderHover: "transparent"
enabled: true
onClicked: {
if (NetworkService.activeEthernetIf === modelData.ifname && ethernetInfoExpanded) {
ethernetInfoExpanded = false;
return;
}
if (NetworkService.activeEthernetIf !== modelData.ifname) {
NetworkService.activeEthernetIf = modelData.ifname;
NetworkService.activeEthernetDetailsTimestamp = 0;
}
ethernetInfoExpanded = true;
NetworkService.refreshActiveEthernetDetails();
}
}
}
// Click handling without anchors in a Layout-managed item
TapHandler {
target: ethHeaderRow
onTapped: {
if (NetworkService.activeEthernetIf === modelData.ifname && ethernetInfoExpanded) {
ethernetInfoExpanded = false;
return;
}
if (NetworkService.activeEthernetIf !== modelData.ifname) {
NetworkService.activeEthernetIf = modelData.ifname;
NetworkService.activeEthernetDetailsTimestamp = 0;
}
ethernetInfoExpanded = true;
NetworkService.refreshActiveEthernetDetails();
}
}
// Inline Ethernet details
Rectangle {
id: ethInfoInline
visible: ethernetInfoExpanded && NetworkService.activeEthernetIf === modelData.ifname
Layout.fillWidth: true
color: Color.mSurfaceVariant
radius: Style.radiusXS
border.width: Style.borderS
border.color: Color.mOutline
implicitHeight: ethInfoGrid.implicitHeight + Style.margin2S
clip: true
Layout.topMargin: Style.marginXS
// Grid/List toggle
NIconButton {
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: Style.marginS
icon: ethernetDetailsGrid ? "layout-list" : "layout-grid"
tooltipText: ethernetDetailsGrid ? I18n.tr("tooltips.list-view") : I18n.tr("tooltips.grid-view")
baseSize: Style.baseWidgetSize * 0.65
onClicked: {
ethernetDetailsGrid = !ethernetDetailsGrid;
Settings.data.network.wifiDetailsViewMode = ethernetDetailsGrid ? "grid" : "list";
}
z: 1
}
GridLayout {
id: ethInfoGrid
anchors.fill: parent
anchors.margins: Style.marginS
anchors.rightMargin: Style.baseWidgetSize
flow: ethernetDetailsGrid ? GridLayout.TopToBottom : GridLayout.LeftToRight
rows: ethernetDetailsGrid ? 3 : 6
columns: ethernetDetailsGrid ? 2 : 1
columnSpacing: Style.marginM
rowSpacing: Style.marginXS
onColumnsChanged: {
if (ethInfoGrid.forceLayout) {
Qt.callLater(function () {
ethInfoGrid.forceLayout();
});
}
}
// --- Item 1: Interface ---
RowLayout {
Layout.fillWidth: true
Layout.preferredWidth: 1
spacing: Style.marginXS
NIcon {
icon: "ethernet"
pointSize: Style.fontSizeXS
color: Color.mOnSurface
Layout.alignment: Qt.AlignVCenter
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: TooltipService.show(parent, I18n.tr("wifi.panel.interface"))
onExited: TooltipService.hide()
}
}
NText {
text: (NetworkService.activeEthernetDetails.ifname && NetworkService.activeEthernetDetails.ifname.length > 0) ? NetworkService.activeEthernetDetails.ifname : (NetworkService.activeEthernetIf || "-")
pointSize: Style.fontSizeXS
color: Color.mOnSurface
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
wrapMode: ethernetDetailsGrid ? Text.NoWrap : Text.WrapAtWordBoundaryOrAnywhere
elide: ethernetDetailsGrid ? Text.ElideRight : Text.ElideNone
maximumLineCount: ethernetDetailsGrid ? 1 : 6
clip: true
// Click-to-copy Ethernet interface name
MouseArea {
anchors.fill: parent
// Guard against undefined by normalizing to empty strings
enabled: ((NetworkService.activeEthernetDetails.ifname || "").length > 0) || ((NetworkService.activeEthernetIf || "").length > 0)
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onEntered: TooltipService.show(parent, I18n.tr("tooltips.copy-address"))
onExited: TooltipService.hide()
onClicked: {
const value = (NetworkService.activeEthernetDetails.ifname && NetworkService.activeEthernetDetails.ifname.length > 0) ? NetworkService.activeEthernetDetails.ifname : (NetworkService.activeEthernetIf || "");
if (value.length > 0) {
Quickshell.execDetached(["wl-copy", value]);
ToastService.showNotice(I18n.tr("common.ethernet"), I18n.tr("common.copied-to-clipboard"), "ethernet");
}
}
}
}
}
// --- Item 2: Hardware Address ---
RowLayout {
Layout.fillWidth: true
Layout.preferredWidth: 1
spacing: Style.marginXS
NIcon {
icon: "hash"
pointSize: Style.fontSizeXS
color: Color.mOnSurface
Layout.alignment: Qt.AlignVCenter
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: TooltipService.show(parent, I18n.tr("bluetooth.panel.device-address"))
onExited: TooltipService.hide()
}
}
NText {
text: NetworkService.activeEthernetDetails.hwAddr || "-"
pointSize: Style.fontSizeXS
color: Color.mOnSurface
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
wrapMode: ethernetDetailsGrid ? Text.NoWrap : Text.WrapAtWordBoundaryOrAnywhere
elide: ethernetDetailsGrid ? Text.ElideRight : Text.ElideNone
maximumLineCount: ethernetDetailsGrid ? 1 : 6
clip: true
MouseArea {
anchors.fill: parent
enabled: (NetworkService.activeEthernetDetails.hwAddr || "").length > 0
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onEntered: TooltipService.show(parent, I18n.tr("tooltips.copy-address"))
onExited: TooltipService.hide()
onClicked: {
const value = NetworkService.activeEthernetDetails.hwAddr || "";
if (value.length > 0) {
Quickshell.execDetached(["wl-copy", value]);
ToastService.showNotice(I18n.tr("common.ethernet"), I18n.tr("common.copied-to-clipboard"), "ethernet");
}
}
}
}
}
// --- Item 3: Link speed ---
RowLayout {
Layout.fillWidth: true
Layout.preferredWidth: 1
spacing: Style.marginXS
NIcon {
icon: "gauge"
pointSize: Style.fontSizeXS
color: Color.mOnSurface
Layout.alignment: Qt.AlignVCenter
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: TooltipService.show(parent, I18n.tr("wifi.panel.link-speed"))
onExited: TooltipService.hide()
}
}
NText {
text: (NetworkService.activeEthernetDetails.speed && NetworkService.activeEthernetDetails.speed.length > 0) ? NetworkService.activeEthernetDetails.speed : "-"
pointSize: Style.fontSizeXS
color: Color.mOnSurface
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
wrapMode: ethernetDetailsGrid ? Text.NoWrap : Text.WrapAtWordBoundaryOrAnywhere
elide: ethernetDetailsGrid ? Text.ElideRight : Text.ElideNone
maximumLineCount: ethernetDetailsGrid ? 1 : 6
clip: true
}
}
// --- Item 4: IPv4 || IPv6 ---
RowLayout {
Layout.fillWidth: true
Layout.preferredWidth: 1
spacing: Style.marginXS
NIcon {
icon: "network"
pointSize: Style.fontSizeXS
color: Color.mOnSurface
Layout.alignment: Qt.AlignVCenter
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: TooltipService.show(parent, root.ipVersion === 4 ? I18n.tr("wifi.panel.ipv4") : I18n.tr("wifi.panel.ipv6"))
onExited: TooltipService.hide()
onClicked: {
root.ipVersion = root.ipVersion === 4 ? 6 : 4;
TooltipService.show(parent, root.ipVersion === 4 ? I18n.tr("wifi.panel.ipv4") : I18n.tr("wifi.panel.ipv6"));
}
}
}
NText {
text: root.ipVersion === 4 ? (NetworkService.activeEthernetDetails.ipv4 || "-") : ((NetworkService.activeEthernetDetails.ipv6 || []).join(", ") || "-")
pointSize: Style.fontSizeXS
color: Color.mOnSurface
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
wrapMode: ethernetDetailsGrid ? Text.NoWrap : Text.WrapAtWordBoundaryOrAnywhere
elide: ethernetDetailsGrid ? Text.ElideRight : Text.ElideNone
maximumLineCount: ethernetDetailsGrid ? 1 : 6
clip: true
// Click-to-copy Ethernet IP address
MouseArea {
anchors.fill: parent
enabled: root.ipVersion === 4 ? (NetworkService.activeEthernetDetails.ipv4 || "").length > 0 : (NetworkService.activeEthernetDetails.ipv6 || []).length > 0
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onEntered: TooltipService.show(parent, I18n.tr("tooltips.copy-address"))
onExited: TooltipService.hide()
onClicked: {
const value = root.ipVersion === 4 ? (NetworkService.activeEthernetDetails.ipv4 || "") : ((NetworkService.activeEthernetDetails.ipv6 || []).join(", ") || "");
if (value.length > 0) {
Quickshell.execDetached(["wl-copy", value]);
ToastService.showNotice(I18n.tr("common.ethernet"), I18n.tr("common.copied-to-clipboard"), "ethernet");
}
}
}
}
}
// --- Item 5: DNS ---
RowLayout {
Layout.fillWidth: true
Layout.preferredWidth: 1
spacing: Style.marginXS
NIcon {
icon: "world"
pointSize: Style.fontSizeXS
color: Color.mOnSurface
Layout.alignment: Qt.AlignVCenter
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: TooltipService.show(parent, root.ipVersion === 4 ? I18n.tr("wifi.panel.dns") + " (" + I18n.tr("wifi.panel.ipv4") + ")" : I18n.tr("wifi.panel.dns") + " (" + I18n.tr("wifi.panel.ipv6") + ")")
onExited: TooltipService.hide()
onClicked: {
root.ipVersion = root.ipVersion === 4 ? 6 : 4;
TooltipService.show(parent, root.ipVersion === 4 ? I18n.tr("wifi.panel.dns") + " (" + I18n.tr("wifi.panel.ipv4") + ")" : I18n.tr("wifi.panel.dns") + " (" + I18n.tr("wifi.panel.ipv6") + ")");
}
}
}
NText {
text: root.ipVersion === 4 ? ((NetworkService.activeEthernetDetails.dns4 || []).join(", ") || "-") : ((NetworkService.activeEthernetDetails.dns6 || []).join(", ") || "-")
pointSize: Style.fontSizeXS
color: Color.mOnSurface
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
wrapMode: ethernetDetailsGrid ? Text.NoWrap : Text.WrapAtWordBoundaryOrAnywhere
elide: ethernetDetailsGrid ? Text.ElideRight : Text.ElideNone
maximumLineCount: ethernetDetailsGrid ? 1 : 6
clip: true
// Click-to-copy Ethernet DNS
MouseArea {
anchors.fill: parent
enabled: root.ipVersion === 4 ? (NetworkService.activeEthernetDetails.dns4 || []).length > 0 : (NetworkService.activeEthernetDetails.dns6 || []).length > 0
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onEntered: TooltipService.show(parent, I18n.tr("tooltips.copy-address"))
onExited: TooltipService.hide()
onClicked: {
const value = root.ipVersion === 4 ? ((NetworkService.activeEthernetDetails.dns4 || []).join(", ") || "") : ((NetworkService.activeEthernetDetails.dns6 || []).join(", ") || "");
if (value.length > 0) {
Quickshell.execDetached(["wl-copy", value]);
ToastService.showNotice(I18n.tr("common.ethernet"), I18n.tr("common.copied-to-clipboard"), "ethernet");
}
}
}
}
}
// --- Item 6: Gateway ---
RowLayout {
Layout.fillWidth: true
Layout.preferredWidth: 1
spacing: Style.marginXS
NIcon {
icon: "router"
pointSize: Style.fontSizeXS
color: Color.mOnSurface
Layout.alignment: Qt.AlignVCenter
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: TooltipService.show(parent, root.ipVersion === 4 ? I18n.tr("common.gateway") + " (" + I18n.tr("wifi.panel.ipv4") + ")" : I18n.tr("common.gateway") + " (" + I18n.tr("wifi.panel.ipv6") + ")")
onExited: TooltipService.hide()
onClicked: {
root.ipVersion = root.ipVersion === 4 ? 6 : 4;
TooltipService.show(parent, root.ipVersion === 4 ? I18n.tr("common.gateway") + " (" + I18n.tr("wifi.panel.ipv4") + ")" : I18n.tr("common.gateway") + " (" + I18n.tr("wifi.panel.ipv6") + ")");
}
}
}
NText {
text: root.ipVersion === 4 ? (NetworkService.activeEthernetDetails.gateway4 || "-") : ((NetworkService.activeEthernetDetails.gateway6 || []).join(", ") || "-")
pointSize: Style.fontSizeXS
color: Color.mOnSurface
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
wrapMode: ethernetDetailsGrid ? Text.NoWrap : Text.WrapAtWordBoundaryOrAnywhere
elide: ethernetDetailsGrid ? Text.ElideRight : Text.ElideNone
maximumLineCount: ethernetDetailsGrid ? 1 : 6
clip: true
// Click-to-copy Ethernet Gateway
MouseArea {
anchors.fill: parent
enabled: root.ipVersion === 4 ? (NetworkService.activeEthernetDetails.gateway4 || "").length > 0 : (NetworkService.activeEthernetDetails.gateway6 || []).length > 0
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onEntered: TooltipService.show(parent, I18n.tr("tooltips.copy-address"))
onExited: TooltipService.hide()
onClicked: {
const value = root.ipVersion === 4 ? (NetworkService.activeEthernetDetails.gateway4 || "") : ((NetworkService.activeEthernetDetails.gateway6 || []).join(", ") || "");
if (value.length > 0) {
Quickshell.execDetached(["wl-copy", value]);
ToastService.showNotice(I18n.tr("common.ethernet"), I18n.tr("common.copied-to-clipboard"), "ethernet");
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}