Introduced Notification server, and added background thorugh quickshell

This commit is contained in:
2025-09-13 23:51:14 -04:00
parent 55a97da636
commit 7081a48426
13 changed files with 263 additions and 10 deletions

View File

@@ -7,4 +7,5 @@ Singleton {
id: root
property bool mediaControlsOpen: false
property bool osdVolumeOpen: false
property bool notificationPanelOpen: false
}

36
background/Background.qml Normal file
View File

@@ -0,0 +1,36 @@
pragma ComponentBehavior: Bound
import qs.common
import Quickshell
import Quickshell.Wayland
import QtQuick
Loader {
asynchronous: true
active: Config.background.enabled
sourceComponent: Variants {
model: Quickshell.screens
PanelWindow {
id: background
required property ShellScreen modelData
screen: modelData
WlrLayershell.namespace: "hydro-os-background"
WlrLayershell.exclusionMode: ExclusionMode.Ignore
WlrLayershell.layer: WlrLayer.Background
color: "black"
anchors {
top: true
bottom: true
left: true
right: true
}
Wallpaper {}
}
}
}

19
background/Wallpaper.qml Normal file
View File

@@ -0,0 +1,19 @@
pragma ComponentBehavior: Bound
import qs.common
import QtQuick
Item {
id: root
property string source: Config.options.background.wallpaperPath
property Image current: one
anchors.fill: parent
Image {
id: one
source: root.source
anchors.fill: parent
}
}

View File

@@ -29,7 +29,7 @@ Scope {
right: true
}
implicitHeight: 45
implicitHeight: Config.options.bar.height
RowLayout { // Left Section
id: leftSection

View File

@@ -33,7 +33,7 @@ Item {
} else if (event.button === Qt.ForwardButton) {
MprisController.shiftPlayer(1);
} else if (event.button === Qt.LeftButton) {
GlobalStates.mediaControlsOpen = !GlobalStates.mediaControlsOpen
GlobalStates.mediaControlsOpen = !GlobalStates.mediaControlsOpen;
}
}
}

View File

@@ -1,3 +1,4 @@
import qs
import qs.common
import qs.common.widgets
import QtQuick
@@ -9,6 +10,14 @@ Item {
height: parent.height
implicitWidth: rowLayout.implicitWidth
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onPressed: (event) => {
GlobalStates.notificationPanelOpen = !GlobalStates.notificationPanelOpen;
}
}
RowLayout {
id: rowLayout
@@ -19,9 +28,9 @@ Item {
Layout.alignment: Qt.AlignVCenter
font.pixelSize: Appearance.font.pixelSize.larger
color: Appearance.m3colors.m3error
text: "" + NotificationServer.amountNotifications
text: "" + NotificationService.amountNotifications
visible: {
NotificationServer.amountNotifications > 0
NotificationService.amountNotifications > 0
}
}
@@ -29,9 +38,9 @@ Item {
Layout.alignment: Qt.AlignVCenter
visible: true
fill: 1
text: NotificationServer.amountNotifications > 0 ? "notifications_unread" : "notifications"
text: NotificationService.amountNotifications > 0 ? "notifications_unread" : "notifications"
iconSize: Appearance.font.pixelSize.larger
color: NotificationServer.amountNotifications > 0 ? Appearance.m3colors.m3error : Appearance.m3colors.m3onSecondaryContainer
color: NotificationService.amountNotifications > 0 ? Appearance.m3colors.m3error : Appearance.m3colors.m3onSecondaryContainer
}
}
}

View File

@@ -40,11 +40,13 @@ Singleton {
}
property JsonObject background: JsonObject {
property string wallpaperPath: ""
property bool enabled: true
property string wallpaperPath: "/usr/share/hydro-os/DefaultBackground.png"
property string thumbnailPath: ""
}
property JsonObject bar: JsonObject {
property int height: 45
property bool bottom: false // Instead of top
property int cornerStyle: 0 // 0: Hug | 1: Float | 2: Plain rectangle
property bool borderless: false // true for no grouping of items

View File

@@ -7,7 +7,7 @@ import Quickshell.Services.Mpris
Singleton {
readonly property list<MprisPlayer> activePlayers: Mpris.players.values
readonly property var meaningfulPlayers: filterDuplicatePlayers(activePlayers)
readonly property bool hasPlayers: meaningfulPlayers.length > 0
readonly property bool hasPlayers: activePlayers.length > 0
property int playerIndex: 0
function activePlayer() {
@@ -15,7 +15,7 @@ Singleton {
return null;
}
assertIndex();
return meaningfulPlayers[playerIndex];
return activePlayers[playerIndex];
}
function shiftPlayer(shift) {
@@ -23,7 +23,7 @@ Singleton {
}
function assertIndex() {
if (playerIndex < 0 || playerIndex >= meaningfulPlayers.length) {
if (playerIndex < 0 || playerIndex >= activePlayers.length) {
playerIndex = (playerIndex + activePlayers.length) % activePlayers.length
}
}

View File

@@ -9,6 +9,7 @@ Singleton {
NotificationServer {
id: server
actionsSupported: true
onNotification: notif => {
notif.tracked = true;

View File

@@ -22,6 +22,7 @@ Button {
property var releaseAction // When left clicking (release)
property var altAction // When right clicking
property var middleClickAction // When middle clicking
property color buttonTextColor: Appearance?.m3colors.m3onBackground ?? "black"
property color colBackground: ColorUtils.transparentize(Appearance?.colors.colLayer1Hover, 1) || "transparent"
property color colBackgroundHover: Appearance?.colors.colLayer1Hover ?? "#E5DFED"
@@ -197,5 +198,6 @@ Button {
contentItem: StyledText {
text: root.buttonText
color: root.buttonTextColor
}
}

111
osd/NotificationItem.qml Normal file
View File

@@ -0,0 +1,111 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Quickshell
import Quickshell.Widgets
import Quickshell.Services.Notifications
import qs.common
import qs.common.widgets
Item {
id: root
required property Notification notif
required property real textWidth
required property real notificationRounding
property real spacing: 8
Layout.fillWidth: true
implicitHeight: content.implicitHeight
ColumnLayout {
id: content
Layout.fillWidth: true
spacing: 0
Rectangle {
implicitHeight: appTitle.implicitHeight
implicitWidth: root.width
anchors.margins: Config.options.bar.cornerStyle === 1 ? (Appearance.sizes.hyprlandGapsOut) : 0
color: Appearance.m3colors.m3primaryContainer
topLeftRadius: root.notificationRounding
topRightRadius: root.notificationRounding
RowLayout {
spacing: 0 // For some reason, adding a spacing of just the value will not work properly
IconImage {
visible: root.notif.appIcon.length > 0
id: appIcon
source: Quickshell.iconPath(root.notif.appIcon)
width: appTitle.height - root.spacing
height: appTitle.height - root.spacing
Layout.leftMargin: root.spacing / 2
}
Text {
// app title
id: appTitle
text: root.notif.appName
color: Appearance.m3colors.m3onPrimaryContainer
Layout.leftMargin: root.spacing / 2
}
}
}
Rectangle {
visible: notifSummary.visible || notifBody.visible
implicitHeight: body.implicitHeight
implicitWidth: root.width
anchors.margins: Config.options.bar.cornerStyle === 1 ? (Appearance.sizes.hyprlandGapsOut) : 0
color: Appearance.colors.colLayer2
bottomLeftRadius: root.notificationRounding
bottomRightRadius: root.notificationRounding
ColumnLayout {
id: body
spacing: root.spacing
Text {
visible: root.notif.summary.length > 0
Layout.leftMargin: root.spacing
Layout.rightMargin: root.spacing
id: notifSummary
text: root.notif.summary
color: Appearance.colors.colOnLayer2
wrapMode: Text.WordWrap
}
Text {
visible: root.notif.body.length > 0
Layout.leftMargin: root.spacing
Layout.rightMargin: root.spacing
Layout.preferredWidth: textWidth
id: notifBody
text: root.notif.body
color: Appearance.colors.colOnLayer2
wrapMode: Text.WordWrap
maximumLineCount: 4
}
RowLayout {
id: actionLayer
Layout.fillWidth: true
Layout.leftMargin: root.spacing
Layout.rightMargin: root.spacing
Layout.bottomMargin: root.spacing
spacing: root.spacing
RippleButton {
buttonText: "Dismiss"
colBackground: Appearance.m3colors.m3primaryContainer
releaseAction: root.notif.dismiss
buttonRadius: root.notificationRounding
}
Repeater {
model: root.notif.actions
RippleButton {
buttonText: modelData.text
buttonTextColor: Appearance.m3colors.m3onTertiaryContainer
colBackground: Appearance.m3colors.m3tertiaryContainer
releaseAction: modelData.invoke
buttonRadius: root.notificationRounding
}
}
}
}
}
}
}

69
osd/NotificationPanel.qml Normal file
View File

@@ -0,0 +1,69 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Wayland
import Quickshell.Services.Notifications
import qs
import qs.common
Scope {
id: root
property bool visible: false
property int panelWidth: 350
Loader {
id: notificationPanelLoader
active: GlobalStates.notificationPanelOpen
/**
onActiveChanged: {
if (!notificationPanelLoader.active & NotificationServer.amountNotifications == 0) {
GlobalStates.notificationPanelOpen = false;
}
}
//*/
sourceComponent: PanelWindow {
id: notificationPanelRoot
visible: true
exclusionMode: ExclusionMode.Ignore
exclusiveZone: 0
implicitWidth: root.panelWidth
anchors {
top: true
right: true
bottom: true
}
margins {
top: Config.options.bar.height
}
Rectangle {
anchors {
fill: parent
margins: Config.options.bar.cornerStyle === 1 ? (Appearance.sizes.hyprlandGapsOut) : 0
}
color: Config.options.bar.showBackground ? Appearance.colors.colLayer1 : "transparent"
}
ColumnLayout {
id: notifs
anchors.margins: 4
anchors.left: parent.left
anchors.right: parent.right
Repeater {
model: NotificationService.notifications
NotificationItem {
required property Notification modelData
notif: modelData
textWidth: root.panelWidth - 14
notificationRounding: Appearance.rounding.unsharpenmore
}
}
}
}
}
}

View File

@@ -2,9 +2,12 @@
import Quickshell
import qs.bar
import qs.osd
import qs.background
Scope {
Bar {}
VolumeDisplay {}
//MediaControls {}
NotificationPanel {}
Background {}
}