feat: Add music and sysinfo to top bar (togglable) - also a bunch of misc fixes

This commit is contained in:
ferreo 2025-07-14 20:40:43 +01:00
parent e1caf737fe
commit b4697235c0
29 changed files with 795 additions and 399 deletions

View file

@ -82,6 +82,22 @@ Scope {
anchors.left: parent.left anchors.left: parent.left
} }
Row {
id: leftWidgetsRow
anchors.verticalCenter: barBackground.verticalCenter
anchors.left: barBackground.left
anchors.leftMargin: 18
spacing: 12
SystemInfo {
anchors.verticalCenter: parent.verticalCenter
}
Media {
anchors.verticalCenter: parent.verticalCenter
}
}
ActiveWindow {} ActiveWindow {}
Workspace { Workspace {

View file

@ -153,13 +153,6 @@ PanelWindow {
anchors.margins: 32 anchors.margins: 32
spacing: 18 spacing: 18
Rectangle {
Layout.fillWidth: true
height: 1.5
color: Theme.outline
opacity: 0.10
}
// Search Bar // Search Bar
Rectangle { Rectangle {
id: searchBar id: searchBar
@ -372,7 +365,7 @@ PanelWindow {
size: 1.1 size: 1.1
fillColor: Theme.backgroundPrimary fillColor: Theme.backgroundPrimary
anchors.top: root.top anchors.top: root.top
offsetX: 397 offsetX: 396
offsetY: 0 offsetY: 0
} }
@ -382,7 +375,7 @@ PanelWindow {
size: 1.1 size: 1.1
fillColor: Theme.backgroundPrimary fillColor: Theme.backgroundPrimary
anchors.top: root.top anchors.top: root.top
offsetX: -397 offsetX: -396
offsetY: 0 offsetY: 0
} }
} }

125
Bar/Modules/Media.qml Normal file
View file

@ -0,0 +1,125 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import Qt5Compat.GraphicalEffects
import qs.Settings
import qs.Services
import qs.Components
Item {
id: mediaControl
width: visible ? mediaRow.width : 0
height: 32
visible: Settings.showMediaInBar && MusicManager.currentPlayer
RowLayout {
id: mediaRow
height: parent.height
spacing: 8
Item {
id: albumArtContainer
width: 24
height: 24
Layout.alignment: Qt.AlignVCenter
// Circular spectrum visualizer
CircularSpectrum {
id: spectrum
values: MusicManager.cavaValues
anchors.centerIn: parent
innerRadius: 10
outerRadius: 18
fillColor: Theme.accentPrimary
strokeColor: Theme.accentPrimary
strokeWidth: 0
z: 0
}
// Album art image
Rectangle {
id: albumArtwork
width: 20
height: 20
anchors.centerIn: parent
radius: 12 // circle
color: Qt.darker(Theme.surface, 1.1)
border.color: Qt.rgba(Theme.accentPrimary.r, Theme.accentPrimary.g, Theme.accentPrimary.b, 0.3)
border.width: 1
z: 1
Image {
id: albumArt
anchors.fill: parent
anchors.margins: 1
fillMode: Image.PreserveAspectCrop
smooth: true
cache: false
asynchronous: true
sourceSize.width: 24
sourceSize.height: 24
source: MusicManager.trackArtUrl
visible: source.toString() !== ""
// Rounded corners using layer
layer.enabled: true
layer.effect: OpacityMask {
cached: true
maskSource: Rectangle {
width: albumArt.width
height: albumArt.height
radius: albumArt.width / 2 // circle
visible: false
}
}
}
// Fallback icon
Text {
anchors.centerIn: parent
text: "music_note"
font.family: "Material Symbols Outlined"
font.pixelSize: 14
color: Qt.rgba(Theme.textPrimary.r, Theme.textPrimary.g, Theme.textPrimary.b, 0.4)
visible: !albumArt.visible
}
// Play/Pause overlay (only visible on hover)
Rectangle {
anchors.fill: parent
radius: parent.radius
color: Qt.rgba(0, 0, 0, 0.5)
visible: playButton.containsMouse
z: 2
Text {
anchors.centerIn: parent
text: MusicManager.isPlaying ? "pause" : "play_arrow"
font.family: "Material Symbols Outlined"
font.pixelSize: 14
color: "white"
}
}
MouseArea {
id: playButton
anchors.fill: parent
hoverEnabled: true
enabled: MusicManager.canPlay || MusicManager.canPause
onClicked: MusicManager.playPause()
}
}
}
// Track info
Text {
text: MusicManager.trackTitle + " - " + MusicManager.trackArtist
color: Theme.textPrimary
font.family: Theme.fontFamily
font.pixelSize: 12
elide: Text.ElideRight
Layout.maximumWidth: 300
Layout.alignment: Qt.AlignVCenter
}
}
}

View file

@ -0,0 +1,81 @@
import QtQuick
import Quickshell
import qs.Settings
import qs.Services
Row {
id: layout
spacing: 10
visible: Settings.showSystemInfoInBar
Row {
id: cpuUsageLayout
spacing: 6
Text {
id: cpuUsageIcon
font.family: "Material Symbols Outlined"
font.pixelSize: Theme.fontSizeBody
text: "speed"
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
color: Theme.accentPrimary
}
Text {
id: cpuUsageText
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
color: Theme.textPrimary
text: Sysinfo.cpuUsageStr
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter
}
}
// CPU Temperature Component
Row {
id: cpuTempLayout
spacing: 3
Text {
font.family: "Material Symbols Outlined"
font.pixelSize: Theme.fontSizeBody
text: "thermometer"
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
color: Theme.accentPrimary
}
Text {
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
color: Theme.textPrimary
text: Sysinfo.cpuTempStr
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter
}
}
// Memory Usage Component
Row {
id: memoryUsageLayout
spacing: 3
Text {
font.family: "Material Symbols Outlined"
font.pixelSize: Theme.fontSizeBody
text: "memory"
color: Theme.accentPrimary
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
}
Text {
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
color: Theme.textPrimary
text: Sysinfo.memoryUsageStr
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter
}
}
}

View file

@ -47,13 +47,13 @@ Item {
hoverEnabled: true hoverEnabled: true
acceptedButtons: Qt.NoButton // Accept wheel events only acceptedButtons: Qt.NoButton // Accept wheel events only
propagateComposedEvents: true propagateComposedEvents: true
onWheel: { onWheel:(wheel) => {
if (!shell) return; if (!shell) return;
let step = 5; let step = 5;
if (wheel.angleDelta.y > 0) { if (wheel.angleDelta.y > 0) {
shell.volume = Math.min(100, shell.volume + step); shell.updateVolume(Math.min(100, shell.volume + step));
} else if (wheel.angleDelta.y < 0) { } else if (wheel.angleDelta.y < 0) {
shell.volume = Math.max(0, shell.volume - step); shell.updateVolume(Math.max(0, shell.volume - step));
} }
} }
} }

View file

@ -2,11 +2,13 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Components import qs.Components
import qs.Services
Scope { Scope {
id: root id: root
property int count: 32 property int count: 32
property int noiseReduction: 60 property int noiseReduction: 60
property bool cavaRunning: false
property string channels: "mono" // or stereo property string channels: "mono" // or stereo
property string monoOption: "average" // or left or right property string monoOption: "average" // or left or right
property var config: ({ property var config: ({
@ -21,15 +23,11 @@ Scope {
}) })
property var values: Array(count).fill(0) // 0 <= value <= 1 property var values: Array(count).fill(0) // 0 <= value <= 1
onConfigChanged: {
process.running = false
process.running = true
}
Process { Process {
property int index: 0 property int index: 0
id: process id: process
stdinEnabled: true stdinEnabled: true
running: MusicManager.isPlaying
command: ["cava", "-p", "/dev/stdin"] command: ["cava", "-p", "/dev/stdin"]
onExited: { stdinEnabled = true; index = 0 } onExited: { stdinEnabled = true; index = 0 }
onStarted: { onStarted: {

View file

@ -12,7 +12,8 @@ Rectangle {
property color progressColor: Theme.accentPrimary property color progressColor: Theme.accentPrimary
property int strokeWidth: 6 property int strokeWidth: 6
property bool showText: true property bool showText: true
property string text: Math.round(progress * 100) + "%" property string units: "%"
property string text: Math.round(progress * 100) + units
property int textSize: 10 property int textSize: 10
property color textColor: Theme.textPrimary property color textColor: Theme.textPrimary

View file

@ -5,26 +5,20 @@ Item {
id: root id: root
property int innerRadius: 34 property int innerRadius: 34
property int outerRadius: 48 property int outerRadius: 48
property int barCount: 40
property color fillColor: "#fff" property color fillColor: "#fff"
property color strokeColor: "#fff" property color strokeColor: "#fff"
property int strokeWidth: 0 property int strokeWidth: 0
property var values: []
width: outerRadius * 2 width: outerRadius * 2
height: outerRadius * 2 height: outerRadius * 2
// Cava input
Cava {
id: cava
count: root.barCount
}
Repeater { Repeater {
model: root.barCount model: root.values.length
Rectangle { Rectangle {
property real value: cava.values[index] property real value: root.values[index]
property real angle: (index / root.barCount) * 360 property real angle: (index / root.values.length) * 360
width: Math.max(2, (root.innerRadius * 2 * Math.PI) / root.barCount - 4) width: Math.max(2, (root.innerRadius * 2 * Math.PI) / root.values.length - 4)
height: value * (root.outerRadius - root.innerRadius) height: value * (root.outerRadius - root.innerRadius)
radius: width / 2 radius: width / 2
color: root.fillColor color: root.fillColor
@ -32,8 +26,8 @@ Item {
border.width: root.strokeWidth border.width: root.strokeWidth
antialiasing: true antialiasing: true
x: root.width / 2 + (root.innerRadius) * Math.cos(Math.PI/2 + 2 * Math.PI * index / root.barCount) - width / 2 x: root.width / 2 + (root.innerRadius) * Math.cos(Math.PI/2 + 2 * Math.PI * index / root.values.length) - width / 2
y: root.height / 2 - (root.innerRadius) * Math.sin(Math.PI/2 + 2 * Math.PI * index / root.barCount) - height y: root.height / 2 - (root.innerRadius) * Math.sin(Math.PI/2 + 2 * Math.PI * index / root.values.length) - height
transform: Rotation { transform: Rotation {
origin.x: width / 2 origin.x: width / 2

BIN
Programs/zigstat Executable file

Binary file not shown.

View file

@ -160,6 +160,7 @@ You will need to install a few things to get everything working:
- `swww` to add fancy wallpaper animations (optional) - `swww` to add fancy wallpaper animations (optional)
- `wallust` to theme the setup based on wallpaper (optional) - `wallust` to theme the setup based on wallpaper (optional)
zigstat is bundled - source can be found [here](https://git.pika-os.com/wm-packages/pikabar/src/branch/main/src/zigstat).
--- ---
## Known issues ## Known issues

157
Services/MusicManager.qml Normal file
View file

@ -0,0 +1,157 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Services.Mpris
import qs.Settings
import qs.Components
Singleton {
id: manager
// Properties
property var currentPlayer: null
property real currentPosition: 0
property int selectedPlayerIndex: 0
property bool isPlaying: currentPlayer ? currentPlayer.isPlaying : false
property string trackTitle: currentPlayer ? (currentPlayer.trackTitle || "Unknown Track") : ""
property string trackArtist: currentPlayer ? (currentPlayer.trackArtist || "Unknown Artist") : ""
property string trackAlbum: currentPlayer ? (currentPlayer.trackAlbum || "Unknown Album") : ""
property string trackArtUrl: currentPlayer ? (currentPlayer.trackArtUrl || "") : ""
property real trackLength: currentPlayer ? currentPlayer.length : 0
property bool canPlay: currentPlayer ? currentPlayer.canPlay : false
property bool canPause: currentPlayer ? currentPlayer.canPause : false
property bool canGoNext: currentPlayer ? currentPlayer.canGoNext : false
property bool canGoPrevious: currentPlayer ? currentPlayer.canGoPrevious : false
property bool canSeek: currentPlayer ? currentPlayer.canSeek : false
property bool hasPlayer: getAvailablePlayers().length > 0
// Initialize
Item {
Component.onCompleted: {
updateCurrentPlayer()
}
}
// Returns available MPRIS players
function getAvailablePlayers() {
if (!Mpris.players || !Mpris.players.values) {
return []
}
let allPlayers = Mpris.players.values
let controllablePlayers = []
for (let i = 0; i < allPlayers.length; i++) {
let player = allPlayers[i]
if (player && player.canControl) {
controllablePlayers.push(player)
}
}
return controllablePlayers
}
// Returns active player or first available
function findActivePlayer() {
let availablePlayers = getAvailablePlayers()
if (availablePlayers.length === 0) {
return null
}
// Use selected player if valid, otherwise use first available
if (selectedPlayerIndex < availablePlayers.length) {
return availablePlayers[selectedPlayerIndex]
} else {
selectedPlayerIndex = 0
return availablePlayers[0]
}
}
// Updates currentPlayer and currentPosition
function updateCurrentPlayer() {
let newPlayer = findActivePlayer()
if (newPlayer !== currentPlayer) {
currentPlayer = newPlayer
currentPosition = currentPlayer ? currentPlayer.position : 0
}
}
// Player control functions
function playPause() {
if (currentPlayer) {
if (currentPlayer.isPlaying) {
currentPlayer.pause()
} else {
currentPlayer.play()
}
}
}
function play() {
if (currentPlayer && currentPlayer.canPlay) {
currentPlayer.play()
}
}
function pause() {
if (currentPlayer && currentPlayer.canPause) {
currentPlayer.pause()
}
}
function next() {
if (currentPlayer && currentPlayer.canGoNext) {
currentPlayer.next()
}
}
function previous() {
if (currentPlayer && currentPlayer.canGoPrevious) {
currentPlayer.previous()
}
}
function seek(position) {
if (currentPlayer && currentPlayer.canSeek) {
currentPlayer.position = position
currentPosition = position
}
}
function seekByRatio(ratio) {
if (currentPlayer && currentPlayer.canSeek && currentPlayer.length > 0) {
let seekPosition = ratio * currentPlayer.length
currentPlayer.position = seekPosition
currentPosition = seekPosition
}
}
// Updates progress bar every second
Timer {
id: positionTimer
interval: 1000
running: currentPlayer && currentPlayer.isPlaying && currentPlayer.length > 0
repeat: true
onTriggered: {
if (currentPlayer && currentPlayer.isPlaying) {
currentPosition = currentPlayer.position
}
}
}
// Reacts to player list changes
Connections {
target: Mpris.players
function onValuesChanged() {
updateCurrentPlayer()
}
}
Cava {
id: cava
count: 44
}
// Expose cava values
property alias cavaValues: cava.values
}

47
Services/Sysinfo.qml Normal file
View file

@ -0,0 +1,47 @@
pragma Singleton
import QtQuick
import Qt.labs.folderlistmodel
import Quickshell
import Quickshell.Io
import qs.Settings
Singleton {
id: manager
property string updateInterval: "2s"
property string cpuUsageStr: ""
property string cpuTempStr: ""
property string memoryUsageStr: ""
property string memoryUsagePerStr: ""
property real cpuUsage: 0
property real memoryUsage: 0
property real cpuTemp: 0
property real diskUsage: 0
property real memoryUsagePer: 0
property string diskUsageStr: ""
Process {
id: zigstatProcess
running: true
command: [Quickshell.shellRoot + "/Programs/zigstat", updateInterval]
stdout: SplitParser {
onRead: function (line) {
try {
const data = JSON.parse(line);
cpuUsage = +data.cpu;
cpuTemp = +data.cputemp;
memoryUsage = +data.mem;
memoryUsagePer = +data.memper;
diskUsage = +data.diskper;
cpuUsageStr = data.cpu + "%";
cpuTempStr = data.cputemp + "°C";
memoryUsageStr = data.mem + "G";
memoryUsagePerStr = data.memper + "%";
diskUsageStr = data.diskper + "%";
} catch (e) {
console.error("Failed to parse zigstat output:", e);
}
}
}
}
}

View file

@ -14,7 +14,7 @@ QtObject {
} }
property string weatherCity: "Dinslaken" property string weatherCity: "Dinslaken"
property string profileImage: "/home/" + Quickshell.env("USER") + "/.face" property string profileImage: "/home/" + Quickshell.env("USER") + "/.face"
property bool useFahrenheit property bool useFahrenheit: false
property string wallpaperFolder: "/usr/share/wallpapers" property string wallpaperFolder: "/usr/share/wallpapers"
property string currentWallpaper: "" property string currentWallpaper: ""
property string videoPath: "~/Videos/" property string videoPath: "~/Videos/"
@ -22,6 +22,8 @@ QtObject {
property bool useSWWW: false property bool useSWWW: false
property bool randomWallpaper: false property bool randomWallpaper: false
property bool useWallpaperTheme: false property bool useWallpaperTheme: false
property bool showSystemInfoInBar: true
property bool showMediaInBar: false
property int wallpaperInterval: 300 property int wallpaperInterval: 300
property string wallpaperResize: "crop" property string wallpaperResize: "crop"
property int transitionFps: 60 property int transitionFps: 60
@ -43,6 +45,10 @@ QtObject {
videoPath = settings.value("videoPath", videoPath) videoPath = settings.value("videoPath", videoPath)
let showActiveWindowIconFlag = settings.value("showActiveWindowIconFlag", "false") let showActiveWindowIconFlag = settings.value("showActiveWindowIconFlag", "false")
showActiveWindowIcon = showActiveWindowIconFlag === "true" showActiveWindowIcon = showActiveWindowIconFlag === "true"
let showSystemInfoInBarFlag = settings.value("showSystemInfoInBarFlag", "true")
showSystemInfoInBar = showSystemInfoInBarFlag === "true"
let showMediaInBarFlag = settings.value("showMediaInBarFlag", "true")
showMediaInBar = showMediaInBarFlag === "true"
let useSWWWFlag = settings.value("useSWWWFlag", "false") let useSWWWFlag = settings.value("useSWWWFlag", "false")
useSWWW = useSWWWFlag === "true" useSWWW = useSWWWFlag === "true"
let randomWallpaperFlag = settings.value("randomWallpaperFlag", "false") let randomWallpaperFlag = settings.value("randomWallpaperFlag", "false")
@ -54,6 +60,7 @@ QtObject {
transitionFps = settings.value("transitionFps", transitionFps) transitionFps = settings.value("transitionFps", transitionFps)
transitionType = settings.value("transitionType", transitionType) transitionType = settings.value("transitionType", transitionType)
transitionDuration = settings.value("transitionDuration", transitionDuration) transitionDuration = settings.value("transitionDuration", transitionDuration)
WallpaperManager.setCurrentWallpaper(currentWallpaper, true); WallpaperManager.setCurrentWallpaper(currentWallpaper, true);
} }
@ -65,6 +72,8 @@ QtObject {
settings.setValue("currentWallpaper", currentWallpaper) settings.setValue("currentWallpaper", currentWallpaper)
settings.setValue("videoPath", videoPath) settings.setValue("videoPath", videoPath)
settings.setValue("showActiveWindowIconFlag", showActiveWindowIcon ? "true" : "false") settings.setValue("showActiveWindowIconFlag", showActiveWindowIcon ? "true" : "false")
settings.setValue("showSystemInfoInBarFlag", showSystemInfoInBar ? "true" : "false")
settings.setValue("showMediaInBarFlag", showMediaInBar ? "true" : "false")
settings.setValue("useSWWWFlag", useSWWW ? "true" : "false") settings.setValue("useSWWWFlag", useSWWW ? "true" : "false")
settings.setValue("randomWallpaperFlag", randomWallpaper ? "true" : "false") settings.setValue("randomWallpaperFlag", randomWallpaper ? "true" : "false")
settings.setValue("useWallpaperThemeFlag", useWallpaperTheme ? "true" : "false") settings.setValue("useWallpaperThemeFlag", useWallpaperTheme ? "true" : "false")

View file

@ -23,6 +23,6 @@
"onAccent": "#0E0F10", "onAccent": "#0E0F10",
"outline": "#565758", "outline": "#565758",
"shadow": "#0E0F10B3", "shadow": "#0E0F10",
"overlay": "#0E0F10CC" "overlay": "#0E0F10"
} }

View file

@ -7,6 +7,10 @@ import Quickshell.Io
Singleton { Singleton {
id: root id: root
function applyOpacity(color, opacity) {
return color.replace("#", "#" + opacity);
}
// FileView to load theme data from JSON file // FileView to load theme data from JSON file
FileView { FileView {
id: themeFile id: themeFile
@ -50,8 +54,8 @@ Singleton {
property string outline: "#44485A" property string outline: "#44485A"
// Shadows & Overlays // Shadows & Overlays
property string shadow: "#000000B3" property string shadow: "#000000"
property string overlay: "#11121ACC" property string overlay: "#11121A"
} }
} }
@ -87,8 +91,8 @@ Singleton {
property color outline: themeData.outline property color outline: themeData.outline
// Shadows & Overlays // Shadows & Overlays
property color shadow: themeData.shadow property color shadow: applyOpacity(themeData.shadow, "B3")
property color overlay: themeData.overlay property color overlay: applyOpacity(themeData.overlay, "66")
// Font Properties // Font Properties
property string fontFamily: "Roboto" // Family for all text property string fontFamily: "Roboto" // Family for all text
@ -98,3 +102,4 @@ Singleton {
property int fontSizeSmall: 14 // Small text like clock, labels property int fontSizeSmall: 14 // Small text like clock, labels
property int fontSizeCaption: 12 // Captions and fine print property int fontSizeCaption: 12 // Captions and fine print
} }

View file

@ -14,8 +14,8 @@
"accentSecondary": "{{ color4 | lighten(0.2) }}", "accentSecondary": "{{ color4 | lighten(0.2) }}",
"accentTertiary": "{{ color4 | darken(0.2) }}", "accentTertiary": "{{ color4 | darken(0.2) }}",
"error": "{{ color5 | darken(0.1) }}", "error": "{{ color5 | lighten(0.1) }}",
"warning": "{{ color5 | lighten(0.1) }}", "warning": "{{ color5 | lighten(0.3) }}",
"highlight": "{{ color4 | lighten(0.4) }}", "highlight": "{{ color4 | lighten(0.4) }}",
"rippleEffect": "{{ color4 | lighten(0.1) }}", "rippleEffect": "{{ color4 | lighten(0.1) }}",
@ -23,6 +23,6 @@
"onAccent": "{{ background }}", "onAccent": "{{ background }}",
"outline": "{{ background | lighten(0.3) }}", "outline": "{{ background | lighten(0.3) }}",
"shadow": "{{ background }}B3", "shadow": "{{ background }}",
"overlay": "{{ background }}CC" "overlay": "{{ background }}"
} }

View file

@ -28,31 +28,36 @@ WlSessionLock {
// On component completed, fetch weather data // On component completed, fetch weather data
Component.onCompleted: { Component.onCompleted: {
fetchWeatherData() fetchWeatherData();
} }
// Weather fetching function // Weather fetching function
function fetchWeatherData() { function fetchWeatherData() {
WeatherHelper.fetchCityWeather(weatherCity, WeatherHelper.fetchCityWeather(weatherCity, function (result) {
function(result) { weatherData = result.weather;
weatherData = result.weather; weatherError = "";
weatherError = ""; }, function (err) {
}, weatherError = err;
function(err) { });
weatherError = err;
}
);
} }
function materialSymbolForCode(code) { function materialSymbolForCode(code) {
if (code === 0) return "sunny"; if (code === 0)
if (code === 1 || code === 2) return "partly_cloudy_day"; return "sunny";
if (code === 3) return "cloud"; if (code === 1 || code === 2)
if (code >= 45 && code <= 48) return "foggy"; return "partly_cloudy_day";
if (code >= 51 && code <= 67) return "rainy"; if (code === 3)
if (code >= 71 && code <= 77) return "weather_snowy"; return "cloud";
if (code >= 80 && code <= 82) return "rainy"; if (code >= 45 && code <= 48)
if (code >= 95 && code <= 99) return "thunderstorm"; return "foggy";
if (code >= 51 && code <= 67)
return "rainy";
if (code >= 71 && code <= 77)
return "weather_snowy";
if (code >= 80 && code <= 82)
return "rainy";
if (code >= 95 && code <= 99)
return "thunderstorm";
return "cloud"; return "cloud";
} }
@ -73,11 +78,11 @@ WlSessionLock {
lock.authenticating = true; lock.authenticating = true;
lock.errorMessage = ""; lock.errorMessage = "";
console.log("[LockScreen] About to create PAM context with userName:", Quickshell.env("USER")) console.log("[LockScreen] About to create PAM context with userName:", Quickshell.env("USER"));
var pam = Qt.createQmlObject('import Quickshell.Services.Pam; PamContext { config: "login"; user: "' + Quickshell.env("USER") + '" }', lock); var pam = Qt.createQmlObject('import Quickshell.Services.Pam; PamContext { config: "login"; user: "' + Quickshell.env("USER") + '" }', lock);
console.log("PamContext created", pam); console.log("PamContext created", pam);
pam.onCompleted.connect(function(result) { pam.onCompleted.connect(function (result) {
console.log("PAM completed with result:", result); console.log("PAM completed with result:", result);
lock.authenticating = false; lock.authenticating = false;
if (result === PamResult.Success) { if (result === PamResult.Success) {
@ -93,7 +98,7 @@ WlSessionLock {
pam.destroy(); pam.destroy();
}); });
pam.onError.connect(function(error) { pam.onError.connect(function (error) {
console.log("PAM error:", error); console.log("PAM error:", error);
lock.authenticating = false; lock.authenticating = false;
lock.errorMessage = pam.message || "Authentication error."; lock.errorMessage = pam.message || "Authentication error.";
@ -101,14 +106,14 @@ WlSessionLock {
pam.destroy(); pam.destroy();
}); });
pam.onPamMessage.connect(function() { pam.onPamMessage.connect(function () {
console.log("PAM message:", pam.message, "isError:", pam.messageIsError); console.log("PAM message:", pam.message, "isError:", pam.messageIsError);
if (pam.messageIsError) { if (pam.messageIsError) {
lock.errorMessage = pam.message; lock.errorMessage = pam.message;
} }
}); });
pam.onResponseRequiredChanged.connect(function() { pam.onResponseRequiredChanged.connect(function () {
console.log("PAM response required:", pam.responseRequired); console.log("PAM response required:", pam.responseRequired);
if (pam.responseRequired && lock.authenticating) { if (pam.responseRequired && lock.authenticating) {
console.log("Responding to PAM with password"); console.log("Responding to PAM with password");
@ -237,30 +242,36 @@ WlSessionLock {
} }
// Handle Enter key // Handle Enter key
Keys.onPressed: function(event) { Keys.onPressed: function (event) {
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
lock.unlockAttempt() lock.unlockAttempt();
} }
} }
Component.onCompleted: { Component.onCompleted: {
forceActiveFocus() forceActiveFocus();
} }
} }
} }
// Error message // Error message
Text { Rectangle {
id: errorMessageRect
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
text: lock.errorMessage width: parent.width * 0.8
color: Theme.error height: 44
font.family: Theme.fontFamily color: Theme.overlay
font.pixelSize: 14 radius: 22
visible: lock.errorMessage !== "" visible: lock.errorMessage !== ""
opacity: lock.errorMessage !== "" ? 1 : 0
Behavior on opacity { Text {
NumberAnimation { duration: 200 } anchors.centerIn: parent
text: lock.errorMessage
color: Theme.error
font.family: Theme.fontFamily
font.pixelSize: 14
opacity: 1
visible: lock.errorMessage !== ""
} }
} }
@ -292,13 +303,15 @@ WlSessionLock {
hoverEnabled: true hoverEnabled: true
onClicked: { onClicked: {
if (!lock.authenticating) { if (!lock.authenticating) {
lock.unlockAttempt() lock.unlockAttempt();
} }
} }
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: 200 } NumberAnimation {
duration: 200
}
} }
} }
} }
@ -344,7 +357,7 @@ WlSessionLock {
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
Text { Text {
text: weatherData && weatherData.current_weather ? (Settings.useFahrenheit ? `${Math.round(weatherData.current_weather.temperature * 9/5 + 32)}°F` : `${Math.round(weatherData.current_weather.temperature)}°C`) : (Settings.useFahrenheit ? "--°F" : "--°C") text: weatherData && weatherData.current_weather ? (Settings.useFahrenheit ? `${Math.round(weatherData.current_weather.temperature * 9 / 5 + 32)}°F` : `${Math.round(weatherData.current_weather.temperature)}°C`) : (Settings.useFahrenheit ? "--°F" : "--°C")
font.family: Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: 18 font.pixelSize: 18
color: Theme.textSecondary color: Theme.textSecondary
@ -369,8 +382,8 @@ WlSessionLock {
running: true running: true
repeat: true repeat: true
onTriggered: { onTriggered: {
timeText.text = Qt.formatDateTime(new Date(), "HH:mm") timeText.text = Qt.formatDateTime(new Date(), "HH:mm");
dateText.text = Qt.formatDateTime(new Date(), "dddd, MMMM d") dateText.text = Qt.formatDateTime(new Date(), "dddd, MMMM d");
} }
} }
@ -380,7 +393,7 @@ WlSessionLock {
running: true running: true
repeat: true repeat: true
onTriggered: { onTriggered: {
fetchWeatherData() fetchWeatherData();
} }
} }
@ -392,7 +405,9 @@ WlSessionLock {
spacing: 12 spacing: 12
// Shutdown // Shutdown
Rectangle { Rectangle {
width: 48; height: 48; radius: 24 width: 48
height: 48
radius: 24
color: shutdownArea.containsMouse ? Theme.error : "transparent" color: shutdownArea.containsMouse ? Theme.error : "transparent"
border.color: Theme.error border.color: Theme.error
border.width: 1 border.width: 1
@ -401,7 +416,7 @@ WlSessionLock {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onClicked: { onClicked: {
Qt.createQmlObject('import Quickshell.Io; Process { command: ["shutdown", "-h", "now"]; running: true }', lock) Qt.createQmlObject('import Quickshell.Io; Process { command: ["shutdown", "-h", "now"]; running: true }', lock);
} }
} }
Text { Text {
@ -414,7 +429,9 @@ WlSessionLock {
} }
// Reboot // Reboot
Rectangle { Rectangle {
width: 48; height: 48; radius: 24 width: 48
height: 48
radius: 24
color: rebootArea.containsMouse ? Theme.accentPrimary : "transparent" color: rebootArea.containsMouse ? Theme.accentPrimary : "transparent"
border.color: Theme.accentPrimary border.color: Theme.accentPrimary
border.width: 1 border.width: 1
@ -423,7 +440,7 @@ WlSessionLock {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onClicked: { onClicked: {
Qt.createQmlObject('import Quickshell.Io; Process { command: ["reboot"]; running: true }', lock) Qt.createQmlObject('import Quickshell.Io; Process { command: ["reboot"]; running: true }', lock);
} }
} }
Text { Text {
@ -436,7 +453,9 @@ WlSessionLock {
} }
// Logout // Logout
Rectangle { Rectangle {
width: 48; height: 48; radius: 24 width: 48
height: 48
radius: 24
color: logoutArea.containsMouse ? Theme.accentSecondary : "transparent" color: logoutArea.containsMouse ? Theme.accentSecondary : "transparent"
border.color: Theme.accentSecondary border.color: Theme.accentSecondary
border.width: 1 border.width: 1
@ -445,7 +464,7 @@ WlSessionLock {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
onClicked: { onClicked: {
Qt.createQmlObject('import Quickshell.Io; Process { command: ["loginctl", "terminate-user", "' + Quickshell.env("USER") + '"]; running: true }', lock) Qt.createQmlObject('import Quickshell.Io; Process { command: ["loginctl", "terminate-user", "' + Quickshell.env("USER") + '"]; running: true }', lock);
} }
} }
Text { Text {

View file

@ -10,7 +10,7 @@ import qs.Settings
Rectangle { Rectangle {
id: settingsModal id: settingsModal
anchors.centerIn: parent anchors.centerIn: parent
color: Settings.Theme.backgroundPrimary color: Theme.backgroundPrimary
radius: 20 radius: 20
visible: false visible: false
z: 100 z: 100
@ -36,15 +36,15 @@ Rectangle {
text: "settings" text: "settings"
font.family: "Material Symbols Outlined" font.family: "Material Symbols Outlined"
font.pixelSize: Theme.fontSizeHeader font.pixelSize: Theme.fontSizeHeader
color: Settings.Theme.accentPrimary color: Theme.accentPrimary
} }
Text { Text {
text: "Settings" text: "Settings"
font.family: Settings.Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeHeader font.pixelSize: Theme.fontSizeHeader
font.bold: true font.bold: true
color: Settings.Theme.textPrimary color: Theme.textPrimary
Layout.fillWidth: true Layout.fillWidth: true
} }
@ -52,8 +52,8 @@ Rectangle {
width: 36 width: 36
height: 36 height: 36
radius: 18 radius: 18
color: closeButtonArea.containsMouse ? Settings.Theme.accentPrimary : "transparent" color: closeButtonArea.containsMouse ? Theme.accentPrimary : "transparent"
border.color: Settings.Theme.accentPrimary border.color: Theme.accentPrimary
border.width: 1 border.width: 1
Text { Text {
@ -61,7 +61,7 @@ Rectangle {
text: "close" text: "close"
font.family: "Material Symbols Outlined" font.family: "Material Symbols Outlined"
font.pixelSize: Theme.fontSizeBody font.pixelSize: Theme.fontSizeBody
color: closeButtonArea.containsMouse ? Settings.Theme.onAccent : Settings.Theme.accentPrimary color: closeButtonArea.containsMouse ? Theme.onAccent : Theme.accentPrimary
} }
MouseArea { MouseArea {
@ -77,7 +77,7 @@ Rectangle {
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 180 Layout.preferredHeight: 180
color: Settings.Theme.surface color: Theme.surface
radius: 18 radius: 18
ColumnLayout { ColumnLayout {
@ -94,15 +94,15 @@ Rectangle {
text: "wb_sunny" text: "wb_sunny"
font.family: "Material Symbols Outlined" font.family: "Material Symbols Outlined"
font.pixelSize: Theme.fontSizeBody font.pixelSize: Theme.fontSizeBody
color: Settings.Theme.accentPrimary color: Theme.accentPrimary
} }
Text { Text {
text: "Weather Settings" text: "Weather Settings"
font.family: Settings.Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeBody font.pixelSize: Theme.fontSizeBody
font.bold: true font.bold: true
color: Settings.Theme.textPrimary color: Theme.textPrimary
Layout.fillWidth: true Layout.fillWidth: true
} }
} }
@ -114,18 +114,18 @@ Rectangle {
Text { Text {
text: "City" text: "City"
font.family: Settings.Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.bold: true font.bold: true
color: Settings.Theme.textPrimary color: Theme.textPrimary
} }
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 40 Layout.preferredHeight: 40
radius: 8 radius: 8
color: Settings.Theme.surfaceVariant color: Theme.surfaceVariant
border.color: cityInput.activeFocus ? Settings.Theme.accentPrimary : Settings.Theme.outline border.color: cityInput.activeFocus ? Theme.accentPrimary : Theme.outline
border.width: 1 border.width: 1
TextInput { TextInput {
@ -139,9 +139,9 @@ Rectangle {
anchors.topMargin: 6 anchors.topMargin: 6
anchors.bottomMargin: 6 anchors.bottomMargin: 6
text: tempWeatherCity text: tempWeatherCity
font.family: Settings.Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Settings.Theme.textPrimary color: Theme.textPrimary
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
clip: true clip: true
focus: true focus: true
@ -170,10 +170,10 @@ Rectangle {
Text { Text {
text: "Temperature Unit" text: "Temperature Unit"
font.family: Settings.Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.bold: true font.bold: true
color: Settings.Theme.textPrimary color: Theme.textPrimary
} }
Item { Item {
@ -186,8 +186,8 @@ Rectangle {
width: 52 width: 52
height: 32 height: 32
radius: 16 radius: 16
color: Settings.Theme.accentPrimary color: Theme.accentPrimary
border.color: Settings.Theme.accentPrimary border.color: Theme.accentPrimary
border.width: 2 border.width: 2
Rectangle { Rectangle {
@ -195,8 +195,8 @@ Rectangle {
width: 28 width: 28
height: 28 height: 28
radius: 14 radius: 14
color: Settings.Theme.surface color: Theme.surface
border.color: Settings.Theme.outline border.color: Theme.outline
border.width: 1 border.width: 1
y: 2 y: 2
x: tempUseFahrenheit ? customSwitch.width - width - 2 : 2 x: tempUseFahrenheit ? customSwitch.width - width - 2 : 2
@ -204,10 +204,10 @@ Rectangle {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: tempUseFahrenheit ? "°F" : "°C" text: tempUseFahrenheit ? "°F" : "°C"
font.family: Settings.Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeCaption font.pixelSize: Theme.fontSizeCaption
font.bold: true font.bold: true
color: Settings.Theme.textPrimary color: Theme.textPrimary
} }
Behavior on x { Behavior on x {
@ -230,7 +230,7 @@ Rectangle {
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 140 Layout.preferredHeight: 140
color: Settings.Theme.surface color: Theme.surface
radius: 18 radius: 18
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
@ -253,15 +253,15 @@ Rectangle {
text: "person" text: "person"
font.family: "Material Symbols Outlined" font.family: "Material Symbols Outlined"
font.pixelSize: Theme.fontSizeBody font.pixelSize: Theme.fontSizeBody
color: Settings.Theme.accentPrimary color: Theme.accentPrimary
} }
Text { Text {
text: "Profile Image" text: "Profile Image"
font.family: Settings.Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeBody font.pixelSize: Theme.fontSizeBody
font.bold: true font.bold: true
color: Settings.Theme.textPrimary color: Theme.textPrimary
Layout.fillWidth: true Layout.fillWidth: true
} }
} }
@ -275,8 +275,8 @@ Rectangle {
width: 36 width: 36
height: 36 height: 36
radius: 18 radius: 18
color: Settings.Theme.surfaceVariant color: Theme.surfaceVariant
border.color: profileImageInput.activeFocus ? Settings.Theme.accentPrimary : Settings.Theme.outline border.color: profileImageInput.activeFocus ? Theme.accentPrimary : Theme.outline
border.width: 1 border.width: 1
Image { Image {
@ -306,7 +306,7 @@ Rectangle {
text: "person" text: "person"
font.family: "Material Symbols Outlined" font.family: "Material Symbols Outlined"
font.pixelSize: Theme.fontSizeBody font.pixelSize: Theme.fontSizeBody
color: Settings.Theme.accentPrimary color: Theme.accentPrimary
visible: tempProfileImage === "" visible: tempProfileImage === ""
} }
} }
@ -316,8 +316,8 @@ Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 40 Layout.preferredHeight: 40
radius: 8 radius: 8
color: Settings.Theme.surfaceVariant color: Theme.surfaceVariant
border.color: profileImageInput.activeFocus ? Settings.Theme.accentPrimary : Settings.Theme.outline border.color: profileImageInput.activeFocus ? Theme.accentPrimary : Theme.outline
border.width: 1 border.width: 1
TextInput { TextInput {
@ -331,9 +331,9 @@ Rectangle {
anchors.topMargin: 6 anchors.topMargin: 6
anchors.bottomMargin: 6 anchors.bottomMargin: 6
text: tempProfileImage text: tempProfileImage
font.family: Settings.Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Settings.Theme.textPrimary color: Theme.textPrimary
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
clip: true clip: true
focus: true focus: true
@ -359,7 +359,7 @@ Rectangle {
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 100 Layout.preferredHeight: 100
color: Settings.Theme.surface color: Theme.surface
radius: 18 radius: 18
ColumnLayout { ColumnLayout {
@ -375,14 +375,14 @@ Rectangle {
text: "image" text: "image"
font.family: "Material Symbols Outlined" font.family: "Material Symbols Outlined"
font.pixelSize: Theme.fontSizeBody font.pixelSize: Theme.fontSizeBody
color: Settings.Theme.accentPrimary color: Theme.accentPrimary
} }
Text { Text {
text: "Wallpaper Folder" text: "Wallpaper Folder"
font.family: Settings.Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeBody font.pixelSize: Theme.fontSizeBody
font.bold: true font.bold: true
color: Settings.Theme.textPrimary color: Theme.textPrimary
Layout.fillWidth: true Layout.fillWidth: true
} }
} }
@ -392,8 +392,8 @@ Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 40 Layout.preferredHeight: 40
radius: 8 radius: 8
color: Settings.Theme.surfaceVariant color: Theme.surfaceVariant
border.color: wallpaperFolderInput.activeFocus ? Settings.Theme.accentPrimary : Settings.Theme.outline border.color: wallpaperFolderInput.activeFocus ? Theme.accentPrimary : Theme.outline
border.width: 1 border.width: 1
TextInput { TextInput {
@ -407,9 +407,9 @@ Rectangle {
anchors.topMargin: 6 anchors.topMargin: 6
anchors.bottomMargin: 6 anchors.bottomMargin: 6
text: tempWallpaperFolder text: tempWallpaperFolder
font.family: Settings.Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Settings.Theme.textPrimary color: Theme.textPrimary
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
clip: true clip: true
selectByMouse: true selectByMouse: true
@ -435,7 +435,7 @@ Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 44 Layout.preferredHeight: 44
radius: 12 radius: 12
color: applyButtonArea.containsMouse ? Settings.Theme.accentPrimary : Settings.Theme.accentPrimary color: applyButtonArea.containsMouse ? Theme.accentPrimary : Theme.accentPrimary
border.color: "transparent" border.color: "transparent"
border.width: 0 border.width: 0
opacity: 1.0 opacity: 1.0
@ -443,10 +443,10 @@ Rectangle {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "Apply Changes" text: "Apply Changes"
font.family: Settings.Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.bold: true font.bold: true
color: applyButtonArea.containsMouse ? Settings.Theme.onAccent : Settings.Theme.onAccent color: applyButtonArea.containsMouse ? Theme.onAccent : Theme.onAccent
} }
MouseArea { MouseArea {

View file

@ -7,7 +7,7 @@ import qs.Settings
Rectangle { Rectangle {
id: profileSettingsCard id: profileSettingsCard
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 200 Layout.preferredHeight: 300
color: Theme.surface color: Theme.surface
radius: 18 radius: 18
border.color: "transparent" border.color: "transparent"
@ -15,6 +15,10 @@ Rectangle {
Layout.bottomMargin: 16 Layout.bottomMargin: 16
property bool showActiveWindowIcon: false property bool showActiveWindowIcon: false
signal showAWIconChanged(bool showActiveWindowIcon) signal showAWIconChanged(bool showActiveWindowIcon)
property bool showSystemInfoInBar: true
signal showSystemInfoChanged(bool showSystemInfoInBar)
property bool showMediaInBar: false
signal showMediaChanged(bool showMediaInBar)
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
@ -125,7 +129,6 @@ Rectangle {
} }
} }
// Show Active Window Icon Setting // Show Active Window Icon Setting
RowLayout { RowLayout {
spacing: 8 spacing: 8
@ -148,8 +151,8 @@ Rectangle {
width: 52 width: 52
height: 32 height: 32
radius: 16 radius: 16
color: Theme.accentPrimary color: showActiveWindowIcon ? Theme.accentPrimary : Theme.surfaceVariant
border.color: Theme.accentPrimary border.color: showActiveWindowIcon ? Theme.accentPrimary : Theme.outline
border.width: 2 border.width: 2
Rectangle { Rectangle {
@ -177,6 +180,110 @@ Rectangle {
} }
} }
// Show System Info In Bar Setting
RowLayout {
spacing: 8
Layout.fillWidth: true
Text {
text: "Show System Info In Bar"
font.pixelSize: 13
font.bold: true
color: Theme.textPrimary
Layout.alignment: Qt.AlignVCenter
}
Item {
Layout.fillWidth: true
}
// Custom Material 3 Switch
Rectangle {
id: customSwitch2
width: 52
height: 32
radius: 16
color: showSystemInfoInBar ? Theme.accentPrimary : Theme.surfaceVariant
border.color: showSystemInfoInBar ? Theme.accentPrimary : Theme.outline
border.width: 2
Rectangle {
id: thumb2
width: 28
height: 28
radius: 14
color: Theme.surface
border.color: Theme.outline
border.width: 1
y: 2
x: showSystemInfoInBar ? customSwitch2.width - width - 2 : 2
Behavior on x {
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
}
}
MouseArea {
anchors.fill: parent
onClicked: {
showSystemInfoChanged(!showSystemInfoInBar)
}
}
}
}
// Show Media In Bar Setting
RowLayout {
spacing: 8
Layout.fillWidth: true
Text {
text: "Show Media In Bar"
font.pixelSize: 13
font.bold: true
color: Theme.textPrimary
Layout.alignment: Qt.AlignVCenter
}
Item {
Layout.fillWidth: true
}
// Custom Material 3 Switch
Rectangle {
id: customSwitch3
width: 52
height: 32
radius: 16
color: showMediaInBar ? Theme.accentPrimary : Theme.surfaceVariant
border.color: showMediaInBar ? Theme.accentPrimary : Theme.outline
border.width: 2
Rectangle {
id: thumb3
width: 28
height: 28
radius: 14
color: Theme.surface
border.color: Theme.outline
border.width: 1
y: 2
x: showMediaInBar ? customSwitch3.width - width - 2 : 2
Behavior on x {
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
}
}
MouseArea {
anchors.fill: parent
onClicked: {
showMediaChanged(!showMediaInBar)
}
}
}
}
// Video Path Input Row // Video Path Input Row
RowLayout { RowLayout {
spacing: 8 spacing: 8
@ -184,7 +291,8 @@ Rectangle {
Text { Text {
text: "Video Path" text: "Video Path"
font.pixelSize: 14 font.pixelSize: 13
font.bold: true
color: Theme.textPrimary color: Theme.textPrimary
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
} }

View file

@ -9,7 +9,7 @@ import qs.Services
PanelWindow { PanelWindow {
id: settingsModal id: settingsModal
implicitWidth: 480 implicitWidth: 480
implicitHeight: 720 implicitHeight: 800
visible: false visible: false
color: "transparent" color: "transparent"
anchors.top: true anchors.top: true
@ -35,6 +35,8 @@ PanelWindow {
property int tempTransitionFps: Settings.transitionFps property int tempTransitionFps: Settings.transitionFps
property string tempTransitionType: Settings.transitionType property string tempTransitionType: Settings.transitionType
property real tempTransitionDuration: Settings.transitionDuration property real tempTransitionDuration: Settings.transitionDuration
property bool tempShowSystemInfoInBar: Settings.showSystemInfoInBar
property bool tempShowMediaInBar: Settings.showMediaInBar
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
@ -141,6 +143,14 @@ PanelWindow {
onShowAWIconChanged: function (showActiveWindowIcon) { onShowAWIconChanged: function (showActiveWindowIcon) {
tempShowActiveWindowIcon = showActiveWindowIcon; tempShowActiveWindowIcon = showActiveWindowIcon;
} }
showSystemInfoInBar: tempShowSystemInfoInBar
onShowSystemInfoChanged: function (showSystemInfoInBar) {
tempShowSystemInfoInBar = showSystemInfoInBar;
}
showMediaInBar: tempShowMediaInBar
onShowMediaChanged: function (showMediaInBar) {
tempShowMediaInBar = showMediaInBar;
}
} }
} }
CollapsibleCategory { CollapsibleCategory {
@ -224,6 +234,8 @@ PanelWindow {
Settings.transitionFps = tempTransitionFps; Settings.transitionFps = tempTransitionFps;
Settings.transitionType = tempTransitionType; Settings.transitionType = tempTransitionType;
Settings.transitionDuration = tempTransitionDuration; Settings.transitionDuration = tempTransitionDuration;
Settings.showSystemInfoInBar = tempShowSystemInfoInBar;
Settings.showMediaInBar = tempShowMediaInBar;
Settings.saveSettings(); Settings.saveSettings();
if (typeof weather !== 'undefined' && weather) { if (typeof weather !== 'undefined' && weather) {
weather.fetchCityWeather(); weather.fetchCityWeather();

View file

@ -73,7 +73,7 @@ Item {
PanelWindow { PanelWindow {
id: bluetoothPanelModal id: bluetoothPanelModal
implicitWidth: 480 implicitWidth: 480
implicitHeight: 720 implicitHeight: 800
visible: false visible: false
color: "transparent" color: "transparent"
anchors.top: true anchors.top: true

View file

@ -2,90 +2,16 @@ import QtQuick 2.15
import QtQuick.Controls 2.15 import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import Qt5Compat.GraphicalEffects import Qt5Compat.GraphicalEffects
import Quickshell.Services.Mpris
import qs.Settings import qs.Settings
import qs.Components import qs.Components
import QtQuick import qs.Services
Rectangle { Rectangle {
id: musicCard id: musicCard
width: 360 width: 360
height: 200 height: 250
color: "transparent" color: "transparent"
property var currentPlayer: null
property real currentPosition: 0
property int selectedPlayerIndex: 0
// Returns available MPRIS players
function getAvailablePlayers() {
if (!Mpris.players || !Mpris.players.values) {
return []
}
let allPlayers = Mpris.players.values
let controllablePlayers = []
for (let i = 0; i < allPlayers.length; i++) {
let player = allPlayers[i]
if (player && player.canControl) {
controllablePlayers.push(player)
}
}
return controllablePlayers
}
// Returns active player or first available
function findActivePlayer() {
let availablePlayers = getAvailablePlayers()
if (availablePlayers.length === 0) {
return null
}
// Use selected player if valid, otherwise use first available
if (selectedPlayerIndex < availablePlayers.length) {
return availablePlayers[selectedPlayerIndex]
} else {
selectedPlayerIndex = 0
return availablePlayers[0]
}
}
// Updates currentPlayer and currentPosition
function updateCurrentPlayer() {
let newPlayer = findActivePlayer()
if (newPlayer !== currentPlayer) {
currentPlayer = newPlayer
currentPosition = currentPlayer ? currentPlayer.position : 0
}
}
// Updates progress bar every second
Timer {
id: positionTimer
interval: 1000
running: currentPlayer && currentPlayer.isPlaying && currentPlayer.length > 0
repeat: true
onTriggered: {
if (currentPlayer && currentPlayer.isPlaying) {
currentPosition = currentPlayer.position
}
}
}
// Reacts to player list changes
Connections {
target: Mpris.players
function onValuesChanged() {
updateCurrentPlayer()
}
}
Component.onCompleted: {
updateCurrentPlayer()
}
Rectangle { Rectangle {
id: card id: card
anchors.fill: parent anchors.fill: parent
@ -96,7 +22,7 @@ Rectangle {
Item { Item {
width: parent.width width: parent.width
height: parent.height height: parent.height
visible: !currentPlayer visible: !MusicManager.currentPlayer
ColumnLayout { ColumnLayout {
anchors.centerIn: parent anchors.centerIn: parent
@ -111,7 +37,7 @@ Rectangle {
} }
Text { Text {
text: getAvailablePlayers().length > 0 ? "No controllable player selected" : "No music player detected" text: MusicManager.hasPlayer ? "No controllable player selected" : "No music player detected"
color: Qt.rgba(Theme.textPrimary.r, Theme.textPrimary.g, Theme.textPrimary.b, 0.6) color: Qt.rgba(Theme.textPrimary.r, Theme.textPrimary.g, Theme.textPrimary.b, 0.6)
font.family: Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
@ -141,6 +67,7 @@ Rectangle {
// Spectrum visualizer // Spectrum visualizer
CircularSpectrum { CircularSpectrum {
id: spectrum id: spectrum
values: MusicManager.cavaValues
anchors.centerIn: parent anchors.centerIn: parent
innerRadius: 30 // just outside 60x60 album art innerRadius: 30 // just outside 60x60 album art
outerRadius: 48 // how far bars extend outerRadius: 48 // how far bars extend
@ -170,7 +97,7 @@ Rectangle {
asynchronous: true asynchronous: true
sourceSize.width: 60 sourceSize.width: 60
sourceSize.height: 60 sourceSize.height: 60
source: currentPlayer ? (currentPlayer.trackArtUrl || "") : "" source: MusicManager.trackArtUrl
visible: source.toString() !== "" visible: source.toString() !== ""
// Rounded corners using layer // Rounded corners using layer
@ -204,7 +131,7 @@ Rectangle {
spacing: 4 spacing: 4
Text { Text {
text: currentPlayer ? (currentPlayer.trackTitle || "Unknown Track") : "" text: MusicManager.trackTitle
color: Theme.textPrimary color: Theme.textPrimary
font.family: Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
@ -216,7 +143,7 @@ Rectangle {
} }
Text { Text {
text: currentPlayer ? (currentPlayer.trackArtist || "Unknown Artist") : "" text: MusicManager.trackArtist
color: Qt.rgba(Theme.textPrimary.r, Theme.textPrimary.g, Theme.textPrimary.b, 0.8) color: Qt.rgba(Theme.textPrimary.r, Theme.textPrimary.g, Theme.textPrimary.b, 0.8)
font.family: Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeCaption font.pixelSize: Theme.fontSizeCaption
@ -225,7 +152,7 @@ Rectangle {
} }
Text { Text {
text: currentPlayer ? (currentPlayer.trackAlbum || "Unknown Album") : "" text: MusicManager.trackAlbum
color: Qt.rgba(Theme.textPrimary.r, Theme.textPrimary.g, Theme.textPrimary.b, 0.6) color: Qt.rgba(Theme.textPrimary.r, Theme.textPrimary.g, Theme.textPrimary.b, 0.6)
font.family: Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeCaption font.pixelSize: Theme.fontSizeCaption
@ -244,8 +171,8 @@ Rectangle {
color: Qt.rgba(Theme.textPrimary.r, Theme.textPrimary.g, Theme.textPrimary.b, 0.15) color: Qt.rgba(Theme.textPrimary.r, Theme.textPrimary.g, Theme.textPrimary.b, 0.15)
Layout.fillWidth: true Layout.fillWidth: true
property real progressRatio: currentPlayer && currentPlayer.length > 0 ? property real progressRatio: MusicManager.trackLength > 0 ?
(currentPosition / currentPlayer.length) : 0 (MusicManager.currentPosition / MusicManager.trackLength) : 0
Rectangle { Rectangle {
id: progressFill id: progressFill
@ -272,7 +199,7 @@ Rectangle {
x: Math.max(0, Math.min(parent.width - width, progressFill.width - width/2)) x: Math.max(0, Math.min(parent.width - width, progressFill.width - width/2))
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: currentPlayer && currentPlayer.length > 0 visible: MusicManager.trackLength > 0
scale: progressMouseArea.containsMouse || progressMouseArea.pressed ? 1.2 : 1.0 scale: progressMouseArea.containsMouse || progressMouseArea.pressed ? 1.2 : 1.0
Behavior on scale { Behavior on scale {
@ -285,23 +212,17 @@ Rectangle {
id: progressMouseArea id: progressMouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
enabled: currentPlayer && currentPlayer.length > 0 && currentPlayer.canSeek enabled: MusicManager.trackLength > 0 && MusicManager.canSeek
onClicked: function(mouse) { onClicked: function(mouse) {
if (currentPlayer && currentPlayer.length > 0) { let ratio = mouse.x / width
let ratio = mouse.x / width MusicManager.seekByRatio(ratio)
let seekPosition = ratio * currentPlayer.length
currentPlayer.position = seekPosition
currentPosition = seekPosition
}
} }
onPositionChanged: function(mouse) { onPositionChanged: function(mouse) {
if (pressed && currentPlayer && currentPlayer.length > 0) { if (pressed) {
let ratio = Math.max(0, Math.min(1, mouse.x / width)) let ratio = Math.max(0, Math.min(1, mouse.x / width))
let seekPosition = ratio * currentPlayer.length MusicManager.seekByRatio(ratio)
currentPlayer.position = seekPosition
currentPosition = seekPosition
} }
} }
} }
@ -326,8 +247,8 @@ Rectangle {
id: previousButton id: previousButton
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
enabled: currentPlayer && currentPlayer.canGoPrevious enabled: MusicManager.canGoPrevious
onClicked: if (currentPlayer) currentPlayer.previous() onClicked: MusicManager.previous()
} }
Text { Text {
@ -352,21 +273,13 @@ Rectangle {
id: playButton id: playButton
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
enabled: currentPlayer && (currentPlayer.canPlay || currentPlayer.canPause) enabled: MusicManager.canPlay || MusicManager.canPause
onClicked: { onClicked: MusicManager.playPause()
if (currentPlayer) {
if (currentPlayer.isPlaying) {
currentPlayer.pause()
} else {
currentPlayer.play()
}
}
}
} }
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: currentPlayer && currentPlayer.isPlaying ? "pause" : "play_arrow" text: MusicManager.isPlaying ? "pause" : "play_arrow"
font.family: "Material Symbols Outlined" font.family: "Material Symbols Outlined"
font.pixelSize: Theme.fontSizeBody font.pixelSize: Theme.fontSizeBody
color: playButton.enabled ? Theme.accentPrimary : Qt.rgba(Theme.textPrimary.r, Theme.textPrimary.g, Theme.textPrimary.b, 0.3) color: playButton.enabled ? Theme.accentPrimary : Qt.rgba(Theme.textPrimary.r, Theme.textPrimary.g, Theme.textPrimary.b, 0.3)
@ -386,8 +299,8 @@ Rectangle {
id: nextButton id: nextButton
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
enabled: currentPlayer && currentPlayer.canGoNext enabled: MusicManager.canGoNext
onClicked: if (currentPlayer) currentPlayer.next() onClicked: MusicManager.next()
} }
Text { Text {
@ -401,10 +314,4 @@ Rectangle {
} }
} }
} }
// Audio Visualizer (Cava)
Cava {
id: cava
count: 64
}
} }

View file

@ -10,7 +10,7 @@ import qs.Components
PanelWindow { PanelWindow {
id: panelPopup id: panelPopup
implicitWidth: 500 implicitWidth: 500
implicitHeight: 750 implicitHeight: 800
visible: false visible: false
color: "transparent" color: "transparent"
screen: modelData screen: modelData
@ -30,7 +30,6 @@ PanelWindow {
slideAnim.from = width; slideAnim.from = width;
slideAnim.to = 0; slideAnim.to = 0;
slideAnim.running = true; slideAnim.running = true;
if (systemMonitor) systemMonitor.startMonitoring();
if (weather) weather.startWeatherFetch(); if (weather) weather.startWeatherFetch();
if (systemWidget) systemWidget.panelVisible = true; if (systemWidget) systemWidget.panelVisible = true;
if (quickAccessWidget) quickAccessWidget.panelVisible = true; if (quickAccessWidget) quickAccessWidget.panelVisible = true;
@ -56,7 +55,6 @@ PanelWindow {
if (panelPopup.slideOffset === panelPopup.width) { if (panelPopup.slideOffset === panelPopup.width) {
panelPopup.visible = false; panelPopup.visible = false;
// Stop monitoring and background tasks when hidden // Stop monitoring and background tasks when hidden
if (systemMonitor) systemMonitor.stopMonitoring();
if (weather) weather.stopWeatherFetch(); if (weather) weather.stopWeatherFetch();
if (systemWidget) systemWidget.panelVisible = false; if (systemWidget) systemWidget.panelVisible = false;
if (quickAccessWidget) quickAccessWidget.panelVisible = false; if (quickAccessWidget) quickAccessWidget.panelVisible = false;

View file

@ -4,7 +4,7 @@ import QtQuick.Controls
import Qt5Compat.GraphicalEffects import Qt5Compat.GraphicalEffects
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import "root:/Settings" as Settings import qs.Settings
Rectangle { Rectangle {
id: quickAccessWidget id: quickAccessWidget
@ -24,7 +24,7 @@ Rectangle {
Rectangle { Rectangle {
id: card id: card
anchors.fill: parent anchors.fill: parent
color: Settings.Theme.surface color: Theme.surface
radius: 18 radius: 18
RowLayout { RowLayout {
@ -38,8 +38,8 @@ Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 44 Layout.preferredHeight: 44
radius: 12 radius: 12
color: settingsButtonArea.containsMouse ? Settings.Theme.accentPrimary : "transparent" color: settingsButtonArea.containsMouse ? Theme.accentPrimary : "transparent"
border.color: Settings.Theme.accentPrimary border.color: Theme.accentPrimary
border.width: 1 border.width: 1
RowLayout { RowLayout {
@ -51,15 +51,15 @@ Rectangle {
text: "settings" text: "settings"
font.family: settingsButtonArea.containsMouse ? "Material Symbols Rounded" : "Material Symbols Outlined" font.family: settingsButtonArea.containsMouse ? "Material Symbols Rounded" : "Material Symbols Outlined"
font.pixelSize: 16 font.pixelSize: 16
color: settingsButtonArea.containsMouse ? Settings.Theme.onAccent : Settings.Theme.accentPrimary color: settingsButtonArea.containsMouse ? Theme.onAccent : Theme.accentPrimary
} }
Text { Text {
text: "Settings" text: "Settings"
font.family: Settings.Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: 14 font.pixelSize: 14
font.bold: true font.bold: true
color: settingsButtonArea.containsMouse ? Settings.Theme.onAccent : Settings.Theme.textPrimary color: settingsButtonArea.containsMouse ? Theme.onAccent : Theme.textPrimary
Layout.fillWidth: true Layout.fillWidth: true
} }
} }
@ -80,9 +80,9 @@ Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 44 Layout.preferredHeight: 44
radius: 12 radius: 12
color: isRecording ? Settings.Theme.accentPrimary : color: isRecording ? Theme.accentPrimary :
(recorderButtonArea.containsMouse ? Settings.Theme.accentPrimary : "transparent") (recorderButtonArea.containsMouse ? Theme.accentPrimary : "transparent")
border.color: Settings.Theme.accentPrimary border.color: Theme.accentPrimary
border.width: 1 border.width: 1
RowLayout { RowLayout {
@ -94,15 +94,15 @@ Rectangle {
text: isRecording ? "radio_button_checked" : "radio_button_unchecked" text: isRecording ? "radio_button_checked" : "radio_button_unchecked"
font.family: (isRecording || recorderButtonArea.containsMouse) ? "Material Symbols Rounded" : "Material Symbols Outlined" font.family: (isRecording || recorderButtonArea.containsMouse) ? "Material Symbols Rounded" : "Material Symbols Outlined"
font.pixelSize: 16 font.pixelSize: 16
color: isRecording || recorderButtonArea.containsMouse ? Settings.Theme.onAccent : Settings.Theme.accentPrimary color: isRecording || recorderButtonArea.containsMouse ? Theme.onAccent : Theme.accentPrimary
} }
Text { Text {
text: isRecording ? "End" : "Record" text: isRecording ? "End" : "Record"
font.family: Settings.Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: 14 font.pixelSize: 14
font.bold: true font.bold: true
color: isRecording || recorderButtonArea.containsMouse ? Settings.Theme.onAccent : Settings.Theme.textPrimary color: isRecording || recorderButtonArea.containsMouse ? Theme.onAccent : Theme.textPrimary
Layout.fillWidth: true Layout.fillWidth: true
} }
} }
@ -127,8 +127,8 @@ Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 44 Layout.preferredHeight: 44
radius: 12 radius: 12
color: wallpaperButtonArea.containsMouse ? Settings.Theme.accentPrimary : "transparent" color: wallpaperButtonArea.containsMouse ? Theme.accentPrimary : "transparent"
border.color: Settings.Theme.accentPrimary border.color: Theme.accentPrimary
border.width: 1 border.width: 1
RowLayout { RowLayout {
@ -140,15 +140,15 @@ Rectangle {
text: "image" text: "image"
font.family: "Material Symbols Outlined" font.family: "Material Symbols Outlined"
font.pixelSize: 16 font.pixelSize: 16
color: wallpaperButtonArea.containsMouse ? Settings.Theme.onAccent : Settings.Theme.accentPrimary color: wallpaperButtonArea.containsMouse ? Theme.onAccent : Theme.accentPrimary
} }
Text { Text {
text: "Wallpaper" text: "Wallpaper"
font.family: Settings.Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: 14 font.pixelSize: 14
font.bold: true font.bold: true
color: wallpaperButtonArea.containsMouse ? Settings.Theme.onAccent : Settings.Theme.textPrimary color: wallpaperButtonArea.containsMouse ? Theme.onAccent : Theme.textPrimary
Layout.fillWidth: true Layout.fillWidth: true
} }
} }

View file

@ -2,116 +2,22 @@ import QtQuick 2.15
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15 import QtQuick.Controls 2.15
import Quickshell.Io import Quickshell.Io
import "root:/Settings" as Settings import qs.Components
import "root:/Components" as Components import qs.Services
import qs.Settings
Rectangle { Rectangle {
id: systemMonitor id: systemMonitor
width: 70 width: 70
height: 200 height: 250
color: "transparent" color: "transparent"
property real cpuUsage: 0
property real memoryUsage: 0
property real diskUsage: 0
property bool isVisible: false property bool isVisible: false
Timer {
id: cpuTimer
interval: 2000
repeat: true
running: isVisible
onTriggered: cpuInfo.running = true
}
Timer {
id: memoryTimer
interval: 3000
repeat: true
running: isVisible
onTriggered: memoryInfo.running = true
}
Timer {
id: diskTimer
interval: 5000
repeat: true
running: isVisible
onTriggered: diskInfo.running = true
}
// Process for getting CPU usage
Process {
id: cpuInfo
command: ["sh", "-c", "top -bn1 | grep 'Cpu(s)' | awk '{print $2}' | awk -F'%' '{print $1}'"]
running: false
stdout: SplitParser {
onRead: data => {
let usage = parseFloat(data.trim())
if (!isNaN(usage)) {
systemMonitor.cpuUsage = usage
}
cpuInfo.running = false
}
}
}
// Process for getting memory usage
Process {
id: memoryInfo
command: ["sh", "-c", "free | grep Mem | awk '{print int($3/$2 * 100)}'"]
running: false
stdout: SplitParser {
onRead: data => {
let usage = parseFloat(data.trim())
if (!isNaN(usage)) {
systemMonitor.memoryUsage = usage
}
memoryInfo.running = false
}
}
}
// Process for getting disk usage
Process {
id: diskInfo
command: ["sh", "-c", "df / | tail -1 | awk '{print int($5)}'"]
running: false
stdout: SplitParser {
onRead: data => {
let usage = parseFloat(data.trim())
if (!isNaN(usage)) {
systemMonitor.diskUsage = usage
}
diskInfo.running = false
}
}
}
// Function to start monitoring
function startMonitoring() {
isVisible = true
// Trigger initial readings
cpuInfo.running = true
memoryInfo.running = true
diskInfo.running = true
}
// Function to stop monitoring
function stopMonitoring() {
isVisible = false
cpuInfo.running = false
memoryInfo.running = false
diskInfo.running = false
}
Rectangle { Rectangle {
id: card id: card
anchors.fill: parent anchors.fill: parent
color: Settings.Theme.surface color: Theme.surface
radius: 18 radius: 18
ColumnLayout { ColumnLayout {
@ -121,8 +27,8 @@ Rectangle {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
// CPU Usage // CPU Usage
Components.CircularProgressBar { CircularProgressBar {
progress: cpuUsage / 100 progress: Sysinfo.cpuUsage / 100
size: 50 size: 50
strokeWidth: 4 strokeWidth: 4
hasNotch: true hasNotch: true
@ -131,9 +37,21 @@ Rectangle {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
} }
// Cpu Temp
CircularProgressBar {
progress: Sysinfo.cpuTemp / 100
size: 50
strokeWidth: 4
hasNotch: true
units: "°C"
notchIcon: "thermometer"
notchIconSize: 14
Layout.alignment: Qt.AlignHCenter
}
// Memory Usage // Memory Usage
Components.CircularProgressBar { CircularProgressBar {
progress: memoryUsage / 100 progress: Sysinfo.memoryUsagePer / 100
size: 50 size: 50
strokeWidth: 4 strokeWidth: 4
hasNotch: true hasNotch: true
@ -143,8 +61,8 @@ Rectangle {
} }
// Disk Usage // Disk Usage
Components.CircularProgressBar { CircularProgressBar {
progress: diskUsage / 100 progress: Sysinfo.diskUsage / 100
size: 50 size: 50
strokeWidth: 4 strokeWidth: 4
hasNotch: true hasNotch: true

View file

@ -10,7 +10,7 @@ import qs.Services
PanelWindow { PanelWindow {
id: wallpaperPanelModal id: wallpaperPanelModal
implicitWidth: 480 implicitWidth: 480
implicitHeight: 720 implicitHeight: 800
visible: false visible: false
color: "transparent" color: "transparent"
anchors.top: true anchors.top: true

View file

@ -2,7 +2,7 @@ import QtQuick 2.15
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15 import QtQuick.Controls 2.15
import qs.Settings import qs.Settings
import "root:/Helpers/Weather.js" as WeatherHelper import "../../../Helpers/Weather.js" as WeatherHelper
Rectangle { Rectangle {
id: weatherRoot id: weatherRoot

View file

@ -335,7 +335,7 @@ Item {
PanelWindow { PanelWindow {
id: wifiPanelModal id: wifiPanelModal
implicitWidth: 480 implicitWidth: 480
implicitHeight: 720 implicitHeight: 800
visible: false visible: false
color: "transparent" color: "transparent"
anchors.top: true anchors.top: true

View file

@ -15,6 +15,13 @@ Scope {
property alias appLauncherPanel: appLauncherPanel property alias appLauncherPanel: appLauncherPanel
function updateVolume(vol) {
volume = vol;
if (defaultAudioSink && defaultAudioSink.audio) {
defaultAudioSink.audio.volume = vol / 100;
}
}
Component.onCompleted: { Component.onCompleted: {
Quickshell.shell = root; Quickshell.shell = root;
} }
@ -48,7 +55,7 @@ Scope {
} }
property var defaultAudioSink: Pipewire.defaultAudioSink property var defaultAudioSink: Pipewire.defaultAudioSink
property int volume: defaultAudioSink && defaultAudioSink.audio ? Math.round(defaultAudioSink.audio.volume * 100) : 0 property int volume: defaultAudioSink && defaultAudioSink.audio && defaultAudioSink.audio.volume ? Math.round(defaultAudioSink.audio.volume * 100) : 0
PwObjectTracker { PwObjectTracker {
objects: [Pipewire.defaultAudioSink] objects: [Pipewire.defaultAudioSink]