Compare commits

...

4 Commits

Author SHA1 Message Date
8975e4f979 Make empty notification list transparent 2025-11-23 14:36:38 +01:00
ec217df778 Fix toasts 2025-11-23 14:28:49 +01:00
aa4ee099e8 Add inner bar implementation for notifications 2025-11-23 13:59:47 +01:00
7e4b78d77b Use a BarItem for the notification pill 2025-11-23 13:59:47 +01:00
5 changed files with 86 additions and 43 deletions

View File

@@ -570,7 +570,8 @@
"follow_bar": "Follow bar (default)",
"top_center": "Top center",
"top_left": "Top left",
"top_right": "Top right"
"top_right": "Top right",
"bar": "Bar (inline)"
}
},
"osd": {

View File

@@ -9,7 +9,7 @@ import qs.Services.System
import qs.Services.UI
import qs.Widgets
NIconButton {
Item {
id: root
property ShellScreen screen
@@ -33,6 +33,9 @@ NIconButton {
readonly property bool showUnreadBadge: (widgetSettings.showUnreadBadge !== undefined) ? widgetSettings.showUnreadBadge : widgetMetadata.showUnreadBadge
readonly property bool hideWhenZero: (widgetSettings.hideWhenZero !== undefined) ? widgetSettings.hideWhenZero : widgetMetadata.hideWhenZero
implicitWidth: pill.width
implicitHeight: pill.height
function computeUnreadCount() {
var since = NotificationService.lastSeenTs;
var count = 0;
@@ -46,17 +49,6 @@ NIconButton {
return count;
}
baseSize: Style.capsuleHeight
applyUiScale: false
density: Settings.data.bar.density
icon: NotificationService.doNotDisturb ? "bell-off" : "bell"
tooltipText: NotificationService.doNotDisturb ? I18n.tr("tooltips.open-notification-history-disable-dnd") : I18n.tr("tooltips.open-notification-history-enable-dnd")
tooltipDirection: BarService.getTooltipDirection()
colorBg: Style.capsuleColor
colorFg: Color.mOnSurface
colorBorder: Color.transparent
colorBorderHover: Color.transparent
NPopupContextMenu {
id: contextMenu
@@ -94,37 +86,79 @@ NIconButton {
}
}
onClicked: {
var panel = PanelService.getPanel("notificationHistoryPanel", screen);
panel?.toggle(this);
}
BarPill {
id: pill
onRightClicked: {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
const pos = BarService.getContextMenuPosition(root, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(root, pos.x, pos.y);
popupMenuWindow.showContextMenu(contextMenu);
property string currentNotif
Connections {
target: NotificationService.activeList
function onCountChanged() {
// keep current text a bit longer for the animation
if (NotificationService.activeList.count > 0) {
var notif = NotificationService.activeList.get(0)
var summary = notif.summary.trim()
var body = notif.body.trim()
pill.currentNotif = `${summary}: ${body}`.replace(/\n/g, " ")
}
}
}
}
Loader {
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: 2
anchors.topMargin: 1
z: 2
active: showUnreadBadge && (!hideWhenZero || computeUnreadCount() > 0)
sourceComponent: Rectangle {
id: badge
readonly property int count: computeUnreadCount()
height: 8
width: height
radius: height / 2
color: Color.mError
border.color: Color.mSurface
border.width: Style.borderS
visible: count > 0 || !hideWhenZero
Component.onCompleted: {
function dismiss(notificationId) {
if (Settings.data.notifications?.location == "bar") {
NotificationService.dismissActiveNotification(notificationId)
}
}
NotificationService.animateAndRemove.connect(dismiss);
}
screen: root.screen
density: Settings.data.bar.density
oppositeDirection: BarService.getPillDirection(root)
icon: NotificationService.doNotDisturb ? "bell-off" : "bell"
tooltipText: NotificationService.doNotDisturb ? I18n.tr("tooltips.open-notification-history-disable-dnd") : I18n.tr("tooltips.open-notification-history-enable-dnd")
text: currentNotif
forceOpen: Settings.data.notifications?.location == "bar" && NotificationService.activeList.count > 0
// prevent open via mouse over
forceClose: NotificationService.activeList.count == 0
opacity: NotificationService.doNotDisturb || computeUnreadCount() > 0 ? 100 : 0
onClicked: {
var panel = PanelService.getPanel("notificationHistoryPanel", screen);
panel?.toggle(this);
}
onRightClicked: {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
const pos = BarService.getContextMenuPosition(root, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(root, pos.x, pos.y);
popupMenuWindow.showContextMenu(contextMenu);
}
}
Loader {
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: 2
anchors.topMargin: 1
z: 2
active: showUnreadBadge && (!hideWhenZero || computeUnreadCount() > 0)
sourceComponent: Rectangle {
id: badge
readonly property int count: computeUnreadCount()
height: 8
width: height
radius: height / 2
color: Color.mError
border.color: Color.mSurface
border.width: Style.borderS
visible: count > 0 || !hideWhenZero
}
}
}
}

View File

@@ -22,7 +22,7 @@ Variants {
property ListModel notificationModel: NotificationService.activeList
// Always create window (but with 0x0 dimensions when no notifications)
active: true
active: Settings.data.notifications?.location != "bar"
// Keep loader active briefly after last notification to allow animations to complete
Timer {

View File

@@ -74,6 +74,10 @@ ColumnLayout {
{
"key": "bottom_right",
"name": I18n.tr("options.launcher.position.bottom_right")
},
{
"key": "bar",
"name": I18n.tr("options.launcher.position.bar")
}
]
currentKey: Settings.data.notifications.location || "top_right"

View File

@@ -134,7 +134,11 @@ Item {
screen: root.screen
// Parse location setting
readonly property string location: Settings.data.notifications?.location || "top_right"
readonly property string location: {
if (Settings.data.notifications?.location == "bar")
return "top_right"
return Settings.data.notifications?.location || "top_right"
}
readonly property bool isTop: location.startsWith("top")
readonly property bool isBottom: location.startsWith("bottom")
readonly property bool isLeft: location.endsWith("_left")