feat: add wip notifications to dash
This commit is contained in:
parent
4e9a6eaa4a
commit
c4b71fc0d4
11 changed files with 184 additions and 103 deletions
|
@ -1,9 +1,11 @@
|
|||
import Quickshell
|
||||
import Quickshell.Services.Notifications
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQml
|
||||
import "base"
|
||||
import "widgets/mpris"
|
||||
import "widgets/notifications"
|
||||
import "provider"
|
||||
|
||||
PanelWindow {
|
||||
|
@ -47,23 +49,6 @@ PanelWindow {
|
|||
|
||||
Component.onCompleted: () => maxSize = homeWindow.screen.width * (2 / 7)
|
||||
|
||||
ListView {
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
model: Notifications.incoming
|
||||
|
||||
delegate: Rectangle {
|
||||
required property var modelData
|
||||
width: 100
|
||||
height: 50
|
||||
Text {
|
||||
text: parent.modelData.appName
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
PropertyAnimation {
|
||||
id: anim
|
||||
|
@ -89,6 +74,32 @@ PanelWindow {
|
|||
Layout.margins: 15
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
|
||||
ListView {
|
||||
id: popupcol
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1000
|
||||
spacing: 10
|
||||
width: parent.width
|
||||
Component.onCompleted: () => {}
|
||||
|
||||
model: Notifications.list
|
||||
|
||||
delegate: NotificationToast {
|
||||
id: toast
|
||||
|
||||
required property var modelData
|
||||
required property int index
|
||||
|
||||
notif: modelData
|
||||
width: ListView.view.width
|
||||
|
||||
onClose: {
|
||||
toast.notif.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MprisSmall {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import "widgets/caffeine"
|
|||
import "windows/notificationtoast"
|
||||
import "windows/workspace-view"
|
||||
import "base"
|
||||
import "provider"
|
||||
import Quickshell // for ShellRoot and PanelWindow
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
@ -18,9 +19,11 @@ PanelWindow {
|
|||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
left: Config.alignment === Config.BarAlignment.Left
|
||||
right: Config.alignment === Config.BarAlignment.Right
|
||||
bottom: true
|
||||
}
|
||||
|
||||
margins.left: 2
|
||||
margins.top: 2
|
||||
margins.bottom: 2
|
||||
|
@ -68,6 +71,7 @@ PanelWindow {
|
|||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouse
|
||||
onClicked: lbar.root.enabled = !lbar.root.enabled
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import QtQuick
|
||||
import "../provider"
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
|
@ -6,5 +7,5 @@ Rectangle {
|
|||
border.color: "black"
|
||||
border.width: 1
|
||||
radius: 5
|
||||
color: "#BD93F9"
|
||||
color: Config.colours.main
|
||||
}
|
||||
|
|
22
src/provider/Config.qml
Normal file
22
src/provider/Config.qml
Normal file
|
@ -0,0 +1,22 @@
|
|||
pragma Singleton
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
id: config
|
||||
property Item notifications: Item {
|
||||
property int toastDuration: 5000
|
||||
}
|
||||
|
||||
enum BarAlignment {
|
||||
Left,
|
||||
Right
|
||||
}
|
||||
|
||||
property int alignment: Config.BarAlignment.Left
|
||||
|
||||
property Item colours: Item {
|
||||
property color main: "#BD93F9"
|
||||
}
|
||||
}
|
|
@ -3,11 +3,13 @@ pragma Singleton
|
|||
import Quickshell.Services.Notifications
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import "../utils/timer.mjs" as Timer
|
||||
|
||||
Singleton {
|
||||
id: notif
|
||||
|
||||
property var _: NotificationServer {
|
||||
id: server
|
||||
actionIconsSupported: true
|
||||
actionsSupported: true
|
||||
bodyHyperlinksSupported: true
|
||||
|
@ -18,10 +20,17 @@ Singleton {
|
|||
|
||||
onNotification: n => {
|
||||
n.tracked = true;
|
||||
incoming.push(n);
|
||||
|
||||
notif.incomingAdded(n);
|
||||
|
||||
Timer.after(1000, notif, () => {
|
||||
notif.incomingRemoved(n.id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
property list<Notification> backlog: notif._.trackedNotifications
|
||||
property list<Notification> incoming: []
|
||||
property alias list: server.trackedNotifications
|
||||
|
||||
signal incomingRemoved(id: int)
|
||||
signal incomingAdded(id: Notification)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
module Provider
|
||||
singleton Config 0.1 Config.qml
|
||||
singleton Player 0.1 Player.qml
|
||||
singleton Inhibitor 0.1 Inhibitor.qml
|
||||
singleton Notifications 0.1 Notifications.qml
|
||||
|
|
2
src/utils/qmldir
Normal file
2
src/utils/qmldir
Normal file
|
@ -0,0 +1,2 @@
|
|||
module Utils
|
||||
Timer 0.1 timer.mjs
|
13
src/utils/timer.mjs
Normal file
13
src/utils/timer.mjs
Normal file
|
@ -0,0 +1,13 @@
|
|||
export function Timer(parent) {
|
||||
return Qt.createQmlObject("import QtQuick; Timer {}", parent);
|
||||
}
|
||||
|
||||
export function after(delay, parent, callback) {
|
||||
const timer = new Timer(parent);
|
||||
|
||||
timer.interval = delay;
|
||||
|
||||
timer.triggered.connect(callback);
|
||||
|
||||
timer.start();
|
||||
}
|
|
@ -1,40 +1,43 @@
|
|||
pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import "../../base"
|
||||
import "../../provider"
|
||||
import Quickshell.Services.Notifications
|
||||
|
||||
MouseArea {
|
||||
id: toast
|
||||
readonly property int lifetime: 5000
|
||||
property int countdownTime: lifetime
|
||||
|
||||
required property string appName
|
||||
required property string summary
|
||||
required property string body
|
||||
required property string appIcon
|
||||
required property string image
|
||||
required property NotificationUrgency urgency
|
||||
required property bool hasActionIcons
|
||||
required property var actions
|
||||
required property int index
|
||||
Component.onCompleted: () => console.log(toast.actions.values)
|
||||
required property Notification notif
|
||||
|
||||
function close(): void {
|
||||
popupcol.model.remove(toast.index, 1);
|
||||
property int actionHeight: 30
|
||||
property int expansionSpeed: 200
|
||||
property bool showTimeBar: false
|
||||
|
||||
property string body
|
||||
property string appName
|
||||
property string summary
|
||||
property string appIcon
|
||||
|
||||
Component.onCompleted: {
|
||||
body = notif?.body ?? "";
|
||||
appName = notif?.appName ?? "";
|
||||
summary = notif?.summary ?? "";
|
||||
appIcon = notif?.appIcon ?? "";
|
||||
}
|
||||
|
||||
hoverEnabled: true
|
||||
height: box.height
|
||||
width: popupcol.width
|
||||
hoverEnabled: true
|
||||
|
||||
signal close
|
||||
|
||||
BRectangle {
|
||||
id: box
|
||||
width: parent.width
|
||||
height: header.height + actions.height + test.height + (5 * 3)
|
||||
height: header.height + toast.actionHeight + bodyBox.height + (5 * 3)
|
||||
|
||||
clip: true
|
||||
|
||||
|
@ -52,29 +55,25 @@ MouseArea {
|
|||
source: toast.appIcon ? Quickshell.iconPath(toast.appIcon) : ""
|
||||
height: parent.height
|
||||
width: height
|
||||
visible: toast.appIcon
|
||||
visible: toast.appIcon ?? false
|
||||
}
|
||||
|
||||
Text {
|
||||
text: (toast.appIcon ? " " : toast.appName + ": ") + toast.summary
|
||||
text: `${toast.appIcon ? "" : `${toast.appName}:`} ${toast.summary}`
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: 12.5
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.rightMargin: 16
|
||||
Button {
|
||||
onClicked: toast.close()
|
||||
height: 16
|
||||
width: 16
|
||||
}
|
||||
Button {
|
||||
onClicked: toast.close()
|
||||
height: 16
|
||||
width: 16
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: test
|
||||
id: bodyBox
|
||||
width: parent.width
|
||||
anchors.top: header.bottom
|
||||
height: 60
|
||||
|
@ -85,17 +84,19 @@ MouseArea {
|
|||
Text {
|
||||
id: text
|
||||
anchors.topMargin: 5
|
||||
text: toast.body
|
||||
text: toast.body ?? ""
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
wrapMode: Text.Wrap
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: 12.5
|
||||
|
||||
Component.onCompleted: () => {
|
||||
if (text.implicitHeight < test.height) {
|
||||
test.height = text.implicitHeight;
|
||||
if (text.implicitHeight < bodyBox.height) {
|
||||
bodyBox.height = text.implicitHeight;
|
||||
}
|
||||
test.maxHeight = text.implicitHeight;
|
||||
|
||||
bodyBox.maxHeight = Qt.binding(() => text.implicitHeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,67 +104,55 @@ MouseArea {
|
|||
name: "expand"
|
||||
when: toast.containsMouse
|
||||
PropertyChanges {
|
||||
target: test
|
||||
height: test.maxHeight
|
||||
target: bodyBox
|
||||
height: bodyBox.maxHeight
|
||||
}
|
||||
}
|
||||
|
||||
transitions: Transition {
|
||||
NumberAnimation {
|
||||
properties: "width,height"
|
||||
duration: 50
|
||||
easing.type: Easing.InOutQuad
|
||||
properties: "height"
|
||||
duration: toast.expansionSpeed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: actions
|
||||
width: parent.width
|
||||
anchors.top: test.bottom
|
||||
anchors.top: bodyBox.bottom
|
||||
anchors.topMargin: 5
|
||||
anchors.bottomMargin: 5
|
||||
Repeater {
|
||||
model: toast.actions
|
||||
id: rep
|
||||
model: toast.notif?.actions
|
||||
|
||||
delegate: ToastAction {
|
||||
delegate: NotificationToastAction {
|
||||
required property var modelData
|
||||
notifAction: modelData
|
||||
hasIcons: toast.hasActionIcons
|
||||
hasIcons: toast.notif?.hasActionIcons ?? false
|
||||
height: toast.actionHeight
|
||||
}
|
||||
}
|
||||
|
||||
visible: toast?.actions ? true : false
|
||||
}
|
||||
|
||||
states: State {
|
||||
name: "expand"
|
||||
when: toast.containsMouse
|
||||
PropertyChanges {
|
||||
target: box
|
||||
height: test.height + header.height + actions.height + 15
|
||||
}
|
||||
}
|
||||
|
||||
transitions: Transition {
|
||||
NumberAnimation {
|
||||
properties: "width,height"
|
||||
duration: 50
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
visible: toast.notif?.actions.length ?? false
|
||||
}
|
||||
}
|
||||
|
||||
NumberAnimation on width {
|
||||
duration: toast.expansionSpeed
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: timeBar
|
||||
visible: toast.showTimeBar
|
||||
anchors.margins: 2
|
||||
anchors.bottom: box.bottom
|
||||
anchors.right: box.right
|
||||
width: (box.width - box.border.width - anchors.margins) * (toast.countdownTime / toast.lifetime)
|
||||
width: box.width - box.border.width - anchors.margins
|
||||
height: 2
|
||||
bottomLeftRadius: box.radius
|
||||
bottomRightRadius: box.radius
|
||||
color: {
|
||||
switch (toast.urgency) {
|
||||
switch (toast.notif?.urgency) {
|
||||
case NotificationUrgency.Critical:
|
||||
return "red";
|
||||
break;
|
||||
|
@ -174,21 +163,13 @@ MouseArea {
|
|||
return "white";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
interval: 10
|
||||
repeat: !toast.containsMouse
|
||||
onTriggered: () => {
|
||||
toast.countdownTime -= timer.interval;
|
||||
if (toast.countdownTime <= 0) {
|
||||
toast.parent.parent.model.remove(toast.index, 1);
|
||||
timer.repeat = false;
|
||||
timer.running = false;
|
||||
NumberAnimation on width {
|
||||
to: 0
|
||||
duration: Config.notifications.toastDuration
|
||||
paused: toast.containsMouse && timeBar.visible
|
||||
running: timeBar.visible
|
||||
}
|
||||
}
|
||||
running: !toast.containsMouse
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ import Quickshell
|
|||
import QtQuick.Controls
|
||||
import "root:provider"
|
||||
import "root:base"
|
||||
import "../../widgets/notifications"
|
||||
|
||||
PanelWindow {
|
||||
id: popups
|
||||
|
@ -36,11 +37,15 @@ PanelWindow {
|
|||
anchors.margins: lbar.width * 0.2
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
spacing: 10
|
||||
|
||||
model: ListModel {
|
||||
id: data
|
||||
Component.onCompleted: () => {
|
||||
Notifications._.notification.connect(e => {
|
||||
data.insert(0, e);
|
||||
Notifications.incomingAdded.connect(n => {
|
||||
data.insert(0, {
|
||||
notif: n
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -80,8 +85,40 @@ PanelWindow {
|
|||
}
|
||||
}
|
||||
|
||||
spacing: 10
|
||||
delegate: Toast {}
|
||||
delegate: NotificationToast {
|
||||
id: toast
|
||||
|
||||
property int countdownTime: Config.notifications.toastDuration
|
||||
required property int index
|
||||
|
||||
width: ListView.view.width
|
||||
showTimeBar: true
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
interval: 100
|
||||
onTriggered: () => {
|
||||
toast.countdownTime -= interval;
|
||||
if (toast.countdownTime <= 0) {
|
||||
toast.close();
|
||||
}
|
||||
}
|
||||
repeat: true
|
||||
running: !toast.containsMouse && toast.countdownTime > 0
|
||||
}
|
||||
|
||||
Component.onCompleted: notif.closed.connect(() => {
|
||||
if (!toast || toast.index < 0)
|
||||
return;
|
||||
ListView.view.model.remove(toast.index, 1);
|
||||
})
|
||||
|
||||
onClose: {
|
||||
if (!toast || toast.index < 0)
|
||||
return;
|
||||
ListView.view.model.remove(toast.index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue