feat: dashboard
This commit is contained in:
parent
25e6f17c60
commit
6e6db08726
9 changed files with 430 additions and 1 deletions
13
config/DashboardConfig.qml
Normal file
13
config/DashboardConfig.qml
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
readonly property Sizes sizes: Sizes {}
|
||||||
|
|
||||||
|
component Sizes: QtObject {
|
||||||
|
readonly property int tabIndicatorHeight: 3
|
||||||
|
readonly property int tabIndicatorSpacing: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
71
modules/dashboard/Background.qml
Normal file
71
modules/dashboard/Background.qml
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import "root:/config"
|
||||||
|
import "root:/services"
|
||||||
|
|
||||||
|
ShapePath {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property Wrapper wrapper
|
||||||
|
readonly property real rounding: BorderConfig.rounding
|
||||||
|
readonly property bool flatten: wrapper.height < rounding * 2
|
||||||
|
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
||||||
|
|
||||||
|
strokeWidth: -1
|
||||||
|
fillColor: BorderConfig.colour
|
||||||
|
|
||||||
|
PathArc {
|
||||||
|
relativeX: root.rounding
|
||||||
|
relativeY: root.roundingY
|
||||||
|
radiusX: root.rounding
|
||||||
|
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
PathLine {
|
||||||
|
relativeX: 0
|
||||||
|
relativeY: root.wrapper.height - root.roundingY * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
PathArc {
|
||||||
|
relativeX: root.rounding
|
||||||
|
relativeY: root.roundingY
|
||||||
|
radiusX: root.rounding
|
||||||
|
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||||
|
direction: PathArc.Counterclockwise
|
||||||
|
}
|
||||||
|
|
||||||
|
PathLine {
|
||||||
|
relativeX: root.wrapper.width - root.rounding * 4
|
||||||
|
relativeY: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PathArc {
|
||||||
|
relativeX: root.rounding
|
||||||
|
relativeY: -root.roundingY
|
||||||
|
radiusX: root.rounding
|
||||||
|
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||||
|
direction: PathArc.Counterclockwise
|
||||||
|
}
|
||||||
|
|
||||||
|
PathLine {
|
||||||
|
relativeX: 0
|
||||||
|
relativeY: -(root.wrapper.height - root.roundingY * 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
PathArc {
|
||||||
|
relativeX: root.rounding
|
||||||
|
relativeY: -root.roundingY
|
||||||
|
radiusX: root.rounding
|
||||||
|
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on fillColor {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
34
modules/dashboard/Content.qml
Normal file
34
modules/dashboard/Content.qml
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import "root:/widgets"
|
||||||
|
import "root:/services"
|
||||||
|
import "root:/config"
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
|
implicitWidth: 800
|
||||||
|
implicitHeight: 300
|
||||||
|
|
||||||
|
Tabs {
|
||||||
|
id: tabs
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: Appearance.padding.normal
|
||||||
|
anchors.margins: Appearance.padding.large
|
||||||
|
|
||||||
|
currentIndex: view.currentIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
SwipeView {
|
||||||
|
id: view
|
||||||
|
|
||||||
|
currentIndex: tabs.currentIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
226
modules/dashboard/Tabs.qml
Normal file
226
modules/dashboard/Tabs.qml
Normal file
|
|
@ -0,0 +1,226 @@
|
||||||
|
import "root:/widgets"
|
||||||
|
import "root:/services"
|
||||||
|
import "root:/config"
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias currentIndex: bar.currentIndex
|
||||||
|
|
||||||
|
implicitHeight: bar.height + indicator.height + indicator.anchors.topMargin + separator.height
|
||||||
|
|
||||||
|
TabBar {
|
||||||
|
id: bar
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
|
||||||
|
background: null
|
||||||
|
|
||||||
|
Tab {
|
||||||
|
iconName: "dashboard"
|
||||||
|
text: qsTr("Dashboard")
|
||||||
|
}
|
||||||
|
|
||||||
|
Tab {
|
||||||
|
iconName: "queue_music"
|
||||||
|
text: qsTr("Media")
|
||||||
|
}
|
||||||
|
|
||||||
|
Tab {
|
||||||
|
iconName: "speed"
|
||||||
|
text: qsTr("Performance")
|
||||||
|
}
|
||||||
|
|
||||||
|
Tab {
|
||||||
|
iconName: "workspaces"
|
||||||
|
text: qsTr("Workspaces")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
id: indicator
|
||||||
|
|
||||||
|
anchors.top: bar.bottom
|
||||||
|
anchors.topMargin: DashboardConfig.sizes.tabIndicatorSpacing
|
||||||
|
|
||||||
|
implicitWidth: bar.currentItem.implicitWidth
|
||||||
|
implicitHeight: DashboardConfig.sizes.tabIndicatorHeight
|
||||||
|
|
||||||
|
x: {
|
||||||
|
const tab = bar.currentItem;
|
||||||
|
return tab.x + (tab.width - tab.implicitWidth) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
color: Colours.palette.m3primary
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
Behavior on x {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on implicitWidth {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
id: separator
|
||||||
|
|
||||||
|
anchors.top: indicator.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
implicitHeight: 1
|
||||||
|
color: Colours.palette.m3outlineVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
component Tab: TabButton {
|
||||||
|
id: tab
|
||||||
|
|
||||||
|
required property string iconName
|
||||||
|
readonly property bool current: TabBar.tabBar.currentItem === this
|
||||||
|
|
||||||
|
background: null
|
||||||
|
|
||||||
|
contentItem: MouseArea {
|
||||||
|
id: mouse
|
||||||
|
|
||||||
|
implicitWidth: Math.max(icon.width, label.width)
|
||||||
|
implicitHeight: icon.height + label.height
|
||||||
|
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
|
||||||
|
onPressed: ({x,y}) => {
|
||||||
|
tab.TabBar.tabBar.setCurrentIndex(tab.TabBar.index);
|
||||||
|
|
||||||
|
const stateY = stateWrapper.y;
|
||||||
|
rippleAnim.x = x;
|
||||||
|
rippleAnim.y = y - stateY;
|
||||||
|
|
||||||
|
const dist = (ox,oy) => ox*ox + oy*oy
|
||||||
|
const stateEndY = stateY + stateWrapper.height
|
||||||
|
rippleAnim.radius = Math.sqrt(Math.max(dist(0, stateY), dist(0, stateEndY), dist(width, stateY), dist(width, stateEndY)))
|
||||||
|
|
||||||
|
rippleAnim.restart();
|
||||||
|
}
|
||||||
|
onWheel: event => {
|
||||||
|
if (event.angleDelta.y > 0)
|
||||||
|
tab.TabBar.tabBar.incrementCurrentIndex();
|
||||||
|
else if (event.angleDelta.y < 0)
|
||||||
|
tab.TabBar.tabBar.decrementCurrentIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
id: rippleAnim
|
||||||
|
|
||||||
|
property real x
|
||||||
|
property real y
|
||||||
|
property real radius
|
||||||
|
|
||||||
|
PropertyAction {
|
||||||
|
target: ripple
|
||||||
|
property: "x"
|
||||||
|
value: rippleAnim.x
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
target: ripple
|
||||||
|
property: "y"
|
||||||
|
value: rippleAnim.y
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
target: ripple
|
||||||
|
property: "opacity"
|
||||||
|
value: 0.1
|
||||||
|
}
|
||||||
|
ParallelAnimation {
|
||||||
|
Anim {
|
||||||
|
target: ripple
|
||||||
|
properties: "implicitWidth,implicitHeight"
|
||||||
|
from: 0
|
||||||
|
to: rippleAnim.radius * 2
|
||||||
|
duration: Appearance.anim.durations.large
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standardDecel
|
||||||
|
}
|
||||||
|
Anim {
|
||||||
|
target: ripple
|
||||||
|
property: "opacity"
|
||||||
|
to: 0
|
||||||
|
duration: Appearance.anim.durations.large
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standardDecel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClippingRectangle {
|
||||||
|
id: stateWrapper
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
implicitHeight: parent.height + DashboardConfig.sizes.tabIndicatorSpacing * 2
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
id: stateLayer
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
color: tab.current ? Colours.palette.m3primary : Colours.palette.m3onSurface
|
||||||
|
opacity: mouse.pressed ? 0.1 : tab.hovered ? 0.08 : 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
id: ripple
|
||||||
|
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
color: tab.current ? Colours.palette.m3primary : Colours.palette.m3onSurface
|
||||||
|
opacity: 0
|
||||||
|
|
||||||
|
transform: Translate {
|
||||||
|
x: -ripple.width / 2
|
||||||
|
y: -ripple.height / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: icon
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.bottom: label.top
|
||||||
|
|
||||||
|
text: tab.iconName
|
||||||
|
color: tab.current ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant
|
||||||
|
font.pointSize: Appearance.font.size.large
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: label
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
|
text: tab.text
|
||||||
|
color: tab.current ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component Anim: NumberAnimation {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
58
modules/dashboard/Wrapper.qml
Normal file
58
modules/dashboard/Wrapper.qml
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import "root:/config"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
|
visible: height > 0
|
||||||
|
implicitHeight: 0
|
||||||
|
implicitWidth: content.width + BorderConfig.rounding * 2
|
||||||
|
transitions: [
|
||||||
|
Transition {
|
||||||
|
from: ""
|
||||||
|
to: "visible"
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
target: root
|
||||||
|
property: "implicitHeight"
|
||||||
|
duration: Appearance.anim.durations.large
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.emphasizedDecel
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
Transition {
|
||||||
|
from: "visible"
|
||||||
|
to: ""
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
target: root
|
||||||
|
property: "implicitHeight"
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.emphasizedAccel
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Content {
|
||||||
|
id: content
|
||||||
|
|
||||||
|
visibilities: root.visibilities
|
||||||
|
}
|
||||||
|
|
||||||
|
states: State {
|
||||||
|
name: "visible"
|
||||||
|
when: root.visibilities.dashboard
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
root.implicitHeight: content.height
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import "root:/modules/osd" as Osd
|
||||||
import "root:/modules/notifications" as Notifications
|
import "root:/modules/notifications" as Notifications
|
||||||
import "root:/modules/session" as Session
|
import "root:/modules/session" as Session
|
||||||
import "root:/modules/launcher" as Launcher
|
import "root:/modules/launcher" as Launcher
|
||||||
|
import "root:/modules/dashboard" as Dashboard
|
||||||
import QtQuick.Shapes
|
import QtQuick.Shapes
|
||||||
|
|
||||||
Shape {
|
Shape {
|
||||||
|
|
@ -43,4 +44,11 @@ Shape {
|
||||||
startX: (root.width - wrapper.width) / 2
|
startX: (root.width - wrapper.width) / 2
|
||||||
startY: root.height
|
startY: root.height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dashboard.Background {
|
||||||
|
wrapper: panels.dashboard
|
||||||
|
|
||||||
|
startX: (root.width - wrapper.width) / 2
|
||||||
|
startY: 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,10 +89,11 @@ Variants {
|
||||||
PersistentProperties {
|
PersistentProperties {
|
||||||
id: visibilities
|
id: visibilities
|
||||||
|
|
||||||
property bool launcher
|
|
||||||
property bool osd
|
property bool osd
|
||||||
property bool notifications: Notifs.popups.length > 0
|
property bool notifications: Notifs.popups.length > 0
|
||||||
property bool session
|
property bool session
|
||||||
|
property bool launcher
|
||||||
|
property bool dashboard
|
||||||
|
|
||||||
Component.onCompleted: Visibilities.screens[scope.modelData] = this
|
Component.onCompleted: Visibilities.screens[scope.modelData] = this
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,10 @@ MouseArea {
|
||||||
function inRightPanel(panel: Item, x: real, y: real): bool {
|
function inRightPanel(panel: Item, x: real, y: real): bool {
|
||||||
return x > BorderConfig.thickness + panel.x && withinPanelHeight(panel, x, y);
|
return x > BorderConfig.thickness + panel.x && withinPanelHeight(panel, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function inTopPanel(panel: Item, x: real, y: real): bool {
|
||||||
|
const panelX = BorderConfig.thickness + panel.x;
|
||||||
|
return y < BorderConfig.thickness + panel.y + panel.height && x >= panelX && x <= panelX + panel.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
@ -50,6 +54,9 @@ MouseArea {
|
||||||
else if (dragX > SessionConfig.dragThreshold)
|
else if (dragX > SessionConfig.dragThreshold)
|
||||||
root.visibilities.session = false;
|
root.visibilities.session = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const showDashboard = root.inTopPanel(panels.dashboard, x, y);
|
||||||
|
root.visibilities.dashboard = showDashboard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import "root:/modules/osd" as Osd
|
||||||
import "root:/modules/notifications" as Notifications
|
import "root:/modules/notifications" as Notifications
|
||||||
import "root:/modules/session" as Session
|
import "root:/modules/session" as Session
|
||||||
import "root:/modules/launcher" as Launcher
|
import "root:/modules/launcher" as Launcher
|
||||||
|
import "root:/modules/dashboard" as Dashboard
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
|
||||||
|
|
@ -16,6 +17,7 @@ Item {
|
||||||
readonly property Notifications.Wrapper notifications: notifications
|
readonly property Notifications.Wrapper notifications: notifications
|
||||||
readonly property Session.Wrapper session: session
|
readonly property Session.Wrapper session: session
|
||||||
readonly property Launcher.Wrapper launcher: launcher
|
readonly property Launcher.Wrapper launcher: launcher
|
||||||
|
readonly property Dashboard.Wrapper dashboard: dashboard
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: BorderConfig.thickness
|
anchors.margins: BorderConfig.thickness
|
||||||
|
|
@ -58,4 +60,13 @@ Item {
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dashboard.Wrapper {
|
||||||
|
id: dashboard
|
||||||
|
|
||||||
|
visibilities: root.visibilities
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue