mirror of
https://github.com/end-4/dots-hyprland.git
synced 2026-06-05 14:59:27 -05:00
waffles: notifications: image support
This commit is contained in:
@@ -84,4 +84,28 @@ Singleton {
|
||||
// Older dates
|
||||
return Qt.formatDateTime(messageTime, "MMMM dd");
|
||||
}
|
||||
|
||||
function processNotificationBody(body, appName) {
|
||||
let processedBody = body
|
||||
|
||||
// Clean Chromium-based browsers notifications - remove first line
|
||||
if (appName) {
|
||||
const lowerApp = appName.toLowerCase()
|
||||
const chromiumBrowsers = [
|
||||
"brave", "chrome", "chromium", "vivaldi", "opera", "microsoft edge"
|
||||
]
|
||||
|
||||
if (chromiumBrowsers.some(name => lowerApp.includes(name))) {
|
||||
const lines = body.split('\n\n')
|
||||
|
||||
if (lines.length > 1 && lines[0].startsWith('<a')) {
|
||||
processedBody = lines.slice(1).join('\n\n')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processedBody = processedBody.replace(/<img/gi, '\n\n<img');
|
||||
|
||||
return processedBody
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,28 +31,6 @@ Item { // Notification item area
|
||||
|
||||
implicitHeight: background.implicitHeight
|
||||
|
||||
function processNotificationBody(body, appName) {
|
||||
let processedBody = body
|
||||
|
||||
// Clean Chromium-based browsers notifications - remove first line
|
||||
if (appName) {
|
||||
const lowerApp = appName.toLowerCase()
|
||||
const chromiumBrowsers = [
|
||||
"brave", "chrome", "chromium", "vivaldi", "opera", "microsoft edge"
|
||||
]
|
||||
|
||||
if (chromiumBrowsers.some(name => lowerApp.includes(name))) {
|
||||
const lines = body.split('\n\n')
|
||||
|
||||
if (lines.length > 1 && lines[0].startsWith('<a')) {
|
||||
processedBody = lines.slice(1).join('\n\n')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return processedBody
|
||||
}
|
||||
|
||||
function destroyWithAnimation(left = false) {
|
||||
root.qmlParent.resetDrag()
|
||||
background.anchors.leftMargin = background.anchors.leftMargin; // Break binding
|
||||
@@ -196,12 +174,13 @@ Item { // Notification item area
|
||||
maximumLineCount: 1
|
||||
textFormat: Text.StyledText
|
||||
text: {
|
||||
return processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>")
|
||||
return NotificationUtils.processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout { // Expanded content
|
||||
id: expandedContentColumn
|
||||
Layout.fillWidth: true
|
||||
opacity: root.expanded ? 1 : 0
|
||||
visible: opacity > 0
|
||||
@@ -218,8 +197,8 @@ Item { // Notification item area
|
||||
elide: Text.ElideRight
|
||||
textFormat: Text.RichText
|
||||
text: {
|
||||
return `<style>img{max-width:${300 /* binding to notificationBodyText.width would cause a binding loop */}px;}</style>` +
|
||||
`${processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>")}`
|
||||
return `<style>img{max-width:${expandedContentColumn.width}px;}</style>` +
|
||||
`${NotificationUtils.processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>")}`
|
||||
}
|
||||
|
||||
onLinkActivated: (link) => {
|
||||
@@ -293,6 +272,8 @@ Item { // Notification item area
|
||||
id: actionRepeater
|
||||
model: notificationObject.actions
|
||||
NotificationActionButton {
|
||||
id: notifAction
|
||||
required property var modelData
|
||||
Layout.fillWidth: true
|
||||
buttonText: modelData.text
|
||||
urgency: notificationObject.urgency
|
||||
|
||||
@@ -7,6 +7,7 @@ import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
// TODO: Replace the icon with QMLized svg (with /usr/lib/qt6/bin/svgtoqml) for proper micro-animation
|
||||
AppButton {
|
||||
id: root
|
||||
|
||||
|
||||
+18
-1
@@ -20,6 +20,7 @@ WBarAttachedPanelContent {
|
||||
property bool collapsed: false
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
id: contentLayout
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: parent.top
|
||||
@@ -41,9 +42,24 @@ WBarAttachedPanelContent {
|
||||
}
|
||||
contentItem: NotificationPaneContent {
|
||||
implicitWidth: calendarColumnLayout.implicitWidth
|
||||
implicitHeight: Notifications.list.length > 0 ? (notificationArea.height - notificationPane.borderWidth * 2) : 230
|
||||
implicitHeight: {
|
||||
if (Notifications.list.length > 0) {
|
||||
return ((contentLayout.height - calendarPane.height - contentLayout.spacing) - notificationPane.borderWidth * 2)
|
||||
}
|
||||
return 230;
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: enableTimer
|
||||
interval: Config.options.hacks.arbitraryRaceConditionDelay
|
||||
onTriggered: heightBehavior.enabled = true;
|
||||
}
|
||||
Behavior on implicitHeight {
|
||||
id: heightBehavior
|
||||
enabled: false
|
||||
Component.onCompleted: {
|
||||
enableTimer.restart();
|
||||
}
|
||||
animation: Looks.transition.enter.createObject(this)
|
||||
}
|
||||
}
|
||||
@@ -51,6 +67,7 @@ WBarAttachedPanelContent {
|
||||
}
|
||||
|
||||
WPane {
|
||||
id: calendarPane
|
||||
contentItem: ColumnLayout {
|
||||
id: calendarColumnLayout
|
||||
spacing: 0
|
||||
|
||||
+123
-34
@@ -1,3 +1,4 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
@@ -41,52 +42,115 @@ MouseArea {
|
||||
anchors.margins: contentItem.padding
|
||||
spacing: 19
|
||||
|
||||
RowLayout {
|
||||
// Header
|
||||
SingleNotificationHeader {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ExpandButton {
|
||||
Layout.topMargin: -2
|
||||
// Content
|
||||
Item {
|
||||
id: actualContent
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
property real spacing: 16
|
||||
implicitHeight: Math.max(contentColumn.implicitHeight, imageLoader.height)
|
||||
implicitWidth: contentColumn.implicitWidth
|
||||
|
||||
Loader {
|
||||
id: imageLoader
|
||||
active: root.notification.image != ""
|
||||
sourceComponent: StyledImage {
|
||||
width: 48
|
||||
height: 48
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
source: root.notification.image
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
ColumnLayout {
|
||||
id: contentColumn
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
spacing: 3
|
||||
|
||||
NotificationHeaderButton {
|
||||
Layout.rightMargin: 4
|
||||
opacity: root.containsMouse ? 1 : 0
|
||||
icon.name: "dismiss"
|
||||
implicitSize: 12
|
||||
onClicked: {
|
||||
Qt.callLater(() => {
|
||||
Notifications.discardNotification(root.notification?.notificationId);
|
||||
});
|
||||
SummaryText {
|
||||
id: summaryText
|
||||
Layout.leftMargin: imageLoader.active ? imageLoader.width + actualContent.spacing : 0
|
||||
}
|
||||
BodyText {
|
||||
Layout.leftMargin: imageLoader.active ? imageLoader.width + actualContent.spacing : 0
|
||||
// onLineLaidOut: (line) => {
|
||||
// if (!imageLoader.active) return;
|
||||
// const dodgeDistance = imageLoader.width + actualContent.spacing;
|
||||
// // print(line.y, dodgeDistance)
|
||||
// if (summaryText.height + line.y > dodgeDistance) {
|
||||
// line.x -= dodgeDistance;
|
||||
// line.width += dodgeDistance;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
// Actions
|
||||
ActionsRow {
|
||||
Layout.fillWidth: true
|
||||
spacing: 3
|
||||
|
||||
SummaryText {}
|
||||
BodyText {}
|
||||
}
|
||||
|
||||
AcrylicButton {
|
||||
id: groupExpandButton
|
||||
visible: root.groupExpandControlMessage !== ""
|
||||
// "+1 notifications" button
|
||||
GroupExpandButton {
|
||||
Layout.bottomMargin: 2
|
||||
horizontalPadding: 10
|
||||
implicitHeight: 24
|
||||
implicitWidth: expandButtonText.implicitWidth + horizontalPadding * 2
|
||||
onClicked: root.groupExpandToggle()
|
||||
contentItem: Item {
|
||||
WText {
|
||||
id: expandButtonText
|
||||
anchors.centerIn: parent
|
||||
text: root.groupExpandControlMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component SingleNotificationHeader: RowLayout {
|
||||
ExpandButton {
|
||||
Layout.topMargin: -2
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NotificationHeaderButton {
|
||||
Layout.rightMargin: 4
|
||||
opacity: root.containsMouse ? 1 : 0
|
||||
icon.name: "dismiss"
|
||||
implicitSize: 12
|
||||
onClicked: {
|
||||
Qt.callLater(() => {
|
||||
Notifications.discardNotification(root.notification?.notificationId);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component ActionsRow: RowLayout {
|
||||
visible: root.expanded && root.notification.actions.length > 0
|
||||
uniformCellSizes: true
|
||||
Repeater {
|
||||
id: actionRepeater
|
||||
model: root.notification.actions
|
||||
delegate: WBorderedButton {
|
||||
id: actionButton
|
||||
Layout.fillHeight: true
|
||||
required property var modelData
|
||||
Layout.fillWidth: true
|
||||
verticalPadding: 16
|
||||
horizontalPadding: 12
|
||||
text: modelData.text
|
||||
implicitHeight: actionButtonText.implicitHeight + verticalPadding * 2
|
||||
contentItem: WText {
|
||||
id: actionButtonText
|
||||
text: actionButton.text
|
||||
font.pixelSize: Looks.font.pixelSize.large
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,8 +170,17 @@ MouseArea {
|
||||
verticalAlignment: Text.AlignTop
|
||||
wrapMode: Text.Wrap
|
||||
maximumLineCount: root.expanded ? 100 : 1
|
||||
text: root.notification?.body
|
||||
text: {
|
||||
if (root.expanded)
|
||||
return `<style>img{max-width:${summaryText.width}px; align: right}</style>` + `${NotificationUtils.processNotificationBody(root.notification.body, root.notification.appName || root.notification.summary).replace(/\n/g, "<br/>")}`;
|
||||
return NotificationUtils.processNotificationBody(root.notification.body, root.notification.appName || root.notification.summary).replace(/\n/g, "<br/>");
|
||||
}
|
||||
color: Looks.colors.subfg
|
||||
textFormat: root.expanded ? Text.RichText : Text.StyledText
|
||||
onLinkActivated: link => {
|
||||
Qt.openUrlExternally(link);
|
||||
GlobalStates.sidebarRightOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
component ExpandButton: NotificationHeaderButton {
|
||||
@@ -140,4 +213,20 @@ MouseArea {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component GroupExpandButton: AcrylicButton {
|
||||
id: groupExpandButton
|
||||
visible: root.groupExpandControlMessage !== ""
|
||||
horizontalPadding: 10
|
||||
implicitHeight: 24
|
||||
implicitWidth: expandButtonText.implicitWidth + horizontalPadding * 2
|
||||
onClicked: root.groupExpandToggle()
|
||||
contentItem: Item {
|
||||
WText {
|
||||
id: expandButtonText
|
||||
anchors.centerIn: parent
|
||||
text: root.groupExpandControlMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user