diff options
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/drawers/Panels.qml | 88 | ||||
| -rw-r--r-- | modules/lock/NotifDock.qml | 4 | ||||
| -rw-r--r-- | modules/lock/NotifGroup.qml | 2 | ||||
| -rw-r--r-- | modules/notifications/AppIconBadge.qml | 57 | ||||
| -rw-r--r-- | modules/notifications/Content.qml | 58 | ||||
| -rw-r--r-- | modules/notifications/Notification.qml | 72 | ||||
| -rw-r--r-- | modules/notifications/NotificationToast.qml | 120 | ||||
| -rw-r--r-- | modules/notifications/NotificationToasts.qml | 186 | ||||
| -rw-r--r-- | modules/notifications/Wrapper.qml | 2 | ||||
| -rw-r--r-- | modules/utilities/toasts/ToastItem.qml | 9 |
10 files changed, 60 insertions, 538 deletions
diff --git a/modules/drawers/Panels.qml b/modules/drawers/Panels.qml index 8b5a251..4ce1182 100644 --- a/modules/drawers/Panels.qml +++ b/modules/drawers/Panels.qml @@ -8,10 +8,6 @@ import qs.modules.bar.popouts as BarPopouts import qs.modules.utilities as Utilities import qs.modules.utilities.toasts as Toasts import qs.modules.sidebar as Sidebar -import qs.components -import qs.components.controls -import qs.components.effects -import qs.services import Quickshell import QtQuick @@ -31,7 +27,6 @@ Item { readonly property alias utilities: utilities readonly property alias toasts: toasts readonly property alias sidebar: sidebar - readonly property alias clearAllButton: clearAllButton anchors.fill: parent anchors.margins: Config.border.thickness @@ -59,89 +54,6 @@ Item { anchors.right: parent.right } - // Clear all notifications button - positioned to the left of the notification panel - Item { - id: clearAllButton - - readonly property bool hasNotifications: Notifs.notClosed.length > 0 - readonly property bool panelVisible: notifications.height > 0 || notifications.implicitHeight > 0 - readonly property bool shouldShow: hasNotifications && panelVisible - - anchors.top: notifications.top - anchors.right: notifications.left - anchors.rightMargin: Appearance.padding.normal - anchors.topMargin: Appearance.padding.large - - width: button.implicitWidth - height: button.implicitHeight - enabled: shouldShow - - IconButton { - id: button - - icon: "clear_all" - radius: Appearance.rounding.normal - padding: Appearance.padding.normal - font.pointSize: Math.round(Appearance.font.size.large * 1.2) - - onClicked: { - // Clear all notifications - for (const notif of Notifs.list.slice()) - notif.close(); - } - - Elevation { - anchors.fill: parent - radius: parent.radius - z: -1 - level: button.stateLayer.containsMouse ? 4 : 3 - } - } - - // Keep notification panel visible when hovering over the button - MouseArea { - anchors.fill: button - hoverEnabled: true - acceptedButtons: Qt.NoButton - onEntered: { - if (notifications.content && Notifs.notClosed.length > 0) { - notifications.content.show(); - } - } - onExited: { - // Panel will be hidden by Interactions.qml if mouse is not over panel or button - } - } - - Behavior on opacity { - Anim { - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } - - Behavior on scale { - Anim { - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } - - opacity: shouldShow ? 1 : 0 - scale: shouldShow ? 1 : 0.5 - } - - Notifications.NotificationToasts { - id: notificationToasts - - panels: root - - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: Config.border.thickness - anchors.rightMargin: Config.border.thickness - } - Session.Wrapper { id: session diff --git a/modules/lock/NotifDock.qml b/modules/lock/NotifDock.qml index db087bd..7551e68 100644 --- a/modules/lock/NotifDock.qml +++ b/modules/lock/NotifDock.qml @@ -22,7 +22,7 @@ ColumnLayout { StyledText { Layout.fillWidth: true - text: Notifs.notClosed.length > 0 ? qsTr("%1 notification%2").arg(Notifs.notClosed.length).arg(Notifs.notClosed.length === 1 ? "" : "s") : qsTr("Notifications") + text: Notifs.list.length > 0 ? qsTr("%1 notification%2").arg(Notifs.list.length).arg(Notifs.list.length === 1 ? "" : "s") : qsTr("Notifications") color: Colours.palette.m3outline font.family: Appearance.font.family.mono font.weight: 500 @@ -42,7 +42,7 @@ ColumnLayout { anchors.centerIn: parent asynchronous: true active: opacity > 0 - opacity: Notifs.notClosed.length > 0 ? 0 : 1 + opacity: Notifs.list.length > 0 ? 0 : 1 sourceComponent: ColumnLayout { spacing: Appearance.spacing.large diff --git a/modules/lock/NotifGroup.qml b/modules/lock/NotifGroup.qml index 50b14ae..2a08c26 100644 --- a/modules/lock/NotifGroup.qml +++ b/modules/lock/NotifGroup.qml @@ -16,7 +16,7 @@ StyledRect { required property string modelData - readonly property list<var> notifs: Notifs.notClosed.filter(notif => notif.appName === modelData) + readonly property list<var> notifs: Notifs.list.filter(notif => notif.appName === modelData) readonly property string image: notifs.find(n => n.image.length > 0)?.image ?? "" readonly property string appIcon: notifs.find(n => n.appIcon.length > 0)?.appIcon ?? "" readonly property string urgency: notifs.some(n => n.urgency === NotificationUrgency.Critical) ? "critical" : notifs.some(n => n.urgency === NotificationUrgency.Normal) ? "normal" : "low" diff --git a/modules/notifications/AppIconBadge.qml b/modules/notifications/AppIconBadge.qml deleted file mode 100644 index 286522f..0000000 --- a/modules/notifications/AppIconBadge.qml +++ /dev/null @@ -1,57 +0,0 @@ -import qs.components -import qs.components.effects -import qs.services -import qs.config -import qs.utils -import Quickshell -import Quickshell.Services.Notifications -import QtQuick - -StyledRect { - id: root - - required property Notifs.Notif modelData - required property bool hasImage - required property bool hasAppIcon - - radius: Appearance.rounding.full - color: modelData.getBadgeBackgroundColor() - implicitWidth: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image - implicitHeight: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image - - Loader { - id: icon - - active: root.hasAppIcon - asynchronous: false - visible: active - - anchors.centerIn: parent - - width: Math.round(parent.width * 0.6) - height: Math.round(parent.width * 0.6) - - sourceComponent: ColouredIcon { - anchors.fill: parent - source: Quickshell.iconPath(root.modelData.appIcon) - colour: root.modelData.getIconColor() - layer.enabled: root.modelData.appIcon.endsWith("symbolic") - } - } - - Loader { - active: !root.hasAppIcon - asynchronous: false - visible: active - anchors.centerIn: parent - anchors.horizontalCenterOffset: -Appearance.font.size.large * 0.02 - anchors.verticalCenterOffset: Appearance.font.size.large * 0.02 - - sourceComponent: MaterialIcon { - text: Icons.getNotifIcon(root.modelData.summary, root.modelData.urgency) - color: root.modelData.getIconColor() - font.pointSize: Appearance.font.size.large - } - } -} - diff --git a/modules/notifications/Content.qml b/modules/notifications/Content.qml index 035a228..2d4590e 100644 --- a/modules/notifications/Content.qml +++ b/modules/notifications/Content.qml @@ -13,8 +13,6 @@ Item { required property Item panels readonly property int padding: Appearance.padding.large - property bool shouldShow: false - anchors.top: parent.top anchors.bottom: parent.bottom anchors.right: parent.right @@ -22,16 +20,13 @@ Item { implicitWidth: Config.notifs.sizes.width + padding * 2 implicitHeight: { const count = list.count; - if (count === 0 || !shouldShow) + if (count === 0) return 0; let height = (count - 1) * Appearance.spacing.smaller; for (let i = 0; i < count; i++) height += list.itemAtIndex(i)?.nonAnimHeight ?? 0; - const screenHeight = QsWindow.window?.screen?.height ?? 0; - const maxHeight = Math.floor(screenHeight * 0.45); - if (visibilities && panels) { if (visibilities.osd) { const h = panels.osd.y - Config.border.rounding * 2 - padding * 2; @@ -46,8 +41,7 @@ Item { } } - const availableHeight = Math.min(maxHeight, screenHeight - Config.border.thickness * 2); - return Math.min(availableHeight, height + padding * 2); + return Math.min((QsWindow.window?.screen?.height ?? 0) - Config.border.thickness * 2, height + padding * 2); } ClippingWrapperRectangle { @@ -61,7 +55,7 @@ Item { id: list model: ScriptModel { - values: [...Notifs.notClosed] + values: Notifs.popups.filter(n => !n.closed) } anchors.fill: parent @@ -198,52 +192,6 @@ Item { } } - Timer { - id: hideTimer - - interval: 5000 - onTriggered: { - if (list.count > 0) - root.shouldShow = false; - } - } - - function show(): void { - if (list.count > 0) { - shouldShow = true; - hideTimer.restart(); - } - } - - Connections { - target: list - - function onCountChanged(): void { - if (list.count === 0) { - root.shouldShow = false; - hideTimer.stop(); - } - } - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.NoButton - onEntered: { - if (list.count > 0) { - root.shouldShow = true; - hideTimer.restart(); - } - } - onExited: { - if (list.count > 0) { - root.shouldShow = false; - hideTimer.stop(); - } - } - } - Behavior on implicitHeight { Anim {} } diff --git a/modules/notifications/Notification.qml b/modules/notifications/Notification.qml index bc5c086..95507fc 100644 --- a/modules/notifications/Notification.qml +++ b/modules/notifications/Notification.qml @@ -17,31 +17,22 @@ StyledRect { required property Notifs.Notif modelData readonly property bool hasImage: modelData.image.length > 0 readonly property bool hasAppIcon: modelData.appIcon.length > 0 - readonly property int nonAnimHeight: { - const baseHeight = summary.implicitHeight + inner.anchors.margins * 2; - return root.expanded - ? baseHeight + appName.height + body.height + actions.height + actions.anchors.topMargin - : baseHeight + bodyPreview.height; - } + readonly property int nonAnimHeight: summary.implicitHeight + (root.expanded ? appName.height + body.height + actions.height + actions.anchors.topMargin : bodyPreview.height) + inner.anchors.margins * 2 property bool expanded - property bool disableSlideIn: false - color: modelData.getBackgroundColor() + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3secondaryContainer : Colours.tPalette.m3surfaceContainer radius: Appearance.rounding.normal implicitWidth: Config.notifs.sizes.width implicitHeight: inner.implicitHeight - x: disableSlideIn ? 0 : Config.notifs.sizes.width + x: Config.notifs.sizes.width Component.onCompleted: { - if (!root.disableSlideIn) { - x = 0; - } + x = 0; modelData.lock(this); } Component.onDestruction: modelData.unlock(this) Behavior on x { - enabled: !disableSlideIn Anim { easing.bezierCurve: Appearance.anim.curves.emphasizedDecel } @@ -143,18 +134,53 @@ StyledRect { Loader { id: appIcon - active: !root.hasImage || root.hasAppIcon - asynchronous: false + active: root.hasAppIcon || !root.hasImage + asynchronous: true anchors.horizontalCenter: root.hasImage ? undefined : image.horizontalCenter anchors.verticalCenter: root.hasImage ? undefined : image.verticalCenter anchors.right: root.hasImage ? image.right : undefined anchors.bottom: root.hasImage ? image.bottom : undefined - sourceComponent: AppIconBadge { - modelData: root.modelData - hasImage: root.hasImage - hasAppIcon: root.hasAppIcon + sourceComponent: StyledRect { + radius: Appearance.rounding.full + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3error : root.modelData.urgency === NotificationUrgency.Low ? Colours.layer(Colours.palette.m3surfaceContainerHighest, 2) : Colours.palette.m3secondaryContainer + implicitWidth: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image + implicitHeight: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image + + Loader { + id: icon + + active: root.hasAppIcon + asynchronous: true + + anchors.centerIn: parent + + width: Math.round(parent.width * 0.6) + height: Math.round(parent.width * 0.6) + + sourceComponent: ColouredIcon { + anchors.fill: parent + source: Quickshell.iconPath(root.modelData.appIcon) + colour: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onError : root.modelData.urgency === NotificationUrgency.Low ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer + layer.enabled: root.modelData.appIcon.endsWith("symbolic") + } + } + + Loader { + active: !root.hasAppIcon + asynchronous: true + anchors.centerIn: parent + anchors.horizontalCenterOffset: -Appearance.font.size.large * 0.02 + anchors.verticalCenterOffset: Appearance.font.size.large * 0.02 + + sourceComponent: MaterialIcon { + text: Icons.getNotifIcon(root.modelData.summary, root.modelData.urgency) + + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onError : root.modelData.urgency === NotificationUrgency.Low ? Colours.palette.m3onSurface : Colours.palette.m3onSecondaryContainer + font.pointSize: Appearance.font.size.large + } + } } } @@ -296,7 +322,7 @@ StyledRect { StateLayer { radius: Appearance.rounding.full - color: root.modelData.getStateLayerColor() + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface function onClicked() { root.expanded = !root.expanded; @@ -417,7 +443,7 @@ StyledRect { required property var modelData radius: Appearance.rounding.full - color: root.modelData.getActionBackgroundColor() + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3secondary : Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) Layout.preferredWidth: actionText.width + Appearance.padding.normal * 2 Layout.preferredHeight: actionText.height + Appearance.padding.small * 2 @@ -426,7 +452,7 @@ StyledRect { StateLayer { radius: Appearance.rounding.full - color: root.modelData.getStateLayerColor() + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onSecondary : Colours.palette.m3onSurface function onClicked(): void { action.modelData.invoke(); @@ -438,7 +464,7 @@ StyledRect { anchors.centerIn: parent text: actionTextMetrics.elidedText - color: root.modelData.getActionTextColor() + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onSecondary : Colours.palette.m3onSurfaceVariant font.pointSize: Appearance.font.size.small } diff --git a/modules/notifications/NotificationToast.qml b/modules/notifications/NotificationToast.qml deleted file mode 100644 index 90414fe..0000000 --- a/modules/notifications/NotificationToast.qml +++ /dev/null @@ -1,120 +0,0 @@ -import qs.components -import qs.components.effects -import qs.services -import qs.config -import qs.utils -import Quickshell -import Quickshell.Widgets -import Quickshell.Services.Notifications -import QtQuick -import QtQuick.Layouts - -StyledRect { - id: root - - required property Notifs.Notif modelData - - readonly property bool hasImage: modelData.image.length > 0 - readonly property bool hasAppIcon: modelData.appIcon.length > 0 - - anchors.left: parent.left - anchors.right: parent.right - implicitHeight: layout.implicitHeight + Appearance.padding.smaller * 2 - - radius: Appearance.rounding.normal - color: Colours.palette.m3surface - - border.width: 1 - border.color: Colours.palette.m3outlineVariant - - Elevation { - anchors.fill: parent - radius: parent.radius - opacity: parent.opacity - z: -1 - level: 3 - } - - RowLayout { - id: layout - - anchors.fill: parent - anchors.margins: Appearance.padding.smaller - anchors.leftMargin: Appearance.padding.normal - anchors.rightMargin: Appearance.padding.normal - spacing: Appearance.spacing.normal - - Item { - Layout.preferredWidth: Config.notifs.sizes.image - Layout.preferredHeight: Config.notifs.sizes.image - - Loader { - id: imageLoader - - active: root.hasImage - asynchronous: true - anchors.fill: parent - - sourceComponent: ClippingRectangle { - radius: Appearance.rounding.full - implicitWidth: Config.notifs.sizes.image - implicitHeight: Config.notifs.sizes.image - - Image { - anchors.fill: parent - source: Qt.resolvedUrl(root.modelData.image) - fillMode: Image.PreserveAspectCrop - cache: false - asynchronous: true - } - } - } - - Loader { - id: appIconLoader - - active: root.hasAppIcon || !root.hasImage - asynchronous: true - - anchors.horizontalCenter: root.hasImage ? undefined : parent.horizontalCenter - anchors.verticalCenter: root.hasImage ? undefined : parent.verticalCenter - anchors.right: root.hasImage ? parent.right : undefined - anchors.bottom: root.hasImage ? parent.bottom : undefined - - sourceComponent: AppIconBadge { - modelData: root.modelData - hasImage: root.hasImage - hasAppIcon: root.hasAppIcon - } - } - } - - ColumnLayout { - Layout.fillWidth: true - spacing: 0 - - StyledText { - id: title - - Layout.fillWidth: true - text: root.modelData.summary - color: Colours.palette.m3onSurface - font.pointSize: Appearance.font.size.normal - elide: Text.ElideRight - } - - StyledText { - Layout.fillWidth: true - textFormat: Text.StyledText - text: root.modelData.body - color: Colours.palette.m3onSurface - opacity: 0.8 - elide: Text.ElideRight - } - } - } - - Behavior on border.color { - CAnim {} - } -} diff --git a/modules/notifications/NotificationToasts.qml b/modules/notifications/NotificationToasts.qml deleted file mode 100644 index 96fe817..0000000 --- a/modules/notifications/NotificationToasts.qml +++ /dev/null @@ -1,186 +0,0 @@ -pragma ComponentBehavior: Bound - -import qs.components -import qs.config -import qs.services -import Quickshell -import Quickshell.Widgets -import QtQuick - -Item { - id: root - - required property Item panels - - readonly property int spacing: Appearance.spacing.small - readonly property int maxToasts: 5 - readonly property bool listVisible: panels.notifications.content.shouldShow - - property bool flag - property var activeToasts: new Set() - - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: Appearance.padding.normal - - implicitWidth: Config.notifs.sizes.width - implicitHeight: { - if (listVisible) - return 0; - - let height = -spacing; - for (let i = 0; i < repeater.count; i++) { - const item = repeater.itemAt(i) as ToastWrapper; - if (item && !item.modelData.closed && !item.previewHidden) - height += item.implicitHeight + spacing; - } - return height; - } - - opacity: listVisible ? 0 : 1 - visible: opacity > 0 - - Behavior on opacity { - Anim { - duration: Appearance.anim.durations.expressiveDefaultSpatial - } - } - - Repeater { - id: repeater - - model: ScriptModel { - values: { - const toasts = []; - let visibleCount = 0; - - for (const notif of Notifs.list) { - if (notif.showAsToast) { - root.activeToasts.add(notif); - } - if (notif.closed) { - root.activeToasts.delete(notif); - } - } - - for (const notif of Notifs.list) { - if (root.activeToasts.has(notif)) { - toasts.push(notif); - if (notif.showAsToast && !notif.closed) { - visibleCount++; - if (visibleCount > root.maxToasts) - break; - } - } - } - return toasts; - } - onValuesChanged: root.flagChanged() - } - - ToastWrapper {} - } - - component ToastWrapper: MouseArea { - id: toast - - required property int index - required property Notifs.Notif modelData - - readonly property bool previewHidden: { - let extraHidden = 0; - for (let i = 0; i < index; i++) { - const item = repeater.itemAt(i); - if (item && item.modelData.closed) - extraHidden++; - } - return index >= root.maxToasts + extraHidden; - } - - opacity: modelData.closed || previewHidden || !modelData.showAsToast ? 0 : 1 - scale: modelData.closed || previewHidden || !modelData.showAsToast ? 0.7 : 1 - - anchors.topMargin: { - root.flag; - let margin = 0; - for (let i = 0; i < index; i++) { - const item = repeater.itemAt(i) as ToastWrapper; - if (item && !item.modelData.closed && !item.previewHidden) - margin += item.implicitHeight + root.spacing; - } - return margin; - } - - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - implicitHeight: toastInner.implicitHeight - - acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton - onClicked: { - modelData.showAsToast = false; - modelData.close(); - } - - Component.onCompleted: modelData.lock(this) - - onPreviewHiddenChanged: { - if (initAnim.running && previewHidden) - initAnim.stop(); - } - - Anim { - id: initAnim - - Component.onCompleted: running = !toast.previewHidden - - target: toast - properties: "opacity,scale" - from: 0 - to: 1 - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - - ParallelAnimation { - running: toast.modelData.closed || (!toast.modelData.showAsToast && !toast.modelData.closed) - onStarted: toast.anchors.topMargin = toast.anchors.topMargin - onFinished: { - if (toast.modelData.closed) - toast.modelData.unlock(toast); - } - - Anim { - target: toast - property: "opacity" - to: 0 - } - Anim { - target: toast - property: "scale" - to: 0.7 - } - } - - NotificationToast { - id: toastInner - - modelData: toast.modelData - } - - Behavior on opacity { - Anim {} - } - - Behavior on scale { - Anim {} - } - - Behavior on anchors.topMargin { - Anim { - duration: Appearance.anim.durations.expressiveDefaultSpatial - easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial - } - } - } -} diff --git a/modules/notifications/Wrapper.qml b/modules/notifications/Wrapper.qml index 4b54883..61acc56 100644 --- a/modules/notifications/Wrapper.qml +++ b/modules/notifications/Wrapper.qml @@ -8,8 +8,6 @@ Item { required property var visibilities required property Item panels - readonly property alias content: content - visible: height > 0 implicitWidth: Math.max(panels.sidebar.width, content.implicitWidth) implicitHeight: content.implicitHeight diff --git a/modules/utilities/toasts/ToastItem.qml b/modules/utilities/toasts/ToastItem.qml index 477a23c..f475500 100644 --- a/modules/utilities/toasts/ToastItem.qml +++ b/modules/utilities/toasts/ToastItem.qml @@ -28,13 +28,14 @@ StyledRect { border.width: 1 border.color: { + let colour = Colours.palette.m3outlineVariant; if (root.modelData.type === Toast.Success) - return Colours.palette.m3success; + colour = Colours.palette.m3success; if (root.modelData.type === Toast.Warning) - return Colours.palette.m3secondaryContainer; + colour = Colours.palette.m3secondaryContainer; if (root.modelData.type === Toast.Error) - return Colours.palette.m3error; - return Colours.palette.m3outlineVariant; + colour = Colours.palette.m3error; + return Qt.alpha(colour, 0.3); } Elevation { |