diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/chevron-right.svg b/dots/.config/quickshell/ii/assets/icons/fluent/chevron-right.svg
new file mode 100644
index 000000000..0ac6a30d5
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/chevron-right.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/speaker-settings.svg b/dots/.config/quickshell/ii/assets/icons/fluent/speaker-settings.svg
new file mode 100644
index 000000000..072abd842
--- /dev/null
+++ b/dots/.config/quickshell/ii/assets/icons/fluent/speaker-settings.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml
index ec47c514b..32d377530 100644
--- a/dots/.config/quickshell/ii/modules/common/Config.qml
+++ b/dots/.config/quickshell/ii/modules/common/Config.qml
@@ -572,7 +572,7 @@ Singleton {
}
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.
// Example: the right-click menu of the Start button
property bool smootherAnimations: true
@@ -580,6 +580,9 @@ Singleton {
property bool bottom: true
property bool leftAlignApps: false
}
+ property JsonObject actionCenter: JsonObject {
+ property list toggles: []
+ }
}
}
}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/AntiFlashbangToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/AntiFlashbangToggle.qml
new file mode 100644
index 000000000..088434ad7
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/AntiFlashbangToggle.qml
@@ -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
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/AudioToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/AudioToggle.qml
new file mode 100644
index 000000000..3f79674da
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/AudioToggle.qml
@@ -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
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/BluetoothToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/BluetoothToggle.qml
new file mode 100644
index 000000000..11b920cb2
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/BluetoothToggle.qml
@@ -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
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/CloudflareWarpToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/CloudflareWarpToggle.qml
new file mode 100644
index 000000000..015010cf7
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/CloudflareWarpToggle.qml
@@ -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 warp-cli 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 warp-cli 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)")
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/ColorPickerToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/ColorPickerToggle.qml
new file mode 100644
index 000000000..611e256c5
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/ColorPickerToggle.qml
@@ -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")
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/DarkModeToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/DarkModeToggle.qml
new file mode 100644
index 000000000..8a98f6f51
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/DarkModeToggle.qml
@@ -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")
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/EasyEffectsToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/EasyEffectsToggle.qml
new file mode 100644
index 000000000..4f76c09cc
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/EasyEffectsToggle.qml
@@ -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")
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/GameModeToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/GameModeToggle.qml
new file mode 100644
index 000000000..d8ba7402b
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/GameModeToggle.qml
@@ -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")
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/IdleInhibitorToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/IdleInhibitorToggle.qml
new file mode 100644
index 000000000..b6cf252bb
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/IdleInhibitorToggle.qml
@@ -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")
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/MicToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/MicToggle.qml
new file mode 100644
index 000000000..ced0cb03e
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/MicToggle.qml
@@ -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")
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/MusicRecognitionToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/MusicRecognitionToggle.qml
new file mode 100644
index 000000000..36f161a7d
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/MusicRecognitionToggle.qml
@@ -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()
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/NetworkToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/NetworkToggle.qml
new file mode 100644
index 000000000..f6f412d01
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/NetworkToggle.qml
@@ -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
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/NightLightToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/NightLightToggle.qml
new file mode 100644
index 000000000..d53af9740
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/NightLightToggle.qml
@@ -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")
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/NotificationToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/NotificationToggle.qml
new file mode 100644
index 000000000..3c4c87146
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/NotificationToggle.qml
@@ -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")
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/OnScreenKeyboardToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/OnScreenKeyboardToggle.qml
new file mode 100644
index 000000000..f98ee5a47
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/OnScreenKeyboardToggle.qml
@@ -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")
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/PowerProfilesToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/PowerProfilesToggle.qml
new file mode 100644
index 000000000..ff4ab19ce
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/PowerProfilesToggle.qml
@@ -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")
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/QuickToggleModel.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/QuickToggleModel.qml
new file mode 100644
index 000000000..176edcb48
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/QuickToggleModel.qml
@@ -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 data
+}
diff --git a/dots/.config/quickshell/ii/modules/common/models/quickToggles/ScreenSnipToggle.qml b/dots/.config/quickshell/ii/modules/common/models/quickToggles/ScreenSnipToggle.qml
new file mode 100644
index 000000000..28c53334a
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/models/quickToggles/ScreenSnipToggle.qml
@@ -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")
+}
diff --git a/dots/.config/quickshell/ii/modules/common/widgets/Circle.qml b/dots/.config/quickshell/ii/modules/common/widgets/Circle.qml
new file mode 100644
index 000000000..ed137a94d
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/common/widgets/Circle.qml
@@ -0,0 +1,9 @@
+import QtQuick
+
+Rectangle {
+ property double diameter
+
+ implicitWidth: diameter
+ implicitHeight: diameter
+ radius: diameter / 2
+}
diff --git a/dots/.config/quickshell/ii/modules/ii/bar/BarContent.qml b/dots/.config/quickshell/ii/modules/ii/bar/BarContent.qml
index 997e0209b..04f13d1aa 100644
--- a/dots/.config/quickshell/ii/modules/ii/bar/BarContent.qml
+++ b/dots/.config/quickshell/ii/modules/ii/bar/BarContent.qml
@@ -197,16 +197,8 @@ Item { // Bar content region
implicitWidth: rightSectionRowLayout.implicitWidth
implicitHeight: Appearance.sizes.baseBarHeight
- onScrollDown: {
- const currentVolume = Audio.value;
- 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);
- }
+ onScrollDown: Audio.decrementVolume();
+ onScrollUp: Audio.incrementVolume();
onMovedAway: GlobalStates.osdVolumeOpen = false;
onPressed: event => {
if (event.button === Qt.LeftButton) {
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidAntiFlashbangToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidAntiFlashbangToggle.qml
index 4fc8ee4f5..f07d6c2db 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidAntiFlashbangToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidAntiFlashbangToggle.qml
@@ -1,3 +1,4 @@
+import qs.modules.common.models.quickToggles
import qs.modules.common
import qs.modules.common.widgets
import qs.services
@@ -6,24 +7,7 @@ import Quickshell
AndroidQuickToggleButton {
id: root
-
- property bool auto: Config.options.light.night.automatic
- name: Translation.tr("Anti-flashbang")
-
- 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")
- }
+ toggleModel: AntiFlashbangToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidAudioToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidAudioToggle.qml
index 52f7459a7..4a0ee5b34 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidAudioToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidAudioToggle.qml
@@ -1,5 +1,6 @@
import qs
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.widgets
import qs.services
import QtQuick
@@ -8,19 +9,5 @@ import Quickshell
AndroidQuickToggleButton {
id: root
- name: Translation.tr("Audio output")
- 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")
- }
+ toggleModel: AudioToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidBluetoothToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidBluetoothToggle.qml
index d592de63b..c0ab7d5c0 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidBluetoothToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidBluetoothToggle.qml
@@ -1,5 +1,6 @@
import qs.services
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.functions
import qs.modules.common.widgets
import QtQuick
@@ -9,22 +10,5 @@ import Quickshell.Bluetooth
AndroidQuickToggleButton {
id: root
- name: Translation.tr("Bluetooth")
- 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}` : "")
- )
- }
+ toggleModel: BluetoothToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidCloudflareWarpToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidCloudflareWarpToggle.qml
index 5b65e673d..9385133bb 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidCloudflareWarpToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidCloudflareWarpToggle.qml
@@ -1,4 +1,5 @@
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.widgets
import qs.services
import QtQuick
@@ -8,73 +9,5 @@ import Quickshell.Io
AndroidQuickToggleButton {
id: root
- name: Translation.tr("Cloudflare WARP")
-
- 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 warp-cli 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 warp-cli 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)")
- }
+ toggleModel: CloudflareWarpToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidColorPickerToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidColorPickerToggle.qml
index 8fdc59205..9319398bd 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidColorPickerToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidColorPickerToggle.qml
@@ -1,5 +1,6 @@
import qs
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.widgets
import qs.services
import QtQuick
@@ -8,25 +9,5 @@ import Quickshell
AndroidQuickToggleButton {
id: root
- name: Translation.tr("Color picker")
- 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")
- }
+ toggleModel: ColorPickerToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidDarkModeToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidDarkModeToggle.qml
index 11be0dae6..4defe6bdd 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidDarkModeToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidDarkModeToggle.qml
@@ -1,27 +1,10 @@
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.widgets
import qs.services
import QtQuick
import Quickshell
AndroidQuickToggleButton {
- id: root
-
- 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")
- }
+ toggleModel: DarkModeToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml
index 0ce6b7ab4..157d9236f 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml
@@ -1,33 +1,11 @@
import qs
+import qs.modules.common.models.quickToggles
import qs.modules.common.widgets
import qs.services
import QtQuick
import Quickshell
AndroidQuickToggleButton {
- id: root
-
- 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")
- }
+ toggleModel: EasyEffectsToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidGameModeToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidGameModeToggle.qml
index ae63622fe..ec3225e02 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidGameModeToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidGameModeToggle.qml
@@ -1,4 +1,5 @@
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.widgets
import qs.services
import QtQuick
@@ -6,30 +7,5 @@ import Quickshell
import Quickshell.Io
AndroidQuickToggleButton {
- id: root
-
- 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")
- }
+ toggleModel: GameModeToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidIdleInhibitorToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidIdleInhibitorToggle.qml
index 2daf1f914..a42d6807c 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidIdleInhibitorToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidIdleInhibitorToggle.qml
@@ -1,21 +1,11 @@
import qs.services
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.functions
import qs.modules.common.widgets
import QtQuick
AndroidQuickToggleButton {
- id: root
-
- name: Translation.tr("Keep awake")
-
- toggled: Idle.inhibit
- buttonIcon: "coffee"
- mainAction: () => {
- Idle.toggleInhibit()
- }
- StyledToolTip {
- text: Translation.tr("Keep system awake")
- }
+ toggleModel: IdleInhibitorToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidMicToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidMicToggle.qml
index 7ffeea7f7..55f36a3a4 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidMicToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidMicToggle.qml
@@ -1,26 +1,11 @@
import qs
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.widgets
import qs.services
import QtQuick
import Quickshell
AndroidQuickToggleButton {
- id: root
-
- 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")
- }
+ toggleModel: MicToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml
index 23e2cda92..41139b048 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml
@@ -1,5 +1,6 @@
import qs
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.widgets
import QtQuick
import Quickshell
@@ -8,25 +9,5 @@ import qs.services
AndroidQuickToggleButton {
- id: root
-
- 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()
- }
-
+ toggleModel: MusicRecognitionToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidNetworkToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidNetworkToggle.qml
index eaf24e141..d5b594ef1 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidNetworkToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidNetworkToggle.qml
@@ -1,5 +1,6 @@
import qs.services
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.functions
import qs.modules.common.widgets
import QtQuick
@@ -7,17 +8,6 @@ import QtQuick
AndroidQuickToggleButton {
id: root
- name: Translation.tr("Internet")
- 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)
- }
+ toggleModel: NetworkToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidNightLightToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidNightLightToggle.qml
index 133b0ffcd..5681734e8 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidNightLightToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidNightLightToggle.qml
@@ -1,34 +1,11 @@
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.widgets
import qs.services
import QtQuick
import Quickshell
AndroidQuickToggleButton {
- id: root
-
- 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")
- }
+ toggleModel: NightLightToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidNotificationToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidNotificationToggle.qml
index eda39d716..544baa43a 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidNotificationToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidNotificationToggle.qml
@@ -1,23 +1,11 @@
import qs
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.widgets
import qs.services
import QtQuick
import Quickshell
AndroidQuickToggleButton {
- id: root
-
- 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")
- }
+ toggleModel: NotificationToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidOnScreenKeyboardToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidOnScreenKeyboardToggle.qml
index 779917802..3c97977ea 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidOnScreenKeyboardToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidOnScreenKeyboardToggle.qml
@@ -1,22 +1,11 @@
import qs
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.widgets
import qs.services
import QtQuick
import Quickshell
AndroidQuickToggleButton {
- id: root
-
- 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")
- }
+ toggleModel: OnScreenKeyboardToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml
index 381113308..0ac826cdd 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml
@@ -1,5 +1,6 @@
import qs
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.widgets
import qs.services
import QtQuick
@@ -7,36 +8,5 @@ import Quickshell
import Quickshell.Services.UPower
AndroidQuickToggleButton {
- id: root
-
- 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")
- }
+ toggleModel: PowerProfilesToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml
index 31ad2f262..ebaac6930 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml
@@ -2,29 +2,42 @@ import QtQuick
import QtQuick.Layouts
import qs.services
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.functions
import qs.modules.common.widgets
GroupButton {
id: root
+ // Info to be passed to by repeater
required property int buttonIndex
required property var buttonData
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 baseCellHeight
required property real cellSpacing
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)
baseHeight: root.baseCellHeight
-
- property bool editMode: false
enableImplicitWidthAnimation: !editMode && root.mouseArea.containsMouse
enableImplicitHeightAnimation: !editMode && root.mouseArea.containsMouse
Behavior on baseWidth {
@@ -41,8 +54,6 @@ GroupButton {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
- signal openMenu()
-
enabled: available || editMode
padding: 6
horizontalPadding: padding
@@ -226,4 +237,9 @@ GroupButton {
event.accepted = true;
}
}
+
+ StyledToolTip {
+ extraVisibleCondition: root.tooltipText !== ""
+ text: root.tooltipText
+ }
}
diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidScreenSnipToggle.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidScreenSnipToggle.qml
index 875022249..703a6ef83 100644
--- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidScreenSnipToggle.qml
+++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/quickToggles/androidStyle/AndroidScreenSnipToggle.qml
@@ -1,5 +1,6 @@
import qs
import qs.modules.common
+import qs.modules.common.models.quickToggles
import qs.modules.common.widgets
import qs.services
import QtQuick
@@ -7,27 +8,5 @@ import Quickshell
import Quickshell.Hyprland
AndroidQuickToggleButton {
- id: root
-
- 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")
- }
+ toggleModel: ScreenSnipToggle {}
}
diff --git a/dots/.config/quickshell/ii/modules/ii/verticalBar/VerticalBarContent.qml b/dots/.config/quickshell/ii/modules/ii/verticalBar/VerticalBarContent.qml
index d3326188e..82ebb4b68 100644
--- a/dots/.config/quickshell/ii/modules/ii/verticalBar/VerticalBarContent.qml
+++ b/dots/.config/quickshell/ii/modules/ii/verticalBar/VerticalBarContent.qml
@@ -171,16 +171,8 @@ Item { // Bar content region
implicitWidth: Appearance.sizes.baseVerticalBarWidth
implicitHeight: bottomSectionColumnLayout.implicitHeight
- onScrollDown: {
- const currentVolume = Audio.value;
- 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);
- }
+ onScrollDown: Audio.decrementVolume();
+ onScrollUp: Audio.incrementVolume();
onMovedAway: GlobalStates.osdVolumeOpen = false;
onPressed: event => {
if (event.button === Qt.LeftButton) {
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterBody.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterBody.qml
new file mode 100644
index 000000000..6f5a8e031
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterBody.qml
@@ -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 toggles: Config.options.waffles.actionCenter.toggles
+ property list 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"
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml
index 6d2e528db..e33fca0bf 100644
--- a/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterContent.qml
@@ -14,15 +14,9 @@ WBarAttachedPanelContent {
anchors.centerIn: parent
spacing: 0
- Rectangle {
- Layout.fillHeight: true
- Layout.fillWidth: true
+ ActionCenterBody {
topLeftRadius: root.border.radius - root.border.border.width
topRightRadius: topLeftRadius
- color: Looks.colors.bgPanelBody
-
- implicitWidth: 360
- implicitHeight: 380
}
Rectangle {
@@ -32,46 +26,9 @@ WBarAttachedPanelContent {
implicitHeight: 1
}
- Rectangle {
- Layout.fillHeight: false
- Layout.fillWidth: true
+ ActionCenterFooter {
bottomLeftRadius: root.border.radius - root.border.border.width
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"
- }
- }
}
}
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterFooter.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterFooter.qml
new file mode 100644
index 000000000..46d2517b8
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterFooter.qml
@@ -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"
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterToggle.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterToggle.qml
new file mode 100644
index 000000000..cb88b86a4
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/ActionCenterToggle.qml
@@ -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"
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/actionCenter/toggles/WNetworkToggle.qml b/dots/.config/quickshell/ii/modules/waffle/actionCenter/toggles/WNetworkToggle.qml
new file mode 100644
index 000000000..aa0ec5cad
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/actionCenter/toggles/WNetworkToggle.qml
@@ -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
+
+
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/SystemButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/SystemButton.qml
index 2ce1cd862..956d25ce7 100644
--- a/dots/.config/quickshell/ii/modules/waffle/bar/SystemButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/bar/SystemButton.qml
@@ -3,6 +3,7 @@ import QtQuick.Layouts
import qs
import qs.services
import qs.modules.common
+import qs.modules.common.widgets
import qs.modules.waffle.looks
BarButton {
@@ -38,22 +39,15 @@ BarButton {
id: volumeHoverArea
iconItem: FluentIcon {
anchors.verticalCenter: parent.verticalCenter
- icon: {
- 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";
- }
+ icon: WIcons.volumeIcon
}
+ onScrollDown: Audio.decrementVolume();
+ onScrollUp: Audio.incrementVolume();
}
IconHoverArea {
id: batteryHoverArea
+ visible: Battery?.available ?? false
iconItem: FluentIcon {
anchors.verticalCenter: parent.verticalCenter
icon: WIcons.batteryIcon
@@ -62,7 +56,7 @@ BarButton {
}
}
- component IconHoverArea: MouseArea {
+ component IconHoverArea: FocusedScrollMouseArea {
id: hoverArea
required property var iconItem
anchors {
diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/tasks/TaskAppButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/tasks/TaskAppButton.qml
index a5915e83e..9f3610fb3 100644
--- a/dots/.config/quickshell/ii/modules/waffle/bar/tasks/TaskAppButton.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/bar/tasks/TaskAppButton.qml
@@ -85,6 +85,7 @@ AppButton {
BarMenu {
id: contextMenu
+ noSmoothClosing: false // On the real thing this is always smooth
model: [
...((root.desktopEntry?.actions.length > 0) ? root.desktopEntry.actions.map(action =>({
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml
index a01628d4a..70d452fa7 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml
@@ -35,6 +35,8 @@ Singleton {
property color bg2Border: root.dark ? "#464646" : "#EEEEEE"
property color fg: root.dark ? "#FFFFFF" : "#000000"
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 dangerActive: "#B62D1F"
property color warning: "#FF9900"
@@ -71,6 +73,9 @@ Singleton {
transition: QtObject {
id: transition
+
+ property int velocity: 850
+
property QtObject easing: QtObject {
property QtObject bezierCurve: QtObject {
readonly property list easeInOut: [0.42,0.00,0.58,1.00,1,1]
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WIcons.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WIcons.qml
index 813b0a1ce..21e471489 100644
--- a/dots/.config/quickshell/ii/modules/waffle/looks/WIcons.qml
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WIcons.qml
@@ -27,5 +27,16 @@ Singleton {
if (Battery.percentage >= 0.9) return "battery-full";
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";
+ }
}
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WPanelIconButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WPanelIconButton.qml
new file mode 100644
index 000000000..edaad11a6
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WPanelIconButton.qml
@@ -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
+ }
+}
diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WSlider.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WSlider.qml
new file mode 100644
index 000000000..16921004c
--- /dev/null
+++ b/dots/.config/quickshell/ii/modules/waffle/looks/WSlider.qml
@@ -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)
+ }
+ }
+ }
+}
diff --git a/dots/.config/quickshell/ii/services/Audio.qml b/dots/.config/quickshell/ii/services/Audio.qml
index 5fca1a51a..633890cd0 100644
--- a/dots/.config/quickshell/ii/services/Audio.qml
+++ b/dots/.config/quickshell/ii/services/Audio.qml
@@ -16,9 +16,31 @@ Singleton {
property PwNode source: Pipewire.defaultAudioSource
readonly property real hardMaxValue: 2.00 // People keep joking about setting volume to 5172% so...
property string audioTheme: Config.options.sounds.theme
-
+ property real value: sink?.audio.volume ?? 0
+
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 {
objects: [sink, source]
}
diff --git a/dots/.config/quickshell/ii/shell.qml b/dots/.config/quickshell/ii/shell.qml
index 766728cf5..cbe7394c5 100644
--- a/dots/.config/quickshell/ii/shell.qml
+++ b/dots/.config/quickshell/ii/shell.qml
@@ -90,7 +90,7 @@ ShellRoot {
property list families: ["ii", "waffle"]
property var panelFamilies: ({
"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() {
const currentIndex = families.indexOf(Config.options.panelFamily)