nosignal-shell/modules/controlcenter/Panes.qml
Robin Seger c588794b20
feat: fullscreen notification & toasts overlay (#1276)
* reworked fullscreen mode as transforming shell

* controlcenter configuring of toasts & notifs

* fix animation on fs switch

* border rounding & shadow animation

* change controlcenter notifications layout

* stay on WlrLayer.Overlay, use Anim

* ci: update action versions

* qmlformat

* format take two

* third time's the charm

* fix: special workspace fullscreen

* fix: bar width border.thickness on non-persistent behaviour

* merge fix

* stop layout shift on close

* last few conventions sorted

* linting

* maximized state to fullscreen

---------

Co-authored-by: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>
2026-03-29 15:22:00 +11:00

182 lines
4.2 KiB
QML

pragma ComponentBehavior: Bound
import "bluetooth"
import "network"
import "audio"
import "appearance"
import "taskbar"
import "notifications"
import "launcher"
import "dashboard"
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
import qs.components
import qs.services
import qs.config
import qs.modules.controlcenter
ClippingRectangle {
id: root
required property Session session
readonly property bool initialOpeningComplete: layout.initialOpeningComplete
color: "transparent"
clip: true
focus: false
activeFocusOnTab: false
MouseArea {
anchors.fill: parent
z: -1
onPressed: function (mouse) {
root.focus = true;
mouse.accepted = false;
}
}
Connections {
function onActiveIndexChanged(): void {
root.focus = true;
}
target: root.session
}
ColumnLayout {
id: layout
property bool animationComplete: true
property bool initialOpeningComplete: false
spacing: 0
y: -root.session.activeIndex * root.height
clip: true
Timer {
id: animationDelayTimer
interval: Appearance.anim.durations.normal
onTriggered: {
layout.animationComplete = true;
}
}
Timer {
id: initialOpeningTimer
interval: Appearance.anim.durations.large
running: true
onTriggered: {
layout.initialOpeningComplete = true;
}
}
Repeater {
model: PaneRegistry.count
Pane {
required property int index
paneIndex: index
componentPath: PaneRegistry.getByIndex(index).component
}
}
Behavior on y {
Anim {}
}
Connections {
function onActiveIndexChanged(): void {
layout.animationComplete = false;
animationDelayTimer.restart();
}
target: root.session
}
}
component Pane: Item {
id: pane
required property int paneIndex
required property string componentPath
property bool hasBeenLoaded: false
function updateActive(): void {
const diff = Math.abs(root.session.activeIndex - pane.paneIndex);
const isActivePane = diff === 0;
let shouldBeActive = false;
if (!layout.initialOpeningComplete) {
shouldBeActive = isActivePane;
} else {
if (diff <= 1) {
shouldBeActive = true;
} else if (pane.hasBeenLoaded) {
shouldBeActive = true;
} else {
shouldBeActive = layout.animationComplete;
}
}
loader.active = shouldBeActive;
}
implicitWidth: root.width
implicitHeight: root.height
Loader {
id: loader
anchors.fill: parent
asynchronous: true
clip: false
active: false
Component.onCompleted: {
Qt.callLater(pane.updateActive);
}
onActiveChanged: {
if (active && !pane.hasBeenLoaded) {
pane.hasBeenLoaded = true;
}
if (active && !item) {
loader.setSource(pane.componentPath, {
"session": root.session
});
}
}
onItemChanged: {
if (item) {
pane.hasBeenLoaded = true;
}
}
}
Connections {
function onActiveIndexChanged(): void {
pane.updateActive();
}
target: root.session
}
Connections {
function onInitialOpeningCompleteChanged(): void {
pane.updateActive();
}
function onAnimationCompleteChanged(): void {
pane.updateActive();
}
target: layout
}
}
}