ported some quickshell stuff from rivendell-hyprdots

This commit is contained in:
Tomas Rivera
2026-03-10 16:22:35 +01:00
parent 4b442dd121
commit b9e3f35abe
80 changed files with 4462 additions and 9 deletions
+70
View File
@@ -0,0 +1,70 @@
// This is how the notification looks
import QtQuick
import QtQuick.Layouts
import Quickshell.Services.Notifications
Item {
id: root
required property Notification notif
implicitWidth: 240
implicitHeight: layout.height
ColumnLayout {
id: layout
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
Image {
id: trumpetTop
Layout.fillWidth: true
Layout.preferredHeight: width * (sourceSize.height / sourceSize.width)
source: "../assets/trumpet-top.png"
smooth: false
}
Rectangle {
id: bannerRect
color: "#3B253F"
Layout.fillWidth: true
implicitHeight: textColumn.height
Layout.leftMargin: (width / trumpetTop.sourceSize.width) * 2 + 3
Layout.rightMargin: (width / trumpetTop.sourceSize.width) * 2 + 3
ColumnLayout {
id: textColumn
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Text {
Layout.maximumWidth: bannerRect.width
text: root.notif.summary + (root.notif.body ? "\n=======" : "")
font.family: "BigBlueTermPlusNerdFont"
wrapMode: Text.Wrap
font.pointSize: 18
font.bold: true
color: "#9292B6"
}
Text {
Layout.maximumWidth: bannerRect.width
text: root.notif.body
font.family: "BigBlueTermPlusNerdFont"
wrapMode: Text.Wrap
font.pointSize: 14
font.bold: false
color: "#9292B6"
}
}
}
}
}
+183
View File
@@ -0,0 +1,183 @@
// This is all the behaviour and animations for the notification
import QtQuick
import Quickshell.Io
import "." as Notifs
Item {
id: root
signal dismissed
required property var notif
property var screen: Qt.size(1920, 1080)
property var lifetime: 5000
enum AnimState {
Returning,
Inert,
Flinging,
Dismissing
}
property var state: Notif.Returning
property var isDragging: false
property var initialX: 200
property var initialY: 100
property var initialR: 45
property var targetX: 0
property var targetY: 0
property var targetR: 0
property var velocityX: 0
property var velocityY: 0
property var velocityR: 0
FrameAnimation {
function dampingVelocity(currentVelocity, delta) {
const spring = 1.0;
const damping = 0.1;
const springForce = spring * delta;
const dampingForce = -damping * currentVelocity;
return currentVelocity + (springForce + dampingForce);
}
running: root.state != Notif.Inert
onTriggered: {
if (root.state == Notif.Returning) {
const deltaX = root.targetX - display.x;
const deltaY = root.targetY - display.y;
const deltaR = root.targetR - display.rotation;
root.velocityX = dampingVelocity(root.velocityX, deltaX);
root.velocityY = dampingVelocity(root.velocityY, deltaY);
root.velocityR = dampingVelocity(root.velocityR, deltaR);
if (Math.abs(root.velocityX) < 0.1 && Math.abs(root.velocityY) < 0.1) {
console.log("inter");
root.state = Notif.Inert;
root.velocityX = 0;
root.velocityY = 0;
root.velocityR = 0;
display.x = root.targetX;
display.y = root.targetY;
display.rotation = root.targetR;
}
if (root.isDragging) {
if (Math.abs(root.velocityX) > 1200 || Math.abs(root.velocityY) > 1200) {
root.state = Notif.Flinging;
}
}
} else if (root.state == Notif.Flinging) {
root.velocityY += 3000 * frameTime;
display.rotation = -root.velocityY * frameTime;
knight.visible = true;
knight.x += root.velocityX * frameTime;
knight.y += root.velocityY * frameTime;
knight.rotation += root.velocityX * 0.2 * frameTime;
if (display.x > display.width || display.y > root.screen.height) {
root.dismissed();
}
} else if (root.state == Notif.Dismissing) {
root.velocityX += frameTime * 20000;
if (display.x > display.width) {
root.dismissed();
}
}
display.x += root.velocityX * frameTime;
display.y += root.velocityY * frameTime;
display.rotation += root.velocityR * frameTime;
}
}
implicitWidth: display.width
implicitHeight: display.height
anchors.fill: display
Notifs.Display {
id: display
notif: root.notif
x: root.initialX
y: root.initialY
rotation: root.initialR
transformOrigin: Item.Right
}
Image {
id: knight
source: "../assets/knight.png"
x: width
width: sourceSize.width * 10
height: sourceSize.height * 10
smooth: false
visible: false
Process {
id: screamCmd
command: ["play", "--no-show-progress", "assets/wilhelm-scream.ogg"]
}
onVisibleChanged: () => {
if (visible) {
screamCmd.startDetached();
}
}
}
MouseArea {
id: mouseArea
anchors.fill: display
acceptedButtons: Qt.LeftButton | Qt.RightButton
enabled: root.state != Notif.Flinging
property var prevMouseX: 0
property var prevMouseY: 0
onPressed: e => {
if (enabled && e.buttons & Qt.LeftButton) {
prevMouseX = e.x;
prevMouseY = e.y;
root.isDragging = true;
root.state = Notif.Returning;
}
}
onReleased: e => {
if (!(e.buttons & Qt.LeftButton)) {
root.isDragging = false;
}
}
onPositionChanged: e => {
if (enabled && root.isDragging) {
root.velocityX = (e.x - prevMouseX) * 200;
root.velocityY = (e.y - prevMouseY) * 200;
prevMouseX = e.x;
prevMouseY = e.y;
}
}
onClicked: e => {
if (enabled && e.button & Qt.RightButton) {
root.state = Notif.Dismissing;
}
}
}
Timer {
id: timer
interval: root.lifetime
repeat: false
running: !mouseArea.containsMouse && root.state == Notif.Inert
onTriggered: () => {
root.state = Notif.Dismissing;
}
}
Process {
id: playSoundCmd
command: ["play", "--no-show-progress", "assets/trumpet.wav"]
}
Component.onCompleted: playSoundCmd.startDetached()
}
+90
View File
@@ -0,0 +1,90 @@
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Wayland
import Quickshell.Services.Notifications
import "."
PanelWindow {
id: root
required property var bar
property list<Notification> notifs
WlrLayershell.namespace: "shell:notifications"
exclusionMode: ExclusionMode.Ignore
color: "transparent"
anchors {
left: true
top: true
bottom: true
right: true
}
NotificationServer {
actionsSupported: true
onNotification: notif => {
notif.tracked = true;
root.notifs = [...root.notifs, notif];
}
}
visible: stack.children.length != 0
mask: Region {
item: stack
}
ListView {
id: stack
model: ScriptModel {
values: [...root.notifs]
}
anchors.right: parent.right
y: root.bar.height
implicitWidth: 240
implicitHeight: children.reduce((h, c) => h + c.height, 0)
interactive: false
spacing: 20
displaced: Transition {
NumberAnimation {
property: "y"
duration: 200
easing.type: Easing.OutCubic
}
}
move: Transition {
NumberAnimation {
property: "y"
duration: 200
easing.type: Easing.OutCubic
}
}
remove: Transition {
NumberAnimation {
property: "y"
duration: 200
easing.type: Easing.OutCubic
}
}
delegate: Notif {
required property Notification modelData
notif: modelData
onDismissed: () => {
modelData.dismiss();
// Remove from list
const index = root.notifs.indexOf(notif);
if (index > -1)
root.notifs.splice(index, 1);
}
}
}
}