1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-04 04:42:05 -04:00
Files
DankMaterialShell/quickshell/Modules/Settings/NotificationsTab.qml
bbedward 196c421b75 Squashed commit of the following:
commit 051b7576f7
Author: purian23 <purian23@gmail.com>
Date:   Sun Feb 15 16:38:45 2026 -0500

    Height for realz

commit 7784488a61
Author: purian23 <purian23@gmail.com>
Date:   Sun Feb 15 16:34:09 2026 -0500

    Fix height and truncate text/URLs

commit 31b328d428
Author: bbedward <bbedward@gmail.com>
Date:   Sun Feb 15 16:25:57 2026 -0500

    notifications: handle URL encoding in markdown2html

commit dbb04f74a2
Author: bbedward <bbedward@gmail.com>
Date:   Sun Feb 15 16:10:20 2026 -0500

    notifications: more comprehensive decoder

commit b29c7192c2
Author: bbedward <bbedward@gmail.com>
Date:   Sun Feb 15 15:51:37 2026 -0500

    notifications: html unescape

commit 8a48fa11ec
Author: purian23 <purian23@gmail.com>
Date:   Sun Feb 15 15:04:33 2026 -0500

    Add expressive curve on init toast

commit ee124f5e04
Author: purian23 <purian23@gmail.com>
Date:   Sun Feb 15 15:02:16 2026 -0500

    Expressive curves on swipe & btn height

commit 0fce904635
Author: purian23 <purian23@gmail.com>
Date:   Sun Feb 15 13:40:02 2026 -0500

    Provide bottom button clearance

commit 00d3829999
Author: bbedward <bbedward@gmail.com>
Date:   Sun Feb 15 13:24:31 2026 -0500

    notifications: cleanup popup display logic

commit fd05768059
Author: purian23 <purian23@gmail.com>
Date:   Sun Feb 15 01:00:55 2026 -0500

    Add Privacy Mode
    - Smoother notification expansions
    - Shadow & Privacy Toggles

commit 0dba11d845
Author: purian23 <purian23@gmail.com>
Date:   Sat Feb 14 22:48:46 2026 -0500

    Further M3 enhancements

commit 949c216964
Author: purian23 <purian23@gmail.com>
Date:   Sat Feb 14 19:59:38 2026 -0500

    Right-Click to set Rules on Notifications directly

commit 62bc25782c
Author: bbedward <bbedward@gmail.com>
Date:   Fri Feb 13 21:44:27 2026 -0500

    notifications: fix compact spacing, reveal header bar, add bottom center
    position, pointing hand cursor fix

commit ed495d4396
Author: purian23 <purian23@gmail.com>
Date:   Fri Feb 13 20:25:40 2026 -0500

    Tighten init toast

commit ebe38322a0
Author: purian23 <purian23@gmail.com>
Date:   Fri Feb 13 20:09:59 2026 -0500

    Update more m3 baselines & spacing

commit b1735bb701
Author: purian23 <purian23@gmail.com>
Date:   Fri Feb 13 14:10:05 2026 -0500

    Expand rules on-Click

commit 9f13546b4d
Author: purian23 <purian23@gmail.com>
Date:   Fri Feb 13 12:59:29 2026 -0500

    Add Notification Rules
    - Additional right-click ops
    - Allow for 3rd boy line on init notification popup

commit be133b73c7
Author: purian23 <purian23@gmail.com>
Date:   Fri Feb 13 10:10:03 2026 -0500

    Truncate long title in groups

commit 4fc275bead
Author: bbedward <bbedward@gmail.com>
Date:   Thu Feb 12 23:27:34 2026 -0500

    notification: expand/collapse animation adjustment

commit 00e6172a68
Author: purian23 <purian23@gmail.com>
Date:   Thu Feb 12 22:50:11 2026 -0500

    Fix global warnings

commit 0772f6deb7
Author: purian23 <purian23@gmail.com>
Date:   Thu Feb 12 22:46:40 2026 -0500

    Tweak expansion duration

commit 0ffeed3ff0
Author: purian23 <purian23@gmail.com>
Date:   Thu Feb 12 22:16:16 2026 -0500

    notifications: Update Material 3 baselines
    - New right-click to mute option
    - New independent Notification Animation settings
2026-02-16 17:57:13 -05:00

881 lines
42 KiB
QML

import QtQuick
import qs.Common
import qs.Widgets
import qs.Modules.Settings.Widgets
Item {
id: root
Component.onCompleted: {
if (SettingsData._pendingExpandNotificationRules) {
SettingsData._pendingExpandNotificationRules = false;
notificationRulesCard.userToggledCollapse = true;
notificationRulesCard.expanded = true;
SettingsData._pendingNotificationRuleIndex = -1;
}
}
readonly property var mutedRules: {
var rules = SettingsData.notificationRules || [];
var out = [];
for (var i = 0; i < rules.length; i++) {
if ((rules[i].action || "").toString().toLowerCase() === "mute")
out.push({ rule: rules[i], index: i });
}
return out;
}
readonly property var timeoutOptions: [
{
text: I18n.tr("Never"),
value: 0
},
{
text: I18n.tr("1 second"),
value: 1000
},
{
text: I18n.tr("3 seconds"),
value: 3000
},
{
text: I18n.tr("5 seconds"),
value: 5000
},
{
text: I18n.tr("8 seconds"),
value: 8000
},
{
text: I18n.tr("10 seconds"),
value: 10000
},
{
text: I18n.tr("15 seconds"),
value: 15000
},
{
text: I18n.tr("30 seconds"),
value: 30000
},
{
text: I18n.tr("1 minute"),
value: 60000
},
{
text: I18n.tr("2 minutes"),
value: 120000
},
{
text: I18n.tr("5 minutes"),
value: 300000
},
{
text: I18n.tr("10 minutes"),
value: 600000
}
]
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");
for (let i = 0; i < timeoutOptions.length; i++) {
if (timeoutOptions[i].value === value)
return timeoutOptions[i].text;
}
if (value === 0)
return I18n.tr("Never");
if (value < 1000)
return value + "ms";
if (value < 60000)
return Math.round(value / 1000) + " " + I18n.tr("seconds");
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
contentHeight: mainColumn.height + Theme.spacingXL
contentWidth: width
Column {
id: mainColumn
topPadding: 4
width: Math.min(550, parent.width - Theme.spacingL * 2)
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.spacingXL
SettingsCard {
width: parent.width
iconName: "notifications"
title: I18n.tr("Notification Popups")
settingKey: "notificationPopups"
SettingsDropdownRow {
settingKey: "notificationPopupPosition"
tags: ["notification", "popup", "position", "screen", "location"]
text: I18n.tr("Popup Position")
description: I18n.tr("Choose where notification popups appear on screen")
currentValue: {
if (SettingsData.notificationPopupPosition === -1)
return I18n.tr("Top Center", "screen position option");
switch (SettingsData.notificationPopupPosition) {
case SettingsData.Position.Top:
return I18n.tr("Top Right", "screen position option");
case SettingsData.Position.Bottom:
return I18n.tr("Bottom Left", "screen position option");
case SettingsData.Position.Left:
return I18n.tr("Top Left", "screen position option");
case SettingsData.Position.Right:
return I18n.tr("Bottom Right", "screen position option");
case SettingsData.Position.BottomCenter:
return I18n.tr("Bottom Center", "screen position option");
default:
return I18n.tr("Top Right", "screen position option");
}
}
options: [I18n.tr("Top Right", "screen position option"), I18n.tr("Top Left", "screen position option"), I18n.tr("Top Center", "screen position option"), I18n.tr("Bottom Center", "screen position option"), I18n.tr("Bottom Right", "screen position option"), I18n.tr("Bottom Left", "screen position option")]
onValueChanged: value => {
switch (value) {
case I18n.tr("Top Right", "screen position option"):
SettingsData.set("notificationPopupPosition", SettingsData.Position.Top);
break;
case I18n.tr("Top Left", "screen position option"):
SettingsData.set("notificationPopupPosition", SettingsData.Position.Left);
break;
case I18n.tr("Top Center", "screen position option"):
SettingsData.set("notificationPopupPosition", -1);
break;
case I18n.tr("Bottom Center", "screen position option"):
SettingsData.set("notificationPopupPosition", SettingsData.Position.BottomCenter);
break;
case I18n.tr("Bottom Right", "screen position option"):
SettingsData.set("notificationPopupPosition", SettingsData.Position.Right);
break;
case I18n.tr("Bottom Left", "screen position option"):
SettingsData.set("notificationPopupPosition", SettingsData.Position.Bottom);
break;
}
SettingsData.sendTestNotifications();
}
}
SettingsToggleRow {
settingKey: "notificationOverlayEnabled"
tags: ["notification", "overlay", "fullscreen", "priority"]
text: I18n.tr("Notification Overlay")
description: I18n.tr("Display all priorities over fullscreen apps")
checked: SettingsData.notificationOverlayEnabled
onToggled: checked => SettingsData.set("notificationOverlayEnabled", checked)
}
SettingsToggleRow {
settingKey: "notificationCompactMode"
tags: ["notification", "compact", "size", "display", "mode"]
text: I18n.tr("Compact")
description: I18n.tr("Use smaller notification cards")
checked: SettingsData.notificationCompactMode
onToggled: checked => SettingsData.set("notificationCompactMode", checked)
}
SettingsToggleRow {
settingKey: "notificationPopupShadowEnabled"
tags: ["notification", "popup", "shadow", "radius", "rounded"]
text: I18n.tr("Popup Shadow")
description: I18n.tr("Show drop shadow on notification popups")
checked: SettingsData.notificationPopupShadowEnabled
onToggled: checked => SettingsData.set("notificationPopupShadowEnabled", checked)
}
SettingsToggleRow {
settingKey: "notificationPopupPrivacyMode"
tags: ["notification", "popup", "privacy", "body", "content", "hide"]
text: I18n.tr("Privacy Mode")
description: I18n.tr("Hide notification content until expanded; popups show collapsed by default")
checked: SettingsData.notificationPopupPrivacyMode
onToggled: checked => SettingsData.set("notificationPopupPrivacyMode", checked)
}
Item {
width: parent.width
height: notificationAnimationColumn.implicitHeight + Theme.spacingM * 2
Column {
id: notificationAnimationColumn
width: parent.width - Theme.spacingM * 2
x: Theme.spacingM
anchors.top: parent.top
anchors.topMargin: Theme.spacingM
spacing: Theme.spacingS
StyledText {
text: I18n.tr("Animation Speed")
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
width: parent.width
}
StyledText {
text: I18n.tr("Control animation duration for notification popups and history")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
DankButtonGroup {
id: notificationSpeedGroup
anchors.horizontalCenter: parent.horizontalCenter
buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingM
minButtonWidth: parent.width < 480 ? 44 : 56
textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium
model: [I18n.tr("None"), I18n.tr("Short"), I18n.tr("Medium"), I18n.tr("Long"), I18n.tr("Custom")]
selectionMode: "single"
currentIndex: SettingsData.notificationAnimationSpeed
onSelectionChanged: (index, selected) => {
if (!selected)
return;
SettingsData.set("notificationAnimationSpeed", index);
}
Connections {
target: SettingsData
function onNotificationAnimationSpeedChanged() {
notificationSpeedGroup.currentIndex = SettingsData.notificationAnimationSpeed;
}
}
}
SettingsSliderRow {
settingKey: "notificationCustomAnimationDuration"
tags: ["notification", "animation", "duration", "custom", "speed"]
text: I18n.tr("Duration")
description: I18n.tr("Base duration for animations (drag to use Custom)")
minimum: 100
maximum: 800
value: Theme.notificationAnimationBaseDuration
unit: "ms"
defaultValue: 400
onSliderValueChanged: newValue => {
if (SettingsData.notificationAnimationSpeed !== SettingsData.AnimationSpeed.Custom) {
SettingsData.set("notificationAnimationSpeed", SettingsData.AnimationSpeed.Custom);
}
SettingsData.set("notificationCustomAnimationDuration", newValue);
}
}
}
}
}
SettingsCard {
width: parent.width
iconName: "notifications_off"
title: I18n.tr("Do Not Disturb")
settingKey: "doNotDisturb"
SettingsToggleRow {
settingKey: "doNotDisturb"
tags: ["notification", "dnd", "mute", "silent", "suppress"]
text: I18n.tr("Enable Do Not Disturb")
description: I18n.tr("Suppress notification popups while enabled")
checked: SessionData.doNotDisturb
onToggled: checked => SessionData.setDoNotDisturb(checked)
}
}
SettingsCard {
id: notificationRulesCard
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();
notificationRulesCard.userToggledCollapse = true;
notificationRulesCard.expanded = true;
}
}
]
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: I18n.tr("Create rules to mute, ignore, hide from history, or override notification priority. Default only overrides priority; notifications still show normally.")
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
popupWidth: 165
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
popupWidth: 170
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
popupWidth: 165
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: "volume_off"
title: I18n.tr("Muted Apps")
settingKey: "mutedApps"
tags: ["notification", "mute", "unmute", "popup"]
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: mutedRules.length > 0 ? I18n.tr("Apps with notification popups muted. Unmute or delete to remove.") : I18n.tr("No apps muted. Right-click a notification and choose \"Mute popups\" to add one here.")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
bottomPadding: Theme.spacingS
}
Repeater {
model: mutedRules
delegate: Rectangle {
width: parent.width
height: mutedRow.implicitHeight + Theme.spacingS * 2
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainer, 0.5)
Row {
id: mutedRow
anchors.fill: parent
anchors.margins: Theme.spacingS
spacing: Theme.spacingM
StyledText {
id: mutedAppLabel
text: (modelData.rule && modelData.rule.pattern) ? modelData.rule.pattern : I18n.tr("Unknown")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: Math.max(0, parent.width - parent.spacing - mutedAppLabel.width - unmuteBtn.width - deleteBtn.width - Theme.spacingS * 5)
height: 1
}
DankButton {
id: unmuteBtn
text: I18n.tr("Unmute")
backgroundColor: Theme.surfaceContainer
textColor: Theme.primary
onClicked: SettingsData.removeNotificationRule(modelData.index)
}
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(modelData.index)
}
}
}
}
}
}
}
SettingsCard {
width: parent.width
iconName: "lock"
title: I18n.tr("Lock Screen", "lock screen notifications settings card")
settingKey: "lockScreenNotifications"
SettingsDropdownRow {
settingKey: "lockScreenNotificationMode"
tags: ["lock", "screen", "notification", "notifications", "privacy"]
text: I18n.tr("Notification Display", "lock screen notification privacy setting")
description: I18n.tr("Control what notification information is shown on the lock screen", "lock screen notification privacy setting")
options: [I18n.tr("Disabled", "lock screen notification mode option"), I18n.tr("Count Only", "lock screen notification mode option"), I18n.tr("App Names", "lock screen notification mode option"), I18n.tr("Full Content", "lock screen notification mode option")]
currentValue: options[SettingsData.lockScreenNotificationMode] || options[0]
onValueChanged: value => {
const idx = options.indexOf(value);
if (idx >= 0) {
SettingsData.set("lockScreenNotificationMode", idx);
}
}
}
}
SettingsCard {
width: parent.width
iconName: "timer"
title: I18n.tr("Notification Timeouts")
settingKey: "notificationTimeouts"
collapsible: true
expanded: false
SettingsDropdownRow {
settingKey: "notificationTimeoutLow"
tags: ["notification", "timeout", "low", "priority", "duration"]
text: I18n.tr("Low Priority")
description: I18n.tr("Timeout for low priority notifications")
currentValue: root.getTimeoutText(SettingsData.notificationTimeoutLow)
options: root.timeoutOptions.map(opt => opt.text)
onValueChanged: value => {
for (let i = 0; i < root.timeoutOptions.length; i++) {
if (root.timeoutOptions[i].text === value) {
SettingsData.set("notificationTimeoutLow", root.timeoutOptions[i].value);
break;
}
}
}
}
SettingsDropdownRow {
settingKey: "notificationTimeoutNormal"
tags: ["notification", "timeout", "normal", "priority", "duration"]
text: I18n.tr("Normal Priority")
description: I18n.tr("Timeout for normal priority notifications")
currentValue: root.getTimeoutText(SettingsData.notificationTimeoutNormal)
options: root.timeoutOptions.map(opt => opt.text)
onValueChanged: value => {
for (let i = 0; i < root.timeoutOptions.length; i++) {
if (root.timeoutOptions[i].text === value) {
SettingsData.set("notificationTimeoutNormal", root.timeoutOptions[i].value);
break;
}
}
}
}
SettingsDropdownRow {
settingKey: "notificationTimeoutCritical"
tags: ["notification", "timeout", "critical", "priority", "duration"]
text: I18n.tr("Critical Priority")
description: I18n.tr("Timeout for critical priority notifications")
currentValue: root.getTimeoutText(SettingsData.notificationTimeoutCritical)
options: root.timeoutOptions.map(opt => opt.text)
onValueChanged: value => {
for (let i = 0; i < root.timeoutOptions.length; i++) {
if (root.timeoutOptions[i].text === value) {
SettingsData.set("notificationTimeoutCritical", root.timeoutOptions[i].value);
break;
}
}
}
}
}
SettingsCard {
width: parent.width
iconName: "history"
title: I18n.tr("History Settings")
settingKey: "notificationHistory"
SettingsToggleRow {
settingKey: "notificationHistoryEnabled"
tags: ["notification", "history", "enable", "disable", "save"]
text: I18n.tr("Enable History", "notification history toggle label")
description: I18n.tr("Save dismissed notifications to history", "notification history toggle description")
checked: SettingsData.notificationHistoryEnabled
onToggled: checked => SettingsData.set("notificationHistoryEnabled", checked)
}
SettingsSliderRow {
settingKey: "notificationHistoryMaxCount"
tags: ["notification", "history", "max", "count", "limit"]
text: I18n.tr("Maximum History")
description: I18n.tr("Maximum number of notifications to keep", "notification history limit")
value: SettingsData.notificationHistoryMaxCount
minimum: 10
maximum: 200
step: 10
unit: ""
defaultValue: 50
onSliderValueChanged: newValue => SettingsData.set("notificationHistoryMaxCount", newValue)
}
SettingsDropdownRow {
settingKey: "notificationHistoryMaxAgeDays"
tags: ["notification", "history", "max", "age", "days", "retention"]
text: I18n.tr("History Retention", "notification history retention settings label")
description: I18n.tr("Auto-delete notifications older than this", "notification history setting")
currentValue: {
switch (SettingsData.notificationHistoryMaxAgeDays) {
case 0:
return I18n.tr("Forever", "notification history retention option");
case 1:
return I18n.tr("1 day", "notification history retention option");
case 3:
return I18n.tr("3 days", "notification history retention option");
case 7:
return I18n.tr("7 days", "notification history retention option");
case 14:
return I18n.tr("14 days", "notification history retention option");
case 30:
return I18n.tr("30 days", "notification history retention option");
default:
return SettingsData.notificationHistoryMaxAgeDays + " " + I18n.tr("days");
}
}
options: [I18n.tr("Forever", "notification history retention option"), I18n.tr("1 day", "notification history retention option"), I18n.tr("3 days", "notification history retention option"), I18n.tr("7 days", "notification history retention option"), I18n.tr("14 days", "notification history retention option"), I18n.tr("30 days", "notification history retention option")]
onValueChanged: value => {
let days = 7;
if (value === I18n.tr("Forever", "notification history retention option"))
days = 0;
else if (value === I18n.tr("1 day", "notification history retention option"))
days = 1;
else if (value === I18n.tr("3 days", "notification history retention option"))
days = 3;
else if (value === I18n.tr("7 days", "notification history retention option"))
days = 7;
else if (value === I18n.tr("14 days", "notification history retention option"))
days = 14;
else if (value === I18n.tr("30 days", "notification history retention option"))
days = 30;
SettingsData.set("notificationHistoryMaxAgeDays", days);
}
}
SettingsToggleRow {
settingKey: "notificationHistorySaveLow"
tags: ["notification", "history", "save", "low", "priority"]
text: I18n.tr("Low Priority")
description: I18n.tr("Save low priority notifications to history", "notification history setting")
checked: SettingsData.notificationHistorySaveLow
onToggled: checked => SettingsData.set("notificationHistorySaveLow", checked)
}
SettingsToggleRow {
settingKey: "notificationHistorySaveNormal"
tags: ["notification", "history", "save", "normal", "priority"]
text: I18n.tr("Normal Priority")
description: I18n.tr("Save normal priority notifications to history", "notification history setting")
checked: SettingsData.notificationHistorySaveNormal
onToggled: checked => SettingsData.set("notificationHistorySaveNormal", checked)
}
SettingsToggleRow {
settingKey: "notificationHistorySaveCritical"
tags: ["notification", "history", "save", "critical", "priority"]
text: I18n.tr("Critical Priority")
description: I18n.tr("Save critical priority notifications to history", "notification history setting")
checked: SettingsData.notificationHistorySaveCritical
onToggled: checked => SettingsData.set("notificationHistorySaveCritical", checked)
}
}
}
}
}