From 2d26626643e447b5c9f6f78619e8472bc35ea599 Mon Sep 17 00:00:00 2001 From: ATMDA Date: Wed, 19 Nov 2025 19:25:26 -0500 Subject: refactor: SplitPaneWithDetails integrated --- modules/controlcenter/bluetooth/BtPane.qml | 84 +++---------- .../components/SplitPaneWithDetails.qml | 130 ++++++++++++++++++++ modules/controlcenter/network/EthernetPane.qml | 121 ++++--------------- modules/controlcenter/network/WirelessPane.qml | 131 ++++----------------- 4 files changed, 190 insertions(+), 276 deletions(-) create mode 100644 modules/controlcenter/components/SplitPaneWithDetails.qml (limited to 'modules/controlcenter') diff --git a/modules/controlcenter/bluetooth/BtPane.qml b/modules/controlcenter/bluetooth/BtPane.qml index c20f14b..3cd6ef9 100644 --- a/modules/controlcenter/bluetooth/BtPane.qml +++ b/modules/controlcenter/bluetooth/BtPane.qml @@ -2,87 +2,39 @@ pragma ComponentBehavior: Bound import ".." import "../components" +import qs.components import qs.components.controls -import qs.components.effects import qs.components.containers import qs.config import Quickshell.Widgets import Quickshell.Bluetooth import QtQuick -import QtQuick.Layouts -Item { +SplitPaneWithDetails { id: root required property Session session anchors.fill: parent - SplitPaneLayout { - anchors.fill: parent + activeItem: session.bt.active + paneIdGenerator: function(item) { + return item ? (item.address || "") : ""; + } - leftContent: Component { - DeviceList { - anchors.fill: parent - session: root.session - } + leftContent: Component { + DeviceList { + session: root.session } + } - rightContent: Component { - Item { - id: rightBtPane - - property BluetoothDevice pane: root.session.bt.active - property string paneId: pane ? (pane.address || "") : "" - property Component targetComponent: settings - property Component nextComponent: settings - - function getComponentForPane() { - return pane ? details : settings; - } - - Component.onCompleted: { - targetComponent = getComponentForPane(); - nextComponent = targetComponent; - } - - Loader { - id: rightLoader - - anchors.fill: parent - - asynchronous: true - sourceComponent: rightBtPane.targetComponent - } - - Behavior on paneId { - PaneTransition { - target: rightLoader - propertyActions: [ - PropertyAction { - target: rightBtPane - property: "targetComponent" - value: rightBtPane.nextComponent - } - ] - } - } - - Connections { - target: root.session.bt - function onActiveChanged() { - rightBtPane.pane = root.session.bt.active; - rightBtPane.nextComponent = rightBtPane.getComponentForPane(); - rightBtPane.paneId = pane ? (pane.address || "") : ""; - } - } - } + rightDetailsComponent: Component { + Details { + session: root.session } } - Component { - id: settings - + rightSettingsComponent: Component { StyledFlickable { id: settingsFlickable flickableDirection: Flickable.VerticalFlick @@ -102,12 +54,4 @@ Item { } } } - - Component { - id: details - - Details { - session: root.session - } - } } diff --git a/modules/controlcenter/components/SplitPaneWithDetails.qml b/modules/controlcenter/components/SplitPaneWithDetails.qml new file mode 100644 index 0000000..e139aca --- /dev/null +++ b/modules/controlcenter/components/SplitPaneWithDetails.qml @@ -0,0 +1,130 @@ +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 + +/** + * SplitPaneWithDetails + * + * A reusable component that provides a split-pane layout with a list on the left + * and a details/settings view on the right. The right pane automatically switches + * between details and settings views based on whether an item is selected. + * + * This component eliminates duplication across WirelessPane, EthernetPane, and BtPane + * by providing a standardized pattern for split-pane layouts with transition animations. + * + * Usage: + * ```qml + * SplitPaneWithDetails { + * activeItem: root.session.network.active + * leftContent: Component { + * WirelessList { + * session: root.session + * } + * } + * rightDetailsComponent: Component { + * WirelessDetails { + * session: root.session + * } + * } + * rightSettingsComponent: Component { + * StyledFlickable { + * WirelessSettings { + * session: root.session + * } + * } + * } + * paneIdGenerator: (item) => item ? (item.ssid || item.bssid || "") : "" + * } + * ``` + */ +Item { + id: root + + required property Component leftContent + required property Component rightDetailsComponent + required property Component rightSettingsComponent + + property var activeItem: null + property var paneIdGenerator: function(item) { return item ? String(item) : ""; } + + // Optional: Additional component to overlay on top (e.g., password dialogs) + property Component overlayComponent: null + + SplitPaneLayout { + id: splitLayout + + anchors.fill: parent + + leftContent: root.leftContent + + rightContent: Component { + Item { + id: rightPaneItem + + property var pane: root.activeItem + property string paneId: root.paneIdGenerator(pane) + property Component targetComponent: root.rightSettingsComponent + property Component nextComponent: root.rightSettingsComponent + + function getComponentForPane() { + return pane ? root.rightDetailsComponent : root.rightSettingsComponent; + } + + Component.onCompleted: { + targetComponent = getComponentForPane(); + nextComponent = targetComponent; + } + + Loader { + id: rightLoader + + anchors.fill: parent + + opacity: 1 + scale: 1 + transformOrigin: Item.Center + + clip: false + asynchronous: true + sourceComponent: rightPaneItem.targetComponent + } + + Behavior on paneId { + PaneTransition { + target: rightLoader + propertyActions: [ + PropertyAction { + target: rightPaneItem + property: "targetComponent" + value: rightPaneItem.nextComponent + } + ] + } + } + + onPaneChanged: { + nextComponent = getComponentForPane(); + paneId = root.paneIdGenerator(pane); + } + } + } + } + + // Overlay component (e.g., password dialogs) + Loader { + id: overlayLoader + + anchors.fill: parent + z: 1000 + sourceComponent: root.overlayComponent + active: root.overlayComponent !== null + } +} + diff --git a/modules/controlcenter/network/EthernetPane.qml b/modules/controlcenter/network/EthernetPane.qml index fc979c3..126535a 100644 --- a/modules/controlcenter/network/EthernetPane.qml +++ b/modules/controlcenter/network/EthernetPane.qml @@ -1,131 +1,50 @@ pragma ComponentBehavior: Bound import ".." +import "../components" import qs.components -import qs.components.effects import qs.components.containers import qs.config import Quickshell.Widgets import QtQuick -import QtQuick.Layouts -RowLayout { +SplitPaneWithDetails { 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 + activeItem: session.ethernet.active + paneIdGenerator: function(item) { + return item ? (item.interface || "") : ""; + } + leftContent: Component { 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 + rightDetailsComponent: Component { + EthernetDetails { + session: root.session } } - 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" + rightSettingsComponent: Component { + StyledFlickable { + flickableDirection: Flickable.VerticalFlick + contentHeight: settingsInner.height clip: true - Loader { - id: loader - - property var pane: root.session.ethernet.active - property string paneId: pane ? (pane.interface || "") : "" - property Component targetComponent: settings - property Component nextComponent: settings - - anchors.fill: parent - anchors.margins: Appearance.padding.large * 2 - - opacity: 1 - scale: 1 - transformOrigin: Item.Center - - clip: true - asynchronous: true - sourceComponent: loader.targetComponent - - Component.onCompleted: { - targetComponent = pane ? details : settings; - nextComponent = targetComponent; - } - - Behavior on paneId { - PaneTransition { - target: loader - propertyActions: [ - PropertyAction { - target: loader - property: "targetComponent" - value: loader.nextComponent - } - ] - } - } - - onPaneChanged: { - nextComponent = pane ? details : settings; - paneId = pane ? (pane.interface || "") : ""; - } - } - } - - InnerBorder { - id: rightBorder - - leftThickness: Appearance.padding.normal / 2 - } - - Component { - id: settings - - StyledFlickable { - flickableDirection: Flickable.VerticalFlick - contentHeight: settingsInner.height - clip: true - - EthernetSettings { - id: settingsInner - - anchors.left: parent.left - anchors.right: parent.right - session: root.session - } - } - } - - Component { - id: details + EthernetSettings { + id: settingsInner - EthernetDetails { + anchors.left: parent.left + anchors.right: parent.right session: root.session } } } -} \ No newline at end of file +} diff --git a/modules/controlcenter/network/WirelessPane.qml b/modules/controlcenter/network/WirelessPane.qml index 0c8f0ae..109d416 100644 --- a/modules/controlcenter/network/WirelessPane.qml +++ b/modules/controlcenter/network/WirelessPane.qml @@ -1,136 +1,57 @@ pragma ComponentBehavior: Bound import ".." +import "../components" import qs.components -import qs.components.effects import qs.components.containers import qs.config import Quickshell.Widgets import QtQuick -import QtQuick.Layouts -RowLayout { +SplitPaneWithDetails { 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 + activeItem: session.network.active + paneIdGenerator: function(item) { + return item ? (item.ssid || item.bssid || "") : ""; + } + leftContent: Component { WirelessList { - 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.network.active - property string paneId: pane ? (pane.ssid || pane.bssid || "") : "" - property Component targetComponent: settings - property Component nextComponent: settings - - anchors.fill: parent - anchors.margins: Appearance.padding.large * 2 - - opacity: 1 - scale: 1 - transformOrigin: Item.Center - - clip: false - asynchronous: true - sourceComponent: loader.targetComponent - - Component.onCompleted: { - targetComponent = pane ? details : settings; - nextComponent = targetComponent; - } - - Behavior on paneId { - PaneTransition { - target: loader - propertyActions: [ - PropertyAction { - target: loader - property: "targetComponent" - value: loader.nextComponent - } - ] - } - } - - onPaneChanged: { - nextComponent = pane ? details : settings; - paneId = pane ? (pane.ssid || pane.bssid || "") : ""; - } - } - } - - InnerBorder { - id: rightBorder - - leftThickness: Appearance.padding.normal / 2 + rightDetailsComponent: Component { + WirelessDetails { + session: root.session } + } - Component { - id: settings - - StyledFlickable { - flickableDirection: Flickable.VerticalFlick - contentHeight: settingsInner.height - clip: true - - WirelessSettings { - id: settingsInner - - anchors.left: parent.left - anchors.right: parent.right - session: root.session - } - } - } + rightSettingsComponent: Component { + StyledFlickable { + flickableDirection: Flickable.VerticalFlick + contentHeight: settingsInner.height + clip: true - Component { - id: details + WirelessSettings { + id: settingsInner - WirelessDetails { + anchors.left: parent.left + anchors.right: parent.right session: root.session } } } - WirelessPasswordDialog { - anchors.fill: parent - session: root.session - z: 1000 + overlayComponent: Component { + WirelessPasswordDialog { + anchors.fill: parent + session: root.session + } } -} \ No newline at end of file +} -- cgit v1.2.3-freya