refactor: SplitPaneWithDetails integrated

This commit is contained in:
ATMDA 2025-11-19 19:25:26 -05:00
parent 70ec8cea65
commit 2d26626643
4 changed files with 192 additions and 278 deletions

View file

@ -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
}
}
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 || "") : "";
}
}
}
leftContent: Component {
DeviceList {
session: root.session
}
}
Component {
id: settings
rightDetailsComponent: Component {
Details {
session: root.session
}
}
rightSettingsComponent: Component {
StyledFlickable {
id: settingsFlickable
flickableDirection: Flickable.VerticalFlick
@ -102,12 +54,4 @@ Item {
}
}
}
Component {
id: details
Details {
session: root.session
}
}
}

View file

@ -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
}
}

View file

@ -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
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
rightDetailsComponent: Component {
EthernetDetails {
session: root.session
}
}
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
EthernetSettings {
id: settingsInner
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
EthernetDetails {
anchors.left: parent.left
anchors.right: parent.right
session: root.session
}
}
}
}
}

View file

@ -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 || "") : "";
}
}
rightDetailsComponent: Component {
WirelessDetails {
session: root.session
}
}
InnerBorder {
id: rightBorder
rightSettingsComponent: Component {
StyledFlickable {
flickableDirection: Flickable.VerticalFlick
contentHeight: settingsInner.height
clip: true
leftThickness: Appearance.padding.normal / 2
}
WirelessSettings {
id: settingsInner
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
}
}
}
Component {
id: details
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
}
}
}
}