refractor quick toggles data, add volume slider for waffles action center

This commit is contained in:
end-4
2025-11-17 23:43:25 +01:00
parent 9228165428
commit fcee7ce6f9
55 changed files with 939 additions and 470 deletions
@@ -0,0 +1 @@
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.47 4.22a.75.75 0 0 0 0 1.06L15.19 12l-6.72 6.72a.75.75 0 1 0 1.06 1.06l7.25-7.25a.75.75 0 0 0 0-1.06L9.53 4.22a.75.75 0 0 0-1.06 0Z" fill="#212121"/></svg>

After

Width:  |  Height:  |  Size: 262 B

@@ -0,0 +1 @@
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M14.704 3.442c.191.226.296.512.296.808v7.25a6.495 6.495 0 0 0-1.5.878V4.789L8.525 9H4.25a.75.75 0 0 0-.75.75v4.5c0 .415.336.75.75.75h4.275l2.487 2.107a6.576 6.576 0 0 0 .23 2.16L7.976 16.5H4.25A2.25 2.25 0 0 1 2 14.25v-4.5A2.25 2.25 0 0 1 4.25 7.5h3.725l4.968-4.204a1.25 1.25 0 0 1 1.761.147Zm-.426 10.535a2 2 0 0 1-1.441 2.496l-.584.145a5.729 5.729 0 0 0 .006 1.807l.54.13a2 2 0 0 1 1.45 2.51l-.187.631c.44.386.94.7 1.484.922l.494-.519a2 2 0 0 1 2.899 0l.498.526a5.28 5.28 0 0 0 1.483-.913l-.198-.686a2 2 0 0 1 1.441-2.497l.584-.144a5.716 5.716 0 0 0-.006-1.807l-.54-.13a2 2 0 0 1-1.45-2.51l.187-.632a5.282 5.282 0 0 0-1.484-.921l-.493.518a2 2 0 0 1-2.9 0l-.498-.525c-.544.22-1.044.53-1.483.913l.198.686ZM17.5 19c-.8 0-1.45-.671-1.45-1.5 0-.828.65-1.5 1.45-1.5.8 0 1.45.672 1.45 1.5 0 .829-.65 1.5-1.45 1.5Z" fill="#212121"/></svg>

After

Width:  |  Height:  |  Size: 936 B

@@ -572,7 +572,7 @@ Singleton {
} }
property JsonObject waffles: JsonObject { property JsonObject waffles: JsonObject {
// Animations on Windoes are kinda janky. Set the following to // Animations on Windoes are kinda janky. Setting the following to
// false will make (some) stuff also be like that for accuracy. // false will make (some) stuff also be like that for accuracy.
// Example: the right-click menu of the Start button // Example: the right-click menu of the Start button
property bool smootherAnimations: true property bool smootherAnimations: true
@@ -580,6 +580,9 @@ Singleton {
property bool bottom: true property bool bottom: true
property bool leftAlignApps: false property bool leftAlignApps: false
} }
property JsonObject actionCenter: JsonObject {
property list<string> toggles: []
}
} }
} }
} }
@@ -0,0 +1,17 @@
import QtQuick
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
name: Translation.tr("Anti-flashbang")
tooltipText: Translation.tr("Anti-flashbang")
icon: "flash_off"
toggled: Config.options.light.antiFlashbang.enable
mainAction: () => {
Config.options.light.antiFlashbang.enable = !Config.options.light.antiFlashbang.enable;
}
hasMenu: true
}
@@ -0,0 +1,17 @@
import QtQuick
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
name: Translation.tr("Audio output")
statusText: toggled ? Translation.tr("Unmuted") : Translation.tr("Muted")
tooltipText: Translation.tr("Audio output | Right-click for volume mixer & device selector")
toggled: !Audio.sink?.audio?.muted
icon: Audio.sink?.audio?.muted ? "volume_off" : "volume_up"
mainAction: () => {
Audio.toggleMute()
}
hasMenu: true
}
@@ -0,0 +1,23 @@
import QtQuick
import Quickshell.Bluetooth
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
name: Translation.tr("Bluetooth")
statusText: BluetoothStatus.firstActiveDevice?.name ?? Translation.tr("No device")
tooltipText: Translation.tr("%1 | Right-click to configure").arg(
(BluetoothStatus.firstActiveDevice?.name ?? Translation.tr("Bluetooth"))
+ (BluetoothStatus.activeDeviceCount > 1 ? ` +${BluetoothStatus.activeDeviceCount - 1}` : "")
)
icon: BluetoothStatus.connected ? "bluetooth_connected" : BluetoothStatus.enabled ? "bluetooth" : "bluetooth_disabled"
available: BluetoothStatus.available
toggled: BluetoothStatus.enabled
mainAction: () => {
Bluetooth.defaultAdapter.enabled = !Bluetooth.defaultAdapter?.enabled
}
hasMenu: true
}
@@ -0,0 +1,78 @@
import QtQuick
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
import Quickshell
import Quickshell.Io
QuickToggleModel {
id: root
name: Translation.tr("Cloudflare WARP")
toggled: false
icon: "cloud_lock"
mainAction: () => {
if (toggled) {
root.toggled = false
Quickshell.execDetached(["warp-cli", "disconnect"])
} else {
root.toggled = true
Quickshell.execDetached(["warp-cli", "connect"])
}
}
Process {
id: connectProc
command: ["warp-cli", "connect"]
onExited: (exitCode, exitStatus) => {
if (exitCode !== 0) {
Quickshell.execDetached(["notify-send",
Translation.tr("Cloudflare WARP"),
Translation.tr("Connection failed. Please inspect manually with the <tt>warp-cli</tt> command")
, "-a", "Shell"
])
}
}
}
Process {
id: registrationProc
command: ["warp-cli", "registration", "new"]
onExited: (exitCode, exitStatus) => {
console.log("Warp registration exited with code and status:", exitCode, exitStatus)
if (exitCode === 0) {
connectProc.running = true
} else {
Quickshell.execDetached(["notify-send",
Translation.tr("Cloudflare WARP"),
Translation.tr("Registration failed. Please inspect manually with the <tt>warp-cli</tt> command"),
"-a", "Shell"
])
}
}
}
Process {
id: fetchActiveState
running: true
command: ["bash", "-c", "warp-cli status"]
stdout: StdioCollector {
id: warpStatusCollector
onStreamFinished: {
if (warpStatusCollector.text.length > 0) {
root.available = true
}
if (warpStatusCollector.text.includes("Unable")) {
registrationProc.running = true
} else if (warpStatusCollector.text.includes("Connected")) {
root.toggled = true
} else if (warpStatusCollector.text.includes("Disconnected")) {
root.toggled = false
}
}
}
}
tooltipText: Translation.tr("Cloudflare WARP (1.1.1.1)")
}
@@ -0,0 +1,29 @@
import QtQuick
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
name: Translation.tr("Color picker")
hasStatusText: false
toggled: false
icon: "colorize"
mainAction: () => {
GlobalStates.sidebarRightOpen = false;
delayedActionTimer.start();
}
Timer {
id: delayedActionTimer
interval: 300
repeat: false
onTriggered: {
Quickshell.execDetached(["hyprpicker", "-a"]);
}
}
tooltipText: Translation.tr("Color picker")
}
@@ -0,0 +1,25 @@
import QtQuick
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
name: Translation.tr("Dark Mode")
statusText: Appearance.m3colors.darkmode ? Translation.tr("Dark") : Translation.tr("Light")
toggled: Appearance.m3colors.darkmode
icon: "contrast"
mainAction: () => {
if (Appearance.m3colors.darkmode) {
Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", "light", "--noswitch"]);
} else {
Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", "dark", "--noswitch"]);
}
}
tooltipText: Translation.tr("Dark Mode")
}
@@ -0,0 +1,30 @@
import QtQuick
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
name: Translation.tr("EasyEffects")
available: EasyEffects.available
toggled: EasyEffects.active
icon: "graphic_eq"
Component.onCompleted: {
EasyEffects.fetchActiveState()
}
mainAction: () => {
EasyEffects.toggle()
}
altAction: () => {
Quickshell.execDetached(["bash", "-c", "flatpak run com.github.wwmm.easyeffects || easyeffects"])
GlobalStates.sidebarRightOpen = false
}
tooltipText: Translation.tr("EasyEffects | Right-click to configure")
}
@@ -0,0 +1,33 @@
import QtQuick
import Quickshell
import Quickshell.Io
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
id: root
name: Translation.tr("Game mode")
toggled: toggled
icon: "gamepad"
mainAction: () => {
root.toggled = !root.toggled
if (root.toggled) {
Quickshell.execDetached(["bash", "-c", `hyprctl --batch "keyword animations:enabled 0; keyword decoration:shadow:enabled 0; keyword decoration:blur:enabled 0; keyword general:gaps_in 0; keyword general:gaps_out 0; keyword general:border_size 1; keyword decoration:rounding 0; keyword general:allow_tearing 1"`])
} else {
Quickshell.execDetached(["hyprctl", "reload"])
}
}
Process {
id: fetchActiveState
running: true
command: ["bash", "-c", `test "$(hyprctl getoption animations:enabled -j | jq ".int")" -ne 0`]
onExited: (exitCode, exitStatus) => {
root.toggled = exitCode !== 0 // Inverted because enabled = nonzero exit
}
}
tooltipText: Translation.tr("Game mode")
}
@@ -0,0 +1,18 @@
import QtQuick
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
name: Translation.tr("Keep awake")
toggled: Idle.inhibit
icon: "coffee"
mainAction: () => {
Idle.toggleInhibit()
}
tooltipText: Translation.tr("Keep system awake")
}
@@ -0,0 +1,20 @@
import QtQuick
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
name: Translation.tr("Audio input")
statusText: toggled ? Translation.tr("Enabled") : Translation.tr("Muted")
toggled: !Audio.source?.audio?.muted
icon: Audio.source?.audio?.muted ? "mic_off" : "mic"
mainAction: () => {
Audio.toggleMicMute()
}
hasMenu: true
tooltipText: Translation.tr("Audio input | Right-click for volume mixer & device selector")
}
@@ -0,0 +1,25 @@
import QtQuick
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
toggled: SongRec.running
property bool sourceIsMonitor: SongRec.monitorSource === SongRec.MonitorSource.Monitor
name: Translation.tr("Identify Music")
statusText: toggled ? Translation.tr("Listening...") : sourceIsMonitor ? Translation.tr("System sound") : Translation.tr("Microphone")
icon: toggled ? "music_cast" : (sourceIsMonitor ? "music_note" : "frame_person_mic")
tooltipText: Translation.tr("Recognize music | Right-click to toggle source")
mainAction: () => {
SongRec.toggleRunning()
}
altAction: () => {
SongRec.toggleMonitorSource()
}
}
@@ -0,0 +1,16 @@
import QtQuick
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
name: Translation.tr("Internet")
statusText: Network.networkName
tooltipText: Translation.tr("%1 | Right-click to configure").arg(Network.networkName)
icon: Network.materialSymbol
toggled: Network.wifiStatus !== "disabled"
mainAction: () => Network.toggleWifi()
hasMenu: true
}
@@ -0,0 +1,28 @@
import QtQuick
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
property bool auto: Config.options.light.night.automatic
name: Translation.tr("Night Light")
statusText: (auto ? Translation.tr("Auto, ") : "") + (toggled ? Translation.tr("Active") : Translation.tr("Inactive"))
toggled: Hyprsunset.active
icon: auto ? "night_sight_auto" : "bedtime"
mainAction: () => {
Hyprsunset.toggle()
}
hasMenu: true
Component.onCompleted: {
Hyprsunset.fetchState()
}
tooltipText: Translation.tr("Night Light | Right-click to configure")
}
@@ -0,0 +1,20 @@
import QtQuick
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
name: Translation.tr("Notifications")
statusText: toggled ? Translation.tr("Show") : Translation.tr("Silent")
toggled: !Notifications.silent
icon: toggled ? "notifications_active" : "notifications_paused"
mainAction: () => {
Notifications.silent = !Notifications.silent;
}
tooltipText: Translation.tr("Show notifications")
}
@@ -0,0 +1,19 @@
import QtQuick
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
name: Translation.tr("Virtual Keyboard")
toggled: GlobalStates.oskOpen
icon: toggled ? "keyboard_hide" : "keyboard"
mainAction: () => {
GlobalStates.oskOpen = !GlobalStates.oskOpen
}
tooltipText: Translation.tr("On-screen keyboard")
}
@@ -0,0 +1,39 @@
import QtQuick
import Quickshell
import Quickshell.Services.UPower
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
name: Translation.tr("Power Profile")
toggled: PowerProfiles.profile !== PowerProfile.Balanced
icon: switch(PowerProfiles.profile) {
case PowerProfile.PowerSaver: return "energy_savings_leaf"
case PowerProfile.Balanced: return "settings_slow_motion"
case PowerProfile.Performance: return "local_fire_department"
}
statusText: switch(PowerProfiles.profile) {
case PowerProfile.PowerSaver: return "Power Saver"
case PowerProfile.Balanced: return "Balanced"
case PowerProfile.Performance: return "Performance"
}
mainAction: () => {
if (PowerProfiles.hasPerformanceProfile) {
switch(PowerProfiles.profile) {
case PowerProfile.PowerSaver: PowerProfiles.profile = PowerProfile.Balanced
break;
case PowerProfile.Balanced: PowerProfiles.profile = PowerProfile.Performance
break;
case PowerProfile.Performance: PowerProfiles.profile = PowerProfile.PowerSaver
break;
}
} else {
PowerProfiles.profile = PowerProfiles.profile == PowerProfile.Balanced ? PowerProfile.PowerSaver : PowerProfile.Balanced
}
}
tooltipText: Translation.tr("Click to cycle through power profiles")
}
@@ -0,0 +1,22 @@
import QtQuick
QtObject {
// Textual info
required property string name
property string statusText
property string tooltipText: ""
property string icon: "close"
// State
property bool hasStatusText: true
property bool available: true
property bool toggled: false
// Interactions
required property var mainAction
property bool hasMenu: false
property var altAction: null
// Allow stuff like Processes to be declared freely
default property list<QtObject> data
}
@@ -0,0 +1,29 @@
import QtQuick
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
QuickToggleModel {
name: Translation.tr("Screen snip")
hasStatusText: false
toggled: false
icon: "screenshot_region"
mainAction: () => {
GlobalStates.sidebarRightOpen = false;
delayedActionTimer.start();
}
Timer {
id: delayedActionTimer
interval: 300
repeat: false
onTriggered: {
Quickshell.execDetached(["qs", "-p", Quickshell.shellPath(""), "ipc", "call", "region", "screenshot"]);
}
}
tooltipText: Translation.tr("Screen snip")
}
@@ -0,0 +1,9 @@
import QtQuick
Rectangle {
property double diameter
implicitWidth: diameter
implicitHeight: diameter
radius: diameter / 2
}
@@ -197,16 +197,8 @@ Item { // Bar content region
implicitWidth: rightSectionRowLayout.implicitWidth implicitWidth: rightSectionRowLayout.implicitWidth
implicitHeight: Appearance.sizes.baseBarHeight implicitHeight: Appearance.sizes.baseBarHeight
onScrollDown: { onScrollDown: Audio.decrementVolume();
const currentVolume = Audio.value; onScrollUp: Audio.incrementVolume();
const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
Audio.sink.audio.volume -= step;
}
onScrollUp: {
const currentVolume = Audio.value;
const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
Audio.sink.audio.volume = Math.min(1, Audio.sink.audio.volume + step);
}
onMovedAway: GlobalStates.osdVolumeOpen = false; onMovedAway: GlobalStates.osdVolumeOpen = false;
onPressed: event => { onPressed: event => {
if (event.button === Qt.LeftButton) { if (event.button === Qt.LeftButton) {
@@ -1,3 +1,4 @@
import qs.modules.common.models.quickToggles
import qs.modules.common import qs.modules.common
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.services import qs.services
@@ -6,24 +7,7 @@ import Quickshell
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root id: root
property bool auto: Config.options.light.night.automatic
name: Translation.tr("Anti-flashbang") toggleModel: AntiFlashbangToggle {}
toggled: Config.options.light.antiFlashbang.enable
buttonIcon: "flash_off"
mainAction: () => {
Config.options.light.antiFlashbang.enable = !Config.options.light.antiFlashbang.enable;
}
altAction: () => {
root.openMenu()
}
StyledToolTip {
text: Translation.tr("Anti-flashbang")
}
} }
@@ -1,5 +1,6 @@
import qs import qs
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.services import qs.services
import QtQuick import QtQuick
@@ -8,19 +9,5 @@ import Quickshell
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root id: root
name: Translation.tr("Audio output") toggleModel: AudioToggle {}
statusText: toggled ? Translation.tr("Unmuted") : Translation.tr("Muted")
toggled: !Audio.sink?.audio?.muted
buttonIcon: Audio.sink?.audio?.muted ? "volume_off" : "volume_up"
mainAction: () => {
Audio.sink.audio.muted = !Audio.sink.audio.muted
}
altAction: () => {
root.openMenu()
}
StyledToolTip {
text: Translation.tr("Audio output | Right-click for volume mixer & device selector")
}
} }
@@ -1,5 +1,6 @@
import qs.services import qs.services
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.functions import qs.modules.common.functions
import qs.modules.common.widgets import qs.modules.common.widgets
import QtQuick import QtQuick
@@ -9,22 +10,5 @@ import Quickshell.Bluetooth
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root id: root
name: Translation.tr("Bluetooth") toggleModel: BluetoothToggle {}
statusText: BluetoothStatus.firstActiveDevice?.name ?? Translation.tr("No device")
available: BluetoothStatus.available
toggled: BluetoothStatus.enabled
buttonIcon: BluetoothStatus.connected ? "bluetooth_connected" : BluetoothStatus.enabled ? "bluetooth" : "bluetooth_disabled"
mainAction: () => {
Bluetooth.defaultAdapter.enabled = !Bluetooth.defaultAdapter?.enabled
}
altAction: () => {
root.openMenu()
}
StyledToolTip {
text: Translation.tr("%1 | Right-click to configure").arg(
(BluetoothStatus.firstActiveDevice?.name ?? Translation.tr("Bluetooth"))
+ (BluetoothStatus.activeDeviceCount > 1 ? ` +${BluetoothStatus.activeDeviceCount - 1}` : "")
)
}
} }
@@ -1,4 +1,5 @@
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.services import qs.services
import QtQuick import QtQuick
@@ -8,73 +9,5 @@ import Quickshell.Io
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root id: root
name: Translation.tr("Cloudflare WARP") toggleModel: CloudflareWarpToggle {}
toggled: false
buttonIcon: "cloud_lock"
mainAction: () => {
if (toggled) {
root.toggled = false
Quickshell.execDetached(["warp-cli", "disconnect"])
} else {
root.toggled = true
Quickshell.execDetached(["warp-cli", "connect"])
}
}
Process {
id: connectProc
command: ["warp-cli", "connect"]
onExited: (exitCode, exitStatus) => {
if (exitCode !== 0) {
Quickshell.execDetached(["notify-send",
Translation.tr("Cloudflare WARP"),
Translation.tr("Connection failed. Please inspect manually with the <tt>warp-cli</tt> command")
, "-a", "Shell"
])
}
}
}
Process {
id: registrationProc
command: ["warp-cli", "registration", "new"]
onExited: (exitCode, exitStatus) => {
console.log("Warp registration exited with code and status:", exitCode, exitStatus)
if (exitCode === 0) {
connectProc.running = true
} else {
Quickshell.execDetached(["notify-send",
Translation.tr("Cloudflare WARP"),
Translation.tr("Registration failed. Please inspect manually with the <tt>warp-cli</tt> command"),
"-a", "Shell"
])
}
}
}
Process {
id: fetchActiveState
running: true
command: ["bash", "-c", "warp-cli status"]
stdout: StdioCollector {
id: warpStatusCollector
onStreamFinished: {
if (warpStatusCollector.text.length > 0) {
root.visible = true
}
if (warpStatusCollector.text.includes("Unable")) {
registrationProc.running = true
} else if (warpStatusCollector.text.includes("Connected")) {
root.toggled = true
} else if (warpStatusCollector.text.includes("Disconnected")) {
root.toggled = false
}
}
}
}
StyledToolTip {
text: Translation.tr("Cloudflare WARP (1.1.1.1)")
}
} }
@@ -1,5 +1,6 @@
import qs import qs
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.services import qs.services
import QtQuick import QtQuick
@@ -8,25 +9,5 @@ import Quickshell
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root id: root
name: Translation.tr("Color picker") toggleModel: ColorPickerToggle {}
statusText: ""
toggled: false
buttonIcon: "colorize"
mainAction: () => {
GlobalStates.sidebarRightOpen = false;
delayedActionTimer.start()
}
Timer {
id: delayedActionTimer
interval: 300
repeat: false
onTriggered: {
Quickshell.execDetached(["hyprpicker", "-a"])
}
}
StyledToolTip {
text: Translation.tr("Color picker")
}
} }
@@ -1,27 +1,10 @@
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.services import qs.services
import QtQuick import QtQuick
import Quickshell import Quickshell
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root toggleModel: DarkModeToggle {}
name: Translation.tr("Dark Mode")
statusText: Appearance.m3colors.darkmode ? Translation.tr("Dark") : Translation.tr("Light")
toggled: Appearance.m3colors.darkmode
buttonIcon: "contrast"
mainAction: () => {
if (Appearance.m3colors.darkmode) {
Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", "light", "--noswitch"]);
} else {
Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", "dark", "--noswitch"]);
}
}
StyledToolTip {
text: Translation.tr("Dark Mode")
}
} }
@@ -1,33 +1,11 @@
import qs import qs
import qs.modules.common.models.quickToggles
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.services import qs.services
import QtQuick import QtQuick
import Quickshell import Quickshell
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root toggleModel: EasyEffectsToggle {}
name: Translation.tr("EasyEffects")
available: EasyEffects.available
toggled: EasyEffects.active
buttonIcon: "graphic_eq"
Component.onCompleted: {
EasyEffects.fetchActiveState()
}
mainAction: () => {
EasyEffects.toggle()
}
altAction: () => {
Quickshell.execDetached(["bash", "-c", "flatpak run com.github.wwmm.easyeffects || easyeffects"])
GlobalStates.sidebarRightOpen = false
}
StyledToolTip {
text: Translation.tr("EasyEffects | Right-click to configure")
}
} }
@@ -1,4 +1,5 @@
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.services import qs.services
import QtQuick import QtQuick
@@ -6,30 +7,5 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root toggleModel: GameModeToggle {}
name: Translation.tr("Game mode")
statusText: ""
toggled: toggled
buttonIcon: "gamepad"
mainAction: () => {
root.toggled = !root.toggled
if (root.toggled) {
Quickshell.execDetached(["bash", "-c", `hyprctl --batch "keyword animations:enabled 0; keyword decoration:shadow:enabled 0; keyword decoration:blur:enabled 0; keyword general:gaps_in 0; keyword general:gaps_out 0; keyword general:border_size 1; keyword decoration:rounding 0; keyword general:allow_tearing 1"`])
} else {
Quickshell.execDetached(["hyprctl", "reload"])
}
}
Process {
id: fetchActiveState
running: true
command: ["bash", "-c", `test "$(hyprctl getoption animations:enabled -j | jq ".int")" -ne 0`]
onExited: (exitCode, exitStatus) => {
root.toggled = exitCode !== 0 // Inverted because enabled = nonzero exit
}
}
StyledToolTip {
text: Translation.tr("Game mode")
}
} }
@@ -1,21 +1,11 @@
import qs.services import qs.services
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.functions import qs.modules.common.functions
import qs.modules.common.widgets import qs.modules.common.widgets
import QtQuick import QtQuick
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root toggleModel: IdleInhibitorToggle {}
name: Translation.tr("Keep awake")
toggled: Idle.inhibit
buttonIcon: "coffee"
mainAction: () => {
Idle.toggleInhibit()
}
StyledToolTip {
text: Translation.tr("Keep system awake")
}
} }
@@ -1,26 +1,11 @@
import qs import qs
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.services import qs.services
import QtQuick import QtQuick
import Quickshell import Quickshell
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root toggleModel: MicToggle {}
name: Translation.tr("Audio input")
statusText: toggled ? Translation.tr("Enabled") : Translation.tr("Muted")
toggled: !Audio.source?.audio?.muted
buttonIcon: Audio.source?.audio?.muted ? "mic_off" : "mic"
mainAction: () => {
Audio.source.audio.muted = !Audio.source.audio.muted
}
altAction: () => {
root.openMenu()
}
StyledToolTip {
text: Translation.tr("Audio input | Right-click for volume mixer & device selector")
}
} }
@@ -1,5 +1,6 @@
import qs import qs
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.widgets import qs.modules.common.widgets
import QtQuick import QtQuick
import Quickshell import Quickshell
@@ -8,25 +9,5 @@ import qs.services
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root toggleModel: MusicRecognitionToggle {}
toggled: SongRec.running
property bool sourceIsMonitor: SongRec.monitorSource === SongRec.MonitorSource.Monitor
name: Translation.tr("Identify Music")
statusText: toggled ? Translation.tr("Listening...") : sourceIsMonitor ? Translation.tr("System sound") : Translation.tr("Microphone")
buttonIcon: toggled ? "music_cast" : (sourceIsMonitor ? "music_note" : "frame_person_mic")
StyledToolTip {
text: Translation.tr("Recognize music | Right-click to toggle source")
}
mainAction: () => {
SongRec.toggleRunning()
}
altAction: () => {
SongRec.toggleMonitorSource()
}
} }
@@ -1,5 +1,6 @@
import qs.services import qs.services
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.functions import qs.modules.common.functions
import qs.modules.common.widgets import qs.modules.common.widgets
import QtQuick import QtQuick
@@ -7,17 +8,6 @@ import QtQuick
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root id: root
name: Translation.tr("Internet") toggleModel: NetworkToggle {}
statusText: Network.networkName
toggled: Network.wifiStatus !== "disabled"
buttonIcon: Network.materialSymbol
mainAction: () => Network.toggleWifi()
altAction: () => {
root.openMenu()
}
StyledToolTip {
text: Translation.tr("%1 | Right-click to configure").arg(Network.networkName)
}
} }
@@ -1,34 +1,11 @@
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.services import qs.services
import QtQuick import QtQuick
import Quickshell import Quickshell
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root toggleModel: NightLightToggle {}
property bool auto: Config.options.light.night.automatic
name: Translation.tr("Night Light")
statusText: (auto ? Translation.tr("Auto, ") : "") + (toggled ? Translation.tr("Active") : Translation.tr("Inactive"))
toggled: Hyprsunset.active
buttonIcon: auto ? "night_sight_auto" : "bedtime"
mainAction: () => {
Hyprsunset.toggle()
}
altAction: () => {
root.openMenu()
}
Component.onCompleted: {
Hyprsunset.fetchState()
}
StyledToolTip {
text: Translation.tr("Night Light | Right-click to configure")
}
} }
@@ -1,23 +1,11 @@
import qs import qs
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.services import qs.services
import QtQuick import QtQuick
import Quickshell import Quickshell
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root toggleModel: NotificationToggle {}
name: Translation.tr("Notifications")
statusText: toggled ? Translation.tr("Show") : Translation.tr("Silent")
toggled: !Notifications.silent
buttonIcon: toggled ? "notifications_active" : "notifications_paused"
mainAction: () => {
Notifications.silent = !Notifications.silent;
}
StyledToolTip {
text: Translation.tr("Show notifications")
}
} }
@@ -1,22 +1,11 @@
import qs import qs
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.services import qs.services
import QtQuick import QtQuick
import Quickshell import Quickshell
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root toggleModel: OnScreenKeyboardToggle {}
name: Translation.tr("Virtual Keyboard")
toggled: GlobalStates.oskOpen
buttonIcon: toggled ? "keyboard_hide" : "keyboard"
mainAction: () => {
GlobalStates.oskOpen = !GlobalStates.oskOpen
}
StyledToolTip {
text: Translation.tr("On-screen keyboard")
}
} }
@@ -1,5 +1,6 @@
import qs import qs
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.services import qs.services
import QtQuick import QtQuick
@@ -7,36 +8,5 @@ import Quickshell
import Quickshell.Services.UPower import Quickshell.Services.UPower
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root toggleModel: PowerProfilesToggle {}
name: Translation.tr("Power Profile")
toggled: PowerProfiles.profile !== PowerProfile.Balanced
buttonIcon: switch(PowerProfiles.profile) {
case PowerProfile.PowerSaver: return "energy_savings_leaf"
case PowerProfile.Balanced: return "settings_slow_motion"
case PowerProfile.Performance: return "local_fire_department"
}
statusText: switch(PowerProfiles.profile) {
case PowerProfile.PowerSaver: return "Power Saver"
case PowerProfile.Balanced: return "Balanced"
case PowerProfile.Performance: return "Performance"
}
mainAction: () => {
if (PowerProfiles.hasPerformanceProfile) {
switch(PowerProfiles.profile) {
case PowerProfile.PowerSaver: PowerProfiles.profile = PowerProfile.Balanced
break;
case PowerProfile.Balanced: PowerProfiles.profile = PowerProfile.Performance
break;
case PowerProfile.Performance: PowerProfiles.profile = PowerProfile.PowerSaver
break;
}
} else {
PowerProfiles.profile = PowerProfiles.profile == PowerProfile.Balanced ? PowerProfile.PowerSaver : PowerProfile.Balanced
}
}
StyledToolTip {
text: Translation.tr("Click to cycle through power profiles")
}
} }
@@ -2,29 +2,42 @@ import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.services import qs.services
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.functions import qs.modules.common.functions
import qs.modules.common.widgets import qs.modules.common.widgets
GroupButton { GroupButton {
id: root id: root
// Info to be passed to by repeater
required property int buttonIndex required property int buttonIndex
required property var buttonData required property var buttonData
required property bool expandedSize required property bool expandedSize
required property string buttonIcon
required property string name
required property var mainAction
property string statusText: toggled ? Translation.tr("Active") : Translation.tr("Inactive")
property bool available: true
required property real baseCellWidth required property real baseCellWidth
required property real baseCellHeight required property real baseCellHeight
required property real cellSpacing required property real cellSpacing
required property int cellSize required property int cellSize
// Signals
signal openMenu()
// Declared in specific toggles
property QuickToggleModel toggleModel
property string name: toggleModel?.name ?? ""
property string statusText: (toggleModel?.hasStatusText) ? (toggleModel?.statusText || (toggled ? Translation.tr("Active") : Translation.tr("Inactive"))) : ""
property string tooltipText: toggleModel?.tooltipText ?? ""
property string buttonIcon: toggleModel?.icon ?? "close"
property bool available: toggleModel?.available ?? true
toggled: toggleModel?.toggled ?? false
property var mainAction: toggleModel?.mainAction ?? null
altAction: toggleModel?.hasMenu ? (() => root.openMenu()) : (toggleModel?.altAction ?? null)
// Edit mode state
property bool editMode: false
// Sizing shenanigans
baseWidth: root.baseCellWidth * cellSize + cellSpacing * (cellSize - 1) baseWidth: root.baseCellWidth * cellSize + cellSpacing * (cellSize - 1)
baseHeight: root.baseCellHeight baseHeight: root.baseCellHeight
property bool editMode: false
enableImplicitWidthAnimation: !editMode && root.mouseArea.containsMouse enableImplicitWidthAnimation: !editMode && root.mouseArea.containsMouse
enableImplicitHeightAnimation: !editMode && root.mouseArea.containsMouse enableImplicitHeightAnimation: !editMode && root.mouseArea.containsMouse
Behavior on baseWidth { Behavior on baseWidth {
@@ -41,8 +54,6 @@ GroupButton {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
} }
signal openMenu()
enabled: available || editMode enabled: available || editMode
padding: 6 padding: 6
horizontalPadding: padding horizontalPadding: padding
@@ -226,4 +237,9 @@ GroupButton {
event.accepted = true; event.accepted = true;
} }
} }
StyledToolTip {
extraVisibleCondition: root.tooltipText !== ""
text: root.tooltipText
}
} }
@@ -1,5 +1,6 @@
import qs import qs
import qs.modules.common import qs.modules.common
import qs.modules.common.models.quickToggles
import qs.modules.common.widgets import qs.modules.common.widgets
import qs.services import qs.services
import QtQuick import QtQuick
@@ -7,27 +8,5 @@ import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
AndroidQuickToggleButton { AndroidQuickToggleButton {
id: root toggleModel: ScreenSnipToggle {}
name: Translation.tr("Screen snip")
statusText: ""
toggled: false
buttonIcon: "screenshot_region"
mainAction: () => {
GlobalStates.sidebarRightOpen = false;
delayedActionTimer.start()
}
Timer {
id: delayedActionTimer
interval: 300
repeat: false
onTriggered: {
Quickshell.execDetached(["qs", "-p", Quickshell.shellPath(""), "ipc", "call", "region", "screenshot"]);
}
}
StyledToolTip {
text: Translation.tr("Screen snip")
}
} }
@@ -171,16 +171,8 @@ Item { // Bar content region
implicitWidth: Appearance.sizes.baseVerticalBarWidth implicitWidth: Appearance.sizes.baseVerticalBarWidth
implicitHeight: bottomSectionColumnLayout.implicitHeight implicitHeight: bottomSectionColumnLayout.implicitHeight
onScrollDown: { onScrollDown: Audio.decrementVolume();
const currentVolume = Audio.value; onScrollUp: Audio.incrementVolume();
const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
Audio.sink.audio.volume -= step;
}
onScrollUp: {
const currentVolume = Audio.value;
const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
Audio.sink.audio.volume = Math.min(1, Audio.sink.audio.volume + step);
}
onMovedAway: GlobalStates.osdVolumeOpen = false; onMovedAway: GlobalStates.osdVolumeOpen = false;
onPressed: event => { onPressed: event => {
if (event.button === Qt.LeftButton) { if (event.button === Qt.LeftButton) {
@@ -0,0 +1,113 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
Rectangle {
id: root
property int currentPage: 0
property alias columns: grid.columns
property alias rows: grid.rows
readonly property int itemsPerPage: columns * rows
property list<string> toggles: Config.options.waffles.actionCenter.toggles
property list<string> togglesInCurrentPage: toggles.slice(currentPage * itemsPerPage, (currentPage + 1) * itemsPerPage)
Layout.fillHeight: true
Layout.fillWidth: true
color: Looks.colors.bgPanelBody
implicitWidth: 360
implicitHeight: contentLayout.implicitHeight
ColumnLayout {
id: contentLayout
anchors.fill: parent
spacing: 0
Item {
id: togglesContainer
property real padding: 22
Layout.fillWidth: true
Layout.bottomMargin: -12
implicitHeight: grid.implicitHeight + padding * 2
GridLayout {
id: grid
anchors {
fill: parent
margins: parent.padding
}
columns: 3
rows: 2
rowSpacing: 12
columnSpacing: 12
uniformCellHeights: true
uniformCellWidths: true
Repeater {
model: ScriptModel {
values: root.togglesInCurrentPage
}
delegate: ActionCenterToggle {
required property var modelData
name: modelData
}
}
}
// TODO: pages indicator on the right
}
Rectangle {
implicitHeight: 1
Layout.fillWidth: true
color: Looks.colors.bg1Border
}
RowLayout {
Layout.margins: 12
Layout.topMargin: 18
Layout.bottomMargin: 14
spacing: 4
WPanelIconButton {
iconName: WIcons.volumeIcon
onClicked: {
Audio.sink.audio.muted = !Audio.sink.audio.muted;
}
}
WSlider {
Layout.fillWidth: true
value: Audio.sink.audio.volume
onMoved: {
Audio.sink.audio.volume = value;
}
}
WPanelIconButton {
contentItem: Item {
anchors.centerIn: parent
Row {
anchors.centerIn: parent
spacing: -1
FluentIcon {
anchors.verticalCenter: parent.verticalCenter
implicitSize: 18
icon: "settings"
}
FluentIcon {
anchors.verticalCenter: parent.verticalCenter
implicitSize: 12
icon: "chevron-right"
}
}
}
}
}
}
}
@@ -14,15 +14,9 @@ WBarAttachedPanelContent {
anchors.centerIn: parent anchors.centerIn: parent
spacing: 0 spacing: 0
Rectangle { ActionCenterBody {
Layout.fillHeight: true
Layout.fillWidth: true
topLeftRadius: root.border.radius - root.border.border.width topLeftRadius: root.border.radius - root.border.border.width
topRightRadius: topLeftRadius topRightRadius: topLeftRadius
color: Looks.colors.bgPanelBody
implicitWidth: 360
implicitHeight: 380
} }
Rectangle { Rectangle {
@@ -32,46 +26,9 @@ WBarAttachedPanelContent {
implicitHeight: 1 implicitHeight: 1
} }
Rectangle { ActionCenterFooter {
Layout.fillHeight: false
Layout.fillWidth: true
bottomLeftRadius: root.border.radius - root.border.border.width bottomLeftRadius: root.border.radius - root.border.border.width
bottomRightRadius: bottomLeftRadius bottomRightRadius: bottomLeftRadius
color: Looks.colors.bgPanelFooter
implicitWidth: 360
implicitHeight: 47
// Battery button
WPanelFooterButton {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 12
contentItem: Row {
spacing: 4
FluentIcon {
anchors.verticalCenter: parent.verticalCenter
icon: WIcons.batteryIcon
}
WText {
anchors.verticalCenter: parent.verticalCenter
text: `${Math.round(Battery.percentage * 100) || 0}%`
}
}
}
// Settings button
WPanelFooterButton {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 12
contentItem: FluentIcon {
icon: "settings"
}
}
} }
} }
} }
@@ -0,0 +1,49 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
Rectangle {
Layout.fillHeight: false
Layout.fillWidth: true
color: Looks.colors.bgPanelFooter
implicitWidth: 360
implicitHeight: 47
// Battery button
WPanelFooterButton {
visible: Battery.available
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 12
contentItem: Row {
spacing: 4
FluentIcon {
anchors.verticalCenter: parent.verticalCenter
icon: WIcons.batteryIcon
}
WText {
anchors.verticalCenter: parent.verticalCenter
text: `${Math.round(Battery.percentage * 100) || 0}%`
}
}
}
// Settings button
WPanelFooterButton {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 12
contentItem: FluentIcon {
icon: "settings"
}
}
}
@@ -0,0 +1,40 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
// It should be perfectly fine to use just a Column here, but somehow
// using ColumnLayout prevents weird opening anim stutter
ColumnLayout {
id: root
property alias name: toggleNameText.text
Rectangle {
Layout.fillWidth: true
implicitWidth: 96
implicitHeight: 48
color: "transparent"
border.width: 1
border.color: Looks.colors.bg0Border // ???
radius: Looks.radius.medium
}
Item {
implicitHeight: 36
Layout.fillWidth: true
WText {
id: toggleNameText
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
right: parent.right
}
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
text: "Toggle"
}
}
}
@@ -0,0 +1,16 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
import qs.modules.waffle.actionCenter
ActionCenterToggle {
id: root
name: Network.ethernet ? Translation.tr("Network") : Network.networkName
}
@@ -3,6 +3,7 @@ import QtQuick.Layouts
import qs import qs
import qs.services import qs.services
import qs.modules.common import qs.modules.common
import qs.modules.common.widgets
import qs.modules.waffle.looks import qs.modules.waffle.looks
BarButton { BarButton {
@@ -38,22 +39,15 @@ BarButton {
id: volumeHoverArea id: volumeHoverArea
iconItem: FluentIcon { iconItem: FluentIcon {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
icon: { icon: WIcons.volumeIcon
const muted = Audio.sink?.audio.muted ?? false;
const volume = Audio.sink?.audio.volume ?? 0;
if (muted)
return volume > 0 ? "speaker-off" : "speaker-none";
if (volume == 0)
return "speaker-none";
if (volume < 0.5)
return "speaker-1";
return "speaker";
}
} }
onScrollDown: Audio.decrementVolume();
onScrollUp: Audio.incrementVolume();
} }
IconHoverArea { IconHoverArea {
id: batteryHoverArea id: batteryHoverArea
visible: Battery?.available ?? false
iconItem: FluentIcon { iconItem: FluentIcon {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
icon: WIcons.batteryIcon icon: WIcons.batteryIcon
@@ -62,7 +56,7 @@ BarButton {
} }
} }
component IconHoverArea: MouseArea { component IconHoverArea: FocusedScrollMouseArea {
id: hoverArea id: hoverArea
required property var iconItem required property var iconItem
anchors { anchors {
@@ -85,6 +85,7 @@ AppButton {
BarMenu { BarMenu {
id: contextMenu id: contextMenu
noSmoothClosing: false // On the real thing this is always smooth
model: [ model: [
...((root.desktopEntry?.actions.length > 0) ? root.desktopEntry.actions.map(action =>({ ...((root.desktopEntry?.actions.length > 0) ? root.desktopEntry.actions.map(action =>({
@@ -35,6 +35,8 @@ Singleton {
property color bg2Border: root.dark ? "#464646" : "#EEEEEE" property color bg2Border: root.dark ? "#464646" : "#EEEEEE"
property color fg: root.dark ? "#FFFFFF" : "#000000" property color fg: root.dark ? "#FFFFFF" : "#000000"
property color fg1: root.dark ? "#D1D1D1" : "#626262" property color fg1: root.dark ? "#D1D1D1" : "#626262"
property color controlBg: root.dark ? "#9B9B9B" : "#868686"
property color controlFg: root.dark ? "#454545" : "#FFFFFF"
property color danger: "#C42B1C" property color danger: "#C42B1C"
property color dangerActive: "#B62D1F" property color dangerActive: "#B62D1F"
property color warning: "#FF9900" property color warning: "#FF9900"
@@ -71,6 +73,9 @@ Singleton {
transition: QtObject { transition: QtObject {
id: transition id: transition
property int velocity: 850
property QtObject easing: QtObject { property QtObject easing: QtObject {
property QtObject bezierCurve: QtObject { property QtObject bezierCurve: QtObject {
readonly property list<real> easeInOut: [0.42,0.00,0.58,1.00,1,1] readonly property list<real> easeInOut: [0.42,0.00,0.58,1.00,1,1]
@@ -27,5 +27,16 @@ Singleton {
if (Battery.percentage >= 0.9) return "battery-full"; if (Battery.percentage >= 0.9) return "battery-full";
return `battery-${Math.ceil(Battery.percentage * 10)}`; return `battery-${Math.ceil(Battery.percentage * 10)}`;
} }
property string volumeIcon: {
const muted = Audio.sink?.audio.muted ?? false;
const volume = Audio.sink?.audio.volume ?? 0;
if (muted)
return volume > 0 ? "speaker-off" : "speaker-none";
if (volume == 0)
return "speaker-none";
if (volume < 0.5)
return "speaker-1";
return "speaker";
}
} }
@@ -0,0 +1,23 @@
import QtQuick
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.waffle.looks
import qs.modules.waffle.bar
WButton {
id: root
property alias iconName: iconContent.icon
inset: 0
implicitWidth: 40
implicitHeight: 40
contentItem: FluentIcon {
id: iconContent
anchors.centerIn: parent
implicitSize: 18
icon: root.iconName
}
}
@@ -0,0 +1,81 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell.Widgets
import qs.modules.common
import qs.modules.common.widgets
Slider {
id: root
property real trackWidth: 4
// leftPadding: handle.width / 2
// rightPadding: handle.width / 2
leftPadding: 0
rightPadding: 0
implicitHeight: handle.implicitHeight
Behavior on value { // This makes the adjusted value (like volume) shift smoothly
SmoothedAnimation {
velocity: Looks.transition.velocity
}
}
background: Item {
id: background
anchors.fill: parent
Rectangle {
id: trackHighlight
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
}
topLeftRadius: root.trackWidth / 2
bottomLeftRadius: root.trackWidth / 2
color: Looks.colors.accent
implicitHeight: root.trackWidth
width: background.width * root.visualPosition
}
Rectangle {
id: trackTrough
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
}
topLeftRadius: root.trackWidth / 2
bottomLeftRadius: root.trackWidth / 2
color: Looks.colors.controlBg
implicitHeight: root.trackWidth
width: background.width * (1 - root.visualPosition)
}
}
handle: Circle {
id: handle
anchors.verticalCenter: parent.verticalCenter
x: (diameter / 2) + root.visualPosition * (root.width - diameter) - (diameter / 2)
diameter: 20
color: Looks.colors.controlFg
MouseArea {
id: handleMouseArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
}
Circle {
anchors.centerIn: parent
diameter: root.pressed ? 10 : handleMouseArea.containsMouse ? 14 : 12
color: Looks.colors.accent
Behavior on diameter {
animation: Looks.transition.enter.createObject(this)
}
}
}
}
+23 -1
View File
@@ -16,9 +16,31 @@ Singleton {
property PwNode source: Pipewire.defaultAudioSource property PwNode source: Pipewire.defaultAudioSource
readonly property real hardMaxValue: 2.00 // People keep joking about setting volume to 5172% so... readonly property real hardMaxValue: 2.00 // People keep joking about setting volume to 5172% so...
property string audioTheme: Config.options.sounds.theme property string audioTheme: Config.options.sounds.theme
property real value: sink?.audio.volume ?? 0
signal sinkProtectionTriggered(string reason); signal sinkProtectionTriggered(string reason);
function toggleMute() {
Audio.sink.audio.muted = !Audio.sink.audio.muted
}
function toggleMicMute() {
Audio.source.audio.muted = !Audio.source.audio.muted
}
function incrementVolume() {
const currentVolume = Audio.value;
const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
Audio.sink.audio.volume = Math.min(1, Audio.sink.audio.volume + step);
}
function decrementVolume() {
const currentVolume = Audio.value;
const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
Audio.sink.audio.volume -= step;
}
PwObjectTracker { PwObjectTracker {
objects: [sink, source] objects: [sink, source]
} }
+1 -1
View File
@@ -90,7 +90,7 @@ ShellRoot {
property list<string> families: ["ii", "waffle"] property list<string> families: ["ii", "waffle"]
property var panelFamilies: ({ property var panelFamilies: ({
"ii": ["iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiReloadPopup", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector"], "ii": ["iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiReloadPopup", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector"],
"waffle": ["wBar", "wBackground", "wActionCenter", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiReloadPopup", "iiSessionScreen", "iiSidebarRight", "iiWallpaperSelector"], "waffle": ["wBar", "wBackground", "wActionCenter", "iiCheatsheet", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiReloadPopup", "iiSessionScreen", "iiSidebarRight", "iiWallpaperSelector"],
}) })
function cyclePanelFamily() { function cyclePanelFamily() {
const currentIndex = families.indexOf(Config.options.panelFamily) const currentIndex = families.indexOf(Config.options.panelFamily)