feat(network): cleanup and UI polish

This commit is contained in:
Lemmy
2026-03-15 19:49:22 -04:00
parent 44b6ba6c30
commit b9fbe6cd1f
7 changed files with 547 additions and 481 deletions
@@ -8,7 +8,7 @@ import qs.Widgets
NIconButtonHot {
property ShellScreen screen
icon: NetworkService.getIcon()
tooltipText: NetworkService.getStatustxt()
tooltipText: NetworkService.getStatusText()
onClicked: {
var panel = PanelService.getPanel("networkPanel", screen);
panel?.toggle(this);
+428 -434
View File
@@ -384,29 +384,32 @@ SmartPanel {
}
// Ethernet view
ColumnLayout {
NBox {
id: ethernetSection
visible: panelViewMode === "ethernet"
width: parent.width
spacing: Style.marginM
Layout.fillWidth: true
Layout.preferredHeight: ethernetColumn.implicitHeight + Style.margin2M
// Section label
NText {
text: I18n.tr("wifi.panel.available-interfaces")
pointSize: Style.fontSizeM
color: Color.mOnSurface
}
ColumnLayout {
id: ethernetColumn
anchors.fill: parent
anchors.margins: Style.marginM
spacing: Style.marginM
// Empty state when no Ethernet devices
NBox {
visible: !(NetworkService.ethernetInterfaces && NetworkService.ethernetInterfaces.length > 0)
Layout.fillWidth: true
Layout.preferredHeight: emptyEthColumn.implicitHeight + Style.margin2M
// 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
anchors.fill: parent
anchors.margins: Style.marginM
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 {
@@ -431,165 +434,173 @@ SmartPanel {
Layout.fillHeight: true
}
}
}
// Interfaces list
ColumnLayout {
id: ethIfacesList
visible: NetworkService.ethernetInterfaces && NetworkService.ethernetInterfaces.length > 0
width: parent.width
spacing: Style.marginXS
// 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
Repeater {
model: NetworkService.ethernetInterfaces || []
delegate: NBox {
id: ethItem
HoverHandler {
id: itemHover
}
function getContentColors(defaultColors = [Color.mSurface, Color.mOnSurface]) {
if (modelData.connected) {
// Special alpha for connected item background
let bgAlpha = Math.min(1.15 - Color.panelBackgroundOpacity, 0.75);
return [Qt.alpha(Color.mPrimary, bgAlpha), Color.mOnPrimary];
HoverHandler {
id: itemHover
}
return defaultColors;
}
Layout.fillWidth: true
Layout.leftMargin: Style.marginXS
Layout.rightMargin: Style.marginXS
implicitHeight: ethItemColumn.implicitHeight + Style.margin2M
radius: Style.radiusM
border.width: Style.borderS
border.color: modelData.connected ? Color.mPrimary : Color.mOutline
color: ethItem.getContentColors()[0]
function getContentColors(defaultColors = [Color.mSurface, Color.mOnSurface]) {
if (modelData.connected) {
return [Color.mPrimary, Color.mOnPrimary];
}
return defaultColors;
}
ColumnLayout {
id: ethItemColumn
width: parent.width - Style.margin2M
x: Style.marginM
y: Style.marginM
spacing: Style.marginS
Layout.fillWidth: true
Layout.leftMargin: Style.marginXS
Layout.rightMargin: Style.marginXS
implicitHeight: ethItemColumn.implicitHeight + Style.margin2M
radius: Style.radiusM
color: ethItem.getContentColors()[0]
// Main row matching WiFi card style
RowLayout {
id: ethHeaderRow
Layout.fillWidth: true
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).
Rectangle {
id: ethIconBg
Layout.preferredWidth: Style.baseWidgetSize
Layout.preferredHeight: Style.baseWidgetSize
radius: Style.radiusM
color: Color.smartAlpha(Color.mSurfaceVariant)
Layout.alignment: Qt.AlignVCenter
RowLayout {
id: ethHeaderRow
Layout.fillWidth: true
spacing: Style.marginS
NIcon {
anchors.centerIn: parent
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
ColumnLayout {
Layout.fillWidth: true
}
RowLayout {
spacing: Style.marginXS
spacing: 2
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]
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
}
// 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)
}
spacing: Style.marginXS
NText {
visible: SystemStatService.rxSpeed > 0
text: SystemStatService.formatSpeed(SystemStatService.rxSpeed)
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: Qt.alpha(ethItem.getContentColors()[1], Style.opacityHeavy)
elide: Text.ElideNone
color: (!modelData.connected || NetworkService.networkConnectivity === "limited" || NetworkService.networkConnectivity === "portal" || NetworkService.networkConnectivity === "unknown") ? Color.mError : ethItem.getContentColors()[1]
}
Item {
visible: SystemStatService.rxSpeed > 0 && SystemStatService.txSpeed > 0
width: Style.marginXS
height: 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.txSpeed > 0
icon: "arrow-up"
pointSize: Style.fontSizeXXS
color: Qt.alpha(ethItem.getContentColors()[1], Style.opacityHeavy)
}
NIcon {
visible: SystemStatService.rxSpeed > 0
icon: "arrow-down"
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
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 {
visible: itemHover.hovered
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();
}
}
}
// Info button on the right
NIconButton {
visible: itemHover.hovered
icon: "info"
tooltipText: I18n.tr("common.info")
baseSize: Style.baseWidgetSize * 0.8
enabled: true
onClicked: {
// Click handling without anchors in a Layout-managed item
TapHandler {
target: ethHeaderRow
onTapped: {
if (NetworkService.activeEthernetIf === modelData.ifname && ethernetInfoExpanded) {
ethernetInfoExpanded = false;
return;
@@ -602,342 +613,325 @@ SmartPanel {
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.radiusS
border.width: Style.borderS
border.color: Color.mOutline
implicitHeight: ethInfoGrid.implicitHeight + Style.margin2S
clip: true
Layout.topMargin: Style.marginXS
// Inline Ethernet details
Rectangle {
id: ethInfoInline
visible: ethernetInfoExpanded && NetworkService.activeEthernetIf === modelData.ifname
Layout.fillWidth: true
color: Color.mSurfaceVariant
radius: Style.radiusS
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.8
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();
});
// 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.8
onClicked: {
ethernetDetailsGrid = !ethernetDetailsGrid;
Settings.data.network.wifiDetailsViewMode = ethernetDetailsGrid ? "grid" : "list";
}
z: 1
}
// --- 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()
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();
});
}
}
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 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
// --- Item 2: Hardware Address ---
RowLayout {
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
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");
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
// --- Item 3: Link speed ---
RowLayout {
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"));
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
}
}
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 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") + ")");
// --- 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
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");
// 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") + ")");
// --- 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
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");
// 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");
}
}
}
}
@@ -395,10 +395,6 @@ Item {
return defaultColors;
}
function getContentColor(defaultColor = Color.mOnSurface) {
return getContentColors([Color.mSurface, defaultColor])[1];
}
Layout.fillWidth: true
Layout.preferredHeight: deviceColumn.implicitHeight + (Style.marginXL)
radius: Style.radiusM
@@ -418,20 +414,12 @@ Item {
spacing: Style.marginM
Layout.alignment: Qt.AlignVCenter
Rectangle {
id: deviceIconBg
Layout.preferredWidth: Style.baseWidgetSize
Layout.preferredHeight: Style.baseWidgetSize
radius: Style.radiusM
color: Color.smartAlpha(Color.mSurfaceVariant)
Layout.alignment: Qt.AlignVCenter
NIcon {
anchors.centerIn: parent
icon: BluetoothService.getDeviceIcon(modelData)
pointSize: Style.fontSizeXXL
color: device.getContentColors()[1]
}
NIcon {
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
horizontalAlignment: Text.AlignLeft
icon: BluetoothService.getDeviceIcon(modelData)
pointSize: Style.fontSizeXXL
color: device.getContentColors()[1]
}
ColumnLayout {
@@ -462,7 +450,7 @@ Item {
}
visible: text !== ""
pointSize: Style.fontSizeXS
color: device.getContentColor(Color.mOnSurfaceVariant)
color: device.getContentColors([Color.mSurfaceVariant, Color.mOnSurfaceVariant])[1]
}
RowLayout {
@@ -482,7 +470,7 @@ Item {
return b === null ? "-" : (b + "%");
}
pointSize: Style.fontSizeXS
color: device.getContentColor(Color.mOnSurfaceVariant)
color: device.getContentColors([Color.mSurfaceVariant, Color.mOnSurfaceVariant])[1]
}
}
}
@@ -498,7 +486,7 @@ Item {
visible: itemHover.hovered && modelData.connected
icon: "info"
tooltipText: I18n.tr("common.info")
baseSize: Style.baseWidgetSize * 0.8
baseSize: Style.baseWidgetSize * 0.75
onClicked: {
const key = BluetoothService.deviceKey(modelData);
root.expandedDeviceKey = (root.expandedDeviceKey === key) ? "" : key;
@@ -509,15 +497,14 @@ Item {
visible: itemHover.hovered && !root.showOnlyLists && (modelData.paired || modelData.trusted) && !modelData.connected && !isBusy && !modelData.blocked
icon: "trash"
tooltipText: I18n.tr("common.unpair")
baseSize: Style.baseWidgetSize * 0.8
baseSize: Style.baseWidgetSize * 0.75
onClicked: BluetoothService.unpairDevice(modelData)
}
NButton {
id: button
visible: itemHover.hovered && (modelData.state !== BluetoothDeviceState.Connecting)
visible: (modelData.state !== BluetoothDeviceState.Connecting)
enabled: (canConnect || canDisconnect || (root.showOnlyLists ? false : canPair)) && !isBusy
outlined: !button.hovered
fontSize: Style.fontSizeS
backgroundColor: modelData.connected ? Color.mError : Color.mPrimary
text: {
@@ -564,7 +551,7 @@ Item {
anchors.margins: Style.marginS
icon: root.detailsGrid ? "layout-list" : "layout-grid"
tooltipText: root.detailsGrid ? I18n.tr("tooltips.list-view") : I18n.tr("tooltips.grid-view")
baseSize: Style.baseWidgetSize * 0.8
baseSize: Style.baseWidgetSize * 0.75
onClicked: {
root.detailsGrid = !root.detailsGrid;
Settings.data.network.bluetoothDetailsViewMode = root.detailsGrid ? "grid" : "list";
@@ -648,6 +648,10 @@ Item {
NBox {
id: networkItem
HoverHandler {
id: itemHover
}
readonly property bool isBusy: NetworkService.connectingTo === modelData.ssid || NetworkService.disconnectingFrom === modelData.ssid || NetworkService.forgettingNetwork === modelData.ssid
readonly property bool isExpanded: root.infoSsid === modelData.ssid
readonly property bool isEnterprise: NetworkService.isEnterprise(modelData.security)
@@ -815,10 +819,10 @@ Item {
}
NIconButton {
visible: modelData.connected && NetworkService.disconnectingFrom !== modelData.ssid
visible: itemHover.hovered && modelData.connected && NetworkService.disconnectingFrom !== modelData.ssid
icon: "info"
tooltipText: I18n.tr("common.info")
baseSize: Style.baseWidgetSize * 0.8
baseSize: Style.baseWidgetSize * 0.75
colorBg: Color.mSurfaceVariant
colorFg: Color.mOnSurface
colorBorder: "transparent"
@@ -834,10 +838,10 @@ Item {
}
NIconButton {
visible: !root.showOnlyLists && (modelData.existing || modelData.cached) && !modelData.connected && !networkItem.isBusy
visible: itemHover.hovered && !root.showOnlyLists && (modelData.existing || modelData.cached) && !modelData.connected && !networkItem.isBusy
icon: "trash"
tooltipText: I18n.tr("tooltips.forget-network")
baseSize: Style.baseWidgetSize * 0.8
baseSize: Style.baseWidgetSize * 0.75
colorBg: Color.mSurfaceVariant
colorFg: Color.mOnSurface
colorBorder: "transparent"
@@ -899,7 +903,7 @@ Item {
anchors.margins: Style.marginS
icon: root.detailsGrid ? "layout-list" : "layout-grid"
tooltipText: root.detailsGrid ? I18n.tr("tooltips.list-view") : I18n.tr("tooltips.grid-view")
baseSize: Style.baseWidgetSize * 0.8
baseSize: Style.baseWidgetSize * 0.75
onClicked: {
root.detailsGrid = !root.detailsGrid;
Settings.data.network.wifiDetailsViewMode = root.detailsGrid ? "grid" : "list";
@@ -961,7 +965,7 @@ Item {
const value = NetworkService.activeWifiIf || "";
if (value.length > 0) {
Quickshell.execDetached(["wl-copy", value]);
ToastService.showNotice(I18n.tr("common.wifi"), I18n.tr("toast.bluetooth.address-copied"), "wifi");
ToastService.showNotice(I18n.tr("common.wifi"), I18n.tr("common.copied-to-clipboard"), "wifi");
}
}
}
@@ -1049,7 +1053,7 @@ Item {
const value = root.ipVersion === 4 ? (NetworkService.activeWifiDetails.ipv4 || "") : ((NetworkService.activeWifiDetails.ipv6 || []).join(", ") || "");
if (value.length > 0) {
Quickshell.execDetached(["wl-copy", value]);
ToastService.showNotice(I18n.tr("common.wifi"), I18n.tr("toast.bluetooth.address-copied"), "wifi");
ToastService.showNotice(I18n.tr("common.wifi"), I18n.tr("common.copied-to-clipboard"), "wifi");
}
}
}
@@ -1092,7 +1096,7 @@ Item {
const value = root.ipVersion === 4 ? ((NetworkService.activeWifiDetails.dns4 || []).join(", ") || "") : ((NetworkService.activeWifiDetails.dns6 || []).join(", ") || "");
if (value.length > 0) {
Quickshell.execDetached(["wl-copy", value]);
ToastService.showNotice(I18n.tr("common.wifi"), I18n.tr("toast.bluetooth.address-copied"), "wifi");
ToastService.showNotice(I18n.tr("common.wifi"), I18n.tr("common.copied-to-clipboard"), "wifi");
}
}
}
@@ -1135,7 +1139,7 @@ Item {
const value = root.ipVersion === 4 ? (NetworkService.activeWifiDetails.gateway4 || "") : ((NetworkService.activeWifiDetails.gateway6 || []).join(", ") || "");
if (value.length > 0) {
Quickshell.execDetached(["wl-copy", value]);
ToastService.showNotice(I18n.tr("common.wifi"), I18n.tr("toast.bluetooth.address-copied"), "wifi");
ToastService.showNotice(I18n.tr("common.wifi"), I18n.tr("common.copied-to-clipboard"), "wifi");
}
}
}
@@ -1250,7 +1254,7 @@ Item {
NIconButton {
icon: "folder-open"
baseSize: Style.baseWidgetSize * 0.8
baseSize: Style.baseWidgetSize * 0.75
onClicked: caCertPicker.openForInline()
}
}
@@ -1390,7 +1394,7 @@ Item {
NIconButton {
icon: "close"
baseSize: Style.baseWidgetSize * 0.8
baseSize: Style.baseWidgetSize * 0.75
onClicked: root.cancelPassword()
}
}
@@ -1439,7 +1443,7 @@ Item {
NIconButton {
icon: "close"
baseSize: Style.baseWidgetSize * 0.8
baseSize: Style.baseWidgetSize * 0.75
onClicked: root.cancelForget()
}
}