feat(nosignal): CachyOS repo toggle + wire Quick Settings placebos

- CachyRepoToggleRow.qml (Settings -> Services): sudoless CachyOS optimized
  repos + linux-cachyos kernel switch, auto-tier (v4>v3); polls
  nosignal-cachy-repo status, runs enable/disable in a floating kitty. Inserted
  after SudoToggleRow in ServicesPage.qml.
- NsQuickSettings.qml: Night Light now drives hyprsunset (tile bound to the real
  pgrep'd process, not a flag); Airplane drives nmcli + bluetoothctl and binds to
  real radio state; VPN placebo tile removed (no backend).

Both built + live-tested on the reference box (06-17 PM). Helper script, sudoers
and hyprsunset dep ship in the nosignal builder.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
28allday 2026-06-18 21:06:20 +01:00
parent 53c5833de0
commit 44b257ce85
3 changed files with 131 additions and 11 deletions

View file

@ -0,0 +1,73 @@
// CachyRepoToggleRow.qml (NoSignal) Settings -> Services toggle to enable /
// disable the CachyOS pacman repositories. Auto-detects the best x86-64 microarch
// tier the CPU supports (v4 > v3). Live state polls `nosignal-cachy-repo status`
// (no root). enable/disable run in a floating terminal so the pacman/download
// output stays visible; the grant is passwordless via sudo -n
// (/etc/sudoers.d/02-nosignal-cachy). enable adds repos, converts userspace to
// the optimized builds (pacman -Suu, pacman pinned stock), and installs the
// linux-cachyos kernel; disable reverts to stock and removes the cachy kernel
// (keeping stock `linux` bootable). A reboot switches the running kernel.
//
// Untracked file under modules/nexus/common auto-discovered as the type
// `CachyRepoToggleRow` via `import qs.modules.nexus.common`. Survives caelestia
// upgrades; pairs with the one-line insert in ServicesPage.qml.
import QtQuick
import Quickshell.Io
import qs.modules.nexus.common
ToggleRow {
id: root
property bool repoOn: false // NB: not `enabled` (reserved Item property)
text: qsTr("CachyOS repositories")
subtext: repoOn
? qsTr("On — CachyOS optimized builds + linux-cachyos kernel (reboot to run it)")
: qsTr("Switch to CachyOS optimized builds + linux-cachyos kernel (reboot after)")
onToggled: {
if (checked)
enableProc.running = true;
else
disableProc.running = true;
reconcile.restart();
}
// --- live state -----------------------------------------------------------
Process {
id: statusProc
command: ["/usr/local/bin/nosignal-cachy-repo", "status"]
stdout: StdioCollector {
onStreamFinished: {
root.repoOn = text.trim() === "enabled";
root.checked = root.repoOn; // drive switch from real state
}
}
}
// --- actions (passwordless; shown in a terminal for pacman output) ---------
Process {
id: enableProc
command: ["kitty", "--class", "TUI.float", "-e", "sh", "-c", "sudo -n /usr/local/bin/nosignal-cachy-repo enable; printf '\\nPress Enter to close...'; read _"]
onExited: reconcile.restart()
}
Process {
id: disableProc
command: ["kitty", "--class", "TUI.float", "-e", "sh", "-c", "sudo -n /usr/local/bin/nosignal-cachy-repo disable; printf '\\nPress Enter to close...'; read _"]
onExited: reconcile.restart()
}
// --- polling --------------------------------------------------------------
Timer {
interval: 5000
repeat: true
running: true
triggeredOnStart: true
onTriggered: statusProc.running = true
}
Timer {
id: reconcile
interval: 2000
onTriggered: statusProc.running = true
}
}

View file

@ -216,6 +216,11 @@ PageBase {
Layout.fillWidth: true
}
// NoSignal: CachyOS repos enable/disable (sudoless, auto-tier)
CachyRepoToggleRow {
Layout.fillWidth: true
}
SelectRow {
Layout.fillWidth: true
last: true

View file

@ -3,10 +3,13 @@ pragma ComponentBehavior: Bound
// NoSignal Quick Settings popout (off the media / battery pill). Avatar + user +
// uptime + power button; 2-col toggle grid; brightness + volume sliders; media
// card. Wired to the real services (Network, Bluetooth, Notifs, Audio,
// Brightness, Players); Night Light / Airplane / VPN are stateful toggles for now.
// Brightness, Players). Night Light drives hyprsunset; Airplane drives the
// NetworkManager + Bluetooth radios. (VPN tile removed pending a real backend.)
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Bluetooth
import qs.services
import qs.utils
@ -20,6 +23,35 @@ NsPanel {
readonly property var brightMon: Brightness.monitors[0] ?? null
// Night Light state tracks the real hyprsunset process rather than a local
// flag, so the tile stays correct across shell reloads or changes made
// elsewhere. Seeded on load (probe runs immediately), reconciled on a timer,
// and re-checked right after a toggle.
property bool nightLightOn: false
Process {
id: nightProbe
command: ["pgrep", "-x", "hyprsunset"]
running: true
stdout: StdioCollector {
onStreamFinished: root.nightLightOn = text.trim().length > 0
}
}
Timer {
interval: 3000
running: true
repeat: true
onTriggered: nightProbe.running = true
}
Timer {
id: nightRefresh
interval: 500
repeat: false
onTriggered: nightProbe.running = true
}
// Header
RowLayout {
Layout.fillWidth: true
@ -128,21 +160,31 @@ NsPanel {
icon: "nightlight"
label: "Night Light"
sub: on ? "Warm 3500K" : "Off"
onToggled: on = !on
on: root.nightLightOn
onToggled: {
if (root.nightLightOn)
Quickshell.execDetached(["pkill", "-x", "hyprsunset"]);
else
Quickshell.execDetached(["sh", "-c", "pkill -x hyprsunset; hyprsunset -t 3500"]);
nightRefresh.restart();
}
}
QSToggle {
id: airTog
icon: "airplanemode_active"
label: "Airplane"
sub: on ? "On" : "Off"
onToggled: on = !on
// Reflects the real radio state: airplane is "On" when both Wi-Fi and
// Bluetooth are down. Network.wifiEnabled tracks nmcli; the adapter
// tracks BlueZ, so the tile self-corrects if radios change elsewhere.
readonly property bool radiosOff: !Network.wifiEnabled && !(Bluetooth.defaultAdapter?.enabled ?? false)
sub: radiosOff ? "On" : "Off"
on: radiosOff
onToggled: {
if (radiosOff)
Quickshell.execDetached(["sh", "-c", "nmcli radio all on; bluetoothctl power on"]);
else
Quickshell.execDetached(["sh", "-c", "nmcli radio all off; bluetoothctl power off"]);
}
QSToggle {
id: vpnTog
icon: "vpn_key"
label: "VPN"
sub: on ? "On" : "Off"
onToggled: on = !on
}
}