Notification backend usable
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
.qmlls.ini
|
||||
.qmlls.ini
|
||||
scripts/
|
||||
|
||||
@@ -26,9 +26,6 @@ WrapperRectangle {
|
||||
item.monitor = barArea.monitor;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ Item {
|
||||
|
||||
color: Theme.backgroudColor
|
||||
implicitWidth: clockText.implicitWidth * 1.6
|
||||
implicitHeight: Theme.heightGaps
|
||||
implicitHeight: Theme.heightGaps
|
||||
radius: 25
|
||||
|
||||
property string calendar: ""
|
||||
@@ -36,9 +36,11 @@ Item {
|
||||
Process {
|
||||
id: cal
|
||||
running: true
|
||||
command: ["cal","-S3"]
|
||||
command: ["cal", "-S3"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {clock.calendar=this.text}
|
||||
onStreamFinished: {
|
||||
clock.calendar = this.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,15 +48,12 @@ Item {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: {
|
||||
cal.running = true
|
||||
PopUpHover.start(clock,"time")
|
||||
cal.running = true;
|
||||
PopUpHover.start(clock, "time");
|
||||
}
|
||||
onExited: {
|
||||
PopUpHover.exit()
|
||||
PopUpHover.exit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import qs.Widgets
|
||||
import Quickshell.Services.Notifications
|
||||
|
||||
Item {
|
||||
id: root
|
||||
id: root
|
||||
|
||||
property var monitor: ""
|
||||
property bool createWindow: false
|
||||
@@ -17,6 +17,12 @@ Item {
|
||||
leftMargin: Theme.gaps
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: root
|
||||
property: "createWindow"
|
||||
value: NotificationService.notificationsNumber > 0 && root.createWindow
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: Theme.backgroudColor
|
||||
implicitWidth: clockText.implicitWidth * 1.6
|
||||
@@ -28,7 +34,7 @@ Item {
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: {
|
||||
NotificationService.notificationsNumber > 0 ? "\udb80\udc9a "+NotificationService.notificationsNumber : "\ueaa2";
|
||||
NotificationService.notificationsNumber > 0 ? "\udb80\udc9a " + NotificationService.notificationsNumber : "\ueaa2";
|
||||
}
|
||||
font.bold: true
|
||||
font.pixelSize: Theme.pixelSize
|
||||
@@ -39,18 +45,15 @@ Item {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
console.log(NotificationService.currentNotification.image);
|
||||
root.createWindow = true
|
||||
root.createWindow = !root.createWindow;
|
||||
}
|
||||
}
|
||||
}
|
||||
LazyLoader {
|
||||
id: windowLoader
|
||||
|
||||
active: root.createWindow
|
||||
active: NotificationService.notificationsNumber ? createWindow : false
|
||||
|
||||
component: NotificationWindow {
|
||||
anchor.item:root
|
||||
}
|
||||
component: NotificationWindow {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,70 +10,68 @@ Singleton {
|
||||
|
||||
property var sortedTopLevels: {
|
||||
if (!ToplevelManager.toplevels || !ToplevelManager.toplevels.values) {
|
||||
return []
|
||||
return [];
|
||||
}
|
||||
|
||||
const topLevels = Array.from(Hyprland.toplevels.values)
|
||||
const topLevels = Array.from(Hyprland.toplevels.values);
|
||||
const sortedHyprland = topLevels.sort((a, b) => {
|
||||
if (a.monitor && b.monitor) {
|
||||
const monitorCompare = a.monitor.name.localeCompare(b.monitor.name)
|
||||
if (monitorCompare !== 0) {
|
||||
return monitorCompare
|
||||
}
|
||||
}
|
||||
if (a.monitor && b.monitor) {
|
||||
const monitorCompare = a.monitor.name.localeCompare(b.monitor.name);
|
||||
if (monitorCompare !== 0) {
|
||||
return monitorCompare;
|
||||
}
|
||||
}
|
||||
|
||||
if (a.workspace && b.workspace) {
|
||||
const workspaceCompare = a.workspace.id - b.workspace.id
|
||||
if (workspaceCompare !== 0) {
|
||||
return workspaceCompare
|
||||
}
|
||||
}
|
||||
if (a.workspace && b.workspace) {
|
||||
const workspaceCompare = a.workspace.id - b.workspace.id;
|
||||
if (workspaceCompare !== 0) {
|
||||
return workspaceCompare;
|
||||
}
|
||||
}
|
||||
|
||||
if (a.lastIpcObject && b.lastIpcObject && a.lastIpcObject.at && b.lastIpcObject.at) {
|
||||
const aX = a.lastIpcObject.at[0]
|
||||
const bX = b.lastIpcObject.at[0]
|
||||
const aY = a.lastIpcObject.at[1]
|
||||
const bY = b.lastIpcObject.at[1]
|
||||
if (a.lastIpcObject && b.lastIpcObject && a.lastIpcObject.at && b.lastIpcObject.at) {
|
||||
const aX = a.lastIpcObject.at[0];
|
||||
const bX = b.lastIpcObject.at[0];
|
||||
const aY = a.lastIpcObject.at[1];
|
||||
const bY = b.lastIpcObject.at[1];
|
||||
|
||||
const xCompare = aX - bX
|
||||
if (Math.abs(xCompare) > 10) {
|
||||
return xCompare
|
||||
}
|
||||
return aY - bY
|
||||
}
|
||||
const xCompare = aX - bX;
|
||||
if (Math.abs(xCompare) > 10) {
|
||||
return xCompare;
|
||||
}
|
||||
return aY - bY;
|
||||
}
|
||||
|
||||
if (a.lastIpcObject && !b.lastIpcObject) {
|
||||
return -1
|
||||
}
|
||||
if (!a.lastIpcObject && b.lastIpcObject) {
|
||||
return 1
|
||||
}
|
||||
if (a.lastIpcObject && !b.lastIpcObject) {
|
||||
return -1;
|
||||
}
|
||||
if (!a.lastIpcObject && b.lastIpcObject) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (a.title && b.title) {
|
||||
return a.title.localeCompare(b.title)
|
||||
}
|
||||
|
||||
return 0
|
||||
})
|
||||
return sortedHyprland.filter(tl => tl.wayland !== null)
|
||||
if (a.title && b.title) {
|
||||
return a.title.localeCompare(b.title);
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
return sortedHyprland.filter(tl => tl.wayland !== null);
|
||||
}
|
||||
|
||||
property var topLevelWorkspaces: {
|
||||
return sortedTopLevels.map(topLevel => topLevel.workspace)
|
||||
return sortedTopLevels.map(topLevel => topLevel.workspace);
|
||||
}
|
||||
|
||||
property var sortedDesktopApplications: {
|
||||
const sortedWayland = sortedTopLevels.map(topLevel => topLevel.wayland).filter(wayland=> wayland !== null)
|
||||
|
||||
const desktopEntries = sortedWayland.map( topLevel => {
|
||||
return DesktopEntries.heuristicLookup(topLevel.appId)
|
||||
})
|
||||
const workspace = sortedTopLevels.map( topLevel => {
|
||||
return topLevel.workspace.id
|
||||
})
|
||||
const workspaceDesktopEntries = new Map()
|
||||
const sortedWayland = sortedTopLevels.map(topLevel => topLevel.wayland).filter(wayland => wayland !== null);
|
||||
|
||||
const desktopEntries = sortedWayland.map(topLevel => {
|
||||
return DesktopEntries.heuristicLookup(topLevel.appId);
|
||||
});
|
||||
const workspace = sortedTopLevels.map(topLevel => {
|
||||
return topLevel.workspace.id;
|
||||
});
|
||||
const workspaceDesktopEntries = new Map();
|
||||
|
||||
for (let i = 0; i < workspace.length; i++) {
|
||||
const key = workspace[i];
|
||||
@@ -85,8 +83,6 @@ Singleton {
|
||||
workspaceDesktopEntries.set(key, [value]);
|
||||
}
|
||||
}
|
||||
return workspaceDesktopEntries
|
||||
|
||||
return workspaceDesktopEntries;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,13 @@ pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Services.Notifications
|
||||
import Quickshell.Widgets
|
||||
import qs.Widgets
|
||||
|
||||
Singleton {
|
||||
id: notificationRoot
|
||||
|
||||
|
||||
readonly property var notificationServer: notificationServer
|
||||
readonly property var trackedNotifications: notificationServer.trackedNotifications
|
||||
readonly property var notificationsNumber: notificationServer.trackedNotifications.values.length
|
||||
@@ -29,6 +26,9 @@ Singleton {
|
||||
notif.dismiss();
|
||||
return;
|
||||
}
|
||||
if (notif.traked) {
|
||||
return;
|
||||
}
|
||||
notif.tracked = true;
|
||||
notificationRoot.currentNotification = notif;
|
||||
notificationRoot.shouldShowOsd = true;
|
||||
@@ -47,19 +47,33 @@ Singleton {
|
||||
|
||||
LazyLoader {
|
||||
id: popupLoader
|
||||
active: currentNotification && shouldShowOsd
|
||||
active: notificationRoot.currentNotification && notificationRoot.shouldShowOsd
|
||||
|
||||
component: NotificationPopup {
|
||||
notification: currentNotification
|
||||
// No signal handler here!
|
||||
}
|
||||
component: PanelWindow {
|
||||
id: notificationWindow
|
||||
|
||||
onItemChanged: {
|
||||
if (item) {
|
||||
item.dismissed.connect(function() {
|
||||
notificationRoot.shouldShowOsd = false
|
||||
currentNotification.dismiss()
|
||||
})
|
||||
anchors.top: true
|
||||
margins.top: screen.height / 100
|
||||
exclusiveZone: 0
|
||||
|
||||
implicitWidth: 400
|
||||
implicitHeight: 905
|
||||
color: "transparent"
|
||||
|
||||
NotificationWrapper {
|
||||
id: notificationWrapper
|
||||
|
||||
notification: notificationRoot.currentNotification
|
||||
implicitWidth: notificationWindow.implicitWidth
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log(notificationWrapper.height);
|
||||
popupLoader.implicitHeight = notificationWrapper.implicitHeight;
|
||||
}
|
||||
onDismissed: {
|
||||
notificationRoot.shouldShowOsd = false;
|
||||
notificationRoot.currentNotification.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,33 +8,32 @@ import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
|
||||
Singleton {
|
||||
|
||||
function start(component, type) {
|
||||
HoverMediator.component = component
|
||||
HoverMediator.type = type
|
||||
hoverPopUp.anchor.updateAnchor()
|
||||
hoverTimer.start()
|
||||
HoverMediator.component = component;
|
||||
HoverMediator.type = type;
|
||||
hoverPopUp.anchor.updateAnchor();
|
||||
hoverTimer.start();
|
||||
}
|
||||
|
||||
function exit() {
|
||||
hoverTimer.stop()
|
||||
hoverPopUp.visible = false
|
||||
hoverTimer.stop();
|
||||
hoverPopUp.visible = false;
|
||||
}
|
||||
|
||||
PopupWindow {
|
||||
id: hoverPopUp
|
||||
id: hoverPopUp
|
||||
|
||||
anchor.item: HoverMediator.component
|
||||
property bool initialized: false
|
||||
anchor.rect.y: HoverMediator.y
|
||||
anchor.rect.x: (HoverMediator.x - this.implicitWidth)/2
|
||||
implicitHeight: wsPopUp.implicitHeight
|
||||
implicitWidth: wsPopUp.implicitWidth
|
||||
anchor.item: HoverMediator.component
|
||||
property bool initialized: false
|
||||
anchor.rect.y: HoverMediator.y
|
||||
anchor.rect.x: (HoverMediator.x - this.implicitWidth) / 2
|
||||
implicitHeight: wsPopUp.implicitHeight
|
||||
implicitWidth: wsPopUp.implicitWidth
|
||||
|
||||
color: "transparent"
|
||||
|
||||
color:"transparent"
|
||||
|
||||
Component {
|
||||
id: stub
|
||||
Text {
|
||||
@@ -45,15 +44,19 @@ Singleton {
|
||||
color: Theme.textColor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Component {
|
||||
id: systray
|
||||
Text {
|
||||
text: {
|
||||
if (!HoverMediator.component.model) return ""
|
||||
if (HoverMediator.component.model.tooltipTitle) return HoverMediator.component.model.tooltipTitle
|
||||
if (HoverMediator.component.model.title) return HoverMediator.component.model.title
|
||||
else return ""
|
||||
if (!HoverMediator.component.model)
|
||||
return "";
|
||||
if (HoverMediator.component.model.tooltipTitle)
|
||||
return HoverMediator.component.model.tooltipTitle;
|
||||
if (HoverMediator.component.model.title)
|
||||
return HoverMediator.component.model.title;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
font.bold: true
|
||||
font.pixelSize: Theme.pixelSize
|
||||
@@ -65,7 +68,7 @@ Singleton {
|
||||
Component {
|
||||
id: time
|
||||
Text {
|
||||
property string calendar:(HoverMediator.component.calendar)? HoverMediator.component.calendar: ""
|
||||
property string calendar: (HoverMediator.component.calendar) ? HoverMediator.component.calendar : ""
|
||||
|
||||
text: calendar
|
||||
font.bold: true
|
||||
@@ -78,7 +81,7 @@ Singleton {
|
||||
Component {
|
||||
id: audio
|
||||
Text {
|
||||
property string sinkDescription:(HoverMediator.component.sink)? HoverMediator.component.sink.description : ""
|
||||
property string sinkDescription: (HoverMediator.component.sink) ? HoverMediator.component.sink.description : ""
|
||||
text: sinkDescription
|
||||
font.bold: true
|
||||
font.pixelSize: Theme.pixelSize
|
||||
@@ -97,14 +100,15 @@ Singleton {
|
||||
|
||||
Repeater {
|
||||
|
||||
property var modelo: HyprlandService.sortedDesktopApplications.get(parent.workspaceIndexAlign)
|
||||
property var modelo: HyprlandService.sortedDesktopApplications.get(parent.workspaceIndexAlign)
|
||||
|
||||
model: modelo
|
||||
delegate: IconImage {
|
||||
|
||||
required property var modelData
|
||||
|
||||
width:30; height:30
|
||||
width: 30
|
||||
height: 30
|
||||
source: (modelData && modelData.icon) ? Quickshell.iconPath(modelData.icon, 1) : ""
|
||||
}
|
||||
}
|
||||
@@ -122,21 +126,28 @@ Singleton {
|
||||
radius: 25
|
||||
opacity: 1
|
||||
Behavior on opacity {
|
||||
NumberAnimation { property: "opacity"; duration: Theme.animationDuration}
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
duration: Theme.animationDuration
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: hoverLoader
|
||||
sourceComponent: {
|
||||
if(!HoverMediator.type) return stub
|
||||
if(HoverMediator.type === "workspace") return workspaceComponent
|
||||
if(HoverMediator.type === "audio") return audio
|
||||
if(HoverMediator.type === "time") return time
|
||||
if(HoverMediator.type === "systray") return systray
|
||||
if (!HoverMediator.type)
|
||||
return stub;
|
||||
if (HoverMediator.type === "workspace")
|
||||
return workspaceComponent;
|
||||
if (HoverMediator.type === "audio")
|
||||
return audio;
|
||||
if (HoverMediator.type === "time")
|
||||
return time;
|
||||
if (HoverMediator.type === "systray")
|
||||
return systray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Timer {
|
||||
@@ -145,7 +156,7 @@ Singleton {
|
||||
interval: 300
|
||||
onTriggered: {
|
||||
// wsPopUp.opacity = 1
|
||||
hoverPopUp.visible = true
|
||||
hoverPopUp.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,5 +14,4 @@ Singleton {
|
||||
|
||||
precision: SystemClock.Seconds
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
@@ -52,12 +51,13 @@ WrapperRectangle {
|
||||
|
||||
implicitHeight: 30
|
||||
implicitWidth: 30
|
||||
color:"transparent"
|
||||
color: "transparent"
|
||||
|
||||
IconImage {
|
||||
anchors.verticalCenter:parent.verticalCenter
|
||||
anchors.horizontalCenter:parent.horizontalCenter
|
||||
width:25; height:25
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 25
|
||||
height: 25
|
||||
source: systrayItem.iconSource
|
||||
}
|
||||
|
||||
@@ -66,30 +66,23 @@ WrapperRectangle {
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
hoverEnabled: true
|
||||
onEntered: {
|
||||
PopUpHover.start(systrayItem,"systray")
|
||||
PopUpHover.start(systrayItem, "systray");
|
||||
}
|
||||
onExited: {
|
||||
PopUpHover.exit()
|
||||
PopUpHover.exit();
|
||||
}
|
||||
onClicked: (mouse) => {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
menuAnchor.menu = systrayItem.model.menu;
|
||||
menuAnchor.anchor.item = systrayItem;
|
||||
menuAnchor.anchor.rect = Qt.rect(
|
||||
0,
|
||||
systrayItem.implicitHeight,
|
||||
0,
|
||||
0
|
||||
);
|
||||
menuAnchor.anchor.rect = Qt.rect(0, systrayItem.implicitHeight, 0, 0);
|
||||
menuAnchor.open();
|
||||
|
||||
} else if (mouse.button === Qt.LeftButton) {
|
||||
// systrayItem.model.activate()
|
||||
}
|
||||
} else if (mouse.button === Qt.LeftButton)
|
||||
// systrayItem.model.activate()
|
||||
{}
|
||||
}
|
||||
onDoubleClicked: {
|
||||
systrayItem.model.activate()
|
||||
systrayItem.model.activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,6 +91,5 @@ WrapperRectangle {
|
||||
|
||||
QsMenuAnchor {
|
||||
id: menuAnchor
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Services.Notifications
|
||||
import Quickshell.Widgets
|
||||
|
||||
PanelWindow {
|
||||
id: notificationRoot
|
||||
|
||||
// Since the panel's screen is unset, it will be picked by the compositor
|
||||
// when the window is created. Most compositors pick the current active monitor.
|
||||
|
||||
property bool hasImage: notification?.image ? true : false
|
||||
|
||||
property string image: {
|
||||
if (hasImage) {
|
||||
return notification.image;
|
||||
}
|
||||
if (notification?.appIcon === "") {
|
||||
return "";
|
||||
}
|
||||
return Quickshell.iconPath(notification?.appIcon);
|
||||
}
|
||||
property var notification: null
|
||||
|
||||
signal dismissed()
|
||||
|
||||
anchors.top: true
|
||||
margins.top: screen.height / 100
|
||||
exclusiveZone: 0
|
||||
|
||||
implicitWidth: 400
|
||||
implicitHeight: 100
|
||||
color: "transparent"
|
||||
|
||||
// An empty click mask prevents the window from blocking mouse events.
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
topLeftRadius: 100
|
||||
bottomLeftRadius: 100
|
||||
topRightRadius: 20
|
||||
bottomRightRadius: 20
|
||||
color: "#80000000"
|
||||
|
||||
MouseArea{
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
notificationRoot.dismissed()
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors {
|
||||
fill: parent
|
||||
}
|
||||
|
||||
ClippingRectangle {
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
|
||||
implicitWidth: 100
|
||||
implicitHeight: 100
|
||||
visible: image? true : false
|
||||
|
||||
color: "grey"
|
||||
|
||||
radius: 100
|
||||
|
||||
IconImage {
|
||||
anchors.centerIn: parent
|
||||
implicitSize: 100
|
||||
source: notificationRoot.image
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
Layout.leftMargin: 10
|
||||
Layout.rightMargin: 10
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
|
||||
implicitHeight: 30
|
||||
radius: 20
|
||||
color: "#50ffffff"
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
|
||||
implicitWidth: parent.width
|
||||
radius: parent.radius
|
||||
color: "white"
|
||||
|
||||
Text {
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
wrapMode: Text.WordWrap
|
||||
fontSizeMode: Text.Fit
|
||||
|
||||
text: notificationRoot.notification.summary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
|
||||
implicitHeight: 55
|
||||
radius: 20
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
|
||||
implicitWidth: parent.width
|
||||
radius: parent.radius
|
||||
color: "white"
|
||||
|
||||
Text {
|
||||
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font.pixelSize: 24
|
||||
wrapMode: Text.WordWrap
|
||||
fontSizeMode: Text.Fit
|
||||
minimumPixelSize: 10
|
||||
elide: Text.ElideRight
|
||||
|
||||
text: notificationRoot.notification.body
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +1,41 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Services.Notifications
|
||||
import Quickshell.Widgets
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import QtQuick.Window
|
||||
|
||||
PopupWindow {
|
||||
|
||||
anchor.item:root
|
||||
anchor.rect.y: parentWindow.height
|
||||
implicitWidth: 400
|
||||
implicitHeight: 1000
|
||||
color: "white"
|
||||
visible:true
|
||||
|
||||
id: notificationRoot
|
||||
|
||||
// Since the panel's screen is unset, it will be picked by the compositor
|
||||
// when the window is created. Most compositors pick the current active monitor.
|
||||
|
||||
|
||||
// An empty click mask prevents the window from blocking mouse events.
|
||||
Component {
|
||||
id: contactDelegate
|
||||
NotificationPopup {
|
||||
id: myItem
|
||||
required property string notification
|
||||
}
|
||||
}
|
||||
anchor.item: root
|
||||
anchor.rect.y: parentWindow?.height
|
||||
implicitWidth: 400
|
||||
implicitHeight: Math.min(listView.contentHeight, 900)
|
||||
color: "white"
|
||||
visible: true
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
anchors.fill: parent
|
||||
model: NotificationService.trackedNotifications.values
|
||||
delegate: contactDelegate
|
||||
highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
|
||||
focus: true
|
||||
orientation: ListView.Vertical
|
||||
verticalLayoutDirection: ListView.BottomToTop
|
||||
clip: true
|
||||
spacing: 5
|
||||
|
||||
delegate: NotificationWrapper {
|
||||
required property var modelData
|
||||
notification: modelData
|
||||
width: ListView.width
|
||||
onDismissed: {
|
||||
if (notification && typeof notification.dismiss === "function") {
|
||||
notification.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
Component.onCompleted: positionViewAtEnd()
|
||||
onModelChanged: positionViewAtEnd()
|
||||
}
|
||||
}
|
||||
|
||||
138
Widgets/NotificationWrapper.qml
Normal file
138
Widgets/NotificationWrapper.qml
Normal file
@@ -0,0 +1,138 @@
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: notificationWrapper
|
||||
|
||||
signal dismissed
|
||||
|
||||
property bool hasImage: notification?.image ? true : false
|
||||
property var notification: null
|
||||
|
||||
property string image: {
|
||||
if (hasImage) {
|
||||
return notification.image;
|
||||
}
|
||||
if (notification?.appIcon === "") {
|
||||
return "";
|
||||
}
|
||||
return Quickshell.iconPath(notification?.appIcon);
|
||||
}
|
||||
|
||||
implicitWidth: 400
|
||||
implicitHeight: notifLayout.implicitHeight
|
||||
topLeftRadius: image ? 100 : 20
|
||||
bottomLeftRadius: image ? 100 : 20
|
||||
topRightRadius: 20
|
||||
bottomRightRadius: 20
|
||||
color: "#80000000"
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
notificationWrapper.dismissed();
|
||||
console.log("opa");
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: notifLayout
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
}
|
||||
|
||||
ClippingRectangle {
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
|
||||
implicitWidth: 100
|
||||
implicitHeight: 100
|
||||
visible: notificationWrapper.image ? true : false
|
||||
|
||||
color: "grey"
|
||||
|
||||
radius: 100
|
||||
|
||||
IconImage {
|
||||
anchors.centerIn: parent
|
||||
implicitSize: 100
|
||||
source: notificationWrapper.image
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
Layout.leftMargin: 10
|
||||
Layout.rightMargin: 10
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
|
||||
implicitHeight: summaryText.implicitHeight + 10
|
||||
radius: 20
|
||||
color: "#50ffffff"
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
|
||||
implicitWidth: parent.width
|
||||
radius: parent.radius
|
||||
color: "white"
|
||||
|
||||
Text {
|
||||
id: summaryText
|
||||
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font.pixelSize: 12
|
||||
wrapMode: Text.WordWrap
|
||||
textFormat: Text.MarkdownText
|
||||
|
||||
text: notificationWrapper.notification.summary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
|
||||
implicitHeight: bodyText.implicitHeight + 10
|
||||
radius: 20
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
|
||||
implicitWidth: parent.width
|
||||
radius: parent.radius
|
||||
color: "white"
|
||||
|
||||
Text {
|
||||
id: bodyText
|
||||
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font.pixelSize: 14
|
||||
wrapMode: Text.WordWrap
|
||||
textFormat: Text.MarkdownText
|
||||
|
||||
text: notificationWrapper.notification.body
|
||||
onLinkActivated: link => Qt.openUrlExternally(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,18 +11,18 @@ import qs.Services
|
||||
|
||||
WrapperMouseArea {
|
||||
id: workspacesWidget
|
||||
|
||||
|
||||
property var monitor: "black"
|
||||
|
||||
onWheel: (wheel) => {
|
||||
onWheel: wheel => {
|
||||
if (wheel.angleDelta.y > 0) {
|
||||
if ((Hyprland.focusedWorkspace.id) % 5 === 0)
|
||||
return ;
|
||||
return;
|
||||
|
||||
Hyprland.dispatch("workspace " + (Hyprland.focusedWorkspace.id + 1));
|
||||
} else if (wheel.angleDelta.y < 0) {
|
||||
if (Hyprland.focusedWorkspace.id === 1 || Hyprland.focusedWorkspace.id === 6)
|
||||
return ;
|
||||
return;
|
||||
|
||||
Hyprland.dispatch("workspace " + (Hyprland.focusedWorkspace.id - 1));
|
||||
}
|
||||
@@ -35,7 +35,7 @@ WrapperMouseArea {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
|
||||
Repeater {
|
||||
id:workspacesRepeater
|
||||
id: workspacesRepeater
|
||||
|
||||
property var monitor: parent.monitor
|
||||
|
||||
@@ -49,11 +49,11 @@ WrapperMouseArea {
|
||||
required property var modelData
|
||||
property var index: modelData // Get the workspace data from the model
|
||||
property int workspaceIndex: parent.monitor === "DP-2" ? modelData + 5 : modelData
|
||||
property int workspaceIndexAlign: workspaceIndex+1
|
||||
property int workspaceIndexAlign: workspaceIndex + 1
|
||||
property var workspace: Hyprland.workspaces.values.length > workspaceIndex ? Hyprland.workspaces.values[workspaceIndex] : null
|
||||
property bool workspaceActive: workspace === Hyprland.focusedWorkspace? true:false
|
||||
property bool workspaceActive: workspace === Hyprland.focusedWorkspace ? true : false
|
||||
property var topLevels: HyprlandService.topLevelWorkspaces
|
||||
property var hasTopLevel: topLevels.filter(topLevelworkspace => topLevelworkspace.id === workspaceIndexAlign).length ? true:false
|
||||
property var hasTopLevel: topLevels.filter(topLevelworkspace => topLevelworkspace.id === workspaceIndexAlign).length ? true : false
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
implicitHeight: Theme.heightGaps
|
||||
@@ -63,17 +63,32 @@ WrapperMouseArea {
|
||||
State {
|
||||
name: "Active"
|
||||
when: workspacesRectangle.workspaceActive
|
||||
PropertyChanges { workspacesRectangle{ color: Theme.color6; implicitWidth: Theme.barSize*1.5}}
|
||||
PropertyChanges {
|
||||
workspacesRectangle {
|
||||
color: Theme.color6
|
||||
implicitWidth: Theme.barSize * 1.5
|
||||
}
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "Filled"
|
||||
when: !workspacesRectangle.workspaceActive && workspacesRectangle.hasTopLevel
|
||||
PropertyChanges { workspacesRectangle{ color: Theme.backgroudColorBright; implicitWidth: Theme.barSize}}
|
||||
PropertyChanges {
|
||||
workspacesRectangle {
|
||||
color: Theme.backgroudColorBright
|
||||
implicitWidth: Theme.barSize
|
||||
}
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "Empty"
|
||||
when: !workspacesRectangle.workspaceActive && !workspacesRectangle.hasTopLevel
|
||||
PropertyChanges { workspacesRectangle{ color: Theme.backgroudColor;implicitWidth: Theme.barSize}}
|
||||
PropertyChanges {
|
||||
workspacesRectangle {
|
||||
color: Theme.backgroudColor
|
||||
implicitWidth: Theme.barSize
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -91,7 +106,7 @@ WrapperMouseArea {
|
||||
|
||||
Text {
|
||||
|
||||
property int workspaceName: workspacesRectangle.workspaceIndexAlign > 5? workspacesRectangle.workspaceIndexAlign -5: workspacesRectangle.workspaceIndexAlign
|
||||
property int workspaceName: workspacesRectangle.workspaceIndexAlign > 5 ? workspacesRectangle.workspaceIndexAlign - 5 : workspacesRectangle.workspaceIndexAlign
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: workspaceName
|
||||
@@ -106,23 +121,21 @@ WrapperMouseArea {
|
||||
hoverEnabled: true
|
||||
onEntered: {
|
||||
if (parent.hasTopLevel && !parent.workspaceActive) {
|
||||
PopUpHover.start(workspacesRectangle, "workspace")
|
||||
PopUpHover.start(workspacesRectangle, "workspace");
|
||||
}
|
||||
}
|
||||
onExited: {
|
||||
PopUpHover.exit()
|
||||
PopUpHover.exit();
|
||||
}
|
||||
onClicked: {
|
||||
if(workspacesRectangle.workspace.id === Hyprland.focusedWorkspace.id) {return} ;
|
||||
if (workspacesRectangle.workspace.id === Hyprland.focusedWorkspace.id) {
|
||||
return;
|
||||
}
|
||||
;
|
||||
Hyprland.dispatch("workspace " + workspacesRectangle.workspace.id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user