shift-shell/components/mobileshell/qml/widgets/notifications/NotificationCard.qml
Devin Lin a8b858dc3e Remove kirigami version in imports
This fixes potential issues stemming from pinning versions on Kirigami
qml api imports
2026-03-06 22:08:07 -05:00

226 lines
6.6 KiB
QML

// SPDX-FileCopyrightText: 2021-2023 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
import QtQuick
import QtQuick.Effects
import QtQuick.Controls
import Qt5Compat.GraphicalEffects
import org.kde.kirigami as Kirigami
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.private.mobileshell as MobileShell
Item {
id: root
/**
* The content that goes inside the notification card
*/
default property Item contentItem
/**
* The panel background type for this notification.
*/
property int panelType: MobileShell.PanelBackground.PanelType.Drawer
/**
* Whether this is a popup notification.
*/
property bool popupNotification: false
/**
* Whether this popup notification is tucked underneath the current popup.
*/
property bool inPopupDrawer: false
/**
* Whether this notification is within the lockscreen.
*/
property bool inLockScreen: false
/**
* The current notification popup height.
*/
property int currentPopupHeight: 0
/**
* The remaining time before the notification popup is dismissed.
*/
property real remainingTimeProgress: 1
/**
* Whether the timer for dismissing the notification popup is running.
*/
property bool closeTimerRunning: false
/**
* Whether tapping on this notification is enabled.
*/
property bool tapEnabled: false
/**
* Whether swipping on this notification is enabled.
*/
property bool swipeGestureEnabled: false
/**
* The current drag offset for this notification.
*/
property real dragOffset: 0
signal tapped()
signal dismissRequested()
signal configureClicked() // TODO implement settings button
signal dragStart()
signal dragEnd()
onContentItemChanged: {
contentItem.parent = contentParent;
contentItem.anchors.fill = contentParent;
contentItem.anchors.margins = Kirigami.Units.largeSpacing;
contentParent.children.push(contentItem);
}
implicitHeight: contentParent.implicitHeight
NumberAnimation on dragOffset {
id: dragAnim
duration: Kirigami.Units.longDuration
easing.type: Easing.OutCubic
onFinished: {
if (to !== 0) {
root.dismissRequested();
}
}
}
MobileShell.PanelBackground {
anchors.fill: mainCard
animate: true
panelType: root.panelType
}
// card
Item {
id: mainCard
anchors.left: parent.left
anchors.leftMargin: root.dragOffset > 0 ? root.dragOffset : 0
anchors.right: parent.right
anchors.rightMargin: root.dragOffset < 0 ? -root.dragOffset : 0
anchors.top: parent.top
implicitHeight: inPopupDrawer ? currentPopupHeight : contentParent.implicitHeight
Behavior on implicitHeight {
NumberAnimation {
duration: Kirigami.Units.veryLongDuration
easing.type: Easing.OutExpo
}
}
ProgressBar {
id: progress
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
width: root.width
height: 2
value: remainingTimeProgress
opacity: closeTimerRunning ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: Kirigami.Units.longDuration
easing.type: Easing.OutQuad
}
}
background: Item
contentItem: Item {
implicitWidth: parent.width
height: parent.height
clip: true
Rectangle {
width: Math.min(progress.visualPosition * (parent.width + root.dragOffset), parent.width)
height: Math.max(Kirigami.Units.cornerRadius * 2, parent.height)
topLeftRadius: Kirigami.Units.cornerRadius
topRightRadius: Kirigami.Units.cornerRadius
color: Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.highlightColor, Kirigami.Theme.backgroundColor, 0.8)
}
Rectangle {
width: Math.min(progress.visualPosition * (parent.width + root.dragOffset), parent.width - Kirigami.Units.cornerRadius)
height: Math.max(Kirigami.Units.cornerRadius * 2, parent.height)
topLeftRadius: Kirigami.Units.cornerRadius
color: Kirigami.ColorUtils.linearInterpolation (Kirigami.Theme.highlightColor, Kirigami.Theme.backgroundColor, 0.8)
}
}
}
// clip
layer.enabled: true
// ensure this is behind the content to not interfere
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: {
if (root.tapEnabled) {
root.tapped()
}
}
}
// content parent
Item {
id: contentParent
anchors.top: parent.top
anchors.left: root.dragOffset > 0 ? parent.left : undefined
anchors.right: root.dragOffset < 0 ? parent.right : undefined
width: root.width
implicitHeight: contentItem.implicitHeight + contentItem.anchors.topMargin + contentItem.anchors.bottomMargin
}
}
DragHandler {
id: dragHandler
enabled: root.swipeGestureEnabled
yAxis.enabled: false
xAxis.enabled: !inPopupDrawer
property real startDragOffset: 0
property real startPosition: 0
property bool startActive: false
onTranslationChanged: {
if (startActive) {
startDragOffset = root.dragOffset;
startPosition = translation.x;
startActive = false;
}
root.dragOffset = startDragOffset + (translation.x - startPosition);
}
onActiveChanged: {
dragAnim.stop();
startActive = active;
if (!active) { // release event
root.dragEnd()
let threshold = Kirigami.Units.gridUnit * 5; // drag threshold
if (root.dragOffset > threshold) {
dragAnim.to = root.width;
} else if (root.dragOffset < -threshold) {
dragAnim.to = -root.width;
} else {
dragAnim.to = 0;
}
dragAnim.restart();
} else {
root.dragStart()
}
}
}
}