From b4920a7cb610c026ec8683f73909400f39097340 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 25 Nov 2025 13:12:46 +0100 Subject: [PATCH] right sidebar: slightly nicer bottom group tab switch anim --- .../ii/sidebarRight/BottomWidgetGroup.qml | 197 ++++++++++++------ 1 file changed, 128 insertions(+), 69 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml index 2adb5f503..638e2d56f 100644 --- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml +++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/BottomWidgetGroup.qml @@ -1,3 +1,4 @@ +pragma ComponentBehavior: Bound import qs.modules.common import qs.modules.common.widgets import qs.services @@ -12,32 +13,47 @@ Rectangle { radius: Appearance.rounding.normal color: Appearance.colors.colLayer1 clip: true - implicitHeight: collapsed ? collapsedBottomWidgetGroupRow.implicitHeight : bottomWidgetGroupRow.implicitHeight + implicitHeight: collapsed ? collapsedBottomWidgetGroupRow.implicitHeight : 350 property int selectedTab: Persistent.states.sidebar.bottomGroup.tab + property int previousIndex: -1 property bool collapsed: Persistent.states.sidebar.bottomGroup.collapsed property var tabs: [ - {"type": "calendar", "name": Translation.tr("Calendar"), "icon": "calendar_month", "widget": "calendar/CalendarWidget.qml"}, - {"type": "todo", "name": Translation.tr("To Do"), "icon": "done_outline", "widget": "todo/TodoWidget.qml"}, - {"type": "timer", "name": Translation.tr("Timer"), "icon": "schedule", "widget": "pomodoro/PomodoroWidget.qml"}, + { + "type": "calendar", + "name": Translation.tr("Calendar"), + "icon": "calendar_month", + "widget": "calendar/CalendarWidget.qml" + }, + { + "type": "todo", + "name": Translation.tr("To Do"), + "icon": "done_outline", + "widget": "todo/TodoWidget.qml" + }, + { + "type": "timer", + "name": Translation.tr("Timer"), + "icon": "schedule", + "widget": "pomodoro/PomodoroWidget.qml" + }, ] Behavior on implicitHeight { NumberAnimation { duration: Appearance.animation.elementMove.duration easing.type: Appearance.animation.elementMove.type - easing.bezierCurve: Appearance.animation.elementMove.bezierCurve + easing.bezierCurve: Appearance.animation.elementMove.bezierCurve } } function setCollapsed(state) { - Persistent.states.sidebar.bottomGroup.collapsed = state + Persistent.states.sidebar.bottomGroup.collapsed = state; if (collapsed) { - bottomWidgetGroupRow.opacity = 0 + bottomWidgetGroupRow.opacity = 0; + } else { + collapsedBottomWidgetGroupRow.opacity = 0; } - else { - collapsedBottomWidgetGroupRow.opacity = 0 - } - collapseCleanFadeTimer.start() + collapseCleanFadeTimer.start(); } Timer { @@ -45,18 +61,19 @@ Rectangle { interval: Appearance.animation.elementMove.duration / 2 repeat: false onTriggered: { - if(collapsed) collapsedBottomWidgetGroupRow.opacity = 1 - else bottomWidgetGroupRow.opacity = 1 + if (collapsed) + collapsedBottomWidgetGroupRow.opacity = 1; + else + bottomWidgetGroupRow.opacity = 1; } } - Keys.onPressed: (event) => { - if ((event.key === Qt.Key_PageDown || event.key === Qt.Key_PageUp) - && event.modifiers === Qt.ControlModifier) { + Keys.onPressed: event => { + if ((event.key === Qt.Key_PageDown || event.key === Qt.Key_PageUp) && event.modifiers === Qt.ControlModifier) { if (event.key === Qt.Key_PageDown) { - root.selectedTab = Math.min(root.selectedTab + 1, root.tabs.length - 1) + root.selectedTab = Math.min(root.selectedTab + 1, root.tabs.length - 1); } else if (event.key === Qt.Key_PageUp) { - root.selectedTab = Math.max(root.selectedTab - 1, 0) + root.selectedTab = Math.max(root.selectedTab - 1, 0); } event.accepted = true; } @@ -77,13 +94,13 @@ Rectangle { } spacing: 15 - + CalendarHeaderButton { Layout.margins: 10 Layout.rightMargin: 0 forceCircle: true downAction: () => { - root.setCollapsed(false) + root.setCollapsed(false); } contentItem: MaterialSymbol { text: "keyboard_arrow_up" @@ -94,7 +111,7 @@ Rectangle { } StyledText { - property int remainingTasks: Todo.list.filter(task => !task.done).length; + property int remainingTasks: Todo.list.filter(task => !task.done).length Layout.margins: 10 Layout.leftMargin: 0 // text: `${DateTime.collapsedCalendarFormat} • ${remainingTasks} task${remainingTasks > 1 ? "s" : ""}` @@ -119,10 +136,10 @@ Rectangle { } } - anchors.fill: parent - height: tabStack.height + anchors.fill: parent + // implicitHeight: tabStack.implicitHeight spacing: 10 - + // Navigation rail Item { Layout.fillHeight: true @@ -141,13 +158,15 @@ Rectangle { Repeater { model: root.tabs NavigationRailButton { + required property int index + required property var modelData showToggledHighlight: false toggled: root.selectedTab == index buttonText: modelData.name buttonIcon: modelData.icon onPressed: { - root.selectedTab = index - Persistent.states.sidebar.bottomGroup.tab = index + root.selectedTab = index; + Persistent.states.sidebar.bottomGroup.tab = index; } } } @@ -158,7 +177,7 @@ Rectangle { anchors.top: parent.top forceCircle: true downAction: () => { - root.setCollapsed(true) + root.setCollapsed(true); } contentItem: MaterialSymbol { text: "keyboard_arrow_down" @@ -170,56 +189,96 @@ Rectangle { } // Content area - Loader { - id: tabStack + Item { Layout.fillWidth: true Layout.fillHeight: true - source: root.tabs[root.selectedTab].widget + // implicitHeight: tabStack.implicitHeight - Behavior on source { - id: switchBehavior + Loader { + id: tabStack + anchors.fill: parent + anchors.bottomMargin: -anchors.topMargin - SequentialAnimation { - id: switchAnim - ParallelAnimation { - PropertyAnimation { - target: tabStack.item - properties: "opacity" - to: 0 - duration: Appearance.animation.elementMoveFast.duration - easing.type: Easing.BezierSpline - easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve - } - PropertyAnimation { - target: tabStack.item - properties: "y" - from: 0 - to: 20 - duration: Appearance.animation.elementMoveFast.duration - easing.type: Easing.InExpo - } + Component.onCompleted: { + tabStack.source = root.tabs[root.selectedTab].widget; + } + + Connections { + target: root + function onSelectedTabChanged() { + if (root.currentTab > root.previousIndex) + tabSwitchBehavior.animation.down = true; + else if (root.currentTab < root.previousIndex) + tabSwitchBehavior.animation.down = false; + tabStack.source = root.tabs[root.selectedTab].widget; } - PropertyAction {} // The source change happens here - ParallelAnimation { - PropertyAnimation { - target: tabStack.item - properties: "opacity" - to: 1 - duration: Appearance.animation.elementMoveFast.duration - easing.type: Easing.BezierSpline - easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve - } - PropertyAnimation { - target: tabStack.item - properties: "y" - from: 20 - to: 0 - duration: Appearance.animation.elementMoveFast.duration - easing.type: Easing.OutExpo - } + } + + Behavior on source { + id: tabSwitchBehavior + animation: TabSwitchAnim { + id: upAnim + down: true } } } } } + + component TabSwitchAnim: SequentialAnimation { + id: switchAnim + property bool down: false + // ScriptAction { + // script: { + // switchAnim.down = root.selectedTab > root.previousIndex; + // } + // } + ParallelAnimation { + PropertyAnimation { + target: tabStack + properties: "opacity" + to: 0 + duration: Appearance.animation.elementMoveFast.duration + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve + } + PropertyAnimation { + target: tabStack.anchors + properties: "topMargin" + to: 10 * (switchAnim.down ? -1 : 1) + duration: Appearance.animation.elementMoveFast.duration + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve + } + } + PropertyAction { + target: tabStack + property: "source" + value: root.tabs[root.selectedTab].widget + } // The source change happens here + ParallelAnimation { + PropertyAnimation { + target: tabStack.anchors + properties: "topMargin" + from: 10 * -(switchAnim.down ? -1 : 1) + to: 0 + duration: Appearance.animation.elementMoveFast.duration + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.elementMoveEnter.bezierCurve + } + PropertyAnimation { + target: tabStack + properties: "opacity" + to: 1 + duration: Appearance.animation.elementMoveFast.duration + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animation.elementMoveEnter.bezierCurve + } + } + ScriptAction { + script: { + root.previousIndex = root.selectedTab; + } + } + } }