diff options
Diffstat (limited to 'modules/controlcenter/Panes.qml')
| -rw-r--r-- | modules/controlcenter/Panes.qml | 178 |
1 files changed, 154 insertions, 24 deletions
diff --git a/modules/controlcenter/Panes.qml b/modules/controlcenter/Panes.qml index 2548c3d..756d73a 100644 --- a/modules/controlcenter/Panes.qml +++ b/modules/controlcenter/Panes.qml @@ -1,6 +1,11 @@ pragma ComponentBehavior: Bound import "bluetooth" +import "network" +import "audio" +import "appearance" +import "taskbar" +import "launcher" import qs.components import qs.services import qs.config @@ -13,24 +18,68 @@ ClippingRectangle { required property Session session + // Expose initialOpeningComplete so parent can check if opening animation is done + readonly property bool initialOpeningComplete: layout.initialOpeningComplete + color: "transparent" + clip: true + focus: false + activeFocusOnTab: false + + // Clear focus when clicking anywhere in the panes area + MouseArea { + anchors.fill: parent + z: -1 + onPressed: function(mouse) { + root.focus = true; + mouse.accepted = false; + } + } + + // Clear focus when switching panes + Connections { + target: root.session + + function onActiveIndexChanged(): void { + root.focus = true; + } + } ColumnLayout { id: layout spacing: 0 y: -root.session.activeIndex * root.height + clip: true + + property bool animationComplete: true + // Track if initial opening animation has completed + // During initial opening, only the active pane loads to avoid hiccups + property bool initialOpeningComplete: false + + Timer { + id: animationDelayTimer + interval: Appearance.anim.durations.normal + onTriggered: { + layout.animationComplete = true; + } + } + + // Timer to detect when initial opening animation completes + // Uses large duration to cover both normal and detached opening cases + Timer { + id: initialOpeningTimer + interval: Appearance.anim.durations.large + running: true + onTriggered: { + layout.initialOpeningComplete = true; + } + } Pane { index: 0 - sourceComponent: Item { - StyledText { - anchors.centerIn: parent - text: qsTr("Work in progress") - color: Colours.palette.m3outline - font.pointSize: Appearance.font.size.extraLarge - font.weight: 500 - } + sourceComponent: NetworkingPane { + session: root.session } } @@ -43,20 +92,44 @@ ClippingRectangle { Pane { index: 2 - sourceComponent: Item { - StyledText { - anchors.centerIn: parent - text: qsTr("Work in progress") - color: Colours.palette.m3outline - font.pointSize: Appearance.font.size.extraLarge - font.weight: 500 - } + sourceComponent: AudioPane { + session: root.session + } + } + + Pane { + index: 3 + sourceComponent: AppearancePane { + session: root.session + } + } + + Pane { + index: 4 + sourceComponent: TaskbarPane { + session: root.session + } + } + + Pane { + index: 5 + sourceComponent: LauncherPane { + session: root.session } } Behavior on y { Anim {} } + + Connections { + target: root.session + function onActiveIndexChanged(): void { + // Mark animation as incomplete and start delay timer + layout.animationComplete = false; + animationDelayTimer.restart(); + } + } } component Pane: Item { @@ -68,19 +141,76 @@ ClippingRectangle { implicitWidth: root.width implicitHeight: root.height + // Track if this pane has ever been loaded to enable caching + property bool hasBeenLoaded: false + + // Function to compute if this pane should be active + function updateActive(): void { + const diff = Math.abs(root.session.activeIndex - pane.index); + const isActivePane = diff === 0; + let shouldBeActive = false; + + // During initial opening animation, only load the active pane + // This prevents hiccups from multiple panes loading simultaneously + if (!layout.initialOpeningComplete) { + shouldBeActive = isActivePane; + } else { + // After initial opening, allow current and adjacent panes for smooth transitions + if (diff <= 1) { + shouldBeActive = true; + } else if (pane.hasBeenLoaded) { + // For distant panes that have been loaded before, keep them active to preserve cached data + shouldBeActive = true; + } else { + // For new distant panes, wait until animation completes to avoid heavy loading during transition + shouldBeActive = layout.animationComplete; + } + } + + loader.active = shouldBeActive; + } + Loader { id: loader anchors.fill: parent - clip: true + clip: false asynchronous: true - active: { - if (root.session.activeIndex === pane.index) - return true; - - const ly = -layout.y; - const ty = pane.index * root.height; - return ly + root.height > ty && ly < ty + root.height; + active: false + + Component.onCompleted: { + pane.updateActive(); + } + + onActiveChanged: { + // Mark pane as loaded when it becomes active + if (active && !pane.hasBeenLoaded) { + pane.hasBeenLoaded = true; + } + } + + onItemChanged: { + // Mark pane as loaded when item is created + if (item) { + pane.hasBeenLoaded = true; + } + } + } + + Connections { + target: root.session + function onActiveIndexChanged(): void { + pane.updateActive(); + } + } + + Connections { + target: layout + function onInitialOpeningCompleteChanged(): void { + pane.updateActive(); + } + function onAnimationCompleteChanged(): void { + pane.updateActive(); } } } |