NoSignal-OS/os updates/gamemode-toggle-deckshift/Toggles.qml
28allday 19fd794b6b NoSignal — fully-offline Arch → Hyprland desktop installer
Single-script builder (nosignal.sh) that turns a stock Arch Linux ISO into a
fully-offline installer for a themed Hyprland + caelestia (Quickshell) desktop:
matching SDDM greeter, Btrfs/Limine bootable snapshots, chwd-style GPU
detection, and a curated "os updates" layer (keybind cheatsheet, settings
panels, system polish, on-box management skill). See README.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 11:03:10 +01:00

207 lines
7.5 KiB
QML

pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Bluetooth
import Caelestia.Components
import Caelestia.Config
import qs.components
import qs.components.controls
import qs.services
import qs.modules.nexus
import qs.modules.bar.popouts as BarPopouts
StyledRect {
id: root
required property DrawerVisibilities visibilities
required property BarPopouts.Wrapper popouts
// NoSignal: the gamepad "Game Mode" toggle launches DeckShift gaming. Hide it
// entirely when DeckShift isn't installed (no gamescope session file) — checked
// once at load by deckshiftProbe below.
property bool deckshiftInstalled: false
Process {
id: deckshiftProbe
running: true
command: ["test", "-f", "/usr/share/wayland-sessions/gamescope-session-steam-nm.desktop"]
onExited: (exitCode, exitStatus) => root.deckshiftInstalled = exitCode === 0
}
readonly property var quickToggles: {
const seenIds = new Set();
return Config.utilities.quickToggles.filter(item => {
if (!(item.enabled ?? true))
return false;
if (seenIds.has(item.id)) {
return false;
}
if (item.id === "vpn") {
return GlobalConfig.utilities.vpn.provider.some(p => typeof p === "object" ? (p.enabled === true) : false);
}
// NoSignal: drop the Game Mode tile unless DeckShift is installed.
if (item.id === "gameMode") {
return root.deckshiftInstalled;
}
seenIds.add(item.id);
return true;
});
}
readonly property int splitIndex: Math.ceil(quickToggles.length / 2)
readonly property bool needExtraRow: quickToggles.length > 6
Layout.fillWidth: true
implicitHeight: layout.implicitHeight + Tokens.padding.extraLargeIncreased
radius: Tokens.rounding.large
color: Colours.tPalette.m3surfaceContainer
ColumnLayout {
id: layout
anchors.fill: parent
anchors.margins: Tokens.padding.large
spacing: Tokens.spacing.medium
StyledText {
text: qsTr("Quick Toggles")
font: Tokens.font.body.medium
}
QuickToggleRow {
model: root.needExtraRow ? root.quickToggles.slice(0, root.splitIndex) : root.quickToggles
}
QuickToggleRow {
visible: root.needExtraRow
model: root.needExtraRow ? root.quickToggles.slice(root.splitIndex) : []
}
}
component QuickToggleRow: ButtonRow {
property alias model: repeater.model
Layout.fillWidth: true
spacing: Tokens.spacing.small
Repeater {
id: repeater
delegate: DelegateChooser {
role: "id"
DelegateChoice {
roleValue: "wifi"
delegate: Toggle {
icon: "wifi"
checked: Nmcli.wifiEnabled
onClicked: Nmcli.toggleWifi()
}
}
DelegateChoice {
roleValue: "bluetooth"
delegate: Toggle {
icon: "bluetooth"
checked: Bluetooth.defaultAdapter?.enabled ?? false // qmllint disable unresolved-type
onClicked: {
const adapter = Bluetooth.defaultAdapter; // qmllint disable unresolved-type
if (adapter)
adapter.enabled = !adapter.enabled;
}
}
}
DelegateChoice {
roleValue: "mic"
delegate: Toggle {
icon: "mic"
checked: !Audio.sourceMuted
onClicked: {
const audio = Audio.source?.audio;
if (audio)
audio.muted = !audio.muted;
}
}
}
DelegateChoice {
roleValue: "settings"
delegate: Toggle {
icon: "settings"
inactiveOnColour: Colours.palette.m3onSurfaceVariant
isToggle: false
onClicked: {
root.visibilities.utilities = false;
WindowFactory.create();
}
}
}
DelegateChoice {
roleValue: "gameMode"
delegate: Toggle {
id: gmTog
// NoSignal: launch the DeckShift gaming session if installed;
// otherwise do nothing. (Was caelestia's cosmetic Game Mode.)
// Kept styled as an off-toggle (muted, outline icon) — the
// gamepad is a momentary LAUNCHER, not a stateful toggle.
// DEBOUNCED: a fast double-click must not fire two
// `switch-to-gaming` runs — two SDDM restarts race the
// one-shot autologin and drop you at the password greeter.
// Guard mirrors the Super+Shift+S bind + the deckshift-login
// install-check, so it no-ops if DeckShift is absent.
property bool launching: false
icon: "gamepad"
disabled: launching
onClicked: {
if (gmTog.launching)
return;
gmTog.launching = true;
gmTog.internalChecked = false; // don't latch "on"
relockTimer.start();
Quickshell.execDetached(["sh", "-c", "[ -x /usr/local/bin/switch-to-gaming ] && [ -f /usr/share/wayland-sessions/gamescope-session-steam-nm.desktop ] && exec /usr/local/bin/switch-to-gaming"]);
}
Timer {
id: relockTimer
interval: 5000
onTriggered: gmTog.launching = false
}
}
}
DelegateChoice {
roleValue: "dnd"
delegate: Toggle {
icon: "notifications_off"
checked: Notifs.dnd
onClicked: Notifs.dnd = !Notifs.dnd
}
}
DelegateChoice {
roleValue: "vpn"
delegate: Toggle {
icon: "vpn_key"
checked: VPN.connected && VPN.status.state !== "needs-auth" && VPN.status.state !== "error"
enabled: !VPN.connecting
isToggle: VPN.status.state !== "needs-auth" && VPN.status.state !== "error"
inactiveOnColour: Colours.palette.m3onSurfaceVariant
onClicked: VPN.toggle()
}
}
}
}
}
component Toggle: IconButton {
inactiveColour: Colours.layer(Colours.palette.m3surfaceContainerHighest, 2)
fillWidth: true
isToggle: true
isRound: true
shapeMorph: true
}
}