Notifications n shi
@@ -52,7 +52,7 @@ Item {
|
|||||||
onCursorPositionChanged: cursorPosition = text.length
|
onCursorPositionChanged: cursorPosition = text.length
|
||||||
Keys.onPressed: (event) => { switch (event.key) {
|
Keys.onPressed: (event) => { switch (event.key) {
|
||||||
case Qt.Key_Escape:
|
case Qt.Key_Escape:
|
||||||
root.close();
|
background.index = 0;
|
||||||
break;
|
break;
|
||||||
case Qt.Key_Return:
|
case Qt.Key_Return:
|
||||||
list.currentItem.execute();
|
list.currentItem.execute();
|
||||||
|
|||||||
153
Panes/NotificationCenter.qml
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import Quickshell.Services.Mpris
|
||||||
|
import Quickshell.Services.Notifications
|
||||||
|
import "../Widgets" as Widgets
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
width: childrenRect.width + 12
|
||||||
|
height: childrenRect.height + 12
|
||||||
|
Row {
|
||||||
|
spacing: 6
|
||||||
|
x: 6
|
||||||
|
y: 6
|
||||||
|
Rectangle {
|
||||||
|
width: 400
|
||||||
|
height: 300
|
||||||
|
color: "#181818"
|
||||||
|
radius: 10
|
||||||
|
Column {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 2
|
||||||
|
opacity: !notifServer.trackedNotifications.values.length
|
||||||
|
Behavior on opacity {NumberAnimation {duration: 150}}
|
||||||
|
Image {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
source: Quickshell.shellPath("assets/notif.svg")
|
||||||
|
width: 24
|
||||||
|
height: 24
|
||||||
|
sourceSize {width: width; height: height}
|
||||||
|
opacity: 0.5
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
color: "#888"
|
||||||
|
text: "No notifications"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ListView {
|
||||||
|
anchors.fill: parent
|
||||||
|
clip: true
|
||||||
|
spacing: 4
|
||||||
|
header: Item {height: 4; width: 1}
|
||||||
|
model: Array.from(notifServer.trackedNotifications.values)
|
||||||
|
delegate: Widgets.Notification {
|
||||||
|
color: "#222"
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
margins: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
id: player
|
||||||
|
property var modelData: Mpris.players.values[0]
|
||||||
|
height: 300
|
||||||
|
width: 250
|
||||||
|
Column {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 2
|
||||||
|
Image {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
source: Quickshell.shellPath("assets/player-symbolic.svg")
|
||||||
|
width: 24
|
||||||
|
height: 24
|
||||||
|
sourceSize {width: width; height: height}
|
||||||
|
opacity: 0.5
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
color: "#888"
|
||||||
|
text: "Nothing playing"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Column {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
opacity: Mpris.players.values.length
|
||||||
|
ClippingRectangle {
|
||||||
|
color: "transparent"
|
||||||
|
width: 180
|
||||||
|
height: 180
|
||||||
|
radius: height/2
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
Image {
|
||||||
|
anchors.fill: parent
|
||||||
|
source: player.modelData?.trackArtUrl ?? source
|
||||||
|
}
|
||||||
|
NumberAnimation on rotation {
|
||||||
|
id: spin
|
||||||
|
paused: !player.modelData?.isPlaying || !root.up || background.index !== 3
|
||||||
|
duration: 30000
|
||||||
|
loops: Animation.Infinite
|
||||||
|
from: 0
|
||||||
|
to: 360
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item {width: 1; height: 10}
|
||||||
|
Text {
|
||||||
|
color: "white"
|
||||||
|
text: player.modelData?.trackTitle ?? ""
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
font.pixelSize: 16
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
color: "white"
|
||||||
|
text: player.modelData?.trackArtist ?? ""
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
font.pixelSize: 12
|
||||||
|
}
|
||||||
|
Item {width: 1; height: 8}
|
||||||
|
Row {
|
||||||
|
height: childrenRect.height
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
component Button: Rectangle {
|
||||||
|
id: button
|
||||||
|
property var action
|
||||||
|
property var clicked
|
||||||
|
radius: 12
|
||||||
|
color: hover.hovered ? "#11ffffff" : "#00ffffff"
|
||||||
|
property var hover: HoverHandler {}
|
||||||
|
width: 40
|
||||||
|
height: width
|
||||||
|
Image {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 8
|
||||||
|
sourceSize {width: width; height: height}
|
||||||
|
source: Quickshell.shellPath(`assets/lazer-${action}-symbolic.svg`)
|
||||||
|
}
|
||||||
|
TapHandler {onTapped: button.clicked()}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
action: "previous"
|
||||||
|
clicked: player.modelData?.previous
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
action: player.modelData?.isPlaying ? "pause" : "play"
|
||||||
|
clicked: player.modelData?.togglePlaying
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
action: "next"
|
||||||
|
clicked: player.modelData?.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Panes/Notifications.qml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell.Services.Notifications
|
||||||
|
import "../Widgets" as Widgets
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
width: 350
|
||||||
|
height: childrenRect.height
|
||||||
|
Connections {
|
||||||
|
target: notifServer
|
||||||
|
function onNotification(notif) {
|
||||||
|
if (root.up) return
|
||||||
|
background.index = 4
|
||||||
|
notifPopup.modelData = notif
|
||||||
|
root.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Widgets.Notification {
|
||||||
|
id: notifPopup
|
||||||
|
anchors.margins: 6
|
||||||
|
modelData: notifServer.trackedNotifications.values[0] ?? undefined
|
||||||
|
color: "transparent"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import QtQuick
|
|||||||
import "../Widgets" as Widgets
|
import "../Widgets" as Widgets
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: 800
|
width: 900
|
||||||
height: 42
|
height: 42
|
||||||
anchors {
|
anchors {
|
||||||
top: parent.top
|
top: parent.top
|
||||||
@@ -14,7 +14,6 @@ Item {
|
|||||||
top: parent.top
|
top: parent.top
|
||||||
left: parent.left
|
left: parent.left
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
leftMargin: 0
|
|
||||||
}
|
}
|
||||||
Widgets.Battery {}
|
Widgets.Battery {}
|
||||||
}
|
}
|
||||||
@@ -31,13 +30,7 @@ Item {
|
|||||||
top: parent.top
|
top: parent.top
|
||||||
right: parent.right
|
right: parent.right
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
rightMargin: 12
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
property var clock: SystemClock {}
|
|
||||||
color: "white"
|
|
||||||
text: Qt.formatDateTime(clock.date, "ddd MMM dd · hh:mm")
|
|
||||||
}
|
}
|
||||||
|
Widgets.Time {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
TopBar.qml
@@ -17,8 +17,8 @@ PanelWindow {
|
|||||||
property var font: {family: "0xProto Nerd Font"}
|
property var font: {family: "0xProto Nerd Font"}
|
||||||
|
|
||||||
implicitWidth: 1024
|
implicitWidth: 1024
|
||||||
implicitHeight: 200
|
implicitHeight: 400
|
||||||
WlrLayershell.keyboardFocus: (up && !shortcut.pressed) ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
WlrLayershell.keyboardFocus: (up && !background.exit.running && !shortcut.pressed && background.index <= 1) ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||||
WlrLayershell.layer: WlrLayer.Overlay
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
exclusionMode: ExclusionMode.Ignore
|
exclusionMode: ExclusionMode.Ignore
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
@@ -39,6 +39,7 @@ PanelWindow {
|
|||||||
name: "topbar"
|
name: "topbar"
|
||||||
description: "Hold to peek, tap to toggle topbar"
|
description: "Hold to peek, tap to toggle topbar"
|
||||||
onPressed: {
|
onPressed: {
|
||||||
|
background.index = 0
|
||||||
root.open()
|
root.open()
|
||||||
}
|
}
|
||||||
onReleased: {
|
onReleased: {
|
||||||
@@ -147,13 +148,14 @@ PanelWindow {
|
|||||||
onStarted: entry.stop()
|
onStarted: entry.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Pane { opacity: 1; Panes.Status { }}
|
Pane { opacity: 1; Panes.Status {} }
|
||||||
Pane { Panes.Launcher {
|
Pane { Panes.Launcher {
|
||||||
id: launcher
|
id: launcher
|
||||||
onShowChanged: if (show) background.index = 1; else background.index = 0
|
onShowChanged: if (show) background.index = 1; else background.index = 0
|
||||||
}}
|
}}
|
||||||
Pane { Panes.Battery {
|
Pane { Panes.Battery {} }
|
||||||
}}
|
Pane { Panes.NotificationCenter {} }
|
||||||
|
Pane { Panes.Notifications {} }
|
||||||
|
|
||||||
property var entry: SequentialAnimation {
|
property var entry: SequentialAnimation {
|
||||||
PauseAnimation {duration: 2}
|
PauseAnimation {duration: 2}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
x: 10
|
x: 10
|
||||||
color: "white"
|
color: "white"
|
||||||
text: `${Math.round(UPower.displayDevice.percentage * 100)}% · ${Math.round(UPower.displayDevice.changeRate)}W`
|
text: `${Math.round(UPower.displayDevice.percentage * 100)}% · ${UPower.displayDevice.changeRate.toPrecision(2)}W`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HoverHandler {id: hover}
|
HoverHandler {id: hover}
|
||||||
|
|||||||
83
Widgets/Notification.qml
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import Quickshell.Services.Notifications
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Effects
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: notifRect
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
property bool exiting: false
|
||||||
|
width: parent?.width ?? 0
|
||||||
|
height: notifContent.childrenRect.height + 20
|
||||||
|
radius: 8
|
||||||
|
color: "#181818"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
antialiasing: true
|
||||||
|
color: "transparent"
|
||||||
|
anchors {
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
left: parent.left
|
||||||
|
leftMargin: 12
|
||||||
|
}
|
||||||
|
radius: 8
|
||||||
|
width: 40
|
||||||
|
height: 40
|
||||||
|
Image {
|
||||||
|
id: notifIcon
|
||||||
|
anchors.fill: parent
|
||||||
|
source: modelData?.image ?? source
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Column {
|
||||||
|
id: notifContent
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
top: parent.top
|
||||||
|
topMargin: 10
|
||||||
|
leftMargin: 16 + (notifIcon.source == "" ? 0 : 44)
|
||||||
|
rightMargin: 16
|
||||||
|
}
|
||||||
|
spacing: 4
|
||||||
|
Text {
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
color: "white"
|
||||||
|
font.family: "Comfortaa"
|
||||||
|
font.pixelSize: 16
|
||||||
|
text: modelData?.summary ?? text
|
||||||
|
elide: Text.ElideRight
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
maximumLineCount: 2
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
color: "white"
|
||||||
|
font.family: "Comfortaa"
|
||||||
|
font.pixelSize: 12
|
||||||
|
text: modelData?.body ?? text
|
||||||
|
elide: Text.ElideRight
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
maximumLineCount: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Timer {
|
||||||
|
running: modelData?.expireTimeout > 0
|
||||||
|
interval: (modelData?.expireTimeout > 0) ? modelData?.expireTimeout : 0
|
||||||
|
onTriggered: modelData.tracked = false
|
||||||
|
}
|
||||||
|
TapHandler {
|
||||||
|
acceptedButtons: Qt.MiddleButton
|
||||||
|
onTapped: modelData.tracked = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
48
Widgets/Time.qml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import Quickshell.Services.Mpris
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
property var player: Mpris.players.values[0]
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
width: children[1].width + 24
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 4
|
||||||
|
radius: 8
|
||||||
|
bottomRightRadius: 12
|
||||||
|
color: hover.hovered ? "#11ffffff" : "#00ffffff"
|
||||||
|
Behavior on color {ColorAnimation {duration: 100}}
|
||||||
|
}
|
||||||
|
Row {
|
||||||
|
spacing: 12
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
x: 12
|
||||||
|
ClippingRectangle {
|
||||||
|
visible: !!root.player
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: 24
|
||||||
|
height: width
|
||||||
|
radius: 6
|
||||||
|
Image {
|
||||||
|
anchors.fill: parent
|
||||||
|
source: root.player?.trackArtUrl ?? source
|
||||||
|
}
|
||||||
|
opacity: root.player?.isPlaying ? 1 : 0.5
|
||||||
|
Behavior on opacity {NumberAnimation {duration: 150}}
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
property var clock: SystemClock {}
|
||||||
|
color: "white"
|
||||||
|
text: Qt.formatDateTime(clock.date, "ddd MMM dd · hh:mm")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HoverHandler {id: hover}
|
||||||
|
TapHandler {onTapped: background.index = 3}
|
||||||
|
}
|
||||||
@@ -18,7 +18,9 @@ Item {
|
|||||||
width: 24
|
width: 24
|
||||||
property var workspace: Hyprland.workspaces.values.find(ws => ws.id === modelData+1)
|
property var workspace: Hyprland.workspaces.values.find(ws => ws.id === modelData+1)
|
||||||
property var icon: {
|
property var icon: {
|
||||||
const appId = workspace?.toplevels.values[0]?.wayland?.appId
|
const appId = workspace ? Array.from(workspace.toplevels.values).sort(
|
||||||
|
(a, b) => b.lastIpcObject.focusHistoryId - a.lastIpcObject.focusHistoryId
|
||||||
|
)[0]?.wayland?.appId : undefined
|
||||||
return DesktopEntries.applications.values.find(
|
return DesktopEntries.applications.values.find(
|
||||||
app => app.startupClass === appId || app.id === appId
|
app => app.startupClass === appId || app.id === appId
|
||||||
)?.icon;
|
)?.icon;
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 159 KiB |
|
Before Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 540 KiB |
|
Before Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 504 KiB |
|
Before Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 279 KiB |
|
Before Width: | Height: | Size: 64 KiB |
@@ -1,8 +1,13 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
import Quickshell.Services.Notifications
|
||||||
import "." as Shell
|
import "." as Shell
|
||||||
|
|
||||||
ShellRoot {
|
ShellRoot {
|
||||||
|
NotificationServer {
|
||||||
|
id: notifServer
|
||||||
|
onNotification: (notif) => notif.tracked = true
|
||||||
|
}
|
||||||
Shell.Wall {}
|
Shell.Wall {}
|
||||||
Shell.TopBar {}
|
Shell.TopBar {}
|
||||||
Shell.Boateye {}
|
Shell.Boateye {}
|
||||||
|
|||||||