quickshell: fix notification toast as separate Variants popup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
18ccb266c3
commit
5ba4e7d6cf
1 changed files with 151 additions and 132 deletions
|
|
@ -458,6 +458,10 @@ in
|
||||||
import Qt5Compat.GraphicalEffects
|
import Qt5Compat.GraphicalEffects
|
||||||
|
|
||||||
ShellRoot {
|
ShellRoot {
|
||||||
|
id: root
|
||||||
|
property var latestNotification: null
|
||||||
|
signal notificationReceived()
|
||||||
|
|
||||||
NotificationServer {
|
NotificationServer {
|
||||||
id: notifServer
|
id: notifServer
|
||||||
bodySupported: true
|
bodySupported: true
|
||||||
|
|
@ -467,7 +471,8 @@ in
|
||||||
keepOnReload: true
|
keepOnReload: true
|
||||||
onNotification: (notification) => {
|
onNotification: (notification) => {
|
||||||
notification.tracked = true;
|
notification.tracked = true;
|
||||||
notifToast.show(notification);
|
root.latestNotification = notification;
|
||||||
|
root.notificationReceived();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1660,157 +1665,171 @@ in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Notification toast popup
|
}
|
||||||
PopupWindow {
|
}
|
||||||
id: notifToast
|
|
||||||
property var currentNotif: null
|
|
||||||
property bool open: false
|
|
||||||
|
|
||||||
function show(notification) {
|
// Notification toast popup
|
||||||
currentNotif = notification;
|
Variants {
|
||||||
visible = true;
|
model: Quickshell.screens
|
||||||
open = true;
|
|
||||||
_toastTimer.restart();
|
PopupWindow {
|
||||||
|
id: notifToast
|
||||||
|
required property var modelData
|
||||||
|
screen: modelData
|
||||||
|
property var currentNotif: null
|
||||||
|
property bool open: false
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
function onNotificationReceived() {
|
||||||
|
if (notifToast.modelData === Quickshell.screens[0]) {
|
||||||
|
notifToast.show(root.latestNotification);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function dismiss() {
|
function show(notification) {
|
||||||
open = false;
|
currentNotif = notification;
|
||||||
_toastCloseDelay.start();
|
visible = true;
|
||||||
|
open = true;
|
||||||
|
_toastTimer.restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
function dismiss() {
|
||||||
|
open = false;
|
||||||
|
_toastCloseDelay.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
anchor.rect.x: (screen ? screen.width / 2 : 0) - 160
|
||||||
|
anchor.rect.y: 30
|
||||||
|
anchor.edges: Edges.Top | Edges.Left
|
||||||
|
visible: false
|
||||||
|
implicitWidth: 320
|
||||||
|
implicitHeight: toastContent.height + 2
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: _toastTimer
|
||||||
|
interval: 5000
|
||||||
|
onTriggered: notifToast.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: _toastCloseDelay
|
||||||
|
interval: 230
|
||||||
|
onTriggered: { notifToast.visible = false; notifToast.open = false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
onHoveredChanged: {
|
||||||
|
if (hovered) _toastTimer.stop();
|
||||||
|
else _toastTimer.restart();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
anchor.window: bar
|
Rectangle {
|
||||||
anchor.rect.x: bar.width / 2 - 160
|
id: toastContent
|
||||||
anchor.rect.y: bar.height
|
anchors.top: parent.top
|
||||||
anchor.edges: Edges.Top | Edges.Left
|
anchors.topMargin: 2
|
||||||
anchor.gravity: Edges.Bottom | Edges.Right
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
visible: false
|
width: 316
|
||||||
width: 320
|
height: toastCol.height + 16
|
||||||
height: toastContent.height + 2
|
radius: 8
|
||||||
color: "transparent"
|
color: "#E6${c.base00}"
|
||||||
|
clip: true
|
||||||
|
|
||||||
Timer {
|
transform: Translate {
|
||||||
id: _toastTimer
|
y: notifToast.open ? 0 : -(toastContent.height + 10)
|
||||||
interval: 5000
|
Behavior on y {
|
||||||
onTriggered: notifToast.dismiss()
|
NumberAnimation { duration: 220; easing.type: Easing.OutCubic }
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: _toastCloseDelay
|
|
||||||
interval: 230
|
|
||||||
onTriggered: { notifToast.visible = false; notifToast.open = false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
HoverHandler {
|
|
||||||
onHoveredChanged: {
|
|
||||||
if (hovered) _toastTimer.stop();
|
|
||||||
else _toastTimer.restart();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
opacity: notifToast.open ? 1.0 : 0.0
|
||||||
id: toastContent
|
Behavior on opacity {
|
||||||
|
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: toastCol
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: toastDismiss.left
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 2
|
anchors.margins: 8
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
spacing: 2
|
||||||
width: 316
|
|
||||||
height: toastCol.height + 16
|
|
||||||
radius: 8
|
|
||||||
color: "#E6${c.base00}"
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
transform: Translate {
|
Text {
|
||||||
y: notifToast.open ? 0 : -(toastContent.height + 10)
|
width: parent.width
|
||||||
Behavior on y {
|
text: notifToast.currentNotif ? (notifToast.currentNotif.summary || notifToast.currentNotif.appName) : ""
|
||||||
NumberAnimation { duration: 220; easing.type: Easing.OutCubic }
|
color: "#${c.base05}"
|
||||||
}
|
font.family: "FiraMono Nerd Font"
|
||||||
|
font.pixelSize: 12
|
||||||
|
font.weight: Font.Medium
|
||||||
|
elide: Text.ElideRight
|
||||||
}
|
}
|
||||||
|
|
||||||
opacity: notifToast.open ? 1.0 : 0.0
|
Text {
|
||||||
Behavior on opacity {
|
width: parent.width
|
||||||
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
text: notifToast.currentNotif ? (notifToast.currentNotif.body || "") : ""
|
||||||
|
color: "#${c.base04}"
|
||||||
|
font.family: "FiraMono Nerd Font"
|
||||||
|
font.pixelSize: 11
|
||||||
|
elide: Text.ElideRight
|
||||||
|
maximumLineCount: 3
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
visible: text !== ""
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
// Action buttons
|
||||||
id: toastCol
|
Row {
|
||||||
anchors.left: parent.left
|
spacing: 4
|
||||||
anchors.right: toastDismiss.left
|
visible: notifToast.currentNotif && notifToast.currentNotif.actions.length > 0
|
||||||
anchors.top: parent.top
|
Repeater {
|
||||||
anchors.margins: 8
|
model: notifToast.currentNotif ? notifToast.currentNotif.actions : []
|
||||||
spacing: 2
|
Rectangle {
|
||||||
|
required property var modelData
|
||||||
Text {
|
width: toastActionText.width + 12
|
||||||
width: parent.width
|
height: toastActionText.height + 6
|
||||||
text: notifToast.currentNotif ? (notifToast.currentNotif.summary || notifToast.currentNotif.appName) : ""
|
radius: 4
|
||||||
color: "#${c.base05}"
|
color: toastActionMa.containsMouse ? "#${c.base02}" : "#${c.base01}"
|
||||||
font.family: "FiraMono Nerd Font"
|
border.width: 1
|
||||||
font.pixelSize: 12
|
border.color: "#${c.base02}"
|
||||||
font.weight: Font.Medium
|
Text {
|
||||||
elide: Text.ElideRight
|
id: toastActionText
|
||||||
}
|
anchors.centerIn: parent
|
||||||
|
text: modelData.text
|
||||||
Text {
|
color: "#${c.base05}"
|
||||||
width: parent.width
|
font.family: "FiraMono Nerd Font"
|
||||||
text: notifToast.currentNotif ? (notifToast.currentNotif.body || "") : ""
|
font.pixelSize: 10
|
||||||
color: "#${c.base04}"
|
}
|
||||||
font.family: "FiraMono Nerd Font"
|
MouseArea {
|
||||||
font.pixelSize: 11
|
id: toastActionMa
|
||||||
elide: Text.ElideRight
|
anchors.fill: parent
|
||||||
maximumLineCount: 3
|
hoverEnabled: true
|
||||||
wrapMode: Text.Wrap
|
cursorShape: Qt.PointingHandCursor
|
||||||
visible: text !== ""
|
onClicked: { modelData.invoke(); notifToast.dismiss(); }
|
||||||
}
|
|
||||||
|
|
||||||
// Action buttons
|
|
||||||
Row {
|
|
||||||
spacing: 4
|
|
||||||
visible: notifToast.currentNotif && notifToast.currentNotif.actions.length > 0
|
|
||||||
Repeater {
|
|
||||||
model: notifToast.currentNotif ? notifToast.currentNotif.actions : []
|
|
||||||
Rectangle {
|
|
||||||
required property var modelData
|
|
||||||
width: toastActionText.width + 12
|
|
||||||
height: toastActionText.height + 6
|
|
||||||
radius: 4
|
|
||||||
color: toastActionMa.containsMouse ? "#${c.base02}" : "#${c.base01}"
|
|
||||||
border.width: 1
|
|
||||||
border.color: "#${c.base02}"
|
|
||||||
Text {
|
|
||||||
id: toastActionText
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: modelData.text
|
|
||||||
color: "#${c.base05}"
|
|
||||||
font.family: "FiraMono Nerd Font"
|
|
||||||
font.pixelSize: 10
|
|
||||||
}
|
|
||||||
MouseArea {
|
|
||||||
id: toastActionMa
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: { modelData.invoke(); notifToast.dismiss(); }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Dismiss X
|
// Dismiss X
|
||||||
Text {
|
Text {
|
||||||
id: toastDismiss
|
id: toastDismiss
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.margins: 8
|
anchors.margins: 8
|
||||||
text: "\u{f0156}"
|
text: "\u{f0156}"
|
||||||
color: toastDismissMa.containsMouse ? "#${c.base05}" : "#${c.base03}"
|
color: toastDismissMa.containsMouse ? "#${c.base05}" : "#${c.base03}"
|
||||||
font.family: "FiraMono Nerd Font"
|
font.family: "FiraMono Nerd Font"
|
||||||
font.pixelSize: 13
|
font.pixelSize: 13
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: toastDismissMa
|
id: toastDismissMa
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: { notifToast.currentNotif.dismiss(); notifToast.dismiss(); }
|
onClicked: { notifToast.currentNotif.dismiss(); notifToast.dismiss(); }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue