test new systray #50
@@ -66,8 +66,8 @@ JsonObject {
|
|||||||
}
|
}
|
||||||
component Padding: JsonObject {
|
component Padding: JsonObject {
|
||||||
property int large: 15 * scale
|
property int large: 15 * scale
|
||||||
property int larger: 12 * scale
|
property int larger: 13 * scale
|
||||||
property int normal: 10 * scale
|
property int normal: 9 * scale
|
||||||
property real scale: 1
|
property real scale: 1
|
||||||
property int small: 5 * scale
|
property int small: 5 * scale
|
||||||
property int smaller: 7 * scale
|
property int smaller: 7 * scale
|
||||||
@@ -75,18 +75,18 @@ JsonObject {
|
|||||||
}
|
}
|
||||||
component Rounding: JsonObject {
|
component Rounding: JsonObject {
|
||||||
property int full: 1000 * scale
|
property int full: 1000 * scale
|
||||||
property int large: 25 * scale
|
property int large: 24 * scale
|
||||||
property int normal: 17 * scale
|
property int normal: 18 * scale
|
||||||
property real scale: 1
|
property real scale: 1
|
||||||
property int small: 12 * scale
|
property int small: 12 * scale
|
||||||
property int smallest: 8 * scale
|
property int smallest: 8 * scale
|
||||||
}
|
}
|
||||||
component Spacing: JsonObject {
|
component Spacing: JsonObject {
|
||||||
property int large: 20 * scale
|
property int large: 20 * scale
|
||||||
property int larger: 15 * scale
|
property int larger: 16 * scale
|
||||||
property int normal: 12 * scale
|
property int normal: 12 * scale
|
||||||
property real scale: 1
|
property real scale: 1
|
||||||
property int small: 7 * scale
|
property int small: 8 * scale
|
||||||
property int smaller: 10 * scale
|
property int smaller: 10 * scale
|
||||||
}
|
}
|
||||||
component Transparency: JsonObject {
|
component Transparency: JsonObject {
|
||||||
|
|||||||
+1
-1
@@ -270,6 +270,7 @@ Singleton {
|
|||||||
function serializeServices(): var {
|
function serializeServices(): var {
|
||||||
return {
|
return {
|
||||||
weatherLocation: services.weatherLocation,
|
weatherLocation: services.weatherLocation,
|
||||||
|
updates: services.updates,
|
||||||
useFahrenheit: services.useFahrenheit,
|
useFahrenheit: services.useFahrenheit,
|
||||||
ddcutilService: services.ddcutilService,
|
ddcutilService: services.ddcutilService,
|
||||||
useTwelveHourClock: services.useTwelveHourClock,
|
useTwelveHourClock: services.useTwelveHourClock,
|
||||||
@@ -322,7 +323,6 @@ Singleton {
|
|||||||
|
|
||||||
ElapsedTimer {
|
ElapsedTimer {
|
||||||
id: timer
|
id: timer
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
|
|||||||
+29
-61
@@ -78,12 +78,29 @@ Singleton {
|
|||||||
return Qt.hsla(c.hslHue, c.hslSaturation, 0.1, 1);
|
return Qt.hsla(c.hslHue, c.hslSaturation, 0.1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reloadHyprRules(): void {
|
||||||
|
const barStr = "keyword layerrule %1 %2, match:namespace ZShell-Bar";
|
||||||
|
const authStr = "keyword layerrule %1 %2, match:namespace ZShell-Auth";
|
||||||
|
Hypr.extras.batchMessage([barStr.arg("blur").arg(transparency.enabled ? 1 : 0), barStr.arg("ignore_alpha").arg(transparency.base - 0.03)]);
|
||||||
|
Hypr.extras.batchMessage([authStr.arg("blur").arg(transparency.enabled ? 1 : 0), authStr.arg("ignore_alpha").arg(transparency.base - 0.03)]);
|
||||||
|
}
|
||||||
|
|
||||||
function setMode(mode: string): void {
|
function setMode(mode: string): void {
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]);
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]);
|
||||||
Config.general.color.mode = mode;
|
Config.general.color.mode = mode;
|
||||||
Config.save();
|
Config.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: debounceTimer.triggered()
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onConfigReloaded(): void {
|
||||||
|
root.reloadHyprRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
target: Hypr
|
||||||
|
}
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
path: `${Paths.state}/scheme.json`
|
path: `${Paths.state}/scheme.json`
|
||||||
watchChanges: true
|
watchChanges: true
|
||||||
@@ -92,72 +109,20 @@ Singleton {
|
|||||||
onLoaded: root.load(text(), false)
|
onLoaded: root.load(text(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: debounceTimer
|
||||||
|
|
||||||
|
interval: 300
|
||||||
|
|
||||||
|
onTriggered: root.reloadHyprRules()
|
||||||
|
}
|
||||||
|
|
||||||
ImageAnalyser {
|
ImageAnalyser {
|
||||||
id: analyser
|
id: analyser
|
||||||
|
|
||||||
source: WallpaperPath.currentWallpaperPath
|
source: WallpaperPath.currentWallpaperPath
|
||||||
}
|
}
|
||||||
|
|
||||||
component M3MaccchiatoPalette: QtObject {
|
|
||||||
property color m3background: "#131317"
|
|
||||||
property color m3error: "#ffb4ab"
|
|
||||||
property color m3errorContainer: "#93000a"
|
|
||||||
property color m3inverseOnSurface: "#303034"
|
|
||||||
property color m3inversePrimary: "#525b92"
|
|
||||||
property color m3inverseSurface: "#e4e1e7"
|
|
||||||
property color m3neutral_paletteKeyColor: "#77767b"
|
|
||||||
property color m3neutral_variant_paletteKeyColor: "#767680"
|
|
||||||
property color m3onBackground: "#e4e1e7"
|
|
||||||
property color m3onError: "#690005"
|
|
||||||
property color m3onErrorContainer: "#ffdad6"
|
|
||||||
property color m3onPrimary: "#232c60"
|
|
||||||
property color m3onPrimaryContainer: "#ffffff"
|
|
||||||
property color m3onPrimaryFixed: "#0b154b"
|
|
||||||
property color m3onPrimaryFixedVariant: "#3a4378"
|
|
||||||
property color m3onSecondary: "#2c2f44"
|
|
||||||
property color m3onSecondaryContainer: "#b1b3ce"
|
|
||||||
property color m3onSecondaryFixed: "#171a2e"
|
|
||||||
property color m3onSecondaryFixedVariant: "#42455c"
|
|
||||||
property color m3onSuccess: "#213528"
|
|
||||||
property color m3onSuccessContainer: "#D1E9D6"
|
|
||||||
property color m3onSurface: "#e4e1e7"
|
|
||||||
property color m3onSurfaceVariant: "#c6c5d1"
|
|
||||||
property color m3onTertiary: "#4c1f48"
|
|
||||||
property color m3onTertiaryContainer: "#000000"
|
|
||||||
property color m3onTertiaryFixed: "#340831"
|
|
||||||
property color m3onTertiaryFixedVariant: "#66365f"
|
|
||||||
property color m3outline: "#90909a"
|
|
||||||
property color m3outlineVariant: "#46464f"
|
|
||||||
property color m3primary: "#bac3ff"
|
|
||||||
property color m3primaryContainer: "#6a73ac"
|
|
||||||
property color m3primaryFixed: "#dee0ff"
|
|
||||||
property color m3primaryFixedDim: "#bac3ff"
|
|
||||||
property color m3primary_paletteKeyColor: "#6a73ac"
|
|
||||||
property color m3scrim: "#000000"
|
|
||||||
property color m3secondary: "#c3c5e0"
|
|
||||||
property color m3secondaryContainer: "#42455c"
|
|
||||||
property color m3secondaryFixed: "#dfe1fd"
|
|
||||||
property color m3secondaryFixedDim: "#c3c5e0"
|
|
||||||
property color m3secondary_paletteKeyColor: "#72758e"
|
|
||||||
property color m3shadow: "#000000"
|
|
||||||
property color m3success: "#B5CCBA"
|
|
||||||
property color m3successContainer: "#374B3E"
|
|
||||||
property color m3surface: "#131317"
|
|
||||||
property color m3surfaceBright: "#39393d"
|
|
||||||
property color m3surfaceContainer: "#1f1f23"
|
|
||||||
property color m3surfaceContainerHigh: "#2a2a2e"
|
|
||||||
property color m3surfaceContainerHighest: "#353438"
|
|
||||||
property color m3surfaceContainerLow: "#1b1b1f"
|
|
||||||
property color m3surfaceContainerLowest: "#0e0e12"
|
|
||||||
property color m3surfaceDim: "#131317"
|
|
||||||
property color m3surfaceTint: "#bac3ff"
|
|
||||||
property color m3surfaceVariant: "#46464f"
|
|
||||||
property color m3tertiary: "#f1b3e5"
|
|
||||||
property color m3tertiaryContainer: "#b77ead"
|
|
||||||
property color m3tertiaryFixed: "#ffd7f4"
|
|
||||||
property color m3tertiaryFixedDim: "#f1b3e5"
|
|
||||||
property color m3tertiary_paletteKeyColor: "#9b6592"
|
|
||||||
}
|
|
||||||
component M3Palette: QtObject {
|
component M3Palette: QtObject {
|
||||||
property color m3background: "#191114"
|
property color m3background: "#191114"
|
||||||
property color m3error: "#ffb4ab"
|
property color m3error: "#ffb4ab"
|
||||||
@@ -279,8 +244,11 @@ Singleton {
|
|||||||
readonly property color m3tertiary_paletteKeyColor: root.layer(root.palette.m3tertiary_paletteKeyColor)
|
readonly property color m3tertiary_paletteKeyColor: root.layer(root.palette.m3tertiary_paletteKeyColor)
|
||||||
}
|
}
|
||||||
component Transparency: QtObject {
|
component Transparency: QtObject {
|
||||||
readonly property real base: Appearance.transparency.base - (root.light ? 0.1 : 0)
|
readonly property real base: Math.max(0, Math.min(1, Appearance.transparency.base - (root.light ? 0.1 : 0)))
|
||||||
readonly property bool enabled: Appearance.transparency.enabled
|
readonly property bool enabled: Appearance.transparency.enabled
|
||||||
readonly property real layers: Appearance.transparency.layers
|
readonly property real layers: Appearance.transparency.layers
|
||||||
|
|
||||||
|
onBaseChanged: debounceTimer.restart()
|
||||||
|
onEnabledChanged: debounceTimer.restart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ JsonObject {
|
|||||||
"to": "YT Music"
|
"to": "YT Music"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
property bool updates: true
|
||||||
property bool useFahrenheit: false
|
property bool useFahrenheit: false
|
||||||
property bool useTwelveHourClock: Qt.locale().timeFormat(Locale.ShortFormat).toLowerCase().includes("a")
|
property bool useTwelveHourClock: Qt.locale().timeFormat(Locale.ShortFormat).toLowerCase().includes("a")
|
||||||
property int visualizerBars: 30
|
property int visualizerBars: 30
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ ColumnLayout {
|
|||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
clip: true
|
clip: true
|
||||||
|
currentIndex: root.greeter.selectedUser ? root.greeter.users.indexOf(root.greeter.selectedUser) : -1
|
||||||
highlightFollowsCurrentItem: false
|
highlightFollowsCurrentItem: false
|
||||||
model: root.greeter.users
|
model: root.greeter.users
|
||||||
spacing: Appearance.spacing.small
|
spacing: Appearance.spacing.small
|
||||||
@@ -84,7 +85,7 @@ ColumnLayout {
|
|||||||
|
|
||||||
StateLayer {
|
StateLayer {
|
||||||
function onClicked(): void {
|
function onClicked(): void {
|
||||||
users.currentIndex = index;
|
root.greeter.selectUser(modelData.username);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
import glob
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import pwd
|
import pwd
|
||||||
@@ -17,21 +18,59 @@ INVALID_SHELLS = {
|
|||||||
|
|
||||||
# Minimum UID for regular users (typically 1000 on most Linux distributions)
|
# Minimum UID for regular users (typically 1000 on most Linux distributions)
|
||||||
MIN_UID = 1000
|
MIN_UID = 1000
|
||||||
|
GREETER_IMAGES_DIR = "/etc/zshell-greeter/images"
|
||||||
|
|
||||||
|
|
||||||
def get_face_path(home: str, username: str) -> str:
|
def get_face_path(home: str, username: str) -> str:
|
||||||
"""Get the path to the user's face/avatar image if it exists."""
|
"""Get the path to the user's face/avatar image if it exists."""
|
||||||
|
greeter_candidates = [
|
||||||
|
os.path.join(GREETER_IMAGES_DIR, f"{username}.face"),
|
||||||
|
os.path.join(GREETER_IMAGES_DIR, f"{username}.face.icon"),
|
||||||
|
]
|
||||||
|
|
||||||
|
for path in greeter_candidates:
|
||||||
|
if os.path.isfile(path):
|
||||||
|
return path
|
||||||
|
|
||||||
|
for path in sorted(glob.glob(os.path.join(GREETER_IMAGES_DIR, f"{username}.*"))):
|
||||||
|
if os.path.isfile(path):
|
||||||
|
return path
|
||||||
|
|
||||||
|
direct_path = os.path.join(GREETER_IMAGES_DIR, username)
|
||||||
|
if os.path.isfile(direct_path):
|
||||||
|
return direct_path
|
||||||
|
|
||||||
|
accountsservice_user = f"/var/lib/AccountsService/users/{username}"
|
||||||
|
if os.path.isfile(accountsservice_user):
|
||||||
|
try:
|
||||||
|
with open(accountsservice_user, "r", encoding="utf-8") as handle:
|
||||||
|
for line in handle:
|
||||||
|
if line.startswith("Icon="):
|
||||||
|
icon_path = line.split("=", 1)[1].strip()
|
||||||
|
if icon_path:
|
||||||
|
if not os.path.isabs(icon_path):
|
||||||
|
icon_path = os.path.join("/var/lib/AccountsService/icons", icon_path)
|
||||||
|
if os.path.isfile(icon_path):
|
||||||
|
return icon_path
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
# Check common locations for user avatars
|
# Check common locations for user avatars
|
||||||
candidates = [
|
candidates = [
|
||||||
os.path.join(home, ".face"),
|
os.path.join(home, ".face"),
|
||||||
os.path.join(home, ".face.icon"),
|
os.path.join(home, ".face.icon"),
|
||||||
f"/var/lib/AccountsService/icons/{username}",
|
f"/var/lib/AccountsService/icons/{username}",
|
||||||
|
f"/usr/share/pixmaps/faces/{username}",
|
||||||
]
|
]
|
||||||
|
|
||||||
for path in candidates:
|
for path in candidates:
|
||||||
if os.path.isfile(path):
|
if os.path.isfile(path):
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
for path in sorted(glob.glob(f"/var/lib/AccountsService/icons/{username}.*")):
|
||||||
|
if os.path.isfile(path):
|
||||||
|
return path
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -5,6 +5,7 @@ import QtQuick
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Paths
|
import qs.Paths
|
||||||
|
import qs.Config
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
@@ -44,12 +45,13 @@ Singleton {
|
|||||||
Timer {
|
Timer {
|
||||||
interval: 1
|
interval: 1
|
||||||
repeat: true
|
repeat: true
|
||||||
running: true
|
running: Config.services.updates
|
||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (!root.loaded || !root.commandReady)
|
if (!root.loaded || !root.commandReady)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (Config.services.updates)
|
||||||
updatesProc.running = true;
|
updatesProc.running = true;
|
||||||
interval = 5000;
|
interval = 5000;
|
||||||
}
|
}
|
||||||
@@ -66,7 +68,7 @@ Singleton {
|
|||||||
Process {
|
Process {
|
||||||
id: cmdDetect
|
id: cmdDetect
|
||||||
|
|
||||||
command: ["sh", "-c", "command -v yay || command -v paru"]
|
command: ["sh", "-c", "command -v checkupdates || command -v yay || command -v paru"]
|
||||||
running: true
|
running: true
|
||||||
|
|
||||||
stdout: StdioCollector {
|
stdout: StdioCollector {
|
||||||
@@ -80,7 +82,11 @@ Singleton {
|
|||||||
helper = "pacman";
|
helper = "pacman";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (helper === "checkupdates") {
|
||||||
|
updatesProc.command = [helper];
|
||||||
|
} else {
|
||||||
updatesProc.command = [helper, "-Qu"];
|
updatesProc.command = [helper, "-Qu"];
|
||||||
|
}
|
||||||
root.commandReady = true;
|
root.commandReady = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,96 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import Quickshell.Io
|
|
||||||
import Quickshell.Services.Pipewire
|
|
||||||
import qs.Daemons
|
|
||||||
import qs.Modules
|
|
||||||
import qs.Config
|
|
||||||
import qs.Components
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property color barColor: DynamicColors.palette.m3primary
|
|
||||||
property color textColor: DynamicColors.palette.m3onSurface
|
|
||||||
|
|
||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
|
||||||
implicitHeight: Config.barConfig.height + Appearance.padding.smallest * 2
|
|
||||||
implicitWidth: 150
|
|
||||||
radius: Appearance.rounding.full
|
|
||||||
|
|
||||||
Behavior on implicitWidth {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: 300
|
|
||||||
easing.type: Easing.OutCubic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: console.log(root.height, root.implicitHeight)
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: layout
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: Appearance.padding.small
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
width: root.implicitWidth - Appearance.padding.small * 3
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
|
||||||
animate: true
|
|
||||||
color: Audio.muted ? DynamicColors.palette.m3error : root.textColor
|
|
||||||
font.pointSize: Appearance.font.size.larger
|
|
||||||
text: Audio.muted ? "volume_off" : "volume_up"
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2)
|
|
||||||
implicitHeight: 4
|
|
||||||
radius: 20
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
id: sinkVolumeBar
|
|
||||||
|
|
||||||
color: Audio.muted ? DynamicColors.palette.m3error : root.barColor
|
|
||||||
implicitWidth: parent.width * (Audio.volume ?? 0)
|
|
||||||
radius: parent.radius
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
bottom: parent.bottom
|
|
||||||
left: parent.left
|
|
||||||
top: parent.top
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
|
||||||
animate: true
|
|
||||||
color: (Audio.sourceMuted ?? false) ? DynamicColors.palette.m3error : root.textColor
|
|
||||||
font.pointSize: Appearance.font.size.larger
|
|
||||||
text: Audio.sourceMuted ? "mic_off" : "mic"
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHigh, 2)
|
|
||||||
implicitHeight: 4
|
|
||||||
radius: 20
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
id: sourceVolumeBar
|
|
||||||
|
|
||||||
color: (Audio.sourceMuted ?? false) ? DynamicColors.palette.m3error : root.barColor
|
|
||||||
implicitWidth: parent.width * (Audio.sourceVolume ?? 0)
|
|
||||||
radius: parent.radius
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
bottom: parent.bottom
|
|
||||||
left: parent.left
|
|
||||||
top: parent.top
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+20
-19
@@ -7,7 +7,8 @@ import qs.Components
|
|||||||
import qs.Modules
|
import qs.Modules
|
||||||
import qs.Config
|
import qs.Config
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
import qs.Modules.UPower
|
import qs.Modules.SysTray
|
||||||
|
import qs.Modules.SysTray.Widgets
|
||||||
import qs.Modules.Network
|
import qs.Modules.Network
|
||||||
import qs.Modules.Updates
|
import qs.Modules.Updates
|
||||||
|
|
||||||
@@ -31,6 +32,24 @@ RowLayout {
|
|||||||
if (visibilities.sidebar || visibilities.dashboard || visibilities.resources || visibilities.settings)
|
if (visibilities.sidebar || visibilities.dashboard || visibilities.resources || visibilities.settings)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (ch.id === "tray") {
|
||||||
|
const tray = ch.item;
|
||||||
|
const localPos = tray.mapFromItem(root, x, height / 2);
|
||||||
|
const sub = tray.getHoveredSubItem(localPos.x, localPos.y);
|
||||||
|
if (sub) {
|
||||||
|
popouts.currentName = sub.id;
|
||||||
|
popouts.currentCenter = Qt.binding(() => {
|
||||||
|
const centerX = sub.item.mapToItem(root, sub.item.width / 2, 0).x;
|
||||||
|
return centerX;
|
||||||
|
});
|
||||||
|
popouts.hasCurrent = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!popouts.currentName.startsWith("traymenu"))
|
||||||
|
popouts.hasCurrent = false;
|
||||||
|
}
|
||||||
|
|
||||||
const id = ch.id;
|
const id = ch.id;
|
||||||
const top = ch.x;
|
const top = ch.x;
|
||||||
const item = ch.item;
|
const item = ch.item;
|
||||||
@@ -93,15 +112,6 @@ RowLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DelegateChoice {
|
|
||||||
roleValue: "audio"
|
|
||||||
|
|
||||||
delegate: WrappedLoader {
|
|
||||||
sourceComponent: AudioWidget {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: "tray"
|
roleValue: "tray"
|
||||||
|
|
||||||
@@ -165,15 +175,6 @@ RowLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DelegateChoice {
|
|
||||||
roleValue: "upower"
|
|
||||||
|
|
||||||
delegate: WrappedLoader {
|
|
||||||
sourceComponent: UPowerWidget {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DelegateChoice {
|
DelegateChoice {
|
||||||
roleValue: "network"
|
roleValue: "network"
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import qs.Components
|
|||||||
import qs.Modules
|
import qs.Modules
|
||||||
import qs.Config
|
import qs.Config
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
import qs.Modules.UPower
|
import qs.Modules.SysTray
|
||||||
|
import qs.Modules.SysTray.Widgets
|
||||||
import qs.Modules.Network
|
import qs.Modules.Network
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ import qs.Config
|
|||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Modules.WSOverview
|
import qs.Modules.WSOverview
|
||||||
import qs.Modules.Network
|
import qs.Modules.Network
|
||||||
import qs.Modules.UPower
|
import qs.Modules.SysTray.Popouts
|
||||||
import qs.Modules.Updates
|
import qs.Modules.Updates
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ RowLayout {
|
|||||||
property int warningThreshold: 80
|
property int warningThreshold: 80
|
||||||
|
|
||||||
percentage: 0
|
percentage: 0
|
||||||
|
spacing: Appearance.spacing.smaller
|
||||||
|
|
||||||
Behavior on animatedPercentage {
|
Behavior on animatedPercentage {
|
||||||
Anim {
|
Anim {
|
||||||
@@ -38,6 +39,7 @@ RowLayout {
|
|||||||
MaterialIcon {
|
MaterialIcon {
|
||||||
id: icon
|
id: icon
|
||||||
|
|
||||||
|
Layout.preferredWidth: 16
|
||||||
color: root.iconColor
|
color: root.iconColor
|
||||||
font.pointSize: Appearance.font.size.larger
|
font.pointSize: Appearance.font.size.larger
|
||||||
text: root.icon
|
text: root.icon
|
||||||
@@ -57,6 +59,11 @@ RowLayout {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
color: root.mainColor
|
color: root.mainColor
|
||||||
implicitHeight: Math.ceil(root.percentage * parent.height)
|
implicitHeight: Math.ceil(root.percentage * parent.height)
|
||||||
|
|
||||||
|
Behavior on implicitHeight {
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,15 @@ SettingsPage {
|
|||||||
Separator {
|
Separator {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingSwitch {
|
||||||
|
name: "Check for updates"
|
||||||
|
object: Config.services
|
||||||
|
setting: "updates"
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
}
|
||||||
|
|
||||||
SettingSwitch {
|
SettingSwitch {
|
||||||
name: "Use Fahrenheit"
|
name: "Use Fahrenheit"
|
||||||
object: Config.services
|
object: Config.services
|
||||||
@@ -60,9 +69,9 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Audio increment"
|
|
||||||
max: 1
|
max: 1
|
||||||
min: 0
|
min: 0
|
||||||
|
name: "Audio increment"
|
||||||
object: Config.services
|
object: Config.services
|
||||||
setting: "audioIncrement"
|
setting: "audioIncrement"
|
||||||
step: 0.05
|
step: 0.05
|
||||||
@@ -72,9 +81,9 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Brightness increment"
|
|
||||||
max: 1
|
max: 1
|
||||||
min: 0
|
min: 0
|
||||||
|
name: "Brightness increment"
|
||||||
object: Config.services
|
object: Config.services
|
||||||
setting: "brightnessIncrement"
|
setting: "brightnessIncrement"
|
||||||
step: 0.05
|
step: 0.05
|
||||||
@@ -84,9 +93,9 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Max volume"
|
|
||||||
max: 5
|
max: 5
|
||||||
min: 0
|
min: 0
|
||||||
|
name: "Max volume"
|
||||||
object: Config.services
|
object: Config.services
|
||||||
setting: "maxVolume"
|
setting: "maxVolume"
|
||||||
step: 0.05
|
step: 0.05
|
||||||
@@ -105,8 +114,8 @@ SettingsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingSpinBox {
|
SettingSpinBox {
|
||||||
name: "Visualizer bars"
|
|
||||||
min: 1
|
min: 1
|
||||||
|
name: "Visualizer bars"
|
||||||
object: Config.services
|
object: Config.services
|
||||||
setting: "visualizerBars"
|
setting: "visualizerBars"
|
||||||
step: 1
|
step: 1
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Services.SystemTray
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Modules.SysTray.Widgets
|
||||||
|
import qs.Modules.SysTray.Popouts
|
||||||
|
import qs.Modules
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property alias items: repeater
|
||||||
|
required property RowLayout loader
|
||||||
|
required property Wrapper popouts
|
||||||
|
|
||||||
|
function getHoveredSubItem(localX, localY) {
|
||||||
|
let modPos = mapToItem(sysTrayMod, localX, localY);
|
||||||
|
if (sysTrayMod.contains(Qt.point(modPos.x, modPos.y))) {
|
||||||
|
let modRowPos = sysTrayMod.mapToItem(sysModRow, modPos.x, modPos.y);
|
||||||
|
let child = sysModRow.childAt(modRowPos.x, modRowPos.y);
|
||||||
|
if (child) {
|
||||||
|
if (child.objectName === "audioWidget")
|
||||||
|
return {
|
||||||
|
id: "audio",
|
||||||
|
item: child
|
||||||
|
};
|
||||||
|
if (child.objectName === "upowerWidget")
|
||||||
|
return {
|
||||||
|
id: "upower",
|
||||||
|
item: child
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let trayPos = mapToItem(sysTray, localX, localY);
|
||||||
|
if (sysTray.contains(Qt.point(trayPos.x, trayPos.y))) {
|
||||||
|
let trayRowPos = sysTray.mapToItem(sysRow, trayPos.x, trayPos.y);
|
||||||
|
let child = sysRow.childAt(trayRowPos.x, trayRowPos.y);
|
||||||
|
if (child && child.hasOwnProperty("popoutId")) {
|
||||||
|
return {
|
||||||
|
id: child.popoutId,
|
||||||
|
item: child
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
height: Config.barConfig.height + Appearance.padding.smallest * 2
|
||||||
|
spacing: Appearance.padding.small
|
||||||
|
width: sysTray.implicitWidth + sysTrayMod.implicitWidth + Appearance.padding.small
|
||||||
|
|
||||||
|
CustomClippingRect {
|
||||||
|
id: sysTray
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
bottomRightRadius: Appearance.rounding.smallest / 2
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
implicitWidth: sysRow.width + Appearance.padding.small * 2
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
topRightRadius: Appearance.rounding.smallest / 2
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: sysRow
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: repeater
|
||||||
|
|
||||||
|
model: SystemTray.items
|
||||||
|
|
||||||
|
TrayItem {
|
||||||
|
id: trayItem
|
||||||
|
|
||||||
|
required property int index
|
||||||
|
required property SystemTrayItem modelData
|
||||||
|
|
||||||
|
implicitHeight: 34
|
||||||
|
implicitWidth: 34
|
||||||
|
ind: index
|
||||||
|
item: modelData
|
||||||
|
loader: root.loader
|
||||||
|
popouts: root.popouts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomClippingRect {
|
||||||
|
id: sysTrayMod
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
bottomLeftRadius: Appearance.rounding.smallest / 2
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
implicitWidth: sysModRow.width + Appearance.padding.smaller * 2
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
topLeftRadius: Appearance.rounding.smallest / 2
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: sysModRow
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Appearance.padding.small
|
||||||
|
|
||||||
|
AudioWidget {
|
||||||
|
objectName: "audioWidget"
|
||||||
|
}
|
||||||
|
|
||||||
|
UPowerWidget {
|
||||||
|
height: parent.height
|
||||||
|
objectName: "upowerWidget"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Services.Pipewire
|
||||||
|
import qs.Daemons
|
||||||
|
import qs.Modules
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property color barColor: DynamicColors.palette.m3primary
|
||||||
|
property color textColor: DynamicColors.palette.m3onSurface
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
animate: true
|
||||||
|
color: (Audio.sourceMuted ?? false) ? DynamicColors.palette.m3error : root.textColor
|
||||||
|
fill: 1
|
||||||
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
text: Audio.sourceMuted ? "mic_off" : "mic"
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
animate: true
|
||||||
|
color: Audio.muted ? DynamicColors.palette.m3error : root.textColor
|
||||||
|
fill: 1
|
||||||
|
font.pointSize: Appearance.font.size.larger
|
||||||
|
text: Audio.muted ? "volume_off" : "volume_up"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import Quickshell.Services.UPower
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Components
|
||||||
|
import qs.Config
|
||||||
|
import qs.Helpers as Helpers
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
animate: true
|
||||||
|
color: !Helpers.UPower.onBattery || UPower.displayDevice.percentage > 0.2 ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3error
|
||||||
|
fill: 1
|
||||||
|
text: {
|
||||||
|
if (!Helpers.UPower.displayDevice.isLaptopBattery) {
|
||||||
|
if (PowerProfiles.profile === PowerProfile.PowerSaver)
|
||||||
|
return "nest_eco_leaf";
|
||||||
|
if (PowerProfiles.profile === PowerProfile.Performance)
|
||||||
|
return "bolt";
|
||||||
|
return "power_settings_new";
|
||||||
|
}
|
||||||
|
|
||||||
|
const perc = Helpers.UPower.displayDevice.percentage;
|
||||||
|
const charging = [UPowerDeviceState.Charging, UPowerDeviceState.FullyCharged, UPowerDeviceState.PendingCharge].includes(Helpers.UPower.displayDevice.state);
|
||||||
|
if (perc === 1)
|
||||||
|
return charging ? "battery_charging_full" : "battery_full";
|
||||||
|
let level = Math.floor(perc * 7);
|
||||||
|
if (charging && (level === 4 || level === 1))
|
||||||
|
level--;
|
||||||
|
return charging ? `battery_charging_${(level + 3) * 10}` : `battery_${level}_bar`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Services.SystemTray
|
|
||||||
import qs.Components
|
|
||||||
import qs.Config
|
|
||||||
|
|
||||||
CustomClippingRect {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
readonly property alias items: repeater
|
|
||||||
required property RowLayout loader
|
|
||||||
required property Wrapper popouts
|
|
||||||
|
|
||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
|
||||||
implicitHeight: Config.barConfig.height + Appearance.padding.smallest * 2
|
|
||||||
implicitWidth: row.width + Appearance.padding.small * 2
|
|
||||||
radius: height / 2
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: row
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
id: repeater
|
|
||||||
|
|
||||||
model: SystemTray.items
|
|
||||||
|
|
||||||
TrayItem {
|
|
||||||
id: trayItem
|
|
||||||
|
|
||||||
required property int index
|
|
||||||
required property SystemTrayItem modelData
|
|
||||||
|
|
||||||
implicitHeight: 34
|
|
||||||
implicitWidth: 34
|
|
||||||
ind: index
|
|
||||||
item: modelData
|
|
||||||
loader: root.loader
|
|
||||||
popouts: root.popouts
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import Quickshell.Services.UPower
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import qs.Components
|
|
||||||
import qs.Config
|
|
||||||
import qs.Helpers as Helpers
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
color: DynamicColors.tPalette.m3surfaceContainer
|
|
||||||
implicitHeight: Config.barConfig.height + Appearance.padding.smallest * 2
|
|
||||||
implicitWidth: layout.implicitWidth + Appearance.padding.normal * 2
|
|
||||||
radius: Appearance.rounding.full
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: layout
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
|
||||||
animate: true
|
|
||||||
color: !Helpers.UPower.onBattery || UPower.displayDevice.percentage > 0.2 ? DynamicColors.palette.m3secondary : DynamicColors.palette.m3error
|
|
||||||
fill: 1
|
|
||||||
text: {
|
|
||||||
if (!Helpers.UPower.displayDevice.isLaptopBattery) {
|
|
||||||
if (PowerProfiles.profile === PowerProfile.PowerSaver)
|
|
||||||
return "nest_eco_leaf";
|
|
||||||
if (PowerProfiles.profile === PowerProfile.Performance)
|
|
||||||
return "bolt";
|
|
||||||
return "power_settings_new";
|
|
||||||
}
|
|
||||||
|
|
||||||
const perc = Helpers.UPower.displayDevice.percentage;
|
|
||||||
const charging = [UPowerDeviceState.Charging, UPowerDeviceState.FullyCharged, UPowerDeviceState.PendingCharge].includes(Helpers.UPower.displayDevice.state);
|
|
||||||
if (perc === 1)
|
|
||||||
return charging ? "battery_charging_full" : "battery_full";
|
|
||||||
let level = Math.floor(perc * 7);
|
|
||||||
if (charging && (level === 4 || level === 1))
|
|
||||||
level--;
|
|
||||||
return charging ? `battery_charging_${(level + 3) * 10}` : `battery_${level}_bar`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
|
||||||
text: Helpers.UPower.displayDevice.isLaptopBattery ? qsTr("%1%").arg(Math.round(UPower.displayDevice.percentage * 100)) : (PowerProfiles.profile === PowerProfile.PowerSaver ? qsTr("Pwr Sav") : PowerProfiles.profile === PowerProfile.Performance ? qsTr("Perf") : qsTr("Bal"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,6 +7,38 @@ main() {
|
|||||||
sudo mkdir -p "/etc/zshell-greeter/images"
|
sudo mkdir -p "/etc/zshell-greeter/images"
|
||||||
sudo cp "$WALLPAPER" "/etc/zshell-greeter/images/greeter_bg.png"
|
sudo cp "$WALLPAPER" "/etc/zshell-greeter/images/greeter_bg.png"
|
||||||
sudo cp "$SCHEME" "/etc/zshell-greeter/scheme.json"
|
sudo cp "$SCHEME" "/etc/zshell-greeter/scheme.json"
|
||||||
|
|
||||||
|
while IFS=: read -r username _ uid _ _ home _; do
|
||||||
|
if [[ -z "$username" || -z "$uid" || -z "$home" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$uid" -lt 1000 ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
face_path=""
|
||||||
|
for candidate in "$home/.face" "$home/.face.icon"; do
|
||||||
|
if [[ -f "$candidate" ]]; then
|
||||||
|
face_path="$candidate"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -n "$face_path" ]]; then
|
||||||
|
ext="${face_path##*.}"
|
||||||
|
case "$face_path" in
|
||||||
|
"$home/.face" | "$home/.face.icon")
|
||||||
|
ext=""
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
if [[ -n "$ext" ]]; then
|
||||||
|
sudo cp "$face_path" "/etc/zshell-greeter/images/${username}.${ext}"
|
||||||
|
else
|
||||||
|
sudo cp "$face_path" "/etc/zshell-greeter/images/${username}.face"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done </etc/passwd
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
main "$@"
|
||||||
|
|||||||
Reference in New Issue
Block a user