right sidebar: slightly nicer bottom group tab switch anim

This commit is contained in:
end-4
2025-11-25 13:12:46 +01:00
parent 08739043f6
commit b4920a7cb6
@@ -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;
}
}
}
}