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

View file

@ -2,38 +2,21 @@ pragma ComponentBehavior: Bound
import Quickshell import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import Quickshell.Widgets import Quickshell.Widgets
import Quickshell.Hyprland
import QtQuick import QtQuick
import Qt.labs.folderlistmodel 2.11 import Qt.labs.folderlistmodel 2.11
import QtQuick.Effects
import qs import qs
import qs.settings import qs.settings
import qs.widgets import qs.widgets
Rectangle { BarComponent {
id: main implicitHeight: Config.moduleHeight
implicitWidth: Config.moduleHeight
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
required property int screenHeight required property int screenHeight
color: Colors.moduleBg id: main
radius: Config.rounding StyledIcon {
implicitWidth: moduleHeight iconName: "preferences-desktop-wallpaper-symbolic"
implicitHeight: moduleHeight anchors.centerIn: parent
MaterialIcon {
anchors.centerIn: main
text: "\ue1bc"
font.bold: true
} }
MouseArea { MouseArea {
id: clickHandler id: clickHandler
@ -61,12 +44,6 @@ Rectangle {
left: 20 left: 20
right: 20 right: 20
} }
HyprlandFocusGrab {
id: grabber
active: wallPicker.visible
windows: [wallPicker]
onCleared: wallPicker.visible = false
}
onVisibleChanged: { onVisibleChanged: {
if (wallPicker.visible) if (wallPicker.visible)
container.forceActiveFocus(); container.forceActiveFocus();
@ -78,7 +55,7 @@ Rectangle {
wallPicker.visible = false; wallPicker.visible = false;
} }
anchors.fill: parent anchors.fill: parent
color: Colors.base00 color: Colors.base02
radius: Config.rounding radius: Config.rounding
GridView { GridView {
id: wallpaperLayout id: wallpaperLayout
@ -122,7 +99,7 @@ Rectangle {
} }
FolderListModel { FolderListModel {
id: wallpaperList id: wallpaperList
folder: Config.wallDir folder: Qt.resolvedUrl(Config.wallDir)
nameFilters: ["*.png"] 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 Quickshell
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.modules.wallpaper
import qs.settings import qs.settings
import qs.modules.applets
import qs import qs
Variants { Variants {
@ -17,14 +17,14 @@ Variants {
right: true right: true
} }
color: 'transparent' color: 'transparent'
implicitHeight: Config.barHeight implicitHeight: Config.cfg.bar.height
margins.top: Config.floating ? 10 : 0 margins.top: Config.cfg.bar.floating ? 10 : 0
margins.left: Config.floating ? 10 : 0 margins.left: Config.cfg.bar.floating ? 10 : 0
margins.right: Config.floating ? 10 : 0 margins.right: Config.cfg.bar.floating ? 10 : 0
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: Colors.barBg color: Colors.barBg
radius: Config.floating ? Config.rounding : 0 radius: Config.cfg.bar.floating ? Config.cfg.appearance.rounding : 0
RowLayout { RowLayout {
anchors.leftMargin: 4 anchors.leftMargin: 4
anchors.left: parent.left anchors.left: parent.left
@ -44,7 +44,6 @@ Variants {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
Mpris {} Mpris {}
Bat {} Bat {}
Tray {} Tray {}
WallPicker { WallPicker {
screenHeight: root.screen.height 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 double percent: UPower.displayDevice.percentage * 100
property bool hasBattery: UPower.displayDevice.isLaptopBattery property bool hasBattery: UPower.displayDevice.isLaptopBattery
property bool charging: UPower.displayDevice.state === UPowerDeviceState.Charging property bool charging: UPower.displayDevice.state === UPowerDeviceState.Charging
implicitHeight: Config.moduleHeight
implicitWidth: batLayout.implicitWidth + 16 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 <= 10) return charging ? "battery-empty-charging" : "battery-empty"
if(percent < 40) return charging ? "battery-level-30-charging" : "battery-level-30" 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 < 50) return charging ? "battery-level-40-charging" : "battery-level-40"
@ -32,16 +33,10 @@ BarComponent {
RowLayout { RowLayout {
id: batLayout id: batLayout
anchors.centerIn: root anchors.centerIn: root
IconImage { StyledIcon {
source: Quickshell.iconPath(root.batteryIcon(root.percent, root.charging) + "-symbolic") iconName: root.batteryIcon()
implicitSize: Config.iconSize
layer.enabled: true
layer.effect: MultiEffect {
colorization: 1.0
colorizationColor: Colors.text
brightness: 0.5
} }
}
StyledText { StyledText {
text: Math.floor(root.percent,root.charging) + "%" 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 { BarComponent {
id: root id: root
implicitHeight: Config.moduleHeight
implicitWidth: songLayout.implicitWidth + 16 implicitWidth: songLayout.implicitWidth + 16
property MprisPlayer spotify: { property MprisPlayer spotify: {
for (const player of Mpris.players.values) { for (const player of Mpris.players.values) {
@ -25,19 +24,12 @@ BarComponent {
RowLayout { RowLayout {
id: songLayout id: songLayout
anchors.centerIn: root anchors.centerIn: root
IconImage { StyledIcon {
source: Quickshell.iconPath("folder-music-symbolic") iconName: "folder-music-symbolic"
implicitSize: Config.iconSize
layer.enabled: true
layer.effect: MultiEffect {
colorization: 1.0
colorizationColor: Colors.text
brightness: 0.5
}
} }
StyledText { StyledText {
Layout.maximumWidth: 400 Layout.maximumWidth: 400
Layout.maximumHeight: Config.barHeight / 1.6 Layout.maximumHeight: Config.cfg.bar.barHeight / 1.6
text: root.spotify?.trackTitle + " - " + root.spotify?.trackArtists text: root.spotify?.trackTitle + " - " + root.spotify?.trackArtists
elide: Text.ElideRight 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 Quickshell
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Effects import qs.modules.applets
import qs
import qs.widgets import qs.widgets
import qs.settings import qs.settings
import qs.modules.Services import qs.modules.Services
@ -13,7 +9,6 @@ import qs.modules.Services
BarComponent { BarComponent {
id: root id: root
active: clickHandler.containsMouse active: clickHandler.containsMouse
implicitHeight: Config.moduleHeight
implicitWidth: pwLayout.implicitWidth + 16 implicitWidth: pwLayout.implicitWidth + 16
RowLayout { RowLayout {
id: pwLayout 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 { BarComponent {
id: root id: root
visible: iconRepeater.count != 0 visible: iconRepeater.count != 0
implicitHeight: Config.moduleHeight
implicitWidth: iconlayout.width + 16 implicitWidth: iconlayout.width + 16
RowLayout { 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 spacing: 0
Repeater { Repeater {
model: WindowManager.screenProjection(root.barScreen).windowsets model: WindowManager.screenProjection(root.barScreen).windowsets
delegate: Rectangle { delegate: BarComponent {
id: wsContainer id: wsContainer
required property var modelData required property var modelData
visible: modelData.shouldDisplay visible: modelData.shouldDisplay
implicitWidth: modelData.active ? 50 : 20 implicitWidth: modelData.active ? 50 : 20
implicitHeight: Config.moduleHeight - 4
color: modelData.active ? Colors.base0D : Colors.moduleBg color: modelData.active ? Colors.base0D : Colors.moduleBg
radius: Config.rounding
Behavior on implicitWidth { Behavior on implicitWidth {
PropertyAnimation { PropertyAnimation {
duration: 350 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 property alias timerStart: dismissTimer
implicitWidth: nScreen.width / 6 implicitWidth: nScreen.width / 6
implicitHeight: 100 implicitHeight: 100
radius: Config.rounding radius: Config.cfg.appearance.rounding
anchors.right: parent?.right anchors.right: parent?.right
color: Colors.barBg color: Colors.barBg
clip: true 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 top: true
right: 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 margins.right: 8
implicitHeight: notiList.contentHeight implicitHeight: notiList.contentHeight
implicitWidth: modelData.width / 6 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 { Image {
cache: false cache: false
anchors.fill: parent anchors.fill: parent
source: Config.wallpaper source: Qt.resolvedUrl(Config.cfg.wallpaper.wallpaper)
} }
} }
} }

View file

@ -2,33 +2,43 @@ pragma Singleton
import QtCore import QtCore
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Io
Singleton { Singleton {
id: root id: root
property string font: "Maple Mono" property alias cfg: cfg
property int fontSize: 12 function save() {
property int iconSize: 14 if (cfgView.loaded)
property int barHeight: 30 cfgView.writeAdapter();
property int rounding: 16 }
property url wallpaper: "file:///home/lucy/.walls/frierensuff.png" FileView {
property bool floating: false id: cfgView
property double opacity: 1.0 path: Qt.resolvedUrl(Quickshell.shellDir + "/settings/settings.json")
property string primaryMon: "eDP-1" watchChanges: true
property string wallDir: "file://" + Quickshell.env("HOME") + "/.walls" onFileChanged: {
property bool showCorners: true this.reload();
property real moduleHeight: barHeight - 8 }
Settings { onLoadFailed: error => {
location: Qt.resolvedUrl("file:///home/lucy/.config/quickshell/settings/settings.ini") if (error === FileViewError.FileNotFound)
property alias font: root.font writeAdapter();
property alias fontSize: root.fontSize }
property alias barHeight: root.barHeight adapter: JsonAdapter {
property alias rounding: root.rounding id: cfg
property alias wallpaper: root.wallpaper property JsonObject appearance: JsonObject {
property alias opacity: root.opacity property string font: "Iosevka"
property alias primaryMon: root.primaryMon property int fontSize: 14
property alias floating: root.floating property int iconSize: 16
property alias wallDir: root.wallDir property int rounding: 16
property alias showCorners: root.showCorners }
property alias iconSize: root.iconSize 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] [General]
barHeight=30 barHeight=30
floating=true floating=false
font=Iosevka font=Iosevka
fontSize=16 fontSize=14
iconSize=18 iconSize=16
opacity=1 opacity=1
primaryMon=eDP-1 primaryMon=eDP-1
rounding=16 rounding=16
showCorners=true showCorners=true
wallDir=file:///home/lucy/.walls wallDir=/home/lucy/.walls/
wallpaper=@Variant(\0\0\0\x11\0\0\0\x1f/home/lucy/.walls/lain_blue.png) 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 { Rectangle {
property bool active: false property bool active: false
color: active ? Colors.activeModuleBg : Colors.moduleBg color: active ? Colors.activeModuleBg : Colors.moduleBg
implicitHeight: Config.moduleHeight implicitHeight: Config.cfg.bar.height - 8
radius: Config.rounding radius: Config.cfg.appearance.rounding
} }

View file

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

View file

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