From 883eec3e4d5d2fb5ad523c781a78f38d9bdf628c Mon Sep 17 00:00:00 2001 From: Uyanide Date: Fri, 6 Mar 2026 15:26:07 +0100 Subject: [PATCH] qs: better sidebar tab switching animation --- .../quickshell/Components/UDualIconToggle.qml | 121 ++++++++++ .../Sidebar/Modules/ConnectionCard.qml | 212 +++++++++--------- .../Modules/NotificationNoteToggleCard.qml | 156 +++++-------- .../.config/quickshell/Services/IpService.qml | 2 +- .../quickshell/Services/MediaService.qml | 1 - 5 files changed, 276 insertions(+), 216 deletions(-) create mode 100644 config/quickshell/.config/quickshell/Components/UDualIconToggle.qml diff --git a/config/quickshell/.config/quickshell/Components/UDualIconToggle.qml b/config/quickshell/.config/quickshell/Components/UDualIconToggle.qml new file mode 100644 index 0000000..c7bf3d7 --- /dev/null +++ b/config/quickshell/.config/quickshell/Components/UDualIconToggle.qml @@ -0,0 +1,121 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import qs.Components +import qs.Constants + +Rectangle { + id: root + + property string currentValue: "" + property string firstOptionValue: "1" + property string firstOptionIcon: "1" + property string secondOptionValue: "2" + property string secondOptionIcon: "2" + + signal toggled(string value) + + implicitWidth: Style.baseWidgetSize * 2.8 + implicitHeight: Style.baseWidgetSize + radius: Math.min(Style.radiusS, height / 2) + color: Colors.mSurface + + Row { + anchors.fill: parent + spacing: Style.marginS / 2 + + Rectangle { + width: root.currentValue === root.firstOptionValue ? (parent.width - parent.spacing) * 0.65 : (parent.width - parent.spacing) * 0.35 + height: parent.height + radius: Math.min(Style.radiusS, height / 2) + color: root.currentValue === root.firstOptionValue ? Colors.mPrimary : "transparent" + + UIcon { + anchors.centerIn: parent + iconName: root.firstOptionIcon + iconSize: Style.fontSizeL + color: root.currentValue === root.firstOptionValue ? Colors.mOnPrimary : Colors.mOnSurface + + Behavior on color { + ColorAnimation { + duration: 200 + } + + } + + } + + MouseArea { + anchors.fill: parent + onClicked: { + root.toggled(root.firstOptionValue); + } + cursorShape: Qt.PointingHandCursor + } + + Behavior on width { + NumberAnimation { + duration: 250 + easing.type: Easing.OutCubic + } + + } + + Behavior on color { + ColorAnimation { + duration: 200 + } + + } + + } + + Rectangle { + width: root.currentValue === root.secondOptionValue ? (parent.width - parent.spacing) * 0.65 : (parent.width - parent.spacing) * 0.35 + height: parent.height + radius: Math.min(Style.radiusS, height / 2) + color: root.currentValue === root.secondOptionValue ? Colors.mPrimary : "transparent" + + UIcon { + anchors.centerIn: parent + iconName: root.secondOptionIcon + iconSize: Style.fontSizeL + color: root.currentValue === root.secondOptionValue ? Colors.mOnPrimary : Colors.mOnSurface + + Behavior on color { + ColorAnimation { + duration: 200 + } + + } + + } + + MouseArea { + anchors.fill: parent + onClicked: { + root.toggled(root.secondOptionValue); + } + cursorShape: Qt.PointingHandCursor + } + + Behavior on width { + NumberAnimation { + duration: 250 + easing.type: Easing.OutCubic + } + + } + + Behavior on color { + ColorAnimation { + duration: 200 + } + + } + + } + + } + +} diff --git a/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/ConnectionCard.qml b/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/ConnectionCard.qml index 1d4786a..ecb368d 100644 --- a/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/ConnectionCard.qml +++ b/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/ConnectionCard.qml @@ -10,7 +10,7 @@ UBox { property string currentPanel: ShellState.leftSiderbarTab // "bluetooth", "wifi" - implicitHeight: contentLoader.implicitHeight + toggleGroup.implicitHeight + Style.marginXS * 2 + Style.marginS * 2 + implicitHeight: (root.currentPanel === "bluetooth" ? btContentLoader.implicitHeight : wifiContentLoader.implicitHeight) + toggleGroup.implicitHeight + Style.marginXS * 2 + Style.marginS * 2 ColumnLayout { spacing: Style.marginXS @@ -20,122 +20,62 @@ UBox { RowLayout { Layout.fillWidth: true - Rectangle { - // border.color: Colors.mOutline - + UDualIconToggle { id: toggleGroup Layout.preferredWidth: Style.baseWidgetSize * 2.8 Layout.preferredHeight: Style.baseWidgetSize - radius: Math.min(Style.radiusS, height / 2) - color: Colors.mSurface - - Row { - anchors.fill: parent - spacing: Style.marginS / 2 - - Rectangle { - id: btnBluetooth - - width: root.currentPanel === "bluetooth" ? (parent.width - parent.spacing) * 0.65 : (parent.width - parent.spacing) * 0.35 - height: parent.height - radius: Math.min(Style.radiusS, height / 2) - color: root.currentPanel === "bluetooth" ? Colors.mPrimary : "transparent" - - UIcon { - anchors.centerIn: parent - iconName: "bluetooth" - iconSize: Style.fontSizeL - color: root.currentPanel === "bluetooth" ? Colors.mOnPrimary : Colors.mOnSurface - - Behavior on color { - ColorAnimation { - duration: 200 - } - - } - - } - - MouseArea { - anchors.fill: parent - onClicked: ShellState.leftSiderbarTab = "bluetooth" - cursorShape: Qt.PointingHandCursor - } - - Behavior on width { - NumberAnimation { - duration: 250 - easing.type: Easing.OutCubic - } - - } - - Behavior on color { - ColorAnimation { - duration: 200 - } - - } - - } - - Rectangle { - id: btnWifi - - width: root.currentPanel === "wifi" ? (parent.width - parent.spacing) * 0.65 : (parent.width - parent.spacing) * 0.35 - height: parent.height - radius: Math.min(Style.radiusS, height / 2) - color: root.currentPanel === "wifi" ? Colors.mPrimary : "transparent" - - UIcon { - anchors.centerIn: parent - iconName: "wifi" - iconSize: Style.fontSizeL - color: root.currentPanel === "wifi" ? Colors.mOnPrimary : Colors.mOnSurface - - Behavior on color { - ColorAnimation { - duration: 200 - } - - } - - } - - MouseArea { - anchors.fill: parent - onClicked: ShellState.leftSiderbarTab = "wifi" - cursorShape: Qt.PointingHandCursor - } - - Behavior on width { - NumberAnimation { - duration: 250 - easing.type: Easing.OutCubic - } - - } - - Behavior on color { - ColorAnimation { - duration: 200 - } - - } - - } - + firstOptionValue: "bluetooth" + firstOptionIcon: "bluetooth" + secondOptionValue: "wifi" + secondOptionIcon: "wifi" + currentValue: root.currentPanel + onToggled: (value) => { + ShellState.leftSiderbarTab = value; } - } Item { Layout.fillWidth: true } - Loader { - sourceComponent: currentPanel === "bluetooth" ? bluetoothHeaderComponent : wifiHeaderComponent + Item { + implicitWidth: Math.max(btHeaderLoader.implicitWidth, wfHeaderLoader.implicitWidth) + implicitHeight: Math.max(btHeaderLoader.implicitHeight, wfHeaderLoader.implicitHeight) + + Loader { + id: btHeaderLoader + + anchors.right: parent.right + sourceComponent: bluetoothHeaderComponent + opacity: root.currentPanel === "bluetooth" ? 1 : 0 + visible: opacity > 0 + + Behavior on opacity { + NumberAnimation { + duration: 300 + } + + } + + } + + Loader { + id: wfHeaderLoader + + anchors.right: parent.right + sourceComponent: wifiHeaderComponent + opacity: root.currentPanel === "wifi" ? 1 : 0 + visible: opacity > 0 + + Behavior on opacity { + NumberAnimation { + duration: 300 + } + + } + + } Component { id: bluetoothHeaderComponent @@ -201,12 +141,66 @@ UBox { Layout.fillWidth: true } - Loader { - id: contentLoader + Item { + id: contentContainer Layout.fillWidth: true Layout.fillHeight: true - sourceComponent: currentPanel === "bluetooth" ? bluetoothComponent : wifiComponent + clip: true + + Loader { + id: btContentLoader + + width: parent.width + height: parent.height + x: root.currentPanel === "bluetooth" ? 0 : -width + opacity: root.currentPanel === "bluetooth" ? 1 : 0 + sourceComponent: bluetoothComponent + + Behavior on x { + NumberAnimation { + duration: 300 + easing.type: Easing.OutCubic + } + + } + + Behavior on opacity { + NumberAnimation { + duration: 300 + easing.type: Easing.OutCubic + } + + } + + } + + Loader { + id: wifiContentLoader + + width: parent.width + height: parent.height + x: root.currentPanel === "wifi" ? 0 : width + opacity: root.currentPanel === "wifi" ? 1 : 0 + sourceComponent: wifiComponent + + Behavior on x { + NumberAnimation { + duration: 300 + easing.type: Easing.OutCubic + } + + } + + Behavior on opacity { + NumberAnimation { + duration: 300 + easing.type: Easing.OutCubic + } + + } + + } Component { id: bluetoothComponent diff --git a/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/NotificationNoteToggleCard.qml b/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/NotificationNoteToggleCard.qml index 0ec5a78..0e42e0e 100644 --- a/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/NotificationNoteToggleCard.qml +++ b/config/quickshell/.config/quickshell/Modules/Sidebar/Modules/NotificationNoteToggleCard.qml @@ -14,127 +14,73 @@ Item { anchors.fill: parent spacing: Style.marginM - Rectangle { + UDualIconToggle { id: toggleGroup Layout.alignment: Qt.AlignHCenter Layout.preferredWidth: Style.baseWidgetSize * 2.8 Layout.preferredHeight: Style.baseWidgetSize - radius: Math.min(Style.radiusS, height / 2) - color: Colors.mSurface - - Row { - anchors.fill: parent - spacing: Style.marginS / 2 - - Rectangle { - id: btnNotifications - - width: root.currentPanel === "notifications" ? (parent.width - parent.spacing) * 0.65 : (parent.width - parent.spacing) * 0.35 - height: parent.height - radius: Math.min(Style.radiusS, height / 2) - color: root.currentPanel === "notifications" ? Colors.mPrimary : "transparent" - - UIcon { - anchors.centerIn: parent - iconName: "bell" - iconSize: Style.fontSizeL - color: root.currentPanel === "notifications" ? Colors.mOnPrimary : Colors.mOnSurface - - Behavior on color { - ColorAnimation { - duration: 200 - } - - } - - } - - MouseArea { - anchors.fill: parent - onClicked: ShellState.rightSiderbarTab = "notifications" - cursorShape: Qt.PointingHandCursor - } - - Behavior on width { - NumberAnimation { - duration: 250 - easing.type: Easing.OutCubic - } - - } - - Behavior on color { - ColorAnimation { - duration: 200 - } - - } - - } - - Rectangle { - id: btnNotes - - width: root.currentPanel === "notes" ? (parent.width - parent.spacing) * 0.65 : (parent.width - parent.spacing) * 0.35 - height: parent.height - radius: Math.min(Style.radiusS, height / 2) - color: root.currentPanel === "notes" ? Colors.mPrimary : "transparent" - - UIcon { - anchors.centerIn: parent - iconName: "notes" - iconSize: Style.fontSizeL - color: root.currentPanel === "notes" ? Colors.mOnPrimary : Colors.mOnSurface - - Behavior on color { - ColorAnimation { - duration: 200 - } - - } - - } - - MouseArea { - anchors.fill: parent - onClicked: ShellState.rightSiderbarTab = "notes" - cursorShape: Qt.PointingHandCursor - } - - Behavior on width { - NumberAnimation { - duration: 250 - easing.type: Easing.OutCubic - } - - } - - Behavior on color { - ColorAnimation { - duration: 200 - } - - } - - } - + firstOptionValue: "notifications" + firstOptionIcon: "bell" + secondOptionValue: "notes" + secondOptionIcon: "notes" + currentValue: root.currentPanel + onToggled: (value) => { + ShellState.rightSiderbarTab = value; } - } Item { Layout.fillWidth: true Layout.fillHeight: true + clip: true NotificationHistoryCard { - anchors.fill: parent - visible: root.currentPanel === "notifications" + width: parent.width + height: parent.height + x: root.currentPanel === "notifications" ? 0 : -width + opacity: root.currentPanel === "notifications" ? 1 : 0 + + Behavior on x { + NumberAnimation { + duration: 300 + easing.type: Easing.OutCubic + } + + } + + Behavior on opacity { + NumberAnimation { + duration: 300 + easing.type: Easing.OutCubic + } + + } + } NoteCard { - anchors.fill: parent - visible: root.currentPanel === "notes" + width: parent.width + height: parent.height + x: root.currentPanel === "notes" ? 0 : width + opacity: root.currentPanel === "notes" ? 1 : 0 + + Behavior on x { + NumberAnimation { + duration: 300 + easing.type: Easing.OutCubic + } + + } + + Behavior on opacity { + NumberAnimation { + duration: 300 + easing.type: Easing.OutCubic + } + + } + } } diff --git a/config/quickshell/.config/quickshell/Services/IpService.qml b/config/quickshell/.config/quickshell/Services/IpService.qml index 4f489cd..b5b1ce1 100644 --- a/config/quickshell/.config/quickshell/Services/IpService.qml +++ b/config/quickshell/.config/quickshell/Services/IpService.qml @@ -124,7 +124,7 @@ Singleton { Timer { id: fetchIPDebouncer - interval: 1000 + interval: 5000 repeat: false running: false onTriggered: { diff --git a/config/quickshell/.config/quickshell/Services/MediaService.qml b/config/quickshell/.config/quickshell/Services/MediaService.qml index 10dff2b..af8d6c7 100644 --- a/config/quickshell/.config/quickshell/Services/MediaService.qml +++ b/config/quickshell/.config/quickshell/Services/MediaService.qml @@ -186,7 +186,6 @@ Singleton { if (newPlayer !== currentPlayer) { currentPlayer = newPlayer; currentPosition = currentPlayer ? currentPlayer.position : 0; - Logger.d("Media", "Switching player"); } }