shift-shell/components/mobileshell/qml/widgets/notifications/NotificationFooterActions.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

126 lines
3.8 KiB
QML

/*
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
* SPDX-FileCopyrightText: 2018-2019 Kai Uwe Broulik <kde@privat.broulik.de>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
import QtQuick 2.15
import QtQuick.Layouts 1.1
import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.components 3.0 as PlasmaComponents
Item {
id: actionContainer
required property BaseNotificationItem notification
property bool popupNotification: false
implicitHeight: Math.max(actionFlow.implicitHeight, replyLoader.height)
visible: actionRepeater.count > 0
signal takeFocus()
Flow {
id: actionFlow
width: parent.width
spacing: Kirigami.Units.smallSpacing
layoutDirection: Qt.RightToLeft
enabled: !replyLoader.active
opacity: replyLoader.active ? 0 : 1
Behavior on opacity {
NumberAnimation {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
// action buttons
Repeater {
id: actionRepeater
model: {
const buttons = [];
var actionNames = (notificationItem.actionNames || []);
var actionLabels = (notificationItem.actionLabels || []);
for (var i = actionNames.length - 1; i >= 0; --i) {
buttons.push({
actionName: actionNames[i],
label: actionLabels[i]
});
}
if (notificationItem.hasReplyAction) {
buttons.unshift({
actionName: "inline-reply",
label: notificationItem.replyActionLabel || i18nc("Reply to message", "Reply")
});
}
return buttons;
}
PlasmaComponents.ToolButton {
flat: false
text: modelData.label || ""
visible: !(notificationItem.hasReplyAction && actionContainer.popupNotification)
onClicked: {
if (modelData.actionName === "inline-reply") {
replyLoader.beginReply();
return;
}
notificationItem.actionInvoked(modelData.actionName);
}
}
}
}
// inline reply field
Loader {
id: replyLoader
width: parent.width
height: active ? item.implicitHeight : 0
// When there is only one action and it is a reply action, show text field right away
active: notificationItem.hasReplyAction && actionContainer.popupNotification
visible: active
opacity: active ? 1 : 0
x: active ? 0 : parent.width
property bool replying: false
Behavior on x {
NumberAnimation {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
Behavior on opacity {
NumberAnimation {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
function beginReply() {
actionContainer.takeFocus();
active = true;
replying = true;
replyLoader.item.activate();
}
sourceComponent: NotificationReplyField {
placeholderText: notificationItem.replyPlaceholderText
buttonIconName: notificationItem.replySubmitButtonIconName
buttonText: notificationItem.replySubmitButtonText
onReplied: notificationItem.replied(text)
replying: replyLoader.replying
onBeginReplyRequested: replyLoader.beginReply()
}
}
}