quickshell: move notification toast into bar surface
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
cb3716a1ec
commit
98560bbbef
1 changed files with 254 additions and 252 deletions
|
|
@ -239,7 +239,6 @@ in
|
||||||
|
|
||||||
-- Layer rules: blur behind bar and toasts
|
-- Layer rules: blur behind bar and toasts
|
||||||
hl.layer_rule({ match = { namespace = "quickshell-bar" }, blur = true, ignore_alpha = 0.3 })
|
hl.layer_rule({ match = { namespace = "quickshell-bar" }, blur = true, ignore_alpha = 0.3 })
|
||||||
hl.layer_rule({ match = { namespace = "quickshell-toast" }, blur = true, ignore_alpha = 0.3 })
|
|
||||||
|
|
||||||
-- Startup
|
-- Startup
|
||||||
hl.on("hyprland.start", function()
|
hl.on("hyprland.start", function()
|
||||||
|
|
@ -515,7 +514,6 @@ in
|
||||||
singleton Theme 1.0 Theme.qml
|
singleton Theme 1.0 Theme.qml
|
||||||
singleton Commands 1.0 Commands.qml
|
singleton Commands 1.0 Commands.qml
|
||||||
Bar 1.0 Bar.qml
|
Bar 1.0 Bar.qml
|
||||||
NotificationToast 1.0 NotificationToast.qml
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -590,12 +588,9 @@ in
|
||||||
|
|
||||||
Bar {
|
Bar {
|
||||||
notifServer: _notifServer
|
notifServer: _notifServer
|
||||||
|
shellRoot: root
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationToast {
|
|
||||||
shellRoot: root
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
@ -619,6 +614,7 @@ in
|
||||||
id: bar
|
id: bar
|
||||||
required property var modelData
|
required property var modelData
|
||||||
required property NotificationServer notifServer
|
required property NotificationServer notifServer
|
||||||
|
required property var shellRoot
|
||||||
screen: modelData
|
screen: modelData
|
||||||
WlrLayershell.namespace: "quickshell-bar"
|
WlrLayershell.namespace: "quickshell-bar"
|
||||||
|
|
||||||
|
|
@ -640,6 +636,12 @@ in
|
||||||
width: activeDropdown && activeDropdown.visible ? activeDropdown.width : 0
|
width: activeDropdown && activeDropdown.visible ? activeDropdown.width : 0
|
||||||
height: activeDropdown && activeDropdown.visible ? activeDropdown.height : 0
|
height: activeDropdown && activeDropdown.visible ? activeDropdown.height : 0
|
||||||
}
|
}
|
||||||
|
Region {
|
||||||
|
x: toastItem.visible ? toastItem.x : 0
|
||||||
|
y: toastItem.visible ? toastItem.y : 0
|
||||||
|
width: toastItem.visible ? toastItem.width : 0
|
||||||
|
height: toastItem.visible ? toastItem.height : 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
@ -651,23 +653,35 @@ in
|
||||||
color: Theme.barBg
|
color: Theme.barBg
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bar bottom border — left segment (up to dropdown gap)
|
// The "gap source" for the bar border — dropdown takes priority, then toast
|
||||||
|
property bool hasGap: (activeDropdown && activeDropdown.dropdownHeight > 0)
|
||||||
|
|| (toastItem.visible && _toastRect.height > 0)
|
||||||
|
property real gapLeft: activeDropdown && activeDropdown.dropdownHeight > 0
|
||||||
|
? activeDropdown.x
|
||||||
|
: toastItem.visible && _toastRect.height > 0
|
||||||
|
? toastItem.x : 0
|
||||||
|
property real gapRight: activeDropdown && activeDropdown.dropdownHeight > 0
|
||||||
|
? activeDropdown.x + activeDropdown.width
|
||||||
|
: toastItem.visible && _toastRect.height > 0
|
||||||
|
? toastItem.x + toastItem.width : 0
|
||||||
|
property bool gapAlignRight: activeDropdown ? activeDropdown.alignRight : false
|
||||||
|
|
||||||
|
// Bar bottom border — left segment (up to gap)
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: barBorderLeft
|
id: barBorderLeft
|
||||||
x: 0; y: 30
|
x: 0; y: 30
|
||||||
width: (!activeDropdown || activeDropdown.dropdownHeight <= 0)
|
width: bar.hasGap ? bar.gapLeft : bar.width
|
||||||
? bar.width : activeDropdown.x
|
|
||||||
height: 1
|
height: 1
|
||||||
color: Theme.base03
|
color: Theme.base03
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bar bottom border — right segment (after dropdown gap)
|
// Bar bottom border — right segment (after gap)
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: barBorderRight
|
id: barBorderRight
|
||||||
visible: activeDropdown && activeDropdown.dropdownHeight > 0 && !activeDropdown.alignRight
|
visible: bar.hasGap && !bar.gapAlignRight
|
||||||
x: activeDropdown ? activeDropdown.x + activeDropdown.width : 0
|
x: bar.gapRight
|
||||||
y: 30
|
y: 30
|
||||||
width: activeDropdown ? bar.width - x : 0
|
width: bar.width - x
|
||||||
height: 1
|
height: 1
|
||||||
color: Theme.base03
|
color: Theme.base03
|
||||||
}
|
}
|
||||||
|
|
@ -2186,257 +2200,245 @@ in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
"quickshell/NotificationToast.qml" = {
|
// ── Notification Toast (only on primary screen) ──
|
||||||
onChange = qsRestart;
|
|
||||||
text = ''
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Wayland
|
|
||||||
import Quickshell.Io
|
|
||||||
import QtQuick
|
|
||||||
|
|
||||||
PanelWindow {
|
|
||||||
id: notifToast
|
|
||||||
required property var shellRoot
|
|
||||||
screen: Quickshell.screens[0]
|
|
||||||
property var currentNotif: null
|
|
||||||
property bool open: false
|
|
||||||
|
|
||||||
readonly property var mutedApps: ["discord", "Discord", "Spotify", "spotify", "vlc", "mpv"]
|
|
||||||
|
|
||||||
WlrLayershell.layer: WlrLayer.Overlay
|
|
||||||
WlrLayershell.namespace: "quickshell-toast"
|
|
||||||
exclusionMode: ExclusionMode.Ignore
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: notifSoundProc
|
|
||||||
command: [Commands.notifSound, "-i", "message"]
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: shellRoot
|
|
||||||
function onNotificationReceived() {
|
|
||||||
notifToast.show(shellRoot.latestNotification);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function show(notification) {
|
|
||||||
currentNotif = notification;
|
|
||||||
visible = true;
|
|
||||||
open = true;
|
|
||||||
_toastTimer.restart();
|
|
||||||
if (!mutedApps.includes(notification.appName)) {
|
|
||||||
notifSoundProc.running = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dismiss() {
|
|
||||||
open = false;
|
|
||||||
_toastCloseDelay.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.top: true
|
|
||||||
margins.top: 30
|
|
||||||
visible: false
|
|
||||||
implicitWidth: 320 + 16
|
|
||||||
implicitHeight: _toastRect.height + 4
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Left inverse corner ear
|
|
||||||
Item {
|
Item {
|
||||||
anchors.right: _toastRect.left
|
id: toastItem
|
||||||
anchors.top: parent.top
|
visible: false
|
||||||
width: 8
|
property var currentNotif: null
|
||||||
height: Math.min(8, _toastRect.height)
|
property bool toastOpen: false
|
||||||
clip: true
|
readonly property var mutedApps: ["discord", "Discord", "Spotify", "spotify", "vlc", "mpv"]
|
||||||
visible: _toastRect.height >= 8
|
readonly property bool isPrimary: bar.screen === Quickshell.screens[0]
|
||||||
Canvas {
|
|
||||||
anchors.top: parent.top
|
|
||||||
width: 8; height: 8
|
|
||||||
onPaint: {
|
|
||||||
var ctx = getContext("2d");
|
|
||||||
ctx.clearRect(0, 0, 8, 8);
|
|
||||||
ctx.fillStyle = Theme.barBg;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(0, 0); ctx.lineTo(8, 0); ctx.lineTo(8, 8);
|
|
||||||
ctx.arc(0, 8, 8, 0, -Math.PI / 2, true);
|
|
||||||
ctx.closePath(); ctx.fill();
|
|
||||||
ctx.strokeStyle = Theme.base03;
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(0, 8, 8, 0, -Math.PI / 2, true);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right inverse corner ear
|
x: Math.round(bar.width / 2 - width / 2)
|
||||||
Item {
|
y: 30
|
||||||
anchors.left: _toastRect.right
|
width: _toastLeftEar.width + _toastRect.width + _toastRightEar.width
|
||||||
anchors.top: parent.top
|
height: _toastRect.height + 4
|
||||||
width: 8
|
|
||||||
height: Math.min(8, _toastRect.height)
|
|
||||||
clip: true
|
|
||||||
visible: _toastRect.height >= 8
|
|
||||||
Canvas {
|
|
||||||
anchors.top: parent.top
|
|
||||||
width: 8; height: 8
|
|
||||||
onPaint: {
|
|
||||||
var ctx = getContext("2d");
|
|
||||||
ctx.clearRect(0, 0, 8, 8);
|
|
||||||
ctx.fillStyle = Theme.barBg;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(0, 0); ctx.lineTo(8, 0);
|
|
||||||
ctx.arc(8, 8, 8, -Math.PI / 2, Math.PI, true);
|
|
||||||
ctx.closePath(); ctx.fill();
|
|
||||||
ctx.strokeStyle = Theme.base03;
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(8, 8, 8, -Math.PI / 2, Math.PI, true);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
Process {
|
||||||
id: _toastRect
|
id: notifSoundProc
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
command: [Commands.notifSound, "-i", "message"]
|
||||||
anchors.top: parent.top
|
|
||||||
width: 320
|
|
||||||
height: notifToast.open ? toastCol.height + 16 : 0
|
|
||||||
color: Theme.barBg
|
|
||||||
radius: 8
|
|
||||||
topLeftRadius: 0
|
|
||||||
topRightRadius: 0
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
// Border outline (sides + bottom with rounded corners)
|
|
||||||
Canvas {
|
|
||||||
anchors.fill: parent
|
|
||||||
onPaint: {
|
|
||||||
var ctx = getContext("2d");
|
|
||||||
var w = width, h = height, r = 8;
|
|
||||||
ctx.clearRect(0, 0, w, h);
|
|
||||||
if (h < 1) return;
|
|
||||||
ctx.strokeStyle = Theme.base03;
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(0.5, r);
|
|
||||||
ctx.lineTo(0.5, h - r);
|
|
||||||
ctx.arc(r + 0.5, h - r - 0.5, r, Math.PI, Math.PI / 2, true);
|
|
||||||
ctx.lineTo(w - r - 0.5, h - 0.5);
|
|
||||||
ctx.arc(w - r - 0.5, h - r - 0.5, r, Math.PI / 2, 0, true);
|
|
||||||
ctx.lineTo(w - 0.5, r);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
onWidthChanged: requestPaint()
|
|
||||||
onHeightChanged: requestPaint()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on height {
|
Connections {
|
||||||
NumberAnimation { duration: 220; easing.type: Easing.OutCubic }
|
target: bar.shellRoot
|
||||||
}
|
function onNotificationReceived() {
|
||||||
|
if (toastItem.isPrimary) {
|
||||||
Column {
|
toastItem.showToast(bar.shellRoot.latestNotification);
|
||||||
id: toastCol
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: toastDismiss.left
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.margins: 8
|
|
||||||
spacing: 2
|
|
||||||
|
|
||||||
Text {
|
|
||||||
width: parent.width
|
|
||||||
text: notifToast.currentNotif ? (notifToast.currentNotif.summary || notifToast.currentNotif.appName) : ""
|
|
||||||
color: Theme.base05
|
|
||||||
font.family: "FiraMono Nerd Font"
|
|
||||||
font.pixelSize: 12
|
|
||||||
font.weight: Font.Medium
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
width: parent.width
|
|
||||||
text: notifToast.currentNotif ? (notifToast.currentNotif.body || "") : ""
|
|
||||||
color: Theme.base04
|
|
||||||
font.family: "FiraMono Nerd Font"
|
|
||||||
font.pixelSize: 11
|
|
||||||
elide: Text.ElideRight
|
|
||||||
maximumLineCount: 3
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
visible: text !== ""
|
|
||||||
}
|
|
||||||
|
|
||||||
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 ? Theme.base02 : Theme.base01
|
|
||||||
border.width: 1
|
|
||||||
border.color: Theme.base02
|
|
||||||
Text {
|
|
||||||
id: toastActionText
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: modelData.text
|
|
||||||
color: Theme.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(); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
function showToast(notification) {
|
||||||
id: toastDismiss
|
currentNotif = notification;
|
||||||
anchors.right: parent.right
|
visible = true;
|
||||||
|
toastOpen = true;
|
||||||
|
_toastTimer.restart();
|
||||||
|
if (!mutedApps.includes(notification.appName)) {
|
||||||
|
notifSoundProc.running = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dismiss() {
|
||||||
|
toastOpen = false;
|
||||||
|
_toastCloseDelay.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: _toastTimer
|
||||||
|
interval: 5000
|
||||||
|
onTriggered: toastItem.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: _toastCloseDelay
|
||||||
|
interval: 230
|
||||||
|
onTriggered: { toastItem.visible = false; toastItem.toastOpen = false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
onHoveredChanged: {
|
||||||
|
if (hovered) _toastTimer.stop();
|
||||||
|
else _toastTimer.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left inverse corner ear
|
||||||
|
Item {
|
||||||
|
id: _toastLeftEar
|
||||||
|
anchors.right: _toastRect.left
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.margins: 8
|
width: 8
|
||||||
text: "\u{f0156}"
|
height: Math.min(8, _toastRect.height)
|
||||||
color: toastDismissMa.containsMouse ? Theme.base05 : Theme.base03
|
clip: true
|
||||||
font.family: "FiraMono Nerd Font"
|
visible: _toastRect.height >= 8
|
||||||
font.pixelSize: 13
|
Canvas {
|
||||||
MouseArea {
|
anchors.top: parent.top
|
||||||
id: toastDismissMa
|
width: 8; height: 8
|
||||||
|
onPaint: {
|
||||||
|
var ctx = getContext("2d");
|
||||||
|
ctx.clearRect(0, 0, 8, 8);
|
||||||
|
ctx.fillStyle = Theme.barBg;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0, 0); ctx.lineTo(8, 0); ctx.lineTo(8, 8);
|
||||||
|
ctx.arc(0, 8, 8, 0, -Math.PI / 2, true);
|
||||||
|
ctx.closePath(); ctx.fill();
|
||||||
|
ctx.strokeStyle = Theme.base03;
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(0, 8, 8, 0, -Math.PI / 2, true);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right inverse corner ear
|
||||||
|
Item {
|
||||||
|
id: _toastRightEar
|
||||||
|
anchors.left: _toastRect.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
width: 8
|
||||||
|
height: Math.min(8, _toastRect.height)
|
||||||
|
clip: true
|
||||||
|
visible: _toastRect.height >= 8
|
||||||
|
Canvas {
|
||||||
|
anchors.top: parent.top
|
||||||
|
width: 8; height: 8
|
||||||
|
onPaint: {
|
||||||
|
var ctx = getContext("2d");
|
||||||
|
ctx.clearRect(0, 0, 8, 8);
|
||||||
|
ctx.fillStyle = Theme.barBg;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0, 0); ctx.lineTo(8, 0);
|
||||||
|
ctx.arc(8, 8, 8, -Math.PI / 2, Math.PI, true);
|
||||||
|
ctx.closePath(); ctx.fill();
|
||||||
|
ctx.strokeStyle = Theme.base03;
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(8, 8, 8, -Math.PI / 2, Math.PI, true);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: _toastRect
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
width: 320
|
||||||
|
height: toastItem.toastOpen ? toastCol.height + 16 : 0
|
||||||
|
color: Theme.barBg
|
||||||
|
radius: 8
|
||||||
|
topLeftRadius: 0
|
||||||
|
topRightRadius: 0
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
// Border outline (sides + bottom with rounded corners)
|
||||||
|
Canvas {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
onPaint: {
|
||||||
cursorShape: Qt.PointingHandCursor
|
var ctx = getContext("2d");
|
||||||
onClicked: { notifToast.currentNotif.dismiss(); notifToast.dismiss(); }
|
var w = width, h = height, r = 8;
|
||||||
|
ctx.clearRect(0, 0, w, h);
|
||||||
|
if (h < 1) return;
|
||||||
|
ctx.strokeStyle = Theme.base03;
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0.5, r);
|
||||||
|
ctx.lineTo(0.5, h - r);
|
||||||
|
ctx.arc(r + 0.5, h - r - 0.5, r, Math.PI, Math.PI / 2, true);
|
||||||
|
ctx.lineTo(w - r - 0.5, h - 0.5);
|
||||||
|
ctx.arc(w - r - 0.5, h - r - 0.5, r, Math.PI / 2, 0, true);
|
||||||
|
ctx.lineTo(w - 0.5, r);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
onWidthChanged: requestPaint()
|
||||||
|
onHeightChanged: requestPaint()
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on height {
|
||||||
|
NumberAnimation { duration: 220; easing.type: Easing.OutCubic }
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: toastCol
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: toastDismiss.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.margins: 8
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
Text {
|
||||||
|
width: parent.width
|
||||||
|
text: toastItem.currentNotif ? (toastItem.currentNotif.summary || toastItem.currentNotif.appName) : ""
|
||||||
|
color: Theme.base05
|
||||||
|
font.family: "FiraMono Nerd Font"
|
||||||
|
font.pixelSize: 12
|
||||||
|
font.weight: Font.Medium
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
width: parent.width
|
||||||
|
text: toastItem.currentNotif ? (toastItem.currentNotif.body || "") : ""
|
||||||
|
color: Theme.base04
|
||||||
|
font.family: "FiraMono Nerd Font"
|
||||||
|
font.pixelSize: 11
|
||||||
|
elide: Text.ElideRight
|
||||||
|
maximumLineCount: 3
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
visible: text !== ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: 4
|
||||||
|
visible: toastItem.currentNotif && toastItem.currentNotif.actions.length > 0
|
||||||
|
Repeater {
|
||||||
|
model: toastItem.currentNotif ? toastItem.currentNotif.actions : []
|
||||||
|
Rectangle {
|
||||||
|
required property var modelData
|
||||||
|
width: toastActionText.width + 12
|
||||||
|
height: toastActionText.height + 6
|
||||||
|
radius: 4
|
||||||
|
color: toastActionMa.containsMouse ? Theme.base02 : Theme.base01
|
||||||
|
border.width: 1
|
||||||
|
border.color: Theme.base02
|
||||||
|
Text {
|
||||||
|
id: toastActionText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: modelData.text
|
||||||
|
color: Theme.base05
|
||||||
|
font.family: "FiraMono Nerd Font"
|
||||||
|
font.pixelSize: 10
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
id: toastActionMa
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: { modelData.invoke(); toastItem.dismiss(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: toastDismiss
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.margins: 8
|
||||||
|
text: "\u{f0156}"
|
||||||
|
color: toastDismissMa.containsMouse ? Theme.base05 : Theme.base03
|
||||||
|
font.family: "FiraMono Nerd Font"
|
||||||
|
font.pixelSize: 13
|
||||||
|
MouseArea {
|
||||||
|
id: toastDismissMa
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: { toastItem.currentNotif.dismiss(); toastItem.dismiss(); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue