mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-10 07:42:09 -04:00
feat(notifications): add configurable notification rules (#1655)
This commit is contained in:
@@ -153,12 +153,12 @@ QtObject {
|
||||
if (!wrapper || !wrapper.notification) {
|
||||
return false;
|
||||
}
|
||||
const incomingUrgency = wrapper.notification.urgency || 0;
|
||||
const incomingUrgency = wrapper.urgency || 0;
|
||||
for (const p of activeWindows) {
|
||||
if (!p.notificationData || !p.notificationData.notification) {
|
||||
continue;
|
||||
}
|
||||
const existingUrgency = p.notificationData.notification.urgency || 0;
|
||||
const existingUrgency = p.notificationData.urgency || 0;
|
||||
if (existingUrgency < incomingUrgency) {
|
||||
return true;
|
||||
}
|
||||
@@ -188,10 +188,9 @@ QtObject {
|
||||
}
|
||||
|
||||
function _selectPopupToRemove(activeWindows, incomingWrapper) {
|
||||
const incomingUrgency = (incomingWrapper && incomingWrapper.notification) ? incomingWrapper.notification.urgency || 0 : 0;
|
||||
const sortedWindows = activeWindows.slice().sort((a, b) => {
|
||||
const aUrgency = (a.notificationData && a.notificationData.notification) ? a.notificationData.notification.urgency || 0 : 0;
|
||||
const bUrgency = (b.notificationData && b.notificationData.notification) ? b.notificationData.notification.urgency || 0 : 0;
|
||||
const aUrgency = (a.notificationData) ? a.notificationData.urgency || 0 : 0;
|
||||
const bUrgency = (b.notificationData) ? b.notificationData.urgency || 0 : 0;
|
||||
if (aUrgency !== bUrgency) {
|
||||
return aUrgency - bUrgency;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,82 @@ Item {
|
||||
}
|
||||
]
|
||||
|
||||
readonly property var notificationRuleFieldOptions: [
|
||||
{
|
||||
value: "appName",
|
||||
label: I18n.tr("App Names", "notification rule match field option")
|
||||
},
|
||||
{
|
||||
value: "desktopEntry",
|
||||
label: I18n.tr("Desktop Entry", "notification rule match field option")
|
||||
},
|
||||
{
|
||||
value: "summary",
|
||||
label: I18n.tr("Summary", "notification rule match field option")
|
||||
},
|
||||
{
|
||||
value: "body",
|
||||
label: I18n.tr("Body", "notification rule match field option")
|
||||
}
|
||||
]
|
||||
|
||||
readonly property var notificationRuleMatchTypeOptions: [
|
||||
{
|
||||
value: "contains",
|
||||
label: I18n.tr("Contains", "notification rule match type option")
|
||||
},
|
||||
{
|
||||
value: "exact",
|
||||
label: I18n.tr("Exact", "notification rule match type option")
|
||||
},
|
||||
{
|
||||
value: "regex",
|
||||
label: I18n.tr("Regex", "notification rule match type option")
|
||||
}
|
||||
]
|
||||
|
||||
readonly property var notificationRuleActionOptions: [
|
||||
{
|
||||
value: "default",
|
||||
label: I18n.tr("Default", "notification rule action option")
|
||||
},
|
||||
{
|
||||
value: "mute",
|
||||
label: I18n.tr("Mute Popups", "notification rule action option")
|
||||
},
|
||||
{
|
||||
value: "ignore",
|
||||
label: I18n.tr("Ignore Completely", "notification rule action option")
|
||||
},
|
||||
{
|
||||
value: "popup_only",
|
||||
label: I18n.tr("Popup Only", "notification rule action option")
|
||||
},
|
||||
{
|
||||
value: "no_history",
|
||||
label: I18n.tr("No History", "notification rule action option")
|
||||
}
|
||||
]
|
||||
|
||||
readonly property var notificationRuleUrgencyOptions: [
|
||||
{
|
||||
value: "default",
|
||||
label: I18n.tr("Default", "notification rule urgency option")
|
||||
},
|
||||
{
|
||||
value: "low",
|
||||
label: I18n.tr("Low Priority", "notification rule urgency option")
|
||||
},
|
||||
{
|
||||
value: "normal",
|
||||
label: I18n.tr("Normal Priority", "notification rule urgency option")
|
||||
},
|
||||
{
|
||||
value: "critical",
|
||||
label: I18n.tr("Critical Priority", "notification rule urgency option")
|
||||
}
|
||||
]
|
||||
|
||||
function getTimeoutText(value) {
|
||||
if (value === undefined || value === null || isNaN(value))
|
||||
return I18n.tr("5 seconds");
|
||||
@@ -73,6 +149,22 @@ Item {
|
||||
return Math.round(value / 60000) + " " + I18n.tr("minutes");
|
||||
}
|
||||
|
||||
function getRuleOptionLabel(options, value, fallback) {
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
if (options[i].value === value)
|
||||
return options[i].label;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
function getRuleOptionValue(options, label, fallback) {
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
if (options[i].label === label)
|
||||
return options[i].value;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
@@ -165,6 +257,228 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "rule_settings"
|
||||
title: I18n.tr("Notification Rules")
|
||||
settingKey: "notificationRules"
|
||||
tags: ["notification", "rules", "mute", "ignore", "priority", "regex", "history"]
|
||||
collapsible: true
|
||||
expanded: false
|
||||
|
||||
headerActions: [
|
||||
DankActionButton {
|
||||
buttonSize: 36
|
||||
iconName: "restart_alt"
|
||||
iconSize: 20
|
||||
visible: JSON.stringify(SettingsData.notificationRules) !== JSON.stringify(SettingsData.getDefaultNotificationRules())
|
||||
backgroundColor: Theme.surfaceContainer
|
||||
iconColor: Theme.surfaceVariantText
|
||||
onClicked: SettingsData.resetNotificationRules()
|
||||
},
|
||||
DankActionButton {
|
||||
buttonSize: 36
|
||||
iconName: "add"
|
||||
iconSize: 20
|
||||
backgroundColor: Theme.surfaceContainer
|
||||
iconColor: Theme.primary
|
||||
onClicked: SettingsData.addNotificationRule()
|
||||
}
|
||||
]
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Create rules to mute, ignore, hide from history, or override notification priority.")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
bottomPadding: Theme.spacingS
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: SettingsData.notificationRules
|
||||
|
||||
delegate: Rectangle {
|
||||
id: ruleItem
|
||||
width: parent.width
|
||||
height: ruleColumn.implicitHeight + Theme.spacingM
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainer, 0.5)
|
||||
|
||||
Column {
|
||||
id: ruleColumn
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingS
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
id: ruleLabel
|
||||
text: I18n.tr("Rule") + " " + (index + 1)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
width: Math.max(0, parent.width - ruleLabel.implicitWidth - enableToggle.width - deleteBtn.width - Theme.spacingS * 3)
|
||||
height: 1
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
id: enableToggle
|
||||
width: 40
|
||||
height: 24
|
||||
hideText: true
|
||||
checked: modelData.enabled !== false
|
||||
onToggled: checked => SettingsData.updateNotificationRuleField(index, "enabled", checked)
|
||||
}
|
||||
|
||||
Item {
|
||||
id: deleteBtn
|
||||
width: 28
|
||||
height: 28
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
color: deleteArea.containsMouse ? Theme.withAlpha(Theme.error, 0.2) : "transparent"
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "delete"
|
||||
size: 18
|
||||
color: deleteArea.containsMouse ? Theme.error : Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: deleteArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: SettingsData.removeNotificationRule(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Pattern")
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
width: parent.width
|
||||
text: modelData.pattern || ""
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
placeholderText: I18n.tr("Pattern")
|
||||
onEditingFinished: SettingsData.updateNotificationRuleField(index, "pattern", text)
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Column {
|
||||
width: (parent.width - Theme.spacingS * 3) / 4
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Field")
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
width: parent.width
|
||||
compactMode: true
|
||||
dropdownWidth: parent.width
|
||||
currentValue: root.getRuleOptionLabel(root.notificationRuleFieldOptions, modelData.field, root.notificationRuleFieldOptions[0].label)
|
||||
options: root.notificationRuleFieldOptions.map(o => o.label)
|
||||
onValueChanged: value => SettingsData.updateNotificationRuleField(index, "field", root.getRuleOptionValue(root.notificationRuleFieldOptions, value, "appName"))
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: (parent.width - Theme.spacingS * 3) / 4
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Type")
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
width: parent.width
|
||||
compactMode: true
|
||||
dropdownWidth: parent.width
|
||||
currentValue: root.getRuleOptionLabel(root.notificationRuleMatchTypeOptions, modelData.matchType, root.notificationRuleMatchTypeOptions[0].label)
|
||||
options: root.notificationRuleMatchTypeOptions.map(o => o.label)
|
||||
onValueChanged: value => SettingsData.updateNotificationRuleField(index, "matchType", root.getRuleOptionValue(root.notificationRuleMatchTypeOptions, value, "contains"))
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: (parent.width - Theme.spacingS * 3) / 4
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Action")
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
width: parent.width
|
||||
compactMode: true
|
||||
dropdownWidth: parent.width
|
||||
currentValue: root.getRuleOptionLabel(root.notificationRuleActionOptions, modelData.action, root.notificationRuleActionOptions[0].label)
|
||||
options: root.notificationRuleActionOptions.map(o => o.label)
|
||||
onValueChanged: value => SettingsData.updateNotificationRuleField(index, "action", root.getRuleOptionValue(root.notificationRuleActionOptions, value, "default"))
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: (parent.width - Theme.spacingS * 3) / 4
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Priority")
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
width: parent.width
|
||||
compactMode: true
|
||||
dropdownWidth: parent.width
|
||||
currentValue: root.getRuleOptionLabel(root.notificationRuleUrgencyOptions, modelData.urgency, root.notificationRuleUrgencyOptions[0].label)
|
||||
options: root.notificationRuleUrgencyOptions.map(o => o.label)
|
||||
onValueChanged: value => SettingsData.updateNotificationRuleField(index, "urgency", root.getRuleOptionValue(root.notificationRuleUrgencyOptions, value, "default"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "lock"
|
||||
|
||||
Reference in New Issue
Block a user