shift-shell/components/mobileshell/qml/notificationpopup/NotificationPopupProvider.qml
Micah Stanley eba6074161 notifications: Implement popup notifications
This merge request implements a more mobile optimized solution for popup notification.
- 

The current controls are:
- Swipe up to move the notification to the notification center.
- Swipe left/right to dismiss the notification entirely.
- If multiple popup notifications are grouped together, tap on the bottom area to view them in a expanded view.

What still needs to be done:
- ~~For notification without a default action, tapping on them should probably open up the associated app.~~ Note: I think I will add this in a separate merge request as it probably should be the case regardless if the notification is a popup
- ~~Swiping down on a notification currently does nothing. Maybe we should map this to a notification action?~~ Note: I have some ideas I will try later, though for now, I will leave this action blank
- ~~The expanded view of notifications should be able to be dismissed by swiping up/down on the top/bottom of the list.~~ Note: Added
- Investigate further into how to remove the current desktop popup notifications.
- ~~Code clean up.~~ Note: The code is at least a bit better

Single popup notification:

![notification_1](/uploads/63d12be6da1dd2676de17940dcadbdfa/notification_1.gif)

Multiple popup notifications:

![notification_2](/uploads/907a14b772f66f46040c28342f4dcf02/notification_2.gif)

Multiple popup notifications in the expanded view:

![notification_3](/uploads/9a7cd09a6bb8a0f7ee70e5bcf7c29c6b/notification_3.gif)

Any feedback would be greatly appreciated.
2024-11-07 16:13:06 +00:00

143 lines
4.7 KiB
QML

/*
* SPDX-FileCopyrightText: 2024 Micah Stanley <stanleymicah@proton.me>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick
import QtQuick.Layouts
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
import org.kde.plasma.private.mobileshell.state as MobileShellState
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.notificationmanager as NotificationManager
import org.kde.plasma.plasma5support 2.0 as P5Support
import org.kde.taskmanager 0.1 as TaskManager
/**
* This sets up and manages the notification popup settings
*/
QtObject {
id: notificationProvider
property var notificationModelType: MobileShell.NotificationsModelType.NotificationsModel
property QtObject notificationSettings: NotificationManager.Settings {
onNotificationsInhibitedUntilChanged: notificationProvider.checkInhibition()
}
property QtObject popupNotificationsModel: NotificationManager.Notifications {
showExpired: false
showDismissed: false
blacklistedDesktopEntries: notificationSettings.popupBlacklistedApplications
blacklistedNotifyRcNames: notificationSettings.popupBlacklistedServices
whitelistedDesktopEntries: []
whitelistedNotifyRcNames: []
showJobs: notificationSettings.jobsInNotifications
sortMode: NotificationManager.Notifications.SortByTypeAndUrgency
sortOrder: Qt.DescendingOrder
groupMode: NotificationManager.Notifications.GroupDisabled
urgencies: {
var urgencies = 0;
// Critical always except in do not disturb mode when disabled in settings
if (!notificationProvider.inhibited || notificationSettings.criticalPopupsInDoNotDisturbMode) {
urgencies |= NotificationManager.Notifications.CriticalUrgency;
}
// Normal only when not in do not disturb mode
if (!notificationProvider.inhibited) {
urgencies |= NotificationManager.Notifications.NormalUrgency;
}
// Low only when enabled in settings and not in do not disturb mode
if (!notificationProvider.inhibited && notificationSettings.lowPriorityPopups) {
urgencies |=NotificationManager.Notifications.LowUrgency;
}
return urgencies;
}
}
property bool inhibited: false
onInhibitedChanged: {
var pa = pulseAudio.item;
if (!pa) {
return;
}
var stream = pa.notificationStream;
if (!stream) {
return;
}
if (inhibited) {
// Only remember that we muted if previously not muted.
if (!stream.muted) {
notificationSettings.notificationSoundsInhibited = true;
stream.mute();
}
} else {
// Only unmute if we previously muted it.
if (notificationSettings.notificationSoundsInhibited) {
stream.unmute();
}
notificationSettings.notificationSoundsInhibited = false;
}
notificationSettings.save();
}
function checkInhibition() {
notificationProvider.inhibited = Qt.binding(function() {
var inhibited = false;
if (!NotificationManager.Server.valid) {
return false;
}
var inhibitedUntil = notificationSettings.notificationsInhibitedUntil;
if (!isNaN(inhibitedUntil.getTime())) {
inhibited |= (Date.now() < inhibitedUntil.getTime());
}
if (notificationSettings.notificationsInhibitedByApplication) {
inhibited |= true;
}
if (notificationSettings.inhibitNotificationsWhenScreensMirrored) {
inhibited |= notificationSettings.screensMirrored;
}
return inhibited;
});
}
property QtObject tasksModel: TaskManager.TasksModel {
groupMode: TaskManager.TasksModel.GroupApplications
groupInline: false
}
property QtObject timeSource: P5Support.DataSource {
engine: "time"
connectedSources: ["Local"]
interval: 60000 // 1 min
intervalAlignment: P5Support.Types.AlignToMinute
onDataChanged: {
checkInhibition();
npm.timeChanged();
}
}
property var npm: NotificationPopupManager {
notificationModelType: notificationProvider.notificationModelType
notificationSettings: notificationProvider.notificationSettings
popupNotificationsModel: notificationProvider.popupNotificationsModel
timeSource: notificationProvider.timeSource
inhibited: notificationProvider.inhibited
tasksModel: notificationProvider.tasksModel
}
}