add scroll edge fade to some scrolled windows

This commit is contained in:
end-4
2025-09-23 11:14:34 +02:00
parent 2b47083c12
commit fc9bda9f7f
8 changed files with 178 additions and 93 deletions
@@ -4,6 +4,7 @@ import qs.services
import qs.modules.common.functions
import QtQuick
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell
import Quickshell.Hyprland
import Quickshell.Services.Notifications
@@ -220,91 +221,110 @@ Item { // Notification item area
PointingHandLinkHover {}
}
StyledFlickable { // Notification actions
id: actionsFlickable
Item {
Layout.fillWidth: true
implicitHeight: actionRowLayout.implicitHeight
contentWidth: actionRowLayout.implicitWidth
clip: !onlyNotification
implicitWidth: actionsFlickable.implicitWidth
implicitHeight: actionsFlickable.implicitHeight
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
Behavior on height {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
Behavior on implicitHeight {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: actionsFlickable.width
height: actionsFlickable.height
radius: Appearance.rounding.small
}
}
RowLayout {
id: actionRowLayout
Layout.alignment: Qt.AlignBottom
ScrollEdgeFade {
target: actionsFlickable
vertical: false
}
NotificationActionButton {
Layout.fillWidth: true
buttonText: Translation.tr("Close")
urgency: notificationObject.urgency
implicitWidth: (notificationObject.actions.length == 0) ? ((actionsFlickable.width - actionRowLayout.spacing) / 2) :
(contentItem.implicitWidth + leftPadding + rightPadding)
StyledFlickable { // Notification actions
id: actionsFlickable
anchors.fill: parent
implicitHeight: actionRowLayout.implicitHeight
contentWidth: actionRowLayout.implicitWidth
onClicked: {
root.destroyWithAnimation()
}
contentItem: MaterialSymbol {
iconSize: Appearance.font.pixelSize.large
horizontalAlignment: Text.AlignHCenter
color: (notificationObject.urgency == NotificationUrgency.Critical) ?
Appearance.m3colors.m3onSurfaceVariant : Appearance.m3colors.m3onSurface
text: "close"
}
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
Behavior on height {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
Behavior on implicitHeight {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
Repeater {
id: actionRepeater
model: notificationObject.actions
RowLayout {
id: actionRowLayout
Layout.alignment: Qt.AlignBottom
NotificationActionButton {
Layout.fillWidth: true
buttonText: modelData.text
buttonText: Translation.tr("Close")
urgency: notificationObject.urgency
implicitWidth: (notificationObject.actions.length == 0) ? ((actionsFlickable.width - actionRowLayout.spacing) / 2) :
(contentItem.implicitWidth + leftPadding + rightPadding)
onClicked: {
Notifications.attemptInvokeAction(notificationObject.notificationId, modelData.identifier);
root.destroyWithAnimation()
}
}
}
NotificationActionButton {
Layout.fillWidth: true
urgency: notificationObject.urgency
implicitWidth: (notificationObject.actions.length == 0) ? ((actionsFlickable.width - actionRowLayout.spacing) / 2) :
(contentItem.implicitWidth + leftPadding + rightPadding)
onClicked: {
Quickshell.clipboardText = notificationObject.body
copyIcon.text = "inventory"
copyIconTimer.restart()
}
Timer {
id: copyIconTimer
interval: 1500
repeat: false
onTriggered: {
copyIcon.text = "content_copy"
contentItem: MaterialSymbol {
iconSize: Appearance.font.pixelSize.large
horizontalAlignment: Text.AlignHCenter
color: (notificationObject.urgency == NotificationUrgency.Critical) ?
Appearance.m3colors.m3onSurfaceVariant : Appearance.m3colors.m3onSurface
text: "close"
}
}
contentItem: MaterialSymbol {
id: copyIcon
iconSize: Appearance.font.pixelSize.large
horizontalAlignment: Text.AlignHCenter
color: (notificationObject.urgency == NotificationUrgency.Critical) ?
Appearance.m3colors.m3onSurfaceVariant : Appearance.m3colors.m3onSurface
text: "content_copy"
Repeater {
id: actionRepeater
model: notificationObject.actions
NotificationActionButton {
Layout.fillWidth: true
buttonText: modelData.text
urgency: notificationObject.urgency
onClicked: {
Notifications.attemptInvokeAction(notificationObject.notificationId, modelData.identifier);
}
}
}
NotificationActionButton {
Layout.fillWidth: true
urgency: notificationObject.urgency
implicitWidth: (notificationObject.actions.length == 0) ? ((actionsFlickable.width - actionRowLayout.spacing) / 2) :
(contentItem.implicitWidth + leftPadding + rightPadding)
onClicked: {
Quickshell.clipboardText = notificationObject.body
copyIcon.text = "inventory"
copyIconTimer.restart()
}
Timer {
id: copyIconTimer
interval: 1500
repeat: false
onTriggered: {
copyIcon.text = "content_copy"
}
}
contentItem: MaterialSymbol {
id: copyIcon
iconSize: Appearance.font.pixelSize.large
horizontalAlignment: Text.AlignHCenter
color: (notificationObject.urgency == NotificationUrgency.Critical) ?
Appearance.m3colors.m3onSurfaceVariant : Appearance.m3colors.m3onSurface
text: "content_copy"
}
}
}
}
}
}
@@ -0,0 +1,59 @@
import QtQuick
import qs.modules.common
import qs.modules.common.functions
Item {
id: root
z: 99
required property Item target
property real fadeSize: Appearance.m3colors.darkmode ? 40 : 20
property color color: ColorUtils.transparentize(Appearance.colors.colShadow, Appearance.m3colors.darkmode ? 0 : 0.7)
property bool vertical: true
anchors.fill: target
EndGradient {
anchors {
top: parent.top
left: parent.left
right: vertical ? parent.right : undefined
bottom: vertical ? undefined : parent.bottom
}
shown: !(root.vertical ? root.target.atYBeginning : root.target.atXBeginning)
}
EndGradient {
anchors {
bottom: parent.bottom
right: parent.right
left: vertical ? parent.left : undefined
top: vertical ? undefined : parent.top
}
shown: !(root.vertical ? root.target.atYEnd : root.target.atXEnd)
rotation: 180
}
component EndGradient: Rectangle {
required property bool shown
height: vertical ? root.fadeSize : parent.height
width: vertical ? parent.width : root.fadeSize
opacity: shown ? 1 : 0
visible: opacity > 0
Behavior on opacity {
animation: Appearance?.animation.elementMoveFast.numberAnimation.createObject(this)
}
gradient: Gradient {
orientation: root.vertical ? Gradient.Vertical : Gradient.Horizontal
GradientStop {
position: 0.0
color: root.color
}
GradientStop {
position: 1.0
color: ColorUtils.transparentize(root.color)
}
}
}
}
@@ -50,4 +50,5 @@ Flickable {
root.scrollTargetY = root.contentY;
}
}
}