make config use json instead of shitty qt implementation

This commit is contained in:
lucy 2026-08-27 18:10:37 +02:00
commit 31965a0dba
40 changed files with 272 additions and 745 deletions

View file

@ -0,0 +1,10 @@
pragma Singleton
import Quickshell
import qs
import qs.settings
Singleton {
id: root
readonly property url wallDir: Config.wallDir
property url currentWallpaper: Config.wallpaper
}

View file

@ -0,0 +1 @@
lucy@nerv.1006:1787837190

View file

@ -1,10 +0,0 @@
pragma Singleton
import Quickshell
import QtQuick
import Quickshell.Pipewire
Singleton {
property
}

View file

@ -1,21 +0,0 @@
pragma Singleton
import Quickshell
import Quickshell.Networking
Singleton {
id: root
property bool wifiEnabled: Networking.wifiEnabled
property string connectivity: Networking.connectivity.toString(Networking.connectivity)
readonly property list<NetworkDevice> devices: Networking.devices.values
function getConnectedDevice() {
for(let i=0; i < devices.length; ++i) {
console.log(i)
if(devices[i].connected) {
return devices[i];
}
return null;
}
}
}

View file

@ -0,0 +1,93 @@
pragma ComponentBehavior: Bound
import qs
import qs.settings
import Quickshell
import QtQuick
import qs.widgets
import qs.modules.Services
import QtQuick.Layouts
import QtQuick.Controls
PopupWindow {
implicitWidth: audioLayout.implicitWidth + 2 * audioLayout.anchors.margins
implicitHeight: audioLayout.implicitHeight + 24
anchor.edges: Edges.Top | Edges.Right
anchor.gravity: Edges.Bottom | Edges.Left
anchor.margins.top: 40
color: 'transparent'
grabFocus: true
Rectangle {
id: root
anchors.fill: parent
color: Colors.barBg
radius: Config.cfg.appearance.rounding
ColumnLayout {
id: audioLayout
anchors.centerIn: parent
anchors.margins: 10
spacing: 8
Repeater {
id: audioRep
model: Audio.sinks
delegate: Rectangle {
Layout.fillWidth: true
id: audioDelContainer
color: Colors.moduleBg
radius: Config.cfg.appearance.rounding
required property var modelData
implicitHeight: audioRow.implicitHeight + 8
implicitWidth: audioRow.implicitWidth
RowLayout {
id: audioRow
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.fill: parent
StyledText {
text: audioDelContainer.modelData.nickname
Layout.leftMargin: 10
Layout.fillWidth: true
Layout.maximumWidth: 200
elide: Text.ElideRight
}
StyledIcon {
Layout.leftMargin: 10
iconName: Audio.getVolumeIcon(audioDelContainer.modelData)
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
onClicked: {
audioDelContainer.modelData.audio.muted = !audioDelContainer.modelData.audio.muted;
}
}
}
StyledIcon {
iconName: audioDelContainer.modelData === Audio.preferredAudio ? "radio-checked-symbolic" : "radio-symbolic"
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
onClicked: {
Audio.setDefaultSink(audioDelContainer.modelData);
}
}
}
Slider {
Layout.rightMargin: 10
value: audioDelContainer.modelData.audio.volume
from: 0
to: 1
onMoved: {
audioDelContainer.modelData.audio.volume = value;
}
}
}
}
}
}
}
}

View file

@ -4,15 +4,13 @@ import Quickshell.Wayland
import Quickshell.Widgets
import QtQuick
import Qt.labs.folderlistmodel 2.11
import QtQuick.Effects
import qs
import qs.settings
import qs.widgets
BarComponent {
implicitHeight: Config.moduleHeight
implicitWidth: Config.moduleHeight
implicitWidth: implicitHeight
required property int screenHeight
id: main
StyledIcon {
@ -57,7 +55,7 @@ BarComponent {
}
anchors.fill: parent
color: Colors.base02
radius: Config.rounding
radius: Config.cfg.appearance.rounding
GridView {
id: wallpaperLayout
clip: true
@ -73,7 +71,7 @@ BarComponent {
id: wallTile
clip: true
required property var modelData
radius: Config.rounding / 1.5
radius: Config.cfg.appearance.rounding / 1.5
color: 'transparent'
implicitWidth: wallpaperLayout.cellWidth - 20
implicitHeight: wallpaperLayout.cellHeight - 20
@ -93,14 +91,15 @@ BarComponent {
acceptedButtons: Qt.LeftButton
hoverEnabled: true
onClicked: {
Config.wallpaper = wallTile.modelData.filePath;
Config.cfg.wallpaper.wallpaper = wallTile.modelData.filePath;
Config.save()
}
}
}
}
FolderListModel {
id: wallpaperList
folder: Config.wallDir
folder: Qt.resolvedUrl(Config.cfg.wallpaper.wallDir)
nameFilters: ["*.png"]
}
}

View file

@ -2,38 +2,21 @@ pragma ComponentBehavior: Bound
import Quickshell
import Quickshell.Wayland
import Quickshell.Widgets
import Quickshell.Hyprland
import QtQuick
import Qt.labs.folderlistmodel 2.11
import QtQuick.Effects
import qs
import qs.settings
import qs.widgets
Rectangle {
id: main
layer.enabled: true
layer.effect: MultiEffect {
id: dropShadow
source: main
shadowEnabled: true
shadowHorizontalOffset: 4
shadowVerticalOffset: 2
shadowOpacity: 0.5
shadowColor: "#020202"
}
required property real moduleHeight
BarComponent {
implicitHeight: Config.moduleHeight
implicitWidth: Config.moduleHeight
required property int screenHeight
color: Colors.moduleBg
radius: Config.rounding
implicitWidth: moduleHeight
implicitHeight: moduleHeight
MaterialIcon {
anchors.centerIn: main
text: "\ue1bc"
font.bold: true
id: main
StyledIcon {
iconName: "preferences-desktop-wallpaper-symbolic"
anchors.centerIn: parent
}
MouseArea {
id: clickHandler
@ -61,12 +44,6 @@ Rectangle {
left: 20
right: 20
}
HyprlandFocusGrab {
id: grabber
active: wallPicker.visible
windows: [wallPicker]
onCleared: wallPicker.visible = false
}
onVisibleChanged: {
if (wallPicker.visible)
container.forceActiveFocus();
@ -78,7 +55,7 @@ Rectangle {
wallPicker.visible = false;
}
anchors.fill: parent
color: Colors.base00
color: Colors.base02
radius: Config.rounding
GridView {
id: wallpaperLayout
@ -122,7 +99,7 @@ Rectangle {
}
FolderListModel {
id: wallpaperList
folder: Config.wallDir
folder: Qt.resolvedUrl(Config.wallDir)
nameFilters: ["*.png"]
}
}

52
modules/bar/#Bat.qml# Normal file
View file

@ -0,0 +1,52 @@
import Quickshell.Services.UPower
import Quickshell
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import QtQuick.Effects
import qs
import qs.widgets
import qs.settings
BarComponent {
id: root
visible: UPower.displayDevice.isLaptopBattery
property double percent: UPower.displayDevice.percentage * 100
property bool hasBattery: UPower.displayDevice.isLaptopBattery
property bool charging: UPower.displayDevice.state === UPowerDeviceState.Charging
implicitWidth: batLayout.implicitWidth + 16
function batteryIcon() {
let charging = root.charging;
let percent = root.percent;
if (percent <= 10)
return charging ? "battery-empty-charging" : "battery-empty";
if (percent < 40)
return charging ? "battery-level-30-charging" : "battery-level-30";
if (percent < 50)
return charging ? "battery-level-40-charging" : "battery-level-40";
if (percent < 60)
return charging ? "battery-level-50-charging" : "battery-level-50";
if (percent < 70)
return charging ? "battery-level-60-charging" : "battery-level-60";
if (percent < 80)
return charging ? "battery-level-70-charging" : "battery-level-70";
if (percent < 90)
return charging ? "battery-level-80-charging" : "battery-level-80";
if (percent > 90)
return charging ? "battery-level-90-charging" : "battery-level-90";
if (percent == 100)
return charging ? "battery-level-100-charging" : "battery-level-100";
}
RowLayout {
id: batLayout
anchors.centerIn: root
StyledIcon {
iconName: root.batteryIcon()
}
StyledText {
text: Math.floor(root.percent, root.charging) + "%"
}
}
}

1
modules/bar/.#Bat.qml Symbolic link
View file

@ -0,0 +1 @@
lucy@nerv.1006:1787837190

View file

@ -1,31 +0,0 @@
pragma ComponentBehavior: Bound
import Quickshell.Widgets
import Quickshell.Hyprland
import QtQuick
import QtQuick.Layouts
import qs
import qs.widgets
import qs.settings
import QtQuick.Effects
BarComponent {
id: root
implicitHeight: moduleHeight
implicitWidth: titleLayout.width + 32
color: Colors.moduleBg
radius: Config.rounding
RowLayout {
id: titleLayout
anchors.centerIn: root
WrapperRectangle {
Layout.maximumWidth: 400
color: 'transparent'
clip: true
StyledText {
property bool onWs: Hyprland.activeToplevel?.workspace == Hyprland.focusedWorkspace
text: onWs ? Hyprland.activeToplevel?.title ?? "Desktop" : "Desktop"
elide: Text.ElideRight
}
}
}
}

View file

@ -1,8 +1,8 @@
import Quickshell
import QtQuick
import QtQuick.Layouts
import qs.modules.wallpaper
import qs.settings
import qs.modules.applets
import qs
Variants {
@ -17,14 +17,14 @@ Variants {
right: true
}
color: 'transparent'
implicitHeight: Config.barHeight
margins.top: Config.floating ? 10 : 0
margins.left: Config.floating ? 10 : 0
margins.right: Config.floating ? 10 : 0
implicitHeight: Config.cfg.bar.height
margins.top: Config.cfg.bar.floating ? 10 : 0
margins.left: Config.cfg.bar.floating ? 10 : 0
margins.right: Config.cfg.bar.floating ? 10 : 0
Rectangle {
anchors.fill: parent
color: Colors.barBg
radius: Config.floating ? Config.rounding : 0
radius: Config.cfg.bar.floating ? Config.cfg.appearance.rounding : 0
RowLayout {
anchors.leftMargin: 4
anchors.left: parent.left
@ -44,7 +44,6 @@ Variants {
anchors.verticalCenter: parent.verticalCenter
Mpris {}
Bat {}
Tray {}
WallPicker {
screenHeight: root.screen.height

View file

@ -1,13 +0,0 @@
import Quickshell
import QtQuick
Variants {
model: Quickshell.screens
delegate: PanelWindow {
anchors {
top: true
left: true
right: true
}
}
}

View file

@ -14,10 +14,11 @@ BarComponent {
property double percent: UPower.displayDevice.percentage * 100
property bool hasBattery: UPower.displayDevice.isLaptopBattery
property bool charging: UPower.displayDevice.state === UPowerDeviceState.Charging
implicitHeight: Config.moduleHeight
implicitWidth: batLayout.implicitWidth + 16
function batteryIcon(percent, charging) {
function batteryIcon() {
let charging = root.charging
let percent = root.percent
if(percent <= 10) return charging ? "battery-empty-charging" : "battery-empty"
if(percent < 40) return charging ? "battery-level-30-charging" : "battery-level-30"
if(percent < 50) return charging ? "battery-level-40-charging" : "battery-level-40"
@ -32,16 +33,10 @@ BarComponent {
RowLayout {
id: batLayout
anchors.centerIn: root
IconImage {
source: Quickshell.iconPath(root.batteryIcon(root.percent, root.charging) + "-symbolic")
implicitSize: Config.iconSize
layer.enabled: true
layer.effect: MultiEffect {
colorization: 1.0
colorizationColor: Colors.text
brightness: 0.5
StyledIcon {
iconName: root.batteryIcon()
}
}
StyledText {
text: Math.floor(root.percent,root.charging) + "%"
}

View file

@ -1,58 +0,0 @@
import Quickshell.Services.UPower
import QtQuick
import QtQuick.Layouts
import QtQuick.Effects
import qs
import qs.widgets
import qs.settings
BarComponent {
id: root
layer.enabled: true
layer.effect: MultiEffect {
id: dropShadow
source: root
shadowEnabled: true
shadowHorizontalOffset: 4
shadowVerticalOffset: 2
shadowOpacity: 0.5
shadowColor: "#020202"
}
clip: true
color: Colors.moduleBg
visible: UPower.displayDevice.isLaptopBattery
property double percent: UPower.displayDevice.percentage * 100
property bool hasBattery: UPower.displayDevice.isLaptopBattery
property bool charging: UPower.displayDevice.state === UPowerDeviceState.Charging
required property double moduleHeight
implicitHeight: moduleHeight
implicitWidth: batLayout.implicitWidth + 16
radius: Config.rounding
function batteryIcon(percent) {
if (root.charging)
return "battery_android_frame_bolt";
if (percent <= 15)
return "battery_android_alert";
if (percent <= 30)
return "battery_android_frame_2";
if (percent <= 50)
return "battery_android_frame_3";
if (percent <= 70)
return "battery_android_frame_4";
if (percent <= 85)
return "battery_android_frame_5";
if (percent <= 100)
return "battery_android_frame_full";
}
RowLayout {
id: batLayout
anchors.centerIn: root
MaterialIcon {
text: root.batteryIcon(root.percent)
}
StyledText {
text: Math.floor(root.percent) + "%"
}
}
}

View file

@ -1,26 +0,0 @@
pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Effects
import qs
import qs.widgets
import qs.settings
BarComponent {
id: root
clip: true
required property double moduleHeight
implicitHeight: moduleHeight
implicitWidth: clockText.implicitWidth + 32
color: Colors.moduleBg
radius: Config.rounding
SystemClock {
id: clock
precision: SystemClock.Seconds
}
StyledText {
id: clockText
anchors.centerIn: root
text: Qt.formatDateTime(clock.date, "d.M.yy - hh:mm:ss")
}
}

View file

@ -11,7 +11,6 @@ import qs.settings
BarComponent {
id: root
implicitHeight: Config.moduleHeight
implicitWidth: songLayout.implicitWidth + 16
property MprisPlayer spotify: {
for (const player of Mpris.players.values) {
@ -25,19 +24,12 @@ BarComponent {
RowLayout {
id: songLayout
anchors.centerIn: root
IconImage {
source: Quickshell.iconPath("folder-music-symbolic")
implicitSize: Config.iconSize
layer.enabled: true
layer.effect: MultiEffect {
colorization: 1.0
colorizationColor: Colors.text
brightness: 0.5
}
StyledIcon {
iconName: "folder-music-symbolic"
}
StyledText {
Layout.maximumWidth: 400
Layout.maximumHeight: Config.barHeight / 1.6
Layout.maximumHeight: Config.cfg.bar.barHeight / 1.6
text: root.spotify?.trackTitle + " - " + root.spotify?.trackArtists
elide: Text.ElideRight
}

View file

@ -1,49 +0,0 @@
pragma ComponentBehavior: Bound
import Quickshell.Services.Mpris
import QtQuick
import QtQuick.Layouts
import QtQuick.Effects
import qs
import qs.widgets
import qs.settings
Rectangle {
id: root
layer.enabled: true
layer.effect: MultiEffect {
id: dropShadow
source: root
shadowEnabled: true
shadowHorizontalOffset: 4
shadowVerticalOffset: 2
shadowOpacity: 0.5
shadowColor: "#020202"
}
required property double moduleHeight
implicitHeight: moduleHeight
implicitWidth: songLayout.implicitWidth + 32
property MprisPlayer spotify: {
for (const player of Mpris.players.values) {
if (player.identity === "Spotify")
return player;
}
return null;
}
visible: spotify !== null && spotify.playbackState === MprisPlaybackState.Playing
clip: true
color: Colors.moduleBg
radius: Config.rounding
RowLayout {
id: songLayout
anchors.centerIn: root
MaterialIcon {
text: "music_note_2"
}
StyledText {
Layout.maximumWidth: 400
Layout.maximumHeight: Config.barHeight / 1.6
text: root.spotify?.trackTitle + " - " + root.spotify?.trackArtists
elide: Text.ElideRight
}
}
}

View file

@ -1,29 +0,0 @@
import qs
import qs.modules.Services
import qs.widgets
import qs.settings
import Quickshell
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
BarComponent {
id: root
implicitWidth: networkLayout.implicitWidth + 24
RowLayout {
anchors.centerIn: root
id: networkLayout
StyledText {
id: status
text: Network.wifiEnabled ? "Wifi enabled :3" : "Wifi disabled :("
}
StyledText {
id: wifiDevName
text: Network.connectedWifiDev?.name ?? "not connected via wifi"
}
StyledText{
id: wiredDevName
text: Network.connectedWiredDev?.name ?? "not connected via wired"
}
}
}

View file

@ -1,11 +1,7 @@
pragma ComponentBehavior: Bound
import Quickshell.Services.Pipewire
import Quickshell.Widgets
import Quickshell
import QtQuick
import QtQuick.Layouts
import QtQuick.Effects
import qs
import qs.modules.applets
import qs.widgets
import qs.settings
import qs.modules.Services
@ -13,7 +9,6 @@ import qs.modules.Services
BarComponent {
id: root
active: clickHandler.containsMouse
implicitHeight: Config.moduleHeight
implicitWidth: pwLayout.implicitWidth + 16
RowLayout {
id: pwLayout

View file

@ -1,77 +0,0 @@
pragma ComponentBehavior: Bound
import Quickshell.Services.Pipewire
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
import QtQuick.Effects
import qs
import qs.widgets
import qs.settings
BarComponent {
id: root
layer.enabled: true
layer.effect: MultiEffect {
id: dropShadow
source: root
shadowEnabled: true
shadowHorizontalOffset: 4
shadowVerticalOffset: 2
shadowOpacity: 0.5
shadowColor: "#020202"
}
color: clickHandler.containsMouse ? Colors.activeModuleBg : Colors.moduleBg
property PwNode defaultAudio: Pipewire.ready ? Pipewire.defaultAudioSink : null
property bool mute: Pipewire.ready ? defaultAudio?.audio.muted : null
radius: Config.rounding
required property double moduleHeight
implicitHeight: moduleHeight
implicitWidth: pwLayout.implicitWidth + 16
function getVolumeIcon() {
let volume = Pipewire.ready ? root.defaultAudio.audio.volume : null;
if (root.mute) {
return "\ue04f";
}
if (volume <= 0.33) {
return "\ue04e";
}
if (volume <= 0.66) {
return "\ue04d";
}
if (volume >= 0.66) {
return "\ue050";
}
}
PwObjectTracker {
objects: [Pipewire.ready ? Pipewire.defaultAudioSink : null]
}
Process {
id: pavuLauncher
command: ["pavucontrol"]
running: false
}
RowLayout {
id: pwLayout
anchors.centerIn: root
spacing: 4
MaterialIcon {
text: root.getVolumeIcon()
opacity: root.defaultAudio?.audio.muted ? 0.6 : 1.0
}
StyledText {
text: Math.round(root.defaultAudio?.audio.volume * 100) + "%"
opacity: root.defaultAudio?.audio.muted ? 0.6 : 1.0
}
}
MouseArea {
id: clickHandler
hoverEnabled: true
acceptedButtons: Qt.LeftButton
cursorShape: Qt.PointingHandCursor
anchors.fill: root
onClicked: pavuLauncher.running = true
}
}

View file

@ -12,7 +12,6 @@ import qs.widgets
BarComponent {
id: root
visible: iconRepeater.count != 0
implicitHeight: Config.moduleHeight
implicitWidth: iconlayout.width + 16
RowLayout {

View file

@ -1,53 +0,0 @@
pragma ComponentBehavior: Bound
import Quickshell
import Quickshell.Services.SystemTray
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import QtQuick.Effects
import qs
import qs.settings
BarComponent {
id: root
visible: iconRepeater.count != 0
implicitHeight: Config.moduleHeight
implicitWidth: iconlayout.width + 16
color: Colors.moduleBg
radius: Config.rounding
RowLayout {
id: iconlayout
anchors.centerIn: root
spacing: 8
Repeater {
id: iconRepeater
model: SystemTray.items
delegate: Item {
id: iconWrapper
required property var modelData
implicitWidth: 16
implicitHeight: 16
IconImage {
anchors.centerIn: parent
source: iconWrapper.modelData.icon
implicitSize: 16
}
QsMenuAnchor {
id: menu
anchor.item: iconWrapper
menu: iconWrapper.modelData.menu
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: mouse => {
if (mouse.button == Qt.RightButton) {
menu.open();
}
}
}
}
}
}
}

View file

@ -1,39 +0,0 @@
import qs
import qs.settings
import Quickshell
import QtQuick
import qs.widgets
PopupWindow {
id: volPopup
anchor.item: root
implicitWidth: 500
implicitHeight: 600
anchor.edges: Edges.Top | Edges.Right
anchor.gravity: Edges.Bottom | Edges.Left
anchor.margins.top: 40
anchor.margins.right: 0
color: 'transparent'
Rectangle {
id: test
anchors.fill: parent
color: Colors.activeModuleBg
radius: Config.rounding
ListView {
id: sourceLayout
model: Pipewire.nodes
delegate: Rectangle {
implicitHeight: 10
required property var modelData
StyledText {
text: parent.modelData.nickname
}
}
}
}
}

View file

@ -16,14 +16,12 @@ BarComponent {
spacing: 0
Repeater {
model: WindowManager.screenProjection(root.barScreen).windowsets
delegate: Rectangle {
delegate: BarComponent {
id: wsContainer
required property var modelData
visible: modelData.shouldDisplay
implicitWidth: modelData.active ? 50 : 20
implicitHeight: Config.moduleHeight - 4
color: modelData.active ? Colors.base0D : Colors.moduleBg
radius: Config.rounding
Behavior on implicitWidth {
PropertyAnimation {
duration: 350

View file

@ -1,27 +0,0 @@
import Quickshell
import Quickshell.WindowManager
import QtQuick
import QtQuick.Layouts
import qs
import qs.widgets
BarComponent {
id: root
required property ShellScreen barScreen
RowLayout {
spacing: 15
anchors.fill: parent
Repeater {
model: WindowManager.screenProjection(root.barScreen).windowsets
delegate: Rectangle {
required property var modelData
visible: modelData.shouldDisplay
StyledText {
id: wsText
text: parent.modelData.name
color: parent.modelData.active ? Colors.base0D: Colors.base03
}
}
}
}
}

View file

@ -1,40 +0,0 @@
import qs
import qs.settings
import Quickshell
import Quickshell.Widgets
import QtQuick
import qs.widgets
PopupWindow {
id: volPopup
anchor.item: root
implicitWidth: 500
implicitHeight: 600
anchor.edges: Edges.Top | Edges.Right
anchor.gravity: Edges.Bottom | Edges.Left
anchor.margins.top: 40
anchor.margins.right: 0
color: 'transparent'
Rectangle {
id: test
anchors.fill: parent
color: Colors.activeModuleBg
radius: Config.rounding
ListView {
id: sourceLayout
model: Pipewire.nodes
delegate: Rectangle {
implicitHeight: 10
required property var modelData
StyledText {
text: parent.modelData.nickname
}
}
}
}
}

View file

@ -13,7 +13,7 @@ WrapperRectangle {
property alias timerStart: dismissTimer
implicitWidth: nScreen.width / 6
implicitHeight: 100
radius: Config.rounding
radius: Config.cfg.appearance.rounding
anchors.right: parent?.right
color: Colors.barBg
clip: true

View file

@ -1,92 +0,0 @@
import Quickshell
import Quickshell.Widgets
import QtQuick.Layouts
import QtQuick
import qs
import qs.settings
import qs.widgets
WrapperRectangle {
id: root
required property var notification
required property ShellScreen nScreen
implicitWidth: nScreen.width / 6
implicitHeight: 100
radius: Config.rounding
anchors.right: parent?.right
color: Colors.barBg
clip: true
Timer {
id: dismissTimer
running: true
interval: 5000
repeat: false
onTriggered: root.notification?.dismiss()
}
child: WrapperMouseArea {
id: mouseHandler
child: RowLayout {
spacing: 10
IconImage {
id: appIcon
Layout.leftMargin: 8
visible: root.notification?.image ? true : false
source: root.notification?.image ? root.notification.image : ''
implicitSize: 64
}
ColumnLayout {
Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true
Layout.preferredWidth: 0
Layout.fillHeight: true
Layout.leftMargin: appIcon.visible ? 0 : 16
RowLayout {
Layout.alignment: Qt.AlignTop
MaterialIcon {
text: "\ue7f7"
font.pixelSize: 12
}
StyledText {
id: appId
text: root.notification?.appName ? root.notification.appName : ''
opacity: 0.4
}
}
ColumnLayout {
spacing: 0
Layout.rightMargin: 40
StyledText {
id: title
Layout.bottomMargin: 0
Layout.topMargin: 5
Layout.alignment: Qt.AlignBottom
Layout.fillWidth: true
text: root.notification?.summary == null ? '' : root.notification.summary
elide: Text.ElideRight
}
StyledText {
id: body
Layout.alignment: Qt.AlignBottom
text: root.notification?.body ? root.notification.body : ''
elide: Text.ElideRight
maximumLineCount: 1
Layout.fillWidth: true
opacity: 0.6
}
}
}
}
acceptedButtons: Qt.LeftButton
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onEntered: {
root.color = Colors.base03;
}
onExited: {
root.color = Colors.base01;
}
onClicked: {
root.notification ? root.notification.dismiss() : '';
}
}
}

View file

@ -16,7 +16,7 @@ Variants {
top: true
right: true
}
margins.top: Config.barHeight + 8 + (Config.floating ? 10 : 0)
margins.top: Config.cfg.bar.height + 8 + (Config.cfg.bar.floating ? 10 : 0)
margins.right: 8
implicitHeight: notiList.contentHeight
implicitWidth: modelData.width / 6

View file

@ -1,46 +0,0 @@
pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import Quickshell.Wayland
import qs.settings
import Quickshell.Hyprland
WlrLayershell {
id: notiPopup
property ShellScreen activeScreen: getActiveScreen()
function getActiveScreen() {
let current = Quickshell.screens[0];
for (let i = 0; i < Quickshell.screens.length; i++) {
current = Quickshell.screens[i];
if (Hyprland.monitorFor(current) == Hyprland.focusedMonitor) {
return current;
}
}
return current;
}
exclusionMode: ExclusionMode.Ignore
layer: WlrLayer.Overlay
screen: activeScreen
anchors {
top: true
right: true
}
margins.top: Config.barHeight + 8 + (Config.floating ? 10 : 0)
margins.right: 8
implicitHeight: notiList.contentHeight
implicitWidth: activeScreen.width / 6
color: 'transparent'
visible: NotiServer.notifications.values.length > 0
ListView {
id: notiList
anchors.fill: parent
model: NotiServer.notifications
spacing: 6
delegate: NotiCard {
required property var modelData
nScreen: notiPopup.activeScreen
notification: modelData
}
}
}

View file

@ -1,18 +0,0 @@
pragma Singleton
import Quickshell
import Quickshell.Services.Notifications
import QtQuick
Singleton {
id: root
property alias notifications: server.trackedNotifications
NotificationServer {
id: server
imageSupported: true
bodyImagesSupported: true
onNotification: notification => {
notification.tracked = true;
}
}
}

View file

@ -21,7 +21,7 @@ Variants {
Image {
cache: false
anchors.fill: parent
source: Config.wallpaper
source: Qt.resolvedUrl(Config.cfg.wallpaper.wallpaper)
}
}
}

View file

@ -2,33 +2,43 @@ pragma Singleton
import QtCore
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
property string font: "Maple Mono"
property int fontSize: 12
property int iconSize: 14
property int barHeight: 30
property int rounding: 16
property url wallpaper: "file:///home/lucy/.walls/frierensuff.png"
property bool floating: false
property double opacity: 1.0
property string primaryMon: "eDP-1"
property string wallDir: "file://" + Quickshell.env("HOME") + "/.walls"
property bool showCorners: true
property real moduleHeight: barHeight - 8
Settings {
location: Qt.resolvedUrl("file:///home/lucy/.config/quickshell/settings/settings.ini")
property alias font: root.font
property alias fontSize: root.fontSize
property alias barHeight: root.barHeight
property alias rounding: root.rounding
property alias wallpaper: root.wallpaper
property alias opacity: root.opacity
property alias primaryMon: root.primaryMon
property alias floating: root.floating
property alias wallDir: root.wallDir
property alias showCorners: root.showCorners
property alias iconSize: root.iconSize
property alias cfg: cfg
function save() {
if (cfgView.loaded)
cfgView.writeAdapter();
}
FileView {
id: cfgView
path: Qt.resolvedUrl(Quickshell.shellDir + "/settings/settings.json")
watchChanges: true
onFileChanged: {
this.reload();
}
onLoadFailed: error => {
if (error === FileViewError.FileNotFound)
writeAdapter();
}
adapter: JsonAdapter {
id: cfg
property JsonObject appearance: JsonObject {
property string font: "Iosevka"
property int fontSize: 14
property int iconSize: 16
property int rounding: 16
}
property JsonObject bar: JsonObject {
property bool floating: true
property int height: 40
property real opacity: 1.0
}
property JsonObject wallpaper: JsonObject {
property string wallDir: Quickshell.env("HOME") + "/.walls/"
property string wallpaper: ""
}
}
}
}

View file

@ -1,12 +1,12 @@
[General]
barHeight=30
floating=true
floating=false
font=Iosevka
fontSize=16
iconSize=18
fontSize=14
iconSize=16
opacity=1
primaryMon=eDP-1
rounding=16
showCorners=true
wallDir=file:///home/lucy/.walls
wallpaper=@Variant(\0\0\0\x11\0\0\0\x1f/home/lucy/.walls/lain_blue.png)
wallDir=/home/lucy/.walls/
wallpaper=/home/lucy/.walls/walkingcastle.png

17
settings/settings.json Normal file
View file

@ -0,0 +1,17 @@
{
"appearance": {
"font": "Iosevka",
"fontSize": 14,
"iconSize": 16,
"rounding": 16
},
"bar": {
"floating": true,
"height": 40,
"opacity": 1
},
"wallpaper": {
"wallDir": "/home/lucy/.walls/",
"wallpaper": "/home/lucy/.walls/frierensuff.png"
}
}

18
settings/settings.json~ Normal file
View file

@ -0,0 +1,18 @@
{
"appearance": {
"font": "Iosevka",
"fontSize": 14,
"iconSize": 16,
"rounding": 16
},
"bar": {
"floating": true,
"height": 38,
"moduleHeight": 30,
"opacity": 1
},
"wallpaper": {
"wallDir": "/home/lucy/.walls/",
"wallpaper": "/home/lucy/.walls/frierensuff.png"
}
}

View file

@ -6,6 +6,6 @@ import qs.settings
Rectangle {
property bool active: false
color: active ? Colors.activeModuleBg : Colors.moduleBg
implicitHeight: Config.moduleHeight
radius: Config.rounding
implicitHeight: Config.cfg.bar.height - 8
radius: Config.cfg.appearance.rounding
}

View file

@ -6,7 +6,7 @@ import qs.settings
IconImage {
required property string iconName
implicitSize: Config.iconSize
implicitSize: Config.cfg.appearance.iconSize
source: Quickshell.iconPath(iconName)
layer.enabled: true
layer.effect: MultiEffect {

View file

@ -4,6 +4,6 @@ import qs.settings
Text {
color: Colors.text
font.family: Config.font
font.pixelSize: Config.fontSize
font.family: Config.cfg.appearance.font
font.pixelSize: Config.cfg.appearance.fontSize
}