From b35ef9091638a58eec05e259d2d6747ee80f20c7 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 22 Oct 2025 23:56:50 +0200 Subject: [PATCH] add anti flashbang could be improve with smooth fading --- .../quickshell/ii/modules/common/Config.qml | 3 + .../modules/common/widgets/WindowDialog.qml | 2 +- .../nightLight/NightLightDialog.qml | 36 +++++++++- .../quickToggles/AndroidQuickPanel.qml | 5 +- .../quickshell/ii/services/Brightness.qml | 67 ++++++++++++++++++- 5 files changed, 105 insertions(+), 8 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml index 7d5a93ea4..54562da02 100644 --- a/dots/.config/quickshell/ii/modules/common/Config.qml +++ b/dots/.config/quickshell/ii/modules/common/Config.qml @@ -303,6 +303,9 @@ Singleton { property string to: "06:30" // Format: "HH:mm", 24-hour time property int colorTemperature: 5000 } + property JsonObject antiFlashbang: JsonObject { + property bool enable: false + } } property JsonObject lock: JsonObject { diff --git a/dots/.config/quickshell/ii/modules/common/widgets/WindowDialog.qml b/dots/.config/quickshell/ii/modules/common/widgets/WindowDialog.qml index 92f6353e3..a0ca64e98 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/WindowDialog.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/WindowDialog.qml @@ -50,7 +50,7 @@ Rectangle { property real targetY: root.height / 2 - root.backgroundHeight / 2 y: root.show ? targetY : (targetY - root.backgroundAnimationMovementDistance) implicitWidth: 350 - implicitHeight: 0 + implicitHeight: contentColumn.implicitHeight + dialogBackground.radius * 2 Behavior on implicitHeight { NumberAnimation { id: dialogBackgroundHeightAnimation diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/nightLight/NightLightDialog.qml b/dots/.config/quickshell/ii/modules/sidebarRight/nightLight/NightLightDialog.qml index 25fb120f0..535aded59 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/nightLight/NightLightDialog.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/nightLight/NightLightDialog.qml @@ -34,7 +34,6 @@ WindowDialog { id: nightLightColumn Layout.topMargin: -16 Layout.fillWidth: true - Layout.fillHeight: true ConfigSwitch { anchors { @@ -81,6 +80,39 @@ WindowDialog { } } + WindowDialogSectionHeader { + text: Translation.tr("Anti-flashbang (experimental)") + } + + WindowDialogSeparator { + Layout.topMargin: -22 + Layout.leftMargin: 0 + Layout.rightMargin: 0 + } + + Column { + id: antiFlashbangColumn + Layout.topMargin: -16 + Layout.fillWidth: true + + ConfigSwitch { + anchors { + left: parent.left + right: parent.right + } + iconSize: Appearance.font.pixelSize.larger + buttonIcon: "destruction" + text: Translation.tr("Enable") + checked: Config.options.light.antiFlashbang.enable + onCheckedChanged: { + Config.options.light.antiFlashbang.enable = checked; + } + StyledToolTip { + text: Translation.tr("Example use case: eroge on one workspace, dark Discord window on another") + } + } + } + WindowDialogSectionHeader { text: Translation.tr("Brightness") } @@ -95,7 +127,7 @@ WindowDialog { id: brightnessColumn Layout.topMargin: -16 Layout.fillWidth: true - // Layout.fillHeight: true + Layout.fillHeight: true WindowDialogSlider { anchors { diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml index 353107822..a7d743585 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml @@ -79,10 +79,7 @@ AbstractQuickPanel { delegate: ButtonGroup { id: toggleRow required property int index - property var modelData: { - print(JSON.stringify(root.toggleRows[index])) - return root.toggleRows[index] - } + property var modelData: root.toggleRows[index] property int startingIndex: { const rows = root.toggleRows; let sum = 0; diff --git a/dots/.config/quickshell/ii/services/Brightness.qml b/dots/.config/quickshell/ii/services/Brightness.qml index 26c7be6cd..ccc7810e2 100644 --- a/dots/.config/quickshell/ii/services/Brightness.qml +++ b/dots/.config/quickshell/ii/services/Brightness.qml @@ -4,6 +4,8 @@ pragma ComponentBehavior: Bound // From https://github.com/caelestia-dots/shell with modifications. // License: GPLv3 +import qs.modules.common +import qs.modules.common.functions import Quickshell import Quickshell.Io import Quickshell.Hyprland @@ -85,6 +87,8 @@ Singleton { } property int rawMaxBrightness: 100 property real brightness + property real brightnessMultiplier: 1.0 + property real multipliedBrightness: Math.max(0, Math.min(1, brightness * brightnessMultiplier)) property bool ready: false onBrightnessChanged: { @@ -120,7 +124,8 @@ Singleton { } function syncBrightness() { - const rounded = Math.round(monitor.brightness * monitor.rawMaxBrightness); + const brightnessValue = monitor.multipliedBrightness + const rounded = Math.round(brightnessValue * monitor.rawMaxBrightness); setProc.command = isDdc ? ["ddcutil", "-b", busNum, "setvcp", "10", rounded] : ["brightnessctl", "--class", "backlight", "s", rounded, "--quiet"]; setProc.startDetached(); } @@ -131,6 +136,11 @@ Singleton { setTimer.restart(); } + function setBrightnessMultiplier(value: real): void { + monitor.brightnessMultiplier = value; + setTimer.restart(); + } + Component.onCompleted: { initialize(); } @@ -146,6 +156,61 @@ Singleton { BrightnessMonitor {} } + // Anti-flashbang + property string screenshotDir: "/tmp/quickshell/brightness/antiflashbang" + function brightnessMultiplierForLightness(x: real): real { + // 6.600135 + 216.360356 * e^(-0.0811129189x) + // Division by 100 is to normalize to [0, 1] + return (6.600135 + 216.360356 * Math.pow(Math.E, -0.0811129189 * x)) / 100.0; + } + Variants { + model: Quickshell.screens + Scope { + id: screenScope + required property var modelData + property string screenName: modelData.name + property string screenshotPath: `${root.screenshotDir}/screenshot-${screenName}.png` + Connections { + enabled: Config.options.light.antiFlashbang.enable + target: Hyprland + function onRawEvent(event) { + if (["workspacev2"].includes(event.name)) { + screenshotTimer.restart(); + } + } + } + + Timer { + id: screenshotTimer + interval: 700 // This is what I have for a Hyprland ws anim + onTriggered: { + screenshotProc.running = false; + screenshotProc.running = true; + } + } + + Process { + id: screenshotProc + command: ["bash", "-c", + `mkdir -p '${StringUtils.shellSingleQuoteEscape(root.screenshotDir)}'` + + ` && grim -o '${StringUtils.shellSingleQuoteEscape(screenScope.screenName)}' '${StringUtils.shellSingleQuoteEscape(screenScope.screenshotPath)}'` + + ` && magick '${StringUtils.shellSingleQuoteEscape(screenScope.screenshotPath)}' -colorspace Gray -format "%[fx:mean*100]" info:` + ] + stdout: StdioCollector { + id: lightnessCollector + onStreamFinished: { + const lightness = lightnessCollector.text + const newMultiplier = root.brightnessMultiplierForLightness(parseFloat(lightness)) + print(lightness, "->", newMultiplier) + Brightness.getMonitorForScreen(screenScope.modelData).setBrightnessMultiplier(newMultiplier) + } + } + } + } + } + + // External trigger points + IpcHandler { target: "brightness"