add noctalia and fuzzel
This commit is contained in:
+62
@@ -0,0 +1,62 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: Style.marginL
|
||||
Layout.fillWidth: true
|
||||
enabled: Settings.data.notifications.enabled
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("panels.notifications.duration-respect-expire-label")
|
||||
description: I18n.tr("panels.notifications.duration-respect-expire-description")
|
||||
checked: Settings.data.notifications.respectExpireTimeout
|
||||
onToggled: checked => Settings.data.notifications.respectExpireTimeout = checked
|
||||
defaultValue: Settings.getDefaultValue("notifications.respectExpireTimeout")
|
||||
}
|
||||
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.notifications.duration-low-urgency-label")
|
||||
description: I18n.tr("panels.notifications.duration-low-urgency-description")
|
||||
from: 1
|
||||
to: 30
|
||||
stepSize: 1
|
||||
showReset: true
|
||||
value: Settings.data.notifications.lowUrgencyDuration
|
||||
onMoved: value => Settings.data.notifications.lowUrgencyDuration = value
|
||||
text: Settings.data.notifications.lowUrgencyDuration + "s"
|
||||
defaultValue: Settings.getDefaultValue("notifications.lowUrgencyDuration")
|
||||
}
|
||||
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.notifications.duration-normal-urgency-label")
|
||||
description: I18n.tr("panels.notifications.duration-normal-urgency-description")
|
||||
from: 1
|
||||
to: 30
|
||||
stepSize: 1
|
||||
showReset: true
|
||||
value: Settings.data.notifications.normalUrgencyDuration
|
||||
onMoved: value => Settings.data.notifications.normalUrgencyDuration = value
|
||||
text: Settings.data.notifications.normalUrgencyDuration + "s"
|
||||
defaultValue: Settings.getDefaultValue("notifications.normalUrgencyDuration")
|
||||
}
|
||||
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.notifications.duration-critical-urgency-label")
|
||||
description: I18n.tr("panels.notifications.duration-critical-urgency-description")
|
||||
from: 1
|
||||
to: 30
|
||||
stepSize: 1
|
||||
showReset: true
|
||||
value: Settings.data.notifications.criticalUrgencyDuration
|
||||
onMoved: value => Settings.data.notifications.criticalUrgencyDuration = value
|
||||
text: Settings.data.notifications.criticalUrgencyDuration + "s"
|
||||
defaultValue: Settings.getDefaultValue("notifications.criticalUrgencyDuration")
|
||||
}
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services.Compositor
|
||||
import qs.Services.System
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: Style.marginL
|
||||
Layout.fillWidth: true
|
||||
|
||||
property var addMonitor
|
||||
property var removeMonitor
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("panels.notifications.settings-enabled-label")
|
||||
description: I18n.tr("panels.notifications.settings-enabled-description")
|
||||
checked: Settings.data.notifications.enabled !== false
|
||||
onToggled: checked => Settings.data.notifications.enabled = checked
|
||||
defaultValue: Settings.getDefaultValue("notifications.enabled")
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Style.marginL
|
||||
enabled: Settings.data.notifications.enabled
|
||||
|
||||
NComboBox {
|
||||
label: I18n.tr("panels.notifications.settings-density-label")
|
||||
description: I18n.tr("panels.notifications.settings-density-description")
|
||||
model: [
|
||||
{
|
||||
"key": "default",
|
||||
"name": I18n.tr("options.notification-density.default")
|
||||
},
|
||||
{
|
||||
"key": "compact",
|
||||
"name": I18n.tr("options.notification-density.compact")
|
||||
}
|
||||
]
|
||||
currentKey: Settings.data.notifications.density || "default"
|
||||
onSelected: key => Settings.data.notifications.density = key
|
||||
defaultValue: Settings.getDefaultValue("notifications.density")
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("tooltips.do-not-disturb-enabled")
|
||||
description: I18n.tr("panels.notifications.settings-do-not-disturb-description")
|
||||
checked: NotificationService.doNotDisturb
|
||||
onToggled: checked => NotificationService.doNotDisturb = checked
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
label: I18n.tr("common.position")
|
||||
description: I18n.tr("panels.notifications.settings-location-description")
|
||||
model: [
|
||||
{
|
||||
"key": "top",
|
||||
"name": I18n.tr("positions.top-center")
|
||||
},
|
||||
{
|
||||
"key": "top_left",
|
||||
"name": I18n.tr("positions.top-left")
|
||||
},
|
||||
{
|
||||
"key": "top_right",
|
||||
"name": I18n.tr("positions.top-right")
|
||||
},
|
||||
{
|
||||
"key": "bottom",
|
||||
"name": I18n.tr("positions.bottom-center")
|
||||
},
|
||||
{
|
||||
"key": "bottom_left",
|
||||
"name": I18n.tr("positions.bottom-left")
|
||||
},
|
||||
{
|
||||
"key": "bottom_right",
|
||||
"name": I18n.tr("positions.bottom-right")
|
||||
}
|
||||
]
|
||||
currentKey: Settings.data.notifications.location || "top_right"
|
||||
onSelected: key => Settings.data.notifications.location = key
|
||||
defaultValue: Settings.getDefaultValue("notifications.location")
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("panels.osd.always-on-top-label")
|
||||
description: I18n.tr("panels.notifications.settings-always-on-top-description")
|
||||
checked: Settings.data.notifications.overlayLayer
|
||||
onToggled: checked => Settings.data.notifications.overlayLayer = checked
|
||||
defaultValue: Settings.getDefaultValue("notifications.overlayLayer")
|
||||
}
|
||||
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.osd.background-opacity-label")
|
||||
description: I18n.tr("panels.notifications.settings-background-opacity-description")
|
||||
from: 0
|
||||
to: 1
|
||||
stepSize: 0.01
|
||||
showReset: true
|
||||
value: Settings.data.notifications.backgroundOpacity
|
||||
onMoved: value => Settings.data.notifications.backgroundOpacity = value
|
||||
text: Math.round(Settings.data.notifications.backgroundOpacity * 100) + "%"
|
||||
defaultValue: Settings.getDefaultValue("notifications.backgroundOpacity")
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NText {
|
||||
text: I18n.tr("panels.notifications.monitors-desc")
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: Quickshell.screens || []
|
||||
delegate: NCheckbox {
|
||||
Layout.fillWidth: true
|
||||
readonly property real compositorScale: {
|
||||
const info = CompositorService.displayScales[modelData.name];
|
||||
return (info && info.scale) ? info.scale : 1.0;
|
||||
}
|
||||
label: modelData.name || I18n.tr("common.unknown")
|
||||
description: {
|
||||
I18n.tr("system.monitor-description", {
|
||||
"model": modelData.model,
|
||||
"width": modelData.width * compositorScale,
|
||||
"height": modelData.height * compositorScale,
|
||||
"scale": compositorScale
|
||||
});
|
||||
}
|
||||
checked: (Settings.data.notifications.monitors || []).indexOf(modelData.name) !== -1
|
||||
onToggled: checked => {
|
||||
if (checked) {
|
||||
Settings.data.notifications.monitors = root.addMonitor(Settings.data.notifications.monitors, modelData.name);
|
||||
} else {
|
||||
Settings.data.notifications.monitors = root.removeMonitor(Settings.data.notifications.monitors, modelData.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: Style.marginL
|
||||
Layout.fillWidth: true
|
||||
enabled: Settings.data.notifications.enabled
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("panels.notifications.history-clear-dismiss-label")
|
||||
description: I18n.tr("panels.notifications.history-clear-dismiss-description")
|
||||
checked: Settings.data.notifications.clearDismissed
|
||||
onToggled: checked => Settings.data.notifications.clearDismissed = checked
|
||||
defaultValue: Settings.getDefaultValue("notifications.clearDismissed")
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("panels.notifications.settings-markdown-label")
|
||||
description: I18n.tr("panels.notifications.settings-markdown-description")
|
||||
checked: Settings.data.notifications.enableMarkdown
|
||||
onToggled: checked => Settings.data.notifications.enableMarkdown = checked
|
||||
defaultValue: Settings.getDefaultValue("notifications.enableMarkdown")
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("panels.notifications.history-low-urgency-label")
|
||||
description: I18n.tr("panels.notifications.history-low-urgency-description")
|
||||
checked: Settings.data.notifications?.saveToHistory?.low !== false
|
||||
onToggled: checked => Settings.data.notifications.saveToHistory.low = checked
|
||||
defaultValue: Settings.getDefaultValue("notifications.saveToHistory.low")
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("panels.notifications.history-normal-urgency-label")
|
||||
description: I18n.tr("panels.notifications.history-normal-urgency-description")
|
||||
checked: Settings.data.notifications?.saveToHistory?.normal !== false
|
||||
onToggled: checked => Settings.data.notifications.saveToHistory.normal = checked
|
||||
defaultValue: Settings.getDefaultValue("notifications.saveToHistory.normal")
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("panels.notifications.history-critical-urgency-label")
|
||||
description: I18n.tr("panels.notifications.history-critical-urgency-description")
|
||||
checked: Settings.data.notifications?.saveToHistory?.critical !== false
|
||||
onToggled: checked => Settings.data.notifications.saveToHistory.critical = checked
|
||||
defaultValue: Settings.getDefaultValue("notifications.saveToHistory.critical")
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Services.System
|
||||
import qs.Widgets
|
||||
|
||||
Popup {
|
||||
id: root
|
||||
modal: true
|
||||
closePolicy: Popup.NoAutoClose
|
||||
dim: true
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: Math.min(500 * Style.uiScaleRatio, parent.width * 0.9)
|
||||
padding: Style.marginL
|
||||
|
||||
property int editIndex: -1
|
||||
property string patternValue: ""
|
||||
property string actionValue: "block"
|
||||
|
||||
signal saved(string pattern, string action)
|
||||
|
||||
property var _savedSlot: null
|
||||
property string _selectedAction: "block"
|
||||
|
||||
background: Rectangle {
|
||||
color: Color.mSurface
|
||||
radius: Style.radiusL
|
||||
border.color: Color.mOutline
|
||||
border.width: Style.borderS
|
||||
}
|
||||
|
||||
onOpened: {
|
||||
patternInput.text = patternValue;
|
||||
actionCombo.currentKey = actionValue;
|
||||
_selectedAction = actionValue;
|
||||
patternInput.forceActiveFocus();
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
id: contentLayout
|
||||
spacing: Style.marginL
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
NText {
|
||||
text: editIndex >= 0 ? I18n.tr("panels.notifications.rules-edit") : I18n.tr("panels.notifications.rules-add")
|
||||
font.weight: Style.fontWeightBold
|
||||
pointSize: Style.fontSizeL
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
onClicked: root.close()
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginM
|
||||
|
||||
NTextInput {
|
||||
id: patternInput
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.notifications.rules-pattern-label")
|
||||
placeholderText: I18n.tr("panels.notifications.rules-pattern-placeholder")
|
||||
fontFamily: Settings.data.ui.fontFixed
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
id: actionCombo
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.notifications.rules-action-label")
|
||||
model: [
|
||||
{
|
||||
"key": "block",
|
||||
"name": I18n.tr("panels.notifications.rules-action-block")
|
||||
},
|
||||
{
|
||||
"key": "mute",
|
||||
"name": I18n.tr("panels.notifications.rules-action-mute")
|
||||
},
|
||||
{
|
||||
"key": "hide",
|
||||
"name": I18n.tr("panels.notifications.rules-action-hide")
|
||||
}
|
||||
]
|
||||
currentKey: actionValue
|
||||
onSelected: key => {
|
||||
actionValue = key;
|
||||
_selectedAction = key;
|
||||
}
|
||||
}
|
||||
|
||||
NLabel {
|
||||
Layout.fillWidth: true
|
||||
label: _selectedAction === "block" ? I18n.tr("panels.notifications.rules-action-block-desc") : (_selectedAction === "mute" ? I18n.tr("panels.notifications.rules-action-mute-desc") : I18n.tr("panels.notifications.rules-action-hide-desc"))
|
||||
labelColor: Color.mOnSurfaceVariant
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginM
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NButton {
|
||||
text: I18n.tr("common.cancel")
|
||||
outlined: true
|
||||
onClicked: root.close()
|
||||
}
|
||||
|
||||
NButton {
|
||||
text: I18n.tr("common.save")
|
||||
icon: "check"
|
||||
backgroundColor: Color.mPrimary
|
||||
textColor: Color.mOnPrimary
|
||||
enabled: patternInput.text.trim() !== ""
|
||||
onClicked: {
|
||||
root.saved(patternInput.text.trim(), _selectedAction || "block");
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: 0
|
||||
|
||||
// Helper functions to update arrays immutably
|
||||
function addMonitor(list, name) {
|
||||
const arr = (list || []).slice();
|
||||
if (!arr.includes(name))
|
||||
arr.push(name);
|
||||
return arr;
|
||||
}
|
||||
function removeMonitor(list, name) {
|
||||
return (list || []).filter(function (n) {
|
||||
return n !== name;
|
||||
});
|
||||
}
|
||||
|
||||
// File pickers for sound sub-tab
|
||||
function openUnifiedSoundPicker() {
|
||||
unifiedSoundFilePicker.open();
|
||||
}
|
||||
function openLowSoundPicker() {
|
||||
lowSoundFilePicker.open();
|
||||
}
|
||||
function openNormalSoundPicker() {
|
||||
normalSoundFilePicker.open();
|
||||
}
|
||||
function openCriticalSoundPicker() {
|
||||
criticalSoundFilePicker.open();
|
||||
}
|
||||
|
||||
NTabBar {
|
||||
id: subTabBar
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.marginM
|
||||
distributeEvenly: false // this is too cramped on this tab to split evenly
|
||||
currentIndex: tabView.currentIndex
|
||||
|
||||
NTabButton {
|
||||
text: I18n.tr("common.appearance")
|
||||
tabIndex: 0
|
||||
checked: subTabBar.currentIndex === 0
|
||||
}
|
||||
NTabButton {
|
||||
text: I18n.tr("common.duration")
|
||||
tabIndex: 1
|
||||
checked: subTabBar.currentIndex === 1
|
||||
}
|
||||
NTabButton {
|
||||
text: I18n.tr("common.history")
|
||||
tabIndex: 2
|
||||
checked: subTabBar.currentIndex === 2
|
||||
}
|
||||
NTabButton {
|
||||
text: I18n.tr("common.sound")
|
||||
tabIndex: 3
|
||||
checked: subTabBar.currentIndex === 3
|
||||
}
|
||||
NTabButton {
|
||||
text: I18n.tr("common.toast")
|
||||
tabIndex: 4
|
||||
checked: subTabBar.currentIndex === 4
|
||||
}
|
||||
NTabButton {
|
||||
text: I18n.tr("panels.notifications.rules-tab")
|
||||
tabIndex: 5
|
||||
checked: subTabBar.currentIndex === 5
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Style.marginL
|
||||
}
|
||||
|
||||
NTabView {
|
||||
id: tabView
|
||||
currentIndex: subTabBar.currentIndex
|
||||
|
||||
GeneralSubTab {
|
||||
addMonitor: root.addMonitor
|
||||
removeMonitor: root.removeMonitor
|
||||
}
|
||||
DurationSubTab {}
|
||||
HistorySubTab {}
|
||||
SoundSubTab {
|
||||
onOpenUnifiedPicker: root.openUnifiedSoundPicker()
|
||||
onOpenLowPicker: root.openLowSoundPicker()
|
||||
onOpenNormalPicker: root.openNormalSoundPicker()
|
||||
onOpenCriticalPicker: root.openCriticalSoundPicker()
|
||||
}
|
||||
ToastSubTab {}
|
||||
RulesSubTab {}
|
||||
}
|
||||
|
||||
// File Pickers for Sound Files
|
||||
NFilePicker {
|
||||
id: unifiedSoundFilePicker
|
||||
title: I18n.tr("panels.notifications.sounds-files-unified-select-title")
|
||||
selectionMode: "files"
|
||||
initialPath: Quickshell.env("HOME")
|
||||
nameFilters: ["*.wav", "*.mp3", "*.ogg", "*.flac", "*.m4a", "*.aac"]
|
||||
onAccepted: paths => {
|
||||
if (paths.length > 0) {
|
||||
const soundPath = paths[0];
|
||||
Settings.data.notifications.sounds.normalSoundFile = soundPath;
|
||||
Settings.data.notifications.sounds.lowSoundFile = soundPath;
|
||||
Settings.data.notifications.sounds.criticalSoundFile = soundPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NFilePicker {
|
||||
id: lowSoundFilePicker
|
||||
title: I18n.tr("panels.notifications.sounds-files-low-select-title")
|
||||
selectionMode: "files"
|
||||
initialPath: Quickshell.env("HOME")
|
||||
nameFilters: ["*.wav", "*.mp3", "*.ogg", "*.flac", "*.m4a", "*.aac"]
|
||||
onAccepted: paths => {
|
||||
if (paths.length > 0) {
|
||||
Settings.data.notifications.sounds.lowSoundFile = paths[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NFilePicker {
|
||||
id: normalSoundFilePicker
|
||||
title: I18n.tr("panels.notifications.sounds-files-normal-select-title")
|
||||
selectionMode: "files"
|
||||
initialPath: Quickshell.env("HOME")
|
||||
nameFilters: ["*.wav", "*.mp3", "*.ogg", "*.flac", "*.m4a", "*.aac"]
|
||||
onAccepted: paths => {
|
||||
if (paths.length > 0) {
|
||||
Settings.data.notifications.sounds.normalSoundFile = paths[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NFilePicker {
|
||||
id: criticalSoundFilePicker
|
||||
title: I18n.tr("panels.notifications.sounds-files-critical-select-title")
|
||||
selectionMode: "files"
|
||||
initialPath: Quickshell.env("HOME")
|
||||
nameFilters: ["*.wav", "*.mp3", "*.ogg", "*.flac", "*.m4a", "*.aac"]
|
||||
onAccepted: paths => {
|
||||
if (paths.length > 0) {
|
||||
Settings.data.notifications.sounds.criticalSoundFile = paths[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Services.System
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: Style.marginL
|
||||
Layout.fillWidth: true
|
||||
enabled: Settings.data.notifications.enabled
|
||||
|
||||
function _saveToService() {
|
||||
NotificationRulesService.save();
|
||||
}
|
||||
|
||||
function _removeRule(index) {
|
||||
var arr = (NotificationRulesService.rules || []).slice();
|
||||
arr.splice(index, 1);
|
||||
NotificationRulesService.rules = arr;
|
||||
_saveToService();
|
||||
}
|
||||
|
||||
NotificationRuleEditPopup {
|
||||
id: editPopup
|
||||
parent: Overlay.overlay
|
||||
}
|
||||
|
||||
function openEdit(index, patternVal, actionVal) {
|
||||
editPopup.editIndex = index;
|
||||
editPopup.patternValue = patternVal || "";
|
||||
editPopup.actionValue = actionVal || "block";
|
||||
|
||||
try {
|
||||
editPopup.saved.disconnect(editPopup._savedSlot);
|
||||
} catch (e) {}
|
||||
|
||||
editPopup._savedSlot = function (pattern, action) {
|
||||
const trimmed = (pattern || "").trim();
|
||||
if (trimmed === "")
|
||||
return;
|
||||
var arr = (NotificationRulesService.rules || []).slice();
|
||||
var rule = {
|
||||
"pattern": trimmed,
|
||||
"action": action
|
||||
};
|
||||
if (index >= 0 && index < arr.length) {
|
||||
arr[index] = rule;
|
||||
} else {
|
||||
arr.push(rule);
|
||||
}
|
||||
NotificationRulesService.rules = arr;
|
||||
_saveToService();
|
||||
};
|
||||
|
||||
editPopup.saved.connect(editPopup._savedSlot);
|
||||
editPopup.open();
|
||||
}
|
||||
|
||||
NLabel {
|
||||
label: I18n.tr("panels.notifications.rules-label")
|
||||
description: I18n.tr("panels.notifications.rules-description")
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginS
|
||||
Layout.bottomMargin: Style.marginS
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: NotificationRulesService.rules || []
|
||||
|
||||
delegate: RowLayout {
|
||||
id: entryDelegate
|
||||
required property int index
|
||||
required property var modelData
|
||||
|
||||
property string pattern: modelData.pattern || ""
|
||||
property string action: modelData.action || "block"
|
||||
property bool isRegex: pattern.length >= 3 && pattern.startsWith("/") && pattern.endsWith("/")
|
||||
|
||||
spacing: Style.marginM
|
||||
Layout.fillWidth: true
|
||||
|
||||
NLabel {
|
||||
Layout.fillWidth: true
|
||||
label: (entryDelegate.isRegex ? "regex: " : "") + entryDelegate.pattern
|
||||
description: entryDelegate.action === "block" ? I18n.tr("panels.notifications.rules-action-block") : (entryDelegate.action === "mute" ? I18n.tr("panels.notifications.rules-action-mute") : I18n.tr("panels.notifications.rules-action-hide"))
|
||||
labelColor: entryDelegate.pattern ? Color.mPrimary : Color.mOnSurface
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "settings"
|
||||
tooltipText: I18n.tr("common.edit")
|
||||
onClicked: root.openEdit(entryDelegate.index, entryDelegate.pattern, entryDelegate.action)
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "trash"
|
||||
tooltipText: I18n.tr("panels.notifications.rules-delete")
|
||||
onClicked: root._removeRule(entryDelegate.index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NButton {
|
||||
text: I18n.tr("panels.notifications.rules-add")
|
||||
icon: "add"
|
||||
enabled: Settings.data.notifications.enabled
|
||||
onClicked: root.openEdit(-1, "", "block")
|
||||
}
|
||||
}
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services.System
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: Style.marginL
|
||||
Layout.fillWidth: true
|
||||
enabled: Settings.data.notifications.enabled
|
||||
|
||||
signal openUnifiedPicker
|
||||
signal openLowPicker
|
||||
signal openNormalPicker
|
||||
signal openCriticalPicker
|
||||
|
||||
// QtMultimedia unavailable message
|
||||
NBox {
|
||||
Layout.fillWidth: true
|
||||
visible: !SoundService.multimediaAvailable
|
||||
implicitHeight: unavailableContent.implicitHeight + Style.margin2L
|
||||
|
||||
RowLayout {
|
||||
id: unavailableContent
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginL
|
||||
spacing: Style.marginM
|
||||
|
||||
NIcon {
|
||||
icon: "warning"
|
||||
color: Color.mOnSurfaceVariant
|
||||
pointSize: Style.fontSizeXL
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
NLabel {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.notifications.sounds-unavailable-label")
|
||||
description: I18n.tr("panels.notifications.sounds-unavailable-description")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
enabled: SoundService.multimediaAvailable
|
||||
label: I18n.tr("panels.notifications.sounds-enabled-label")
|
||||
description: I18n.tr("panels.notifications.sounds-enabled-description")
|
||||
checked: Settings.data.notifications?.sounds?.enabled ?? false
|
||||
onToggled: checked => Settings.data.notifications.sounds.enabled = checked
|
||||
defaultValue: Settings.getDefaultValue("notifications.sounds.enabled")
|
||||
}
|
||||
|
||||
// Sound Volume
|
||||
NValueSlider {
|
||||
enabled: SoundService.multimediaAvailable && (Settings.data.notifications?.sounds?.enabled ?? false)
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.notifications.sounds-volume-label")
|
||||
description: I18n.tr("panels.notifications.sounds-volume-description")
|
||||
from: 0
|
||||
to: 1
|
||||
stepSize: 0.01
|
||||
showReset: true
|
||||
value: Settings.data.notifications?.sounds?.volume ?? 0.5
|
||||
onMoved: value => Settings.data.notifications.sounds.volume = value
|
||||
text: Math.round((Settings.data.notifications?.sounds?.volume ?? 0.5) * 100) + "%"
|
||||
defaultValue: Settings.getDefaultValue("notifications.sounds.volume")
|
||||
}
|
||||
|
||||
// Separate Sounds Toggle
|
||||
NToggle {
|
||||
enabled: SoundService.multimediaAvailable && (Settings.data.notifications?.sounds?.enabled ?? false)
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.notifications.sounds-separate-label")
|
||||
description: I18n.tr("panels.notifications.sounds-separate-description")
|
||||
checked: Settings.data.notifications?.sounds?.separateSounds ?? false
|
||||
onToggled: checked => Settings.data.notifications.sounds.separateSounds = checked
|
||||
defaultValue: Settings.getDefaultValue("notifications.sounds.separateSounds")
|
||||
}
|
||||
|
||||
// Unified Sound File (shown when separateSounds is false)
|
||||
ColumnLayout {
|
||||
enabled: SoundService.multimediaAvailable && (Settings.data.notifications?.sounds?.enabled ?? false)
|
||||
visible: !(Settings.data.notifications?.sounds?.separateSounds ?? false)
|
||||
spacing: Style.marginXXS
|
||||
Layout.fillWidth: true
|
||||
|
||||
NLabel {
|
||||
label: I18n.tr("panels.notifications.sounds-files-unified-label")
|
||||
description: I18n.tr("panels.notifications.sounds-files-unified-description")
|
||||
}
|
||||
|
||||
NTextInputButton {
|
||||
enabled: parent.enabled
|
||||
Layout.fillWidth: true
|
||||
placeholderText: I18n.tr("panels.notifications.sounds-files-placeholder")
|
||||
text: Settings.data.notifications?.sounds?.normalSoundFile ?? ""
|
||||
buttonIcon: "folder-open"
|
||||
buttonTooltip: I18n.tr("panels.notifications.sounds-files-select-file")
|
||||
onInputTextChanged: text => {
|
||||
// When separate sounds are enabled, this row is hidden but still
|
||||
// bound to normalSoundFile; user edits to normal still update that
|
||||
// key and would re-trigger this handler and wipe low/critical.
|
||||
if (Settings.data.notifications.sounds.separateSounds) {
|
||||
return;
|
||||
}
|
||||
const soundPath = text;
|
||||
Settings.data.notifications.sounds.normalSoundFile = soundPath;
|
||||
Settings.data.notifications.sounds.lowSoundFile = soundPath;
|
||||
Settings.data.notifications.sounds.criticalSoundFile = soundPath;
|
||||
}
|
||||
onButtonClicked: root.openUnifiedPicker()
|
||||
}
|
||||
}
|
||||
|
||||
// Separate Sound Files (shown when separateSounds is true)
|
||||
ColumnLayout {
|
||||
visible: SoundService.multimediaAvailable && (Settings.data.notifications?.sounds?.enabled ?? false) && (Settings.data.notifications?.sounds?.separateSounds ?? false)
|
||||
spacing: Style.marginXXS
|
||||
Layout.fillWidth: true
|
||||
|
||||
// Low Urgency Sound File
|
||||
ColumnLayout {
|
||||
spacing: Style.marginXXS
|
||||
Layout.fillWidth: true
|
||||
|
||||
NLabel {
|
||||
label: I18n.tr("panels.notifications.sounds-files-low-label")
|
||||
description: I18n.tr("panels.notifications.sounds-files-low-description")
|
||||
}
|
||||
|
||||
NTextInputButton {
|
||||
enabled: parent.enabled
|
||||
Layout.fillWidth: true
|
||||
placeholderText: I18n.tr("panels.notifications.sounds-files-placeholder")
|
||||
text: Settings.data.notifications?.sounds?.lowSoundFile ?? ""
|
||||
buttonIcon: "folder-open"
|
||||
buttonTooltip: I18n.tr("panels.notifications.sounds-files-select-file")
|
||||
onInputTextChanged: text => Settings.data.notifications.sounds.lowSoundFile = text
|
||||
onButtonClicked: root.openLowPicker()
|
||||
}
|
||||
}
|
||||
|
||||
// Normal Urgency Sound File
|
||||
ColumnLayout {
|
||||
spacing: Style.marginXXS
|
||||
Layout.fillWidth: true
|
||||
|
||||
NLabel {
|
||||
label: I18n.tr("panels.notifications.sounds-files-normal-label")
|
||||
description: I18n.tr("panels.notifications.sounds-files-normal-description")
|
||||
}
|
||||
|
||||
NTextInputButton {
|
||||
enabled: parent.enabled
|
||||
Layout.fillWidth: true
|
||||
placeholderText: I18n.tr("panels.notifications.sounds-files-placeholder")
|
||||
text: Settings.data.notifications?.sounds?.normalSoundFile ?? ""
|
||||
buttonIcon: "folder-open"
|
||||
buttonTooltip: I18n.tr("panels.notifications.sounds-files-select-file")
|
||||
onInputTextChanged: text => Settings.data.notifications.sounds.normalSoundFile = text
|
||||
onButtonClicked: root.openNormalPicker()
|
||||
}
|
||||
}
|
||||
|
||||
// Critical Urgency Sound File
|
||||
ColumnLayout {
|
||||
spacing: Style.marginXXS
|
||||
Layout.fillWidth: true
|
||||
|
||||
NLabel {
|
||||
label: I18n.tr("panels.notifications.sounds-files-critical-label")
|
||||
description: I18n.tr("panels.notifications.sounds-files-critical-description")
|
||||
}
|
||||
|
||||
NTextInputButton {
|
||||
enabled: parent.enabled
|
||||
Layout.fillWidth: true
|
||||
placeholderText: I18n.tr("panels.notifications.sounds-files-placeholder")
|
||||
text: Settings.data.notifications?.sounds?.criticalSoundFile ?? ""
|
||||
buttonIcon: "folder-open"
|
||||
buttonTooltip: I18n.tr("panels.notifications.sounds-files-select-file")
|
||||
onInputTextChanged: text => Settings.data.notifications.sounds.criticalSoundFile = text
|
||||
onButtonClicked: root.openCriticalPicker()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Excluded Apps List
|
||||
ColumnLayout {
|
||||
enabled: SoundService.multimediaAvailable && (Settings.data.notifications?.sounds?.enabled ?? false)
|
||||
spacing: Style.marginXXS
|
||||
Layout.fillWidth: true
|
||||
|
||||
NLabel {
|
||||
label: I18n.tr("panels.notifications.sounds-excluded-apps-label")
|
||||
description: I18n.tr("panels.notifications.sounds-excluded-apps-description")
|
||||
}
|
||||
|
||||
NTextInput {
|
||||
enabled: parent.enabled
|
||||
Layout.fillWidth: true
|
||||
placeholderText: I18n.tr("panels.notifications.sounds-excluded-apps-placeholder")
|
||||
text: Settings.data.notifications?.sounds?.excludedApps ?? ""
|
||||
onTextChanged: Settings.data.notifications.sounds.excludedApps = text
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: Style.marginL
|
||||
Layout.fillWidth: true
|
||||
|
||||
NCheckbox {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.notifications.toast-media-label")
|
||||
description: I18n.tr("panels.notifications.toast-media-description")
|
||||
checked: Settings.data.notifications.enableMediaToast
|
||||
onToggled: checked => Settings.data.notifications.enableMediaToast = checked
|
||||
}
|
||||
|
||||
NCheckbox {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.notifications.toast-keyboard-label")
|
||||
description: I18n.tr("panels.notifications.toast-keyboard-description")
|
||||
checked: Settings.data.notifications.enableKeyboardLayoutToast
|
||||
onToggled: checked => Settings.data.notifications.enableKeyboardLayoutToast = checked
|
||||
}
|
||||
|
||||
NCheckbox {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.notifications.toast-battery-label")
|
||||
description: I18n.tr("panels.notifications.toast-battery-description")
|
||||
checked: Settings.data.notifications.enableBatteryToast
|
||||
onToggled: checked => Settings.data.notifications.enableBatteryToast = checked
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user