Create Styled things and finish notifications module

This commit is contained in:
Amaro Lopes
2025-10-09 22:32:48 -03:00
parent eddae605d4
commit db1ab727a7
13 changed files with 380 additions and 190 deletions

View File

@@ -8,6 +8,8 @@ Singleton {
readonly property string hyprlandSignature: Quickshell.env("HYPRLAND_INSTANCE_SIGNATURE")
readonly property var focusedMon: Hyprland.focusedMonitor
property var sortedTopLevels: {
if (!ToplevelManager.toplevels || !ToplevelManager.toplevels.values) {
return [];

View File

@@ -5,6 +5,7 @@ import QtQuick
import Quickshell
import Quickshell.Services.Notifications
import qs.Widgets
import qs.Services
Singleton {
id: notificationRoot
@@ -12,8 +13,9 @@ Singleton {
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
property bool notificationsMuted: false
property ListModel globalList: ListModel {}
NotificationServer {
id: notificationServer
@@ -21,54 +23,134 @@ Singleton {
}
Connections {
function onNotification(notif) {
if (notif.body == "MediaOngoingActivity") {
return;
}
if (notif.tracked) {
return;
}
notif.tracked = true;
notificationRoot.currentNotification = notif;
notificationRoot.shouldShowOsd = true;
notificationTimer.start();
}
target: notificationServer
function onNotification(notif) {
if(notif.transient) return;
if (notif.body === "MediaOngoingActivity")
return;
notif.tracked = true;
notificationRoot.addNotification(globalList, notif);
if (notif.lastGeneration)
return;
// Use the refactored helper
notificationRoot.addNotification(notificationList, notif);
}
}
Timer {
id: notificationTimer
ListModel {
id: notificationList
}
/**
* @param {ListModel} model
* @param {var} targetNotif
*/
function removeNotification(model, targetNotif) {
if (!model || typeof model.remove !== "function") {
console.warn("removeNotification(): invalid model");
return;
}
for (let i = 0; i < model.count; i++) {
if (model.get(i).notif === targetNotif) {
model.remove(i);
break;
}
}
}
/**
* @param {ListModel} model
* @param {var} notif
*/
function addNotification(model, notif) {
if (!model || typeof model.append !== "function") {
console.warn("addNotification(): invalid model");
return;
}
// Avoid duplicates
for (let i = 0; i < model.count; i++) {
if (model.get(i).notif === notif)
return;
}
model.append({
notif
});
notif.closed.connect(function (reason) {
removeNotification(model, notif);
});
}
// function notificationDismiss(notif) {
// removeNotification(notificationList, notif);
// removeNotification(globalList, notif);
// notif.dismiss();
// }
function notificationDismiss(notif) {
removeNotification(notificationList, notif);
removeNotification(globalList, notif);
if (notif && typeof notif.dismiss === "function")
notif.dismiss(); // dismiss first
interval: 5000
onTriggered: parent.shouldShowOsd = false
}
LazyLoader {
id: popupLoader
active: notificationRoot.currentNotification && notificationRoot.shouldShowOsd
active: notificationList.count && !notificationRoot.notificationsMuted
component: PanelWindow {
id: notificationWindow
screen: {
Quickshell.screens.filter(screen => screen.name == HyprlandService.focusedMon.name)[0];
}
anchors.top: true
margins.top: screen.height / 100
exclusiveZone: 0
implicitWidth: 400
implicitHeight: 905
implicitHeight: screen.height
color: "transparent"
mask: Region { item: listView }
NotificationWrapper {
id: notificationWrapper
ListView {
id: listView
model: notificationList
implicitWidth: parent.width
implicitHeight: contentHeight
orientation: ListView.Vertical
clip: true
spacing: 5
interactive: false
notification: notificationRoot.currentNotification
implicitWidth: notificationWindow.implicitWidth
delegate: NotificationWrapper {
id: notifWrapper
onDismissed: {
notificationRoot.shouldShowOsd = false;
notificationRoot.currentNotification.dismiss();
required property var modelData
notification: modelData
implicitWidth: listView.width
startTimer: NotificationUrgency.toString(notification?.urgency) === "Critical"? false: true
timerDuration: 5000
onDismissed: {
if (notification && typeof notification.dismiss === "function")
notificationRoot.notificationDismiss(notification);
}
onTimedout: {
notificationRoot.removeNotification(notificationList, notification)
}
}
Component.onCompleted: positionViewAtEnd()
}
}
}

View File

@@ -6,6 +6,7 @@ import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
import qs.Common
import qs.Common.Styled
import qs.Services
Singleton {
@@ -35,18 +36,14 @@ Singleton {
Component {
id: stub
Text {
StyledText {
text: "stub"
font.bold: true
font.pixelSize: Theme.pixelSize
font.family: Theme.fontFamily
color: Theme.textColor
}
}
Component {
id: systray
Text {
StyledText {
text: {
if (!HoverMediator.component?.model)
return "";
@@ -57,35 +54,24 @@ Singleton {
else
return "";
}
font.bold: true
font.pixelSize: Theme.pixelSize
font.family: Theme.fontFamily
color: Theme.textColor
}
}
Component {
id: time
Text {
StyledText {
property string calendar: (HoverMediator.component.calendar) ? HoverMediator.component.calendar : ""
text: calendar
font.bold: true
font.pixelSize: Theme.pixelSize
font.family: Theme.fontFamilyMono
color: Theme.textColor
}
}
Component {
id: audio
Text {
StyledText {
property string sinkDescription: (HoverMediator.component.sink) ? HoverMediator.component.sink.description : ""
text: sinkDescription
font.bold: true
font.pixelSize: Theme.pixelSize
font.family: Theme.fontFamily
color: Theme.textColor
}
}
@@ -114,13 +100,15 @@ Singleton {
}
}
WrapperRectangle {
BackgroundRectangle {
id: wsPopUp
leftMargin: (Theme.gaps * 2)
rightMargin: (Theme.gaps * 2)
topMargin: Theme.gaps
bottomMargin: Theme.gaps
MarginWrapperManager {
leftMargin: (Theme.gaps * 2)
rightMargin: (Theme.gaps * 2)
topMargin: Theme.gaps
bottomMargin: Theme.gaps
}
color: Theme.backgroudColor
radius: 25
opacity: 1