mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
toppanel/notifications: add clean all and do not disturb
Hi, this MR adds "clear all" and "do not disturb" buttons to `NotificationsWidget`. Few other corrections have been made: - Transitions should now work correctly, plus they can be disabled via `MobileShell.MobileShellSettings.animationsEnabled`; - Loaders are now asynchronous; - List items have now their own margins, in order to not clip their shadows.\ It only remains to implement a context menu to set do not disturb mode for a given period of time. I think it's a secondary feature on which we can work later, but in case tell me what to do. Unfortunately I can't test the lockscreen on a phone at the moment, and I cannot take a performance test as well. It would be great if someone tested all these things, otherwise I'll provide as soon as possible. Closes: https://invent.kde.org/plasma/plasma-mobile/-/issues/134
This commit is contained in:
parent
db86c14293
commit
d8399e88be
4 changed files with 194 additions and 45 deletions
|
|
@ -71,6 +71,7 @@ PlasmaCore.ColorScope {
|
|||
top: mediaWidget.bottom
|
||||
topMargin: 0
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 0
|
||||
right: quickSettings.left
|
||||
left: parent.left
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ PlasmaCore.ColorScope {
|
|||
color: Qt.rgba(PlasmaCore.Theme.backgroundColor.r,
|
||||
PlasmaCore.Theme.backgroundColor.g,
|
||||
PlasmaCore.Theme.backgroundColor.b,
|
||||
notificationWidget.hasNotifications ? 0.95 : 0.7)
|
||||
0.95)
|
||||
Behavior on color { ColorAnimation { duration: PlasmaCore.Units.longDuration } }
|
||||
opacity: Math.max(0, Math.min(1, actionDrawer.offset / root.minimizedQuickSettingsOffset))
|
||||
}
|
||||
|
|
@ -114,11 +114,8 @@ PlasmaCore.ColorScope {
|
|||
top: quickSettings.top
|
||||
topMargin: quickSettings.height + translate.y
|
||||
bottom: parent.bottom
|
||||
bottomMargin: PlasmaCore.Units.largeSpacing
|
||||
left: parent.left
|
||||
leftMargin: PlasmaCore.Units.largeSpacing
|
||||
right: parent.right
|
||||
rightMargin: PlasmaCore.Units.largeSpacing
|
||||
}
|
||||
opacity: applyMinMax(root.actionDrawer.offset / root.minimizedQuickSettingsOffset)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Window 2.2
|
||||
import QtGraphicalEffects 1.12
|
||||
|
||||
|
|
@ -29,17 +29,17 @@ Item {
|
|||
/**
|
||||
* The notification model for the widget.
|
||||
*/
|
||||
property var historyModel: []
|
||||
property var historyModel
|
||||
|
||||
/**
|
||||
* The type of notification model used for the widget.
|
||||
*/
|
||||
property int historyModelType: NotificationsModelType.NotificationsModel
|
||||
property int historyModelType
|
||||
|
||||
/**
|
||||
* The notification model settings for the widget.
|
||||
*/
|
||||
property var notificationSettings: NotificationManager.Settings {}
|
||||
property var notificationSettings
|
||||
|
||||
/**
|
||||
* Whether invoking notification actions requires authentiation of some sort.
|
||||
|
|
@ -55,6 +55,8 @@ Item {
|
|||
*/
|
||||
readonly property bool hasNotifications: list.count > 0
|
||||
|
||||
readonly property bool doNotDisturbModeEnabled: !isNaN(notificationSettings.notificationsInhibitedUntil)
|
||||
|
||||
enum ModelType {
|
||||
NotificationsModel, // used in the logged-in shell
|
||||
WatchedNotificationsModel // used on the lockscreen
|
||||
|
|
@ -85,8 +87,29 @@ Item {
|
|||
*/
|
||||
function clearHistory() {
|
||||
historyModel.clear(NotificationManager.Notifications.ClearExpired);
|
||||
|
||||
if (historyModel.count === 0) {
|
||||
backgroundClicked();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles Do Not Disturb mode.
|
||||
*/
|
||||
function toggleDoNotDisturbMode() {
|
||||
if (doNotDisturbModeEnabled) {
|
||||
notificationSettings.defaults();
|
||||
} else {
|
||||
var until = new Date();
|
||||
|
||||
until.setFullYear(until.getFullYear() + 1);
|
||||
|
||||
notificationSettings.notificationsInhibitedUntil = until;
|
||||
}
|
||||
|
||||
notificationSettings.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the system notification settings.
|
||||
*/
|
||||
|
|
@ -102,33 +125,49 @@ Item {
|
|||
intervalAlignment: PlasmaCore.Types.AlignToMinute
|
||||
}
|
||||
|
||||
// implement background clicking signal
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: backgroundClicked()
|
||||
z: -1 // ensure that this is below notification items so we don't steal button clicks
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: list
|
||||
model: historyModel
|
||||
currentIndex: -1
|
||||
|
||||
clip: true
|
||||
|
||||
currentIndex: 0
|
||||
|
||||
property var pendingNotificationWithAction
|
||||
|
||||
readonly property int animationDuration: MobileShell.MobileShellSettings.animationsEnabled ? PlasmaCore.Units.longDuration : 0
|
||||
|
||||
// If a screen overflow occurs, fix height in order to maintain tool buttons in place.
|
||||
readonly property bool listOverflowing: contentItem.childrenRect.height + toolButtons.height + bottomMargin + spacing >= root.height
|
||||
|
||||
bottomMargin: spacing * 2
|
||||
|
||||
height: count === 0 ? 0 : listOverflowing ? root.height - toolButtons.height - bottomMargin : contentItem.childrenRect.height + spacing
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
// TODO keyboard focus
|
||||
highlightMoveDuration: 0
|
||||
highlightResizeDuration: 0
|
||||
highlight: Item {}
|
||||
|
||||
section {
|
||||
property: "isInGroup"
|
||||
criteria: ViewSection.FullString
|
||||
}
|
||||
|
||||
// implement background clicking signal
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root.backgroundClicked()
|
||||
z: -1 // ensure that this is below notification items so we don't steal button clicks
|
||||
section {
|
||||
property: "isGroup"
|
||||
criteria: ViewSection.FullString
|
||||
}
|
||||
|
||||
PlasmaExtras.PlaceholderMessage {
|
||||
|
|
@ -149,26 +188,15 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
// Run every time an item is visually added to the list, thus when `Show n more` button is clicked as well.
|
||||
add: Transition {
|
||||
SequentialAnimation {
|
||||
PropertyAction { property: "opacity"; value: 0 }
|
||||
PauseAnimation { duration: PlasmaCore.Units.longDuration }
|
||||
ParallelAnimation {
|
||||
NumberAnimation { property: "opacity"; from: 0; to: 1; duration: PlasmaCore.Units.longDuration }
|
||||
NumberAnimation { property: "height"; from: 0; duration: PlasmaCore.Units.longDuration }
|
||||
}
|
||||
}
|
||||
NumberAnimation { property: "opacity"; from: 0; to: 1; duration: list.animationDuration }
|
||||
}
|
||||
addDisplaced: Transition {
|
||||
NumberAnimation { properties: "y"; duration: PlasmaCore.Units.longDuration }
|
||||
// Run every time an item is displaced, such as when the order is scrambled due to a group expansion.
|
||||
displaced: Transition {
|
||||
NumberAnimation { properties: "y"; duration: list.animationDuration }
|
||||
}
|
||||
removeDisplaced: Transition {
|
||||
SequentialAnimation {
|
||||
PauseAnimation { duration: PlasmaCore.Units.longDuration }
|
||||
NumberAnimation { properties: "y"; duration: PlasmaCore.Units.longDuration }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function isRowExpanded(row) {
|
||||
var idx = historyModel.index(row, 0);
|
||||
return historyModel.data(idx, NotificationManager.Notifications.IsGroupExpandedRole);
|
||||
|
|
@ -191,19 +219,38 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Instantly re-align items after group expansion.
|
||||
forceLayout();
|
||||
}
|
||||
|
||||
delegate: Loader {
|
||||
id: delegateLoader
|
||||
width: list.width
|
||||
|
||||
anchors {
|
||||
left: parent ? parent.left : undefined
|
||||
leftMargin: PlasmaCore.Units.largeSpacing
|
||||
right: parent ? parent.right : undefined
|
||||
rightMargin: PlasmaCore.Units.largeSpacing
|
||||
}
|
||||
|
||||
height: model.isGroup ? groupDelegate.height : notificationDelegate.height
|
||||
sourceComponent: model.isGroup ? groupDelegate : notificationDelegate
|
||||
asynchronous: true
|
||||
|
||||
required property var model
|
||||
required property int index
|
||||
|
||||
// We have to do this here in order to control the animation before the item is completely removed
|
||||
ListView.onRemove: SequentialAnimation {
|
||||
PropertyAction { target: delegateLoader; property: "ListView.delayRemove"; value: true }
|
||||
NumberAnimation { target: delegateLoader; property: "opacity"; to: 0.0; duration: list.animationDuration }
|
||||
PropertyAction { target: delegateLoader; property: "ListView.delayRemove"; value: false }
|
||||
}
|
||||
|
||||
Component {
|
||||
id: groupDelegate
|
||||
NotificationGroupHeader {
|
||||
NotificationGroupHeader {
|
||||
applicationName: model.applicationName
|
||||
applicationIconSource: model.applicationIconName
|
||||
originName: model.originName || ""
|
||||
|
|
@ -213,12 +260,16 @@ Item {
|
|||
|
||||
Component {
|
||||
id: notificationDelegate
|
||||
ColumnLayout {
|
||||
|
||||
Column {
|
||||
spacing: PlasmaCore.Units.smallSpacing
|
||||
|
||||
height: notificationItem.height + showMoreLoader.height
|
||||
|
||||
NotificationItem {
|
||||
id: notificationItem
|
||||
Layout.fillWidth: true
|
||||
width: parent.width
|
||||
height: implicitHeight
|
||||
|
||||
model: delegateLoader.model
|
||||
modelIndex: delegateLoader.index
|
||||
|
|
@ -233,16 +284,37 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
// Every item has got an instance of this loader, but it becomes active only for last ones that take place in big enough groups.
|
||||
Loader {
|
||||
id: showMoreLoader
|
||||
|
||||
height: visible ? implicitHeight : 0
|
||||
opacity: 0.0
|
||||
visible: active
|
||||
|
||||
asynchronous: true
|
||||
|
||||
active: {
|
||||
// if we have the WatchedNotificationsModel, we don't have notification grouping support
|
||||
if (typeof model.groupChildrenCount === 'undefined')
|
||||
return false;
|
||||
|
||||
|
||||
return (model.groupChildrenCount > model.expandedGroupChildrenCount || model.isGroupExpanded)
|
||||
&& delegateLoader.ListView.nextSection !== delegateLoader.ListView.section
|
||||
&& delegateLoader.ListView.nextSection != delegateLoader.ListView.section;
|
||||
}
|
||||
|
||||
// state + transition: animates the item when it becomes visible. Fade off is handled by above ListView.onRemove.
|
||||
states: State {
|
||||
name: "VISIBLE"
|
||||
when: showMoreLoader.status == Loader.Ready
|
||||
PropertyChanges { target: showMoreLoader; opacity: 1.0 }
|
||||
}
|
||||
transitions: Transition {
|
||||
to: "VISIBLE"
|
||||
SequentialAnimation {
|
||||
PauseAnimation { duration: list.animationDuration * 2 }
|
||||
NumberAnimation { properties: "opacity"; duration: list.animationDuration }
|
||||
}
|
||||
}
|
||||
|
||||
sourceComponent: PlasmaComponents3.ToolButton {
|
||||
|
|
@ -250,11 +322,86 @@ Item {
|
|||
text: model.isGroupExpanded ? i18n("Show Fewer")
|
||||
: i18nc("Expand to show n more notifications",
|
||||
"Show %1 More", (model.groupChildrenCount - model.expandedGroupChildrenCount))
|
||||
onClicked: list.setGroupExpanded(model.index, !model.isGroupExpanded)
|
||||
onClicked: {
|
||||
list.setGroupExpanded(model.index, !model.isGroupExpanded)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: toolButtons
|
||||
|
||||
visible: !root.actionsRequireUnlock
|
||||
|
||||
width: root.width
|
||||
height: toolLayout.implicitHeight + spacer.height
|
||||
|
||||
anchors {
|
||||
top: list.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: spacer
|
||||
|
||||
visible: list.listOverflowing
|
||||
|
||||
anchors {
|
||||
top: toolButtons.top
|
||||
left: toolButtons.left
|
||||
right: toolButtons.right
|
||||
}
|
||||
|
||||
height: 1
|
||||
|
||||
opacity: 0.25
|
||||
color: PlasmaCore.Theme.textColor
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: toolLayout
|
||||
|
||||
anchors {
|
||||
top: spacer.bottom
|
||||
topMargin: list.spacing
|
||||
left: parent.left
|
||||
leftMargin: PlasmaCore.Units.smallSpacing
|
||||
right: parent.right
|
||||
rightMargin: PlasmaCore.Units.smallSpacing
|
||||
bottom: parent.bottom
|
||||
bottomMargin: list.spacing
|
||||
}
|
||||
|
||||
PlasmaComponents3.ToolButton {
|
||||
id: doNotDisturbButton
|
||||
|
||||
Layout.alignment: hasNotifications ? Qt.AlignLeft : Qt.AlignHCenter
|
||||
|
||||
font.bold: true
|
||||
|
||||
icon.name: doNotDisturbModeEnabled ? "notifications" : "notifications-disabled"
|
||||
text: doNotDisturbModeEnabled ? "Enable Notifications" : "Do Not Disturb"
|
||||
onClicked: toggleDoNotDisturbMode()
|
||||
}
|
||||
|
||||
PlasmaComponents3.ToolButton {
|
||||
id: clearButton
|
||||
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
visible: hasNotifications
|
||||
|
||||
font.bold: true
|
||||
|
||||
icon.name: "edit-clear-history"
|
||||
text: "Clear All Notifications"
|
||||
onClicked: clearHistory()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,13 @@ import org.kde.plasma.core 2.0 as PlasmaCore
|
|||
import org.kde.notificationmanager 1.1 as Notifications
|
||||
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||
|
||||
import org.kde.notificationmanager 1.0 as NotificationManager
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
required property var lockScreenState
|
||||
property var notificationsModel: []
|
||||
property var notificationSettings: NotificationManager.Settings {}
|
||||
|
||||
readonly property bool notificationsShown: notificationsList.hasNotifications
|
||||
|
||||
|
|
@ -61,6 +64,7 @@ Rectangle {
|
|||
historyModelType: MobileShell.NotificationsModelType.WatchedNotificationsModel
|
||||
actionsRequireUnlock: true
|
||||
historyModel: root.notificationsModel
|
||||
notificationSettings: root.notificationSettings
|
||||
|
||||
property bool requestNotificationAction: false
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue