nosignal-shell/modules/controlcenter/notifications/NotificationsPane.qml
2026-04-11 22:17:24 +10:00

427 lines
17 KiB
QML

pragma ComponentBehavior: Bound
import ".."
import "../components"
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
import Caelestia.Config
import qs.components
import qs.components.containers
import qs.components.controls
import qs.components.effects
import qs.services
Item {
id: root
required property Session session
property bool notificationsExpire: Config.notifs.expire ?? true
property string notificationsFullscreen: Config.notifs.fullscreen ?? "on"
property bool notificationsOpenExpanded: Config.notifs.openExpanded ?? false
property int notificationsDefaultExpireTimeout: Config.notifs.defaultExpireTimeout ?? 5000
property int notificationsGroupPreviewNum: Config.notifs.groupPreviewNum ?? 3
property int maxToasts: Config.utilities.maxToasts ?? 4
property string toastsFullscreen: Config.utilities.toasts.fullscreen ?? "off"
property bool chargingChanged: Config.utilities.toasts.chargingChanged ?? true
property bool gameModeChanged: Config.utilities.toasts.gameModeChanged ?? true
property bool dndChanged: Config.utilities.toasts.dndChanged ?? true
property bool audioOutputChanged: Config.utilities.toasts.audioOutputChanged ?? true
property bool audioInputChanged: Config.utilities.toasts.audioInputChanged ?? true
property bool capsLockChanged: Config.utilities.toasts.capsLockChanged ?? true
property bool numLockChanged: Config.utilities.toasts.numLockChanged ?? true
property bool kbLayoutChanged: Config.utilities.toasts.kbLayoutChanged ?? true
property bool vpnChanged: Config.utilities.toasts.vpnChanged ?? true
property bool nowPlaying: Config.utilities.toasts.nowPlaying ?? false
function saveConfig(): void {
Config.notifs.expire = root.notificationsExpire;
Config.notifs.fullscreen = root.notificationsFullscreen;
Config.notifs.openExpanded = root.notificationsOpenExpanded;
Config.notifs.defaultExpireTimeout = root.notificationsDefaultExpireTimeout;
Config.notifs.groupPreviewNum = root.notificationsGroupPreviewNum;
Config.utilities.maxToasts = root.maxToasts;
Config.utilities.toasts.fullscreen = root.toastsFullscreen;
Config.utilities.toasts.chargingChanged = root.chargingChanged;
Config.utilities.toasts.gameModeChanged = root.gameModeChanged;
Config.utilities.toasts.dndChanged = root.dndChanged;
Config.utilities.toasts.audioOutputChanged = root.audioOutputChanged;
Config.utilities.toasts.audioInputChanged = root.audioInputChanged;
Config.utilities.toasts.capsLockChanged = root.capsLockChanged;
Config.utilities.toasts.numLockChanged = root.numLockChanged;
Config.utilities.toasts.kbLayoutChanged = root.kbLayoutChanged;
Config.utilities.toasts.vpnChanged = root.vpnChanged;
Config.utilities.toasts.nowPlaying = root.nowPlaying;
Config.save();
}
anchors.fill: parent
ClippingRectangle {
id: notificationsClippingRect
anchors.fill: parent
anchors.margins: Tokens.padding.normal
anchors.leftMargin: 0
anchors.rightMargin: Tokens.padding.normal
color: "transparent"
radius: notificationsBorder.innerRadius
Loader {
id: notificationsLoader
anchors.fill: parent
anchors.margins: Tokens.padding.large + Tokens.padding.normal
anchors.leftMargin: Tokens.padding.large
anchors.rightMargin: Tokens.padding.large
sourceComponent: notificationsContentComponent
}
}
InnerBorder {
id: notificationsBorder
leftThickness: 0
rightThickness: Tokens.padding.normal
}
Component {
id: notificationsContentComponent
StyledFlickable {
id: notificationsFlickable
flickableDirection: Flickable.VerticalFlick
contentHeight: notificationsLayout.height
StyledScrollBar.vertical: StyledScrollBar {
flickable: notificationsFlickable
}
RowLayout {
id: notificationsLayout
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
spacing: Tokens.spacing.normal
ColumnLayout {
Layout.fillWidth: true
Layout.maximumWidth: 500
Layout.alignment: Qt.AlignTop
spacing: Tokens.spacing.normal
SectionContainer {
Layout.fillWidth: true
alignTop: true
StyledText {
text: qsTr("Notifications")
font.pointSize: Tokens.font.size.normal
}
SplitButtonRow {
id: notificationsFullscreenSelector
function syncActiveItem(): void {
active = root.notificationsFullscreen === "off" ? notificationsFullscreenOffItem : notificationsFullscreenOnItem;
}
label: qsTr("Show in fullscreen")
menuItems: [notificationsFullscreenOffItem, notificationsFullscreenOnItem]
Component.onCompleted: syncActiveItem()
Connections {
function onNotificationsFullscreenChanged(): void {
notificationsFullscreenSelector.syncActiveItem();
}
target: root
}
MenuItem {
id: notificationsFullscreenOffItem
text: qsTr("Off")
icon: "notifications_off"
activeText: qsTr("Off")
onClicked: {
root.notificationsFullscreen = "off";
root.saveConfig();
}
}
MenuItem {
id: notificationsFullscreenOnItem
text: qsTr("On")
icon: "notifications"
activeText: qsTr("On")
onClicked: {
root.notificationsFullscreen = "on";
root.saveConfig();
}
}
}
SwitchRow {
label: qsTr("Expire automatically")
checked: root.notificationsExpire
onToggled: checked => {
root.notificationsExpire = checked;
root.saveConfig();
}
}
SwitchRow {
label: qsTr("Open expanded")
checked: root.notificationsOpenExpanded
onToggled: checked => {
root.notificationsOpenExpanded = checked;
root.saveConfig();
}
}
SpinBoxRow {
label: qsTr("Default timeout")
value: root.notificationsDefaultExpireTimeout
min: 1000
max: 60000
step: 500
onValueModified: value => {
root.notificationsDefaultExpireTimeout = value;
root.saveConfig();
}
}
SpinBoxRow {
label: qsTr("Group preview count")
value: root.notificationsGroupPreviewNum
min: 1
max: 10
step: 1
onValueModified: value => {
root.notificationsGroupPreviewNum = value;
root.saveConfig();
}
}
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
spacing: Tokens.spacing.normal
SectionContainer {
Layout.fillWidth: true
alignTop: true
StyledText {
text: qsTr("Toast settings")
font.pointSize: Tokens.font.size.normal
}
SplitButtonRow {
id: toastFullscreenSelector
function syncActiveItem(): void {
if (root.toastsFullscreen === "all") {
active = toastFullscreenAllItem;
return;
}
if (root.toastsFullscreen === "important") {
active = toastFullscreenImportantItem;
return;
}
active = toastFullscreenOffItem;
}
Layout.fillWidth: true
z: expanded ? 100 : 0
label: qsTr("Show in fullscreen")
menuItems: [toastFullscreenOffItem, toastFullscreenImportantItem, toastFullscreenAllItem]
Component.onCompleted: syncActiveItem()
Connections {
function onToastsFullscreenChanged(): void {
toastFullscreenSelector.syncActiveItem();
}
target: root
}
MenuItem {
id: toastFullscreenOffItem
text: qsTr("Off")
icon: "notifications_off"
activeText: qsTr("Off")
onClicked: {
root.toastsFullscreen = "off";
root.saveConfig();
}
}
MenuItem {
id: toastFullscreenImportantItem
text: qsTr("Important")
icon: "priority_high"
activeText: qsTr("Important")
onClicked: {
root.toastsFullscreen = "important";
root.saveConfig();
}
}
MenuItem {
id: toastFullscreenAllItem
text: qsTr("On")
icon: "notifications"
activeText: qsTr("On")
onClicked: {
root.toastsFullscreen = "all";
root.saveConfig();
}
}
}
SpinBoxRow {
Layout.fillWidth: true
label: qsTr("Visible toasts")
value: root.maxToasts
min: 1
max: 10
step: 1
onValueModified: value => {
root.maxToasts = value;
root.saveConfig();
}
}
GridLayout {
Layout.fillWidth: true
columns: 2
columnSpacing: Tokens.spacing.normal
rowSpacing: Tokens.spacing.normal
SwitchRow {
Layout.fillWidth: true
label: qsTr("Charging changes")
checked: root.chargingChanged
onToggled: checked => {
root.chargingChanged = checked;
root.saveConfig();
}
}
SwitchRow {
Layout.fillWidth: true
label: qsTr("Game mode changes")
checked: root.gameModeChanged
onToggled: checked => {
root.gameModeChanged = checked;
root.saveConfig();
}
}
SwitchRow {
Layout.fillWidth: true
label: qsTr("Do not disturb")
checked: root.dndChanged
onToggled: checked => {
root.dndChanged = checked;
root.saveConfig();
}
}
SwitchRow {
Layout.fillWidth: true
label: qsTr("Audio output changes")
checked: root.audioOutputChanged
onToggled: checked => {
root.audioOutputChanged = checked;
root.saveConfig();
}
}
SwitchRow {
Layout.fillWidth: true
label: qsTr("Audio input changes")
checked: root.audioInputChanged
onToggled: checked => {
root.audioInputChanged = checked;
root.saveConfig();
}
}
SwitchRow {
Layout.fillWidth: true
label: qsTr("Caps lock changes")
checked: root.capsLockChanged
onToggled: checked => {
root.capsLockChanged = checked;
root.saveConfig();
}
}
SwitchRow {
Layout.fillWidth: true
label: qsTr("Num lock changes")
checked: root.numLockChanged
onToggled: checked => {
root.numLockChanged = checked;
root.saveConfig();
}
}
SwitchRow {
Layout.fillWidth: true
label: qsTr("Keyboard layout changes")
checked: root.kbLayoutChanged
onToggled: checked => {
root.kbLayoutChanged = checked;
root.saveConfig();
}
}
SwitchRow {
Layout.fillWidth: true
label: qsTr("VPN changes")
checked: root.vpnChanged
onToggled: checked => {
root.vpnChanged = checked;
root.saveConfig();
}
}
SwitchRow {
Layout.fillWidth: true
label: qsTr("Now playing")
checked: root.nowPlaying
onToggled: checked => {
root.nowPlaying = checked;
root.saveConfig();
}
}
}
}
}
}
}
}
}