plugin: rust-side modules + theme services with serde-typed config

This commit is contained in:
Damocles 2026-05-04 22:58:12 +02:00
parent a86e90e927
commit f34f3f2f4e
95 changed files with 2477 additions and 1011 deletions

View file

@ -69,7 +69,12 @@
formatter = forAllSystems ({ treefmt-eval, ... }: treefmt-eval.config.build.wrapper); formatter = forAllSystems ({ treefmt-eval, ... }: treefmt-eval.config.build.wrapper);
packages = forAllSystems ( packages = forAllSystems (
{ pkgs, rawPkgs, craneLib, ... }: {
pkgs,
rawPkgs,
craneLib,
...
}:
let let
# Rebuild quickshell against patched Qt via its overlay # Rebuild quickshell against patched Qt via its overlay
qs = (pkgs.extend quickshell.overlays.default).quickshell.override { qs = (pkgs.extend quickshell.overlays.default).quickshell.override {
@ -161,6 +166,7 @@
{ {
pkgs, pkgs,
rawPkgs, rawPkgs,
craneLib,
treefmt-eval, treefmt-eval,
}: }:
{ {

View file

@ -56,8 +56,7 @@ let
src = ../plugin; src = ../plugin;
name = "nova-plugin-source"; name = "nova-plugin-source";
filter = filter =
path: type: path: type: (baseNameOf path == "qt_plugin_exports.txt") || (craneLib.filterCargoSources path type);
(baseNameOf path == "qt_plugin_exports.txt") || (craneLib.filterCargoSources path type);
}; };
commonArgs = { commonArgs = {

258
plugin/Cargo.lock generated
View file

@ -2,6 +2,15 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "aho-corasick"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "anstyle" name = "anstyle"
version = "1.0.14" version = "1.0.14"
@ -38,7 +47,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "696283b40e1a39d208ee614b92e5f6521d16962edeb47c48372585ec92419943" checksum = "696283b40e1a39d208ee614b92e5f6521d16962edeb47c48372585ec92419943"
dependencies = [ dependencies = [
"thiserror", "thiserror 1.0.69",
] ]
[[package]] [[package]]
@ -161,7 +170,7 @@ dependencies = [
"cxx-qt-macro", "cxx-qt-macro",
"qt-build-utils", "qt-build-utils",
"static_assertions", "static_assertions",
"thiserror", "thiserror 1.0.69",
] ]
[[package]] [[package]]
@ -252,6 +261,27 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "dirs"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys",
]
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.2" version = "1.0.2"
@ -270,6 +300,17 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
[[package]]
name = "getrandom"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.3.4" version = "0.3.4"
@ -319,16 +360,31 @@ version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
dependencies = [ dependencies = [
"getrandom", "getrandom 0.3.4",
"libc", "libc",
] ]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.186" version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "libredox"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "link-cplusplus" name = "link-cplusplus"
version = "1.0.12" version = "1.0.12"
@ -350,6 +406,21 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44cd706ff0d503ee32b2071166510ca27e281228de10cd3aa8d35ff94560f81" checksum = "a44cd706ff0d503ee32b2071166510ca27e281228de10cd3aa8d35ff94560f81"
[[package]]
name = "log"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "matchers"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
dependencies = [
"regex-automata",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.8.0" version = "2.8.0"
@ -365,9 +436,41 @@ dependencies = [
"cxx-qt", "cxx-qt",
"cxx-qt-build", "cxx-qt-build",
"cxx-qt-lib", "cxx-qt-lib",
"dirs",
"libc", "libc",
"serde",
"serde_json",
"tracing",
"tracing-subscriber",
] ]
[[package]]
name = "nu-ansi-term"
version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
"windows-sys",
]
[[package]]
name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "pin-project-lite"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.106" version = "1.0.106"
@ -387,7 +490,7 @@ dependencies = [
"cc", "cc",
"semver", "semver",
"serde", "serde",
"thiserror", "thiserror 1.0.69",
] ]
[[package]] [[package]]
@ -405,6 +508,34 @@ version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "redox_users"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
dependencies = [
"getrandom 0.2.17",
"libredox",
"thiserror 2.0.18",
]
[[package]]
name = "regex-automata"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.22" version = "1.0.22"
@ -466,12 +597,27 @@ dependencies = [
"zmij", "zmij",
] ]
[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
dependencies = [
"lazy_static",
]
[[package]] [[package]]
name = "shlex" name = "shlex"
version = "1.3.0" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]] [[package]]
name = "static_assertions" name = "static_assertions"
version = "1.1.0" version = "1.1.0"
@ -510,7 +656,16 @@ version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl 1.0.69",
]
[[package]]
name = "thiserror"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
dependencies = [
"thiserror-impl 2.0.18",
] ]
[[package]] [[package]]
@ -524,6 +679,87 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "thiserror-impl"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
dependencies = [
"cfg-if",
]
[[package]]
name = "tracing"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [
"log",
"once_cell",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
dependencies = [
"matchers",
"nu-ansi-term",
"once_cell",
"regex-automata",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
]
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.24" version = "1.0.24"
@ -548,6 +784,18 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]]
name = "valuable"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]] [[package]]
name = "wasip2" name = "wasip2"
version = "1.0.3+wasi-0.2.9" version = "1.0.3+wasi-0.2.9"

View file

@ -18,6 +18,11 @@ cxx-qt = "0.8.1"
cxx-qt-lib = { version = "0.8.1", features = ["qt_full"] } cxx-qt-lib = { version = "0.8.1", features = ["qt_full"] }
ctor = "0.13" ctor = "0.13"
libc = "0.2" libc = "0.2"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149"
dirs = "6.0.0"
tracing = "0.1.44"
tracing-subscriber = { version = "0.3.23", features = ["env-filter"] }
[build-dependencies] [build-dependencies]
cxx-qt-build = "0.8.1" cxx-qt-build = "0.8.1"

View file

@ -27,7 +27,12 @@ fn main() {
// build a dummy crate that only compiles dependencies. Skip cxx-qt codegen in // build a dummy crate that only compiles dependencies. Skip cxx-qt codegen in
// that case - we just want cxx-qt-lib (the heavy dep) cached, not our own glue. // that case - we just want cxx-qt-lib (the heavy dep) cached, not our own glue.
let manifest = std::path::Path::new(env!("CARGO_MANIFEST_DIR")); let manifest = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let bridge_files = ["src/system_stats.rs", "src/cpu_service.rs"]; let bridge_files = [
"src/system_stats.rs",
"src/cpu_service.rs",
"src/modules_service.rs",
"src/theme_service.rs",
];
if !bridge_files.iter().all(|p| manifest.join(p).exists()) { if !bridge_files.iter().all(|p| manifest.join(p).exists()) {
return; return;
} }

View file

@ -1,8 +1,18 @@
pub mod cpu_service; pub mod cpu_service;
pub mod modules_service;
pub mod stats; pub mod stats;
pub mod system_stats; pub mod system_stats;
pub mod theme_service;
#[ctor::ctor(unsafe)] #[ctor::ctor(unsafe)]
fn on_dylib_load() { fn on_dylib_load() {
eprintln!("[nova-plugin] dylib loaded (libNovaStats.so)"); // Init tracing once at .so load. RUST_LOG-style filter via env, default WARN.
let _ = tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("warn")),
)
.try_init();
tracing::info!(target: "nova_plugin", "dylib loaded (libNovaStats.so)");
} }

View file

@ -0,0 +1,771 @@
//! Settings service: parses `$XDG_CONFIG_HOME/nova-shell/modules.json` once at
//! plugin load and exposes per-leaf primitive Q_PROPERTYs to QML. Defaults
//! mirror the previous QML implementation; a missing file yields all defaults
//! silently. Read errors / malformed JSON crash so misconfigurations are loud.
//! Unknown fields warn via `tracing` and are otherwise ignored.
use core::pin::Pin;
use cxx_qt::CxxQtType;
use cxx_qt_lib::{QList, QString};
use serde::Deserialize;
use std::path::PathBuf;
#[cxx_qt::bridge]
pub mod qobject {
unsafe extern "C++" {
include!("cxx-qt-lib/qstring.h");
type QString = cxx_qt_lib::QString;
include!("cxx-qt-lib/core/qlist/qlist_QString.h");
type QList_QString = cxx_qt_lib::QList<cxx_qt_lib::QString>;
}
extern "RustQt" {
#[qobject]
#[qml_element]
#[qml_singleton]
// Stats polling interval (-1 = use default).
#[qproperty(i32, stats_daemon_interval, cxx_name = "statsDaemonInterval")]
// Per-module enables (mirrors `<group>.enable`).
#[qproperty(bool, workspaces_enable, cxx_name = "workspacesEnable")]
#[qproperty(bool, tray_enable, cxx_name = "trayEnable")]
#[qproperty(bool, window_title_enable, cxx_name = "windowTitleEnable")]
#[qproperty(bool, clock_enable, cxx_name = "clockEnable")]
#[qproperty(bool, mpris_enable, cxx_name = "mprisEnable")]
#[qproperty(bool, volume_enable, cxx_name = "volumeEnable")]
#[qproperty(bool, bluetooth_enable, cxx_name = "bluetoothEnable")]
#[qproperty(bool, network_enable, cxx_name = "networkEnable")]
#[qproperty(bool, power_profile_enable, cxx_name = "powerProfileEnable")]
#[qproperty(bool, idle_inhibitor_enable, cxx_name = "idleInhibitorEnable")]
#[qproperty(bool, cpu_enable, cxx_name = "cpuEnable")]
#[qproperty(bool, memory_enable, cxx_name = "memoryEnable")]
#[qproperty(bool, privacy_enable, cxx_name = "privacyEnable")]
#[qproperty(bool, screen_corners_enable, cxx_name = "screenCornersEnable")]
#[qproperty(bool, power_enable, cxx_name = "powerEnable")]
#[qproperty(bool, background_overlay_enable, cxx_name = "backgroundOverlayEnable")]
#[qproperty(bool, overview_backdrop_enable, cxx_name = "overviewBackdropEnable")]
// Notifications.
#[qproperty(bool, notifications_enable, cxx_name = "notificationsEnable")]
#[qproperty(i32, notifications_timeout, cxx_name = "notificationsTimeout")]
#[qproperty(i32, notifications_max_popups, cxx_name = "notificationsMaxPopups")]
#[qproperty(i32, notifications_max_visible, cxx_name = "notificationsMaxVisible")]
#[qproperty(i32, notifications_max_history, cxx_name = "notificationsMaxHistory")]
// Backlight.
#[qproperty(bool, backlight_enable, cxx_name = "backlightEnable")]
#[qproperty(i32, backlight_step, cxx_name = "backlightStep")]
// Weather.
#[qproperty(bool, weather_enable, cxx_name = "weatherEnable")]
#[qproperty(QList_QString, weather_args, cxx_name = "weatherArgs")]
#[qproperty(i32, weather_interval, cxx_name = "weatherInterval")]
// Temperature.
#[qproperty(bool, temperature_enable, cxx_name = "temperatureEnable")]
#[qproperty(i32, temperature_warm, cxx_name = "temperatureWarm")]
#[qproperty(i32, temperature_hot, cxx_name = "temperatureHot")]
#[qproperty(QString, temperature_device, cxx_name = "temperatureDevice")]
// GPU.
#[qproperty(bool, gpu_enable, cxx_name = "gpuEnable")]
#[qproperty(i32, gpu_warm, cxx_name = "gpuWarm")]
#[qproperty(i32, gpu_hot, cxx_name = "gpuHot")]
// Disk.
#[qproperty(bool, disk_enable, cxx_name = "diskEnable")]
#[qproperty(i32, disk_interval, cxx_name = "diskInterval")]
#[qproperty(i32, disk_warn_threshold, cxx_name = "diskWarnThreshold")]
// Battery.
#[qproperty(bool, battery_enable, cxx_name = "batteryEnable")]
#[qproperty(bool, battery_poweralertd, cxx_name = "batteryPoweralertd")]
#[qproperty(i32, battery_warning, cxx_name = "batteryWarning")]
#[qproperty(i32, battery_critical, cxx_name = "batteryCritical")]
// Lock screen.
#[qproperty(bool, lock_enable, cxx_name = "lockEnable")]
#[qproperty(bool, lock_mpris, cxx_name = "lockMpris")]
#[qproperty(bool, lock_notifications, cxx_name = "lockNotifications")]
#[qproperty(bool, lock_screenshot, cxx_name = "lockScreenshot")]
#[qproperty(bool, lock_threat_effect, cxx_name = "lockThreatEffect")]
#[qproperty(bool, lock_volume, cxx_name = "lockVolume")]
#[qproperty(bool, lock_weather, cxx_name = "lockWeather")]
// Dock.
#[qproperty(bool, dock_enable, cxx_name = "dockEnable")]
#[qproperty(i32, dock_width, cxx_name = "dockWidth")]
#[qproperty(bool, dock_applet_clock, cxx_name = "dockAppletClock")]
#[qproperty(bool, dock_applet_cpu, cxx_name = "dockAppletCpu")]
#[qproperty(bool, dock_applet_gpu, cxx_name = "dockAppletGpu")]
#[qproperty(bool, dock_applet_memory, cxx_name = "dockAppletMemory")]
#[qproperty(bool, dock_applet_temperature, cxx_name = "dockAppletTemperature")]
#[qproperty(bool, dock_applet_disk, cxx_name = "dockAppletDisk")]
#[qproperty(bool, dock_applet_battery, cxx_name = "dockAppletBattery")]
#[qproperty(bool, dock_applet_network, cxx_name = "dockAppletNetwork")]
#[qproperty(bool, dock_applet_bluetooth, cxx_name = "dockAppletBluetooth")]
#[qproperty(bool, dock_applet_volume, cxx_name = "dockAppletVolume")]
#[qproperty(bool, dock_applet_backlight, cxx_name = "dockAppletBacklight")]
#[qproperty(bool, dock_applet_weather, cxx_name = "dockAppletWeather")]
#[qproperty(bool, dock_applet_mpris, cxx_name = "dockAppletMpris")]
#[qproperty(bool, dock_applet_notifications, cxx_name = "dockAppletNotifications")]
#[qproperty(bool, dock_applet_power, cxx_name = "dockAppletPower")]
// Systemd / machinectl bar modules.
#[qproperty(bool, systemd_enable, cxx_name = "systemdEnable")]
#[qproperty(i32, systemd_interval, cxx_name = "systemdInterval")]
#[qproperty(bool, machinectl_enable, cxx_name = "machinectlEnable")]
#[qproperty(i32, machinectl_interval, cxx_name = "machinectlInterval")]
type ModulesService = super::ModulesServiceRust;
}
impl cxx_qt::Initialize for ModulesService {}
}
// ── Pure Rust data layer ─────────────────────────────────────────────────────
// One struct per group, plus a top-level `ModulesData`. Defaults mirror the
// previous QML implementation, NOT serde's type defaults. `#[serde(default)]`
// on every leaf so partial JSON objects get filled in from `Default`.
mod data {
use super::Deserialize;
fn t() -> bool {
true
}
fn weather_args_default() -> Vec<String> {
vec!["--nerd".to_owned()]
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Plain {
#[serde(default = "t")]
pub enable: bool,
}
impl Default for Plain {
fn default() -> Self {
Self { enable: true }
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Notifications {
#[serde(default = "t")]
pub enable: bool,
#[serde(default = "Notifications::d_timeout")]
pub timeout: i32,
#[serde(default = "Notifications::d_max_popups")]
pub max_popups: i32,
#[serde(default = "Notifications::d_max_visible")]
pub max_visible: i32,
#[serde(default = "Notifications::d_max_history")]
pub max_history: i32,
}
impl Notifications {
fn d_timeout() -> i32 {
3000
}
fn d_max_popups() -> i32 {
4
}
fn d_max_visible() -> i32 {
10
}
fn d_max_history() -> i32 {
-1
}
}
impl Default for Notifications {
fn default() -> Self {
Self {
enable: true,
timeout: Self::d_timeout(),
max_popups: Self::d_max_popups(),
max_visible: Self::d_max_visible(),
max_history: Self::d_max_history(),
}
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Backlight {
#[serde(default = "t")]
pub enable: bool,
#[serde(default = "Backlight::d_step")]
pub step: i32,
}
impl Backlight {
fn d_step() -> i32 {
5
}
}
impl Default for Backlight {
fn default() -> Self {
Self {
enable: true,
step: Self::d_step(),
}
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Weather {
#[serde(default = "t")]
pub enable: bool,
#[serde(default = "weather_args_default")]
pub args: Vec<String>,
#[serde(default = "Weather::d_interval")]
pub interval: i32,
}
impl Weather {
fn d_interval() -> i32 {
3_600_000
}
}
impl Default for Weather {
fn default() -> Self {
Self {
enable: true,
args: weather_args_default(),
interval: Self::d_interval(),
}
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Temperature {
#[serde(default = "t")]
pub enable: bool,
#[serde(default = "Temperature::d_warm")]
pub warm: i32,
#[serde(default = "Temperature::d_hot")]
pub hot: i32,
#[serde(default)]
pub device: String,
}
impl Temperature {
fn d_warm() -> i32 {
80
}
fn d_hot() -> i32 {
90
}
}
impl Default for Temperature {
fn default() -> Self {
Self {
enable: true,
warm: Self::d_warm(),
hot: Self::d_hot(),
device: String::new(),
}
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Gpu {
#[serde(default = "t")]
pub enable: bool,
#[serde(default = "Gpu::d_warm")]
pub warm: i32,
#[serde(default = "Gpu::d_hot")]
pub hot: i32,
}
impl Gpu {
fn d_warm() -> i32 {
70
}
fn d_hot() -> i32 {
85
}
}
impl Default for Gpu {
fn default() -> Self {
Self {
enable: true,
warm: Self::d_warm(),
hot: Self::d_hot(),
}
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Disk {
#[serde(default = "t")]
pub enable: bool,
#[serde(default = "Disk::d_interval")]
pub interval: i32,
#[serde(default = "Disk::d_warn_threshold")]
pub warn_threshold: i32,
}
impl Disk {
fn d_interval() -> i32 {
30_000
}
fn d_warn_threshold() -> i32 {
85
}
}
impl Default for Disk {
fn default() -> Self {
Self {
enable: true,
interval: Self::d_interval(),
warn_threshold: Self::d_warn_threshold(),
}
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Battery {
#[serde(default = "t")]
pub enable: bool,
#[serde(default = "t")]
pub poweralertd: bool,
#[serde(default = "Battery::d_warning")]
pub warning: i32,
#[serde(default = "Battery::d_critical")]
pub critical: i32,
}
impl Battery {
fn d_warning() -> i32 {
25
}
fn d_critical() -> i32 {
15
}
}
impl Default for Battery {
fn default() -> Self {
Self {
enable: true,
poweralertd: true,
warning: Self::d_warning(),
critical: Self::d_critical(),
}
}
}
#[derive(Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct Lock {
#[serde(default = "t")]
pub enable: bool,
#[serde(default = "t")]
pub mpris: bool,
#[serde(default = "t")]
pub notifications: bool,
#[serde(default = "t")]
pub screenshot: bool,
#[serde(default = "t")]
pub threat_effect: bool,
#[serde(default = "t")]
pub volume: bool,
#[serde(default = "t")]
pub weather: bool,
}
#[derive(Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct DockApplets {
#[serde(default = "t")]
pub clock: bool,
#[serde(default = "t")]
pub cpu: bool,
#[serde(default = "t")]
pub gpu: bool,
#[serde(default = "t")]
pub memory: bool,
#[serde(default = "t")]
pub temperature: bool,
#[serde(default = "t")]
pub disk: bool,
#[serde(default = "t")]
pub battery: bool,
#[serde(default = "t")]
pub network: bool,
#[serde(default = "t")]
pub bluetooth: bool,
#[serde(default = "t")]
pub volume: bool,
#[serde(default = "t")]
pub backlight: bool,
#[serde(default = "t")]
pub weather: bool,
#[serde(default = "t")]
pub mpris: bool,
#[serde(default = "t")]
pub notifications: bool,
#[serde(default = "t")]
pub power: bool,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Dock {
#[serde(default = "t")]
pub enable: bool,
#[serde(default = "Dock::d_width")]
pub width: i32,
#[serde(default)]
pub applets: DockApplets,
}
impl Dock {
fn d_width() -> i32 {
300
}
}
impl Default for Dock {
fn default() -> Self {
Self {
enable: true,
width: Self::d_width(),
applets: DockApplets::default(),
}
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct WithInterval {
#[serde(default = "t")]
pub enable: bool,
#[serde(default = "WithInterval::d_interval")]
pub interval: i32,
}
impl WithInterval {
fn d_interval() -> i32 {
15_000
}
}
impl Default for WithInterval {
fn default() -> Self {
Self {
enable: true,
interval: Self::d_interval(),
}
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct StatsDaemon {
#[serde(default = "StatsDaemon::d_interval")]
pub interval: i32,
}
impl StatsDaemon {
fn d_interval() -> i32 {
-1
}
}
impl Default for StatsDaemon {
fn default() -> Self {
Self {
interval: Self::d_interval(),
}
}
}
#[derive(Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct ModulesData {
#[serde(default)]
pub workspaces: Plain,
#[serde(default)]
pub tray: Plain,
#[serde(default)]
pub window_title: Plain,
#[serde(default)]
pub clock: Plain,
#[serde(default)]
pub mpris: Plain,
#[serde(default)]
pub volume: Plain,
#[serde(default)]
pub bluetooth: Plain,
#[serde(default)]
pub network: Plain,
#[serde(default)]
pub power_profile: Plain,
#[serde(default)]
pub idle_inhibitor: Plain,
#[serde(default)]
pub cpu: Plain,
#[serde(default)]
pub memory: Plain,
#[serde(default)]
pub privacy: Plain,
#[serde(default)]
pub screen_corners: Plain,
#[serde(default)]
pub power: Plain,
#[serde(default)]
pub background_overlay: Plain,
#[serde(default)]
pub overview_backdrop: Plain,
#[serde(default)]
pub notifications: Notifications,
#[serde(default)]
pub backlight: Backlight,
#[serde(default)]
pub weather: Weather,
#[serde(default)]
pub temperature: Temperature,
#[serde(default)]
pub gpu: Gpu,
#[serde(default)]
pub disk: Disk,
#[serde(default)]
pub battery: Battery,
#[serde(default)]
pub lock: Lock,
#[serde(default)]
pub dock: Dock,
#[serde(default)]
pub systemd: WithInterval,
#[serde(default)]
pub machinectl: WithInterval,
#[serde(default)]
pub stats_daemon: StatsDaemon,
}
}
use data::ModulesData;
pub struct ModulesServiceRust {
stats_daemon_interval: i32,
workspaces_enable: bool,
tray_enable: bool,
window_title_enable: bool,
clock_enable: bool,
mpris_enable: bool,
volume_enable: bool,
bluetooth_enable: bool,
network_enable: bool,
power_profile_enable: bool,
idle_inhibitor_enable: bool,
cpu_enable: bool,
memory_enable: bool,
privacy_enable: bool,
screen_corners_enable: bool,
power_enable: bool,
background_overlay_enable: bool,
overview_backdrop_enable: bool,
notifications_enable: bool,
notifications_timeout: i32,
notifications_max_popups: i32,
notifications_max_visible: i32,
notifications_max_history: i32,
backlight_enable: bool,
backlight_step: i32,
weather_enable: bool,
weather_args: QList<QString>,
weather_interval: i32,
temperature_enable: bool,
temperature_warm: i32,
temperature_hot: i32,
temperature_device: QString,
gpu_enable: bool,
gpu_warm: i32,
gpu_hot: i32,
disk_enable: bool,
disk_interval: i32,
disk_warn_threshold: i32,
battery_enable: bool,
battery_poweralertd: bool,
battery_warning: i32,
battery_critical: i32,
lock_enable: bool,
lock_mpris: bool,
lock_notifications: bool,
lock_screenshot: bool,
lock_threat_effect: bool,
lock_volume: bool,
lock_weather: bool,
dock_enable: bool,
dock_width: i32,
dock_applet_clock: bool,
dock_applet_cpu: bool,
dock_applet_gpu: bool,
dock_applet_memory: bool,
dock_applet_temperature: bool,
dock_applet_disk: bool,
dock_applet_battery: bool,
dock_applet_network: bool,
dock_applet_bluetooth: bool,
dock_applet_volume: bool,
dock_applet_backlight: bool,
dock_applet_weather: bool,
dock_applet_mpris: bool,
dock_applet_notifications: bool,
dock_applet_power: bool,
systemd_enable: bool,
systemd_interval: i32,
machinectl_enable: bool,
machinectl_interval: i32,
}
impl Default for ModulesServiceRust {
fn default() -> Self {
Self::from_data(load_modules_data())
}
}
impl ModulesServiceRust {
fn from_data(d: ModulesData) -> Self {
let mut weather_args = QList::<QString>::default();
for s in &d.weather.args {
weather_args.append(QString::from(s.as_str()));
}
Self {
stats_daemon_interval: d.stats_daemon.interval,
workspaces_enable: d.workspaces.enable,
tray_enable: d.tray.enable,
window_title_enable: d.window_title.enable,
clock_enable: d.clock.enable,
mpris_enable: d.mpris.enable,
volume_enable: d.volume.enable,
bluetooth_enable: d.bluetooth.enable,
network_enable: d.network.enable,
power_profile_enable: d.power_profile.enable,
idle_inhibitor_enable: d.idle_inhibitor.enable,
cpu_enable: d.cpu.enable,
memory_enable: d.memory.enable,
privacy_enable: d.privacy.enable,
screen_corners_enable: d.screen_corners.enable,
power_enable: d.power.enable,
background_overlay_enable: d.background_overlay.enable,
overview_backdrop_enable: d.overview_backdrop.enable,
notifications_enable: d.notifications.enable,
notifications_timeout: d.notifications.timeout,
notifications_max_popups: d.notifications.max_popups,
notifications_max_visible: d.notifications.max_visible,
notifications_max_history: d.notifications.max_history,
backlight_enable: d.backlight.enable,
backlight_step: d.backlight.step,
weather_enable: d.weather.enable,
weather_args,
weather_interval: d.weather.interval,
temperature_enable: d.temperature.enable,
temperature_warm: d.temperature.warm,
temperature_hot: d.temperature.hot,
temperature_device: QString::from(d.temperature.device.as_str()),
gpu_enable: d.gpu.enable,
gpu_warm: d.gpu.warm,
gpu_hot: d.gpu.hot,
disk_enable: d.disk.enable,
disk_interval: d.disk.interval,
disk_warn_threshold: d.disk.warn_threshold,
battery_enable: d.battery.enable,
battery_poweralertd: d.battery.poweralertd,
battery_warning: d.battery.warning,
battery_critical: d.battery.critical,
lock_enable: d.lock.enable,
lock_mpris: d.lock.mpris,
lock_notifications: d.lock.notifications,
lock_screenshot: d.lock.screenshot,
lock_threat_effect: d.lock.threat_effect,
lock_volume: d.lock.volume,
lock_weather: d.lock.weather,
dock_enable: d.dock.enable,
dock_width: d.dock.width,
dock_applet_clock: d.dock.applets.clock,
dock_applet_cpu: d.dock.applets.cpu,
dock_applet_gpu: d.dock.applets.gpu,
dock_applet_memory: d.dock.applets.memory,
dock_applet_temperature: d.dock.applets.temperature,
dock_applet_disk: d.dock.applets.disk,
dock_applet_battery: d.dock.applets.battery,
dock_applet_network: d.dock.applets.network,
dock_applet_bluetooth: d.dock.applets.bluetooth,
dock_applet_volume: d.dock.applets.volume,
dock_applet_backlight: d.dock.applets.backlight,
dock_applet_weather: d.dock.applets.weather,
dock_applet_mpris: d.dock.applets.mpris,
dock_applet_notifications: d.dock.applets.notifications,
dock_applet_power: d.dock.applets.power,
systemd_enable: d.systemd.enable,
systemd_interval: d.systemd.interval,
machinectl_enable: d.machinectl.enable,
machinectl_interval: d.machinectl.interval,
}
}
}
pub(crate) fn config_path(file: &str) -> PathBuf {
let base = dirs::config_dir().unwrap_or_else(|| {
// Treat a missing HOME/XDG as a user error, not a silent default; matches
// the rule that perm/format issues should surface immediately.
panic!("[nova-plugin] could not resolve $XDG_CONFIG_HOME or $HOME for config lookup");
});
base.join("nova-shell").join(file)
}
fn load_modules_data() -> ModulesData {
let path = config_path("modules.json");
let raw = match std::fs::read_to_string(&path) {
Ok(s) => s,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
tracing::info!(
target: "nova_plugin::config",
"modules.json not found at {}, using defaults", path.display()
);
return ModulesData::default();
}
Err(e) => panic!("[nova-plugin] cannot read {}: {e}", path.display()),
};
parse_modules(&raw, &path)
}
fn parse_modules(raw: &str, path: &std::path::Path) -> ModulesData {
// First pass: catch unknown keys via a generic Value, warn but keep going.
if let Ok(serde_json::Value::Object(map)) = serde_json::from_str::<serde_json::Value>(raw) {
let known: &[&str] = &[
"workspaces",
"tray",
"windowTitle",
"clock",
"mpris",
"volume",
"bluetooth",
"network",
"powerProfile",
"idleInhibitor",
"cpu",
"memory",
"privacy",
"screenCorners",
"power",
"backgroundOverlay",
"overviewBackdrop",
"notifications",
"backlight",
"weather",
"temperature",
"gpu",
"disk",
"battery",
"lock",
"dock",
"systemd",
"machinectl",
"statsDaemon",
];
for key in map.keys() {
if !known.contains(&key.as_str()) {
tracing::warn!(
target: "nova_plugin::config",
"{}: unknown top-level key `{key}` ignored", path.display()
);
}
}
}
serde_json::from_str(raw)
.unwrap_or_else(|e| panic!("[nova-plugin] {}: malformed JSON: {e}", path.display()))
}
impl cxx_qt::Initialize for qobject::ModulesService {
fn initialize(self: Pin<&mut Self>) {
// Default-construct populates from disk; nothing else to do.
let _ = self;
}
}

414
plugin/src/theme_service.rs Normal file
View file

@ -0,0 +1,414 @@
//! Theme service: parses `$XDG_CONFIG_HOME/nova-shell/theme.json` once at plugin
//! load. Same file-handling rules as `modules_service`. Color values are exposed
//! as `QString` (#RRGGBB) which QML auto-coerces to `color` at the binding site.
//!
//! `reducedMotion` (which combines this config with PowerProfileService) and
//! `loadColor()` (a pure JS gradient helper) live in `services/ThemeUtil.qml` -
//! they need the QML-side PowerProfileService and don't fit a Rust singleton.
use core::pin::Pin;
use cxx_qt::CxxQtType;
use cxx_qt_lib::{QColor, QString};
use serde::Deserialize;
#[cxx_qt::bridge]
pub mod qobject {
unsafe extern "C++" {
include!("cxx-qt-lib/qstring.h");
type QString = cxx_qt_lib::QString;
include!("cxx-qt-lib/qcolor.h");
type QColor = cxx_qt_lib::QColor;
}
extern "RustQt" {
#[qobject]
#[qml_element]
#[qml_singleton]
// base16 palette as proper QColor so QML gets `.r/.g/.b` access without Qt.color().
#[qproperty(QColor, base00)]
#[qproperty(QColor, base01)]
#[qproperty(QColor, base02)]
#[qproperty(QColor, base03)]
#[qproperty(QColor, base04)]
#[qproperty(QColor, base05)]
#[qproperty(QColor, base06)]
#[qproperty(QColor, base07)]
#[qproperty(QColor, base08)]
#[qproperty(QColor, base09)]
#[qproperty(QColor, base0_a, cxx_name = "base0A")]
#[qproperty(QColor, base0_b, cxx_name = "base0B")]
#[qproperty(QColor, base0_c, cxx_name = "base0C")]
#[qproperty(QColor, base0_d, cxx_name = "base0D")]
#[qproperty(QColor, base0_e, cxx_name = "base0E")]
#[qproperty(QColor, base0_f, cxx_name = "base0F")]
// Typography.
#[qproperty(QString, font_family, cxx_name = "fontFamily")]
#[qproperty(QString, icon_font_family, cxx_name = "iconFontFamily")]
#[qproperty(i32, font_size, cxx_name = "fontSize")]
// Layout / decoration.
#[qproperty(f64, bar_opacity, cxx_name = "barOpacity")]
#[qproperty(i32, bar_height, cxx_name = "barHeight")]
#[qproperty(i32, bar_padding, cxx_name = "barPadding")]
#[qproperty(i32, module_spacing, cxx_name = "moduleSpacing")]
#[qproperty(i32, group_spacing, cxx_name = "groupSpacing")]
#[qproperty(i32, group_padding, cxx_name = "groupPadding")]
#[qproperty(i32, radius)]
#[qproperty(i32, screen_radius, cxx_name = "screenRadius")]
// Reduced-motion config flag (the effective value combines this with
// PowerProfileService.powerSaver - that combination lives in ThemeUtil.qml).
#[qproperty(bool, reduced_motion_config, cxx_name = "reducedMotionConfig")]
type ThemeService = super::ThemeServiceRust;
}
impl cxx_qt::Initialize for ThemeService {}
}
mod data {
use super::Deserialize;
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Colors {
#[serde(default = "Colors::d_base00")]
pub base00: String,
#[serde(default = "Colors::d_base01")]
pub base01: String,
#[serde(default = "Colors::d_base02")]
pub base02: String,
#[serde(default = "Colors::d_base03")]
pub base03: String,
#[serde(default = "Colors::d_base04")]
pub base04: String,
#[serde(default = "Colors::d_base05")]
pub base05: String,
#[serde(default = "Colors::d_base06")]
pub base06: String,
#[serde(default = "Colors::d_base07")]
pub base07: String,
#[serde(default = "Colors::d_base08")]
pub base08: String,
#[serde(default = "Colors::d_base09")]
pub base09: String,
#[serde(default = "Colors::d_base0a", rename = "base0A")]
pub base0_a: String,
#[serde(default = "Colors::d_base0b", rename = "base0B")]
pub base0_b: String,
#[serde(default = "Colors::d_base0c", rename = "base0C")]
pub base0_c: String,
#[serde(default = "Colors::d_base0d", rename = "base0D")]
pub base0_d: String,
#[serde(default = "Colors::d_base0e", rename = "base0E")]
pub base0_e: String,
#[serde(default = "Colors::d_base0f", rename = "base0F")]
pub base0_f: String,
}
impl Colors {
// Defaults match Theme.qml's catppuccin-style starting palette.
fn d_base00() -> String {
"#1e1e2e".to_owned()
}
fn d_base01() -> String {
"#181825".to_owned()
}
fn d_base02() -> String {
"#313244".to_owned()
}
fn d_base03() -> String {
"#45475a".to_owned()
}
fn d_base04() -> String {
"#585b70".to_owned()
}
fn d_base05() -> String {
"#cdd6f4".to_owned()
}
fn d_base06() -> String {
"#f5e0dc".to_owned()
}
fn d_base07() -> String {
"#b4befe".to_owned()
}
fn d_base08() -> String {
"#f38ba8".to_owned()
}
fn d_base09() -> String {
"#fab387".to_owned()
}
fn d_base0a() -> String {
"#f9e2af".to_owned()
}
fn d_base0b() -> String {
"#a6e3a1".to_owned()
}
fn d_base0c() -> String {
"#94e2d5".to_owned()
}
fn d_base0d() -> String {
"#89b4fa".to_owned()
}
fn d_base0e() -> String {
"#cba6f7".to_owned()
}
fn d_base0f() -> String {
"#f2cdcd".to_owned()
}
}
impl Default for Colors {
fn default() -> Self {
Self {
base00: Self::d_base00(),
base01: Self::d_base01(),
base02: Self::d_base02(),
base03: Self::d_base03(),
base04: Self::d_base04(),
base05: Self::d_base05(),
base06: Self::d_base06(),
base07: Self::d_base07(),
base08: Self::d_base08(),
base09: Self::d_base09(),
base0_a: Self::d_base0a(),
base0_b: Self::d_base0b(),
base0_c: Self::d_base0c(),
base0_d: Self::d_base0d(),
base0_e: Self::d_base0e(),
base0_f: Self::d_base0f(),
}
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ThemeData {
#[serde(default)]
pub colors: Colors,
#[serde(default = "ThemeData::d_font_family")]
pub font_family: String,
#[serde(default = "ThemeData::d_icon_font_family")]
pub icon_font_family: String,
#[serde(default = "ThemeData::d_font_size")]
pub font_size: i32,
#[serde(default = "ThemeData::d_bar_opacity")]
pub bar_opacity: f64,
#[serde(default = "ThemeData::d_bar_height")]
pub bar_height: i32,
#[serde(default = "ThemeData::d_bar_padding")]
pub bar_padding: i32,
#[serde(default = "ThemeData::d_module_spacing")]
pub module_spacing: i32,
#[serde(default = "ThemeData::d_group_spacing")]
pub group_spacing: i32,
#[serde(default = "ThemeData::d_group_padding")]
pub group_padding: i32,
#[serde(default = "ThemeData::d_radius")]
pub radius: i32,
#[serde(default = "ThemeData::d_screen_radius")]
pub screen_radius: i32,
#[serde(default)]
pub reduced_motion: bool,
}
impl ThemeData {
fn d_font_family() -> String {
"sans-serif".to_owned()
}
fn d_icon_font_family() -> String {
"Symbols Nerd Font".to_owned()
}
fn d_font_size() -> i32 {
12
}
fn d_bar_opacity() -> f64 {
0.9
}
fn d_bar_height() -> i32 {
32
}
fn d_bar_padding() -> i32 {
8
}
fn d_module_spacing() -> i32 {
4
}
fn d_group_spacing() -> i32 {
6
}
fn d_group_padding() -> i32 {
8
}
fn d_radius() -> i32 {
4
}
fn d_screen_radius() -> i32 {
15
}
}
impl Default for ThemeData {
fn default() -> Self {
Self {
colors: Colors::default(),
font_family: Self::d_font_family(),
icon_font_family: Self::d_icon_font_family(),
font_size: Self::d_font_size(),
bar_opacity: Self::d_bar_opacity(),
bar_height: Self::d_bar_height(),
bar_padding: Self::d_bar_padding(),
module_spacing: Self::d_module_spacing(),
group_spacing: Self::d_group_spacing(),
group_padding: Self::d_group_padding(),
radius: Self::d_radius(),
screen_radius: Self::d_screen_radius(),
reduced_motion: false,
}
}
}
}
use data::ThemeData;
pub struct ThemeServiceRust {
base00: QColor,
base01: QColor,
base02: QColor,
base03: QColor,
base04: QColor,
base05: QColor,
base06: QColor,
base07: QColor,
base08: QColor,
base09: QColor,
base0_a: QColor,
base0_b: QColor,
base0_c: QColor,
base0_d: QColor,
base0_e: QColor,
base0_f: QColor,
font_family: QString,
icon_font_family: QString,
font_size: i32,
bar_opacity: f64,
bar_height: i32,
bar_padding: i32,
module_spacing: i32,
group_spacing: i32,
group_padding: i32,
radius: i32,
screen_radius: i32,
reduced_motion_config: bool,
}
impl Default for ThemeServiceRust {
fn default() -> Self {
Self::from_data(load_theme_data())
}
}
/// Parse a `#RRGGBB` (or `#AARRGGBB`) hex string into a `QColor`. Panics on
/// malformed input - file-level malformed JSON already does this; reaching
/// here with a bad hex means the user wrote `"colors": {"base00": "garbage"}`
/// which we'd rather flag immediately than render as default magenta.
fn parse_hex(s: &str) -> QColor {
let h = s.trim_start_matches('#');
let v = u32::from_str_radix(h, 16)
.unwrap_or_else(|_| panic!("[nova-plugin] theme.json: invalid color `{s}`"));
match h.len() {
6 => QColor::from_rgb(
((v >> 16) & 0xff) as i32,
((v >> 8) & 0xff) as i32,
(v & 0xff) as i32,
),
8 => QColor::from_rgba(
((v >> 16) & 0xff) as i32,
((v >> 8) & 0xff) as i32,
(v & 0xff) as i32,
((v >> 24) & 0xff) as i32,
),
_ => panic!("[nova-plugin] theme.json: color `{s}` must be #RRGGBB or #AARRGGBB"),
}
}
impl ThemeServiceRust {
fn from_data(d: ThemeData) -> Self {
let s = |x: &str| QString::from(x);
let c = parse_hex;
Self {
base00: c(&d.colors.base00),
base01: c(&d.colors.base01),
base02: c(&d.colors.base02),
base03: c(&d.colors.base03),
base04: c(&d.colors.base04),
base05: c(&d.colors.base05),
base06: c(&d.colors.base06),
base07: c(&d.colors.base07),
base08: c(&d.colors.base08),
base09: c(&d.colors.base09),
base0_a: c(&d.colors.base0_a),
base0_b: c(&d.colors.base0_b),
base0_c: c(&d.colors.base0_c),
base0_d: c(&d.colors.base0_d),
base0_e: c(&d.colors.base0_e),
base0_f: c(&d.colors.base0_f),
font_family: s(&d.font_family),
icon_font_family: s(&d.icon_font_family),
font_size: d.font_size,
bar_opacity: d.bar_opacity,
bar_height: d.bar_height,
bar_padding: d.bar_padding,
module_spacing: d.module_spacing,
group_spacing: d.group_spacing,
group_padding: d.group_padding,
radius: d.radius,
screen_radius: d.screen_radius,
reduced_motion_config: d.reduced_motion,
}
}
}
fn load_theme_data() -> ThemeData {
let path = crate::modules_service::config_path("theme.json");
let raw = match std::fs::read_to_string(&path) {
Ok(s) => s,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
tracing::info!(
target: "nova_plugin::config",
"theme.json not found at {}, using defaults", path.display()
);
return ThemeData::default();
}
Err(e) => panic!("[nova-plugin] cannot read {}: {e}", path.display()),
};
if let Ok(serde_json::Value::Object(map)) = serde_json::from_str::<serde_json::Value>(&raw) {
let known: &[&str] = &[
"colors",
"fontFamily",
"iconFontFamily",
"fontSize",
"barOpacity",
"barHeight",
"barPadding",
"moduleSpacing",
"groupSpacing",
"groupPadding",
"radius",
"screenRadius",
"reducedMotion",
];
for key in map.keys() {
if !known.contains(&key.as_str()) {
tracing::warn!(
target: "nova_plugin::config",
"{}: unknown top-level key `{key}` ignored", path.display()
);
}
}
}
serde_json::from_str(&raw)
.unwrap_or_else(|e| panic!("[nova-plugin] {}: malformed JSON: {e}", path.display()))
}
impl cxx_qt::Initialize for qobject::ThemeService {
fn initialize(self: Pin<&mut Self>) {
let _ = self;
}
}

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
// Action bar for applet-level controls (power toggles, DND, clear-all, etc.) // Action bar for applet-level controls (power toggles, DND, clear-all, etc.)
// Place at the top of an applet Column. Children are right-aligned action buttons. // Place at the top of an applet Column. Children are right-aligned action buttons.
@ -26,6 +27,6 @@ Item {
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
height: 1 height: 1
color: S.Theme.base03 color: NS.ThemeService.base03
} }
} }

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Item { Item {
id: root id: root
@ -18,8 +19,8 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "\uF185" text: "\uF185"
color: root.accentColor color: root.accentColor
font.pixelSize: S.Theme.fontSize + 2 font.pixelSize: NS.ThemeService.fontSize + 2
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
} }
Item { Item {
@ -33,7 +34,7 @@ Item {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base02 color: NS.ThemeService.base02
radius: 3 radius: 3
} }
@ -71,9 +72,9 @@ Item {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.percent + "%" text: root.percent + "%"
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
width: 30 width: 30
} }
} }

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Column { Column {
id: root id: root
@ -8,7 +9,7 @@ Column {
property bool active: true property bool active: true
readonly property color _stateColor: S.BatteryService.charging ? S.Theme.base0B : S.BatteryService.critical ? S.Theme.base09 : S.BatteryService.percent < S.BatteryService.warnThresh ? S.Theme.base0A : root.accentColor readonly property color _stateColor: S.BatteryService.charging ? NS.ThemeService.base0B : S.BatteryService.critical ? NS.ThemeService.base09 : S.BatteryService.percent < S.BatteryService.warnThresh ? NS.ThemeService.base0A : root.accentColor
// Header - pct + time // Header - pct + time
Item { Item {
@ -25,8 +26,8 @@ Column {
return Math.round(S.BatteryService.percent) + "%" + (ts ? " " + ts : ""); return Math.round(S.BatteryService.percent) + "%" + (ts ? " " + ts : "");
} }
color: root._stateColor color: root._stateColor
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
} }
} }
@ -46,7 +47,7 @@ Column {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base02 color: NS.ThemeService.base02
radius: 3 radius: 3
} }
@ -70,7 +71,7 @@ Column {
width: 1 width: 1
height: parent.height + 4 height: parent.height + 4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: S.Theme.base0A color: NS.ThemeService.base0A
opacity: 0.6 opacity: 0.6
} }
@ -80,7 +81,7 @@ Column {
width: 1 width: 1
height: parent.height + 4 height: parent.height + 4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: S.Theme.base08 color: NS.ThemeService.base08
opacity: 0.6 opacity: 0.6
} }
} }
@ -99,11 +100,11 @@ Column {
thresholds: [ thresholds: [
{ {
value: S.BatteryService.warnThresh, value: S.BatteryService.warnThresh,
color: S.Theme.base0A color: NS.ThemeService.base0A
}, },
{ {
value: S.BatteryService.critThresh, value: S.BatteryService.critThresh,
color: S.Theme.base08 color: NS.ThemeService.base08
} }
] ]
} }
@ -118,9 +119,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "warn " + S.BatteryService.warnThresh + "% crit " + S.BatteryService.critThresh + "%" text: "warn " + S.BatteryService.warnThresh + "% crit " + S.BatteryService.critThresh + "%"
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.letterSpacing: 0.5 font.letterSpacing: 0.5
} }
@ -129,9 +130,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "24h" text: "24h"
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
@ -159,7 +160,7 @@ Column {
height: 24 height: 24
history: S.BatteryService.rateHistory history: S.BatteryService.rateHistory
strokeColor: root._stateColor strokeColor: root._stateColor
colorAt: v => v >= 0 ? S.Theme.base0B : root._stateColor colorAt: v => v >= 0 ? NS.ThemeService.base0B : root._stateColor
active: root.active active: root.active
maxValue: null maxValue: null
minValue: null minValue: null
@ -173,7 +174,7 @@ Column {
value: Math.round(S.BatteryService.healthPercent) + "%" value: Math.round(S.BatteryService.healthPercent) + "%"
valueColor: { valueColor: {
const h = S.BatteryService.healthPercent; const h = S.BatteryService.healthPercent;
return h < 50 ? S.Theme.base08 : h < 75 ? S.Theme.base0A : S.Theme.base0B; return h < 50 ? NS.ThemeService.base08 : h < 75 ? NS.ThemeService.base0A : NS.ThemeService.base0B;
} }
} }

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
// NOT safe for lock screen - can toggle bluetooth power and connect/disconnect devices // NOT safe for lock screen - can toggle bluetooth power and connect/disconnect devices
Column { Column {
@ -20,9 +21,9 @@ Column {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "\uF011" text: "\uF011"
color: S.BluetoothService.enabled ? root.accentColor : S.Theme.base04 color: S.BluetoothService.enabled ? root.accentColor : NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
@ -57,9 +58,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "\uF294" text: "\uF294"
color: entry._pending || entry.modelData.connected ? root.accentColor : S.Theme.base04 color: entry._pending || entry.modelData.connected ? root.accentColor : NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize + 1 font.pixelSize: NS.ThemeService.fontSize + 1
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
} }
Text { Text {
@ -69,9 +70,9 @@ Column {
anchors.rightMargin: 4 anchors.rightMargin: 4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: entry.modelData.name text: entry.modelData.name
color: entry._pending || entry.modelData.connected ? root.accentColor : S.Theme.base05 color: entry._pending || entry.modelData.connected ? root.accentColor : NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: entry.modelData.connected || entry._pending font.bold: entry.modelData.connected || entry._pending
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -82,9 +83,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: entry._pending ? (entry.modelData.connected ? "disconnecting..." : "connecting...") : (entry.modelData.battery >= 0 ? entry.modelData.battery + "%" : "") text: entry._pending ? (entry.modelData.connected ? "disconnecting..." : "connecting...") : (entry.modelData.battery >= 0 ? entry.modelData.battery + "%" : "")
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.italic: entry._pending font.italic: entry._pending
width: text ? implicitWidth : 0 width: text ? implicitWidth : 0
} }
@ -92,7 +93,7 @@ Column {
// Pulse animation while pending // Pulse animation while pending
SequentialAnimation on opacity { SequentialAnimation on opacity {
loops: Animation.Infinite loops: Animation.Infinite
running: entry._pending && !S.Theme.reducedMotion running: entry._pending && !S.ThemeUtil.reducedMotion
NumberAnimation { NumberAnimation {
to: 0.5 to: 0.5
duration: 400 duration: 400
@ -121,8 +122,8 @@ Column {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: S.BluetoothService.enabled ? "No paired devices" : "Bluetooth is off" text: S.BluetoothService.enabled ? "No paired devices" : "Bluetooth is off"
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Column { Column {
id: root id: root
@ -64,8 +65,8 @@ Column {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root._locale.standaloneMonthName(root._month, Locale.LongFormat) + " " + root._year text: root._locale.standaloneMonthName(root._month, Locale.LongFormat) + " " + root._year
color: root.accentColor color: root.accentColor
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
} }
@ -74,9 +75,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "W" + root._weekNumber(root.currentDate) text: "W" + root._weekNumber(root.currentDate)
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
@ -91,9 +92,9 @@ Column {
height: 18 height: 18
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
text: modelData text: modelData
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
} }
} }
@ -121,9 +122,9 @@ Column {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: modelData.day text: modelData.day
color: modelData.isToday ? S.Theme.base00 : modelData.isCurrentMonth ? S.Theme.base05 : S.Theme.base03 color: modelData.isToday ? NS.ThemeService.base00 : modelData.isCurrentMonth ? NS.ThemeService.base05 : NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: modelData.isToday font.bold: modelData.isToday
} }
} }
@ -136,9 +137,9 @@ Column {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
text: root.currentDate.toLocaleDateString(root._locale, Locale.LongFormat) text: root.currentDate.toLocaleDateString(root._locale, Locale.LongFormat)
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
Item { Item {

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Column { Column {
id: root id: root
@ -32,7 +33,7 @@ Column {
readonly property int _u: S.CpuService.cores[index]?.usage ?? 0 readonly property int _u: S.CpuService.cores[index]?.usage ?? 0
readonly property real _f: S.CpuService.cores[index]?.freq_ghz ?? 0 readonly property real _f: S.CpuService.cores[index]?.freq_ghz ?? 0
readonly property color _barColor: S.Theme.loadColor(_u) readonly property color _barColor: S.ThemeUtil.loadColor(_u)
readonly property bool _throttled: { readonly property bool _throttled: {
const maxF = S.CpuService.coreMaxFreq[index] ?? 0; const maxF = S.CpuService.coreMaxFreq[index] ?? 0;
return maxF > 0 && _f < maxF * 0.85 && _u >= 60; return maxF > 0 && _f < maxF * 0.85 && _u >= 60;
@ -56,7 +57,7 @@ Column {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - 16 width: parent.width - 16
height: 1 height: 1
color: S.Theme.base03 color: NS.ThemeService.base03
} }
// Row content pinned to bottom of delegate // Row content pinned to bottom of delegate
@ -71,9 +72,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: index text: index
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
width: 16 width: 16
} }
@ -88,7 +89,7 @@ Column {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base02 color: NS.ThemeService.base02
radius: 2 radius: 2
} }
@ -115,7 +116,7 @@ Column {
height: 10 height: 10
history: S.CpuService.cores[parent.parent.index]?.history ?? [] history: S.CpuService.cores[parent.parent.index]?.history ?? []
strokeColor: parent.parent._barColor strokeColor: parent.parent._barColor
colorAt: v => S.Theme.loadColor(v) colorAt: v => S.ThemeUtil.loadColor(v)
active: root.active active: root.active
} }
@ -125,9 +126,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: parent.parent._f.toFixed(2) text: parent.parent._f.toFixed(2)
color: parent.parent._throttled ? S.Theme.base08 : S.Theme.base04 color: parent.parent._throttled ? NS.ThemeService.base08 : NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
width: 34 width: 34
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
} }
@ -141,7 +142,7 @@ Column {
InfoRow { InfoRow {
label: "Total" label: "Total"
value: S.CpuService.usage + "% @ " + S.CpuService.freqGhz.toFixed(2) + " GHz" value: S.CpuService.usage + "% @ " + S.CpuService.freqGhz.toFixed(2) + " GHz"
valueColor: S.Theme.loadColor(S.CpuService.usage) valueColor: S.ThemeUtil.loadColor(S.CpuService.usage)
} }
SparklineCanvas { SparklineCanvas {
@ -152,7 +153,7 @@ Column {
height: 32 height: 32
history: S.CpuService.history history: S.CpuService.history
strokeColor: root.accentColor strokeColor: root.accentColor
colorAt: v => S.Theme.loadColor(v) colorAt: v => S.ThemeUtil.loadColor(v)
active: root.active active: root.active
} }
@ -172,9 +173,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "PROCESS" text: "PROCESS"
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1 font.letterSpacing: 1
} }
@ -183,9 +184,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "CPU" text: "CPU"
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1 font.letterSpacing: 1
} }
} }
@ -203,9 +204,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: modelData.cmd text: modelData.cmd
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
elide: Text.ElideRight elide: Text.ElideRight
width: parent.width - 80 width: parent.width - 80
} }
@ -215,9 +216,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: modelData.cpu.toFixed(1) + "%" text: modelData.cpu.toFixed(1) + "%"
color: S.Theme.loadColor(modelData.cpu) color: S.ThemeUtil.loadColor(modelData.cpu)
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
width: 36 width: 36
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
} }

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Column { Column {
id: root id: root
@ -31,9 +32,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: modelData.target text: modelData.target
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
elide: Text.ElideRight elide: Text.ElideRight
width: 72 width: 72
} }
@ -49,14 +50,14 @@ Column {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base02 color: NS.ThemeService.base02
radius: 2 radius: 2
} }
Rectangle { Rectangle {
width: parent.width * (modelData.pct / 100) width: parent.width * (modelData.pct / 100)
height: parent.height height: parent.height
color: S.Theme.loadColor(modelData.pct) color: S.ThemeUtil.loadColor(modelData.pct)
radius: 2 radius: 2
Behavior on width { Behavior on width {
NumberAnimation { NumberAnimation {
@ -72,9 +73,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root._fmt(modelData.usedBytes) + "/" + root._fmt(modelData.totalBytes) text: root._fmt(modelData.usedBytes) + "/" + root._fmt(modelData.totalBytes)
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
width: 72 width: 72
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
} }

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Column { Column {
id: root id: root
@ -22,9 +23,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: S.SystemStats.gpuVendor.toUpperCase() text: S.SystemStats.gpuVendor.toUpperCase()
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1 font.letterSpacing: 1
} }
@ -33,9 +34,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: S.SystemStats.gpuUsage + "%" text: S.SystemStats.gpuUsage + "%"
color: S.Theme.loadColor(S.SystemStats.gpuUsage) color: S.ThemeUtil.loadColor(S.SystemStats.gpuUsage)
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
} }
} }
@ -55,14 +56,14 @@ Column {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base02 color: NS.ThemeService.base02
radius: 3 radius: 3
} }
Rectangle { Rectangle {
width: parent.width * Math.min(1, S.SystemStats.gpuUsage / 100) width: parent.width * Math.min(1, S.SystemStats.gpuUsage / 100)
height: parent.height height: parent.height
color: S.Theme.loadColor(S.SystemStats.gpuUsage) color: S.ThemeUtil.loadColor(S.SystemStats.gpuUsage)
radius: 3 radius: 3
Behavior on width { Behavior on width {
enabled: root.active enabled: root.active
@ -84,7 +85,7 @@ Column {
height: 32 height: 32
history: S.SystemStats.gpuHistory history: S.SystemStats.gpuHistory
strokeColor: root.accentColor strokeColor: root.accentColor
colorAt: v => S.Theme.loadColor(v) colorAt: v => S.ThemeUtil.loadColor(v)
active: root.active active: root.active
} }
@ -100,9 +101,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "VRAM" text: "VRAM"
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1 font.letterSpacing: 1
} }
@ -112,8 +113,8 @@ Column {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root._fmt(S.SystemStats.gpuVramUsedGb) + " / " + root._fmt(S.SystemStats.gpuVramTotalGb) text: root._fmt(S.SystemStats.gpuVramUsedGb) + " / " + root._fmt(S.SystemStats.gpuVramTotalGb)
color: root.accentColor color: root.accentColor
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
} }
} }
@ -132,7 +133,7 @@ Column {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base02 color: NS.ThemeService.base02
radius: 2 radius: 2
} }
@ -158,7 +159,7 @@ Column {
height: 22 height: 22
label: "Temp" label: "Temp"
value: S.SystemStats.gpuTempC + "\u00B0C" value: S.SystemStats.gpuTempC + "\u00B0C"
valueColor: S.SystemStats.gpuTempC > S.Modules.gpu.hot ? S.Theme.base08 : S.SystemStats.gpuTempC > S.Modules.gpu.warm ? S.Theme.base0A : S.Theme.base05 valueColor: S.SystemStats.gpuTempC > NS.ModulesService.gpuHot ? NS.ThemeService.base08 : S.SystemStats.gpuTempC > NS.ModulesService.gpuWarm ? NS.ThemeService.base0A : NS.ThemeService.base05
} }
Item { Item {

View file

@ -1,12 +1,13 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "../services" as S import "../services" as S
import NovaStats as NS
Item { Item {
id: root id: root
property bool running: false property bool running: false
property bool reducedMotion: S.Theme.reducedMotion property bool reducedMotion: S.ThemeUtil.reducedMotion
readonly property real wavePhase: fx.uWavePhase readonly property real wavePhase: fx.uWavePhase
ShaderEffect { ShaderEffect {
@ -22,9 +23,9 @@ Item {
property real uGlitch: 0 property real uGlitch: 0
property real uGlitchSeed: 0.0 property real uGlitchSeed: 0.0
property vector4d uResolution: Qt.vector4d(width, height, 0, 0) property vector4d uResolution: Qt.vector4d(width, height, 0, 0)
property color uC0: S.Theme.base0C property color uC0: NS.ThemeService.base0C
property color uC1: S.Theme.base0E property color uC1: NS.ThemeService.base0E
property color uC2: S.Theme.base09 property color uC2: NS.ThemeService.base09
Connections { Connections {
target: root target: root

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Item { Item {
id: root id: root
@ -14,8 +15,8 @@ Item {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 4 anchors.leftMargin: 4
anchors.rightMargin: 4 anchors.rightMargin: 4
color: root.hovered ? S.Theme.base02 : "transparent" color: root.hovered ? NS.ThemeService.base02 : "transparent"
radius: S.Theme.radius radius: NS.ThemeService.radius
z: -1 z: -1
} }

View file

@ -1,12 +1,13 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Item { Item {
id: root id: root
required property string label required property string label
required property string value required property string value
property color valueColor: S.Theme.base05 property color valueColor: NS.ThemeService.base05
width: parent?.width ?? 0 width: parent?.width ?? 0
height: 18 height: 18
@ -16,9 +17,9 @@ Item {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.label text: root.label
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
Text { Text {
@ -27,7 +28,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.value text: root.value
color: root.valueColor color: root.valueColor
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }

View file

@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Column { Column {
id: root id: root
@ -20,8 +21,8 @@ Column {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 4 anchors.leftMargin: 4
anchors.rightMargin: 4 anchors.rightMargin: 4
color: _localHdrHover.hovered ? S.Theme.base02 : "transparent" color: _localHdrHover.hovered ? NS.ThemeService.base02 : "transparent"
radius: S.Theme.radius radius: NS.ThemeService.radius
z: -1 z: -1
} }
@ -34,9 +35,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: " localhost" text: " localhost"
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
Rectangle { Rectangle {
@ -48,10 +49,10 @@ Column {
color: { color: {
const st = S.SystemdService.systemState; const st = S.SystemdService.systemState;
if (st === "running") if (st === "running")
return S.Theme.base0B; return NS.ThemeService.base0B;
if (st === "degraded") if (st === "degraded")
return S.Theme.base0A; return NS.ThemeService.base0A;
return S.Theme.base08; return NS.ThemeService.base08;
} }
opacity: 0.85 opacity: 0.85
radius: 3 radius: 3
@ -62,9 +63,9 @@ Column {
id: _localStateLbl id: _localStateLbl
anchors.centerIn: parent anchors.centerIn: parent
text: S.SystemdService.systemState text: S.SystemdService.systemState
color: S.Theme.base00 color: NS.ThemeService.base00
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
@ -74,9 +75,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root._localExpanded ? "" : "" text: root._localExpanded ? "" : ""
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
} }
TapHandler { TapHandler {
@ -99,9 +100,9 @@ Column {
anchors.leftMargin: 24 anchors.leftMargin: 24
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "SYSTEM" text: "SYSTEM"
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1 font.letterSpacing: 1
} }
} }
@ -126,9 +127,9 @@ Column {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "no failures" text: "no failures"
color: S.Theme.base0B color: NS.ThemeService.base0B
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
@ -142,9 +143,9 @@ Column {
anchors.leftMargin: 24 anchors.leftMargin: 24
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "USER" text: "USER"
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1 font.letterSpacing: 1
} }
} }
@ -169,9 +170,9 @@ Column {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "no failures" text: "no failures"
color: S.Theme.base0B color: NS.ThemeService.base0B
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
} }
@ -209,8 +210,8 @@ Column {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 4 anchors.leftMargin: 4
anchors.rightMargin: 4 anchors.rightMargin: 4
color: _mHdrHover.hovered ? S.Theme.base02 : "transparent" color: _mHdrHover.hovered ? NS.ThemeService.base02 : "transparent"
radius: S.Theme.radius radius: NS.ThemeService.radius
z: -1 z: -1
} }
@ -223,9 +224,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: " " + _machineSection.modelData.name text: " " + _machineSection.modelData.name
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
elide: Text.ElideRight elide: Text.ElideRight
width: parent.width - 100 width: parent.width - 100
} }
@ -239,10 +240,10 @@ Column {
color: { color: {
const st = S.MachinectlService.machineState(_machineSection.modelData.name); const st = S.MachinectlService.machineState(_machineSection.modelData.name);
if (st === "running") if (st === "running")
return S.Theme.base0B; return NS.ThemeService.base0B;
if (st === "degraded") if (st === "degraded")
return S.Theme.base0A; return NS.ThemeService.base0A;
return st === "unknown" ? "transparent" : S.Theme.base08; return st === "unknown" ? "transparent" : NS.ThemeService.base08;
} }
opacity: 0.85 opacity: 0.85
radius: 3 radius: 3
@ -253,9 +254,9 @@ Column {
id: _mStateLbl id: _mStateLbl
anchors.centerIn: parent anchors.centerIn: parent
text: S.MachinectlService.machineState(_machineSection.modelData.name) text: S.MachinectlService.machineState(_machineSection.modelData.name)
color: S.Theme.base00 color: NS.ThemeService.base00
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
@ -265,9 +266,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: _machineSection._expanded ? "" : "" text: _machineSection._expanded ? "" : ""
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
} }
TapHandler { TapHandler {
@ -293,9 +294,9 @@ Column {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "loading..." text: "loading..."
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
@ -310,9 +311,9 @@ Column {
anchors.leftMargin: 24 anchors.leftMargin: 24
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "SYSTEM" text: "SYSTEM"
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1 font.letterSpacing: 1
} }
} }
@ -337,9 +338,9 @@ Column {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "no failures" text: "no failures"
color: S.Theme.base0B color: NS.ThemeService.base0B
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
} }

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Column { Column {
id: root id: root
@ -35,7 +36,7 @@ Column {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base02 color: NS.ThemeService.base02
radius: 3 radius: 3
} }
@ -43,7 +44,7 @@ Column {
Rectangle { Rectangle {
width: parent.width * Math.min(1, (root.usedGb + root.cachedGb) / Math.max(root.totalGb, 0.001)) width: parent.width * Math.min(1, (root.usedGb + root.cachedGb) / Math.max(root.totalGb, 0.001))
height: parent.height height: parent.height
color: S.Theme.base0D color: NS.ThemeService.base0D
opacity: 0.4 opacity: 0.4
radius: 3 radius: 3
Behavior on width { Behavior on width {
@ -97,7 +98,7 @@ Column {
height: 32 height: 32
history: S.SystemStats.memHistory history: S.SystemStats.memHistory
strokeColor: root.accentColor strokeColor: root.accentColor
colorAt: v => S.Theme.loadColor(v) colorAt: v => S.ThemeUtil.loadColor(v)
active: root.active active: root.active
} }
@ -117,9 +118,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "PROCESS" text: "PROCESS"
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1 font.letterSpacing: 1
} }
@ -128,9 +129,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "MEM" text: "MEM"
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1 font.letterSpacing: 1
} }
} }
@ -148,9 +149,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: modelData.cmd text: modelData.cmd
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
elide: Text.ElideRight elide: Text.ElideRight
width: parent.width - 80 width: parent.width - 80
} }
@ -160,9 +161,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: modelData.mem.toFixed(1) + "%" text: modelData.mem.toFixed(1) + "%"
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
width: 36 width: 36
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
} }

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Column { Column {
id: root id: root
@ -15,7 +16,7 @@ Column {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base02 color: NS.ThemeService.base02
} }
// Outgoing art - snaps to current opacity, then fades out // Outgoing art - snaps to current opacity, then fades out
@ -132,7 +133,7 @@ Column {
} }
GradientStop { GradientStop {
position: 1 position: 1
color: S.Theme.base01 color: NS.ThemeService.base01
} }
} }
} }
@ -140,9 +141,9 @@ Column {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "\uF001" text: "\uF001"
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: 28 font.pixelSize: 28
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
visible: !_artImg._hasArt visible: !_artImg._hasArt
} }
} }
@ -164,9 +165,9 @@ Column {
Text { Text {
width: parent.width width: parent.width
text: S.MprisService.player?.trackTitle || "No track" text: S.MprisService.player?.trackTitle || "No track"
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize + 1 font.pixelSize: NS.ThemeService.fontSize + 1
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -180,9 +181,9 @@ Column {
const artist = Array.isArray(p.trackArtists) ? p.trackArtists.join(", ") : (p.trackArtists || ""); const artist = Array.isArray(p.trackArtists) ? p.trackArtists.join(", ") : (p.trackArtists || "");
return [artist, p.trackAlbum].filter(s => s).join(" \u2014 "); return [artist, p.trackAlbum].filter(s => s).join(" \u2014 ");
} }
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
elide: Text.ElideRight elide: Text.ElideRight
visible: text !== "" visible: text !== ""
} }
@ -209,18 +210,18 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: parent._fmtTime(parent.pos) text: parent._fmtTime(parent.pos)
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
Text { Text {
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: parent._fmtTime(parent.dur) text: parent._fmtTime(parent.dur)
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
Item { Item {
@ -231,7 +232,7 @@ Column {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base02 color: NS.ThemeService.base02
radius: 2 radius: 2
} }
Rectangle { Rectangle {
@ -254,9 +255,9 @@ Column {
Text { Text {
text: "\uF048" text: "\uF048"
color: S.MprisService.player?.canGoPrevious ? S.Theme.base05 : S.Theme.base03 color: S.MprisService.player?.canGoPrevious ? NS.ThemeService.base05 : NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize + 4 font.pixelSize: NS.ThemeService.fontSize + 4
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
HoverHandler { HoverHandler {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
@ -270,8 +271,8 @@ Column {
Text { Text {
text: S.MprisService.playing ? "\uF04C" : "\uF04B" text: S.MprisService.playing ? "\uF04C" : "\uF04B"
color: root.accentColor color: root.accentColor
font.pixelSize: S.Theme.fontSize + 8 font.pixelSize: NS.ThemeService.fontSize + 8
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
HoverHandler { HoverHandler {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
@ -283,9 +284,9 @@ Column {
Text { Text {
text: "\uF051" text: "\uF051"
color: S.MprisService.player?.canGoNext ? S.Theme.base05 : S.Theme.base03 color: S.MprisService.player?.canGoNext ? NS.ThemeService.base05 : NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize + 4 font.pixelSize: NS.ThemeService.fontSize + 4
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
HoverHandler { HoverHandler {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
@ -323,17 +324,17 @@ Column {
width: _pLabel.implicitWidth + 12 width: _pLabel.implicitWidth + 12
height: 18 height: 18
radius: 9 radius: 9
color: _active ? S.Theme.base02 : (pHover.hovered ? S.Theme.base02 : "transparent") color: _active ? NS.ThemeService.base02 : (pHover.hovered ? NS.ThemeService.base02 : "transparent")
border.color: _active ? root.accentColor : S.Theme.base03 border.color: _active ? root.accentColor : NS.ThemeService.base03
border.width: _active ? 1 : 0 border.width: _active ? 1 : 0
Text { Text {
id: _pLabel id: _pLabel
anchors.centerIn: parent anchors.centerIn: parent
text: modelData.identity ?? "Player" text: modelData.identity ?? "Player"
color: _active ? root.accentColor : S.Theme.base04 color: _active ? root.accentColor : NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: _active font.bold: _active
} }

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
// NOT safe for lock screen - can toggle wifi and connect/disconnect networks // NOT safe for lock screen - can toggle wifi and connect/disconnect networks
Column { Column {
@ -20,9 +21,9 @@ Column {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "\uF011" text: "\uF011"
color: S.NetworkService.wifiEnabled ? root.accentColor : S.Theme.base04 color: S.NetworkService.wifiEnabled ? root.accentColor : NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
@ -55,9 +56,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: entry.modelData.isWifi ? "\uF1EB" : "\uDB80\uDE00" text: entry.modelData.isWifi ? "\uF1EB" : "\uDB80\uDE00"
color: entry.modelData.active ? root.accentColor : S.Theme.base05 color: entry.modelData.active ? root.accentColor : NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize + 1 font.pixelSize: NS.ThemeService.fontSize + 1
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
} }
Text { Text {
@ -67,9 +68,9 @@ Column {
anchors.rightMargin: 4 anchors.rightMargin: 4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: entry.modelData.name text: entry.modelData.name
color: entry.modelData.active ? root.accentColor : S.Theme.base05 color: entry.modelData.active ? root.accentColor : NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: entry.modelData.active font.bold: entry.modelData.active
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -80,9 +81,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: entry.modelData.signal >= 0 ? entry.modelData.signal + "%" : "" text: entry.modelData.signal >= 0 ? entry.modelData.signal + "%" : ""
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
width: entry.modelData.signal >= 0 ? implicitWidth : 0 width: entry.modelData.signal >= 0 ? implicitWidth : 0
} }
@ -102,8 +103,8 @@ Column {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: S.NetworkService.wifiEnabled ? "No networks available" : "Wi-Fi is off" text: S.NetworkService.wifiEnabled ? "No networks available" : "Wi-Fi is off"
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }

View file

@ -1,6 +1,7 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import "../modules" as M import "../modules" as M
import NovaStats as NS
// NOT safe for lock screen - notification contents may be sensitive, // NOT safe for lock screen - notification contents may be sensitive,
// can dismiss/clear notifications and toggle DND // can dismiss/clear notifications and toggle DND
@ -21,9 +22,9 @@ Column {
// Clear all // Clear all
Text { Text {
text: "\uF1F8" text: "\uF1F8"
color: _clearHover.hovered ? S.Theme.base08 : S.Theme.base04 color: _clearHover.hovered ? NS.ThemeService.base08 : NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
visible: S.NotifService.count > 0 visible: S.NotifService.count > 0
HoverHandler { HoverHandler {
@ -38,9 +39,9 @@ Column {
// DND toggle // DND toggle
Text { Text {
text: S.NotifService.dnd ? "\uDB82\uDE93" : "\uDB80\uDC9C" text: S.NotifService.dnd ? "\uDB82\uDE93" : "\uDB80\uDC9C"
color: S.NotifService.dnd ? S.Theme.base09 : S.Theme.base04 color: S.NotifService.dnd ? NS.ThemeService.base09 : NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
HoverHandler { HoverHandler {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
@ -201,7 +202,7 @@ Column {
ListView { ListView {
id: _notifList id: _notifList
width: root.contentWidth width: root.contentWidth
height: Math.min(contentHeight, 60 * (S.Modules.notifications.maxVisible || 10)) height: Math.min(contentHeight, 60 * (NS.ModulesService.notificationsMaxVisible || 10))
clip: true clip: true
boundsBehavior: Flickable.StopAtBounds boundsBehavior: Flickable.StopAtBounds
model: root._flatModel model: root._flatModel
@ -228,7 +229,7 @@ Column {
readonly property real _targetHeight: { readonly property real _targetHeight: {
if (_type === "header") if (_type === "header")
return modelData.collapsed ? (28 + modelData.count * (S.Theme.fontSize + 4)) : 28; return modelData.collapsed ? (28 + modelData.count * (NS.ThemeService.fontSize + 4)) : 28;
return _notifCard.implicitHeight; return _notifCard.implicitHeight;
} }
@ -298,12 +299,12 @@ Column {
anchors.leftMargin: 10 anchors.leftMargin: 10
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: (28 - height) / 2 anchors.topMargin: (28 - height) / 2
width: S.Theme.fontSize + 2 width: NS.ThemeService.fontSize + 2
height: S.Theme.fontSize + 2 height: NS.ThemeService.fontSize + 2
source: notifDelegate._type === "header" ? (notifDelegate.modelData.resolvedIcon || "") : "" source: notifDelegate._type === "header" ? (notifDelegate.modelData.resolvedIcon || "") : ""
visible: status === Image.Ready visible: status === Image.Ready
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
sourceSize: Qt.size(S.Theme.fontSize + 2, S.Theme.fontSize + 2) sourceSize: Qt.size(NS.ThemeService.fontSize + 2, NS.ThemeService.fontSize + 2)
asynchronous: true asynchronous: true
} }
@ -315,9 +316,9 @@ Column {
height: 28 height: 28
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: notifDelegate._type === "header" && notifDelegate.modelData.collapsed ? "\u25B8" : "\u25BE" text: notifDelegate._type === "header" && notifDelegate.modelData.collapsed ? "\u25B8" : "\u25BE"
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
opacity: _headerHover.hovered ? 1 : 0 opacity: _headerHover.hovered ? 1 : 0
} }
@ -330,9 +331,9 @@ Column {
height: 28 height: 28
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: notifDelegate._type === "header" ? (notifDelegate.modelData.appName || "Unknown") : "" text: notifDelegate._type === "header" ? (notifDelegate.modelData.appName || "Unknown") : ""
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -345,9 +346,9 @@ Column {
height: 28 height: 28
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: "\uF1F8" text: "\uF1F8"
color: _groupDismissHover.hovered ? S.Theme.base08 : S.Theme.base04 color: _groupDismissHover.hovered ? NS.ThemeService.base08 : NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
opacity: _headerHover.hovered ? 1 : 0 opacity: _headerHover.hovered ? 1 : 0
HoverHandler { HoverHandler {
@ -373,14 +374,14 @@ Column {
anchors.leftMargin: 10 anchors.leftMargin: 10
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 10 anchors.rightMargin: 10
y: 28 + index * (S.Theme.fontSize + 4) y: 28 + index * (NS.ThemeService.fontSize + 4)
height: S.Theme.fontSize + 4 height: NS.ThemeService.fontSize + 4
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: modelData text: modelData
elide: Text.ElideRight elide: Text.ElideRight
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
color: S.Theme.base04 color: NS.ThemeService.base04
} }
} }
} }
@ -442,8 +443,8 @@ Column {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: "No notifications" text: "No notifications"
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }

View file

@ -1,6 +1,7 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "../services" as S import "../services" as S
import NovaStats as NS
// NOT safe for lock screen - executes system commands (shutdown, reboot, logout, suspend) // NOT safe for lock screen - executes system commands (shutdown, reboot, logout, suspend)
Column { Column {
@ -42,35 +43,35 @@ Column {
label: "Lock", label: "Lock",
icon: "\uF023", icon: "\uF023",
cmd: ["loginctl", "lock-session"], cmd: ["loginctl", "lock-session"],
color: S.Theme.base0D, color: NS.ThemeService.base0D,
confirm: false confirm: false
}, },
{ {
label: "Suspend", label: "Suspend",
icon: "\uF186", icon: "\uF186",
cmd: ["systemctl", "suspend"], cmd: ["systemctl", "suspend"],
color: S.Theme.base0E, color: NS.ThemeService.base0E,
confirm: false confirm: false
}, },
{ {
label: "Logout", label: "Logout",
icon: "\uF2F5", icon: "\uF2F5",
cmd: root._isNiri ? ["niri", "msg", "action", "quit"] : ["loginctl", "terminate-user", ""], cmd: root._isNiri ? ["niri", "msg", "action", "quit"] : ["loginctl", "terminate-user", ""],
color: S.Theme.base0A, color: NS.ThemeService.base0A,
confirm: false confirm: false
}, },
{ {
label: "Reboot", label: "Reboot",
icon: "\uF021", icon: "\uF021",
cmd: ["systemctl", "reboot"], cmd: ["systemctl", "reboot"],
color: S.Theme.base09, color: NS.ThemeService.base09,
confirm: true confirm: true
}, },
{ {
label: "Shutdown", label: "Shutdown",
icon: "\uF011", icon: "\uF011",
cmd: ["systemctl", "poweroff"], cmd: ["systemctl", "poweroff"],
color: S.Theme.base08, color: NS.ThemeService.base08,
confirm: true confirm: true
} }
] ]
@ -88,8 +89,8 @@ Column {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 4 anchors.leftMargin: 4
anchors.rightMargin: 4 anchors.rightMargin: 4
color: entryHover.hovered ? S.Theme.base02 : "transparent" color: entryHover.hovered ? NS.ThemeService.base02 : "transparent"
radius: S.Theme.radius radius: NS.ThemeService.radius
} }
Text { Text {
@ -99,8 +100,8 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
text: entry.modelData.icon text: entry.modelData.icon
color: entry.modelData.color color: entry.modelData.color
font.pixelSize: S.Theme.fontSize + 1 font.pixelSize: NS.ThemeService.fontSize + 1
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
} }
Text { Text {
@ -108,9 +109,9 @@ Column {
anchors.left: entryIcon.right anchors.left: entryIcon.right
anchors.leftMargin: 10 anchors.leftMargin: 10
text: entry.modelData.label text: entry.modelData.label
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
HoverHandler { HoverHandler {
@ -138,9 +139,9 @@ Column {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: root._confirmItem ? root._confirmItem.label + "?" : "" text: root._confirmItem ? root._confirmItem.label + "?" : ""
color: root._confirmItem ? root._confirmItem.color : S.Theme.base05 color: root._confirmItem ? root._confirmItem.color : NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
} }
} }
@ -155,18 +156,18 @@ Column {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: cancelHover.hovered ? S.Theme.base02 : S.Theme.base01 color: cancelHover.hovered ? NS.ThemeService.base02 : NS.ThemeService.base01
radius: S.Theme.radius radius: NS.ThemeService.radius
border.width: 1 border.width: 1
border.color: S.Theme.base03 border.color: NS.ThemeService.base03
} }
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "Cancel" text: "Cancel"
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
HoverHandler { HoverHandler {
@ -187,21 +188,21 @@ Column {
anchors.fill: parent anchors.fill: parent
color: { color: {
if (!root._confirmItem) if (!root._confirmItem)
return S.Theme.base02; return NS.ThemeService.base02;
const c = root._confirmItem.color; const c = root._confirmItem.color;
return confirmHover.hovered ? Qt.rgba(c.r, c.g, c.b, 0.3) : Qt.rgba(c.r, c.g, c.b, 0.15); return confirmHover.hovered ? Qt.rgba(c.r, c.g, c.b, 0.3) : Qt.rgba(c.r, c.g, c.b, 0.15);
} }
radius: S.Theme.radius radius: NS.ThemeService.radius
border.width: 1 border.width: 1
border.color: root._confirmItem ? root._confirmItem.color : S.Theme.base03 border.color: root._confirmItem ? root._confirmItem.color : NS.ThemeService.base03
} }
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "Confirm" text: "Confirm"
color: root._confirmItem ? root._confirmItem.color : S.Theme.base05 color: root._confirmItem ? root._confirmItem.color : NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
} }

View file

@ -1,9 +1,10 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Rectangle { Rectangle {
width: (parent?.width ?? 16) - 16 width: (parent?.width ?? 16) - 16
height: 1 height: 1
anchors.horizontalCenter: parent?.horizontalCenter anchors.horizontalCenter: parent?.horizontalCenter
color: S.Theme.base03 color: NS.ThemeService.base03
} }

View file

@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Column { Column {
id: root id: root
@ -21,9 +22,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "SYSTEM" text: "SYSTEM"
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1 font.letterSpacing: 1
} }
@ -35,10 +36,10 @@ Column {
color: { color: {
const st = S.SystemdService.systemState; const st = S.SystemdService.systemState;
if (st === "running") if (st === "running")
return S.Theme.base0B; return NS.ThemeService.base0B;
if (st === "degraded") if (st === "degraded")
return S.Theme.base0A; return NS.ThemeService.base0A;
return S.Theme.base08; return NS.ThemeService.base08;
} }
opacity: 0.85 opacity: 0.85
radius: 3 radius: 3
@ -49,9 +50,9 @@ Column {
id: _sysStateLbl id: _sysStateLbl
anchors.centerIn: parent anchors.centerIn: parent
text: S.SystemdService.systemState text: S.SystemdService.systemState
color: S.Theme.base00 color: NS.ThemeService.base00
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
} }
@ -79,9 +80,9 @@ Column {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "no failed system units" text: "no failed system units"
color: S.Theme.base0B color: NS.ThemeService.base0B
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
@ -97,9 +98,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "USER" text: "USER"
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1 font.letterSpacing: 1
} }
@ -111,10 +112,10 @@ Column {
color: { color: {
const st = S.SystemdService.userState; const st = S.SystemdService.userState;
if (st === "running") if (st === "running")
return S.Theme.base0B; return NS.ThemeService.base0B;
if (st === "degraded") if (st === "degraded")
return S.Theme.base0A; return NS.ThemeService.base0A;
return S.Theme.base08; return NS.ThemeService.base08;
} }
opacity: 0.85 opacity: 0.85
radius: 3 radius: 3
@ -125,9 +126,9 @@ Column {
id: _userStateLbl id: _userStateLbl
anchors.centerIn: parent anchors.centerIn: parent
text: S.SystemdService.userState text: S.SystemdService.userState
color: S.Theme.base00 color: NS.ThemeService.base00
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
} }
@ -155,9 +156,9 @@ Column {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "no failed user units" text: "no failed user units"
color: S.Theme.base0B color: NS.ThemeService.base0B
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Item { Item {
id: root id: root
@ -72,8 +73,8 @@ Item {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 4 anchors.leftMargin: 4
anchors.rightMargin: 4 anchors.rightMargin: 4
color: _rowHover.hovered ? S.Theme.base02 : "transparent" color: _rowHover.hovered ? NS.ThemeService.base02 : "transparent"
radius: S.Theme.radius radius: NS.ThemeService.radius
z: -1 z: -1
} }
@ -88,9 +89,9 @@ Item {
anchors.rightMargin: 6 anchors.rightMargin: 6
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.unitName text: root.unitName
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -99,7 +100,7 @@ Item {
anchors.right: _restartBtn.left anchors.right: _restartBtn.left
anchors.rightMargin: 6 anchors.rightMargin: 6
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: S.Theme.base08 color: NS.ThemeService.base08
opacity: 0.85 opacity: 0.85
radius: 3 radius: 3
width: _subStateLbl.width + 8 width: _subStateLbl.width + 8
@ -109,9 +110,9 @@ Item {
id: _subStateLbl id: _subStateLbl
anchors.centerIn: parent anchors.centerIn: parent
text: root.subState text: root.subState
color: S.Theme.base00 color: NS.ThemeService.base00
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
@ -127,9 +128,9 @@ Item {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "" text: ""
color: _rHover.hovered ? root.accentColor : S.Theme.base04 color: _rHover.hovered ? root.accentColor : NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
duration: 80 duration: 80
@ -164,9 +165,9 @@ Item {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: root._expanded ? "" : "" text: root._expanded ? "" : ""
color: _expHover.hovered ? root.accentColor : S.Theme.base04 color: _expHover.hovered ? root.accentColor : NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
duration: 80 duration: 80
@ -202,16 +203,16 @@ Item {
anchors.leftMargin: 8 anchors.leftMargin: 8
anchors.rightMargin: 8 anchors.rightMargin: 8
anchors.bottomMargin: 4 anchors.bottomMargin: 4
color: S.Theme.base01 color: NS.ThemeService.base01
radius: S.Theme.radius radius: NS.ThemeService.radius
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
visible: root._loading visible: root._loading
text: "loading..." text: "loading..."
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
Flickable { Flickable {
@ -226,9 +227,9 @@ Item {
id: _jContent id: _jContent
width: _flick.width width: _flick.width
text: root._jText text: root._jText
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
wrapMode: Text.WrapAnywhere wrapMode: Text.WrapAnywhere
} }

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Column { Column {
id: root id: root
@ -14,7 +15,7 @@ Column {
property bool active: true property bool active: true
property string deviceFilter: "" property string deviceFilter: ""
property color stateColor: temp > hot ? S.Theme.base08 : temp > warm ? S.Theme.base0A : root.accentColor property color stateColor: temp > hot ? NS.ThemeService.base08 : temp > warm ? NS.ThemeService.base0A : root.accentColor
Behavior on stateColor { Behavior on stateColor {
ColorAnimation { ColorAnimation {
duration: 300 duration: 300
@ -32,8 +33,8 @@ Column {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.temp + "\u00B0C" text: root.temp + "\u00B0C"
color: root.stateColor color: root.stateColor
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
width: _tempSizer.implicitWidth width: _tempSizer.implicitWidth
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
@ -63,7 +64,7 @@ Column {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base02 color: NS.ThemeService.base02
radius: 3 radius: 3
} }
@ -87,7 +88,7 @@ Column {
width: 1 width: 1
height: parent.height + 4 height: parent.height + 4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: S.Theme.base0A color: NS.ThemeService.base0A
opacity: 0.6 opacity: 0.6
} }
@ -97,7 +98,7 @@ Column {
width: 1 width: 1
height: parent.height + 4 height: parent.height + 4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: S.Theme.base08 color: NS.ThemeService.base08
opacity: 0.6 opacity: 0.6
} }
} }
@ -116,11 +117,11 @@ Column {
thresholds: [ thresholds: [
{ {
value: root.warm, value: root.warm,
color: S.Theme.base0A color: NS.ThemeService.base0A
}, },
{ {
value: root.hot, value: root.hot,
color: S.Theme.base08 color: NS.ThemeService.base08
} }
] ]
} }
@ -135,9 +136,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "warm " + root.warm + "\u00B0 hot " + root.hot + "\u00B0" text: "warm " + root.warm + "\u00B0 hot " + root.hot + "\u00B0"
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.letterSpacing: 0.5 font.letterSpacing: 0.5
} }
@ -146,9 +147,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "10 min" text: "10 min"
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 3 font.pixelSize: NS.ThemeService.fontSize - 3
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
@ -179,9 +180,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: modelData.name text: modelData.name
color: _isActive ? root.accentColor : S.Theme.base04 color: _isActive ? root.accentColor : NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
elide: Text.ElideRight elide: Text.ElideRight
width: parent.width - 80 width: parent.width - 80
} }
@ -191,9 +192,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: modelData.celsius + "\u00B0C" text: modelData.celsius + "\u00B0C"
color: S.Theme.loadColor(modelData.celsius) color: S.ThemeUtil.loadColor(modelData.celsius)
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: _isActive font.bold: _isActive
} }
} }

View file

@ -1,6 +1,7 @@
import QtQuick import QtQuick
import Quickshell.Services.Pipewire import Quickshell.Services.Pipewire
import "../services" as S import "../services" as S
import NovaStats as NS
Column { Column {
id: root id: root
@ -11,7 +12,7 @@ Column {
property real volume: sink?.audio?.volume ?? 0 property real volume: sink?.audio?.volume ?? 0
property bool muted: sink?.audio?.muted ?? false property bool muted: sink?.audio?.muted ?? false
readonly property string volumeIcon: muted ? "\uF026" : (volume > 0.5 ? "\uF028" : (volume > 0 ? "\uF027" : "\uF026")) readonly property string volumeIcon: muted ? "\uF026" : (volume > 0.5 ? "\uF028" : (volume > 0 ? "\uF027" : "\uF026"))
readonly property color volumeColor: muted ? S.Theme.base04 : root.accentColor readonly property color volumeColor: muted ? NS.ThemeService.base04 : root.accentColor
// Slider row // Slider row
Item { Item {
@ -25,8 +26,8 @@ Column {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.volumeIcon text: root.volumeIcon
color: root.volumeColor color: root.volumeColor
font.pixelSize: S.Theme.fontSize + 2 font.pixelSize: NS.ThemeService.fontSize + 2
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
HoverHandler { HoverHandler {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
@ -48,7 +49,7 @@ Column {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base02 color: NS.ThemeService.base02
radius: 3 radius: 3
} }
Rectangle { Rectangle {
@ -86,9 +87,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: Math.round(root.volume * 100) + "%" text: Math.round(root.volume * 100) + "%"
color: root.muted ? S.Theme.base04 : S.Theme.base05 color: root.muted ? NS.ThemeService.base04 : NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
width: 30 width: 30
} }
} }
@ -113,8 +114,8 @@ Column {
leftPadding: 12 leftPadding: 12
text: "Output Devices" text: "Output Devices"
color: root.accentColor color: root.accentColor
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
Repeater { Repeater {
@ -134,9 +135,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: modelData.description || modelData.name || "Unknown" text: modelData.description || modelData.name || "Unknown"
color: parent._active ? root.accentColor : S.Theme.base05 color: parent._active ? root.accentColor : NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: parent._active font.bold: parent._active
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -159,8 +160,8 @@ Column {
leftPadding: 12 leftPadding: 12
text: "Applications" text: "Applications"
color: root.accentColor color: root.accentColor
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
Repeater { Repeater {
@ -183,9 +184,9 @@ Column {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: streamEntry._muted ? "\uF026" : "\uF028" text: streamEntry._muted ? "\uF026" : "\uF028"
color: streamEntry._muted ? S.Theme.base04 : S.Theme.base05 color: streamEntry._muted ? NS.ThemeService.base04 : NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
HoverHandler { HoverHandler {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
@ -202,9 +203,9 @@ Column {
anchors.leftMargin: 6 anchors.leftMargin: 6
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: streamEntry._appName text: streamEntry._appName
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
elide: Text.ElideRight elide: Text.ElideRight
width: 70 width: 70
} }
@ -220,13 +221,13 @@ Column {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base02 color: NS.ThemeService.base02
radius: 2 radius: 2
} }
Rectangle { Rectangle {
width: parent.width * Math.min(1, Math.max(0, streamEntry._vol)) width: parent.width * Math.min(1, Math.max(0, streamEntry._vol))
height: parent.height height: parent.height
color: streamEntry._muted ? S.Theme.base04 : root.accentColor color: streamEntry._muted ? NS.ThemeService.base04 : root.accentColor
radius: 2 radius: 2
} }
@ -253,9 +254,9 @@ Column {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: Math.round(streamEntry._vol * 100) + "%" text: Math.round(streamEntry._vol * 100) + "%"
color: streamEntry._muted ? S.Theme.base04 : S.Theme.base05 color: streamEntry._muted ? NS.ThemeService.base04 : NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
width: 28 width: 28
} }
} }

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Column { Column {
id: root id: root
@ -17,8 +18,8 @@ Column {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: S.WeatherService.icon text: S.WeatherService.icon
color: root.accentColor color: root.accentColor
font.pixelSize: S.Theme.fontSize + 2 font.pixelSize: NS.ThemeService.fontSize + 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
@ -28,9 +29,9 @@ Column {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
text: S.WeatherService.tooltip.replace(/\n/g, "<br>") text: S.WeatherService.tooltip.replace(/\n/g, "<br>")
textFormat: Text.RichText textFormat: Text.RichText
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
lineHeight: 1.3 lineHeight: 1.3
} }

View file

@ -7,6 +7,7 @@ import "." as D
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import "../modules" as M import "../modules" as M
import NovaStats as NS
PanelWindow { PanelWindow {
id: root id: root
@ -25,11 +26,10 @@ PanelWindow {
anchors.bottom: true anchors.bottom: true
// Counteract the bar's exclusive zone so the dock extends to the top of the screen // Counteract the bar's exclusive zone so the dock extends to the top of the screen
margins.top: -S.Theme.barHeight margins.top: -NS.ThemeService.barHeight
readonly property int _dockWidth: S.Modules.dock.width ?? 300 readonly property int _dockWidth: NS.ModulesService.dockWidth ?? 300
readonly property var _applets: S.Modules.dock.applets ?? {} readonly property color _accent: NS.ThemeService.base0C
readonly property color _accent: S.Theme.base0C
implicitWidth: _dockWidth implicitWidth: _dockWidth
@ -55,14 +55,14 @@ PanelWindow {
if (S.DockState.open) { if (S.DockState.open) {
root._winVisible = true; root._winVisible = true;
_hideAnim.stop(); _hideAnim.stop();
if (S.Theme.reducedMotion) { if (S.ThemeUtil.reducedMotion) {
root._slideX = 0; root._slideX = 0;
} else { } else {
_showAnim.start(); _showAnim.start();
} }
} else { } else {
_showAnim.stop(); _showAnim.stop();
if (S.Theme.reducedMotion) { if (S.ThemeUtil.reducedMotion) {
root._slideX = root._dockWidth; root._slideX = root._dockWidth;
root._winVisible = false; root._winVisible = false;
} else { } else {
@ -113,8 +113,8 @@ PanelWindow {
Rectangle { Rectangle {
id: _bg id: _bg
anchors.fill: parent anchors.fill: parent
color: S.Theme.base00 color: NS.ThemeService.base00
opacity: S.DockState.mode === "pinned" ? 1.0 : Math.max(S.Theme.barOpacity, 0.85) opacity: S.DockState.mode === "pinned" ? 1.0 : Math.max(NS.ThemeService.barOpacity, 0.85)
transform: Translate { transform: Translate {
x: root._slideX x: root._slideX
@ -128,7 +128,7 @@ PanelWindow {
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
width: 1 width: 1
color: S.Theme.base09 color: NS.ThemeService.base09
opacity: _bg.opacity opacity: _bg.opacity
transform: Translate { transform: Translate {
@ -142,7 +142,7 @@ PanelWindow {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
height: S.Theme.barHeight height: NS.ThemeService.barHeight
visible: S.DockState.mode === "pinned" visible: S.DockState.mode === "pinned"
transform: Translate { transform: Translate {
@ -151,7 +151,7 @@ PanelWindow {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base00 color: NS.ThemeService.base00
} }
// Bottom border - gradient matching bar style (base0C to base09, but just the right end) // Bottom border - gradient matching bar style (base0C to base09, but just the right end)
@ -160,7 +160,7 @@ PanelWindow {
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
height: 1 height: 1
color: S.Theme.base09 color: NS.ThemeService.base09
} }
// Dock toggle // Dock toggle
@ -185,7 +185,7 @@ PanelWindow {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.leftMargin: S.Theme.groupSpacing + 1 anchors.leftMargin: NS.ThemeService.groupSpacing + 1
contentHeight: _column.height contentHeight: _column.height
clip: true clip: true
boundsBehavior: Flickable.StopAtBounds boundsBehavior: Flickable.StopAtBounds
@ -205,7 +205,7 @@ PanelWindow {
// Clock // Clock
D.DockCard { D.DockCard {
visible: root._applets.clock ?? true visible: NS.ModulesService.dockAppletClock
icon: "\uF017" icon: "\uF017"
title: "Clock" title: "Clock"
accentColor: root._accent accentColor: root._accent
@ -221,7 +221,7 @@ PanelWindow {
// CPU // CPU
D.DockCard { D.DockCard {
id: _cpuCard id: _cpuCard
visible: root._applets.cpu ?? true visible: NS.ModulesService.dockAppletCpu
icon: "\uF2DB" icon: "\uF2DB"
title: "CPU" title: "CPU"
accentColor: root._accent accentColor: root._accent
@ -237,7 +237,7 @@ PanelWindow {
// GPU // GPU
D.DockCard { D.DockCard {
visible: (root._applets.gpu ?? true) && S.SystemStats.gpuAvailable visible: (NS.ModulesService.dockAppletGpu) && S.SystemStats.gpuAvailable
icon: "\uEB4C" icon: "\uEB4C"
title: "GPU" title: "GPU"
accentColor: root._accent accentColor: root._accent
@ -253,7 +253,7 @@ PanelWindow {
// Memory // Memory
D.DockCard { D.DockCard {
id: _memCard id: _memCard
visible: root._applets.memory ?? true visible: NS.ModulesService.dockAppletMemory
icon: "\uEFC5" icon: "\uEFC5"
title: "Memory" title: "Memory"
accentColor: root._accent accentColor: root._accent
@ -275,7 +275,7 @@ PanelWindow {
// Temperature // Temperature
D.DockCard { D.DockCard {
visible: root._applets.temperature ?? true visible: NS.ModulesService.dockAppletTemperature
icon: "\uF2C9" icon: "\uF2C9"
title: "Temperature" title: "Temperature"
accentColor: root._accent accentColor: root._accent
@ -284,19 +284,19 @@ PanelWindow {
C.TemperatureApplet { C.TemperatureApplet {
width: parent.width width: parent.width
temp: S.SystemStats.tempCelsius temp: S.SystemStats.tempCelsius
warm: S.Modules.temperature.warm || 80 warm: NS.ModulesService.temperatureWarm || 80
hot: S.Modules.temperature.hot || 90 hot: NS.ModulesService.temperatureHot || 90
history: S.SystemStats.tempHistory history: S.SystemStats.tempHistory
devices: S.SystemStats.tempDevices devices: S.SystemStats.tempDevices
accentColor: root._accent accentColor: root._accent
deviceFilter: S.Modules.temperature.device || "" deviceFilter: NS.ModulesService.temperatureDevice || ""
active: parent.expanded active: parent.expanded
} }
} }
// Disk // Disk
D.DockCard { D.DockCard {
visible: root._applets.disk ?? true visible: NS.ModulesService.dockAppletDisk
icon: "\uF0C9" icon: "\uF0C9"
title: "Disk" title: "Disk"
accentColor: root._accent accentColor: root._accent
@ -311,7 +311,7 @@ PanelWindow {
// Battery // Battery
D.DockCard { D.DockCard {
visible: (root._applets.battery ?? true) && S.BatteryService.available visible: (NS.ModulesService.dockAppletBattery) && S.BatteryService.available
icon: "\uDB80\uDC84" icon: "\uDB80\uDC84"
title: "Battery" title: "Battery"
accentColor: root._accent accentColor: root._accent
@ -326,7 +326,7 @@ PanelWindow {
// Network // Network
D.DockCard { D.DockCard {
visible: root._applets.network ?? true visible: NS.ModulesService.dockAppletNetwork
icon: "\uF1EB" icon: "\uF1EB"
title: "Network" title: "Network"
accentColor: root._accent accentColor: root._accent
@ -341,7 +341,7 @@ PanelWindow {
// Bluetooth // Bluetooth
D.DockCard { D.DockCard {
visible: (root._applets.bluetooth ?? true) && S.BluetoothService.state !== "unavailable" visible: (NS.ModulesService.dockAppletBluetooth) && S.BluetoothService.state !== "unavailable"
icon: "\uF294" icon: "\uF294"
title: "Bluetooth" title: "Bluetooth"
accentColor: root._accent accentColor: root._accent
@ -356,7 +356,7 @@ PanelWindow {
// Volume // Volume
D.DockCard { D.DockCard {
visible: root._applets.volume ?? true visible: NS.ModulesService.dockAppletVolume
icon: "\uF028" icon: "\uF028"
title: "Sound" title: "Sound"
accentColor: root._accent accentColor: root._accent
@ -370,7 +370,7 @@ PanelWindow {
// Backlight // Backlight
D.DockCard { D.DockCard {
visible: (root._applets.backlight ?? true) && S.BacklightService.available visible: (NS.ModulesService.dockAppletBacklight) && S.BacklightService.available
icon: "\uF185" icon: "\uF185"
title: "Brightness" title: "Brightness"
accentColor: root._accent accentColor: root._accent
@ -386,7 +386,7 @@ PanelWindow {
// Weather // Weather
D.DockCard { D.DockCard {
visible: (root._applets.weather ?? true) && S.WeatherService.available visible: (NS.ModulesService.dockAppletWeather) && S.WeatherService.available
icon: S.WeatherService.icon icon: S.WeatherService.icon
title: "Weather" title: "Weather"
accentColor: root._accent accentColor: root._accent
@ -400,7 +400,7 @@ PanelWindow {
// Now Playing // Now Playing
D.DockCard { D.DockCard {
visible: (root._applets.mpris ?? true) && S.MprisService.player !== null visible: (NS.ModulesService.dockAppletMpris) && S.MprisService.player !== null
icon: "\uF04B" icon: "\uF04B"
title: "Now Playing" title: "Now Playing"
accentColor: root._accent accentColor: root._accent
@ -414,7 +414,7 @@ PanelWindow {
// Notifications // Notifications
D.DockCard { D.DockCard {
visible: root._applets.notifications ?? true visible: NS.ModulesService.dockAppletNotifications
icon: "\uDB80\uDC9C" icon: "\uDB80\uDC9C"
title: "Notifications" title: "Notifications"
accentColor: root._accent accentColor: root._accent
@ -429,7 +429,7 @@ PanelWindow {
// Power // Power
D.DockCard { D.DockCard {
visible: root._applets.power ?? true visible: NS.ModulesService.dockAppletPower
icon: "\uF011" icon: "\uF011"
title: "Power" title: "Power"
accentColor: root._accent accentColor: root._accent

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
// Collapsible card for the applet dock. // Collapsible card for the applet dock.
// Set icon, title, and place applet content as children. // Set icon, title, and place applet content as children.
@ -9,20 +10,20 @@ Rectangle {
property string icon: "" property string icon: ""
property string title: "" property string title: ""
property bool expanded: false property bool expanded: false
property color accentColor: S.Theme.base0C property color accentColor: NS.ThemeService.base0C
default property alias content: _contentColumn.children default property alias content: _contentColumn.children
width: parent?.width ?? 300 width: parent?.width ?? 300
height: _header.height + (_contentColumn.visible ? _contentColumn.height : 0) height: _header.height + (_contentColumn.visible ? _contentColumn.height : 0)
radius: S.Theme.radius + 2 radius: NS.ThemeService.radius + 2
color: Qt.rgba(S.Theme.base01.r, S.Theme.base01.g, S.Theme.base01.b, 0.7) color: Qt.rgba(NS.ThemeService.base01.r, NS.ThemeService.base01.g, NS.ThemeService.base01.b, 0.7)
border.color: Qt.rgba(S.Theme.base03.r, S.Theme.base03.g, S.Theme.base03.b, 0.3) border.color: Qt.rgba(NS.ThemeService.base03.r, NS.ThemeService.base03.g, NS.ThemeService.base03.b, 0.3)
border.width: 1 border.width: 1
clip: true clip: true
Behavior on height { Behavior on height {
enabled: !S.Theme.reducedMotion enabled: !S.ThemeUtil.reducedMotion
NumberAnimation { NumberAnimation {
duration: 150 duration: 150
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
@ -41,8 +42,8 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.icon text: root.icon
color: root.accentColor color: root.accentColor
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
} }
Text { Text {
@ -50,10 +51,10 @@ Rectangle {
anchors.leftMargin: 30 anchors.leftMargin: 30
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.title text: root.title
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.bold: true font.bold: true
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
Text { Text {
@ -61,9 +62,9 @@ Rectangle {
anchors.rightMargin: 10 anchors.rightMargin: 10
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.expanded ? "\uF078" : "\uF054" text: root.expanded ? "\uF078" : "\uF054"
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
Behavior on text { Behavior on text {
enabled: false enabled: false
@ -84,7 +85,7 @@ Rectangle {
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
height: 1 height: 1
color: S.Theme.base03 color: NS.ThemeService.base03
opacity: root.expanded ? 0.5 : 0 opacity: root.expanded ? 0.5 : 0
} }
} }

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Item { Item {
id: root id: root
@ -15,7 +16,7 @@ Item {
property bool _revealed: false property bool _revealed: false
on_RawProgressChanged: if (_rawProgress >= 1) on_RawProgressChanged: if (_rawProgress >= 1)
_revealed = true _revealed = true
readonly property real _rawProgress: S.Theme.reducedMotion ? 1 : Math.max(0, Math.min(1, wavePhase / 300)) readonly property real _rawProgress: S.ThemeUtil.reducedMotion ? 1 : Math.max(0, Math.min(1, wavePhase / 300))
readonly property real _progress: (_revealed ? 1 : _rawProgress) * unlockFade readonly property real _progress: (_revealed ? 1 : _rawProgress) * unlockFade
opacity: _progress opacity: _progress
property real _slideX: (1 - _progress) * -80 property real _slideX: (1 - _progress) * -80
@ -53,32 +54,32 @@ Item {
Text { Text {
text: _clockRow._hours text: _clockRow._hours
color: S.Theme.base0C color: NS.ThemeService.base0C
font.pixelSize: root._fontSize font.pixelSize: root._fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
} }
Text { Text {
text: ":" text: ":"
color: S.Theme.base0E color: NS.ThemeService.base0E
font.pixelSize: root._fontSize font.pixelSize: root._fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
} }
Text { Text {
text: _clockRow._minutes text: _clockRow._minutes
color: S.Theme.base09 color: NS.ThemeService.base09
font.pixelSize: root._fontSize font.pixelSize: root._fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
} }
} }
Text { Text {
text: Qt.formatDate(new Date(), "dddd, d MMMM") text: Qt.formatDate(new Date(), "dddd, d MMMM")
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize + 2 font.pixelSize: NS.ThemeService.fontSize + 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
Timer { Timer {
interval: 60000 interval: 60000

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Item { Item {
id: root id: root
@ -15,18 +16,18 @@ Item {
anchors.fill: parent anchors.fill: parent
color: { color: {
if (root.state === "fail" || root.state === "error") if (root.state === "fail" || root.state === "error")
return Qt.rgba(S.Theme.base08.r, S.Theme.base08.g, S.Theme.base08.b, 0.15); return Qt.rgba(NS.ThemeService.base08.r, NS.ThemeService.base08.g, NS.ThemeService.base08.b, 0.15);
if (root.state === "busy") if (root.state === "busy")
return Qt.rgba(S.Theme.base0D.r, S.Theme.base0D.g, S.Theme.base0D.b, 0.1); return Qt.rgba(NS.ThemeService.base0D.r, NS.ThemeService.base0D.g, NS.ThemeService.base0D.b, 0.1);
return S.Theme.base02; return NS.ThemeService.base02;
} }
radius: height / 2 radius: height / 2
border.color: { border.color: {
if (root.state === "fail" || root.state === "error") if (root.state === "fail" || root.state === "error")
return S.Theme.base08; return NS.ThemeService.base08;
if (root.state === "busy") if (root.state === "busy")
return S.Theme.base0D; return NS.ThemeService.base0D;
return S.Theme.base03; return NS.ThemeService.base03;
} }
border.width: 1 border.width: 1
@ -52,9 +53,9 @@ Item {
return "Too many attempts"; return "Too many attempts";
return "Enter password"; return "Enter password";
} }
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
opacity: root.buffer.length === 0 ? 1 : 0 opacity: root.buffer.length === 0 ? 1 : 0
Behavior on opacity { Behavior on opacity {
@ -80,7 +81,7 @@ Item {
width: 10 width: 10
height: 10 height: 10
radius: 5 radius: 5
color: S.Theme.base05 color: NS.ThemeService.base05
scale: 0 scale: 0
opacity: 0 opacity: 0

View file

@ -1,11 +1,12 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
Row { Row {
id: root id: root
spacing: 6 spacing: 6
visible: (S.Modules.lock.notifications ?? true) && _notifGroups.length > 0 visible: (NS.ModulesService.lockNotifications ?? true) && _notifGroups.length > 0
readonly property var _notifGroups: { readonly property var _notifGroups: {
const notifs = S.NotifService.list.filter(n => n.state !== "dismissed"); const notifs = S.NotifService.list.filter(n => n.state !== "dismissed");
@ -34,8 +35,8 @@ Row {
width: _pillRow.implicitWidth + 12 width: _pillRow.implicitWidth + 12
height: 24 height: 24
radius: 12 radius: 12
color: Qt.rgba(S.Theme.base01.r, S.Theme.base01.g, S.Theme.base01.b, 0.7) color: Qt.rgba(NS.ThemeService.base01.r, NS.ThemeService.base01.g, NS.ThemeService.base01.b, 0.7)
border.color: Qt.rgba(S.Theme.base03.r, S.Theme.base03.g, S.Theme.base03.b, 0.3) border.color: Qt.rgba(NS.ThemeService.base03.r, NS.ThemeService.base03.g, NS.ThemeService.base03.b, 0.3)
border.width: 1 border.width: 1
HoverHandler { HoverHandler {
@ -48,9 +49,9 @@ Row {
anchors.bottom: parent.top anchors.bottom: parent.top
anchors.bottomMargin: 4 anchors.bottomMargin: 4
text: _pill.modelData.name || "" text: _pill.modelData.name || ""
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
visible: _pillHover.hovered && text !== "" visible: _pillHover.hovered && text !== ""
} }
@ -71,9 +72,9 @@ Row {
Text { Text {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: _pill.modelData.count > 1 ? _pill.modelData.count.toString() : "" text: _pill.modelData.count > 1 ? _pill.modelData.count.toString() : ""
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
visible: _pill.modelData.count > 1 visible: _pill.modelData.count > 1
} }
} }

View file

@ -4,6 +4,7 @@ import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
WlSessionLockSurface { WlSessionLockSurface {
id: root id: root
@ -11,7 +12,7 @@ WlSessionLockSurface {
required property WlSessionLock lock required property WlSessionLock lock
required property LockAuth auth required property LockAuth auth
color: S.Theme.base00 color: NS.ThemeService.base00
// Keyboard input via TextInput - engages Qt's full input pipeline including // Keyboard input via TextInput - engages Qt's full input pipeline including
// text-input protocol, which is more reliable than Keys on a plain Item in // text-input protocol, which is more reliable than Keys on a plain Item in
@ -47,7 +48,7 @@ WlSessionLockSurface {
// Threat level: eased curve so fails 1-2 are subtle, 3+ ramps up. // Threat level: eased curve so fails 1-2 are subtle, 3+ ramps up.
// Max ~0.6 at fail 5 (previously that was fail 3). // Max ~0.6 at fail 5 (previously that was fail 3).
readonly property bool _threatEnabled: S.Modules.lock.threatEffect ?? true readonly property bool _threatEnabled: NS.ModulesService.lockThreatEffect ?? true
readonly property real _threat: { readonly property real _threat: {
if (!_threatEnabled || root.auth.failCount <= 0) if (!_threatEnabled || root.auth.failCount <= 0)
return 0; return 0;
@ -68,7 +69,7 @@ WlSessionLockSurface {
layer.effect: ShaderEffect { layer.effect: ShaderEffect {
property real uThreat: root._threat property real uThreat: root._threat
property real uPulse: root._heartbeat property real uPulse: root._heartbeat
property color uColor: S.Theme.base08 property color uColor: NS.ThemeService.base08
fragmentShader: Quickshell.shellPath("modules/lock_threat.frag.qsb") fragmentShader: Quickshell.shellPath("modules/lock_threat.frag.qsb")
} }
@ -77,7 +78,7 @@ WlSessionLockSurface {
// compositor fallback color (niri red) from bleeding through. // compositor fallback color (niri red) from bleeding through.
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base00 color: NS.ThemeService.base00
} }
// Clear desktop screenshot from ScreenshotService - visible immediately. // Clear desktop screenshot from ScreenshotService - visible immediately.
@ -86,7 +87,7 @@ WlSessionLockSurface {
Image { Image {
anchors.fill: parent anchors.fill: parent
source: S.ScreenshotService.get(root.screen?.name ?? "") source: S.ScreenshotService.get(root.screen?.name ?? "")
visible: (S.Modules.lock.screenshot ?? true) && source !== "" && !S.Theme.reducedMotion visible: (NS.ModulesService.lockScreenshot ?? true) && source !== "" && !S.ThemeUtil.reducedMotion
opacity: _unlockFade opacity: _unlockFade
fillMode: Image.PreserveAspectCrop fillMode: Image.PreserveAspectCrop
} }
@ -118,7 +119,7 @@ WlSessionLockSurface {
Image { Image {
anchors.fill: parent anchors.fill: parent
source: S.ScreenshotService.get(root.screen?.name ?? "") source: S.ScreenshotService.get(root.screen?.name ?? "")
visible: (S.Modules.lock.screenshot ?? true) && source !== "" && !S.Theme.reducedMotion visible: (NS.ModulesService.lockScreenshot ?? true) && source !== "" && !S.ThemeUtil.reducedMotion
fillMode: Image.PreserveAspectCrop fillMode: Image.PreserveAspectCrop
layer.enabled: true layer.enabled: true
@ -186,9 +187,9 @@ WlSessionLockSurface {
anchors.top: _lockInput.bottom anchors.top: _lockInput.bottom
anchors.topMargin: 16 anchors.topMargin: 16
text: root.auth.message text: root.auth.message
color: S.Theme.base08 color: NS.ThemeService.base08
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
opacity: root.auth.message ? 1 : 0 opacity: root.auth.message ? 1 : 0
Behavior on opacity { Behavior on opacity {
@ -206,10 +207,10 @@ WlSessionLockSurface {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
visible: root.auth.failCount > 0 visible: root.auth.failCount > 0
text: root.auth.failCount + (root.auth.failCount === 1 ? " failed attempt" : " failed attempts") text: root.auth.failCount + (root.auth.failCount === 1 ? " failed attempt" : " failed attempts")
color: S.Theme.base08 color: NS.ThemeService.base08
opacity: Math.max(0.4, root._threat) opacity: Math.max(0.4, root._threat)
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
// Right column - widgets, fly in when wave exits screen // Right column - widgets, fly in when wave exits screen
@ -261,7 +262,7 @@ WlSessionLockSurface {
interval: 30000 interval: 30000
running: _keyInput.text.length > 0 && root.auth.state !== "busy" running: _keyInput.text.length > 0 && root.auth.state !== "busy"
onTriggered: { onTriggered: {
if (!S.Theme.reducedMotion) if (!S.ThemeUtil.reducedMotion)
_shakeAnim.restart(); _shakeAnim.restart();
_keyInput.text = ""; _keyInput.text = "";
} }
@ -371,7 +372,7 @@ WlSessionLockSurface {
SequentialAnimation { SequentialAnimation {
id: _heartbeatAnim id: _heartbeatAnim
loops: Animation.Infinite loops: Animation.Infinite
running: root._threatEnabled && root.auth.failCount >= 3 && root.lock.secure && !S.Theme.reducedMotion running: root._threatEnabled && root.auth.failCount >= 3 && root.lock.secure && !S.ThemeUtil.reducedMotion
// Systole (sharp spike) // Systole (sharp spike)
NumberAnimation { NumberAnimation {
@ -417,8 +418,8 @@ WlSessionLockSurface {
// so the bar's ScreenCorners aren't visible. Draw our own. // so the bar's ScreenCorners aren't visible. Draw our own.
component LockCorner: Canvas { component LockCorner: Canvas {
property int corner: 0 property int corner: 0
readonly property int _r: S.Theme.screenRadius readonly property int _r: NS.ThemeService.screenRadius
visible: _r > 0 && S.Modules.screenCorners.enable visible: _r > 0 && NS.ModulesService.screenCornersEnable
width: _r width: _r
height: _r height: _r
z: 999 z: 999

View file

@ -1,6 +1,7 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
Item { Item {
id: root id: root
@ -16,7 +17,7 @@ Item {
property bool _revealed: false property bool _revealed: false
on_RawProgressChanged: if (_rawProgress >= 1) on_RawProgressChanged: if (_rawProgress >= 1)
_revealed = true _revealed = true
readonly property real _rawProgress: S.Theme.reducedMotion ? 1 : (screenWidth > 0 ? Math.max(0, Math.min(1, (wavePhase - screenWidth) / 500)) : 0) readonly property real _rawProgress: S.ThemeUtil.reducedMotion ? 1 : (screenWidth > 0 ? Math.max(0, Math.min(1, (wavePhase - screenWidth) / 500)) : 0)
readonly property real _progress: (_revealed ? 1 : _rawProgress) * unlockFade readonly property real _progress: (_revealed ? 1 : _rawProgress) * unlockFade
opacity: _progress opacity: _progress
property real _slideX: (1 - _progress) * 80 property real _slideX: (1 - _progress) * 80
@ -38,11 +39,11 @@ Item {
id: _weatherCard id: _weatherCard
width: parent.width width: parent.width
height: _weatherContent.implicitHeight + 16 height: _weatherContent.implicitHeight + 16
radius: S.Theme.radius + 2 radius: NS.ThemeService.radius + 2
color: Qt.rgba(S.Theme.base01.r, S.Theme.base01.g, S.Theme.base01.b, 0.7) color: Qt.rgba(NS.ThemeService.base01.r, NS.ThemeService.base01.g, NS.ThemeService.base01.b, 0.7)
border.color: Qt.rgba(S.Theme.base03.r, S.Theme.base03.g, S.Theme.base03.b, 0.3) border.color: Qt.rgba(NS.ThemeService.base03.r, NS.ThemeService.base03.g, NS.ThemeService.base03.b, 0.3)
border.width: 1 border.width: 1
visible: (S.Modules.lock.weather ?? true) && S.WeatherService.available visible: (NS.ModulesService.lockWeather ?? true) && S.WeatherService.available
C.WeatherApplet { C.WeatherApplet {
id: _weatherContent id: _weatherContent
@ -50,7 +51,7 @@ Item {
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 8 anchors.topMargin: 8
accentColor: S.Theme.base0C accentColor: NS.ThemeService.base0C
} }
} }
@ -65,11 +66,11 @@ Item {
id: _mprisCard id: _mprisCard
width: parent.width width: parent.width
height: _mprisContent.implicitHeight + 16 height: _mprisContent.implicitHeight + 16
radius: S.Theme.radius + 2 radius: NS.ThemeService.radius + 2
color: Qt.rgba(S.Theme.base01.r, S.Theme.base01.g, S.Theme.base01.b, 0.7) color: Qt.rgba(NS.ThemeService.base01.r, NS.ThemeService.base01.g, NS.ThemeService.base01.b, 0.7)
border.color: Qt.rgba(S.Theme.base03.r, S.Theme.base03.g, S.Theme.base03.b, 0.3) border.color: Qt.rgba(NS.ThemeService.base03.r, NS.ThemeService.base03.g, NS.ThemeService.base03.b, 0.3)
border.width: 1 border.width: 1
visible: (S.Modules.lock.mpris ?? true) && S.MprisService.player !== null visible: (NS.ModulesService.lockMpris ?? true) && S.MprisService.player !== null
C.MprisApplet { C.MprisApplet {
id: _mprisContent id: _mprisContent
@ -77,7 +78,7 @@ Item {
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 8 anchors.topMargin: 8
accentColor: S.Theme.base0D accentColor: NS.ThemeService.base0D
} }
} }
@ -86,11 +87,11 @@ Item {
id: _volumeCard id: _volumeCard
width: parent.width width: parent.width
height: _volumeContent.implicitHeight + 16 height: _volumeContent.implicitHeight + 16
radius: S.Theme.radius + 2 radius: NS.ThemeService.radius + 2
color: Qt.rgba(S.Theme.base01.r, S.Theme.base01.g, S.Theme.base01.b, 0.7) color: Qt.rgba(NS.ThemeService.base01.r, NS.ThemeService.base01.g, NS.ThemeService.base01.b, 0.7)
border.color: Qt.rgba(S.Theme.base03.r, S.Theme.base03.g, S.Theme.base03.b, 0.3) border.color: Qt.rgba(NS.ThemeService.base03.r, NS.ThemeService.base03.g, NS.ThemeService.base03.b, 0.3)
border.width: 1 border.width: 1
visible: (S.Modules.lock.volume ?? true) && S.PipewireService.sink !== null visible: (NS.ModulesService.lockVolume ?? true) && S.PipewireService.sink !== null
C.VolumeApplet { C.VolumeApplet {
id: _volumeContent id: _volumeContent
@ -98,7 +99,7 @@ Item {
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 8 anchors.topMargin: 8
accentColor: S.Theme.base0E accentColor: NS.ThemeService.base0E
} }
} }
@ -107,9 +108,9 @@ Item {
id: _backlightCard id: _backlightCard
width: parent.width width: parent.width
height: _backlightContent.implicitHeight + 8 height: _backlightContent.implicitHeight + 8
radius: S.Theme.radius + 2 radius: NS.ThemeService.radius + 2
color: Qt.rgba(S.Theme.base01.r, S.Theme.base01.g, S.Theme.base01.b, 0.7) color: Qt.rgba(NS.ThemeService.base01.r, NS.ThemeService.base01.g, NS.ThemeService.base01.b, 0.7)
border.color: Qt.rgba(S.Theme.base03.r, S.Theme.base03.g, S.Theme.base03.b, 0.3) border.color: Qt.rgba(NS.ThemeService.base03.r, NS.ThemeService.base03.g, NS.ThemeService.base03.b, 0.3)
border.width: 1 border.width: 1
visible: S.BacklightService.available visible: S.BacklightService.available
@ -120,7 +121,7 @@ Item {
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 4 anchors.topMargin: 4
percent: S.BacklightService.percent percent: S.BacklightService.percent
accentColor: S.Theme.base0A accentColor: NS.ThemeService.base0A
onSetPercent: pct => S.BacklightService.setPercent(pct) onSetPercent: pct => S.BacklightService.setPercent(pct)
} }
} }

View file

@ -4,6 +4,7 @@ import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
PanelWindow { PanelWindow {
id: root id: root
@ -43,9 +44,9 @@ PanelWindow {
Text { Text {
text: Qt.formatDateTime(clock.date, "HH") text: Qt.formatDateTime(clock.date, "HH")
color: S.Theme.base0D color: NS.ThemeService.base0D
font.pixelSize: 72 font.pixelSize: 72
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@ -53,22 +54,22 @@ PanelWindow {
text: ":" text: ":"
color: colon._colors[colon._colorIdx % colon._colors.length] color: colon._colors[colon._colorIdx % colon._colors.length]
Behavior on color { Behavior on color {
enabled: !S.Theme.reducedMotion enabled: !S.ThemeUtil.reducedMotion
ColorAnimation { ColorAnimation {
duration: 500 duration: 500
} }
} }
font.pixelSize: 72 font.pixelSize: 72
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
opacity: colon.opacity opacity: colon.opacity
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
Text { Text {
text: Qt.formatDateTime(clock.date, "mm") text: Qt.formatDateTime(clock.date, "mm")
color: S.Theme.base0E color: NS.ThemeService.base0E
font.pixelSize: 72 font.pixelSize: 72
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@ -78,7 +79,7 @@ PanelWindow {
source: glowSource source: glowSource
anchors.fill: glowSource anchors.fill: glowSource
shadowEnabled: true shadowEnabled: true
shadowColor: S.Theme.base0D shadowColor: NS.ThemeService.base0D
shadowBlur: 1.0 shadowBlur: 1.0
shadowVerticalOffset: 0 shadowVerticalOffset: 0
shadowHorizontalOffset: 0 shadowHorizontalOffset: 0
@ -91,10 +92,10 @@ PanelWindow {
Text { Text {
text: Qt.formatDateTime(clock.date, "HH") text: Qt.formatDateTime(clock.date, "HH")
color: S.Theme.base0D color: NS.ThemeService.base0D
opacity: 0.85 opacity: 0.85
font.pixelSize: 72 font.pixelSize: 72
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@ -102,16 +103,16 @@ PanelWindow {
id: colon id: colon
text: ":" text: ":"
font.pixelSize: 72 font.pixelSize: 72
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
opacity: 0.85 opacity: 0.85
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
property int _colorIdx: 0 property int _colorIdx: 0
readonly property var _colors: [S.Theme.base08, S.Theme.base09, S.Theme.base0A, S.Theme.base0B, S.Theme.base0C, S.Theme.base0D, S.Theme.base0E, S.Theme.base05] readonly property var _colors: [NS.ThemeService.base08, NS.ThemeService.base09, NS.ThemeService.base0A, NS.ThemeService.base0B, NS.ThemeService.base0C, NS.ThemeService.base0D, NS.ThemeService.base0E, NS.ThemeService.base05]
color: _colors[_colorIdx % _colors.length] color: _colors[_colorIdx % _colors.length]
Behavior on color { Behavior on color {
enabled: !S.Theme.reducedMotion enabled: !S.ThemeUtil.reducedMotion
ColorAnimation { ColorAnimation {
duration: 500 duration: 500
} }
@ -139,7 +140,7 @@ PanelWindow {
Connections { Connections {
target: clock target: clock
function onDateChanged() { function onDateChanged() {
if (S.Theme.reducedMotion) if (S.ThemeUtil.reducedMotion)
return; return;
colon._colorIdx++; colon._colorIdx++;
colonAnim.restart(); colonAnim.restart();
@ -148,10 +149,10 @@ PanelWindow {
} }
Text { Text {
text: Qt.formatDateTime(clock.date, "mm") text: Qt.formatDateTime(clock.date, "mm")
color: S.Theme.base0E color: NS.ThemeService.base0E
opacity: 0.85 opacity: 0.85
font.pixelSize: 72 font.pixelSize: 72
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@ -163,16 +164,16 @@ PanelWindow {
id: dateText id: dateText
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
text: Qt.formatDateTime(clock.date, "dddd, dd MMMM yyyy") text: Qt.formatDateTime(clock.date, "dddd, dd MMMM yyyy")
color: S.Theme.base05 color: NS.ThemeService.base05
opacity: 0.5 opacity: 0.5
font.pixelSize: 18 font.pixelSize: 18
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.letterSpacing: 4 font.letterSpacing: 4
layer.enabled: true layer.enabled: true
layer.effect: MultiEffect { layer.effect: MultiEffect {
shadowEnabled: true shadowEnabled: true
shadowColor: S.Theme.base0D shadowColor: NS.ThemeService.base0D
shadowBlur: 0.4 shadowBlur: 0.4
shadowVerticalOffset: 0 shadowVerticalOffset: 0
shadowHorizontalOffset: 0 shadowHorizontalOffset: 0
@ -187,7 +188,7 @@ PanelWindow {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base02 color: NS.ThemeService.base02
radius: 1 radius: 1
opacity: 0.3 opacity: 0.3
} }
@ -196,7 +197,7 @@ PanelWindow {
height: parent.height height: parent.height
color: colon._colors[colon._colorIdx % colon._colors.length] color: colon._colors[colon._colorIdx % colon._colors.length]
Behavior on color { Behavior on color {
enabled: !S.Theme.reducedMotion enabled: !S.ThemeUtil.reducedMotion
ColorAnimation { ColorAnimation {
duration: 500 duration: 500
} }
@ -205,7 +206,7 @@ PanelWindow {
opacity: 0.6 opacity: 0.6
Behavior on width { Behavior on width {
enabled: !S.Theme.reducedMotion enabled: !S.ThemeUtil.reducedMotion
NumberAnimation { NumberAnimation {
duration: 50 duration: 50
} }

View file

@ -3,11 +3,12 @@ import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
spacing: S.Theme.moduleSpacing spacing: NS.ThemeService.moduleSpacing
active: S.Modules.backlight.enable && S.BacklightService.available active: NS.ModulesService.backlightEnable && S.BacklightService.available
tooltip: "Brightness: " + percent + "%" tooltip: "Brightness: " + percent + "%"
panelNamespace: "nova-backlight" panelNamespace: "nova-backlight"
panelContentWidth: 200 panelContentWidth: 200

View file

@ -4,6 +4,7 @@ import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
PanelWindow { PanelWindow {
id: bar id: bar
@ -19,13 +20,13 @@ PanelWindow {
margins.right: S.DockState.reservedWidthAnimated margins.right: S.DockState.reservedWidthAnimated
implicitHeight: S.Theme.barHeight implicitHeight: NS.ThemeService.barHeight
exclusiveZone: implicitHeight exclusiveZone: implicitHeight
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: S.Theme.base00 color: NS.ThemeService.base00
opacity: S.Theme.barOpacity opacity: NS.ThemeService.barOpacity
} }
Canvas { Canvas {
@ -35,7 +36,7 @@ PanelWindow {
const ctx = getContext("2d"); const ctx = getContext("2d");
const w = width; const w = width;
const h = height; const h = height;
const r = S.Theme.screenRadius; const r = NS.ThemeService.screenRadius;
const lw = 3; const lw = 3;
const hw = lw / 2; const hw = lw / 2;
@ -43,8 +44,8 @@ PanelWindow {
// Glow wash behind the border // Glow wash behind the border
const glowGrad = ctx.createLinearGradient(0, 0, w, 0); const glowGrad = ctx.createLinearGradient(0, 0, w, 0);
glowGrad.addColorStop(0, S.Theme.base0C.toString()); glowGrad.addColorStop(0, NS.ThemeService.base0C.toString());
glowGrad.addColorStop(1, S.Theme.base09.toString()); glowGrad.addColorStop(1, NS.ThemeService.base09.toString());
ctx.globalAlpha = 0.25; ctx.globalAlpha = 0.25;
ctx.fillStyle = glowGrad; ctx.fillStyle = glowGrad;
ctx.fillRect(0, 0, w, h); ctx.fillRect(0, 0, w, h);
@ -61,8 +62,8 @@ PanelWindow {
// Horizontal gradient for the border // Horizontal gradient for the border
const grad = ctx.createLinearGradient(0, 0, w, 0); const grad = ctx.createLinearGradient(0, 0, w, 0);
grad.addColorStop(0, S.Theme.base0C.toString()); grad.addColorStop(0, NS.ThemeService.base0C.toString());
grad.addColorStop(1, S.Theme.base09.toString()); grad.addColorStop(1, NS.ThemeService.base09.toString());
ctx.strokeStyle = grad; ctx.strokeStyle = grad;
ctx.lineWidth = lw; ctx.lineWidth = lw;
@ -97,16 +98,16 @@ PanelWindow {
Item { Item {
anchors.fill: parent anchors.fill: parent
anchors.topMargin: S.Theme.groupSpacing anchors.topMargin: NS.ThemeService.groupSpacing
anchors.leftMargin: S.Theme.groupSpacing anchors.leftMargin: NS.ThemeService.groupSpacing
anchors.rightMargin: S.Theme.groupSpacing anchors.rightMargin: NS.ThemeService.groupSpacing
// ---- center (declared first so left/right can anchor to it) ---- // ---- center (declared first so left/right can anchor to it) ----
RowLayout { RowLayout {
id: centerSection id: centerSection
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: S.Theme.groupSpacing spacing: NS.ThemeService.groupSpacing
M.BarGroup { M.BarGroup {
M.PrivacyModule {} M.PrivacyModule {}
@ -120,7 +121,7 @@ PanelWindow {
anchors.left: parent.left anchors.left: parent.left
anchors.right: centerSection.left anchors.right: centerSection.left
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: S.Theme.groupSpacing spacing: NS.ThemeService.groupSpacing
M.BarGroup { M.BarGroup {
id: workspacesGroup id: workspacesGroup
@ -135,10 +136,10 @@ PanelWindow {
id: _windowTitleGroup id: _windowTitleGroup
Layout.minimumWidth: 0 Layout.minimumWidth: 0
clip: true clip: true
visible: S.Modules.windowTitle.enable && S.NiriIpc.focusedTitle !== "" visible: NS.ModulesService.windowTitleEnable && S.NiriIpc.focusedTitle !== ""
M.WindowTitleModule { M.WindowTitleModule {
id: _windowTitle id: _windowTitle
readonly property real _maxWidth: Math.max(0, centerSection.x - _windowTitleGroup.x - 2 * S.Theme.groupPadding - S.Theme.groupSpacing) readonly property real _maxWidth: Math.max(0, centerSection.x - _windowTitleGroup.x - 2 * NS.ThemeService.groupPadding - NS.ThemeService.groupSpacing)
width: Math.min(naturalWidth, _maxWidth) width: Math.min(naturalWidth, _maxWidth)
} }
} }
@ -152,7 +153,7 @@ PanelWindow {
anchors.left: centerSection.right anchors.left: centerSection.right
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: S.Theme.groupSpacing spacing: NS.ThemeService.groupSpacing
Item { Item {
Layout.fillWidth: true Layout.fillWidth: true

View file

@ -3,6 +3,7 @@ import QtQuick.Effects
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
Item { Item {
id: root id: root
@ -18,14 +19,14 @@ Item {
const effectiveWidth = scr.width - (S.DockState.reservedWidthAnimated ?? 0); const effectiveWidth = scr.width - (S.DockState.reservedWidthAnimated ?? 0);
return Math.max(0, Math.min(1, gx / (effectiveWidth > 0 ? effectiveWidth : scr.width))); return Math.max(0, Math.min(1, gx / (effectiveWidth > 0 ? effectiveWidth : scr.width)));
} }
property color borderColor: Qt.rgba(S.Theme.base0C.r + (S.Theme.base09.r - S.Theme.base0C.r) * _posFrac, S.Theme.base0C.g + (S.Theme.base09.g - S.Theme.base0C.g) * _posFrac, S.Theme.base0C.b + (S.Theme.base09.b - S.Theme.base0C.b) * _posFrac, 1) property color borderColor: Qt.rgba(NS.ThemeService.base0C.r + (NS.ThemeService.base09.r - NS.ThemeService.base0C.r) * _posFrac, NS.ThemeService.base0C.g + (NS.ThemeService.base09.g - NS.ThemeService.base0C.g) * _posFrac, NS.ThemeService.base0C.b + (NS.ThemeService.base09.b - NS.ThemeService.base0C.b) * _posFrac, 1)
property bool leftEdge: false property bool leftEdge: false
property bool rightEdge: false property bool rightEdge: false
readonly property real _tlr: leftEdge ? S.Theme.screenRadius : S.Theme.radius readonly property real _tlr: leftEdge ? NS.ThemeService.screenRadius : NS.ThemeService.radius
readonly property real _trr: rightEdge ? S.Theme.screenRadius : S.Theme.radius readonly property real _trr: rightEdge ? NS.ThemeService.screenRadius : NS.ThemeService.radius
readonly property real _blr: S.Theme.radius readonly property real _blr: NS.ThemeService.radius
readonly property real _brr: S.Theme.radius readonly property real _brr: NS.ThemeService.radius
// Check children's `active` instead of visibleChildren to avoid circular // Check children's `active` instead of visibleChildren to avoid circular
// effectiveVisible dependency: if the BarGroup is invisible, children's // effectiveVisible dependency: if the BarGroup is invisible, children's
@ -41,9 +42,9 @@ Item {
} }
implicitWidth: row.implicitWidth + _pad * 2 implicitWidth: row.implicitWidth + _pad * 2
implicitHeight: S.Theme.barHeight - 3 - _pad implicitHeight: NS.ThemeService.barHeight - 3 - _pad
readonly property int _pad: S.Theme.groupPadding readonly property int _pad: NS.ThemeService.groupPadding
property bool _hovered: false property bool _hovered: false
HoverHandler { HoverHandler {
@ -57,7 +58,7 @@ Item {
topRightRadius: root._trr topRightRadius: root._trr
bottomLeftRadius: root._blr bottomLeftRadius: root._blr
bottomRightRadius: root._brr bottomRightRadius: root._brr
color: Qt.rgba(S.Theme.base01.r, S.Theme.base01.g, S.Theme.base01.b, 0.55) color: Qt.rgba(NS.ThemeService.base01.r, NS.ThemeService.base01.g, NS.ThemeService.base01.b, 0.55)
} }
// Frost sheen subtle white highlight, top-heavy // Frost sheen subtle white highlight, top-heavy
@ -137,7 +138,7 @@ Item {
property real _pulse: 0.08 property real _pulse: 0.08
SequentialAnimation on _pulse { SequentialAnimation on _pulse {
running: root._hovered && !S.Theme.reducedMotion running: root._hovered && !S.ThemeUtil.reducedMotion
loops: Animation.Infinite loops: Animation.Infinite
NumberAnimation { NumberAnimation {
to: 0.22 to: 0.22
@ -156,7 +157,7 @@ Item {
id: row id: row
property color accentColor: root.borderColor property color accentColor: root.borderColor
anchors.centerIn: parent anchors.centerIn: parent
spacing: S.Theme.moduleSpacing + 2 spacing: NS.ThemeService.moduleSpacing + 2
} }
// Separator lines overlaid between visible row children // Separator lines overlaid between visible row children

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
// Icon element with crossfade animation on icon change. // Icon element with crossfade animation on icon change.
// Pure visual component - tooltip handling lives in the parent BarModule. // Pure visual component - tooltip handling lives in the parent BarModule.
@ -7,7 +8,7 @@ Text {
id: root id: root
property string icon: "" property string icon: ""
property string minIcon: "" property string minIcon: ""
property color accentColor: parent?.accentColor ?? S.Theme.base05 property color accentColor: parent?.accentColor ?? NS.ThemeService.base05
property string _displayIcon: icon property string _displayIcon: icon
property string _pendingIcon: "" property string _pendingIcon: ""
@ -42,8 +43,8 @@ Text {
width: minIcon ? Math.max(implicitWidth, _minIconMetrics.width) : implicitWidth width: minIcon ? Math.max(implicitWidth, _minIconMetrics.width) : implicitWidth
horizontalAlignment: minIcon ? Text.AlignHCenter : Text.AlignLeft horizontalAlignment: minIcon ? Text.AlignHCenter : Text.AlignLeft
color: root.accentColor color: root.accentColor
font.pixelSize: S.Theme.fontSize + 1 font.pixelSize: NS.ThemeService.fontSize + 1
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
TextMetrics { TextMetrics {

View file

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import "../services" as S import "../services" as S
import NovaStats as NS
// Label element with minimum-width support via minText. // Label element with minimum-width support via minText.
// Pure visual component - tooltip handling lives in the parent BarModule. // Pure visual component - tooltip handling lives in the parent BarModule.
@ -7,14 +8,14 @@ Text {
id: root id: root
property string label: "" property string label: ""
property string minText: "" property string minText: ""
property color accentColor: parent?.accentColor ?? S.Theme.base05 property color accentColor: parent?.accentColor ?? NS.ThemeService.base05
text: label text: label
width: minText ? Math.max(implicitWidth, _minMetrics.width) : implicitWidth width: minText ? Math.max(implicitWidth, _minMetrics.width) : implicitWidth
horizontalAlignment: minText ? Text.AlignHCenter : Text.AlignLeft horizontalAlignment: minText ? Text.AlignHCenter : Text.AlignLeft
color: root.accentColor color: root.accentColor
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
TextMetrics { TextMetrics {

View file

@ -2,6 +2,7 @@ import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
// Unified base component for all bar modules. // Unified base component for all bar modules.
// Provides: tooltip on hover, panel state management, OSD flash support. // Provides: tooltip on hover, panel state management, OSD flash support.
@ -20,7 +21,7 @@ Row {
property string tooltip: "" property string tooltip: ""
property bool _hovered: false property bool _hovered: false
property color accentColor: parent?.accentColor ?? S.Theme.base05 property color accentColor: parent?.accentColor ?? NS.ThemeService.base05
property int cursorShape: Qt.PointingHandCursor property int cursorShape: Qt.PointingHandCursor
// Panel state // Panel state

View file

@ -3,11 +3,12 @@ import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
spacing: S.Theme.moduleSpacing spacing: NS.ThemeService.moduleSpacing
active: S.Modules.battery.enable && S.BatteryService.available active: NS.ModulesService.batteryEnable && S.BatteryService.available
tooltip: "Battery: " + Math.round(S.BatteryService.percent) + "%" + (S.BatteryService.charging ? " (charging)" : "") tooltip: "Battery: " + Math.round(S.BatteryService.percent) + "%" + (S.BatteryService.charging ? " (charging)" : "")
panelNamespace: "nova-battery" panelNamespace: "nova-battery"
panelContentWidth: 240 panelContentWidth: 240
@ -35,7 +36,7 @@ M.BarModule {
} }
color: S.BatteryService.stateColor color: S.BatteryService.stateColor
opacity: root._blinkOpacity opacity: root._blinkOpacity
font.pixelSize: S.Theme.fontSize + 2 font.pixelSize: NS.ThemeService.fontSize + 2
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
M.BarLabel { M.BarLabel {

View file

@ -3,11 +3,12 @@ import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
spacing: S.Theme.moduleSpacing spacing: NS.ThemeService.moduleSpacing
active: S.Modules.bluetooth.enable && S.BluetoothService.state !== "unavailable" active: NS.ModulesService.bluetoothEnable && S.BluetoothService.state !== "unavailable"
tooltip: { tooltip: {
if (S.BluetoothService.state === "connected") if (S.BluetoothService.state === "connected")
return "Bluetooth: " + S.BluetoothService.device; return "Bluetooth: " + S.BluetoothService.device;
@ -33,7 +34,7 @@ M.BarModule {
M.BarIcon { M.BarIcon {
icon: "\uF294" icon: "\uF294"
color: S.BluetoothService.state === "off" ? S.Theme.base04 : root.accentColor color: S.BluetoothService.state === "off" ? NS.ThemeService.base04 : root.accentColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
M.BarLabel { M.BarLabel {

View file

@ -3,11 +3,12 @@ import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
active: S.Modules.clock.enable active: NS.ModulesService.clockEnable
spacing: S.Theme.moduleSpacing spacing: NS.ThemeService.moduleSpacing
tooltip: Qt.formatDateTime(clock.date, "dddd, dd. MMMM yyyy HH:mm:ss") tooltip: Qt.formatDateTime(clock.date, "dddd, dd. MMMM yyyy HH:mm:ss")
panelNamespace: "nova-clock" panelNamespace: "nova-clock"
panelContentWidth: 220 panelContentWidth: 220
@ -25,7 +26,7 @@ M.BarModule {
} }
M.BarLabel { M.BarLabel {
font.pixelSize: S.Theme.fontSize + 1 font.pixelSize: NS.ThemeService.fontSize + 1
label: Qt.formatDateTime(clock.date, "ddd, dd. MMM HH:mm") label: Qt.formatDateTime(clock.date, "ddd, dd. MMM HH:mm")
minText: "Wed, 00. Sep 00:00" minText: "Wed, 00. Sep 00:00"
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter

View file

@ -3,11 +3,12 @@ import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
active: S.Modules.cpu.enable active: NS.ModulesService.cpuEnable
spacing: Math.max(1, S.Theme.moduleSpacing - 2) spacing: Math.max(1, NS.ThemeService.moduleSpacing - 2)
tooltip: "CPU: " + S.CpuService.usage + "% @ " + S.CpuService.freqGhz.toFixed(2) + " GHz" tooltip: "CPU: " + S.CpuService.usage + "% @ " + S.CpuService.freqGhz.toFixed(2) + " GHz"
panelNamespace: "nova-cpu" panelNamespace: "nova-cpu"
panelContentWidth: 260 panelContentWidth: 260

View file

@ -3,11 +3,12 @@ import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
active: S.Modules.disk.enable active: NS.ModulesService.diskEnable
spacing: Math.max(1, S.Theme.moduleSpacing - 2) spacing: Math.max(1, NS.ThemeService.moduleSpacing - 2)
tooltip: "Disk: " + _rootPct + "% used" tooltip: "Disk: " + _rootPct + "% used"
panelNamespace: "nova-disk" panelNamespace: "nova-disk"
panelContentWidth: 260 panelContentWidth: 260
@ -21,7 +22,7 @@ M.BarModule {
property var _mounts: S.SystemStats.diskMounts property var _mounts: S.SystemStats.diskMounts
property int _rootPct: S.SystemStats.diskRootPct property int _rootPct: S.SystemStats.diskRootPct
readonly property int _warnThreshold: S.Modules.disk.warnThreshold ?? 85 readonly property int _warnThreshold: NS.ModulesService.diskWarnThreshold ?? 85
readonly property bool _anyWarn: { readonly property bool _anyWarn: {
for (const m of _mounts) for (const m of _mounts)
if (m.pct >= _warnThreshold) if (m.pct >= _warnThreshold)
@ -31,13 +32,13 @@ M.BarModule {
M.BarIcon { M.BarIcon {
icon: "\uF0C9" icon: "\uF0C9"
color: root._anyWarn ? S.Theme.base09 : root.accentColor color: root._anyWarn ? NS.ThemeService.base09 : root.accentColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
M.BarLabel { M.BarLabel {
label: root._rootPct + "%" label: root._rootPct + "%"
minText: "100%" minText: "100%"
color: root._anyWarn ? S.Theme.base09 : root.accentColor color: root._anyWarn ? NS.ThemeService.base09 : root.accentColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }

View file

@ -1,10 +1,11 @@
import QtQuick import QtQuick
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
active: S.Modules.dock.enable && S.DockState.mode !== "pinned" active: NS.ModulesService.dockEnable && S.DockState.mode !== "pinned"
tooltip: S.DockState.open ? "Close dock" : "Open dock" tooltip: S.DockState.open ? "Close dock" : "Open dock"
onTapped: S.DockState.toggle() onTapped: S.DockState.toggle()

View file

@ -3,11 +3,12 @@ import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
spacing: Math.max(1, S.Theme.moduleSpacing - 2) spacing: Math.max(1, NS.ThemeService.moduleSpacing - 2)
active: S.Modules.gpu.enable && S.SystemStats.gpuAvailable active: NS.ModulesService.gpuEnable && S.SystemStats.gpuAvailable
tooltip: "GPU: " + S.SystemStats.gpuUsage + "%" tooltip: "GPU: " + S.SystemStats.gpuUsage + "%"
panelNamespace: "nova-gpu" panelNamespace: "nova-gpu"
panelContentWidth: 240 panelContentWidth: 240

View file

@ -3,6 +3,7 @@ import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
// Bar panel - fullscreen transparent window so content can resize freely // Bar panel - fullscreen transparent window so content can resize freely
// without triggering Wayland surface resizes. // without triggering Wayland surface resizes.
@ -83,7 +84,7 @@ PanelWindow {
} }
_winVisible = true; _winVisible = true;
hideAnim.stop(); hideAnim.stop();
if (S.Theme.reducedMotion) { if (S.ThemeUtil.reducedMotion) {
panelContainer.opacity = 1; panelContainer.opacity = 1;
panelContainer.y = 0; panelContainer.y = 0;
} else { } else {
@ -97,7 +98,7 @@ PanelWindow {
if (!_winVisible) if (!_winVisible)
return; return;
showAnim.stop(); showAnim.stop();
if (S.Theme.reducedMotion) { if (S.ThemeUtil.reducedMotion) {
_winVisible = false; _winVisible = false;
dismissed(); dismissed();
} else { } else {
@ -185,7 +186,7 @@ PanelWindow {
y: panelContainer.y y: panelContainer.y
width: panelContainer.width width: panelContainer.width
height: panelContainer.height height: panelContainer.height
opacity: panelContainer.opacity * Math.max(S.Theme.barOpacity, 0.85) opacity: panelContainer.opacity * Math.max(NS.ThemeService.barOpacity, 0.85)
accentColor: root.accentColor accentColor: root.accentColor
} }
@ -228,7 +229,7 @@ PanelWindow {
color: "transparent" color: "transparent"
border.color: root.accentColor border.color: root.accentColor
border.width: 1 border.width: 1
radius: S.Theme.radius radius: NS.ThemeService.radius
opacity: panelContainer.opacity opacity: panelContainer.opacity
} }
} }

View file

@ -2,10 +2,11 @@ import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
active: S.Modules.idleInhibitor.enable active: NS.ModulesService.idleInhibitorEnable
tooltip: { tooltip: {
const parts = ["Idle inhibition: " + (S.IdleInhibitService.active ? "active" : "inactive")]; const parts = ["Idle inhibition: " + (S.IdleInhibitService.active ? "active" : "inactive")];
if (S.IdleInhibitService.inhibitors) if (S.IdleInhibitService.inhibitors)
@ -23,7 +24,7 @@ M.BarModule {
} }
M.BarIcon { M.BarIcon {
color: S.IdleInhibitService.active ? S.Theme.base09 : root.accentColor color: S.IdleInhibitService.active ? NS.ThemeService.base09 : root.accentColor
icon: S.IdleInhibitService.active ? "\uF06E" : "\uF070" icon: S.IdleInhibitService.active ? "\uF06E" : "\uF070"
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }

View file

@ -5,10 +5,11 @@ import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
active: S.Modules.machinectl.enable active: NS.ModulesService.machinectlEnable
tooltip: { tooltip: {
const n = S.MachinectlService.machines.length; const n = S.MachinectlService.machines.length;
return n === 0 ? "no containers" : n + " container" + (n === 1 ? "" : "s"); return n === 0 ? "no containers" : n + " container" + (n === 1 ? "" : "s");
@ -30,7 +31,7 @@ M.BarModule {
} }
} }
readonly property color _stateColor: S.MachinectlService.anyUnhealthy ? S.Theme.base0A : root.accentColor readonly property color _stateColor: S.MachinectlService.anyUnhealthy ? NS.ThemeService.base0A : root.accentColor
M.BarIcon { M.BarIcon {
icon: "" icon: ""

View file

@ -3,11 +3,12 @@ import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
active: S.Modules.memory.enable active: NS.ModulesService.memoryEnable
spacing: Math.max(1, S.Theme.moduleSpacing - 2) spacing: Math.max(1, NS.ThemeService.moduleSpacing - 2)
tooltip: "Memory: " + usedGb.toFixed(1) + " / " + totalGb.toFixed(1) + " GB" tooltip: "Memory: " + usedGb.toFixed(1) + " / " + totalGb.toFixed(1) + " GB"
panelNamespace: "nova-memory" panelNamespace: "nova-memory"
panelContentWidth: 240 panelContentWidth: 240

View file

@ -5,11 +5,12 @@ import Quickshell.Services.Mpris
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
spacing: S.Theme.moduleSpacing spacing: NS.ThemeService.moduleSpacing
active: S.Modules.mpris.enable && S.MprisService.player !== null active: NS.ModulesService.mprisEnable && S.MprisService.player !== null
tooltip: S.MprisService.player ? (S.MprisService.player.trackTitle || S.MprisService.player.identity || "Media") + (S.MprisService.playing ? " (playing)" : " (paused)") : "Media" tooltip: S.MprisService.player ? (S.MprisService.player.trackTitle || S.MprisService.player.identity || "Media") + (S.MprisService.playing ? " (playing)" : " (paused)") : "Media"
panelNamespace: "nova-mpris" panelNamespace: "nova-mpris"
panelContentWidth: 280 panelContentWidth: 280

View file

@ -3,11 +3,12 @@ import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
active: S.Modules.network.enable active: NS.ModulesService.networkEnable
spacing: S.Theme.moduleSpacing spacing: NS.ThemeService.moduleSpacing
tooltip: { tooltip: {
if (state === "wifi") if (state === "wifi")
return "Wi-Fi: " + S.NetworkService.essid; return "Wi-Fi: " + S.NetworkService.essid;
@ -45,13 +46,13 @@ M.BarModule {
return "\uDB85\uDE16"; return "\uDB85\uDE16";
return "\uDB82\uDCFD"; return "\uDB82\uDCFD";
} }
color: root.state === "disconnected" ? S.Theme.base08 : root.accentColor color: root.state === "disconnected" ? NS.ThemeService.base08 : root.accentColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
M.BarLabel { M.BarLabel {
visible: root.state === "wifi" visible: root.state === "wifi"
label: S.NetworkService.essid label: S.NetworkService.essid
color: root.state === "disconnected" ? S.Theme.base08 : root.accentColor color: root.state === "disconnected" ? NS.ThemeService.base08 : root.accentColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }

View file

@ -2,6 +2,7 @@ import QtQuick
import Quickshell.Services.Notifications import Quickshell.Services.Notifications
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
// Shared notification card: background, progress bar, urgency bar, icon, text, dismiss button. // Shared notification card: background, progress bar, urgency bar, icon, text, dismiss button.
// Does NOT include dismiss animation or dismiss logic emits dismissRequested() instead. // Does NOT include dismiss animation or dismiss logic emits dismissRequested() instead.
@ -14,7 +15,7 @@ Item {
property bool dismissOnAction: true property bool dismissOnAction: true
property int iconSize: 32 property int iconSize: 32
property int bodyMaxLines: 3 property int bodyMaxLines: 3
property color accentColor: S.Theme.base0D property color accentColor: NS.ThemeService.base0D
signal dismissRequested signal dismissRequested
@ -36,9 +37,9 @@ Item {
// Background: base01, base02 on hover // Background: base01, base02 on hover
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: _hover.hovered ? S.Theme.base02 : S.Theme.base01 color: _hover.hovered ? NS.ThemeService.base02 : NS.ThemeService.base01
opacity: _hover.hovered ? 1.0 : Math.max(S.Theme.barOpacity, 0.9) opacity: _hover.hovered ? 1.0 : Math.max(NS.ThemeService.barOpacity, 0.9)
radius: S.Theme.radius radius: NS.ThemeService.radius
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
@ -53,7 +54,7 @@ Item {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
width: parent.width * Math.min(1, Math.max(0, (root.notif?.hints?.value ?? 0) / 100)) width: parent.width * Math.min(1, Math.max(0, (root.notif?.hints?.value ?? 0) / 100))
color: S.Theme.base03 color: NS.ThemeService.base03
radius: parent.radius radius: parent.radius
Behavior on width { Behavior on width {
@ -73,7 +74,7 @@ Item {
radius: 1 radius: 1
color: { color: {
const u = root.notif?.urgency ?? NotificationUrgency.Normal; const u = root.notif?.urgency ?? NotificationUrgency.Normal;
return u === NotificationUrgency.Critical ? S.Theme.base08 : u === NotificationUrgency.Low ? S.Theme.base04 : S.Theme.base0D; return u === NotificationUrgency.Critical ? NS.ThemeService.base08 : u === NotificationUrgency.Low ? NS.ThemeService.base04 : NS.ThemeService.base0D;
} }
} }
@ -101,9 +102,9 @@ Item {
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 8 anchors.topMargin: 8
text: "\uF00D" text: "\uF00D"
color: _dismissHover.hovered ? S.Theme.base08 : S.Theme.base03 color: _dismissHover.hovered ? NS.ThemeService.base08 : NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
opacity: _hover.hovered ? 1 : 0 opacity: _hover.hovered ? 1 : 0
HoverHandler { HoverHandler {
@ -159,9 +160,9 @@ Item {
Text { Text {
text: root.notif?.appName ?? "Notification" text: root.notif?.appName ?? "Notification"
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
width: parent.width - _timeText.implicitWidth - 4 width: parent.width - _timeText.implicitWidth - 4
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -169,9 +170,9 @@ Item {
Text { Text {
id: _timeText id: _timeText
text: root.notif?.timeStr ?? "" text: root.notif?.timeStr ?? ""
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
@ -182,9 +183,9 @@ Item {
Text { Text {
text: root.notif?.summary ?? "" text: root.notif?.summary ?? ""
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
elide: Text.ElideRight elide: Text.ElideRight
width: parent.width - _inlineTime.implicitWidth - 4 width: parent.width - _inlineTime.implicitWidth - 4
@ -193,9 +194,9 @@ Item {
Text { Text {
id: _inlineTime id: _inlineTime
text: root.notif?.timeStr ?? "" text: root.notif?.timeStr ?? ""
color: S.Theme.base03 color: NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
@ -204,9 +205,9 @@ Item {
visible: root.showAppName visible: root.showAppName
width: parent.width width: parent.width
text: root.notif?.summary ?? "" text: root.notif?.summary ?? ""
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: true font.bold: true
elide: Text.ElideRight elide: Text.ElideRight
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
@ -216,9 +217,9 @@ Item {
Text { Text {
width: parent.width width: parent.width
text: root.notif?.body ?? "" text: root.notif?.body ?? ""
color: S.Theme.base04 color: NS.ThemeService.base04
font.pixelSize: S.Theme.fontSize - 1 font.pixelSize: NS.ThemeService.fontSize - 1
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
elide: Text.ElideRight elide: Text.ElideRight
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
maximumLineCount: root.bodyMaxLines maximumLineCount: root.bodyMaxLines
@ -239,9 +240,9 @@ Item {
required property var modelData required property var modelData
width: _actText.implicitWidth + 12 width: _actText.implicitWidth + 12
height: _actText.implicitHeight + 6 height: _actText.implicitHeight + 6
radius: S.Theme.radius radius: NS.ThemeService.radius
color: _actHover.hovered ? S.Theme.base03 : "transparent" color: _actHover.hovered ? NS.ThemeService.base03 : "transparent"
border.color: S.Theme.base03 border.color: NS.ThemeService.base03
border.width: 1 border.width: 1
Text { Text {
@ -249,8 +250,8 @@ Item {
anchors.centerIn: parent anchors.centerIn: parent
text: parent.modelData.text text: parent.modelData.text
color: root.accentColor color: root.accentColor
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
HoverHandler { HoverHandler {

View file

@ -4,6 +4,7 @@ import Quickshell.Wayland
import Quickshell.Services.Notifications import Quickshell.Services.Notifications
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
PanelWindow { PanelWindow {
id: root id: root
@ -32,7 +33,7 @@ PanelWindow {
property var _knownIds: ({}) property var _knownIds: ({})
Repeater { Repeater {
model: S.NotifService.popups.slice(0, S.Modules.notifications.maxPopups || 4) model: S.NotifService.popups.slice(0, NS.ModulesService.notificationsMaxPopups || 4)
delegate: Item { delegate: Item {
id: popupItem id: popupItem
@ -66,7 +67,7 @@ PanelWindow {
_heightScale = 1; _heightScale = 1;
} else { } else {
popupCol._knownIds[modelData.id] = true; popupCol._knownIds[modelData.id] = true;
if (S.Theme.reducedMotion) { if (S.ThemeUtil.reducedMotion) {
opacity = 1; opacity = 1;
x = 0; x = 0;
_heightScale = 1; _heightScale = 1;
@ -86,7 +87,7 @@ PanelWindow {
} }
Behavior on y { Behavior on y {
enabled: popupItem._entered && !S.Theme.reducedMotion enabled: popupItem._entered && !S.ThemeUtil.reducedMotion
NumberAnimation { NumberAnimation {
duration: 200 duration: 200
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
@ -127,7 +128,7 @@ PanelWindow {
popupItem.modelData.beginDismiss(); popupItem.modelData.beginDismiss();
_fullDismiss = !!full; _fullDismiss = !!full;
slideIn.stop(); slideIn.stop();
if (S.Theme.reducedMotion) { if (S.ThemeUtil.reducedMotion) {
full ? S.NotifService.dismiss(modelData.id) : S.NotifService.dismissPopup(modelData.id); full ? S.NotifService.dismiss(modelData.id) : S.NotifService.dismissPopup(modelData.id);
} else { } else {
slideOut.start(); slideOut.start();

View file

@ -4,11 +4,12 @@ import Quickshell.Services.Notifications
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
active: S.Modules.notifications.enable active: NS.ModulesService.notificationsEnable
spacing: S.Theme.moduleSpacing spacing: NS.ThemeService.moduleSpacing
tooltip: S.NotifService.count > 0 ? "Notifications: " + S.NotifService.count + (S.NotifService.dnd ? " (DND)" : "") : (S.NotifService.dnd ? "Do not disturb" : "No notifications") tooltip: S.NotifService.count > 0 ? "Notifications: " + S.NotifService.count + (S.NotifService.dnd ? " (DND)" : "") : (S.NotifService.dnd ? "Do not disturb" : "No notifications")
panelNamespace: "nova-notifications" panelNamespace: "nova-notifications"
panelContentWidth: 350 panelContentWidth: 350
@ -28,13 +29,13 @@ M.BarModule {
return S.NotifService.count > 0 ? "\uDB80\uDCA0" : "\uDB82\uDE93"; return S.NotifService.count > 0 ? "\uDB80\uDCA0" : "\uDB82\uDE93";
return S.NotifService.count > 0 ? "\uDB84\uDD6B" : "\uDB80\uDC9C"; return S.NotifService.count > 0 ? "\uDB84\uDD6B" : "\uDB80\uDC9C";
} }
color: S.NotifService.dnd ? S.Theme.base04 : root.accentColor color: S.NotifService.dnd ? NS.ThemeService.base04 : root.accentColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
M.BarLabel { M.BarLabel {
id: countLabel id: countLabel
label: S.NotifService.count > 0 ? String(S.NotifService.count) + (root.hasUrgent ? "!" : "") : "" label: S.NotifService.count > 0 ? String(S.NotifService.count) + (root.hasUrgent ? "!" : "") : ""
color: root.hasUrgent ? S.Theme.base08 : root.accentColor color: root.hasUrgent ? NS.ThemeService.base08 : root.accentColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
transform: Scale { transform: Scale {
@ -67,7 +68,7 @@ M.BarModule {
Connections { Connections {
target: S.NotifService target: S.NotifService
function onCountChanged() { function onCountChanged() {
if (S.NotifService.count > 0 && !S.Theme.reducedMotion) if (S.NotifService.count > 0 && !S.ThemeUtil.reducedMotion)
popAnim.start(); popAnim.start();
} }
} }

View file

@ -1,13 +1,14 @@
import QtQuick import QtQuick
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
Rectangle { Rectangle {
property color accentColor: S.Theme.base05 property color accentColor: NS.ThemeService.base05
color: S.Theme.base01 color: NS.ThemeService.base01
opacity: Math.max(S.Theme.barOpacity, 0.85) opacity: Math.max(NS.ThemeService.barOpacity, 0.85)
radius: S.Theme.radius radius: NS.ThemeService.radius
border.color: accentColor border.color: accentColor
border.width: 1 border.width: 1
} }

View file

@ -4,10 +4,11 @@ import Quickshell.Io
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
active: S.Modules.power.enable active: NS.ModulesService.powerEnable
tooltip: "Power menu" tooltip: "Power menu"
panelNamespace: "nova-power" panelNamespace: "nova-power"
panelContentWidth: 180 panelContentWidth: 180

View file

@ -1,10 +1,11 @@
import QtQuick import QtQuick
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
active: S.Modules.powerProfile.enable active: NS.ModulesService.powerProfileEnable
tooltip: "Power profile: " + (S.PowerProfileService.profile || "unknown") tooltip: "Power profile: " + (S.PowerProfileService.profile || "unknown")
onTapped: { onTapped: {
const cycle = ["performance", "balanced", "power-saver"]; const cycle = ["performance", "balanced", "power-saver"];
@ -13,7 +14,7 @@ M.BarModule {
} }
M.BarIcon { M.BarIcon {
color: S.PowerProfileService.profile === "performance" ? S.Theme.base09 : S.PowerProfileService.profile === "power-saver" ? S.Theme.base0B : root.accentColor color: S.PowerProfileService.profile === "performance" ? NS.ThemeService.base09 : S.PowerProfileService.profile === "power-saver" ? NS.ThemeService.base0B : root.accentColor
icon: { icon: {
if (S.PowerProfileService.profile === "performance") if (S.PowerProfileService.profile === "performance")
return "\uF0E7"; return "\uF0E7";

View file

@ -3,10 +3,11 @@ import QtQuick.Effects
import Quickshell.Services.Pipewire import Quickshell.Services.Pipewire
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
spacing: S.Theme.moduleSpacing spacing: NS.ThemeService.moduleSpacing
cursorShape: Qt.ArrowCursor cursorShape: Qt.ArrowCursor
readonly property bool _videoCapture: { readonly property bool _videoCapture: {
@ -35,21 +36,21 @@ M.BarModule {
return false; return false;
} }
active: S.Modules.privacy.enable && (root._videoCapture || root._audioIn) active: NS.ModulesService.privacyEnable && (root._videoCapture || root._audioIn)
// Screenshare indicator // Screenshare indicator
Text { Text {
visible: root._videoCapture visible: root._videoCapture
text: "\uF03D" text: "\uF03D"
color: S.Theme.base08 color: NS.ThemeService.base08
font.pixelSize: S.Theme.fontSize + 2 font.pixelSize: NS.ThemeService.fontSize + 2
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
layer.enabled: true layer.enabled: true
layer.effect: MultiEffect { layer.effect: MultiEffect {
shadowEnabled: true shadowEnabled: true
shadowColor: S.Theme.base08 shadowColor: NS.ThemeService.base08
shadowBlur: 0.8 shadowBlur: 0.8
shadowVerticalOffset: 0 shadowVerticalOffset: 0
shadowHorizontalOffset: 0 shadowHorizontalOffset: 0
@ -65,15 +66,15 @@ M.BarModule {
Text { Text {
visible: root._audioIn visible: root._audioIn
text: "\uF130" text: "\uF130"
color: S.Theme.base0B color: NS.ThemeService.base0B
font.pixelSize: S.Theme.fontSize + 2 font.pixelSize: NS.ThemeService.fontSize + 2
font.family: S.Theme.iconFontFamily font.family: NS.ThemeService.iconFontFamily
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
layer.enabled: true layer.enabled: true
layer.effect: MultiEffect { layer.effect: MultiEffect {
shadowEnabled: true shadowEnabled: true
shadowColor: S.Theme.base0B shadowColor: NS.ThemeService.base0B
shadowBlur: 0.8 shadowBlur: 0.8
shadowVerticalOffset: 0 shadowVerticalOffset: 0
shadowHorizontalOffset: 0 shadowHorizontalOffset: 0

View file

@ -3,7 +3,7 @@ import "../services" as S
SequentialAnimation { SequentialAnimation {
id: root id: root
loops: S.Theme.reducedMotion ? 1 : Animation.Infinite loops: S.ThemeUtil.reducedMotion ? 1 : Animation.Infinite
property real minOpacity: 0.4 property real minOpacity: 0.4
property int halfDuration: 400 property int halfDuration: 400

View file

@ -3,6 +3,7 @@ import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
// Draws rounded black corners at the edges of each screen. // Draws rounded black corners at the edges of each screen.
// Disabled when screenRadius is 0. // Disabled when screenRadius is 0.
@ -11,7 +12,7 @@ Item {
required property var screen required property var screen
readonly property int _r: S.Theme.screenRadius readonly property int _r: NS.ThemeService.screenRadius
component Corner: PanelWindow { component Corner: PanelWindow {
id: win id: win

View file

@ -5,10 +5,11 @@ import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
active: S.Modules.systemd.enable active: NS.ModulesService.systemdEnable
tooltip: { tooltip: {
const sys = S.SystemdService.systemState; const sys = S.SystemdService.systemState;
const fc = S.SystemdService.totalFailedCount; const fc = S.SystemdService.totalFailedCount;
@ -40,8 +41,8 @@ M.BarModule {
if (st === "running") if (st === "running")
return root.accentColor; return root.accentColor;
if (st === "degraded") if (st === "degraded")
return S.Theme.base0A; return NS.ThemeService.base0A;
return S.Theme.base08; return NS.ThemeService.base08;
} }
M.BarIcon { M.BarIcon {

View file

@ -3,11 +3,12 @@ import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
active: S.Modules.temperature.enable active: NS.ModulesService.temperatureEnable
spacing: Math.max(1, S.Theme.moduleSpacing - 2) spacing: Math.max(1, NS.ThemeService.moduleSpacing - 2)
tooltip: "Temperature: " + _temp + "\u00B0C" tooltip: "Temperature: " + _temp + "\u00B0C"
panelNamespace: "nova-temperature" panelNamespace: "nova-temperature"
panelContentWidth: 220 panelContentWidth: 220
@ -25,9 +26,9 @@ M.BarModule {
} }
} }
readonly property int _warm: S.Modules.temperature.warm || 80 readonly property int _warm: NS.ModulesService.temperatureWarm || 80
readonly property int _hot: S.Modules.temperature.hot || 90 readonly property int _hot: NS.ModulesService.temperatureHot || 90
readonly property string _deviceFilter: S.Modules.temperature.device || "" readonly property string _deviceFilter: NS.ModulesService.temperatureDevice || ""
readonly property int _temp: { readonly property int _temp: {
if (_deviceFilter !== "") { if (_deviceFilter !== "") {
@ -38,7 +39,7 @@ M.BarModule {
return S.SystemStats.tempCelsius; return S.SystemStats.tempCelsius;
} }
property color _stateColor: _temp > _hot ? S.Theme.base08 : _temp > _warm ? S.Theme.base0A : root.accentColor property color _stateColor: _temp > _hot ? NS.ThemeService.base08 : _temp > _warm ? NS.ThemeService.base0A : root.accentColor
Behavior on _stateColor { Behavior on _stateColor {
ColorAnimation { ColorAnimation {
duration: 300 duration: 300

View file

@ -3,6 +3,7 @@ import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
PanelWindow { PanelWindow {
id: root id: root
@ -17,7 +18,7 @@ PanelWindow {
if (_shown) { if (_shown) {
_winVisible = true; _winVisible = true;
hideAnim.stop(); hideAnim.stop();
if (S.Theme.reducedMotion) { if (S.ThemeUtil.reducedMotion) {
content.opacity = 1; content.opacity = 1;
content.y = 0; content.y = 0;
} else { } else {
@ -25,7 +26,7 @@ PanelWindow {
} }
} else { } else {
showAnim.stop(); showAnim.stop();
if (S.Theme.reducedMotion) { if (S.ThemeUtil.reducedMotion) {
_winVisible = false; _winVisible = false;
} else { } else {
hideAnim.start(); hideAnim.start();
@ -43,8 +44,8 @@ PanelWindow {
margins.top: 0 margins.top: 0
margins.left: Math.max(0, Math.min(Math.round(M.TooltipState.itemX - implicitWidth / 2), screen.width - implicitWidth)) margins.left: Math.max(0, Math.min(Math.round(M.TooltipState.itemX - implicitWidth / 2), screen.width - implicitWidth))
implicitWidth: label.implicitWidth + S.Theme.barPadding * 2 implicitWidth: label.implicitWidth + NS.ThemeService.barPadding * 2
implicitHeight: label.implicitHeight + S.Theme.barPadding * 2 implicitHeight: label.implicitHeight + NS.ThemeService.barPadding * 2
ParallelAnimation { ParallelAnimation {
id: showAnim id: showAnim
@ -101,9 +102,9 @@ PanelWindow {
anchors.centerIn: parent anchors.centerIn: parent
text: M.TooltipState.text.replace(/\n/g, "<br>") text: M.TooltipState.text.replace(/\n/g, "<br>")
textFormat: Text.RichText textFormat: Text.RichText
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
} }
} }

View file

@ -2,11 +2,12 @@ pragma Singleton
import QtQuick import QtQuick
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
QtObject { QtObject {
property bool visible: false property bool visible: false
property string text: "" property string text: ""
property real itemX: 0 property real itemX: 0
property var screen: null property var screen: null
property color accentColor: S.Theme.base05 property color accentColor: NS.ThemeService.base05
} }

View file

@ -2,6 +2,7 @@ import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
M.HoverPanel { M.HoverPanel {
id: menuWindow id: menuWindow
@ -29,8 +30,8 @@ M.HoverPanel {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 4 anchors.leftMargin: 4
anchors.rightMargin: 4 anchors.rightMargin: 4
color: backArea.containsMouse ? S.Theme.base02 : "transparent" color: backArea.containsMouse ? NS.ThemeService.base02 : "transparent"
radius: S.Theme.radius radius: NS.ThemeService.radius
} }
Text { Text {
@ -38,9 +39,9 @@ M.HoverPanel {
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 12 anchors.leftMargin: 12
text: "\u2039 Back" text: "\u2039 Back"
color: S.Theme.base05 color: NS.ThemeService.base05
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
MouseArea { MouseArea {
@ -74,7 +75,7 @@ M.HoverPanel {
anchors.leftMargin: 8 anchors.leftMargin: 8
anchors.rightMargin: 8 anchors.rightMargin: 8
height: 1 height: 1
color: S.Theme.base03 color: NS.ThemeService.base03
} }
Rectangle { Rectangle {
@ -82,8 +83,8 @@ M.HoverPanel {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 4 anchors.leftMargin: 4
anchors.rightMargin: 4 anchors.rightMargin: 4
color: rowArea.containsMouse && entryItem.modelData.enabled ? S.Theme.base02 : "transparent" color: rowArea.containsMouse && entryItem.modelData.enabled ? NS.ThemeService.base02 : "transparent"
radius: S.Theme.radius radius: NS.ThemeService.radius
} }
M.ThemedIcon { M.ThemedIcon {
@ -92,8 +93,8 @@ M.HoverPanel {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 12 anchors.leftMargin: 12
width: S.Theme.fontSize width: NS.ThemeService.fontSize
height: S.Theme.fontSize height: NS.ThemeService.fontSize
source: entryItem.modelData.icon source: entryItem.modelData.icon
tint: menuWindow.accentColor tint: menuWindow.accentColor
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
@ -107,9 +108,9 @@ M.HoverPanel {
anchors.right: entryChevron.visible ? entryChevron.left : parent.right anchors.right: entryChevron.visible ? entryChevron.left : parent.right
anchors.rightMargin: entryChevron.visible ? 4 : 12 anchors.rightMargin: entryChevron.visible ? 4 : 12
text: entryItem.modelData.text text: entryItem.modelData.text
color: entryItem.modelData.enabled ? S.Theme.base05 : S.Theme.base03 color: entryItem.modelData.enabled ? NS.ThemeService.base05 : NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -120,9 +121,9 @@ M.HoverPanel {
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 12 anchors.rightMargin: 12
text: "\u203A" text: "\u203A"
color: entryItem.modelData.enabled ? S.Theme.base05 : S.Theme.base03 color: entryItem.modelData.enabled ? NS.ThemeService.base05 : NS.ThemeService.base03
font.pixelSize: S.Theme.fontSize font.pixelSize: NS.ThemeService.fontSize
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
} }
MouseArea { MouseArea {

View file

@ -6,13 +6,14 @@ import Quickshell.Services.SystemTray
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
spacing: S.Theme.moduleSpacing + 2 spacing: NS.ThemeService.moduleSpacing + 2
cursorShape: Qt.ArrowCursor cursorShape: Qt.ArrowCursor
active: S.Modules.tray.enable && _trayRepeater.count > 0 active: NS.ModulesService.trayEnable && _trayRepeater.count > 0
property var _activeMenu: null property var _activeMenu: null
@ -28,8 +29,8 @@ M.BarModule {
property bool _hovered: false property bool _hovered: false
property real _pulseOpacity: 1 property real _pulseOpacity: 1
implicitWidth: S.Theme.fontSize + 4 implicitWidth: NS.ThemeService.fontSize + 4
implicitHeight: S.Theme.fontSize + 4 implicitHeight: NS.ThemeService.fontSize + 4
M.PulseAnimation on _pulseOpacity { M.PulseAnimation on _pulseOpacity {
running: iconItem._needsAttention running: iconItem._needsAttention
@ -43,7 +44,7 @@ M.BarModule {
layer.enabled: iconItem._needsAttention || iconItem._hovered layer.enabled: iconItem._needsAttention || iconItem._hovered
layer.effect: MultiEffect { layer.effect: MultiEffect {
shadowEnabled: true shadowEnabled: true
shadowColor: iconItem._needsAttention ? S.Theme.base08 : S.Theme.base05 shadowColor: iconItem._needsAttention ? NS.ThemeService.base08 : NS.ThemeService.base05
shadowBlur: iconItem._needsAttention ? 0.8 : 0.5 shadowBlur: iconItem._needsAttention ? 0.8 : 0.5
shadowVerticalOffset: 0 shadowVerticalOffset: 0
shadowHorizontalOffset: 0 shadowHorizontalOffset: 0
@ -52,7 +53,7 @@ M.BarModule {
M.ThemedIcon { M.ThemedIcon {
anchors.fill: parent anchors.fill: parent
source: iconItem.modelData.icon source: iconItem.modelData.icon
tint: iconItem._needsAttention ? S.Theme.base08 : root.accentColor tint: iconItem._needsAttention ? NS.ThemeService.base08 : root.accentColor
} }
} }

View file

@ -3,11 +3,12 @@ import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
active: S.Modules.volume.enable active: NS.ModulesService.volumeEnable
spacing: S.Theme.moduleSpacing spacing: NS.ThemeService.moduleSpacing
tooltip: "Volume: " + Math.round(volume * 100) + "%" + (muted ? " (muted)" : "") tooltip: "Volume: " + Math.round(volume * 100) + "%" + (muted ? " (muted)" : "")
panelNamespace: "nova-volume" panelNamespace: "nova-volume"
panelContentWidth: 220 panelContentWidth: 220
@ -21,7 +22,7 @@ M.BarModule {
readonly property real volume: S.PipewireService.volume readonly property real volume: S.PipewireService.volume
readonly property bool muted: S.PipewireService.muted readonly property bool muted: S.PipewireService.muted
readonly property string _volumeIcon: muted ? "\uF026" : (volume > 0.5 ? "\uF028" : (volume > 0 ? "\uF027" : "\uF026")) readonly property string _volumeIcon: muted ? "\uF026" : (volume > 0.5 ? "\uF028" : (volume > 0 ? "\uF027" : "\uF026"))
readonly property color _volumeColor: muted ? S.Theme.base04 : root.accentColor readonly property color _volumeColor: muted ? NS.ThemeService.base04 : root.accentColor
property bool _volumeInit: false property bool _volumeInit: false
property bool _mutedInit: false property bool _mutedInit: false

View file

@ -3,11 +3,12 @@ import Quickshell
import "." as M import "." as M
import "../services" as S import "../services" as S
import "../applets" as C import "../applets" as C
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
spacing: S.Theme.moduleSpacing spacing: NS.ThemeService.moduleSpacing
active: S.Modules.weather.enable && S.WeatherService.available active: NS.ModulesService.weatherEnable && S.WeatherService.available
tooltip: "Weather" tooltip: "Weather"
panelNamespace: "nova-weather" panelNamespace: "nova-weather"
panelContentWidth: 280 panelContentWidth: 280

View file

@ -4,10 +4,11 @@ import Quickshell
import Quickshell.Widgets import Quickshell.Widgets
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
spacing: S.Theme.moduleSpacing spacing: NS.ThemeService.moduleSpacing
tooltip: S.NiriIpc.focusedAppId ? S.NiriIpc.focusedAppId + "\n" + S.NiriIpc.focusedTitle : S.NiriIpc.focusedTitle tooltip: S.NiriIpc.focusedAppId ? S.NiriIpc.focusedAppId + "\n" + S.NiriIpc.focusedTitle : S.NiriIpc.focusedTitle
cursorShape: Qt.ArrowCursor cursorShape: Qt.ArrowCursor
@ -27,7 +28,7 @@ M.BarModule {
id: _icon id: _icon
visible: root._iconSource !== "" visible: root._iconSource !== ""
source: root._iconSource source: root._iconSource
implicitSize: S.Theme.fontSize + 2 implicitSize: NS.ThemeService.fontSize + 2
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
layer.enabled: true layer.enabled: true
layer.effect: MultiEffect { layer.effect: MultiEffect {

View file

@ -3,10 +3,11 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
import "../services" as S import "../services" as S
import NovaStats as NS
M.BarModule { M.BarModule {
id: root id: root
active: S.Modules.workspaces.enable active: NS.ModulesService.workspacesEnable
spacing: 4 spacing: 4
cursorShape: Qt.ArrowCursor cursorShape: Qt.ArrowCursor
@ -79,10 +80,10 @@ M.BarModule {
} }
} }
width: S.Theme.fontSize + 4 width: NS.ThemeService.fontSize + 4
height: S.Theme.fontSize + 4 height: NS.ThemeService.fontSize + 4
radius: width / 2 radius: width / 2
color: pill.active ? root.accentColor : (pill._hovered ? S.Theme.base03 : S.Theme.base02) color: pill.active ? root.accentColor : (pill._hovered ? NS.ThemeService.base03 : NS.ThemeService.base02)
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
duration: 150 duration: 150
@ -92,9 +93,9 @@ M.BarModule {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: pill.modelData.idx text: pill.modelData.idx
color: pill.active ? S.Theme.base00 : root.accentColor color: pill.active ? NS.ThemeService.base00 : root.accentColor
font.pixelSize: S.Theme.fontSize - 2 font.pixelSize: NS.ThemeService.fontSize - 2
font.family: S.Theme.fontFamily font.family: NS.ThemeService.fontFamily
font.bold: pill.active font.bold: pill.active
} }

View file

@ -4,6 +4,7 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import "." as S import "." as S
import NovaStats as NS
QtObject { QtObject {
id: root id: root
@ -12,7 +13,7 @@ QtObject {
readonly property bool available: _blDev !== "" readonly property bool available: _blDev !== ""
function adjust(delta) { function adjust(delta) {
const step = S.Modules.backlight.step || 5; const step = NS.ModulesService.backlightStep || 5;
_adjProc.cmd = delta > 0 ? "light -A " + step : "light -U " + step; _adjProc.cmd = delta > 0 ? "light -A " + step : "light -U " + step;
_adjProc.running = true; _adjProc.running = true;
} }

View file

@ -3,6 +3,7 @@ pragma Singleton
import QtQuick import QtQuick
import Quickshell.Services.UPower import Quickshell.Services.UPower
import "." as S import "." as S
import NovaStats as NS
QtObject { QtObject {
id: root id: root
@ -20,11 +21,11 @@ QtObject {
readonly property bool healthSupported: dev?.healthSupported ?? false readonly property bool healthSupported: dev?.healthSupported ?? false
readonly property real healthPercent: (dev?.healthPercentage ?? 1) * 100 readonly property real healthPercent: (dev?.healthPercentage ?? 1) * 100
readonly property int critThresh: S.Modules.battery.critical || 15 readonly property int critThresh: NS.ModulesService.batteryCritical || 15
readonly property int warnThresh: S.Modules.battery.warning || 25 readonly property int warnThresh: NS.ModulesService.batteryWarning || 25
readonly property bool critical: percent < critThresh && !charging readonly property bool critical: percent < critThresh && !charging
readonly property color stateColor: charging ? S.Theme.base0B : critical ? S.Theme.base09 : percent < warnThresh ? S.Theme.base0A : S.Theme.base05 readonly property color stateColor: charging ? NS.ThemeService.base0B : critical ? NS.ThemeService.base09 : percent < warnThresh ? NS.ThemeService.base0A : NS.ThemeService.base05
// 24h history (1440 samples @ 60s) // 24h history (1440 samples @ 60s)
property var history: [] property var history: []

View file

@ -3,6 +3,7 @@ pragma Singleton
import QtQuick import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as S import "." as S
import NovaStats as NS
QtObject { QtObject {
id: root id: root
@ -38,7 +39,7 @@ QtObject {
// Status polling (bar icon state) // Status polling (bar icon state)
property Process _statusProc: Process { property Process _statusProc: Process {
running: S.Modules.bluetooth.enable running: NS.ModulesService.bluetoothEnable
command: ["sh", "-c", "s=$(bluetoothctl show 2>/dev/null); " + "[ -z \"$s\" ] && echo unavailable && exit; " + "echo \"$s\" | grep -q 'Powered: yes' || { echo off:; exit; }; " + "info=$(bluetoothctl info 2>/dev/null); " + "d=$(echo \"$info\" | awk -F': ' '/\\tName:/{n=$2}/Connected: yes/{c=1}END{if(c)print n}'); " + "[ -n \"$d\" ] && echo \"connected:$d\" || { echo on:; exit; }; " + "bat=$(echo \"$info\" | awk -F': ' '/Battery Percentage.*\\(/{gsub(/[^0-9]/,\"\",$2);print $2}'); " + "[ -n \"$bat\" ] && echo \"bat:$bat\""] command: ["sh", "-c", "s=$(bluetoothctl show 2>/dev/null); " + "[ -z \"$s\" ] && echo unavailable && exit; " + "echo \"$s\" | grep -q 'Powered: yes' || { echo off:; exit; }; " + "info=$(bluetoothctl info 2>/dev/null); " + "d=$(echo \"$info\" | awk -F': ' '/\\tName:/{n=$2}/Connected: yes/{c=1}END{if(c)print n}'); " + "[ -n \"$d\" ] && echo \"connected:$d\" || { echo on:; exit; }; " + "bat=$(echo \"$info\" | awk -F': ' '/Battery Percentage.*\\(/{gsub(/[^0-9]/,\"\",$2);print $2}'); " + "[ -n \"$bat\" ] && echo \"bat:$bat\""]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
@ -58,7 +59,7 @@ QtObject {
// Event-driven: watch BlueZ DBus property changes // Event-driven: watch BlueZ DBus property changes
property Process _monitor: Process { property Process _monitor: Process {
running: S.Modules.bluetooth.enable running: NS.ModulesService.bluetoothEnable
command: ["sh", "-c", "dbus-monitor --system \"interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path_namespace='/org/bluez'\" 2>/dev/null"] command: ["sh", "-c", "dbus-monitor --system \"interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path_namespace='/org/bluez'\" 2>/dev/null"]
stdout: SplitParser { stdout: SplitParser {
splitMarker: "\n" splitMarker: "\n"
@ -73,7 +74,7 @@ QtObject {
property Timer _fallbackPoll: Timer { property Timer _fallbackPoll: Timer {
interval: 60000 interval: 60000
running: S.Modules.bluetooth.enable running: NS.ModulesService.bluetoothEnable
repeat: true repeat: true
onTriggered: root.refresh() onTriggered: root.refresh()
} }

View file

@ -39,7 +39,7 @@ QtObject {
property Timer _pollTimer: Timer { property Timer _pollTimer: Timer {
interval: { interval: {
const ms = S.Modules.statsDaemon.interval; const ms = NS.ModulesService.statsDaemonInterval;
return ms > 0 ? ms : 4000; return ms > 0 ? ms : 4000;
} }
running: true running: true

View file

@ -3,11 +3,12 @@ pragma Singleton
import QtQuick import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as S import "." as S
import NovaStats as NS
QtObject { QtObject {
id: root id: root
readonly property bool enabled: S.Modules.lock.enable readonly property bool enabled: NS.ModulesService.lockEnable
property bool locked: false property bool locked: false
property string sessionPath: "" property string sessionPath: ""

View file

@ -3,6 +3,7 @@ pragma Singleton
import QtQuick import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as S import "." as S
import NovaStats as NS
QtObject { QtObject {
id: root id: root
@ -71,8 +72,8 @@ QtObject {
} }
property Timer _poll: Timer { property Timer _poll: Timer {
interval: S.Modules.machinectl.interval ?? 15000 interval: NS.ModulesService.machinectlInterval ?? 15000
running: S.Modules.machinectl.enable running: NS.ModulesService.machinectlEnable
repeat: true repeat: true
triggeredOnStart: true triggeredOnStart: true
onTriggered: if (!root._listProc.running) onTriggered: if (!root._listProc.running)

View file

@ -1,180 +0,0 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
QtObject {
id: root
property var workspaces: ({
enable: true
})
property var tray: ({
enable: true
})
property var windowTitle: ({
enable: true
})
property var clock: ({
enable: true
})
property var notifications: ({
enable: true,
timeout: 3000,
maxPopups: 4,
maxVisible: 10,
maxHistory: -1
})
property var mpris: ({
enable: true
})
property var volume: ({
enable: true
})
property var bluetooth: ({
enable: true
})
property var backlight: ({
enable: true,
step: 5
})
property var network: ({
enable: true
})
property var powerProfile: ({
enable: true
})
property var idleInhibitor: ({
enable: true
})
property var weather: ({
enable: true,
args: ["--nerd"],
interval: 3600000
})
property var temperature: ({
enable: true,
warm: 80,
hot: 90,
device: ""
})
property var gpu: ({
enable: true,
warm: 70,
hot: 85
})
property var cpu: ({
enable: true
})
property var memory: ({
enable: true
})
property var disk: ({
enable: true,
interval: 30000,
warnThreshold: 85
})
property var battery: ({
enable: true,
warning: 25,
critical: 15
})
property var privacy: ({
enable: true
})
property var screenCorners: ({
enable: true
})
property var power: ({
enable: true
})
property var backgroundOverlay: ({
enable: true
})
property var overviewBackdrop: ({
enable: true
})
property var lock: ({
enable: true,
screenshot: true,
notifications: true,
mpris: true,
volume: true,
weather: true,
threatEffect: true
})
property var dock: ({
enable: true,
width: 300,
applets: {
clock: true,
cpu: true,
gpu: true,
memory: true,
temperature: true,
disk: true,
battery: true,
network: true,
bluetooth: true,
volume: true,
backlight: true,
weather: true,
mpris: true,
notifications: true,
power: true
}
})
property var systemd: ({
enable: true,
interval: 15000
})
property var machinectl: ({
enable: true,
interval: 15000
})
property var statsDaemon: ({
interval: -1
})
// All module keys that have an enable flag used to default-enable anything
// not explicitly mentioned in modules.json
readonly property var _moduleKeys: ["workspaces", "tray", "windowTitle", "clock", "notifications", "mpris", "volume", "bluetooth", "backlight", "network", "powerProfile", "idleInhibitor", "weather", "temperature", "gpu", "cpu", "memory", "disk", "battery", "privacy", "screenCorners", "power", "backgroundOverlay", "overviewBackdrop", "lock", "dock", "systemd", "machinectl"]
// Fallback: if modules.json doesn't exist, enable everything
Component.onCompleted: _apply("{}")
property FileView _file: FileView {
path: (Quickshell.env("XDG_CONFIG_HOME") || (Quickshell.env("HOME") + "/.config")) + "/nova-shell/modules.json"
watchChanges: true
onFileChanged: reload()
onLoaded: root._apply(text())
}
function _apply(raw) {
let data = {};
try {
data = JSON.parse(raw);
} catch (e) {}
// Enable all modules that aren't explicitly mentioned in the JSON
for (const k of _moduleKeys) {
if (!(k in data))
root[k] = Object.assign({}, root[k], {
enable: true
});
}
// Apply JSON overrides
for (const k of Object.keys(data)) {
if (!(k in root))
continue;
const v = data[k];
if (typeof v === "object" && v !== null)
root[k] = Object.assign({}, root[k], v);
else if (typeof v === "boolean")
root[k] = Object.assign({}, root[k], {
enable: v
});
}
}
}

View file

@ -3,6 +3,7 @@ pragma Singleton
import QtQuick import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as S import "." as S
import NovaStats as NS
QtObject { QtObject {
id: root id: root
@ -40,7 +41,7 @@ QtObject {
// Status polling // Status polling
property Process _statusProc: Process { property Process _statusProc: Process {
running: S.Modules.network.enable running: NS.ModulesService.networkEnable
command: ["sh", "-c", "line=$(nmcli -t -f NAME,TYPE,DEVICE connection show --active 2>/dev/null | head -1); if [ -z \"$line\" ]; then dev=$(nmcli -t -f DEVICE,STATE device 2>/dev/null | grep ':connected' | grep -v ':unmanaged\\|:unavailable\\|:disconnected\\|:connecting' | head -1 | cut -d: -f1); [ -n \"$dev\" ] && line=\"linked:linked:$dev\"; fi; [ -z \"$line\" ] && exit 0; echo \"$line\"; dev=$(echo \"$line\" | cut -d: -f3); ip=$(nmcli -t -f IP4.ADDRESS device show \"$dev\" 2>/dev/null | head -1 | cut -d: -f2); echo \"ip:${ip:-}\"; sig=$(nmcli -t -f GENERAL.SIGNAL device show \"$dev\" 2>/dev/null | head -1 | cut -d: -f2); echo \"sig:${sig:-}\""] command: ["sh", "-c", "line=$(nmcli -t -f NAME,TYPE,DEVICE connection show --active 2>/dev/null | head -1); if [ -z \"$line\" ]; then dev=$(nmcli -t -f DEVICE,STATE device 2>/dev/null | grep ':connected' | grep -v ':unmanaged\\|:unavailable\\|:disconnected\\|:connecting' | head -1 | cut -d: -f1); [ -n \"$dev\" ] && line=\"linked:linked:$dev\"; fi; [ -z \"$line\" ] && exit 0; echo \"$line\"; dev=$(echo \"$line\" | cut -d: -f3); ip=$(nmcli -t -f IP4.ADDRESS device show \"$dev\" 2>/dev/null | head -1 | cut -d: -f2); echo \"ip:${ip:-}\"; sig=$(nmcli -t -f GENERAL.SIGNAL device show \"$dev\" 2>/dev/null | head -1 | cut -d: -f2); echo \"sig:${sig:-}\""]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
@ -76,7 +77,7 @@ QtObject {
// Event-driven monitor // Event-driven monitor
property Process _monitor: Process { property Process _monitor: Process {
running: S.Modules.network.enable running: NS.ModulesService.networkEnable
command: ["nmcli", "monitor"] command: ["nmcli", "monitor"]
stdout: SplitParser { stdout: SplitParser {
splitMarker: "\n" splitMarker: "\n"
@ -92,7 +93,7 @@ QtObject {
// Fallback poll // Fallback poll
property Timer _fallbackPoll: Timer { property Timer _fallbackPoll: Timer {
interval: 60000 interval: 60000
running: S.Modules.network.enable running: NS.ModulesService.networkEnable
repeat: true repeat: true
onTriggered: root.refresh() onTriggered: root.refresh()
} }

View file

@ -4,6 +4,7 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Services.Notifications import Quickshell.Services.Notifications
import "." as S import "." as S
import NovaStats as NS
QtObject { QtObject {
id: root id: root
@ -96,7 +97,7 @@ QtObject {
}); });
// Trim excess popups // Trim excess popups
const max = S.Modules.notifications.maxPopups || 4; const max = NS.ModulesService.notificationsMaxPopups || 4;
const currentPopups = root.list.filter(n => n.popup); const currentPopups = root.list.filter(n => n.popup);
if (currentPopups.length > max) { if (currentPopups.length > max) {
for (let i = max; i < currentPopups.length; i++) for (let i = max; i < currentPopups.length; i++)
@ -106,13 +107,13 @@ QtObject {
// Auto-expire popup (skip for critical) // Auto-expire popup (skip for critical)
if (item.popup && !isCritical) { if (item.popup && !isCritical) {
const timeout = notif.expireTimeout > 0 ? notif.expireTimeout : (S.Modules.notifications.timeout || 3000); const timeout = notif.expireTimeout > 0 ? notif.expireTimeout : (NS.ModulesService.notificationsTimeout || 3000);
item._expireTimer.interval = timeout; item._expireTimer.interval = timeout;
item._expireTimer.running = true; item._expireTimer.running = true;
} }
// Trim history (-1 = unlimited) // Trim history (-1 = unlimited)
const maxHistory = S.Modules.notifications.maxHistory ?? -1; const maxHistory = NS.ModulesService.notificationsMaxHistory ?? -1;
while (maxHistory > 0 && root.list.length > maxHistory) { while (maxHistory > 0 && root.list.length > maxHistory) {
const old = root.list.pop(); const old = root.list.pop();
old.finishDismiss(); old.finishDismiss();

View file

@ -3,6 +3,7 @@ pragma Singleton
import QtQuick import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as S import "." as S
import NovaStats as NS
QtObject { QtObject {
id: root id: root
@ -11,7 +12,7 @@ QtObject {
readonly property bool powerSaver: profile === "power-saver" readonly property bool powerSaver: profile === "power-saver"
property var _proc: Process { property var _proc: Process {
running: S.Modules.powerProfile.enable running: NS.ModulesService.powerProfileEnable
command: ["powerprofilesctl", "get"] command: ["powerprofilesctl", "get"]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: root.profile = text.trim() onStreamFinished: root.profile = text.trim()
@ -19,7 +20,7 @@ QtObject {
} }
property var _monitor: Process { property var _monitor: Process {
running: S.Modules.powerProfile.enable running: NS.ModulesService.powerProfileEnable
command: ["sh", "-c", "dbus-monitor --system \"interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='/net/hadess/PowerProfiles'\" 2>/dev/null"] command: ["sh", "-c", "dbus-monitor --system \"interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='/net/hadess/PowerProfiles'\" 2>/dev/null"]
stdout: SplitParser { stdout: SplitParser {
splitMarker: "\n" splitMarker: "\n"
@ -34,7 +35,7 @@ QtObject {
property var _poll: Timer { property var _poll: Timer {
interval: 60000 interval: 60000
running: S.Modules.powerProfile.enable running: NS.ModulesService.powerProfileEnable
repeat: true repeat: true
onTriggered: root._proc.running = true onTriggered: root._proc.running = true
} }

View file

@ -52,7 +52,7 @@ QtObject {
// Drive the Rust service from QML timers; both intervals read from Modules config. // Drive the Rust service from QML timers; both intervals read from Modules config.
property Timer _statsTimer: Timer { property Timer _statsTimer: Timer {
interval: { interval: {
const ms = M.Modules.statsDaemon.interval; const ms = NS.ModulesService.statsDaemonInterval;
return ms > 0 ? ms : 4000; return ms > 0 ? ms : 4000;
} }
running: true running: true
@ -62,7 +62,7 @@ QtObject {
} }
property Timer _diskTimer: Timer { property Timer _diskTimer: Timer {
interval: M.Modules.disk.interval || 30000 interval: NS.ModulesService.diskInterval || 30000
running: true running: true
repeat: true repeat: true
triggeredOnStart: true triggeredOnStart: true

View file

@ -3,6 +3,7 @@ pragma Singleton
import QtQuick import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as S import "." as S
import NovaStats as NS
QtObject { QtObject {
id: root id: root
@ -64,8 +65,8 @@ QtObject {
} }
property Timer _poll: Timer { property Timer _poll: Timer {
interval: S.Modules.systemd.interval ?? 15000 interval: NS.ModulesService.systemdInterval ?? 15000
running: S.Modules.systemd.enable running: NS.ModulesService.systemdEnable
repeat: true repeat: true
triggeredOnStart: true triggeredOnStart: true
onTriggered: if (!root._pollProc.running) onTriggered: if (!root._pollProc.running)

View file

@ -1,95 +0,0 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
QtObject {
id: root
// base16 palette, overwritten from ~/.config/nova-shell/theme.json
property color base00: "#1e1e2e"
property color base01: "#181825"
property color base02: "#313244"
property color base03: "#45475a"
property color base04: "#585b70"
property color base05: "#cdd6f4"
property color base06: "#f5e0dc"
property color base07: "#b4befe"
property color base08: "#f38ba8"
property color base09: "#fab387"
property color base0A: "#f9e2af"
property color base0B: "#a6e3a1"
property color base0C: "#94e2d5"
property color base0D: "#89b4fa"
property color base0E: "#cba6f7"
property color base0F: "#f2cdcd"
property string fontFamily: "sans-serif"
property string iconFontFamily: "Symbols Nerd Font"
property int fontSize: 12
property real barOpacity: 0.9
property int barHeight: 32
property int barPadding: 8
property int moduleSpacing: 4
property int groupSpacing: 6
property int groupPadding: 8
property int radius: 4
property int screenRadius: 15
property bool _reducedMotionConfig: false
readonly property bool reducedMotion: _reducedMotionConfig || PowerProfileService.powerSaver
// Green -> yellow -> red gradient for 0-100% load/usage values
function loadColor(pct) {
const t = Math.max(0, Math.min(100, pct)) / 100;
const a = t < 0.5 ? root.base0B : root.base0A;
const b = t < 0.5 ? root.base0A : root.base08;
const u = t < 0.5 ? t * 2 : (t - 0.5) * 2;
return Qt.rgba(a.r + (b.r - a.r) * u, a.g + (b.g - a.g) * u, a.b + (b.b - a.b) * u, 1);
}
property FileView _themeFile: FileView {
path: (Quickshell.env("XDG_CONFIG_HOME") || (Quickshell.env("HOME") + "/.config")) + "/nova-shell/theme.json"
watchChanges: true
onFileChanged: reload()
onLoaded: root._apply(text())
}
function _apply(raw) {
let data;
try {
data = JSON.parse(raw);
} catch (e) {
return;
}
const c = data.colors || {};
for (const k of Object.keys(c)) {
if (k in root)
root[k] = c[k];
}
if (data.fontFamily)
root.fontFamily = data.fontFamily;
if (data.iconFontFamily)
root.iconFontFamily = data.iconFontFamily;
if (data.fontSize)
root.fontSize = data.fontSize;
if (data.barOpacity !== undefined)
root.barOpacity = data.barOpacity;
if (data.barHeight !== undefined)
root.barHeight = data.barHeight;
if (data.barPadding !== undefined)
root.barPadding = data.barPadding;
if (data.moduleSpacing !== undefined)
root.moduleSpacing = data.moduleSpacing;
if (data.groupSpacing !== undefined)
root.groupSpacing = data.groupSpacing;
if (data.groupPadding !== undefined)
root.groupPadding = data.groupPadding;
if (data.radius !== undefined)
root.radius = data.radius;
if (data.screenRadius !== undefined)
root.screenRadius = data.screenRadius;
if (data.reducedMotion !== undefined)
root._reducedMotionConfig = data.reducedMotion;
}
}

View file

@ -0,0 +1,23 @@
pragma Singleton
import QtQuick
import NovaStats as NS
import "." as S
// Helpers that need QML-side state (PowerProfileService) or compute over the
// raw theme primitives. Plain values come straight from NS.ThemeService.
QtObject {
id: root
// Effective reduced-motion: configured value OR power-saver active.
readonly property bool reducedMotion: NS.ThemeService.reducedMotionConfig || S.PowerProfileService.powerSaver
// Green -> yellow -> red gradient for 0-100% load/usage values.
function loadColor(pct) {
const t = Math.max(0, Math.min(100, pct)) / 100;
const a = t < 0.5 ? NS.ThemeService.base0B : NS.ThemeService.base0A;
const b = t < 0.5 ? NS.ThemeService.base0A : NS.ThemeService.base08;
const u = t < 0.5 ? t * 2 : (t - 0.5) * 2;
return Qt.rgba(a.r + (b.r - a.r) * u, a.g + (b.g - a.g) * u, a.b + (b.b - a.b) * u, 1);
}
}

View file

@ -4,6 +4,7 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import "." as S import "." as S
import NovaStats as NS
QtObject { QtObject {
id: root id: root
@ -13,8 +14,8 @@ QtObject {
readonly property bool available: icon !== "" readonly property bool available: icon !== ""
property Process _proc: Process { property Process _proc: Process {
running: S.Modules.weather.enable running: NS.ModulesService.weatherEnable
command: ["wttrbar"].concat(S.Modules.weather.args) command: ["wttrbar"].concat(NS.ModulesService.weatherArgs)
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
try { try {
@ -30,8 +31,8 @@ QtObject {
} }
property Timer _poll: Timer { property Timer _poll: Timer {
interval: S.Modules.weather.interval || 3600000 interval: NS.ModulesService.weatherInterval || 3600000
running: S.Modules.weather.enable running: NS.ModulesService.weatherEnable
repeat: true repeat: true
onTriggered: root._proc.running = true onTriggered: root._proc.running = true
} }

View file

@ -9,7 +9,6 @@ singleton DockState 1.0 DockState.qml
singleton IdleInhibitService 1.0 IdleInhibitService.qml singleton IdleInhibitService 1.0 IdleInhibitService.qml
singleton LockService 1.0 LockService.qml singleton LockService 1.0 LockService.qml
singleton MachinectlService 1.0 MachinectlService.qml singleton MachinectlService 1.0 MachinectlService.qml
singleton Modules 1.0 Modules.qml
singleton MprisService 1.0 MprisService.qml singleton MprisService 1.0 MprisService.qml
singleton NetworkService 1.0 NetworkService.qml singleton NetworkService 1.0 NetworkService.qml
singleton NiriIpc 1.0 NiriIpc.qml singleton NiriIpc 1.0 NiriIpc.qml
@ -20,6 +19,6 @@ singleton ScreenshotService 1.0 ScreenshotService.qml
singleton SleepService 1.0 SleepService.qml singleton SleepService 1.0 SleepService.qml
singleton SystemStats 1.0 SystemStats.qml singleton SystemStats 1.0 SystemStats.qml
singleton SystemdService 1.0 SystemdService.qml singleton SystemdService 1.0 SystemdService.qml
singleton Theme 1.0 Theme.qml singleton ThemeUtil 1.0 ThemeUtil.qml
singleton WeatherService 1.0 WeatherService.qml singleton WeatherService 1.0 WeatherService.qml
# keep-sorted end # keep-sorted end

View file

@ -5,6 +5,7 @@ import "modules"
import "services" import "services"
import "dock" as Dock import "dock" as Dock
import "lock" as Lock import "lock" as Lock
import NovaStats as NS
import Quickshell import Quickshell
ShellRoot { ShellRoot {
@ -35,49 +36,49 @@ ShellRoot {
} }
LazyLoader { LazyLoader {
active: (Modules.notifications.maxPopups ?? 4) > 0 active: NS.ModulesService.notificationsMaxPopups > 0
NotifPopup { NotifPopup {
screen: scope.modelData screen: scope.modelData
} }
} }
LazyLoader { LazyLoader {
active: Modules.backgroundOverlay.enable active: NS.ModulesService.backgroundOverlayEnable
BackgroundOverlay { BackgroundOverlay {
screen: scope.modelData screen: scope.modelData
} }
} }
LazyLoader { LazyLoader {
active: Modules.overviewBackdrop.enable && NiriIpc.available active: NS.ModulesService.overviewBackdropEnable && NiriIpc.available
OverviewBackdrop { OverviewBackdrop {
screen: scope.modelData screen: scope.modelData
} }
} }
LazyLoader { LazyLoader {
active: Modules.lock.enable && (Modules.lock.screenshot ?? true) active: NS.ModulesService.lockEnable && NS.ModulesService.lockScreenshot
ScreenCapture { ScreenCapture {
screen: scope.modelData screen: scope.modelData
} }
} }
LazyLoader { LazyLoader {
active: Modules.screenCorners.enable active: NS.ModulesService.screenCornersEnable
ScreenCorners { ScreenCorners {
screen: scope.modelData screen: scope.modelData
} }
} }
LazyLoader { LazyLoader {
active: Modules.dock.enable && scope._isRightmost active: NS.ModulesService.dockEnable && scope._isRightmost
Dock.AppletDock { Dock.AppletDock {
screen: scope.modelData screen: scope.modelData
} }
} }
LazyLoader { LazyLoader {
active: Modules.dock.enable && scope._isRightmost active: NS.ModulesService.dockEnable && scope._isRightmost
Dock.DockEdgeTrigger { Dock.DockEdgeTrigger {
screen: scope.modelData screen: scope.modelData
} }

View file

@ -1,57 +1,199 @@
shell/applets/AppletActionBar.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/BacklightApplet.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/BacklightApplet.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/BatteryApplet.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/BatteryApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/BatteryApplet.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/BatteryApplet.qml: Type "QColor" of property "base09" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/BatteryApplet.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/BatteryApplet.qml: Type "QColor" of property "base0B" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/BluetoothApplet.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/BluetoothApplet.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/BluetoothApplet.qml: Unqualified access [unqualified] shell/applets/BluetoothApplet.qml: Unqualified access [unqualified]
shell/applets/ClockApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/ClockApplet.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/ClockApplet.qml: Unqualified access [unqualified] shell/applets/ClockApplet.qml: Unqualified access [unqualified]
shell/applets/CpuApplet.qml: Member "_barColor" not found on type "QQuickItem" [missing-property] shell/applets/CpuApplet.qml: Member "_barColor" not found on type "QQuickItem" [missing-property]
shell/applets/CpuApplet.qml: Member "_f" not found on type "QQuickItem" [missing-property] shell/applets/CpuApplet.qml: Member "_f" not found on type "QQuickItem" [missing-property]
shell/applets/CpuApplet.qml: Member "_throttled" not found on type "QQuickItem" [missing-property] shell/applets/CpuApplet.qml: Member "_throttled" not found on type "QQuickItem" [missing-property]
shell/applets/CpuApplet.qml: Member "_u" not found on type "QQuickItem" [missing-property]
shell/applets/CpuApplet.qml: Member "index" not found on type "QQuickItem" [missing-property] shell/applets/CpuApplet.qml: Member "index" not found on type "QQuickItem" [missing-property]
shell/applets/CpuApplet.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/CpuApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/CpuApplet.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/CpuApplet.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/CpuApplet.qml: Unqualified access [unqualified] shell/applets/CpuApplet.qml: Unqualified access [unqualified]
shell/applets/DiskApplet.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/DiskApplet.qml: Unqualified access [unqualified] shell/applets/DiskApplet.qml: Unqualified access [unqualified]
shell/applets/GpuApplet.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/GpuApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/GpuApplet.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/GpuApplet.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/GpuApplet.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/HexWaveBackground.qml: Type "QColor" of property "base09" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/HexWaveBackground.qml: Type "QColor" of property "base0C" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/HexWaveBackground.qml: Type "QColor" of property "base0E" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/HoverableListItem.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/InfoRow.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/InfoRow.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base00" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base0B" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MemoryApplet.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MemoryApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MemoryApplet.qml: Type "QColor" of property "base0D" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MemoryApplet.qml: Unqualified access [unqualified] shell/applets/MemoryApplet.qml: Unqualified access [unqualified]
shell/applets/MprisApplet.qml: Member "frac" not found on type "QQuickItem" [missing-property] shell/applets/MprisApplet.qml: Member "frac" not found on type "QQuickItem" [missing-property]
shell/applets/MprisApplet.qml: Member "join" not found on type "QString" [missing-property] shell/applets/MprisApplet.qml: Member "join" not found on type "QString" [missing-property]
shell/applets/MprisApplet.qml: Member "spacing" not found on type "Repeater" [missing-property]
shell/applets/MprisApplet.qml: Type "QColor" of property "base01" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MprisApplet.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MprisApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MprisApplet.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MprisApplet.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MprisApplet.qml: Unqualified access [unqualified] shell/applets/MprisApplet.qml: Unqualified access [unqualified]
shell/applets/NetworkApplet.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/NetworkApplet.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/NetworkApplet.qml: Unqualified access [unqualified] shell/applets/NetworkApplet.qml: Unqualified access [unqualified]
shell/applets/NotifApplet.qml: Member "_notif" not found on type "QQuickItem" [missing-property] shell/applets/NotifApplet.qml: Member "_notif" not found on type "QQuickItem" [missing-property]
shell/applets/NotifApplet.qml: Member "_type" not found on type "QQuickItem" [missing-property] shell/applets/NotifApplet.qml: Member "_type" not found on type "QQuickItem" [missing-property]
shell/applets/NotifApplet.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/NotifApplet.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/NotifApplet.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/NotifApplet.qml: Type "QColor" of property "base09" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/NotifApplet.qml: Unqualified access [unqualified] shell/applets/NotifApplet.qml: Unqualified access [unqualified]
shell/applets/PowerApplet.qml: Type "QColor" of property "base01" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/PowerApplet.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/PowerApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/PowerApplet.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/PowerApplet.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/PowerApplet.qml: Type "QColor" of property "base09" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/PowerApplet.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/PowerApplet.qml: Type "QColor" of property "base0D" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/PowerApplet.qml: Type "QColor" of property "base0E" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/PowerApplet.qml: Unqualified access [unqualified] shell/applets/PowerApplet.qml: Unqualified access [unqualified]
shell/applets/Separator.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdApplet.qml: Type "QColor" of property "base00" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdApplet.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdApplet.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdApplet.qml: Type "QColor" of property "base0B" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base00" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base01" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/TemperatureApplet.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/TemperatureApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/TemperatureApplet.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/TemperatureApplet.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/TemperatureApplet.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/TemperatureApplet.qml: Unqualified access [unqualified] shell/applets/TemperatureApplet.qml: Unqualified access [unqualified]
shell/applets/VolumeApplet.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/VolumeApplet.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/VolumeApplet.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/VolumeApplet.qml: Unqualified access [unqualified] shell/applets/VolumeApplet.qml: Unqualified access [unqualified]
shell/applets/WeatherApplet.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/dock/AppletDock.qml: Could not find property "top". [missing-property] shell/dock/AppletDock.qml: Could not find property "top". [missing-property]
shell/dock/AppletDock.qml: Type "QColor" of property "base00" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/dock/AppletDock.qml: Type "QColor" of property "base09" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/dock/AppletDock.qml: Type "QColor" of property "base0C" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/dock/AppletDock.qml: Type PanelWindow is not creatable. [uncreatable-type] shell/dock/AppletDock.qml: Type PanelWindow is not creatable. [uncreatable-type]
shell/dock/AppletDock.qml: Type margins is used but it is not resolved [unresolved-type] shell/dock/AppletDock.qml: Type margins is used but it is not resolved [unresolved-type]
shell/dock/AppletDock.qml: unknown grouped property scope margins. [unqualified] shell/dock/AppletDock.qml: unknown grouped property scope margins. [unqualified]
shell/dock/DockCard.qml: Type "QColor" of property "base01" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/dock/DockCard.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/dock/DockCard.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/dock/DockCard.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/dock/DockCard.qml: Type "QColor" of property "base0C" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/dock/DockEdgeTrigger.qml: Type PanelWindow is not creatable. [uncreatable-type] shell/dock/DockEdgeTrigger.qml: Type PanelWindow is not creatable. [uncreatable-type]
shell/lock/Lock.qml: Unqualified access [unqualified] shell/lock/Lock.qml: Unqualified access [unqualified]
shell/lock/LockAuth.qml: Unqualified access [unqualified] shell/lock/LockAuth.qml: Unqualified access [unqualified]
shell/lock/LockClock.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockClock.qml: Type "QColor" of property "base09" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockClock.qml: Type "QColor" of property "base0C" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockClock.qml: Type "QColor" of property "base0E" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockInput.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockInput.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockInput.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockInput.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockInput.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockInput.qml: Type "QColor" of property "base0D" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockNotifPills.qml: Type "QColor" of property "base01" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockNotifPills.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockNotifPills.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockSurface.qml: Type "QColor" of property "base00" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockSurface.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockSurface.qml: Unqualified access [unqualified] shell/lock/LockSurface.qml: Unqualified access [unqualified]
shell/lock/LockWidgets.qml: Type "QColor" of property "base01" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockWidgets.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockWidgets.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockWidgets.qml: Type "QColor" of property "base0C" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockWidgets.qml: Type "QColor" of property "base0D" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/lock/LockWidgets.qml: Type "QColor" of property "base0E" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BackgroundOverlay.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BackgroundOverlay.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BackgroundOverlay.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BackgroundOverlay.qml: Type "QColor" of property "base09" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BackgroundOverlay.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BackgroundOverlay.qml: Type "QColor" of property "base0B" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BackgroundOverlay.qml: Type "QColor" of property "base0C" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BackgroundOverlay.qml: Type "QColor" of property "base0D" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BackgroundOverlay.qml: Type "QColor" of property "base0E" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BackgroundOverlay.qml: Type PanelWindow is not creatable. [uncreatable-type] shell/modules/BackgroundOverlay.qml: Type PanelWindow is not creatable. [uncreatable-type]
shell/modules/BacklightModule.qml: Unqualified access [unqualified] shell/modules/BacklightModule.qml: Unqualified access [unqualified]
shell/modules/Bar.qml: Could not find property "right". [missing-property] shell/modules/Bar.qml: Could not find property "right". [missing-property]
shell/modules/Bar.qml: Type "QColor" of property "base00" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/Bar.qml: Type "QColor" of property "base09" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/Bar.qml: Type "QColor" of property "base0C" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/Bar.qml: Type PanelWindow is not creatable. [uncreatable-type] shell/modules/Bar.qml: Type PanelWindow is not creatable. [uncreatable-type]
shell/modules/Bar.qml: Type margins is used but it is not resolved [unresolved-type] shell/modules/Bar.qml: Type margins is used but it is not resolved [unresolved-type]
shell/modules/Bar.qml: unknown grouped property scope margins. [unqualified] shell/modules/Bar.qml: unknown grouped property scope margins. [unqualified]
shell/modules/BarGroup.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/BarGroup.qml: Member "screen" not found on type "QObject" [missing-property]
shell/modules/BarGroup.qml: Type "QColor" of property "base01" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BarGroup.qml: Type "QColor" of property "base09" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BarGroup.qml: Type "QColor" of property "base0C" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BarGroup.qml: Unqualified access [unqualified] shell/modules/BarGroup.qml: Unqualified access [unqualified]
shell/modules/BarIcon.qml: Member "accentColor" not found on type "QQuickItem" [missing-property] shell/modules/BarIcon.qml: Member "accentColor" not found on type "QQuickItem" [missing-property]
shell/modules/BarIcon.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BarLabel.qml: Member "accentColor" not found on type "QQuickItem" [missing-property] shell/modules/BarLabel.qml: Member "accentColor" not found on type "QQuickItem" [missing-property]
shell/modules/BarLabel.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BarModule.qml: Member "accentColor" not found on type "QQuickItem" [missing-property] shell/modules/BarModule.qml: Member "accentColor" not found on type "QQuickItem" [missing-property]
shell/modules/BarModule.qml: Member "keepOpen" not found on type "QObject" [missing-property] shell/modules/BarModule.qml: Member "keepOpen" not found on type "QObject" [missing-property]
shell/modules/BarModule.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/BarModule.qml: Member "screen" not found on type "QObject" [missing-property]
shell/modules/BarModule.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BarModule.qml: Unqualified access [unqualified] shell/modules/BarModule.qml: Unqualified access [unqualified]
shell/modules/BatteryModule.qml: Unqualified access [unqualified] shell/modules/BatteryModule.qml: Unqualified access [unqualified]
shell/modules/BluetoothModule.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/BluetoothModule.qml: Unqualified access [unqualified] shell/modules/BluetoothModule.qml: Unqualified access [unqualified]
shell/modules/ClockModule.qml: Unqualified access [unqualified] shell/modules/ClockModule.qml: Unqualified access [unqualified]
shell/modules/CpuModule.qml: Unqualified access [unqualified] shell/modules/CpuModule.qml: Unqualified access [unqualified]
shell/modules/DiskModule.qml: Type "QColor" of property "base09" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/DiskModule.qml: Unqualified access [unqualified] shell/modules/DiskModule.qml: Unqualified access [unqualified]
shell/modules/GpuModule.qml: Unqualified access [unqualified] shell/modules/GpuModule.qml: Unqualified access [unqualified]
shell/modules/HoverPanel.qml: Could not find property "top". [missing-property] shell/modules/HoverPanel.qml: Could not find property "top". [missing-property]
shell/modules/HoverPanel.qml: Type PanelWindow is not creatable. [uncreatable-type] shell/modules/HoverPanel.qml: Type PanelWindow is not creatable. [uncreatable-type]
shell/modules/HoverPanel.qml: Type margins is used but it is not resolved [unresolved-type] shell/modules/HoverPanel.qml: Type margins is used but it is not resolved [unresolved-type]
shell/modules/HoverPanel.qml: unknown grouped property scope margins. [unqualified] shell/modules/HoverPanel.qml: unknown grouped property scope margins. [unqualified]
shell/modules/IdleInhibitorModule.qml: Type "QColor" of property "base09" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/MachinectlModule.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/MemoryModule.qml: Unqualified access [unqualified] shell/modules/MemoryModule.qml: Unqualified access [unqualified]
shell/modules/MprisModule.qml: Unqualified access [unqualified] shell/modules/MprisModule.qml: Unqualified access [unqualified]
shell/modules/NetworkModule.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/NetworkModule.qml: Unqualified access [unqualified] shell/modules/NetworkModule.qml: Unqualified access [unqualified]
shell/modules/NotifCard.qml: Type "QColor" of property "base01" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/NotifCard.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/NotifCard.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/NotifCard.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/NotifCard.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/NotifCard.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/NotifCard.qml: Type "QColor" of property "base0D" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/NotifCard.qml: Unqualified access [unqualified] shell/modules/NotifCard.qml: Unqualified access [unqualified]
shell/modules/NotifPopup.qml: Could not find property "right". [missing-property] shell/modules/NotifPopup.qml: Could not find property "right". [missing-property]
shell/modules/NotifPopup.qml: Could not find property "top". [missing-property] shell/modules/NotifPopup.qml: Could not find property "top". [missing-property]
@ -59,34 +201,75 @@ shell/modules/NotifPopup.qml: Type PanelWindow is not creatable. [uncreatable-ty
shell/modules/NotifPopup.qml: Type margins is used but it is not resolved [unresolved-type] shell/modules/NotifPopup.qml: Type margins is used but it is not resolved [unresolved-type]
shell/modules/NotifPopup.qml: Unqualified access [unqualified] shell/modules/NotifPopup.qml: Unqualified access [unqualified]
shell/modules/NotifPopup.qml: unknown grouped property scope margins. [unqualified] shell/modules/NotifPopup.qml: unknown grouped property scope margins. [unqualified]
shell/modules/NotificationsModule.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/NotificationsModule.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/NotificationsModule.qml: Unqualified access [unqualified] shell/modules/NotificationsModule.qml: Unqualified access [unqualified]
shell/modules/OverviewBackdrop.qml: Type PanelWindow is not creatable. [uncreatable-type] shell/modules/OverviewBackdrop.qml: Type PanelWindow is not creatable. [uncreatable-type]
shell/modules/PopupBackground.qml: Type "QColor" of property "base01" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/PopupBackground.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/PowerModule.qml: Unqualified access [unqualified] shell/modules/PowerModule.qml: Unqualified access [unqualified]
shell/modules/PowerProfileModule.qml: Type "QColor" of property "base09" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/PowerProfileModule.qml: Type "QColor" of property "base0B" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/PrivacyModule.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/PrivacyModule.qml: Type "QColor" of property "base0B" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/ScreenCapture.qml: Type PanelWindow is not creatable. [uncreatable-type] shell/modules/ScreenCapture.qml: Type PanelWindow is not creatable. [uncreatable-type]
shell/modules/ScreenCorners.qml: Could not find property "right". [missing-property] shell/modules/ScreenCorners.qml: Could not find property "right". [missing-property]
shell/modules/ScreenCorners.qml: Type PanelWindow is not creatable. [uncreatable-type] shell/modules/ScreenCorners.qml: Type PanelWindow is not creatable. [uncreatable-type]
shell/modules/ScreenCorners.qml: Type margins is used but it is not resolved [unresolved-type] shell/modules/ScreenCorners.qml: Type margins is used but it is not resolved [unresolved-type]
shell/modules/ScreenCorners.qml: Unqualified access [unqualified] shell/modules/ScreenCorners.qml: Unqualified access [unqualified]
shell/modules/ScreenCorners.qml: unknown grouped property scope margins. [unqualified] shell/modules/ScreenCorners.qml: unknown grouped property scope margins. [unqualified]
shell/modules/SystemdModule.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/SystemdModule.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/TemperatureModule.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/TemperatureModule.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/TemperatureModule.qml: Unqualified access [unqualified] shell/modules/TemperatureModule.qml: Unqualified access [unqualified]
shell/modules/ThemedIcon.qml: Unqualified access [unqualified] shell/modules/ThemedIcon.qml: Unqualified access [unqualified]
shell/modules/Tooltip.qml: Could not find property "left". [missing-property] shell/modules/Tooltip.qml: Could not find property "left". [missing-property]
shell/modules/Tooltip.qml: Could not find property "top". [missing-property] shell/modules/Tooltip.qml: Could not find property "top". [missing-property]
shell/modules/Tooltip.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/Tooltip.qml: Type PanelWindow is not creatable. [uncreatable-type] shell/modules/Tooltip.qml: Type PanelWindow is not creatable. [uncreatable-type]
shell/modules/Tooltip.qml: Type margins is used but it is not resolved [unresolved-type] shell/modules/Tooltip.qml: Type margins is used but it is not resolved [unresolved-type]
shell/modules/Tooltip.qml: unknown grouped property scope margins. [unqualified] shell/modules/Tooltip.qml: unknown grouped property scope margins. [unqualified]
shell/modules/TooltipState.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/TrayMenu.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/TrayMenu.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/TrayMenu.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/TrayMenu.qml: Unqualified access [unqualified] shell/modules/TrayMenu.qml: Unqualified access [unqualified]
shell/modules/TrayModule.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/TrayModule.qml: Member "screen" not found on type "QObject" [missing-property]
shell/modules/TrayModule.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/TrayModule.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/TrayModule.qml: Type "qs::dbus::dbusmenu::DBusMenuHandle" of property "menu" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type] shell/modules/TrayModule.qml: Type "qs::dbus::dbusmenu::DBusMenuHandle" of property "menu" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/TrayModule.qml: Unqualified access [unqualified] shell/modules/TrayModule.qml: Unqualified access [unqualified]
shell/modules/VolumeModule.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/VolumeModule.qml: Unqualified access [unqualified] shell/modules/VolumeModule.qml: Unqualified access [unqualified]
shell/modules/WeatherModule.qml: Unqualified access [unqualified] shell/modules/WeatherModule.qml: Unqualified access [unqualified]
shell/modules/WindowTitleModule.qml: Unqualified access [unqualified] shell/modules/WindowTitleModule.qml: Unqualified access [unqualified]
shell/modules/WorkspacesModule.qml: Member "screen" not found on type "QObject" [missing-property] shell/modules/WorkspacesModule.qml: Member "screen" not found on type "QObject" [missing-property]
shell/modules/WorkspacesModule.qml: Type "QColor" of property "base00" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/WorkspacesModule.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/WorkspacesModule.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/WorkspacesModule.qml: Unqualified access [unqualified] shell/modules/WorkspacesModule.qml: Unqualified access [unqualified]
shell/services/BatteryService.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/BatteryService.qml: Type "QColor" of property "base09" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/BatteryService.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/BatteryService.qml: Type "QColor" of property "base0B" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/BluetoothService.qml: Unqualified access [unqualified] shell/services/BluetoothService.qml: Unqualified access [unqualified]
shell/services/CpuService.qml: Type "QList_QString" of property "coreTypes" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/CpuService.qml: Type "QList_QString" of property "cores" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/CpuService.qml: Type "QList_f64" of property "coreMaxFreq" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/CpuService.qml: Type "QList_i32" of property "history" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/LockService.qml: Type QProcess::ExitStatus of parameter exitStatus in signal called exited was not found, but is required to compile onExited. Did you add all imports and dependencies? [signal-handler-parameters] shell/services/LockService.qml: Type QProcess::ExitStatus of parameter exitStatus in signal called exited was not found, but is required to compile onExited. Did you add all imports and dependencies? [signal-handler-parameters]
shell/services/LockService.qml: Unqualified access [unqualified] shell/services/LockService.qml: Unqualified access [unqualified]
shell/services/MprisService.qml: Unqualified access [unqualified] shell/services/MprisService.qml: Unqualified access [unqualified]
shell/services/NetworkService.qml: Unqualified access [unqualified]
shell/services/PowerProfileService.qml: Unqualified access [unqualified] shell/services/PowerProfileService.qml: Unqualified access [unqualified]
shell/services/SystemStats.qml: Type "QList_QString" of property "diskMounts" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/SystemStats.qml: Type "QList_QString" of property "tempDevices" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/SystemStats.qml: Type "QList_i32" of property "gpuHistory" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/SystemStats.qml: Type "QList_i32" of property "memHistory" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/SystemStats.qml: Type "QList_i32" of property "tempHistory" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/ThemeUtil.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/ThemeUtil.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/ThemeUtil.qml: Type "QColor" of property "base0B" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/services/WeatherService.qml: Type "QList_QString" of property "weatherArgs" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/shell.qml: Unqualified access [unqualified] shell/shell.qml: Unqualified access [unqualified]