feat: add notification sound and notification window enhancements. Ready for alpha.NotificationBody needs work
This commit is contained in:
+2
-1
@@ -2,4 +2,5 @@
|
||||
Colors.qml
|
||||
modules/wlogout/scripts/helper.sh
|
||||
config/path/ConfigPath.qml
|
||||
config/path/WallpaperPath.qml
|
||||
config/path/WallpaperPath.qml
|
||||
modules/notification/assets/notification.ogg
|
||||
@@ -105,6 +105,15 @@ download \
|
||||
"$SCRIPT_DIR/modules/jl/assets/correct.svg" \
|
||||
"correct.svg"
|
||||
|
||||
# ----------------------------
|
||||
# Sounds
|
||||
# ----------------------------
|
||||
|
||||
download \
|
||||
"https://raw.githubusercontent.com/akx/Notifications/master/OGG/Chord.ogg" \
|
||||
"$SCRIPT_DIR/modules/notification/assets/notification.ogg" \
|
||||
"notification.ogg"
|
||||
|
||||
# ----------------------------
|
||||
# Nerd Font
|
||||
# ----------------------------
|
||||
|
||||
@@ -7,20 +7,20 @@ import Quickshell.Services.Pipewire
|
||||
Item {
|
||||
id: root
|
||||
|
||||
PwObjectTracker {
|
||||
objects: [ Pipewire.defaultAudioSource ]
|
||||
}
|
||||
|
||||
property var audioSource: Pipewire.defaultAudioSource
|
||||
|
||||
property bool exists: audioSource != null
|
||||
property bool exists: audioSource != null && audioSource.ready
|
||||
property bool mute: audioSource?.audio?.muted ?? false
|
||||
property real volume: Math.round((audioSource?.audio?.volume ?? 0) * 1000) / 10
|
||||
|
||||
property bool volumeChanged: false
|
||||
|
||||
PwObjectTracker {
|
||||
objects: [ root.audioSource ]
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: audioSource?.audio
|
||||
target: root.audioSource?.audio
|
||||
|
||||
function onVolumeChanged() {
|
||||
root.volumeChanged = true;
|
||||
|
||||
@@ -5,18 +5,24 @@ import "../../config"
|
||||
import "./notificationServer"
|
||||
|
||||
PanelWindow {
|
||||
mask: Region {}
|
||||
// mask: Region {}
|
||||
|
||||
id: notificationWindow
|
||||
|
||||
anchors.top: true
|
||||
anchors.left: true
|
||||
|
||||
implicitHeight: screen.height/6
|
||||
implicitWidth: screen.width/6
|
||||
// implicitHeight: screen.height/6
|
||||
implicitHeight: contentHeight+(content.spacing*(notificationListModel.count-1))
|
||||
implicitWidth: contentWidth
|
||||
|
||||
|
||||
color: "transparent"
|
||||
|
||||
ListModel {
|
||||
id: notificationListModel
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: NotificationS
|
||||
|
||||
@@ -25,17 +31,11 @@ PanelWindow {
|
||||
return
|
||||
if (NotificationS.correctMonitor(screen)) {
|
||||
console.log("[Notification]: This notification belongs to me!", screen.x, screen.y)
|
||||
// currentNotifications.push(notification)
|
||||
// currentNotifications = currentNotifications
|
||||
currentNotification = notification
|
||||
currentNotifications = currentNotifications.concat([notification])
|
||||
notificationListModel.append({notificationData: notification})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property var currentNotification: null
|
||||
property var currentNotifications: []
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -44,22 +44,53 @@ PanelWindow {
|
||||
color: "transparent"
|
||||
|
||||
Column {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
spacing: 5
|
||||
spacing: -2
|
||||
|
||||
Repeater {
|
||||
model: currentNotifications
|
||||
id: notificationRepeater
|
||||
model: notificationListModel
|
||||
|
||||
delegate: NotificationBody {
|
||||
required property int index
|
||||
required property var notificationData
|
||||
|
||||
notification: currentNotifications[index]
|
||||
width: notificationWindow.width
|
||||
notification: notificationData
|
||||
|
||||
onDismissed: function(notification) {
|
||||
notificationListModel.remove(index)
|
||||
notification.dismiss()
|
||||
console.log("[Notification]: Dismissed Notification:", notification.appName, notification.id, notification.summary, notification.body)
|
||||
}
|
||||
}
|
||||
onItemAdded: updateContentSize()
|
||||
onItemRemoved: updateContentSize()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property real contentWidth: 0
|
||||
property real contentHeight: 0
|
||||
|
||||
function updateContentSize() {
|
||||
let width = 0
|
||||
let height = 0
|
||||
|
||||
for (let i = 0; i < notificationRepeater.count; ++i) {
|
||||
let item = notificationRepeater.itemAt(i)
|
||||
|
||||
if (item) {
|
||||
width = Math.max(width, item.width)
|
||||
height += item.height
|
||||
}
|
||||
}
|
||||
|
||||
contentWidth = width
|
||||
contentHeight = height
|
||||
console.log("[updateContentSize] contentWidth:", contentWidth, "contentHeight:", contentHeight)
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log(
|
||||
"[Notification]:",
|
||||
|
||||
@@ -6,7 +6,84 @@ Rectangle {
|
||||
id: root
|
||||
|
||||
required property var notification
|
||||
property real duration: 5000 // Expected in milliseconds (e.g., 5000 for 5s)
|
||||
|
||||
signal dismissed(var notification)
|
||||
|
||||
implicitWidth: content.implicitWidth + 2*18
|
||||
implicitHeight: content.implicitHeight + 18 + progressBar.height
|
||||
|
||||
color: Qt.alpha(Colors.primaryContainer, 0.75)
|
||||
border.width: Config.border_width
|
||||
border.color: Colors.primary
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
onClicked: {
|
||||
dismissed(root.notification)
|
||||
}
|
||||
|
||||
Column {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
spacing: 5
|
||||
|
||||
Text {
|
||||
id: appNameText
|
||||
text: root.notification?.id + ": " + (root.notification?.appName ?? "")
|
||||
font.family: Config.font
|
||||
font.pixelSize: 18
|
||||
color: Colors.primary
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Text {
|
||||
id: summaryText
|
||||
text: root.notification?.summary ?? ""
|
||||
font.family: Config.font
|
||||
font.pixelSize: 22
|
||||
color: Colors.primary
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
Text {
|
||||
id: bodyText
|
||||
text: root.notification?.body ?? ""
|
||||
font.family: Config.font
|
||||
font.pixelSize: 16
|
||||
color: Colors.primary
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Timeout progress bar
|
||||
Rectangle {
|
||||
id: progressBar
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
height: 10
|
||||
color: Colors.primary
|
||||
|
||||
property real progress: 1.0
|
||||
width: root.width * progress
|
||||
|
||||
NumberAnimation on progress {
|
||||
id: anim
|
||||
running: root.duration > 0
|
||||
from: 1.0
|
||||
to: 0.0
|
||||
// If your duration property comes in seconds (e.g., 5), change to: (root.duration * 1000)
|
||||
duration: root.duration
|
||||
paused: mouseArea.containsMouse
|
||||
|
||||
onFinished: root.dismissed(root.notification)
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log(
|
||||
@@ -16,54 +93,4 @@ Rectangle {
|
||||
notification.appName
|
||||
)
|
||||
}
|
||||
|
||||
implicitWidth: parent ? parent.width : 300
|
||||
implicitHeight: content.implicitHeight + 20
|
||||
|
||||
color: "transparent"
|
||||
|
||||
border.width: Config.border_width
|
||||
border.color: Colors.primary
|
||||
|
||||
Column {
|
||||
id: content
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
|
||||
spacing: 5
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
|
||||
text: root.notification?.appName ?? ""
|
||||
font.family: Config.font
|
||||
font.pixelSize: 18
|
||||
color: Colors.primary
|
||||
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
|
||||
text: root.notification?.summary ?? ""
|
||||
font.family: Config.font
|
||||
font.pixelSize: 22
|
||||
color: Colors.primary
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
|
||||
text: root.notification?.body ?? ""
|
||||
font.family: Config.font
|
||||
font.pixelSize: 16
|
||||
color: Colors.primary
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,16 @@ pragma Singleton
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Services.Notifications
|
||||
import "../../../config"
|
||||
|
||||
Item {
|
||||
id: notificationServerState
|
||||
|
||||
property var focusedMonitor: null
|
||||
property var newestNotification: null
|
||||
property var trackedNotifications: [] // TODO
|
||||
|
||||
signal notificationReceived(var notification)
|
||||
|
||||
@@ -18,33 +19,69 @@ Item {
|
||||
return (Hyprland.monitorFor(screen) === focusedMonitor)
|
||||
}
|
||||
|
||||
Process {
|
||||
id: notificationSound
|
||||
command: ["pw-play", "--volume", "0.25", Config.configDir + "/modules/notification/assets/notification.ogg"]
|
||||
function play() {
|
||||
if (running)
|
||||
return
|
||||
console.log(
|
||||
"[NotificationSound] Playing:", Config.configDir + "/modules/notification/assets/notification.ogg"
|
||||
)
|
||||
notificationSound.startDetached()
|
||||
}
|
||||
}
|
||||
|
||||
NotificationServer {
|
||||
id: notificationServer
|
||||
onNotification: function(notification) {
|
||||
if(notification.lastGeneration){
|
||||
console.log(
|
||||
"[NotificationServer] Closing Notification:",
|
||||
notification.appName, notification.id, notification.summary, notification.body
|
||||
)
|
||||
notification.dismiss()
|
||||
return
|
||||
}
|
||||
// if(notification.lastGeneration){
|
||||
// console.log(
|
||||
// "[NotificationServer] Closing Notification:",
|
||||
// notification.appName, notification.id, notification.summary, notification.body
|
||||
// )
|
||||
// notification.dismiss()
|
||||
// return
|
||||
// }
|
||||
notification.tracked = true
|
||||
console.log(
|
||||
"[NotificationServer] Notification received:",
|
||||
notification.appName, notification.id, notification.summary, notification.body
|
||||
)
|
||||
notificationReceived(notification)
|
||||
|
||||
let timer = notificationTimerComponent.createObject(
|
||||
notificationServerState,
|
||||
{ notification: notification }
|
||||
)
|
||||
|
||||
Hyprland.refreshMonitors()
|
||||
waitTimer.start()
|
||||
timer.start()
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: waitTimer
|
||||
interval: 2000
|
||||
repeat: false
|
||||
onTriggered: focusedMonitor = Hyprland.focusedMonitor
|
||||
Component {
|
||||
id: notificationTimerComponent
|
||||
|
||||
Timer {
|
||||
required property var notification
|
||||
|
||||
interval: 2000
|
||||
repeat: false
|
||||
|
||||
onTriggered: {
|
||||
focusedMonitor = Hyprland.focusedMonitor
|
||||
notificationReceived(notification)
|
||||
if(!notification.lastGeneration){
|
||||
notificationSound.play()
|
||||
}
|
||||
|
||||
// destroy()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
focusedMonitor = Hyprland.focusedMonitor
|
||||
console.log("[NotificationServer]: Component completed")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user