diff --git a/dotfiles/.config/hypr/scripts/brightness.sh b/dotfiles/.config/hypr/scripts/brightness.sh new file mode 100644 index 000000000..2ba5354cd --- /dev/null +++ b/dotfiles/.config/hypr/scripts/brightness.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash + +get_mode() { + if ls /sys/class/backlight/* >/dev/null 2>&1; then + echo "backlight" + else + echo "ddc" + fi +} + +MODE=$(get_mode) + +case "$1" in + +displays) + if [ "$MODE" = "backlight" ]; then + echo 1 + else + ddcutil detect | grep "Display" | wc -l + fi +;; + +get) + if [ "$MODE" = "backlight" ]; then + brightnessctl -m | awk -F, '{gsub("%","",$4); print $4}' + else + ddcutil getvcp 10 | grep -oP 'current value =\s*\K\d+' | head -1 + fi +;; + +get-display) + if [ "$MODE" = "backlight" ]; then + brightnessctl -m | awk -F, '{gsub("%","",$4); print $4}' + else + ddcutil --display "$2" getvcp 10 | grep -oP 'current value =\s*\K\d+' + fi +;; + +set) + if [ "$MODE" = "backlight" ]; then + brightnessctl set "$2%" + else + for d in $(seq 1 $(ddcutil detect | grep Display | wc -l)); do + ddcutil --display "$d" setvcp 10 "$2" + done + fi +;; + +set-percentage) + if [ "$MODE" = "backlight" ]; then + brightnessctl set "$2%" + else + for d in $(seq 1 $(ddcutil detect | grep Display | wc -l)); do + current=$(ddcutil --display "$d" getvcp 10 | grep -oP 'current value =\s*\K\d+') + new=$((current + $2)) + + [ "$new" -gt 100 ] && new=100 + [ "$new" -lt 0 ] && new=0 + + ddcutil --display "$d" setvcp 10 "$new" + done + fi +;; + +set-display) + if [ "$MODE" = "backlight" ]; then + brightnessctl set "$3%" + else + ddcutil --display "$2" setvcp 10 "$3" + fi +;; + +set-display-percentage) + if [ "$MODE" = "backlight" ]; then + brightnessctl set "$3%" + else + delta="$3" + current=$(ddcutil --display "$2" getvcp 10 | grep -oP 'current value =\s*\K\d+') + new=$((current + delta)) + + [ "$new" -gt 100 ] && new=100 + [ "$new" -lt 0 ] && new=0 + + ddcutil --display "$2" setvcp 10 "$new" + fi + +esac diff --git a/dotfiles/.config/quickshell/SidebarApp/BrightnessControls.qml b/dotfiles/.config/quickshell/SidebarApp/BrightnessControls.qml new file mode 100644 index 000000000..c30a761ff --- /dev/null +++ b/dotfiles/.config/quickshell/SidebarApp/BrightnessControls.qml @@ -0,0 +1,118 @@ +import Quickshell +import Quickshell.Io +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import qs.CustomTheme + +ColumnLayout { + id: root + Layout.fillWidth: true + spacing: 20 + + property bool isOpen: false + property int screenCount: 1 + + Process { + id: brightnessDisplays + command: ["bash", "-c", "~/.config/hypr/scripts/brightness.sh displays"] + + running: root.isOpen + + stdout: StdioCollector { + onStreamFinished: { + root.screenCount = parseInt(this.text.trim()); + } + } + } + + Text { + text: "Brightness" // Sun/Brightness icon + color: Theme.primary + font.family: "monospace" + font.pixelSize: 18 + Layout.alignment: Qt.AlignVCenter + } + + Repeater { + model: root.screenCount + + delegate: RowLayout { + Layout.fillWidth: true + spacing: 15 + + Text { + text: "☀ " + color: Theme.primary + font.family: "monospace" + font.pixelSize: 18 + Layout.alignment: Qt.AlignVCenter + } + + Slider { + id: brightnessSlider + Layout.fillWidth: true + from: 0 + to: 100 + value: 50 // Default + + Process { + command: ["bash", "-c", "~/.config/hypr/scripts/brightness.sh get-display " + (index + 1)] + running: root.isOpen + stdout: StdioCollector { + onStreamFinished: { + let v = parseInt(this.text.trim()); + if (!isNaN(v)) + brightnessSlider.value = v; + } + } + } + + Timer { + id: brightnessTimer + interval: 50 // play with the delay if you want to make it more or less responsive, keep in mind that DDC/CI commands can be slow and you don't want to spam them too much + repeat: false + + onTriggered: { + Quickshell.execDetached(["bash", "-c", "~/.config/hypr/scripts/brightness.sh set-display " + (index + 1) + " " + Math.round(brightnessSlider.value)]); + } + } + + onMoved: { + brightnessTimer.restart(); + } + + background: Rectangle { + x: brightnessSlider.leftPadding + y: brightnessSlider.topPadding + brightnessSlider.availableHeight / 2 - height / 2 + implicitWidth: 200 + implicitHeight: 6 + width: brightnessSlider.availableWidth + height: implicitHeight + radius: 3 + color: Theme.background + border.color: Theme.primary + border.width: 1 + + Rectangle { + width: brightnessSlider.visualPosition * parent.width + height: parent.height + color: Theme.primary + radius: 3 + } + } + + handle: Rectangle { + x: brightnessSlider.leftPadding + brightnessSlider.visualPosition * (brightnessSlider.availableWidth - width) + y: brightnessSlider.topPadding + brightnessSlider.availableHeight / 2 - height / 2 + implicitWidth: 16 + implicitHeight: 16 + radius: 8 + color: brightnessSlider.pressed ? Theme.background : Theme.primary + border.color: Theme.primary + border.width: 1 + } + } + } + } +} diff --git a/dotfiles/.config/quickshell/SidebarApp/SidebarWindow.qml b/dotfiles/.config/quickshell/SidebarApp/SidebarWindow.qml index af90e7045..d9c38084f 100644 --- a/dotfiles/.config/quickshell/SidebarApp/SidebarWindow.qml +++ b/dotfiles/.config/quickshell/SidebarApp/SidebarWindow.qml @@ -38,7 +38,7 @@ PanelWindow { active: root.isOpen onCleared: { if (root.isOpen) { - root.isOpen = false + root.isOpen = false; } } } @@ -48,7 +48,7 @@ PanelWindow { sequence: "Escape" onActivated: { if (root.isOpen) { - root.isOpen = false + root.isOpen = false; } } } @@ -57,7 +57,9 @@ PanelWindow { property bool isOpen: false visible: isOpen || slideAnim.running - margins { right: root.currentMargin } + margins { + right: root.currentMargin + } property real currentMargin: isOpen ? 0 : -470 Behavior on currentMargin { @@ -70,9 +72,15 @@ PanelWindow { IpcHandler { target: "sidebar" - function toggle(): void { root.isOpen = !root.isOpen } - function open(): void { root.isOpen = true } - function close(): void { root.isOpen = false } + function toggle(): void { + root.isOpen = !root.isOpen; + } + function open(): void { + root.isOpen = true; + } + function close(): void { + root.isOpen = false; + } } Process { @@ -81,8 +89,8 @@ PanelWindow { stdout: StdioCollector { onStreamFinished: { - console.log(this.text.trim()) - root.isHyprlandSettingsInstalled = (this.text.trim() === "0") + console.log(this.text.trim()); + root.isHyprlandSettingsInstalled = (this.text.trim() === "0"); } } } @@ -142,7 +150,11 @@ PanelWindow { implicitHeight: 22 radius: 11 color: parent.parent.checked ? Theme.background : Theme.on_primary - Behavior on x { NumberAnimation { duration: 150 } } + Behavior on x { + NumberAnimation { + duration: 150 + } + } } } } @@ -150,7 +162,9 @@ PanelWindow { component SettingsWheel: Button { implicitWidth: 28 implicitHeight: 28 - background: Rectangle { color: "transparent" } + background: Rectangle { + color: "transparent" + } contentItem: Item { Image { anchors.centerIn: parent @@ -175,7 +189,9 @@ PanelWindow { property string iconSrc: "" implicitWidth: 28 implicitHeight: 28 - background: Rectangle { color: "transparent" } + background: Rectangle { + color: "transparent" + } contentItem: Item { Text { anchors.centerIn: parent @@ -243,30 +259,37 @@ PanelWindow { ActionIcon { iconSrc: "../shared/icons/darklight.svg" onClicked: { - Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/ml4w/scripts/ml4w-toggle-theme"]) + Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/ml4w/scripts/ml4w-toggle-theme"]); } } ActionIcon { iconSrc: "../shared/icons/picker.svg" onClicked: { - root.isOpen = false - Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/ml4w/settings/hyprpicker.sh"]) + root.isOpen = false; + Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/ml4w/settings/hyprpicker.sh"]); } } ActionIcon { iconSrc: "../shared/icons/screenshot.svg" onClicked: { - root.isOpen = false - Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/hypr/scripts/screenshot.sh"]) + root.isOpen = false; + Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/hypr/scripts/screenshot.sh"]); } } - Item { Layout.fillWidth: true } + Item { + Layout.fillWidth: true + } } - Rectangle { Layout.fillWidth: true; implicitHeight: 1; color: Theme.primary; opacity: 0.3 } + Rectangle { + Layout.fillWidth: true + implicitHeight: 1 + color: Theme.primary + opacity: 0.3 + } // --- THREE BUTTONS ROW --- RowLayout { @@ -276,29 +299,34 @@ PanelWindow { ML4WButton { text: "Welcome" onClicked: { - root.isOpen = false - Quickshell.execDetached(["bash", "-c", "qs ipc call welcome toggle"]) + root.isOpen = false; + Quickshell.execDetached(["bash", "-c", "qs ipc call welcome toggle"]); } } ML4WButton { text: "Settings" onClicked: { - root.isOpen = false + root.isOpen = false; // Quickshell.execDetached(["kitty", "--class", "dotfiles-floating", "-e", "ml4w-dotfiles-settings", "com.ml4w.dotfiles"]) - Quickshell.execDetached(["bash", "-c", "qs -p " + Quickshell.env("HOME") + "/.local/share/ml4w-dotfiles-settings/quickshell ipc call settings toggle"]) + Quickshell.execDetached(["bash", "-c", "qs -p " + Quickshell.env("HOME") + "/.local/share/ml4w-dotfiles-settings/quickshell ipc call settings toggle"]); } } ML4WButton { text: "HyprMod" visible: root.isHyprlandSettingsInstalled onClicked: { - root.isOpen = false - Quickshell.execDetached(["hyprmod"]) + root.isOpen = false; + Quickshell.execDetached(["hyprmod"]); } } } - Rectangle { Layout.fillWidth: true; implicitHeight: 1; color: Theme.primary; opacity: 0.3 } + Rectangle { + Layout.fillWidth: true + implicitHeight: 1 + color: Theme.primary + opacity: 0.3 + } // --- SCROLLABLE CONTENT --- ScrollView { @@ -312,7 +340,9 @@ PanelWindow { policy: ScrollBar.AsNeeded interactive: true contentItem: Rectangle { - implicitWidth: 6; radius: 3; color: Theme.primary + implicitWidth: 6 + radius: 3 + color: Theme.primary opacity: parent.pressed ? 1.0 : (parent.active ? 0.8 : 0.4) } } @@ -327,144 +357,25 @@ PanelWindow { Layout.fillWidth: true spacing: 20 - // LOUDNESS SLIDER - RowLayout { - Layout.fillWidth: true - spacing: 15 - - Text { - text: "" // Speaker icon - color: Theme.primary - font.family: "monospace" - font.pixelSize: 18 - Layout.alignment: Qt.AlignVCenter - } - - Slider { - id: volumeSlider - Layout.fillWidth: true - from: 0 - to: 100 - value: 50 // Default - - Process { - command: ["bash", "-c", "wpctl get-volume @DEFAULT_AUDIO_SINK@ | awk '{print int($2 * 100)}'"] - running: root.isOpen - stdout: StdioCollector { - onStreamFinished: { - let val = parseInt(this.text.trim()) - if (!isNaN(val)) volumeSlider.value = val; - } - } - } - - onMoved: { - Quickshell.execDetached(["bash", "-c", "wpctl set-volume @DEFAULT_AUDIO_SINK@ " + Math.round(value) + "%"]) - } - - background: Rectangle { - x: volumeSlider.leftPadding - y: volumeSlider.topPadding + volumeSlider.availableHeight / 2 - height / 2 - implicitWidth: 200 - implicitHeight: 6 - width: volumeSlider.availableWidth - height: implicitHeight - radius: 3 - color: Theme.background - border.color: Theme.primary - border.width: 1 - - Rectangle { - width: volumeSlider.visualPosition * parent.width - height: parent.height - color: Theme.primary - radius: 3 - } - } - - handle: Rectangle { - x: volumeSlider.leftPadding + volumeSlider.visualPosition * (volumeSlider.availableWidth - width) - y: volumeSlider.topPadding + volumeSlider.availableHeight / 2 - height / 2 - implicitWidth: 16 - implicitHeight: 16 - radius: 8 - color: volumeSlider.pressed ? Theme.background : Theme.primary - border.color: Theme.primary - border.width: 1 - } - } + SoundControls { + id: soundControls + isOpen: root.isOpen } - // BRIGHTNESS SLIDER - RowLayout { - Layout.fillWidth: true - spacing: 15 - - Text { - text: "" // Sun/Brightness icon - color: Theme.primary - font.family: "monospace" - font.pixelSize: 18 - Layout.alignment: Qt.AlignVCenter - } - - Slider { - id: brightnessSlider - Layout.fillWidth: true - from: 10 // Guaranteed Minimum 10% - to: 100 - value: 100 - - Process { - command: ["bash", "-c", "brightnessctl -m | awk -F, '{gsub(\"%\",\"\",$4); print $4}'"] - running: root.isOpen - stdout: StdioCollector { - onStreamFinished: { - let val = parseInt(this.text.trim()) - if (!isNaN(val)) brightnessSlider.value = Math.max(10, val); - } - } - } - - onMoved: { - Quickshell.execDetached(["bash", "-c", "brightnessctl set " + Math.round(value) + "%"]) - } - - background: Rectangle { - x: brightnessSlider.leftPadding - y: brightnessSlider.topPadding + brightnessSlider.availableHeight / 2 - height / 2 - implicitWidth: 200 - implicitHeight: 6 - width: brightnessSlider.availableWidth - height: implicitHeight - radius: 3 - color: Theme.background - border.color: Theme.primary - border.width: 1 - - Rectangle { - width: brightnessSlider.visualPosition * parent.width - height: parent.height - color: Theme.primary - radius: 3 - } - } - - handle: Rectangle { - x: brightnessSlider.leftPadding + brightnessSlider.visualPosition * (brightnessSlider.availableWidth - width) - y: brightnessSlider.topPadding + brightnessSlider.availableHeight / 2 - height / 2 - implicitWidth: 16 - implicitHeight: 16 - radius: 8 - color: brightnessSlider.pressed ? Theme.background : Theme.primary - border.color: Theme.primary - border.width: 1 - } - } + BrightnessControls { + id: brightnessControls + isOpen: root.isOpen } } - Rectangle { Layout.fillWidth: true; implicitHeight: 1; color: Theme.primary; opacity: 0.3; Layout.topMargin: 5; Layout.bottomMargin: 5 } + Rectangle { + Layout.fillWidth: true + implicitHeight: 1 + color: Theme.primary + opacity: 0.3 + Layout.topMargin: 5 + Layout.bottomMargin: 5 + } // --- MPRIS PLAYERS (Scrollable ListView) --- ListView { @@ -489,7 +400,9 @@ PanelWindow { policy: mprisListView.count > 2 ? ScrollBar.AsNeeded : ScrollBar.AlwaysOff interactive: true contentItem: Rectangle { - implicitWidth: 6; radius: 3; color: Theme.primary + implicitWidth: 6 + radius: 3 + color: Theme.primary opacity: parent.pressed ? 1.0 : (parent.active ? 0.8 : 0.4) } } @@ -557,8 +470,10 @@ PanelWindow { Text { Layout.fillWidth: true text: { - if (player.trackArtist) return player.trackArtist; - if (player.trackArtists && player.trackArtists.length > 0) return player.trackArtists[0]; + if (player.trackArtist) + return player.trackArtist; + if (player.trackArtists && player.trackArtists.length > 0) + return player.trackArtists[0]; return "Unknown Artist"; } color: Theme.on_background @@ -568,13 +483,17 @@ PanelWindow { opacity: 0.8 } - Item { Layout.fillHeight: true } + Item { + Layout.fillHeight: true + } RowLayout { Layout.fillWidth: true spacing: 15 - Item { Layout.fillWidth: true } + Item { + Layout.fillWidth: true + } ActionIcon { iconTxt: "󰒮" @@ -597,7 +516,9 @@ PanelWindow { onClicked: player.next() } - Item { Layout.fillWidth: true } + Item { + Layout.fillWidth: true + } } } } @@ -605,12 +526,12 @@ PanelWindow { } Rectangle { - Layout.fillWidth: true; - implicitHeight: 1; - color: Theme.primary; - opacity: 0.3; - Layout.topMargin: 5; - Layout.bottomMargin: 5; + Layout.fillWidth: true + implicitHeight: 1 + color: Theme.primary + opacity: 0.3 + Layout.topMargin: 5 + Layout.bottomMargin: 5 visible: Mpris.players.values.length > 0 } @@ -627,19 +548,18 @@ PanelWindow { running: root.isOpen stdout: StdioCollector { onStreamFinished: { - console.log("Test for Waybar: " + this.text.trim()) - waybarSwitch.checked = (this.text.trim() === "1") - waybarSwitch.ready = true + console.log("Test for Waybar: " + this.text.trim()); + waybarSwitch.checked = (this.text.trim() === "1"); + waybarSwitch.ready = true; } } } onClicked: { - if (!ready) return; - let fileCmd = checked - ? "rm -f ~/.config/ml4w/settings/waybar-disabled" - : "touch ~/.config/ml4w/settings/waybar-disabled" - console.log("Waybar cmd: " + fileCmd) - Quickshell.execDetached(["bash", "-c", fileCmd + ";" + Quickshell.env("HOME") + "/.config/waybar/launch.sh"]) + if (!ready) + return; + let fileCmd = checked ? "rm -f ~/.config/ml4w/settings/waybar-disabled" : "touch ~/.config/ml4w/settings/waybar-disabled"; + console.log("Waybar cmd: " + fileCmd); + Quickshell.execDetached(["bash", "-c", fileCmd + ";" + Quickshell.env("HOME") + "/.config/waybar/launch.sh"]); } } @@ -651,18 +571,29 @@ PanelWindow { implicitWidth: 220 padding: 8 - background: Rectangle { color: Theme.background; border.color: Theme.primary; border.width: 1; radius: 8 } - ML4WMenuItem { text: "Select Waybar Theme"; onClicked: { - Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/waybar/themeswitcher.sh"]) + background: Rectangle { + color: Theme.background + border.color: Theme.primary + border.width: 1 + radius: 8 + } + ML4WMenuItem { + text: "Select Waybar Theme" + onClicked: { + Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/waybar/themeswitcher.sh"]); } } - ML4WMenuItem { text: "Edit Quicklinks"; onClicked: { - root.isOpen = false - Quickshell.execDetached(["gnome-text-editor", Quickshell.env("HOME") + "/.config/ml4w/settings/waybar-quicklinks.json"]) + ML4WMenuItem { + text: "Edit Quicklinks" + onClicked: { + root.isOpen = false; + Quickshell.execDetached(["gnome-text-editor", Quickshell.env("HOME") + "/.config/ml4w/settings/waybar-quicklinks.json"]); } } - ML4WMenuItem { text: "Reload Waybar"; onClicked: { - Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/waybar/launch.sh"]) + ML4WMenuItem { + text: "Reload Waybar" + onClicked: { + Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/waybar/launch.sh"]); } } } @@ -682,22 +613,23 @@ PanelWindow { running: root.isOpen stdout: StdioCollector { onStreamFinished: { - console.log("Test for Dock: " + this.text.trim()) - dockSwitch.checked = (this.text.trim() === "1") - dockSwitch.ready = true + console.log("Test for Dock: " + this.text.trim()); + dockSwitch.checked = (this.text.trim() === "1"); + dockSwitch.ready = true; } } } onClicked: { - if (!ready) return; - let fileCmd = checked - ? "rm -f ~/.config/ml4w/settings/dock-disabled" - : "touch ~/.config/ml4w/settings/dock-disabled" - console.log("Dock cmd: " + fileCmd) - Quickshell.execDetached(["bash", "-c", fileCmd + "; " + Quickshell.env("HOME") + "/.config/nwg-dock-hyprland/launch.sh"]) + if (!ready) + return; + let fileCmd = checked ? "rm -f ~/.config/ml4w/settings/dock-disabled" : "touch ~/.config/ml4w/settings/dock-disabled"; + console.log("Dock cmd: " + fileCmd); + Quickshell.execDetached(["bash", "-c", fileCmd + "; " + Quickshell.env("HOME") + "/.config/nwg-dock-hyprland/launch.sh"]); } } - Item { implicitWidth: 28 } + Item { + implicitWidth: 28 + } } // --- DOCK AUTOHIDE --- @@ -713,22 +645,23 @@ PanelWindow { running: root.isOpen stdout: StdioCollector { onStreamFinished: { - console.log("Test for Dock Autohide: " + this.text.trim()) - dockAutohideSwitch.checked = (this.text.trim() === "1") - dockAutohideSwitch.ready = true + console.log("Test for Dock Autohide: " + this.text.trim()); + dockAutohideSwitch.checked = (this.text.trim() === "1"); + dockAutohideSwitch.ready = true; } } } onClicked: { - if (!ready) return; - let fileCmd = checked - ? "mkdir -p ~/.config/ml4w/settings && touch ~/.config/ml4w/settings/dock-autohide" - : "rm -f ~/.config/ml4w/settings/dock-autohide" - console.log("Dock Autohide cmd: " + fileCmd) - Quickshell.execDetached(["bash", "-c", fileCmd + "; " + Quickshell.env("HOME") + "/.config/nwg-dock-hyprland/launch.sh"]) + if (!ready) + return; + let fileCmd = checked ? "mkdir -p ~/.config/ml4w/settings && touch ~/.config/ml4w/settings/dock-autohide" : "rm -f ~/.config/ml4w/settings/dock-autohide"; + console.log("Dock Autohide cmd: " + fileCmd); + Quickshell.execDetached(["bash", "-c", fileCmd + "; " + Quickshell.env("HOME") + "/.config/nwg-dock-hyprland/launch.sh"]); } } - Item { implicitWidth: 28 } + Item { + implicitWidth: 28 + } } // --- GAMEMODE --- @@ -744,18 +677,21 @@ PanelWindow { running: root.isOpen stdout: StdioCollector { onStreamFinished: { - console.log("Test for Gamemode: " + this.text.trim()) - gamemodeSwitch.checked = (this.text.trim() === "0") - gamemodeSwitch.ready = true + console.log("Test for Gamemode: " + this.text.trim()); + gamemodeSwitch.checked = (this.text.trim() === "0"); + gamemodeSwitch.ready = true; } } } onClicked: { - if (!ready) return; - Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/hypr/scripts/gamemode.sh"]) + if (!ready) + return; + Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/hypr/scripts/gamemode.sh"]); } } - Item { implicitWidth: 28 } + Item { + implicitWidth: 28 + } } // --- FASTFETCH --- @@ -771,21 +707,31 @@ PanelWindow { running: root.isOpen stdout: StdioCollector { onStreamFinished: { - console.log("Test for Fastfetch: " + this.text.trim()) - fastfetchSwitch.checked = (this.text.trim() === "0") - fastfetchSwitch.ready = true + console.log("Test for Fastfetch: " + this.text.trim()); + fastfetchSwitch.checked = (this.text.trim() === "0"); + fastfetchSwitch.ready = true; } } } onClicked: { - if (!ready) return; - Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/ml4w/scripts/ml4w-toggle-fastfetch"]) + if (!ready) + return; + Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/ml4w/scripts/ml4w-toggle-fastfetch"]); } } - Item { implicitWidth: 28 } + Item { + implicitWidth: 28 + } } - Rectangle { Layout.fillWidth: true; implicitHeight: 1; color: Theme.primary; opacity: 0.3; Layout.topMargin: 5; Layout.bottomMargin: 5 } + Rectangle { + Layout.fillWidth: true + implicitHeight: 1 + color: Theme.primary + opacity: 0.3 + Layout.topMargin: 5 + Layout.bottomMargin: 5 + } // --- WALLPAPER --- RowLayout { @@ -795,8 +741,8 @@ PanelWindow { ActionIcon { iconSrc: "../shared/icons/wallpaper.svg" onClicked: { - root.isOpen = false - Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/ml4w/scripts/ml4w-wallpaper-app"]) + root.isOpen = false; + Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/ml4w/scripts/ml4w-wallpaper-app"]); } } } @@ -809,8 +755,8 @@ PanelWindow { ActionIcon { iconSrc: "../shared/icons/theme.svg" onClicked: { - root.isOpen = false - Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/ml4w/themes/themes.sh"]) + root.isOpen = false; + Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/ml4w/themes/themes.sh"]); } } SettingsWheel { @@ -822,20 +768,31 @@ PanelWindow { implicitWidth: 220 padding: 8 - background: Rectangle { color: Theme.background; border.color: Theme.primary; border.width: 1; radius: 8 } - ML4WMenuItem { text: "Set GTK Theme"; onClicked: { - root.isOpen = false - Quickshell.execDetached(["nwg-look"]) + background: Rectangle { + color: Theme.background + border.color: Theme.primary + border.width: 1 + radius: 8 + } + ML4WMenuItem { + text: "Set GTK Theme" + onClicked: { + root.isOpen = false; + Quickshell.execDetached(["nwg-look"]); } } - ML4WMenuItem { text: "Set QT Theme"; onClicked: { - root.isOpen = false - Quickshell.execDetached(["qt6ct"]) + ML4WMenuItem { + text: "Set QT Theme" + onClicked: { + root.isOpen = false; + Quickshell.execDetached(["qt6ct"]); } } - ML4WMenuItem { text: "Refresh GTK Theme"; onClicked: { - root.isOpen = false - Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/hypr/scripts/gtk.sh"]) + ML4WMenuItem { + text: "Refresh GTK Theme" + onClicked: { + root.isOpen = false; + Quickshell.execDetached(["bash", "-c", Quickshell.env("HOME") + "/.config/hypr/scripts/gtk.sh"]); } } } diff --git a/dotfiles/.config/quickshell/SidebarApp/SoundControls.qml b/dotfiles/.config/quickshell/SidebarApp/SoundControls.qml new file mode 100644 index 000000000..7ae17d65d --- /dev/null +++ b/dotfiles/.config/quickshell/SidebarApp/SoundControls.qml @@ -0,0 +1,114 @@ +import Quickshell +import Quickshell.Io +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import qs.CustomTheme + +ColumnLayout { + id: root + Layout.fillWidth: true + spacing: 20 + + property bool isOpen: false + property var soundIds: [] + + Process { + id: soundOutputs + command: ["bash", "-c", "pactl list sinks short | awk '{print $1}'"] + + running: root.isOpen + + stdout: StdioCollector { + onStreamFinished: { + root.soundIds = this.text.trim().split("\n").map(id => parseInt(id)).filter(id => !isNaN(id)); + console.log("Sinks:", root.soundIds); + } + } + } + + ColumnLayout { + Layout.fillWidth: true + spacing: 20 + + Text { + text: "Sound" + color: Theme.primary + font.family: "monospace" + font.pixelSize: 18 + } + + Repeater { + model: root.soundIds + + delegate: RowLayout { + Layout.fillWidth: true + spacing: 15 + + property int sinkId: modelData + + Text { + text: " " //+ sinkId + color: Theme.primary + font.family: "monospace" + font.pixelSize: 18 + } + + Slider { + id: soundSlider + Layout.fillWidth: true + from: 0 + to: 100 + value: 50 + + Process { + command: ["bash", "-c", "pactl get-sink-volume " + sinkId + " | grep -o '[0-9]*%' | head -1 | sed 's/%//'"] + running: root.isOpen + stdout: StdioCollector { + onStreamFinished: { + let v = parseInt(this.text.trim()); + if (!isNaN(v)) + soundSlider.value = v; + } + } + } + + onMoved: { + Quickshell.execDetached(["bash", "-c", "pactl set-sink-volume " + sinkId + " " + Math.round(value) + "%"]); + } + + background: Rectangle { + x: soundSlider.leftPadding + y: soundSlider.topPadding + soundSlider.availableHeight / 2 - height / 2 + implicitWidth: 200 + implicitHeight: 6 + width: soundSlider.availableWidth + height: implicitHeight + radius: 3 + color: Theme.background + border.color: Theme.primary + border.width: 1 + + Rectangle { + width: soundSlider.visualPosition * parent.width + height: parent.height + color: Theme.primary + radius: 3 + } + } + + handle: Rectangle { + x: soundSlider.leftPadding + soundSlider.visualPosition * (soundSlider.availableWidth - width) + y: soundSlider.topPadding + soundSlider.availableHeight / 2 - height / 2 + implicitWidth: 16 + implicitHeight: 16 + radius: 8 + color: soundSlider.pressed ? Theme.background : Theme.primary + border.color: Theme.primary + border.width: 1 + } + } + } + } + } +}