Notifications WIP

This commit is contained in:
Amaro Lopes
2025-10-07 17:11:20 -03:00
parent c66d043ece
commit d9406f2a90
9 changed files with 326 additions and 79 deletions

View File

@@ -9,9 +9,9 @@ Rectangle {
property string monitor: ""
property string icon: " "
property bool audioPipewireActive: Pipewire.defaultAudioSink? true:false
property int volume: audioPipewireActive? Math.round(Pipewire.defaultAudioSink.audio.volume * 100): 30
property var sink: audioPipewireActive? Pipewire.defaultAudioSink : null
property bool audioPipewireActive: Pipewire.defaultAudioSink ? true : false
property var sink: audioPipewireActive ? Pipewire.defaultAudioSink : null
property int volume: audioPipewireActive ? Math.round(sink.audio.volume * 100) : 30
implicitWidth: audioText.implicitWidth * 1.6
implicitHeight: Theme.heightGaps
@@ -20,12 +20,11 @@ Rectangle {
states: [
State {
name: "Mute"
when: audioWidget.volume == 0
when: audioWidget.volume == 0 || audioWidget.sink.audio.muted
PropertyChanges {
audioWidget.icon: " "
}
},
State {
name: "low volume"
@@ -34,7 +33,6 @@ Rectangle {
PropertyChanges {
audioWidget.icon: " "
}
},
State {
name: "high volume"
@@ -43,7 +41,6 @@ Rectangle {
PropertyChanges {
audioWidget.icon: " "
}
}
]
@@ -56,13 +53,13 @@ Rectangle {
audioWidget.volume = Math.round(Pipewire.defaultAudioSink.audio.volume * 100);
}
target: audioWidget.audioPipewireActive? Pipewire.defaultAudioSink.audio: null
target: audioWidget.audioPipewireActive ? Pipewire.defaultAudioSink.audio : null
}
Text {
id: audioText
property string audioTextText: audioWidget.audioPipewireActive? audioWidget.icon + " " + Math.round(Pipewire.defaultAudioSink.audio.volume * 100).toString() + "%" : ""
property string audioTextText: audioWidget.audioPipewireActive ? audioWidget.icon + " " + Math.round(Pipewire.defaultAudioSink.audio.volume * 100).toString() + "%" : ""
anchors.centerIn: parent
text: audioTextText
@@ -81,26 +78,31 @@ Rectangle {
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
hoverEnabled: true
onEntered: {
PopUpHover.start(audioWidget,"audio")
PopUpHover.start(audioWidget, "audio");
}
onExited: {
// PopUpHover.exit()
PopUpHover.exit()
PopUpHover.exit();
}
onClicked: {
onClicked: mouse => {
if (mouse.button === Qt.RightButton) {
parent.sink.audio.muted = !parent.sink.audio.muted;
} else if (mouse.button === Qt.LeftButton) {
audioWidgetProcess.startDetached();
}
onWheel: (wheel) => {
}
onWheel: wheel => {
if (wheel.angleDelta.y > 0) {
if (0)
return ;
return;
Pipewire.defaultAudioSink.audio.volume = (audioWidget.volume + 5) / 100;
} else if (wheel.angleDelta.y < 0) {
if (0)
return ;
return;
Pipewire.defaultAudioSink.audio.volume = (audioWidget.volume - 5) / 100;
}

52
Bar.qml
View File

@@ -5,15 +5,15 @@ PanelWindow {
id: root
property var modelData: null
property var panelMonitor: modelData? modelData.name:"DP-1"
property var panelMonitor: modelData ? modelData.name : "DP-1"
property var barComponentsLeft: []
property var barComponentsCenter: []
property var barComponentsRight: []
screen:modelData
screen: modelData
implicitHeight: Theme.barSize
color: Qt.rgba(0.68, 0.75, 0.88,0)
color: Qt.rgba(0.68, 0.75, 0.88, 0)
anchors {
top: true
@@ -21,31 +21,31 @@ PanelWindow {
right: true
}
BarArea{
anchors{
left:parent.left
verticalCenter:parent.verticalCenter
}
monitor:root.panelMonitor
components:root.barComponentsLeft
}
BarArea{
anchors{
horizontalCenter:parent.horizontalCenter
verticalCenter:parent.verticalCenter
}
monitor:root.panelMonitor
components:root.barComponentsCenter
}
BarArea{
anchors{
right:parent.right
verticalCenter:parent.verticalCenter
BarArea {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
}
monitor: root.panelMonitor
components:root.barComponentsRight
components: root.barComponentsLeft
}
BarArea {
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
monitor: root.panelMonitor
components: root.barComponentsCenter
}
BarArea {
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
}
monitor: root.panelMonitor
components: root.barComponentsRight
}
// Helper function to set monitor property on loaded items
}

View File

@@ -1,11 +1,16 @@
import QtQuick
import Quickshell
import Quickshell.Widgets
import qs.Services
import qs.Common
import qs.Widgets
import Quickshell.Services.Notifications
Item {
id: root
property var monitor: ""
property bool createWindow: false
MarginWrapperManager {
rightMargin: Theme.gaps
@@ -22,19 +27,30 @@ Item {
id: clockText
anchors.centerIn: parent
text: "OPA!"
text: {
NotificationService.notificationsNumber > 0 ? "\udb80\udc9a "+NotificationService.notificationsNumber : "\ueaa2";
}
font.bold: true
font.pixelSize: Theme.pixelSize
font.family: Theme.fontFamily
color: Theme.textColor
}
MouseArea{
MouseArea {
anchors.fill: parent
onClicked: {
console.log(Notifications.tracked)
console.log(NotificationService.currentNotification.image);
root.createWindow = true
}
}
}
LazyLoader {
id: windowLoader
}
active: root.createWindow
component: NotificationWindow {
anchor.item:root
}
}
}

View File

@@ -0,0 +1,66 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.Notifications
import Quickshell.Widgets
import qs.Widgets
Singleton {
id: notificationRoot
readonly property var notificationServer: notificationServer
readonly property var trackedNotifications: notificationServer.trackedNotifications
readonly property var notificationsNumber: notificationServer.trackedNotifications.values.length
property bool shouldShowOsd: false
property var currentNotification: null
NotificationServer {
id: notificationServer
imageSupported: true
}
Connections {
function onNotification(notif) {
if (notif.body == "MediaOngoingActivity") {
notif.dismiss();
return;
}
notif.tracked = true;
notificationRoot.currentNotification = notif;
notificationRoot.shouldShowOsd = true;
notificationTimer.start();
}
target: notificationServer
}
Timer {
id: notificationTimer
interval: 5000
onTriggered: parent.shouldShowOsd = false
}
LazyLoader {
id: popupLoader
active: currentNotification && shouldShowOsd
component: NotificationPopup {
notification: currentNotification
// No signal handler here!
}
onItemChanged: {
if (item) {
item.dismissed.connect(function() {
notificationRoot.shouldShowOsd = false
currentNotification.dismiss()
})
}
}
}
}

View File

@@ -1,28 +0,0 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Services.Notifications
Singleton {
id: notificationsRoot
NotificationServer {
id: nServer
imageSupported: true
}
Connections {
function onNotification(rapazinho) {
console.log(rapazinho.id)
console.log(nServer.trackedNotifications)
}
target: nServer
}
property var tracked: nServer.trackedNotifications
}

View File

@@ -0,0 +1,149 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.Notifications
import Quickshell.Widgets
PanelWindow {
id: notificationRoot
// Since the panel's screen is unset, it will be picked by the compositor
// when the window is created. Most compositors pick the current active monitor.
property bool hasImage: notification?.image ? true : false
property string image: {
if (hasImage) {
return notification.image;
}
if (notification?.appIcon === "") {
return "";
}
return Quickshell.iconPath(notification?.appIcon);
}
property var notification: null
signal dismissed()
anchors.top: true
margins.top: screen.height / 100
exclusiveZone: 0
implicitWidth: 400
implicitHeight: 100
color: "transparent"
// An empty click mask prevents the window from blocking mouse events.
Rectangle {
anchors.fill: parent
topLeftRadius: 100
bottomLeftRadius: 100
topRightRadius: 20
bottomRightRadius: 20
color: "#80000000"
MouseArea{
anchors.fill: parent
onClicked: {
notificationRoot.dismissed()
}
}
RowLayout {
anchors {
fill: parent
}
ClippingRectangle {
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
implicitWidth: 100
implicitHeight: 100
visible: image? true : false
color: "grey"
radius: 100
IconImage {
anchors.centerIn: parent
implicitSize: 100
source: notificationRoot.image
}
}
ColumnLayout {
Layout.leftMargin: 10
Layout.rightMargin: 10
Rectangle {
Layout.fillWidth: true
implicitHeight: 30
radius: 20
color: "#50ffffff"
Rectangle {
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
}
implicitWidth: parent.width
radius: parent.radius
color: "white"
Text {
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
fontSizeMode: Text.Fit
text: notificationRoot.notification.summary
}
}
}
Rectangle {
Layout.fillWidth: true
implicitHeight: 55
radius: 20
Rectangle {
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
}
implicitWidth: parent.width
radius: parent.radius
color: "white"
Text {
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 24
wrapMode: Text.WordWrap
fontSizeMode: Text.Fit
minimumPixelSize: 10
elide: Text.ElideRight
text: notificationRoot.notification.body
}
}
}
}
}
}
}

View File

@@ -0,0 +1,42 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.Notifications
import Quickshell.Widgets
import qs.Services
import qs.Widgets
PopupWindow {
anchor.item:root
anchor.rect.y: parentWindow.height
implicitWidth: 400
implicitHeight: 1000
color: "white"
visible:true
id: notificationRoot
// Since the panel's screen is unset, it will be picked by the compositor
// when the window is created. Most compositors pick the current active monitor.
// An empty click mask prevents the window from blocking mouse events.
Component {
id: contactDelegate
NotificationPopup {
id: myItem
required property string notification
}
}
ListView {
anchors.fill: parent
model: NotificationService.trackedNotifications.values
delegate: contactDelegate
highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
focus: true
}
}

View File

@@ -105,7 +105,7 @@ WrapperMouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
if (parent.hasTopLevel) {
if (parent.hasTopLevel && !parent.workspaceActive) {
PopUpHover.start(workspacesRectangle, "workspace")
}
}

View File

@@ -18,7 +18,7 @@ ShellRoot {
Variants {
model: Quickshell.screens
delegate: Bar{
delegate: Bar {
modelData: item
barComponentsLeft: ["NotificationsWidget.qml"]
barComponentsCenter: ["Workspaces.qml"]