289 lines
6.6 KiB
QML
289 lines
6.6 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import Quickshell
|
|
import QtQuick
|
|
import ZShell
|
|
import ZShell.Components
|
|
import ZShell.Config
|
|
import ZShell.Services
|
|
import qs.Components
|
|
import qs.Components.Notifs
|
|
import qs.Daemons
|
|
import qs.Helpers
|
|
import qs.Services
|
|
|
|
Item {
|
|
id: root
|
|
|
|
readonly property int padding: Tokens.padding.small
|
|
readonly property int clamped: ZUtils.clamp(padding - Config.bar.border, 0, padding)
|
|
|
|
required property int topPadding
|
|
required property Item panels
|
|
required property ScreenState screenState
|
|
|
|
anchors.bottom: parent.bottom
|
|
anchors.right: parent.right
|
|
anchors.top: parent.top
|
|
implicitHeight: {
|
|
if (list.count === 0)
|
|
return 0;
|
|
|
|
let height = list.layoutHeight;
|
|
|
|
if (panels.popouts.hasCurrent && (panels.popouts.currentCenter + (panels.popouts.current?.width / 2)) > panels.notifications.x)
|
|
return 0;
|
|
|
|
if (screenState.dashboard && (panels.dashboard.x + panels.dashboard.width >= panels.notifications.x))
|
|
return 0;
|
|
|
|
if (screenState.osd) {
|
|
const h = panels.osd.y - Tokens.spacing.small * 2 - padding * 2;
|
|
if (height > h)
|
|
height = h;
|
|
}
|
|
|
|
return Math.min(((QsWindow.window as QsWindow)?.screen?.height ?? 0) + padding - clamped * 2 - topPadding, height + padding * 2);
|
|
}
|
|
|
|
implicitWidth: Config.notifs.sizes.width + padding * 2
|
|
|
|
Behavior on implicitHeight {
|
|
Anim {}
|
|
}
|
|
|
|
Item {
|
|
anchors.fill: parent
|
|
anchors.margins: root.padding
|
|
clip: true
|
|
|
|
KineticFlickable {
|
|
id: view
|
|
|
|
anchors.fill: parent
|
|
|
|
contentHeight: list.implicitHeight
|
|
contentWidth: width
|
|
flickableDirection: Flickable.VerticalFlick
|
|
|
|
LazyListView {
|
|
id: list
|
|
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
implicitHeight: contentHeight
|
|
|
|
spacing: Tokens.spacing.medium
|
|
readyDelay: 1
|
|
cacheBuffer: (QsWindow.window as QsWindow)?.screen.height ?? 0
|
|
removeDuration: Tokens.anim.durations.normal
|
|
|
|
useCustomViewport: true
|
|
viewport: Qt.rect(0, view.contentY, width, view.height)
|
|
|
|
model: ScriptModel {
|
|
values: {
|
|
if (!Config.notifs.showInFullscreen) {
|
|
if (Hypr.monitorFor(root.panels.screen).activeWorkspace?.toplevels.values.some(t => t.lastIpcObject.fullscreen > 1) ?? false)
|
|
return [];
|
|
}
|
|
return [...NotifServer.popupGroups];
|
|
}
|
|
}
|
|
|
|
delegate: NotifWrapper {}
|
|
|
|
onViewportAdjustNeeded: d => {
|
|
if (contentYAnim.running)
|
|
contentYAnim.complete();
|
|
contentYAnim.to = Math.max(0, view.contentY + d);
|
|
contentYAnim.start();
|
|
}
|
|
|
|
Anim {
|
|
id: contentYAnim
|
|
|
|
target: view
|
|
property: "contentY"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
component NotifWrapper: Item {
|
|
id: wrapper
|
|
|
|
required property NotificationGroup modelData
|
|
property bool expanded: Config.notifs.openExpanded
|
|
readonly property bool holding: area.containsMouse || area.pressed || card.rowPressed
|
|
|
|
function forEachPopup(fn: var): void {
|
|
for (const n of [...card.notifs])
|
|
fn(n);
|
|
}
|
|
|
|
function holdGroupExpiry(): void {
|
|
wrapper.modelData.holdExpiry();
|
|
}
|
|
|
|
LazyListView.trackViewport: !expanded && card.nonAnimHeight < card.implicitHeight
|
|
LazyListView.preferredHeight: LazyListView.removing ? 0 : card.nonAnimHeight
|
|
LazyListView.visibleHeight: LazyListView.removing ? 0 : card.implicitHeight
|
|
LazyListView.onRemovingChanged: {
|
|
if (!wrapper.LazyListView.removing)
|
|
return;
|
|
|
|
slideOut.to = (area.x >= 0 ? root.implicitWidth : -root.implicitWidth) * 2;
|
|
slideOut.start();
|
|
}
|
|
|
|
implicitWidth: area.implicitWidth
|
|
implicitHeight: card.implicitHeight
|
|
|
|
enabled: !LazyListView.removing
|
|
z: LazyListView.removing ? 1 : 0
|
|
|
|
onHoldingChanged: {
|
|
if (holding)
|
|
holdGroupExpiry();
|
|
else
|
|
wrapper.modelData.releaseExpiry();
|
|
}
|
|
|
|
Connections {
|
|
function onNotifsChanged(): void {
|
|
if (wrapper.holding)
|
|
wrapper.holdGroupExpiry();
|
|
}
|
|
|
|
function onExpireTimerRestarted(): void {
|
|
if (expireProgress.running)
|
|
expireProgress.stop();
|
|
expireProgressReset.start();
|
|
}
|
|
|
|
function onExpirePausedChanged(): void {
|
|
if (wrapper.modelData.expirePaused) {
|
|
if (expireProgress.running)
|
|
expireProgress.pause();
|
|
} else {
|
|
if (expireProgress.running)
|
|
expireProgress.resume();
|
|
else
|
|
expireProgress.start();
|
|
}
|
|
}
|
|
|
|
target: wrapper.modelData
|
|
}
|
|
|
|
Anim {
|
|
id: slideOut
|
|
|
|
target: area
|
|
property: "x"
|
|
duration: Tokens.anim.durations.normal
|
|
easing: Tokens.anim.emphasized
|
|
}
|
|
|
|
Anim {
|
|
id: expireProgressReset
|
|
|
|
readonly property bool nPaused: wrapper.modelData.expirePaused
|
|
|
|
target: progress
|
|
property: "implicitWidth"
|
|
type: Anim.FastEffects
|
|
to: nPaused ? area.width : area.width * (1 - duration / expireProgress.duration)
|
|
|
|
onFinished: {
|
|
if (nPaused)
|
|
expireProgress.duration = wrapper.modelData.expireTimeout;
|
|
else
|
|
expireProgress.duration = wrapper.modelData.expireTimeout - expireProgressReset.duration;
|
|
expireProgress.from = to;
|
|
if (!nPaused)
|
|
expireProgress.start();
|
|
}
|
|
}
|
|
|
|
Anim {
|
|
id: expireProgress
|
|
|
|
running: wrapper.modelData.expireActive
|
|
target: progress
|
|
property: "implicitWidth"
|
|
duration: wrapper.modelData.expireTimeout
|
|
easing.type: Easing.Linear
|
|
from: area.width
|
|
to: 0
|
|
}
|
|
|
|
Item {
|
|
anchors.top: parent.top
|
|
|
|
implicitWidth: area.implicitWidth
|
|
implicitHeight: card.implicitHeight
|
|
clip: true
|
|
|
|
NotifSwipeArea {
|
|
id: area
|
|
|
|
implicitWidth: root.implicitWidth - root.padding * 2
|
|
implicitHeight: card.implicitHeight
|
|
x: wrapper.LazyListView.adding ? implicitWidth : 0
|
|
|
|
expanded: wrapper.expanded
|
|
|
|
onRequestExpand: expand => wrapper.expanded = expand
|
|
onSwiped: wrapper.forEachPopup(n => n.dismissPopup())
|
|
onDismissed: wrapper.forEachPopup(n => n.dismiss())
|
|
onClicked: event => {
|
|
if (!Config.notifs.actionOnClick || event.button !== Qt.LeftButton || card.notifs.length !== 1)
|
|
return;
|
|
|
|
const actions = card.notifs[0].actions;
|
|
if (actions.length === 1)
|
|
actions[0].invoke();
|
|
}
|
|
|
|
NotifGroupCard {
|
|
id: card
|
|
|
|
group: wrapper.modelData
|
|
container: view
|
|
expanded: wrapper.expanded
|
|
onRequestExpand: expand => wrapper.expanded = expand
|
|
onSwiped: notif => notif.dismissPopup()
|
|
onLinkActivated: notif => notif.dismissPopup()
|
|
bottomPadding: Config.notifs.expire ? progress.implicitHeight : 0
|
|
}
|
|
|
|
CustomClippingRect {
|
|
anchors.fill: parent
|
|
|
|
radius: Tokens.rounding.large
|
|
|
|
visible: Config.notifs.expire
|
|
|
|
CustomRect {
|
|
id: progress
|
|
|
|
anchors.bottom: parent.bottom
|
|
anchors.right: parent.right
|
|
implicitWidth: parent.width
|
|
implicitHeight: 6
|
|
color: Colors.palette.m3outlineVariant
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Behavior on y {
|
|
enabled: wrapper.LazyListView.ready
|
|
|
|
Anim {}
|
|
}
|
|
}
|
|
}
|