diff --git a/config/dot/quickshell/modules/quicksettings/PowerProfileList.qml b/config/dot/quickshell/modules/quicksettings/PowerProfileList.qml new file mode 100644 index 0000000..c1ba48e --- /dev/null +++ b/config/dot/quickshell/modules/quicksettings/PowerProfileList.qml @@ -0,0 +1,57 @@ +// The three system power profiles, as an expandable list. +// +// A row per profile rather than a cycling button: there are three, and cycling +// through them means passing through one you did not want on a machine where +// the change is immediate and audible. The same shape the audio device lists +// use, so the panel reads consistently. +// +// The daemon owns the profile -- it survives a shell restart and anything else +// on the system can change it -- so this reads back rather than assuming, the +// same as monitor brightness. + +import QtQuick +import qs.config +import qs.services + +Column { + id: root + + spacing: 2 + + Repeater { + model: PowerProfiles.profiles + + RowButton { + required property var modelData + + width: root.width + icon: { + switch (modelData) { + case "power-saver": return "power-profile-power-saver-symbolic"; + case "performance": return "power-profile-performance-symbolic"; + default: return "power-profile-balanced-symbolic"; + } + } + iconFallback: "preferences-system-power-symbolic" + label: PowerProfiles.label(modelData) + sublabel: PowerProfiles.detail(modelData) + selected: modelData === PowerProfiles.active + dimmed: PowerProfiles.busy + onClicked: PowerProfiles.set(modelData) + } + } + + // Only when it is true. A machine that cannot deliver the profile it is set + // to is the one case where the label alone is misleading. + Text { + visible: PowerProfiles.degraded !== "" + width: root.width + text: "Limited right now: " + PowerProfiles.degraded + color: Theme.fgMuted + font.family: Theme.fontFamily + font.pixelSize: Theme.fontSizeSmall + wrapMode: Text.WordWrap + leftPadding: 10 + topPadding: 4 + } +} diff --git a/config/dot/quickshell/modules/quicksettings/QuickSettings.qml b/config/dot/quickshell/modules/quicksettings/QuickSettings.qml index 080e7a9..2da8c02 100644 --- a/config/dot/quickshell/modules/quicksettings/QuickSettings.qml +++ b/config/dot/quickshell/modules/quicksettings/QuickSettings.qml @@ -45,6 +45,9 @@ PanelWindow { if (root.visible) { KdeConnect.refresh(); HomeAssistant.refresh(); + // The daemon owns the power profile and anything on the system can + // change it, so the panel asks rather than trusting what it last saw. + PowerProfiles.refresh(); openAnim.restart(); } else { panel.reset(); diff --git a/config/dot/quickshell/modules/quicksettings/QuickSettingsPanel.qml b/config/dot/quickshell/modules/quicksettings/QuickSettingsPanel.qml index 7f6ec59..b799c7c 100644 --- a/config/dot/quickshell/modules/quicksettings/QuickSettingsPanel.qml +++ b/config/dot/quickshell/modules/quicksettings/QuickSettingsPanel.qml @@ -130,6 +130,21 @@ Item { onToggled: Caffeine.toggle() } + Toggle { + width: root.cellWidth + icon: ColorScheme.dark ? "weather-clear-night-symbolic" : "weather-clear-symbolic" + label: "Appearance" + sublabel: ColorScheme.dark ? "Dark" : "Light" + // "active" reads as the non-default state across this grid, and + // dark is what Panama ships, so light is the lit one. + active: !ColorScheme.dark + // Writes the preference and stops. ColorScheme propagates it to + // GTK, the portal, the terminals, the launcher, btop, tmux and + // the lock screen; nothing here needs to know that list. + onToggled: SystemSettings.commitPreference("colorScheme", + ColorScheme.dark ? "light" : "dark") + } + Toggle { width: root.cellWidth icon: "night-light-symbolic" @@ -190,6 +205,38 @@ Item { color: Theme.alpha(Theme.fg, 0.1) } + // ── Power ─────────────────────────────────────────────────────────── + // Only where a power-profiles daemon is actually running. A desktop + // without one should not show a control that cannot do anything. + RowButton { + visible: PowerProfiles.available + width: content.width + icon: { + switch (PowerProfiles.active) { + case "power-saver": return "power-profile-power-saver-symbolic"; + case "performance": return "power-profile-performance-symbolic"; + default: return "power-profile-balanced-symbolic"; + } + } + iconFallback: "preferences-system-power-symbolic" + label: "Power profile" + sublabel: PowerProfiles.degraded !== "" + ? PowerProfiles.label(PowerProfiles.active) + " · limited" + : PowerProfiles.label(PowerProfiles.active) + selected: root.expandedSection === "power" + onClicked: root.expand("power") + } + + Section { + width: content.width + expanded: root.expandedSection === "power" + + PowerProfileList { + anchors.left: parent.left + anchors.right: parent.right + } + } + // ── Sliders ───────────────────────────────────────────────────────── AudioSlider { width: content.width diff --git a/config/dot/quickshell/modules/quicksettings/qmldir b/config/dot/quickshell/modules/quicksettings/qmldir index e1d356e..83a5679 100644 --- a/config/dot/quickshell/modules/quicksettings/qmldir +++ b/config/dot/quickshell/modules/quicksettings/qmldir @@ -17,3 +17,4 @@ RowButton 1.0 RowButton.qml ScrollColumn 1.0 ScrollColumn.qml Section 1.0 Section.qml WifiList 1.0 WifiList.qml +PowerProfileList 1.0 PowerProfileList.qml