forked from Shinonome/dots-hyprland
right sidebar: slightly nicer bottom group tab switch anim
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user