Notifications n shi
@@ -52,7 +52,7 @@ Item {
|
||||
onCursorPositionChanged: cursorPosition = text.length
|
||||
Keys.onPressed: (event) => { switch (event.key) {
|
||||
case Qt.Key_Escape:
|
||||
root.close();
|
||||
background.index = 0;
|
||||
break;
|
||||
case Qt.Key_Return:
|
||||
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
|
||||
|
||||
Item {
|
||||
width: 800
|
||||
width: 900
|
||||
height: 42
|
||||
anchors {
|
||||
top: parent.top
|
||||
@@ -14,7 +14,6 @@ Item {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
bottom: parent.bottom
|
||||
leftMargin: 0
|
||||
}
|
||||
Widgets.Battery {}
|
||||
}
|
||||
@@ -31,13 +30,7 @@ Item {
|
||||
top: parent.top
|
||||
right: parent.right
|
||||
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 {}
|
||||
}
|
||||
}
|
||||
|
||||
10
TopBar.qml
@@ -17,8 +17,8 @@ PanelWindow {
|
||||
property var font: {family: "0xProto Nerd Font"}
|
||||
|
||||
implicitWidth: 1024
|
||||
implicitHeight: 200
|
||||
WlrLayershell.keyboardFocus: (up && !shortcut.pressed) ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||
implicitHeight: 400
|
||||
WlrLayershell.keyboardFocus: (up && !background.exit.running && !shortcut.pressed && background.index <= 1) ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
color: "transparent"
|
||||
@@ -39,6 +39,7 @@ PanelWindow {
|
||||
name: "topbar"
|
||||
description: "Hold to peek, tap to toggle topbar"
|
||||
onPressed: {
|
||||
background.index = 0
|
||||
root.open()
|
||||
}
|
||||
onReleased: {
|
||||
@@ -152,8 +153,9 @@ PanelWindow {
|
||||
id: launcher
|
||||
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 {
|
||||
PauseAnimation {duration: 2}
|
||||
|
||||
@@ -50,7 +50,7 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
x: 10
|
||||
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}
|
||||
|
||||
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
|
||||
property var workspace: Hyprland.workspaces.values.find(ws => ws.id === modelData+1)
|
||||
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(
|
||||
app => app.startupClass === appId || app.id === appId
|
||||
)?.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 |