summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--components/ConnectionHeader.qml32
-rw-r--r--components/ConnectionInfoSection.qml60
-rw-r--r--components/PropertyRow.qml27
-rw-r--r--components/SectionContainer.qml31
-rw-r--r--components/SectionHeader.qml28
-rw-r--r--components/controls/ToggleRow.qml29
-rw-r--r--modules/controlcenter/ethernet/EthernetDetails.qml238
-rw-r--r--modules/controlcenter/network/Details.qml305
-rw-r--r--plan.plan.md113
9 files changed, 432 insertions, 431 deletions
diff --git a/components/ConnectionHeader.qml b/components/ConnectionHeader.qml
new file mode 100644
index 0000000..3f77fd9
--- /dev/null
+++ b/components/ConnectionHeader.qml
@@ -0,0 +1,32 @@
+import qs.components
+import qs.services
+import qs.config
+import QtQuick
+import QtQuick.Layouts
+
+ColumnLayout {
+ id: root
+
+ required property string icon
+ required property string title
+
+ spacing: Appearance.spacing.normal
+ Layout.alignment: Qt.AlignHCenter
+
+ MaterialIcon {
+ Layout.alignment: Qt.AlignHCenter
+ animate: true
+ text: root.icon
+ font.pointSize: Appearance.font.size.extraLarge * 3
+ font.bold: true
+ }
+
+ StyledText {
+ Layout.alignment: Qt.AlignHCenter
+ animate: true
+ text: root.title
+ font.pointSize: Appearance.font.size.large
+ font.bold: true
+ }
+}
+
diff --git a/components/ConnectionInfoSection.qml b/components/ConnectionInfoSection.qml
new file mode 100644
index 0000000..88c6b3a
--- /dev/null
+++ b/components/ConnectionInfoSection.qml
@@ -0,0 +1,60 @@
+import qs.components
+import qs.components.effects
+import qs.services
+import qs.config
+import QtQuick
+import QtQuick.Layouts
+
+ColumnLayout {
+ id: root
+
+ required property var deviceDetails
+
+ spacing: Appearance.spacing.small / 2
+
+ StyledText {
+ text: qsTr("IP Address")
+ }
+
+ StyledText {
+ text: root.deviceDetails?.ipAddress || qsTr("Not available")
+ color: Colours.palette.m3outline
+ font.pointSize: Appearance.font.size.small
+ }
+
+ StyledText {
+ Layout.topMargin: Appearance.spacing.normal
+ text: qsTr("Subnet Mask")
+ }
+
+ StyledText {
+ text: root.deviceDetails?.subnet || qsTr("Not available")
+ color: Colours.palette.m3outline
+ font.pointSize: Appearance.font.size.small
+ }
+
+ StyledText {
+ Layout.topMargin: Appearance.spacing.normal
+ text: qsTr("Gateway")
+ }
+
+ StyledText {
+ text: root.deviceDetails?.gateway || qsTr("Not available")
+ color: Colours.palette.m3outline
+ font.pointSize: Appearance.font.size.small
+ }
+
+ StyledText {
+ Layout.topMargin: Appearance.spacing.normal
+ text: qsTr("DNS Servers")
+ }
+
+ StyledText {
+ text: (root.deviceDetails && root.deviceDetails.dns && root.deviceDetails.dns.length > 0) ? root.deviceDetails.dns.join(", ") : qsTr("Not available")
+ color: Colours.palette.m3outline
+ font.pointSize: Appearance.font.size.small
+ wrapMode: Text.Wrap
+ Layout.maximumWidth: parent.width
+ }
+}
+
diff --git a/components/PropertyRow.qml b/components/PropertyRow.qml
new file mode 100644
index 0000000..697830a
--- /dev/null
+++ b/components/PropertyRow.qml
@@ -0,0 +1,27 @@
+import qs.components
+import qs.services
+import qs.config
+import QtQuick
+import QtQuick.Layouts
+
+ColumnLayout {
+ id: root
+
+ required property string label
+ required property string value
+ property bool showTopMargin: false
+
+ spacing: Appearance.spacing.small / 2
+
+ StyledText {
+ Layout.topMargin: root.showTopMargin ? Appearance.spacing.normal : 0
+ text: root.label
+ }
+
+ StyledText {
+ text: root.value
+ color: Colours.palette.m3outline
+ font.pointSize: Appearance.font.size.small
+ }
+}
+
diff --git a/components/SectionContainer.qml b/components/SectionContainer.qml
new file mode 100644
index 0000000..d41254b
--- /dev/null
+++ b/components/SectionContainer.qml
@@ -0,0 +1,31 @@
+import qs.components
+import qs.components.effects
+import qs.services
+import qs.config
+import QtQuick
+import QtQuick.Layouts
+
+StyledRect {
+ id: root
+
+ default property alias content: contentColumn.data
+ property real contentSpacing: Appearance.spacing.larger
+
+ Layout.fillWidth: true
+ implicitHeight: contentColumn.implicitHeight + Appearance.padding.large * 2
+
+ radius: Appearance.rounding.normal
+ color: Colours.tPalette.m3surfaceContainer
+
+ ColumnLayout {
+ id: contentColumn
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.margins: Appearance.padding.large
+
+ spacing: root.contentSpacing
+ }
+}
+
diff --git a/components/SectionHeader.qml b/components/SectionHeader.qml
new file mode 100644
index 0000000..897e63a
--- /dev/null
+++ b/components/SectionHeader.qml
@@ -0,0 +1,28 @@
+import qs.components
+import qs.services
+import qs.config
+import QtQuick
+import QtQuick.Layouts
+
+ColumnLayout {
+ id: root
+
+ required property string title
+ property string description: ""
+
+ spacing: 0
+
+ StyledText {
+ Layout.topMargin: Appearance.spacing.large
+ text: root.title
+ font.pointSize: Appearance.font.size.larger
+ font.weight: 500
+ }
+
+ StyledText {
+ visible: root.description !== ""
+ text: root.description
+ color: Colours.palette.m3outline
+ }
+}
+
diff --git a/components/controls/ToggleRow.qml b/components/controls/ToggleRow.qml
new file mode 100644
index 0000000..23dc2a2
--- /dev/null
+++ b/components/controls/ToggleRow.qml
@@ -0,0 +1,29 @@
+import qs.components
+import qs.components.controls
+import qs.services
+import qs.config
+import QtQuick
+import QtQuick.Layouts
+
+RowLayout {
+ id: root
+
+ 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: root.label
+ }
+
+ StyledSwitch {
+ id: toggle
+
+ cLayer: 2
+ }
+}
+
diff --git a/modules/controlcenter/ethernet/EthernetDetails.qml b/modules/controlcenter/ethernet/EthernetDetails.qml
index 1db3db0..a49eb4f 100644
--- a/modules/controlcenter/ethernet/EthernetDetails.qml
+++ b/modules/controlcenter/ethernet/EthernetDetails.qml
@@ -43,229 +43,73 @@ Item {
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
+ ConnectionHeader {
+ icon: "cable"
+ title: root.device?.interface ?? qsTr("Unknown")
}
- StyledText {
- Layout.alignment: Qt.AlignHCenter
- animate: true
- text: root.device?.interface ?? qsTr("Unknown")
- font.pointSize: Appearance.font.size.large
- font.bold: true
+ SectionHeader {
+ title: qsTr("Connection status")
+ description: qsTr("Connection settings for this device")
}
- 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) {
- // Use connection name if available, otherwise use interface
- Network.connectEthernet(root.device?.connection || "", root.device?.interface || "");
- } else {
- if (root.device?.connection) {
- Network.disconnectEthernet(root.device.connection);
- }
+ SectionContainer {
+ ToggleRow {
+ label: qsTr("Connected")
+ checked: root.device?.connected ?? false
+ toggle.onToggled: {
+ if (checked) {
+ // Use connection name if available, otherwise use interface
+ Network.connectEthernet(root.device?.connection || "", root.device?.interface || "");
+ } 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
+ SectionHeader {
+ title: qsTr("Device properties")
+ description: qsTr("Additional information")
}
- 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
+ SectionContainer {
+ contentSpacing: Appearance.spacing.small / 2
- 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")
- }
+ PropertyRow {
+ label: qsTr("Interface")
+ value: root.device?.interface ?? qsTr("Unknown")
+ }
- StyledText {
- text: root.device?.state ?? qsTr("Unknown")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
+ PropertyRow {
+ showTopMargin: true
+ label: qsTr("Connection")
+ value: root.device?.connection || qsTr("Not connected")
}
- }
- StyledText {
- Layout.topMargin: Appearance.spacing.large
- text: qsTr("Connection information")
- font.pointSize: Appearance.font.size.larger
- font.weight: 500
+ PropertyRow {
+ showTopMargin: true
+ label: qsTr("State")
+ value: root.device?.state ?? qsTr("Unknown")
+ }
}
- StyledText {
- text: qsTr("Network connection details")
- color: Colours.palette.m3outline
+ SectionHeader {
+ title: qsTr("Connection information")
+ description: qsTr("Network connection details")
}
- StyledRect {
- Layout.fillWidth: true
- implicitHeight: connectionInfo.implicitHeight + Appearance.padding.large * 2
-
- radius: Appearance.rounding.normal
- color: Colours.tPalette.m3surfaceContainer
-
- ColumnLayout {
- id: connectionInfo
-
- 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("IP Address")
- }
-
- StyledText {
- text: Network.ethernetDeviceDetails?.ipAddress || qsTr("Not available")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
-
- StyledText {
- Layout.topMargin: Appearance.spacing.normal
- text: qsTr("Subnet Mask")
- }
-
- StyledText {
- text: Network.ethernetDeviceDetails?.subnet || qsTr("Not available")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
-
- StyledText {
- Layout.topMargin: Appearance.spacing.normal
- text: qsTr("Gateway")
- }
-
- StyledText {
- text: Network.ethernetDeviceDetails?.gateway || qsTr("Not available")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
-
- StyledText {
- Layout.topMargin: Appearance.spacing.normal
- text: qsTr("DNS Servers")
- }
-
- StyledText {
- text: (Network.ethernetDeviceDetails && Network.ethernetDeviceDetails.dns && Network.ethernetDeviceDetails.dns.length > 0) ? Network.ethernetDeviceDetails.dns.join(", ") : qsTr("Not available")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- wrapMode: Text.Wrap
- Layout.maximumWidth: parent.width
- }
+ SectionContainer {
+ ConnectionInfoSection {
+ deviceDetails: Network.ethernetDeviceDetails
}
}
}
}
- component Toggle: RowLayout {
- required property string label
- property alias checked: toggle.checked
- property alias toggle: toggle
-
- Layout.fillWidth: true
- spacing: Appearance.spacing.normal
-
- StyledText {
- Layout.fillWidth: true
- text: parent.label
- }
-
- StyledSwitch {
- id: toggle
-
- cLayer: 2
- }
- }
}
diff --git a/modules/controlcenter/network/Details.qml b/modules/controlcenter/network/Details.qml
index 31d20bc..a53f62e 100644
--- a/modules/controlcenter/network/Details.qml
+++ b/modules/controlcenter/network/Details.qml
@@ -54,272 +54,109 @@ Item {
anchors.right: parent.right
spacing: Appearance.spacing.normal
- MaterialIcon {
- Layout.alignment: Qt.AlignHCenter
- animate: true
- text: root.network?.isSecure ? "lock" : "wifi"
- font.pointSize: Appearance.font.size.extraLarge * 3
- font.bold: true
+ ConnectionHeader {
+ icon: root.network?.isSecure ? "lock" : "wifi"
+ title: root.network?.ssid ?? qsTr("Unknown")
}
- StyledText {
- Layout.alignment: Qt.AlignHCenter
- animate: true
- text: root.network?.ssid ?? qsTr("Unknown")
- font.pointSize: Appearance.font.size.large
- font.bold: true
+ SectionHeader {
+ title: qsTr("Connection status")
+ description: qsTr("Connection settings for this network")
}
- 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 network")
- color: Colours.palette.m3outline
- }
-
- StyledRect {
- Layout.fillWidth: true
- implicitHeight: networkStatus.implicitHeight + Appearance.padding.large * 2
-
- radius: Appearance.rounding.normal
- color: Colours.tPalette.m3surfaceContainer
-
- ColumnLayout {
- id: networkStatus
-
- 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.network?.active ?? false
- toggle.onToggled: {
- if (checked) {
- // If already connected to a different network, disconnect first
- if (Network.active && Network.active.ssid !== root.network.ssid) {
- Network.disconnectFromNetwork();
- // Wait a moment before connecting to new network
- Qt.callLater(() => {
- connectToNetwork();
- });
- } else {
+ SectionContainer {
+ ToggleRow {
+ label: qsTr("Connected")
+ checked: root.network?.active ?? false
+ toggle.onToggled: {
+ if (checked) {
+ // If already connected to a different network, disconnect first
+ if (Network.active && Network.active.ssid !== root.network.ssid) {
+ Network.disconnectFromNetwork();
+ // Wait a moment before connecting to new network
+ Qt.callLater(() => {
connectToNetwork();
- }
+ });
} else {
- Network.disconnectFromNetwork();
+ connectToNetwork();
}
+ } else {
+ Network.disconnectFromNetwork();
}
+ }
- function connectToNetwork(): void {
- if (root.network.isSecure) {
- // Try connecting without password first (in case it's saved)
- Network.connectToNetworkWithPasswordCheck(
- root.network.ssid,
- root.network.isSecure,
- () => {
- // Callback: connection failed, show password dialog
- root.session.network.showPasswordDialog = true;
- root.session.network.pendingNetwork = root.network;
- }
- );
- } else {
- Network.connectToNetwork(root.network.ssid, "");
- }
+ function connectToNetwork(): void {
+ if (root.network.isSecure) {
+ // Try connecting without password first (in case it's saved)
+ Network.connectToNetworkWithPasswordCheck(
+ root.network.ssid,
+ root.network.isSecure,
+ () => {
+ // Callback: connection failed, show password dialog
+ root.session.network.showPasswordDialog = true;
+ root.session.network.pendingNetwork = root.network;
+ }
+ );
+ } else {
+ Network.connectToNetwork(root.network.ssid, "");
}
}
}
}
- StyledText {
- Layout.topMargin: Appearance.spacing.large
- text: qsTr("Network properties")
- font.pointSize: Appearance.font.size.larger
- font.weight: 500
- }
-
- StyledText {
- text: qsTr("Additional information")
- color: Colours.palette.m3outline
+ SectionHeader {
+ title: qsTr("Network properties")
+ description: qsTr("Additional information")
}
- StyledRect {
- Layout.fillWidth: true
- implicitHeight: networkProps.implicitHeight + Appearance.padding.large * 2
+ SectionContainer {
+ contentSpacing: Appearance.spacing.small / 2
- radius: Appearance.rounding.normal
- color: Colours.tPalette.m3surfaceContainer
-
- ColumnLayout {
- id: networkProps
-
- 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("SSID")
- }
-
- StyledText {
- text: root.network?.ssid ?? qsTr("Unknown")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
-
- StyledText {
- Layout.topMargin: Appearance.spacing.normal
- text: qsTr("BSSID")
- }
-
- StyledText {
- text: root.network?.bssid ?? qsTr("Unknown")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
-
- StyledText {
- Layout.topMargin: Appearance.spacing.normal
- text: qsTr("Signal strength")
- }
-
- StyledText {
- text: root.network ? qsTr("%1%").arg(root.network.strength) : qsTr("N/A")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
-
- StyledText {
- Layout.topMargin: Appearance.spacing.normal
- text: qsTr("Frequency")
- }
+ PropertyRow {
+ label: qsTr("SSID")
+ value: root.network?.ssid ?? qsTr("Unknown")
+ }
- StyledText {
- text: root.network ? qsTr("%1 MHz").arg(root.network.frequency) : qsTr("N/A")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
+ PropertyRow {
+ showTopMargin: true
+ label: qsTr("BSSID")
+ value: root.network?.bssid ?? qsTr("Unknown")
+ }
- StyledText {
- Layout.topMargin: Appearance.spacing.normal
- text: qsTr("Security")
- }
+ PropertyRow {
+ showTopMargin: true
+ label: qsTr("Signal strength")
+ value: root.network ? qsTr("%1%").arg(root.network.strength) : qsTr("N/A")
+ }
- StyledText {
- text: root.network ? (root.network.isSecure ? root.network.security : qsTr("Open")) : qsTr("N/A")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
+ PropertyRow {
+ showTopMargin: true
+ label: qsTr("Frequency")
+ value: root.network ? qsTr("%1 MHz").arg(root.network.frequency) : qsTr("N/A")
}
- }
- StyledText {
- Layout.topMargin: Appearance.spacing.large
- text: qsTr("Connection information")
- font.pointSize: Appearance.font.size.larger
- font.weight: 500
+ PropertyRow {
+ showTopMargin: true
+ label: qsTr("Security")
+ value: root.network ? (root.network.isSecure ? root.network.security : qsTr("Open")) : qsTr("N/A")
+ }
}
- StyledText {
- text: qsTr("Network connection details")
- color: Colours.palette.m3outline
+ SectionHeader {
+ title: qsTr("Connection information")
+ description: qsTr("Network connection details")
}
- StyledRect {
- Layout.fillWidth: true
- implicitHeight: connectionInfo.implicitHeight + Appearance.padding.large * 2
-
- radius: Appearance.rounding.normal
- color: Colours.tPalette.m3surfaceContainer
-
- ColumnLayout {
- id: connectionInfo
-
- 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("IP Address")
- }
-
- StyledText {
- text: Network.wirelessDeviceDetails?.ipAddress || qsTr("Not available")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
-
- StyledText {
- Layout.topMargin: Appearance.spacing.normal
- text: qsTr("Subnet Mask")
- }
-
- StyledText {
- text: Network.wirelessDeviceDetails?.subnet || qsTr("Not available")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
-
- StyledText {
- Layout.topMargin: Appearance.spacing.normal
- text: qsTr("Gateway")
- }
-
- StyledText {
- text: Network.wirelessDeviceDetails?.gateway || qsTr("Not available")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
-
- StyledText {
- Layout.topMargin: Appearance.spacing.normal
- text: qsTr("DNS Servers")
- }
-
- StyledText {
- text: (Network.wirelessDeviceDetails && Network.wirelessDeviceDetails.dns && Network.wirelessDeviceDetails.dns.length > 0) ? Network.wirelessDeviceDetails.dns.join(", ") : qsTr("Not available")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- wrapMode: Text.Wrap
- Layout.maximumWidth: parent.width
- }
+ SectionContainer {
+ ConnectionInfoSection {
+ deviceDetails: Network.wirelessDeviceDetails
}
}
}
}
- component Toggle: RowLayout {
- required property string label
- property alias checked: toggle.checked
- property alias toggle: toggle
-
- Layout.fillWidth: true
- spacing: Appearance.spacing.normal
+}
- StyledText {
- Layout.fillWidth: true
- text: parent.label
- }
- StyledSwitch {
- id: toggle
- cLayer: 2
- }
- }
-}
diff --git a/plan.plan.md b/plan.plan.md
new file mode 100644
index 0000000..5b6f1f2
--- /dev/null
+++ b/plan.plan.md
@@ -0,0 +1,113 @@
+# Refactoring Plan: Control Center Panes
+
+## Overview
+
+After analyzing the last 30 commits, I've identified significant code duplication and opportunities for modularization in the control center panels. This plan focuses on extracting common patterns into reusable components.
+
+## Key Refactoring Opportunities
+
+### 1. Details Component Consolidation
+
+**Files affected:** `modules/controlcenter/network/Details.qml`, `modules/controlcenter/ethernet/EthernetDetails.qml`
+
+**Issue:** Both files share identical structure:
+
+- Header with icon and title
+- Connection status section
+- Properties section
+- Connection information section (IP, subnet, gateway, DNS)
+
+**Solution:** Create `components/ConnectionDetails.qml` that accepts:
+
+- Device/network object
+- Icon name
+- Title property path
+- Details source (wirelessDeviceDetails vs ethernetDeviceDetails)
+
+**Impact:** Reduces ~200 lines of duplication.
+
+### 2. ToggleButton Component Extraction
+
+**Files affected:** `modules/controlcenter/network/NetworkList.qml`, `modules/controlcenter/ethernet/EthernetList.qml`
+
+**Issue:** Both files define identical `ToggleButton` component (lines 228-301 in NetworkList, 170-243 in EthernetList).
+
+**Solution:** Move to `components/controls/ToggleButton.qml` and import in both files.
+
+**Impact:** Eliminates ~70 lines of duplication.
+
+### 3. Switch/SpinBox Row Components
+
+**Files affected:** `modules/controlcenter/appearance/AppearancePane.qml`, `modules/controlcenter/taskbar/TaskbarPane.qml`
+
+**Issue:** Repeated patterns for:
+
+- Switch rows (label + StyledSwitch)
+- SpinBox rows (label + CustomSpinBox)
+- Same layout, spacing, and styling
+
+**Solution:** Create:
+
+- `components/controls/SwitchRow.qml` - label + switch with config save callback
+- `components/controls/SpinBoxRow.qml` - label + spinbox with config save callback
+
+**Impact:** Reduces ~30-40 lines per row instance (20+ instances total).
+
+### 4. Font List Delegate Consolidation
+
+**Files affected:** `modules/controlcenter/appearance/AppearancePane.qml`
+
+**Issue:** Three nearly identical font list implementations (Material, Mono, Sans) with only the property binding differing.
+
+**Solution:** Create `components/FontList.qml` that accepts:
+
+- Current font property
+- Save callback function
+- Title text
+
+**Impact:** Reduces ~150 lines of duplication.
+
+### 5. List Item Selection Pattern
+
+**Files affected:** Multiple list delegates across panes
+
+**Issue:** Repeated pattern for selected item highlighting:
+
+- Color with alpha based on selection
+- Border width/color based on selection
+- StateLayer click handler
+
+**Solution:** Create `components/SelectableListItem.qml` wrapper that handles selection styling.
+
+**Impact:** Reduces ~10-15 lines per list delegate.
+
+## Implementation Order
+
+1. **ConnectionDetails consolidation** (medium impact)
+2. **FontList consolidation** (low-medium impact)
+3. **SelectableListItem pattern** (nice-to-have, lower priority)
+
+## Files to Create
+
+- `components/controls/SelectableListItem.qml`
+- `components/ConnectionDetails.qml`
+- `components/FontList.qml`
+
+## Completed Items
+
+- ✅ `components/controls/CollapsibleSection.qml` - DONE
+- ✅ `components/controls/SwitchRow.qml` - DONE
+- ✅ `components/controls/SpinBoxRow.qml` - DONE
+- ✅ `components/controls/ToggleButton.qml` - DONE
+
+## Estimated Impact
+
+- **Lines removed:** ~400-500 lines of duplicated code (from remaining items)
+- **Maintainability:** Significantly improved - changes to common patterns only need to be made once
+- **Readability:** Panes become more declarative and easier to understand
+- **Testability:** Reusable components can be tested independently
+
+## Completed Refactoring
+
+- **Lines removed so far:** ~1300+ lines of duplicated code
+- **Components created:** CollapsibleSection, SwitchRow, SpinBoxRow, ToggleButton \ No newline at end of file