From 24163dfa4a328327978a57794f0dfde804c9f6e5 Mon Sep 17 00:00:00 2001 From: Sighthesia <87855491+Sighthesia@users.noreply.github.com> Date: Fri, 3 Oct 2025 01:34:51 +0800 Subject: [PATCH 01/94] bar: fix float bar tint loss --- .config/quickshell/ii/modules/bar/BarContent.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/quickshell/ii/modules/bar/BarContent.qml b/.config/quickshell/ii/modules/bar/BarContent.qml index 7b0a090dc..97447fb4d 100644 --- a/.config/quickshell/ii/modules/bar/BarContent.qml +++ b/.config/quickshell/ii/modules/bar/BarContent.qml @@ -27,7 +27,7 @@ Item { // Bar content region // Background shadow Loader { - active: Config.options.bar.showBackground && Config.options.bar.cornerStyle === 1 + active: false // For bars background color consistency anchors.fill: barBackground sourceComponent: StyledRectangularShadow { anchors.fill: undefined // The loader's anchors act on this, and this should not have any anchor From 31706e27248d25e1df16b77aa170ebb2d01d06d5 Mon Sep 17 00:00:00 2001 From: Sighthesia <87855491+Sighthesia@users.noreply.github.com> Date: Sun, 5 Oct 2025 17:42:25 +0800 Subject: [PATCH 02/94] config: add floatSytleShadow option --- .config/quickshell/ii/modules/common/Config.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/.config/quickshell/ii/modules/common/Config.qml b/.config/quickshell/ii/modules/common/Config.qml index 00e0afd2a..13155d362 100644 --- a/.config/quickshell/ii/modules/common/Config.qml +++ b/.config/quickshell/ii/modules/common/Config.qml @@ -155,6 +155,7 @@ Singleton { } property bool bottom: false // Instead of top property int cornerStyle: 0 // 0: Hug | 1: Float | 2: Plain rectangle + property bool floatStyleShadow: true // Show shadow behind bar when cornerStyle == 1 (Float) property bool borderless: false // true for no grouping of items property string topLeftIcon: "spark" // Options: "distro" or any icon name in ~/.config/quickshell/ii/assets/icons property bool showBackground: true From c1fa902189e4e195ecf51bf5659ed0c866163428 Mon Sep 17 00:00:00 2001 From: Sighthesia <87855491+Sighthesia@users.noreply.github.com> Date: Sun, 5 Oct 2025 17:48:01 +0800 Subject: [PATCH 03/94] bar: change shadow to configurable --- .config/quickshell/ii/modules/bar/BarContent.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/quickshell/ii/modules/bar/BarContent.qml b/.config/quickshell/ii/modules/bar/BarContent.qml index 97447fb4d..9e452f65a 100644 --- a/.config/quickshell/ii/modules/bar/BarContent.qml +++ b/.config/quickshell/ii/modules/bar/BarContent.qml @@ -27,7 +27,7 @@ Item { // Bar content region // Background shadow Loader { - active: false // For bars background color consistency + active: Config.options.bar.showBackground && Config.options.bar.cornerStyle === 1 && Config.options.bar.floatShadow anchors.fill: barBackground sourceComponent: StyledRectangularShadow { anchors.fill: undefined // The loader's anchors act on this, and this should not have any anchor From 3b3be4b6cb102f55f375a7ac20057cc1d06631cf Mon Sep 17 00:00:00 2001 From: Sighthesia <87855491+Sighthesia@users.noreply.github.com> Date: Sun, 5 Oct 2025 17:52:23 +0800 Subject: [PATCH 04/94] fix error option name --- .config/quickshell/ii/modules/bar/BarContent.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/quickshell/ii/modules/bar/BarContent.qml b/.config/quickshell/ii/modules/bar/BarContent.qml index 9e452f65a..111aa77e0 100644 --- a/.config/quickshell/ii/modules/bar/BarContent.qml +++ b/.config/quickshell/ii/modules/bar/BarContent.qml @@ -27,7 +27,7 @@ Item { // Bar content region // Background shadow Loader { - active: Config.options.bar.showBackground && Config.options.bar.cornerStyle === 1 && Config.options.bar.floatShadow + active: Config.options.bar.showBackground && Config.options.bar.cornerStyle === 1 && Config.options.bar.floatStyleShadow anchors.fill: barBackground sourceComponent: StyledRectangularShadow { anchors.fill: undefined // The loader's anchors act on this, and this should not have any anchor From 60f055f07d9793314091bb56fbe94187d96bc884 Mon Sep 17 00:00:00 2001 From: vaguesyntax Date: Sun, 26 Oct 2025 02:46:39 +0300 Subject: [PATCH 05/94] initial commit of musicRecognition --- .../quickshell/ii/modules/common/Config.qml | 1 + .../common/widgets/notification_utils.js | 3 + .../ii/modules/settings/ServicesConfig.qml | 11 +++ .../quickToggles/AndroidQuickPanel.qml | 2 +- .../androidStyle/AndroidEasyEffectsToggle.qml | 2 +- .../androidStyle/AndroidMusicRecognition.qml | 77 +++++++++++++++++++ .../AndroidToggleDelegateChooser.qml | 13 ++++ .../musicRecognition/musicRecognition.sh | 43 +++++++++++ 8 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml create mode 100755 dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml index f496f7bab..83fda7cee 100644 --- a/dots/.config/quickshell/ii/modules/common/Config.qml +++ b/dots/.config/quickshell/ii/modules/common/Config.qml @@ -374,6 +374,7 @@ Singleton { property JsonObject resources: JsonObject { property int updateInterval: 3000 + property int musicRecognitionTimeout: 16 } property JsonObject search: JsonObject { diff --git a/dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js b/dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js index 7ab21c3bb..fb32a5d51 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js +++ b/dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js @@ -17,13 +17,16 @@ function findSuitableMaterialSymbol(summary = "") { 'time': 'scheduleb', 'installed': 'download', 'configuration reloaded': 'reset_wrench', + 'unable': 'indeterminate_question_box', 'config': 'reset_wrench', 'update': 'update', 'ai response': 'neurology', 'control': 'settings', 'upsca': 'compare', + 'music': 'music_note', 'install': 'deployed_code_update', 'startswith:file': 'folder_copy', // Declarative startsWith check + }; const lowerSummary = summary.toLowerCase(); diff --git a/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml b/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml index fae5bf4de..64c015ff2 100644 --- a/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml @@ -54,6 +54,17 @@ ContentPage { Config.options.resources.updateInterval = value; } } + ConfigSpinBox { + icon: "timer_off" + text: Translation.tr("Music recognition timeout (s)") + value: Config.options.resources.musicRecognitionTimeout + from: 2 + to: 100 + stepSize: 2 + onValueChanged: { + Config.options.resources.musicRecognitionTimeout = value; + } + } } ContentSection { diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml index a7d743585..5d450adec 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml @@ -29,7 +29,7 @@ AbstractQuickPanel { readonly property real baseCellHeight: 56 // Toggles - readonly property list availableToggleTypes: ["network", "bluetooth", "idleInhibitor", "easyEffects", "nightLight", "darkMode", "cloudflareWarp", "gameMode", "screenSnip", "colorPicker", "onScreenKeyboard", "mic", "audio", "notifications", "powerProfile"] + readonly property list availableToggleTypes: ["network", "bluetooth", "idleInhibitor", "easyEffects", "nightLight", "darkMode", "cloudflareWarp", "gameMode", "screenSnip", "colorPicker", "onScreenKeyboard", "mic", "audio", "notifications", "powerProfile","musicrecognition"] readonly property int columns: Config.options.sidebar.quickToggles.android.columns readonly property list toggles: Config.ready ? Config.options.sidebar.quickToggles.android.toggles : [] readonly property list toggleRows: toggleRowsForList(toggles) diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml index c907abf77..86605becd 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml @@ -10,7 +10,7 @@ AndroidQuickToggleButton { name: Translation.tr("EasyEffects") toggled: EasyEffects.active - buttonIcon: "graphic_eq" + buttonIcon: "instant_mix" Component.onCompleted: { EasyEffects.fetchActiveState() diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml new file mode 100644 index 000000000..30487453d --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml @@ -0,0 +1,77 @@ +import qs +import qs.modules.common +import qs.modules.common.widgets +import QtQuick +import Quickshell +import Quickshell.Io +import qs.services + + +AndroidQuickToggleButton { + id: root + + property int timeoutInterval: 5 + property int timeoutDuration: Config.options.resources.musicRecognitionTimeout + property string resultsJSON + + property string recognizedTrackTitle + property string recognizedTrackSubtitle + property string recognizedTrackURL + + name: Translation.tr("Identify Music") + statusText: toggled ? Translation.tr("Listening...") : Translation.tr("Inactive") + toggled: false + buttonIcon: toggled ? "cadence" : "graphic_eq" + onClicked: { + if (!toggled){ + recognizeMusicProc.running = true + } else { + recognizeMusicProc.running = false + } + + root.toggled = !root.toggled + } + + Process { + id: recognizeMusicProc + running: false + command: [`${Directories.scriptPath}/musicRecognition/musicRecognition.sh`, "-i", root.timeoutInterval, "-t", root.timeoutDuration] + stdout: StdioCollector { + onStreamFinished: { + root.resultsJSON = this.text + if (this.text.length < 100) { + Quickshell.execDetached(["notify-send", "No music recognized", "Please make sure your music is playing and try again", "-a", "Shell"]) + toggled = false + return + } + var obj = JSON.parse(root.resultsJSON) + root.recognizedTrackTitle = obj.track.title + root.recognizedTrackSubtitle = obj.track.subtitle + root.recognizedTrackURL = obj.track.url + musicReconizedProc.running = true + toggled = false + } + } + } + + + Process { + id: musicReconizedProc + running: false + command: [ "notify-send" , "Music Recognized" , root.recognizedTrackTitle + " by " + root.recognizedTrackSubtitle , "-A" , "Shazam Link" , "-a" , "Shell"] + stdout: StdioCollector { + onStreamFinished: { + if (this.text !== ""){ + Qt.openUrlExternally(root.recognizedTrackURL); + } + } + } + } + + + + StyledToolTip { + //text: Translation.tr("Identifies the song that’s playing right now") + text: "Identifies the song that’s playing right now" + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml index a8f79c843..b97243d6b 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml @@ -232,4 +232,17 @@ DelegateChooser { cellSize: modelData.size } } + DelegateChoice { roleValue: "musicrecognition"; AndroidMusicRecognition { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + } } + } diff --git a/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh b/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh new file mode 100755 index 000000000..6bb671d5a --- /dev/null +++ b/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +MONITOR_SOURCE="alsa_output.pci-0000_00_1f.3.analog-stereo.monitor" + +# Default değerler +INTERVAL=5 +TOTAL_DURATION=30 + +# Parametreleri oku +while getopts "i:t:" opt; do + case $opt in + i) INTERVAL=$OPTARG ;; + t) TOTAL_DURATION=$OPTARG ;; + *) echo "Usage: $0 [-i interval_seconds] [-t total_duration_seconds]" + exit 1 ;; + esac +done + +START_TIME=$(date +%s) + +while true; do + CURRENT_TIME=$(date +%s) + ELAPSED=$((CURRENT_TIME - START_TIME)) + + if (( ELAPSED >= TOTAL_DURATION )); then + echo "Total duration reached. Exiting." + exit 0 + fi + + TMP_FILE=$(mktemp /tmp/recording.XXXXXX.wav) + + parec --device="$MONITOR_SOURCE" --format=s16le --rate=44100 --channels=2 \ + > >(ffmpeg -f s16le -ar 44100 -ac 2 -i - -t $INTERVAL -acodec libmp3lame "$TMP_FILE" -y -hide_banner -loglevel error) \ + 2>/dev/null + + RESULT=$(songrec audio-file-to-recognized-song "$TMP_FILE" 2>/dev/null || true) + rm -f "$TMP_FILE" + + if [ -n "$RESULT" ] && [ ${#RESULT} -gt 300 ]; then + echo "$RESULT" + exit 0 + fi +done From cf159f611283b71c7708c4263e43e4dfd774c43b Mon Sep 17 00:00:00 2001 From: vaguesyntax Date: Sun, 26 Oct 2025 03:45:43 +0300 Subject: [PATCH 06/94] some typos --- .../ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml | 2 +- .../quickToggles/androidStyle/AndroidMusicRecognition.qml | 2 +- .../quickToggles/androidStyle/AndroidToggleDelegateChooser.qml | 2 +- .../quickshell/ii/scripts/musicRecognition/musicRecognition.sh | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml index 5d450adec..b5e49d3b0 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml @@ -29,7 +29,7 @@ AbstractQuickPanel { readonly property real baseCellHeight: 56 // Toggles - readonly property list availableToggleTypes: ["network", "bluetooth", "idleInhibitor", "easyEffects", "nightLight", "darkMode", "cloudflareWarp", "gameMode", "screenSnip", "colorPicker", "onScreenKeyboard", "mic", "audio", "notifications", "powerProfile","musicrecognition"] + readonly property list availableToggleTypes: ["network", "bluetooth", "idleInhibitor", "easyEffects", "nightLight", "darkMode", "cloudflareWarp", "gameMode", "screenSnip", "colorPicker", "onScreenKeyboard", "mic", "audio", "notifications", "powerProfile","musicRecognition"] readonly property int columns: Config.options.sidebar.quickToggles.android.columns readonly property list toggles: Config.ready ? Config.options.sidebar.quickToggles.android.toggles : [] readonly property list toggleRows: toggleRowsForList(toggles) diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml index 30487453d..a472093e6 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml @@ -40,7 +40,7 @@ AndroidQuickToggleButton { onStreamFinished: { root.resultsJSON = this.text if (this.text.length < 100) { - Quickshell.execDetached(["notify-send", "No music recognized", "Please make sure your music is playing and try again", "-a", "Shell"]) + Quickshell.execDetached(["notify-send", "Unable to recognize music", "Please make sure your music is playing and try again", "-a", "Shell"]) toggled = false return } diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml index b97243d6b..aa5356e2e 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml @@ -232,7 +232,7 @@ DelegateChooser { cellSize: modelData.size } } - DelegateChoice { roleValue: "musicrecognition"; AndroidMusicRecognition { + DelegateChoice { roleValue: "musicRecognition"; AndroidMusicRecognition { required property int index required property var modelData buttonIndex: root.startingIndex + index diff --git a/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh b/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh index 6bb671d5a..671688cbd 100755 --- a/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh +++ b/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh @@ -6,7 +6,6 @@ MONITOR_SOURCE="alsa_output.pci-0000_00_1f.3.analog-stereo.monitor" INTERVAL=5 TOTAL_DURATION=30 -# Parametreleri oku while getopts "i:t:" opt; do case $opt in i) INTERVAL=$OPTARG ;; From b137feac16e838c254686badcfd20bd90d9a887e Mon Sep 17 00:00:00 2001 From: vaguesyntax Date: Sun, 26 Oct 2025 12:24:35 +0300 Subject: [PATCH 07/94] fix: recognized notif not getting pushed --- .../androidStyle/AndroidMusicRecognition.qml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml index a472093e6..924ec936c 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml @@ -49,6 +49,7 @@ AndroidQuickToggleButton { root.recognizedTrackSubtitle = obj.track.subtitle root.recognizedTrackURL = obj.track.url musicReconizedProc.running = true + recognizedMusicKiller.running = true toggled = false } } @@ -68,10 +69,14 @@ AndroidQuickToggleButton { } } - + Timer { + id: recognizedMusicKiller + running: false; repeat: false + interval: 5000 + onTriggered: musicReconizedProc.running = false + } StyledToolTip { - //text: Translation.tr("Identifies the song that’s playing right now") - text: "Identifies the song that’s playing right now" + text: Translation.tr("Identifies the song that’s playing right now") } } From 496225ab9d4767e78b3d96b8b847db42c7ece2a9 Mon Sep 17 00:00:00 2001 From: vaguesyntax Date: Sun, 26 Oct 2025 14:04:52 +0300 Subject: [PATCH 08/94] refactor code --- .../androidStyle/AndroidMusicRecognition.qml | 75 +++++++++---------- .../musicRecognition/musicRecognition.sh | 9 ++- 2 files changed, 40 insertions(+), 44 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml index 924ec936c..c3aeff1a6 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml @@ -12,24 +12,37 @@ AndroidQuickToggleButton { property int timeoutInterval: 5 property int timeoutDuration: Config.options.resources.musicRecognitionTimeout - property string resultsJSON - - property string recognizedTrackTitle - property string recognizedTrackSubtitle - property string recognizedTrackURL - name: Translation.tr("Identify Music") - statusText: toggled ? Translation.tr("Listening...") : Translation.tr("Inactive") + statusText: toggled ? Translation.tr("Listening...") : Translation.tr("Inactive") toggled: false buttonIcon: toggled ? "cadence" : "graphic_eq" - onClicked: { - if (!toggled){ - recognizeMusicProc.running = true - } else { - recognizeMusicProc.running = false + + property var recognizedTrack: ({ title:"", subtitle:"", url:""}) + + function handleRecognition(jsonText) { + try { + var obj = JSON.parse(jsonText) + root.recognizedTrack = { + title: obj.track.title, + subtitle: obj.track.subtitle, + url: obj.track.url + } + musicReconizedProc.running = true + } catch(e) { + Quickshell.execDetached(["notify-send", "Unable to recognize music", "Please make sure your music is playing and try again", "-a", "Shell"]) + } finally { + root.toggled = false } - + } + + StyledToolTip { + text: Translation.tr("Identifies the song that’s currently playing") + } + + onClicked: { root.toggled = !root.toggled + recognizeMusicProc.running = root.toggled + musicReconizedProc.running = false } Process { @@ -38,45 +51,27 @@ AndroidQuickToggleButton { command: [`${Directories.scriptPath}/musicRecognition/musicRecognition.sh`, "-i", root.timeoutInterval, "-t", root.timeoutDuration] stdout: StdioCollector { onStreamFinished: { - root.resultsJSON = this.text - if (this.text.length < 100) { - Quickshell.execDetached(["notify-send", "Unable to recognize music", "Please make sure your music is playing and try again", "-a", "Shell"]) - toggled = false - return - } - var obj = JSON.parse(root.resultsJSON) - root.recognizedTrackTitle = obj.track.title - root.recognizedTrackSubtitle = obj.track.subtitle - root.recognizedTrackURL = obj.track.url - musicReconizedProc.running = true - recognizedMusicKiller.running = true - toggled = false + handleRecognition(this.text) } } } - Process { id: musicReconizedProc running: false - command: [ "notify-send" , "Music Recognized" , root.recognizedTrackTitle + " by " + root.recognizedTrackSubtitle , "-A" , "Shazam Link" , "-a" , "Shell"] + command: [ + "notify-send", + Translation.tr("Music Recognized"), + root.recognizedTrack.title + " - " + root.recognizedTrack.subtitle, + "-A", "Shazam", + "-a", "Shell" + ] stdout: StdioCollector { onStreamFinished: { if (this.text !== ""){ - Qt.openUrlExternally(root.recognizedTrackURL); + Qt.openUrlExternally(root.recognizedTrack.url); } } } } - - Timer { - id: recognizedMusicKiller - running: false; repeat: false - interval: 5000 - onTriggered: musicReconizedProc.running = false - } - - StyledToolTip { - text: Translation.tr("Identifies the song that’s playing right now") - } } diff --git a/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh b/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh index 671688cbd..810635814 100755 --- a/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh +++ b/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh @@ -1,10 +1,11 @@ #!/bin/bash -MONITOR_SOURCE="alsa_output.pci-0000_00_1f.3.analog-stereo.monitor" +## can be added manually if not chosen automatically with running this on terminal 'pw-cli list-objects | grep node.name' +MONITOR_SOURCE=$(pactl list short sources 2>/dev/null | grep -m1 monitor | awk '{print $2}' || true) -# Default değerler INTERVAL=5 TOTAL_DURATION=30 +MIN_VALID_RESULT_LENGTH=300 while getopts "i:t:" opt; do case $opt in @@ -22,7 +23,7 @@ while true; do ELAPSED=$((CURRENT_TIME - START_TIME)) if (( ELAPSED >= TOTAL_DURATION )); then - echo "Total duration reached. Exiting." + echo "Total duration reached, no music recognized." exit 0 fi @@ -35,7 +36,7 @@ while true; do RESULT=$(songrec audio-file-to-recognized-song "$TMP_FILE" 2>/dev/null || true) rm -f "$TMP_FILE" - if [ -n "$RESULT" ] && [ ${#RESULT} -gt 300 ]; then + if [ -n "$RESULT" ] && [ ${#RESULT} -gt $MIN_VALID_RESULT_LENGTH ]; then echo "$RESULT" exit 0 fi From a05b041d691bb89482cdf7b17fd3fdd95ad80bc1 Mon Sep 17 00:00:00 2001 From: vaguesyntax Date: Sun, 26 Oct 2025 14:12:04 +0300 Subject: [PATCH 09/94] fixes and youtube button --- .../ii/modules/common/widgets/notification_utils.js | 2 +- .../quickToggles/androidStyle/AndroidMusicRecognition.qml | 8 ++++++-- .../ii/scripts/musicRecognition/musicRecognition.sh | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js b/dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js index fb32a5d51..dbdeebde9 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js +++ b/dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js @@ -23,7 +23,7 @@ function findSuitableMaterialSymbol(summary = "") { 'ai response': 'neurology', 'control': 'settings', 'upsca': 'compare', - 'music': 'music_note', + 'music': 'queue_music', 'install': 'deployed_code_update', 'startswith:file': 'folder_copy', // Declarative startsWith check diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml index c3aeff1a6..57efb17e7 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml @@ -29,7 +29,7 @@ AndroidQuickToggleButton { } musicReconizedProc.running = true } catch(e) { - Quickshell.execDetached(["notify-send", "Unable to recognize music", "Please make sure your music is playing and try again", "-a", "Shell"]) + Quickshell.execDetached(["notify-send", Translation.tr("Unable to recognize music"), Translation.tr("Please make sure your music is playing and try again"), "-a", "Shell"]) } finally { root.toggled = false } @@ -64,12 +64,16 @@ AndroidQuickToggleButton { Translation.tr("Music Recognized"), root.recognizedTrack.title + " - " + root.recognizedTrack.subtitle, "-A", "Shazam", + "-A", "YouTube", "-a", "Shell" ] stdout: StdioCollector { onStreamFinished: { - if (this.text !== ""){ + if (this.text === "") return + if (this.text == 0){ Qt.openUrlExternally(root.recognizedTrack.url); + } else { + Qt.openUrlExternally("https://www.youtube.com/results?search_query=" + root.recognizedTrack.title + " - " + root.recognizedTrack.subtitle); } } } diff --git a/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh b/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh index 810635814..fb805b4ac 100755 --- a/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh +++ b/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh @@ -1,6 +1,6 @@ #!/bin/bash -## can be added manually if not chosen automatically with running this on terminal 'pw-cli list-objects | grep node.name' +## can be added manually if not chosen automatically with running this on terminal 'pw-cli list-objects | grep node.name' and manually choose the one you want. MONITOR_SOURCE=$(pactl list short sources 2>/dev/null | grep -m1 monitor | awk '{print $2}' || true) INTERVAL=5 From 28e956e55c193ff6015bfc0ad8e3cf1dc5cad247 Mon Sep 17 00:00:00 2001 From: vaguesyntax Date: Sun, 26 Oct 2025 16:00:49 +0300 Subject: [PATCH 10/94] togglable monitor-source --- .../androidStyle/AndroidMusicRecognition.qml | 19 ++++++++++++++--- .../musicRecognition/musicRecognition.sh | 21 +++++++++++++------ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml index 57efb17e7..e674660b3 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml @@ -12,8 +12,11 @@ AndroidQuickToggleButton { property int timeoutInterval: 5 property int timeoutDuration: Config.options.resources.musicRecognitionTimeout + + property string monitorSource: "monitor" // "monitor" (system sound) , "input" (microphone) + name: Translation.tr("Identify Music") - statusText: toggled ? Translation.tr("Listening...") : Translation.tr("Inactive") + statusText: toggled ? Translation.tr("Listening...") : monitorSource === "monitor" ? Translation.tr("System sound") : Translation.tr("Microphone") toggled: false buttonIcon: toggled ? "cadence" : "graphic_eq" @@ -34,9 +37,10 @@ AndroidQuickToggleButton { root.toggled = false } } + StyledToolTip { - text: Translation.tr("Identifies the song that’s currently playing") + text: Translation.tr("Identifies currently playing song | Right-click to change monitor source") } onClicked: { @@ -44,11 +48,20 @@ AndroidQuickToggleButton { recognizeMusicProc.running = root.toggled musicReconizedProc.running = false } + altAction: () => { + if (root.monitorSource === "monitor"){ + root.monitorSource = "input" + return + }else { + root.monitorSource = "monitor" + } + + } Process { id: recognizeMusicProc running: false - command: [`${Directories.scriptPath}/musicRecognition/musicRecognition.sh`, "-i", root.timeoutInterval, "-t", root.timeoutDuration] + command: [`${Directories.scriptPath}/musicRecognition/musicRecognition.sh`, "-i", root.timeoutInterval, "-t", root.timeoutDuration, "-s", root.monitorSource] stdout: StdioCollector { onStreamFinished: { handleRecognition(this.text) diff --git a/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh b/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh index fb805b4ac..f0b7c20a3 100755 --- a/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh +++ b/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh @@ -1,21 +1,30 @@ #!/bin/bash -## can be added manually if not chosen automatically with running this on terminal 'pw-cli list-objects | grep node.name' and manually choose the one you want. -MONITOR_SOURCE=$(pactl list short sources 2>/dev/null | grep -m1 monitor | awk '{print $2}' || true) - INTERVAL=5 TOTAL_DURATION=30 -MIN_VALID_RESULT_LENGTH=300 +MIN_VALID_RESULT_LENGTH=300 +SOURCE_TYPE="monitor" # default | "monitor" : system_sound , "input" : microphone -while getopts "i:t:" opt; do +while getopts "i:t:s:" opt; do case $opt in i) INTERVAL=$OPTARG ;; t) TOTAL_DURATION=$OPTARG ;; - *) echo "Usage: $0 [-i interval_seconds] [-t total_duration_seconds]" + s) SOURCE_TYPE=$OPTARG ;; + *) echo "Usage: $0 [-i interval_seconds] [-t total_duration_seconds] [-s monitor|input]" exit 1 ;; esac done +# Kaynağı belirle +if [ "$SOURCE_TYPE" = "monitor" ]; then + MONITOR_SOURCE=$(pactl list short sources 2>/dev/null | grep -m1 monitor | awk '{print $2}' || true) +elif [ "$SOURCE_TYPE" = "input" ]; then + MONITOR_SOURCE=$(pactl info | grep "Default Source:" | awk '{print $3}' || true) +else + echo "Invalid source type: $SOURCE_TYPE. Use 'monitor' or 'input'." + exit 1 +fi + START_TIME=$(date +%s) while true; do From 53998cc51ad4aa84dfb21928a84b7f536edafd07 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 26 Oct 2025 15:44:48 +0100 Subject: [PATCH 11/94] region selector: fix fab button color --- dots/.config/quickshell/ii/modules/common/Appearance.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dots/.config/quickshell/ii/modules/common/Appearance.qml b/dots/.config/quickshell/ii/modules/common/Appearance.qml index f4b42cac0..8a0446f0e 100644 --- a/dots/.config/quickshell/ii/modules/common/Appearance.qml +++ b/dots/.config/quickshell/ii/modules/common/Appearance.qml @@ -159,6 +159,8 @@ Singleton { property color colTertiaryContainer: m3colors.m3tertiaryContainer property color colTertiaryContainerHover: ColorUtils.mix(m3colors.m3tertiaryContainer, m3colors.m3onTertiaryContainer, 0.90) property color colTertiaryContainerActive: ColorUtils.mix(m3colors.m3tertiaryContainer, colLayer1Active, 0.54) + property color colOnTertiary: m3colors.m3onTertiary + property color colOnTertiaryContainer: m3colors.m3onTertiaryContainer property color colOnSecondaryContainer: m3colors.m3onSecondaryContainer property color colSurfaceContainerLow: ColorUtils.transparentize(m3colors.m3surfaceContainerLow, root.contentTransparency) property color colSurfaceContainer: ColorUtils.transparentize(m3colors.m3surfaceContainer, root.contentTransparency) From 7c5740a39b678c4a103f9743bb7ff6e3ce48db5b Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 26 Oct 2025 15:45:07 +0100 Subject: [PATCH 12/94] use quickshell region selector for recording --- dots/.config/hypr/hyprland/keybinds.conf | 7 +- dots/.config/hypr/hyprland/scripts/record.sh | 42 ----------- .../quickshell/ii/modules/bar/UtilButtons.qml | 2 +- .../ii/modules/common/Directories.qml | 1 + .../modules/regionSelector/OptionsToolbar.qml | 3 + .../regionSelector/RegionSelection.qml | 41 +++++++++-- .../modules/regionSelector/RegionSelector.qml | 29 +++++++- .../quickshell/ii/scripts/videos/record.sh | 69 +++++++++++++++++++ 8 files changed, 143 insertions(+), 51 deletions(-) delete mode 100755 dots/.config/hypr/hyprland/scripts/record.sh create mode 100755 dots/.config/quickshell/ii/scripts/videos/record.sh diff --git a/dots/.config/hypr/hyprland/keybinds.conf b/dots/.config/hypr/hyprland/keybinds.conf index 60bca72af..b48daf625 100644 --- a/dots/.config/hypr/hyprland/keybinds.conf +++ b/dots/.config/hypr/hyprland/keybinds.conf @@ -73,9 +73,10 @@ bindd = Super+Shift, C, Color picker, exec, hyprpicker -a # Pick color (Hex) >> bindld = ,Print, Screenshot >> clipboard ,exec,grim - | wl-copy # Screenshot >> clipboard bindld = Ctrl,Print, Screenshot >> clipboard & save, exec, mkdir -p $(xdg-user-dir PICTURES)/Screenshots && grim $(xdg-user-dir PICTURES)/Screenshots/Screenshot_"$(date '+%Y-%m-%d_%H.%M.%S')".png # Screenshot >> clipboard & file # Recording stuff -bindl = Super+Alt, R, exec, ~/.config/hypr/hyprland/scripts/record.sh # Record region (no sound) -bindl = Ctrl+Alt, R, exec, ~/.config/hypr/hyprland/scripts/record.sh --fullscreen # [hidden] Record screen (no sound) -bindl = Super+Shift+Alt, R, exec, ~/.config/hypr/hyprland/scripts/record.sh --fullscreen-sound # Record screen (with sound) +bindl = Super+Alt, R, global, quickshell:regionRecord # Record region (no sound) +bindl = Super+Alt, R, exec, qs -c $qsConfig ipc call TEST_ALIVE || ~/.config/quickshell/$qsConfig/scripts/videos/record.sh # [hidden] Record region (no sound) (fallback) +bindl = Ctrl+Alt, R, exec, ~/.config/quickshell/$qsConfig/scripts/videos/record.sh --fullscreen # [hidden] Record screen (no sound) +bindl = Super+Shift+Alt, R, exec, ~/.config/quickshell/$qsConfig/scripts/videos/record.sh --fullscreen --sound # Record screen (with sound) # AI bindd = Super+Shift+Alt, mouse:273, Generate AI summary for selected text, exec, ~/.config/hypr/hyprland/scripts/ai/primary-buffer-query.sh # AI summary for selected text diff --git a/dots/.config/hypr/hyprland/scripts/record.sh b/dots/.config/hypr/hyprland/scripts/record.sh deleted file mode 100755 index 37435ac15..000000000 --- a/dots/.config/hypr/hyprland/scripts/record.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash - -getdate() { - date '+%Y-%m-%d_%H.%M.%S' -} -getaudiooutput() { - pactl list sources | grep 'Name' | grep 'monitor' | cut -d ' ' -f2 -} -getactivemonitor() { - hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .name' -} - -xdgvideo="$(xdg-user-dir VIDEOS)" -if [[ $xdgvideo = "$HOME" ]]; then - unset xdgvideo -fi -mkdir -p "${xdgvideo:-$HOME/Videos}" -cd "${xdgvideo:-$HOME/Videos}" || exit - -if pgrep wf-recorder > /dev/null; then - notify-send "Recording Stopped" "Stopped" -a 'Recorder' & - pkill wf-recorder & -else - if [[ "$1" == "--fullscreen-sound" ]]; then - notify-send "Starting recording" 'recording_'"$(getdate)"'.mp4' -a 'Recorder' & disown - wf-recorder -o "$(getactivemonitor)" --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --audio="$(getaudiooutput)" - elif [[ "$1" == "--fullscreen" ]]; then - notify-send "Starting recording" 'recording_'"$(getdate)"'.mp4' -a 'Recorder' & disown - wf-recorder -o "$(getactivemonitor)" --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t - else - if ! region="$(slurp 2>&1)"; then - notify-send "Recording cancelled" "Selection was cancelled" -a 'Recorder' & disown - exit 1 - fi - notify-send "Starting recording" 'recording_'"$(getdate)"'.mp4' -a 'Recorder' & disown - if [[ "$1" == "--sound" ]]; then - wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --geometry "$region" --audio="$(getaudiooutput)" - else - wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --geometry "$region" - fi - fi -fi diff --git a/dots/.config/quickshell/ii/modules/bar/UtilButtons.qml b/dots/.config/quickshell/ii/modules/bar/UtilButtons.qml index d7f73a4e3..cc3eb64a2 100644 --- a/dots/.config/quickshell/ii/modules/bar/UtilButtons.qml +++ b/dots/.config/quickshell/ii/modules/bar/UtilButtons.qml @@ -41,7 +41,7 @@ Item { visible: Config.options.bar.utilButtons.showScreenRecord sourceComponent: CircleUtilButton { Layout.alignment: Qt.AlignVCenter - onClicked: Quickshell.execDetached(["bash", "-c", "~/.config/hypr/hyprland/scripts/record.sh"]) + onClicked: Quickshell.execDetached([Directories.recordScriptPath]) MaterialSymbol { horizontalAlignment: Qt.AlignHCenter fill: 1 diff --git a/dots/.config/quickshell/ii/modules/common/Directories.qml b/dots/.config/quickshell/ii/modules/common/Directories.qml index 94821e857..411ed6c7f 100644 --- a/dots/.config/quickshell/ii/modules/common/Directories.qml +++ b/dots/.config/quickshell/ii/modules/common/Directories.qml @@ -42,6 +42,7 @@ Singleton { property string userAiPrompts: FileUtils.trimFileProtocol(`${Directories.shellConfig}/ai/prompts`) property string aiChats: FileUtils.trimFileProtocol(`${Directories.state}/user/ai/chats`) property string aiTranslationScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/ai/gemini-translate.sh`) + property string recordScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/videos/record.sh`) // Cleanup on init Component.onCompleted: { Quickshell.execDetached(["mkdir", "-p", `${shellConfig}`]) diff --git a/dots/.config/quickshell/ii/modules/regionSelector/OptionsToolbar.qml b/dots/.config/quickshell/ii/modules/regionSelector/OptionsToolbar.qml index cc314fbd3..e737e9cac 100644 --- a/dots/.config/quickshell/ii/modules/regionSelector/OptionsToolbar.qml +++ b/dots/.config/quickshell/ii/modules/regionSelector/OptionsToolbar.qml @@ -44,6 +44,9 @@ Toolbar { return "image_search"; case RegionSelection.SnipAction.CharRecognition: return "document_scanner"; + case RegionSelection.SnipAction.Record: + case RegionSelection.SnipAction.RecordWithSound: + return "videocam"; default: return ""; } diff --git a/dots/.config/quickshell/ii/modules/regionSelector/RegionSelection.qml b/dots/.config/quickshell/ii/modules/regionSelector/RegionSelection.qml index 39c45d965..05610f9dd 100644 --- a/dots/.config/quickshell/ii/modules/regionSelector/RegionSelection.qml +++ b/dots/.config/quickshell/ii/modules/regionSelector/RegionSelection.qml @@ -14,6 +14,7 @@ import Qt.labs.synchronizer PanelWindow { id: root visible: false + color: "transparent" WlrLayershell.namespace: "quickshell:regionSelector" WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive @@ -26,7 +27,7 @@ PanelWindow { } // TODO: Ask: sidebar AI; Ocr: tesseract - enum SnipAction { Copy, Edit, Search, CharRecognition } + enum SnipAction { Copy, Edit, Search, CharRecognition, Record, RecordWithSound } enum SelectionMode { RectCorners, Circle } property var action: RegionSelection.SnipAction.Copy property var selectionMode: RegionSelection.SelectionMode.RectCorners @@ -175,14 +176,35 @@ PanelWindow { property real regionY: Math.min(dragStartY, draggingY) Process { - id: screenshotProcess + id: screenshotProc running: true command: ["bash", "-c", `mkdir -p '${StringUtils.shellSingleQuoteEscape(root.screenshotDir)}' && grim -o '${StringUtils.shellSingleQuoteEscape(root.screen.name)}' '${StringUtils.shellSingleQuoteEscape(root.screenshotPath)}'`] onExited: (exitCode, exitStatus) => { - root.visible = true; if (root.enableContentRegions) imageDetectionProcess.running = true; + root.preparationDone = !checkRecordingProc.running; } } + property bool isRecording: root.action === RegionSelection.SnipAction.Record || root.action === RegionSelection.SnipAction.RecordWithSound + property bool recordingShouldStop: false + Process { + id: checkRecordingProc + running: isRecording + command: ["pidof", "wf-recorder"] + onExited: (exitCode, exitStatus) => { + root.preparationDone = !screenshotProc.running + root.recordingShouldStop = (exitCode === 0); + } + } + property bool preparationDone: false + onPreparationDoneChanged: { + if (!preparationDone) return; + if (root.isRecording && root.recordingShouldStop) { + Quickshell.execDetached([Directories.recordScriptPath]); + root.dismiss(); + return; + } + root.visible = true; + } Process { id: imageDetectionProcess @@ -221,11 +243,16 @@ PanelWindow { } // Set command for action + const rx = Math.round(root.regionX * root.monitorScale); + const ry = Math.round(root.regionY * root.monitorScale); + const rw = Math.round(root.regionWidth * root.monitorScale); + const rh = Math.round(root.regionHeight * root.monitorScale); const cropBase = `magick ${StringUtils.shellSingleQuoteEscape(root.screenshotPath)} ` - + `-crop ${root.regionWidth * root.monitorScale}x${root.regionHeight * root.monitorScale}+${root.regionX * root.monitorScale}+${root.regionY * root.monitorScale}` + + `-crop ${rw}x${rh}+${rx}+${ry}` const cropToStdout = `${cropBase} -` const cropInPlace = `${cropBase} '${StringUtils.shellSingleQuoteEscape(root.screenshotPath)}'` const cleanup = `rm '${StringUtils.shellSingleQuoteEscape(root.screenshotPath)}'` + const slurpRegion = `${rx},${ry} ${rw}x${rh}` const uploadAndGetUrl = (filePath) => { return `curl -sF files[]=@'${StringUtils.shellSingleQuoteEscape(filePath)}' ${root.fileUploadApiEndpoint} | jq -r '.files[0].url'` } @@ -242,6 +269,12 @@ PanelWindow { case RegionSelection.SnipAction.CharRecognition: snipProc.command = ["bash", "-c", `${cropInPlace} && tesseract '${StringUtils.shellSingleQuoteEscape(root.screenshotPath)}' stdout -l $(tesseract --list-langs | awk 'NR>1{print $1}' | tr '\\n' '+' | sed 's/\\+$/\\n/') | wl-copy && ${cleanup}`] break; + case RegionSelection.SnipAction.Record: + snipProc.command = ["bash", "-c", `${Directories.recordScriptPath} --region '${slurpRegion}'`] + break; + case RegionSelection.SnipAction.RecordWithSound: + snipProc.command = ["bash", "-c", `${Directories.recordScriptPath} --region '${slurpRegion}' --sound`] + break; default: console.warn("[Region Selector] Unknown snip action, skipping snip."); root.dismiss(); diff --git a/dots/.config/quickshell/ii/modules/regionSelector/RegionSelector.qml b/dots/.config/quickshell/ii/modules/regionSelector/RegionSelector.qml index 0ccb26eb0..40440366a 100644 --- a/dots/.config/quickshell/ii/modules/regionSelector/RegionSelector.qml +++ b/dots/.config/quickshell/ii/modules/regionSelector/RegionSelector.qml @@ -62,6 +62,18 @@ Scope { GlobalStates.regionSelectorOpen = true } + function record() { + root.action = RegionSelection.SnipAction.Record + root.selectionMode = RegionSelection.SelectionMode.RectCorners + GlobalStates.regionSelectorOpen = true + } + + function recordWithSound() { + root.action = RegionSelection.SnipAction.RecordWithSound + root.selectionMode = RegionSelection.SelectionMode.RectCorners + GlobalStates.regionSelectorOpen = true + } + IpcHandler { target: "region" @@ -71,10 +83,15 @@ Scope { function search() { root.search() } - function ocr() { root.ocr() } + function record() { + root.record() + } + function recordWithSound() { + root.recordWithSound() + } } GlobalShortcut { @@ -92,4 +109,14 @@ Scope { description: "Recognizes text in the selected region" onPressed: root.ocr() } + GlobalShortcut { + name: "regionRecord" + description: "Records the selected region" + onPressed: root.record() + } + GlobalShortcut { + name: "regionRecordWithSound" + description: "Records the selected region with sound" + onPressed: root.recordWithSound() + } } diff --git a/dots/.config/quickshell/ii/scripts/videos/record.sh b/dots/.config/quickshell/ii/scripts/videos/record.sh new file mode 100755 index 000000000..794bcf1ba --- /dev/null +++ b/dots/.config/quickshell/ii/scripts/videos/record.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +getdate() { + date '+%Y-%m-%d_%H.%M.%S' +} +getaudiooutput() { + pactl list sources | grep 'Name' | grep 'monitor' | cut -d ' ' -f2 +} +getactivemonitor() { + hyprctl monitors -j | jq -r '.[] | select(.focused == true) | .name' +} + +xdgvideo="$(xdg-user-dir VIDEOS)" +if [[ $xdgvideo = "$HOME" ]]; then + unset xdgvideo +fi +mkdir -p "${xdgvideo:-$HOME/Videos}" +cd "${xdgvideo:-$HOME/Videos}" || exit + +# parse --region without modifying $@ so other flags like --fullscreen still work +ARGS=("$@") +MANUAL_REGION="" +SOUND_FLAG=0 +FULLSCREEN_FLAG=0 +for ((i=0;i<${#ARGS[@]};i++)); do + if [[ "${ARGS[i]}" == "--region" ]]; then + if (( i+1 < ${#ARGS[@]} )); then + MANUAL_REGION="${ARGS[i+1]}" + else + notify-send "Recording cancelled" "No region specified for --region" -a 'Recorder' & disown + exit 1 + fi + elif [[ "${ARGS[i]}" == "--sound" ]]; then + SOUND_FLAG=1 + elif [[ "${ARGS[i]}" == "--fullscreen" ]]; then + FULLSCREEN_FLAG=1 + fi +done + +if pgrep wf-recorder > /dev/null; then + notify-send "Recording Stopped" "Stopped" -a 'Recorder' & + pkill wf-recorder & +else + if [[ $FULLSCREEN_FLAG -eq 1 ]]; then + notify-send "Starting recording" 'recording_'"$(getdate)"'.mp4' -a 'Recorder' & disown + if [[ $SOUND_FLAG -eq 1 ]]; then + wf-recorder -o "$(getactivemonitor)" --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --audio="$(getaudiooutput)" + else + wf-recorder -o "$(getactivemonitor)" --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t + fi + else + # If a manual region was provided via --region, use it; otherwise run slurp as before. + if [[ -n "$MANUAL_REGION" ]]; then + region="$MANUAL_REGION" + else + if ! region="$(slurp 2>&1)"; then + notify-send "Recording cancelled" "Selection was cancelled" -a 'Recorder' & disown + exit 1 + fi + fi + + notify-send "Starting recording" 'recording_'"$(getdate)"'.mp4' -a 'Recorder' & disown + if [[ $SOUND_FLAG -eq 1 ]]; then + wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --geometry "$region" --audio="$(getaudiooutput)" + else + wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --geometry "$region" + fi + fi +fi From 4fd5ba56303587735c17a56dc37af2893aecb972 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 26 Oct 2025 15:49:26 +0100 Subject: [PATCH 13/94] add super+shift+r for region record makes sense cuz other stuff with region selector use super+shift --- dots/.config/hypr/hyprland/keybinds.conf | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dots/.config/hypr/hyprland/keybinds.conf b/dots/.config/hypr/hyprland/keybinds.conf index b48daf625..e2f37e034 100644 --- a/dots/.config/hypr/hyprland/keybinds.conf +++ b/dots/.config/hypr/hyprland/keybinds.conf @@ -73,12 +73,14 @@ bindd = Super+Shift, C, Color picker, exec, hyprpicker -a # Pick color (Hex) >> bindld = ,Print, Screenshot >> clipboard ,exec,grim - | wl-copy # Screenshot >> clipboard bindld = Ctrl,Print, Screenshot >> clipboard & save, exec, mkdir -p $(xdg-user-dir PICTURES)/Screenshots && grim $(xdg-user-dir PICTURES)/Screenshots/Screenshot_"$(date '+%Y-%m-%d_%H.%M.%S')".png # Screenshot >> clipboard & file # Recording stuff -bindl = Super+Alt, R, global, quickshell:regionRecord # Record region (no sound) +bindl = Super+Shift, R, global, quickshell:regionRecord # Record region (no sound) +bindl = Super+Shift, R, exec, qs -c $qsConfig ipc call TEST_ALIVE || ~/.config/quickshell/$qsConfig/scripts/videos/record.sh # [hidden] Record region (no sound) (fallback) +bindl = Super+Alt, R, global, quickshell:regionRecord # [hidden] Record region (no sound) bindl = Super+Alt, R, exec, qs -c $qsConfig ipc call TEST_ALIVE || ~/.config/quickshell/$qsConfig/scripts/videos/record.sh # [hidden] Record region (no sound) (fallback) bindl = Ctrl+Alt, R, exec, ~/.config/quickshell/$qsConfig/scripts/videos/record.sh --fullscreen # [hidden] Record screen (no sound) bindl = Super+Shift+Alt, R, exec, ~/.config/quickshell/$qsConfig/scripts/videos/record.sh --fullscreen --sound # Record screen (with sound) # AI -bindd = Super+Shift+Alt, mouse:273, Generate AI summary for selected text, exec, ~/.config/hypr/hyprland/scripts/ai/primary-buffer-query.sh # AI summary for selected text +bindd = Super+Shift+Alt, mouse:273, Generate AI summary for selected text, exec, ~/.config/hypr/hyprland/scripts/ai/primary-buffer-query.sh # [hidden] AI summary for selected text #! ##! Window From 7f245e2896928538a2cc0849539442229bd778f2 Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 26 Oct 2025 23:13:49 +0800 Subject: [PATCH 14/94] Rearrange sdata/subcmd; add --skip-backup --- .../0.run.sh} | 0 .../options.sh} | 0 .../0.run.sh} | 0 .../options.sh} | 0 .../0.run.sh} | 10 +++ .../exp-update-tester.sh | 22 +++---- .../options.sh} | 0 .../0.greeting.sh} | 0 .../1.deps-selector.sh} | 1 + .../2.setups-selector.sh} | 1 + .../3.files.sh} | 20 ++++-- .../install.sh => subcmd-install/options.sh} | 4 +- setup | 66 ++++++++----------- 13 files changed, 71 insertions(+), 53 deletions(-) rename sdata/{step/exp-uninstall.sh => subcmd-exp-uninstall/0.run.sh} (100%) rename sdata/{options/exp-uninstall.sh => subcmd-exp-uninstall/options.sh} (100%) rename sdata/{step/exp-update-old.sh => subcmd-exp-update-old/0.run.sh} (100%) rename sdata/{options/exp-update-old.sh => subcmd-exp-update-old/options.sh} (100%) rename sdata/{step/exp-update.sh => subcmd-exp-update/0.run.sh} (98%) rename sdata/{step => subcmd-exp-update}/exp-update-tester.sh (96%) rename sdata/{options/exp-update.sh => subcmd-exp-update/options.sh} (100%) rename sdata/{step/0.install-greeting.sh => subcmd-install/0.greeting.sh} (100%) rename sdata/{step/1.install-deps-selector.sh => subcmd-install/1.deps-selector.sh} (99%) rename sdata/{step/2.install-setups-selector.sh => subcmd-install/2.setups-selector.sh} (97%) rename sdata/{step/3.install-files.sh => subcmd-install/3.files.sh} (94%) rename sdata/{options/install.sh => subcmd-install/options.sh} (92%) diff --git a/sdata/step/exp-uninstall.sh b/sdata/subcmd-exp-uninstall/0.run.sh similarity index 100% rename from sdata/step/exp-uninstall.sh rename to sdata/subcmd-exp-uninstall/0.run.sh diff --git a/sdata/options/exp-uninstall.sh b/sdata/subcmd-exp-uninstall/options.sh similarity index 100% rename from sdata/options/exp-uninstall.sh rename to sdata/subcmd-exp-uninstall/options.sh diff --git a/sdata/step/exp-update-old.sh b/sdata/subcmd-exp-update-old/0.run.sh similarity index 100% rename from sdata/step/exp-update-old.sh rename to sdata/subcmd-exp-update-old/0.run.sh diff --git a/sdata/options/exp-update-old.sh b/sdata/subcmd-exp-update-old/options.sh similarity index 100% rename from sdata/options/exp-update-old.sh rename to sdata/subcmd-exp-update-old/options.sh diff --git a/sdata/step/exp-update.sh b/sdata/subcmd-exp-update/0.run.sh similarity index 98% rename from sdata/step/exp-update.sh rename to sdata/subcmd-exp-update/0.run.sh index 32d90ebec..632d63082 100644 --- a/sdata/step/exp-update.sh +++ b/sdata/subcmd-exp-update/0.run.sh @@ -3,6 +3,16 @@ # shellcheck shell=bash +##################################################################################### +# Notes by @clsty: +# +# I'm not the one who developed this script (see issue#2284 which discussed about the history). +# However it contains many unnecessary logics. This is typically what AI will do. +# I don't really care if it's AI-generated or not, it's just an extra option in addition to ./setup install, so as long as the users say it works, it should be fine. +# However, it's not easy to maintain something like this. +# The redundant logic should be cleaned up someday. +# +# This also applies for exp-update.tester.sh, TBH I don't think that file is really needed, and it also looks like AI-generated. Just guessing though. ##################################################################################### # # exp-update.sh - Enhanced dotfiles update script diff --git a/sdata/step/exp-update-tester.sh b/sdata/subcmd-exp-update/exp-update-tester.sh similarity index 96% rename from sdata/step/exp-update-tester.sh rename to sdata/subcmd-exp-update/exp-update-tester.sh index 9b467d7a1..15e93f150 100755 --- a/sdata/step/exp-update-tester.sh +++ b/sdata/subcmd-exp-update/exp-update-tester.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# exp-update-tester.sh - Test suite for exp-update.sh +# exp-update-tester.sh - Test suite for exp-update # set -euo pipefail @@ -129,7 +129,7 @@ log_header() { :; } log_die() { echo "ERROR: \$1"; exit 1; } STY_CYAN="" STY_RST="" STY_YELLOW="" -# Set required environment variables for exp-update.sh +# Set required environment variables for exp-update/0.run.sh SKIP_NOTICE=true REPO_ROOT="\$1" CHECK_PACKAGES=false @@ -139,7 +139,7 @@ VERBOSE=false NON_INTERACTIVE=true SOURCE_ONLY=true -source "$ORIGINAL_DIR/sdata/step/exp-update.sh" +source "$ORIGINAL_DIR/sdata/subcmd-exp-update/0.run.sh" detected_dirs=\$(detect_repo_structure) if [[ -n "\$detected_dirs" ]]; then read -ra MONITOR_DIRS <<<"\$detected_dirs" @@ -190,7 +190,7 @@ log_success() { :; } log_header() { :; } log_die() { echo "ERROR: \$1"; exit 1; } -# Set required environment variables for exp-update.sh +# Set required environment variables for exp-update SKIP_NOTICE=true REPO_ROOT="\$1" CHECK_PACKAGES=false @@ -200,7 +200,7 @@ VERBOSE=false NON_INTERACTIVE=true SOURCE_ONLY=true -source "$ORIGINAL_DIR/sdata/step/exp-update.sh" +source "$ORIGINAL_DIR/sdata/subcmd-exp-update/0.run.sh" detected_dirs=\$(detect_repo_structure) if [[ -n "\$detected_dirs" ]]; then read -ra MONITOR_DIRS <<<"\$detected_dirs" @@ -276,7 +276,7 @@ log_success() { :; } log_header() { :; } log_die() { echo "ERROR: \$1" >&2; exit 1; } -# FIXED: Set REPO_ROOT before sourcing exp-update.sh +# FIXED: Set REPO_ROOT before sourcing exp-update REPO_ROOT="\$1" export REPO_ROOT @@ -293,7 +293,7 @@ HOME_UPDATE_IGNORE_FILE="/dev/null" # Source the production script to use the real should_ignore function # Redirect all unwanted output to stderr, then to /dev/null -source "$ORIGINAL_DIR/sdata/step/exp-update.sh" 2>/dev/null +source "$ORIGINAL_DIR/sdata/subcmd-exp-update/0.run.sh" 2>/dev/null test_cases=( "\$REPO_ROOT/app.log:0" @@ -348,7 +348,7 @@ test_safe_read_security() { log_test "Testing safe_read uses secure assignment (printf -v)" local safe_read_function - safe_read_function=$(awk '/^safe_read\(\) \{/,/^\}/' "$ORIGINAL_DIR/sdata/step/exp-update.sh") + safe_read_function=$(awk '/^safe_read\(\) \{/,/^\}/' "$ORIGINAL_DIR/sdata/subcmd-exp-update/0.run.sh") if [[ -z "$safe_read_function" ]]; then log_fail "Could not find safe_read function" @@ -547,7 +547,7 @@ log_success() { :; } log_header() { :; } log_die() { echo "ERROR: \$1" >&2; exit 1; } -# FIXED: Set REPO_ROOT before sourcing exp-update.sh +# FIXED: Set REPO_ROOT before sourcing exp-update REPO_ROOT="\$1" export REPO_ROOT @@ -563,7 +563,7 @@ UPDATE_IGNORE_FILE="\${REPO_ROOT}/.updateignore" HOME_UPDATE_IGNORE_FILE="/dev/null" # Source the production script to use the real should_ignore function -source "$ORIGINAL_DIR/sdata/step/exp-update.sh" 2>/dev/null +source "$ORIGINAL_DIR/sdata/subcmd-exp-update/0.run.sh" 2>/dev/null # Load patterns into cache load_ignore_patterns @@ -649,7 +649,7 @@ VERBOSE=false NON_INTERACTIVE=true SOURCE_ONLY=true -source "$ORIGINAL_DIR/sdata/step/exp-update.sh" 2>/dev/null +source "$ORIGINAL_DIR/sdata/subcmd-exp-update/0.run.sh" 2>/dev/null test_dir="/tmp/test-ensure-dir-\$\$" diff --git a/sdata/options/exp-update.sh b/sdata/subcmd-exp-update/options.sh similarity index 100% rename from sdata/options/exp-update.sh rename to sdata/subcmd-exp-update/options.sh diff --git a/sdata/step/0.install-greeting.sh b/sdata/subcmd-install/0.greeting.sh similarity index 100% rename from sdata/step/0.install-greeting.sh rename to sdata/subcmd-install/0.greeting.sh diff --git a/sdata/step/1.install-deps-selector.sh b/sdata/subcmd-install/1.deps-selector.sh similarity index 99% rename from sdata/step/1.install-deps-selector.sh rename to sdata/subcmd-install/1.deps-selector.sh index c1f4bea0c..ebed1bb04 100644 --- a/sdata/step/1.install-deps-selector.sh +++ b/sdata/subcmd-install/1.deps-selector.sh @@ -1,5 +1,6 @@ # This script is meant to be sourced. # It's not for directly running. +printf "${STY_CYAN}[$0]: 1. Install dependencies\n${STY_RST}" function outdate_detect(){ # Shallow clone prevent latest_commit_timestamp() from working. diff --git a/sdata/step/2.install-setups-selector.sh b/sdata/subcmd-install/2.setups-selector.sh similarity index 97% rename from sdata/step/2.install-setups-selector.sh rename to sdata/subcmd-install/2.setups-selector.sh index c279d7085..e4c8e612d 100644 --- a/sdata/step/2.install-setups-selector.sh +++ b/sdata/subcmd-install/2.setups-selector.sh @@ -1,5 +1,6 @@ # This script is meant to be sourced. # It's not for directly running. +printf "${STY_CYAN}[$0]: 2. Setup for permissions/services etc\n${STY_RST}" # shellcheck shell=bash diff --git a/sdata/step/3.install-files.sh b/sdata/subcmd-install/3.files.sh similarity index 94% rename from sdata/step/3.install-files.sh rename to sdata/subcmd-install/3.files.sh index eaea5017a..a9dc7c7e0 100644 --- a/sdata/step/3.install-files.sh +++ b/sdata/subcmd-install/3.files.sh @@ -1,5 +1,6 @@ # This script is meant to be sourced. # It's not for directly running. +printf "${STY_CYAN}[$0]: 3. Copying config files\n${STY_RST}" # shellcheck shell=bash @@ -67,6 +68,15 @@ function ask_backup_configs(){ if $backup;then backup_clashing_targets dots/.config $XDG_CONFIG_HOME "${BACKUP_DIR}/.config" backup_clashing_targets dots/.local/share $XDG_DATA_HOME "${BACKUP_DIR}/.local/share" + printf "${STY_BLUE}Backup into \"${BACKUP_DIR}\" finished.${STY_RST}\n" + fi +} +function auto_backup_configs(){ + # Backup when $BACKUP_DIR does not exist + if [[ ! -d "$BACKUP_DIR" ]]; then + backup_clashing_targets dots/.config $XDG_CONFIG_HOME "${BACKUP_DIR}/.config" + backup_clashing_targets dots/.local/share $XDG_DATA_HOME "${BACKUP_DIR}/.local/share" + printf "${STY_BLUE}Backup into \"${BACKUP_DIR}\" finished.${STY_RST}\n" fi } @@ -75,10 +85,12 @@ function ask_backup_configs(){ # In case some dirs does not exists v mkdir -p $XDG_BIN_HOME $XDG_CACHE_HOME $XDG_CONFIG_HOME/quickshell $XDG_DATA_HOME -case $ask in - false) sleep 0 ;; - *) ask_backup_configs ;; -esac +if [[ ! "${SKIP_BACKUP}" == true ]]; then + case $ask in + false) auto_backup_configs ;; + *) ask_backup_configs ;; + esac +fi # TODO: A better method for users to choose their customization, # for example some users may prefer ZSH over FISH, and foot over kitty. diff --git a/sdata/options/install.sh b/sdata/subcmd-install/options.sh similarity index 92% rename from sdata/options/install.sh rename to sdata/subcmd-install/options.sh index fa3f2b4e3..46a31d71f 100644 --- a/sdata/options/install.sh +++ b/sdata/subcmd-install/options.sh @@ -14,6 +14,7 @@ Options for install: --skip-allsetups Skip the whole process setting up permissions/services etc --skip-allfiles Skip the whole process copying configuration files -s, --skip-sysupdate Skip system package upgrade e.g. \"sudo pacman -Syu\" + --skip-backup Skip backup conflicting files --skip-quickshell Skip installing the config for Quickshell --skip-hyprland Skip installing the config for Hyprland --skip-fish Skip installing the config for Fish @@ -33,7 +34,7 @@ cleancache(){ # `man getopt` to see more para=$(getopt \ -o hfk:cs \ - -l help,force,fontset:,clean,skip-allgreeting,skip-alldeps,skip-allsetups,skip-allfiles,skip-sysupdate,skip-quickshell,skip-fish,skip-hyprland,skip-plasmaintg,skip-miscconf,exp-files,via-nix \ + -l help,force,fontset:,clean,skip-allgreeting,skip-alldeps,skip-allsetups,skip-allfiles,skip-sysupdate,skip-backup,skip-quickshell,skip-fish,skip-hyprland,skip-plasmaintg,skip-miscconf,exp-files,via-nix \ -n "$0" -- "$@") [ $? != 0 ] && echo "$0: Error when getopt, please recheck parameters." && exit 1 ##################################################################################### @@ -63,6 +64,7 @@ while true ; do --skip-allsetups) SKIP_ALLSETUPS=true;shift;; --skip-allfiles) SKIP_ALLFILES=true;shift;; -s|--skip-sysupdate) SKIP_SYSUPDATE=true;shift;; + --skip-backup) SKIP_BACKUP=true;shift;; --skip-hyprland) SKIP_HYPRLAND=true;shift;; --skip-fish) SKIP_FISH=true;shift;; --skip-quickshell) SKIP_QUICKSHELL=true;shift;; diff --git a/setup b/setup index 8fe456ff9..8e6b51d6d 100755 --- a/setup +++ b/setup @@ -34,75 +34,67 @@ case $1 in # Global help help|--help|-h)showhelp_global;exit;; # Correct subcommand - install|install-deps|install-setups|install-files|exp-uninstall|exp-update|exp-update-old) - SCRIPT_SUBCOMMAND=$1;shift;; - # No subcommand - -*|"")SCRIPT_SUBCOMMAND=install;; + install|exp-uninstall|exp-update|exp-update-old) + SUBCMD_NAME=$1 + SUBCMD_DIR=./sdata/subcmd-$1 + shift;; + # Correct subcommand but not using ./sdata/subcmd-$1 + install-deps|install-setups|install-files) + SUBCMD_NAME=$1 + SUBCMD_DIR=./sdata/subcmd-install + shift;; + # No subcommand, default to install + -*|"") + SUBCMD_NAME=install + SUBCMD_DIR=./sdata/subcmd-install + ;; # Wrong subcommand *)printf "${STY_RED}Unknown subcommand \"$1\".${STY_RST}\n";showhelp_global;exit 1;; esac ##################################################################################### -case ${SCRIPT_SUBCOMMAND} in +if [[ -f "${SUBCMD_DIR}/options.sh" ]]; + then source "${SUBCMD_DIR}/options.sh" +fi +case ${SUBCMD_NAME} in install) - source ./sdata/options/install.sh if [[ "${SKIP_ALLGREETING}" != true ]]; then - source ./sdata/step/0.install-greeting.sh + source ${SUBCMD_DIR}/0.greeting.sh fi if [[ "${SKIP_ALLDEPS}" != true ]]; then - printf "${STY_CYAN}[$0]: 1. Install dependencies\n${STY_RST}" - source ./sdata/step/1.install-deps-selector.sh + source ${SUBCMD_DIR}/1.deps-selector.sh fi if [[ "${SKIP_ALLSETUPS}" != true ]]; then - printf "${STY_CYAN}[$0]: 2. Setup for permissions/services etc\n${STY_RST}" - source ./sdata/step/2.install-setups-selector.sh + source ${SUBCMD_DIR}/2.setups-selector.sh fi if [[ "${SKIP_ALLFILES}" != true ]]; then - printf "${STY_CYAN}[$0]: 3. Copying config files\n${STY_RST}" if [[ "${EXPERIMENTAL_FILES_SCRIPT}" == true ]]; then - source ./sdata/step/3.install-files.experimental.sh + source ${SUBCMD_DIR}/3.files-exp.sh else - source ./sdata/step/3.install-files.sh + source ${SUBCMD_DIR}/3.files.sh fi fi ;; install-deps) - source ./sdata/options/install.sh if [[ "${SKIP_ALLDEPS}" != true ]]; then - printf "${STY_CYAN}[$0]: 1. Install dependencies\n${STY_RST}" - source ./sdata/step/1.install-deps-selector.sh + source ${SUBCMD_DIR}/1.deps-selector.sh fi ;; install-setups) - source ./sdata/options/install.sh if [[ "${SKIP_ALLSETUPS}" != true ]]; then - printf "${STY_CYAN}[$0]: 2. Setup for permissions/services etc\n${STY_RST}" - source ./sdata/step/2.install-setups-selector.sh + source ${SUBCMD_DIR}/2.setups-selector.sh fi ;; install-files) - source ./sdata/options/install.sh if [[ "${SKIP_ALLFILES}" != true ]]; then - printf "${STY_CYAN}[$0]: 3. Copying config files\n${STY_RST}" if [[ "${EXPERIMENTAL_FILES_SCRIPT}" == true ]]; then - source ./sdata/step/3.install-files.experimental.sh + source ${SUBCMD_DIR}/3.files-exp.sh else - source ./sdata/step/3.install-files.sh + source ${SUBCMD_DIR}/3.files.sh fi fi ;; - exp-uninstall) - source ./sdata/options/exp-uninstall.sh - source ./sdata/step/exp-uninstall.sh - exit - ;; - exp-update) - source ./sdata/options/exp-update.sh - source ./sdata/step/exp-update.sh - exit - ;; - exp-update-old) - source ./sdata/options/exp-update-old.sh - source ./sdata/step/exp-update-old.sh + exp-*) + source ${SUBCMD_DIR}/0.run.sh exit ;; esac From 47129318505f974f83eecb5810e1c464681e6937 Mon Sep 17 00:00:00 2001 From: "Celestial.y" Date: Sun, 26 Oct 2025 23:36:40 +0800 Subject: [PATCH 15/94] Update case in setup --- setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup b/setup index 8e6b51d6d..170e43464 100755 --- a/setup +++ b/setup @@ -93,7 +93,7 @@ case ${SUBCMD_NAME} in fi fi ;; - exp-*) + *) source ${SUBCMD_DIR}/0.run.sh exit ;; From 437b2020b73bcc003092755ba94f168ff5cb849c Mon Sep 17 00:00:00 2001 From: "Celestial.y" Date: Mon, 27 Oct 2025 01:09:30 +0800 Subject: [PATCH 16/94] Update 3.files.sh --- sdata/subcmd-install/3.files.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sdata/subcmd-install/3.files.sh b/sdata/subcmd-install/3.files.sh index a9dc7c7e0..cb294ce29 100644 --- a/sdata/subcmd-install/3.files.sh +++ b/sdata/subcmd-install/3.files.sh @@ -83,7 +83,7 @@ function auto_backup_configs(){ ##################################################################################### # In case some dirs does not exists -v mkdir -p $XDG_BIN_HOME $XDG_CACHE_HOME $XDG_CONFIG_HOME/quickshell $XDG_DATA_HOME +v mkdir -p $XDG_BIN_HOME $XDG_CACHE_HOME $XDG_CONFIG_HOME $XDG_DATA_HOME if [[ ! "${SKIP_BACKUP}" == true ]]; then case $ask in @@ -119,7 +119,8 @@ esac case $SKIP_QUICKSHELL in true) sleep 0;; *) - warning_rsync; v rsync -av --delete dots/.config/quickshell/ii/ "$XDG_CONFIG_HOME"/quickshell/ii/ + # Should overwriting the whole directory not only ~/.config/quickshell/ii/ cuz https://github.com/end-4/dots-hyprland/issues/2294#issuecomment-3448671064 + warning_rsync; v rsync -av --delete dots/.config/quickshell/ "$XDG_CONFIG_HOME"/quickshell/ ;; esac From 839ca74bf1b392e2f77c854ed6ed0f8c36195a98 Mon Sep 17 00:00:00 2001 From: z0 Date: Sun, 26 Oct 2025 22:00:35 +0300 Subject: [PATCH 17/94] Prepend Noto Sans Arabic in fontconfig --- dots/.config/fontconfig/conf.d | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dots/.config/fontconfig/conf.d b/dots/.config/fontconfig/conf.d index f450859f1..23a4607eb 100644 --- a/dots/.config/fontconfig/conf.d +++ b/dots/.config/fontconfig/conf.d @@ -1,9 +1,14 @@ - - - none + + + none + + + + + Noto Sans Arabic From 04963a616d975d2542096c7997474a538a6a4d9f Mon Sep 17 00:00:00 2001 From: z0 Date: Mon, 27 Oct 2025 00:35:23 +0300 Subject: [PATCH 18/94] remove binding=strong from arabic font prepend --- dots/.config/fontconfig/conf.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/fontconfig/conf.d b/dots/.config/fontconfig/conf.d index 23a4607eb..e3823c16d 100644 --- a/dots/.config/fontconfig/conf.d +++ b/dots/.config/fontconfig/conf.d @@ -7,7 +7,7 @@ - + Noto Sans Arabic From 991f113e4e4d9035dd1ced2042a9f854d983e6ca Mon Sep 17 00:00:00 2001 From: z0 Date: Mon, 27 Oct 2025 00:40:27 +0300 Subject: [PATCH 19/94] prepend font only if lang is ar --- dots/.config/fontconfig/conf.d | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dots/.config/fontconfig/conf.d b/dots/.config/fontconfig/conf.d index e3823c16d..cb84b18d5 100644 --- a/dots/.config/fontconfig/conf.d +++ b/dots/.config/fontconfig/conf.d @@ -7,6 +7,9 @@ + + ar + Noto Sans Arabic From 3aa1d5f1ed23e0b857e1bd895f2979612d500696 Mon Sep 17 00:00:00 2001 From: 0blivi0nis <182329535+0blivi0nis@users.noreply.github.com> Date: Sun, 26 Oct 2025 14:50:50 -0700 Subject: [PATCH 20/94] =?UTF-8?q?=E2=9C=A8=20feat(lock):=20add=20fingerpri?= =?UTF-8?q?nt=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Credit to @wooze-pao for providing the required code in #2162 --- .../quickshell/ii/modules/lock/Lock.qml | 10 ++++ .../ii/modules/lock/LockContext.qml | 46 +++++++++++++++++++ .../ii/modules/lock/LockSurface.qml | 22 +++++++++ .../ii/modules/lock/pam/fprintd.conf | 1 + 4 files changed, 79 insertions(+) create mode 100644 dots/.config/quickshell/ii/modules/lock/pam/fprintd.conf diff --git a/dots/.config/quickshell/ii/modules/lock/Lock.qml b/dots/.config/quickshell/ii/modules/lock/Lock.qml index 15950093c..5cfc12d72 100644 --- a/dots/.config/quickshell/ii/modules/lock/Lock.qml +++ b/dots/.config/quickshell/ii/modules/lock/Lock.qml @@ -32,6 +32,16 @@ Scope { } } + Connections { + target: GlobalStates + function onScreenLockedChanged() { + if (GlobalStates.screenLocked) { + lockContext.reset(); + lockContext.tryFingerUnlock(); + } + } + } + onUnlocked: (targetAction) => { // Perform the target action if it's not just unlocking if (targetAction == LockContext.ActionEnum.Poweroff) { diff --git a/dots/.config/quickshell/ii/modules/lock/LockContext.qml b/dots/.config/quickshell/ii/modules/lock/LockContext.qml index 7d030fc42..8a1bd5854 100644 --- a/dots/.config/quickshell/ii/modules/lock/LockContext.qml +++ b/dots/.config/quickshell/ii/modules/lock/LockContext.qml @@ -2,6 +2,7 @@ import qs import qs.modules.common import QtQuick import Quickshell +import Quickshell.Io import Quickshell.Services.Pam Scope { @@ -18,8 +19,13 @@ Scope { property string currentText: "" property bool unlockInProgress: false property bool showFailure: false + property bool fingerprintsConfigured: false property var targetAction: LockContext.ActionEnum.Unlock + Component.onCompleted: { + fingerprintCheckProcess.running = true; + } + function resetTargetAction() { root.targetAction = LockContext.ActionEnum.Unlock; } @@ -37,6 +43,46 @@ Scope { root.clearText(); root.unlockInProgress = false; } + + function tryFingerUnlock() { + fingerPam.start(); + } + + function stopPam() { + fingerPam.abort(); + } + + Process { + id: fingerprintCheckProcess + command: ["bash", "-c", "fprintd-list $(whoami)"] + stdout: StdioCollector { + id: fingerprintOutputCollector + onStreamFinished: { + root.fingerprintsConfigured = fingerprintOutputCollector.text.includes("Fingerprints for user"); + } + } + onExited: (exitCode, exitStatus) => { + if (exitCode !== 0) { + console.warn("fprintd-list command exited with error:", exitCode, exitStatus); + root.fingerprintsConfigured = false; + } + } + } + + PamContext { + id: fingerPam + + configDirectory: "pam" + config: "fprintd.conf" + + onCompleted: result => { + if (result == PamResult.Success) { + root.unlocked(root.targetAction); + } else if (result == PamResult.Error){ // if timeout or etc.. + tryFingerUnlock() + } + } + } Timer { id: passwordClearTimer diff --git a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml index 5feba6c72..1f7c47c75 100644 --- a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml +++ b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml @@ -98,6 +98,28 @@ MouseArea { scale: root.toolbarScale opacity: root.toolbarOpacity + // Fingerprint + Loader { + Layout.leftMargin: 10 + Layout.alignment: Qt.AlignVCenter + active: root.context.fingerprintsConfigured // Bind to actual fingerprint availability + visible: root.context.fingerprintsConfigured + + sourceComponent: Row { + spacing: 8 + + MaterialSymbol { + id: fingerprintIcon + anchors.verticalCenter: parent.verticalCenter + fill: 1 + text: "fingerprint" + iconSize: Appearance.font.pixelSize.huge + color: Appearance.colors.colOnSurfaceVariant + animateChange: true + } + } + } + ToolbarTextField { id: passwordBox placeholderText: GlobalStates.screenUnlockFailed ? Translation.tr("Incorrect password") : Translation.tr("Enter password") diff --git a/dots/.config/quickshell/ii/modules/lock/pam/fprintd.conf b/dots/.config/quickshell/ii/modules/lock/pam/fprintd.conf new file mode 100644 index 000000000..73d9cc725 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/lock/pam/fprintd.conf @@ -0,0 +1 @@ +auth sufficient pam_fprintd.so \ No newline at end of file From cc49b4c9213930e2d7ca4e9088cc120c17e40db3 Mon Sep 17 00:00:00 2001 From: z0 Date: Mon, 27 Oct 2025 02:32:40 +0300 Subject: [PATCH 21/94] Updated conf.d --- dots/.config/fontconfig/conf.d | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dots/.config/fontconfig/conf.d b/dots/.config/fontconfig/conf.d index cb84b18d5..016af78bc 100644 --- a/dots/.config/fontconfig/conf.d +++ b/dots/.config/fontconfig/conf.d @@ -6,11 +6,13 @@ none + + - - ar + + sans-serif - + Noto Sans Arabic From 6be1437eccba5cb05ea3f90b176eb310ee7a174b Mon Sep 17 00:00:00 2001 From: jwihardi Date: Sun, 26 Oct 2025 23:05:00 -0400 Subject: [PATCH 22/94] added smart-live-rebuild --- sdata/dist-gentoo/install-deps.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdata/dist-gentoo/install-deps.sh b/sdata/dist-gentoo/install-deps.sh index 911512ddf..7c7dcd58d 100644 --- a/sdata/dist-gentoo/install-deps.sh +++ b/sdata/dist-gentoo/install-deps.sh @@ -24,6 +24,7 @@ printf "${STY_RST}" pause x sudo emerge --noreplace --quiet app-eselect/eselect-repository +x sudo emerge --noreplace --quiet app-portage/smart-live-rebuild if [[ -z $(eselect repository list | grep localrepo) ]]; then v sudo eselect repository create localrepo @@ -53,6 +54,7 @@ v sudo sh -c 'cat ./sdata/dist-gentoo/additional-useflags >> /etc/portage/packag # Update system v sudo emerge --sync v sudo emerge --quiet --newuse --update --deep @world +v sudo emerge --quiet @smart-live-rebuild v sudo emerge --depclean # Remove old ebuilds (if this isn't done the wildcard will fuck upon a version change) @@ -80,7 +82,6 @@ v sudo ebuild ${ebuild_dir}/dev-libs/hyprlang/hyprlang*9999.ebuild digest v sudo ebuild ${ebuild_dir}/dev-util/hyprwayland-scanner/hyprwayland-scanner*9999.ebuild digest ###### LIVE EBUILDS END - # Install dependencies for i in "${metapkgs[@]}"; do x sudo mkdir -p ${ebuild_dir}/app-misc/${i} From 9610baf903a346ef1bbb98a87ddcbae086021b0b Mon Sep 17 00:00:00 2001 From: 0blivi0nis <182329535+0blivi0nis@users.noreply.github.com> Date: Sun, 26 Oct 2025 23:05:45 -0700 Subject: [PATCH 23/94] =?UTF-8?q?=F0=9F=90=9B=20fix(lock):=20remove=20dupl?= =?UTF-8?q?icate=20connection,=20only=20start=20if=20configured,=20stop=20?= =?UTF-8?q?on=20unlock?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../quickshell/ii/modules/lock/Lock.qml | 7 -- .../ii/modules/lock/LockContext.qml | 85 ++++++++++--------- 2 files changed, 44 insertions(+), 48 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/lock/Lock.qml b/dots/.config/quickshell/ii/modules/lock/Lock.qml index 5cfc12d72..12ba1a2eb 100644 --- a/dots/.config/quickshell/ii/modules/lock/Lock.qml +++ b/dots/.config/quickshell/ii/modules/lock/Lock.qml @@ -25,13 +25,6 @@ Scope { LockContext { id: lockContext - Connections { - target: GlobalStates - function onScreenLockedChanged() { - if (GlobalStates.screenLocked) lockContext.reset(); - } - } - Connections { target: GlobalStates function onScreenLockedChanged() { diff --git a/dots/.config/quickshell/ii/modules/lock/LockContext.qml b/dots/.config/quickshell/ii/modules/lock/LockContext.qml index 8a1bd5854..8b245237b 100644 --- a/dots/.config/quickshell/ii/modules/lock/LockContext.qml +++ b/dots/.config/quickshell/ii/modules/lock/LockContext.qml @@ -2,7 +2,7 @@ import qs import qs.modules.common import QtQuick import Quickshell -import Quickshell.Io +import Quickshell.Io // Required for StdioCollector import Quickshell.Services.Pam Scope { @@ -43,46 +43,6 @@ Scope { root.clearText(); root.unlockInProgress = false; } - - function tryFingerUnlock() { - fingerPam.start(); - } - - function stopPam() { - fingerPam.abort(); - } - - Process { - id: fingerprintCheckProcess - command: ["bash", "-c", "fprintd-list $(whoami)"] - stdout: StdioCollector { - id: fingerprintOutputCollector - onStreamFinished: { - root.fingerprintsConfigured = fingerprintOutputCollector.text.includes("Fingerprints for user"); - } - } - onExited: (exitCode, exitStatus) => { - if (exitCode !== 0) { - console.warn("fprintd-list command exited with error:", exitCode, exitStatus); - root.fingerprintsConfigured = false; - } - } - } - - PamContext { - id: fingerPam - - configDirectory: "pam" - config: "fprintd.conf" - - onCompleted: result => { - if (result == PamResult.Success) { - root.unlocked(root.targetAction); - } else if (result == PamResult.Error){ // if timeout or etc.. - tryFingerUnlock() - } - } - } Timer { id: passwordClearTimer @@ -106,6 +66,33 @@ Scope { pam.start(); } + function tryFingerUnlock() { + if (root.fingerprintsConfigured) { + fingerPam.start(); + } + } + + function stopFingerPam() { + fingerPam.abort(); + } + + Process { + id: fingerprintCheckProcess + command: ["bash", "-c", "fprintd-list $(whoami)"] + stdout: StdioCollector { + id: fingerprintOutputCollector + onStreamFinished: { + root.fingerprintsConfigured = fingerprintOutputCollector.text.includes("Fingerprints for user"); + } + } + onExited: (exitCode, exitStatus) => { + if (exitCode !== 0) { + console.warn("fprintd-list command exited with error:", exitCode, exitStatus); + root.fingerprintsConfigured = false; + } + } + } + PamContext { id: pam @@ -120,6 +107,7 @@ Scope { onCompleted: result => { if (result == PamResult.Success) { root.unlocked(root.targetAction); + stopFingerPam(); } else { root.clearText(); root.unlockInProgress = false; @@ -129,4 +117,19 @@ Scope { } } + PamContext { + id: fingerPam + + configDirectory: "pam" + config: "fprintd.conf" + + onCompleted: result => { + if (result == PamResult.Success) { + root.unlocked(root.targetAction); + stopFingerPam(); + } else if (result == PamResult.Error){ // if timeout or etc.. + tryFingerUnlock() + } + } + } } From 8d7e4bdd0d38f6c4f0e06c426c8d05cdd59f0381 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 27 Oct 2025 09:22:19 +0100 Subject: [PATCH 24/94] lock: fix duplicate hyprlock spawning --- dots/.config/quickshell/ii/modules/lock/Lock.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/lock/Lock.qml b/dots/.config/quickshell/ii/modules/lock/Lock.qml index 15950093c..f090350c6 100644 --- a/dots/.config/quickshell/ii/modules/lock/Lock.qml +++ b/dots/.config/quickshell/ii/modules/lock/Lock.qml @@ -113,7 +113,7 @@ Scope { onPressed: { if (Config.options.lock.useHyprlock) { - Quickshell.execDetached(["hyprlock"]) + Quickshell.execDetached(["bash", "-c", "pidof hyprlock || hyprlock"]); return; } GlobalStates.screenLocked = true; From 43960b3a605e8ba75191b3c972093a6cd42e171e Mon Sep 17 00:00:00 2001 From: clsty Date: Mon, 27 Oct 2025 23:38:28 +0800 Subject: [PATCH 25/94] Fix outdate_detect() --- sdata/subcmd-install/1.deps-selector.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdata/subcmd-install/1.deps-selector.sh b/sdata/subcmd-install/1.deps-selector.sh index ebed1bb04..71f8cf066 100644 --- a/sdata/subcmd-install/1.deps-selector.sh +++ b/sdata/subcmd-install/1.deps-selector.sh @@ -4,7 +4,7 @@ printf "${STY_CYAN}[$0]: 1. Install dependencies\n${STY_RST}" function outdate_detect(){ # Shallow clone prevent latest_commit_timestamp() from working. - v git_auto_unshallow + x git_auto_unshallow local source_path="$1" local target_path="$2" From 957a63d04a168c54ad96a56d35234c2933319ba0 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 27 Oct 2025 17:14:59 +0100 Subject: [PATCH 26/94] make screenshot to clipboard and file actually copy to clipboard (#2311) --- dots/.config/hypr/hyprland/keybinds.conf | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dots/.config/hypr/hyprland/keybinds.conf b/dots/.config/hypr/hyprland/keybinds.conf index e2f37e034..263d5048d 100644 --- a/dots/.config/hypr/hyprland/keybinds.conf +++ b/dots/.config/hypr/hyprland/keybinds.conf @@ -70,8 +70,9 @@ bind = Super+Shift, T,exec, qs -c $qsConfig ipc call TEST_ALIVE || pidof slurp | # Color picker bindd = Super+Shift, C, Color picker, exec, hyprpicker -a # Pick color (Hex) >> clipboard # Fullscreen screenshot -bindld = ,Print, Screenshot >> clipboard ,exec,grim - | wl-copy # Screenshot >> clipboard -bindld = Ctrl,Print, Screenshot >> clipboard & save, exec, mkdir -p $(xdg-user-dir PICTURES)/Screenshots && grim $(xdg-user-dir PICTURES)/Screenshots/Screenshot_"$(date '+%Y-%m-%d_%H.%M.%S')".png # Screenshot >> clipboard & file +bindl = ,Print,exec,grim - | wl-copy # Screenshot >> clipboard +bindln = Ctrl,Print, exec, mkdir -p $(xdg-user-dir PICTURES)/Screenshots && grim $(xdg-user-dir PICTURES)/Screenshots/Screenshot_"$(date '+%Y-%m-%d_%H.%M.%S')".png # Screenshot >> clipboard & file (file) +bindln = Ctrl,Print,exec,grim - | wl-copy # [hidden] Screenshot >> clipboard & file (clipboard) # Recording stuff bindl = Super+Shift, R, global, quickshell:regionRecord # Record region (no sound) bindl = Super+Shift, R, exec, qs -c $qsConfig ipc call TEST_ALIVE || ~/.config/quickshell/$qsConfig/scripts/videos/record.sh # [hidden] Record region (no sound) (fallback) From c1a5641ff5cf2b7b82590aa5474805f8329e9e9e Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 27 Oct 2025 17:32:26 +0100 Subject: [PATCH 27/94] fix wrong minimum brightness (#2310) --- dots/.config/quickshell/ii/services/Brightness.qml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dots/.config/quickshell/ii/services/Brightness.qml b/dots/.config/quickshell/ii/services/Brightness.qml index e2d164814..5232f76f9 100644 --- a/dots/.config/quickshell/ii/services/Brightness.qml +++ b/dots/.config/quickshell/ii/services/Brightness.qml @@ -16,8 +16,6 @@ import QtQuick */ Singleton { id: root - property real minimumBrightnessAllowed: 0.00001 // Setting to 0 would kind of turn off the screen. We don't want that. - signal brightnessChanged() property var ddcMonitors: [] @@ -137,14 +135,14 @@ Singleton { } function syncBrightness() { - const brightnessValue = Math.max(monitor.multipliedBrightness, root.minimumBrightnessAllowed) - const rounded = Math.round(brightnessValue * monitor.rawMaxBrightness); - setProc.command = isDdc ? ["ddcutil", "-b", busNum, "setvcp", "10", rounded] : ["brightnessctl", "--class", "backlight", "s", rounded, "--quiet"]; + const brightnessValue = Math.max(monitor.multipliedBrightness, 0) + const rawValueRounded = Math.max(Math.floor(brightnessValue * monitor.rawMaxBrightness), 1); + setProc.command = isDdc ? ["ddcutil", "-b", busNum, "setvcp", "10", rawValueRounded] : ["brightnessctl", "--class", "backlight", "s", rawValueRounded, "--quiet"]; setProc.startDetached(); } function setBrightness(value: real): void { - value = Math.max(root.minimumBrightnessAllowed, Math.min(1, value)); + value = Math.max(0, Math.min(1, value)); monitor.brightness = value; } From 901aa820e5c5051b3b18a44657ea537e73922545 Mon Sep 17 00:00:00 2001 From: vaguesyntax Date: Mon, 27 Oct 2025 19:33:17 +0300 Subject: [PATCH 28/94] fix config and icons --- dots/.config/quickshell/ii/modules/common/Config.qml | 5 ++++- .../quickshell/ii/modules/settings/ServicesConfig.qml | 11 +++++++++-- .../androidStyle/AndroidEasyEffectsToggle.qml | 2 +- .../androidStyle/AndroidMusicRecognition.qml | 4 ++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml index 83fda7cee..70cca4275 100644 --- a/dots/.config/quickshell/ii/modules/common/Config.qml +++ b/dots/.config/quickshell/ii/modules/common/Config.qml @@ -374,7 +374,10 @@ Singleton { property JsonObject resources: JsonObject { property int updateInterval: 3000 - property int musicRecognitionTimeout: 16 + } + + property JsonObject musicRecognition: JsonObject { + property int timeout: 16 } property JsonObject search: JsonObject { diff --git a/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml b/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml index 64c015ff2..d1fb137c5 100644 --- a/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml @@ -54,15 +54,22 @@ ContentPage { Config.options.resources.updateInterval = value; } } + + } + + ContentSection { + icon: "music_cast" + title: Translation.tr("Music Recognition") + ConfigSpinBox { icon: "timer_off" text: Translation.tr("Music recognition timeout (s)") - value: Config.options.resources.musicRecognitionTimeout + value: Config.options.musicRecognition.timeout from: 2 to: 100 stepSize: 2 onValueChanged: { - Config.options.resources.musicRecognitionTimeout = value; + Config.options.musicRecognition.timeout = value; } } } diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml index 86605becd..c907abf77 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml @@ -10,7 +10,7 @@ AndroidQuickToggleButton { name: Translation.tr("EasyEffects") toggled: EasyEffects.active - buttonIcon: "instant_mix" + buttonIcon: "graphic_eq" Component.onCompleted: { EasyEffects.fetchActiveState() diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml index e674660b3..585b784f7 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml @@ -11,14 +11,14 @@ AndroidQuickToggleButton { id: root property int timeoutInterval: 5 - property int timeoutDuration: Config.options.resources.musicRecognitionTimeout + property int timeoutDuration: Config.options.musicRecognition.timeout property string monitorSource: "monitor" // "monitor" (system sound) , "input" (microphone) name: Translation.tr("Identify Music") statusText: toggled ? Translation.tr("Listening...") : monitorSource === "monitor" ? Translation.tr("System sound") : Translation.tr("Microphone") toggled: false - buttonIcon: toggled ? "cadence" : "graphic_eq" + buttonIcon: toggled ? "music_cast" : "music_note" property var recognizedTrack: ({ title:"", subtitle:"", url:""}) From 035e51b36e56cf44f758f864f1ce3ae3f3e83965 Mon Sep 17 00:00:00 2001 From: vaguesyntax Date: Mon, 27 Oct 2025 20:39:45 +0300 Subject: [PATCH 29/94] add interval to settings, update the script (it was not working as intented) --- .../quickshell/ii/modules/common/Config.qml | 1 + .../ii/modules/settings/ServicesConfig.qml | 15 +++++++- .../androidStyle/AndroidMusicRecognition.qml | 3 +- .../musicRecognition/musicRecognition.sh | 38 ++++++++++--------- 4 files changed, 37 insertions(+), 20 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml index 70cca4275..7a66d90f6 100644 --- a/dots/.config/quickshell/ii/modules/common/Config.qml +++ b/dots/.config/quickshell/ii/modules/common/Config.qml @@ -378,6 +378,7 @@ Singleton { property JsonObject musicRecognition: JsonObject { property int timeout: 16 + property int interval: 4 } property JsonObject search: JsonObject { diff --git a/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml b/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml index d1fb137c5..11fc82966 100644 --- a/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml @@ -63,15 +63,26 @@ ContentPage { ConfigSpinBox { icon: "timer_off" - text: Translation.tr("Music recognition timeout (s)") + text: Translation.tr("Total duration timeout (s)") value: Config.options.musicRecognition.timeout - from: 2 + from: 10 to: 100 stepSize: 2 onValueChanged: { Config.options.musicRecognition.timeout = value; } } + ConfigSpinBox { + icon: "av_timer" + text: Translation.tr("Polling interval (s)") + value: Config.options.musicRecognition.interval + from: 2 + to: 10 + stepSize: 1 + onValueChanged: { + Config.options.musicRecognition.interval = value; + } + } } ContentSection { diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml index 585b784f7..f7e475547 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml @@ -10,9 +10,10 @@ import qs.services AndroidQuickToggleButton { id: root - property int timeoutInterval: 5 + property int timeoutInterval: Config.options.musicRecognition.interval property int timeoutDuration: Config.options.musicRecognition.timeout + property string monitorSource: "monitor" // "monitor" (system sound) , "input" (microphone) name: Translation.tr("Identify Music") diff --git a/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh b/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh index f0b7c20a3..4f129f29d 100755 --- a/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh +++ b/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh @@ -1,51 +1,55 @@ #!/bin/bash -INTERVAL=5 +INTERVAL=2 TOTAL_DURATION=30 MIN_VALID_RESULT_LENGTH=300 -SOURCE_TYPE="monitor" # default | "monitor" : system_sound , "input" : microphone +SOURCE_TYPE="monitor" # monitor | input +TMP_RAW="/tmp/songrec_recording.raw" +TMP_MP3="/tmp/songrec_recording.mp3" while getopts "i:t:s:" opt; do case $opt in i) INTERVAL=$OPTARG ;; t) TOTAL_DURATION=$OPTARG ;; s) SOURCE_TYPE=$OPTARG ;; - *) echo "Usage: $0 [-i interval_seconds] [-t total_duration_seconds] [-s monitor|input]" - exit 1 ;; + *) exit 1 ;; esac done - -# Kaynağı belirle if [ "$SOURCE_TYPE" = "monitor" ]; then MONITOR_SOURCE=$(pactl list short sources 2>/dev/null | grep -m1 monitor | awk '{print $2}' || true) elif [ "$SOURCE_TYPE" = "input" ]; then MONITOR_SOURCE=$(pactl info | grep "Default Source:" | awk '{print $3}' || true) else - echo "Invalid source type: $SOURCE_TYPE. Use 'monitor' or 'input'." exit 1 fi +if [ -z "$MONITOR_SOURCE" ]; then + exit 1 +fi + +cleanup() { + rm -f "$TMP_RAW" "$TMP_MP3" + pkill -P $$ parec >/dev/null 2>&1 || true +} +trap cleanup EXIT + +parec --device="$MONITOR_SOURCE" --format=s16le --rate=44100 --channels=2 > "$TMP_RAW" & START_TIME=$(date +%s) while true; do + sleep "$INTERVAL" CURRENT_TIME=$(date +%s) ELAPSED=$((CURRENT_TIME - START_TIME)) - + if (( ELAPSED >= TOTAL_DURATION )); then - echo "Total duration reached, no music recognized." exit 0 fi - TMP_FILE=$(mktemp /tmp/recording.XXXXXX.wav) + ffmpeg -f s16le -ar 44100 -ac 2 -i "$TMP_RAW" -acodec libmp3lame -y -hide_banner -loglevel error "$TMP_MP3" 2>/dev/null - parec --device="$MONITOR_SOURCE" --format=s16le --rate=44100 --channels=2 \ - > >(ffmpeg -f s16le -ar 44100 -ac 2 -i - -t $INTERVAL -acodec libmp3lame "$TMP_FILE" -y -hide_banner -loglevel error) \ - 2>/dev/null + RESULT=$(songrec audio-file-to-recognized-song "$TMP_MP3" 2>/dev/null || true) - RESULT=$(songrec audio-file-to-recognized-song "$TMP_FILE" 2>/dev/null || true) - rm -f "$TMP_FILE" - - if [ -n "$RESULT" ] && [ ${#RESULT} -gt $MIN_VALID_RESULT_LENGTH ]; then + if echo "$RESULT" | grep -q '"matches": \[' && [ ${#RESULT} -gt $MIN_VALID_RESULT_LENGTH ]; then echo "$RESULT" exit 0 fi From 08d1a2dfd6dd201c39eb184b4fece97e5e497647 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 27 Oct 2025 22:44:33 +0100 Subject: [PATCH 30/94] buttongroup: fix childrencount accessing from children --- .../quickshell/ii/modules/common/widgets/ButtonGroup.qml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/ButtonGroup.qml b/dots/.config/quickshell/ii/modules/common/widgets/ButtonGroup.qml index 32cd5e04f..d3c9114eb 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/ButtonGroup.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/ButtonGroup.qml @@ -13,8 +13,8 @@ Rectangle { property alias uniformCellSizes: rowLayout.uniformCellSizes property real spacing: 5 property real padding: 0 - property int clickIndex: rowLayout.clickIndex - property int childrenCount: rowLayout.children.length + property alias clickIndex: rowLayout.clickIndex + property alias childrenCount: rowLayout.childrenCount property real contentWidth: { let total = 0; @@ -44,5 +44,6 @@ Rectangle { anchors.margins: root.padding spacing: root.spacing property int clickIndex: -1 + property int childrenCount: children.length }] } From 06d12fb8ecdcebb964fb684d98c7ddb420f0beaa Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 28 Oct 2025 08:48:57 +0100 Subject: [PATCH 31/94] music recognition: add check for songrec command existence --- .../androidStyle/AndroidMusicRecognition.qml | 11 +++++++++-- .../ii/scripts/musicRecognition/musicRecognition.sh | 3 +-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml index f7e475547..621bf7cf0 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml @@ -41,14 +41,15 @@ AndroidQuickToggleButton { StyledToolTip { - text: Translation.tr("Identifies currently playing song | Right-click to change monitor source") + text: Translation.tr("Recognize music | Right-click to toggle source") } - onClicked: { + onClicked: { root.toggled = !root.toggled recognizeMusicProc.running = root.toggled musicReconizedProc.running = false } + altAction: () => { if (root.monitorSource === "monitor"){ root.monitorSource = "input" @@ -68,6 +69,12 @@ AndroidQuickToggleButton { handleRecognition(this.text) } } + onExited: (exitCode, exitStatus) => { + if (exitCode === 1) { + Quickshell.execDetached(["notify-send", Translation.tr("Couldn't recognize music"), Translation.tr("Make sure you have songrec installed"), "-a", "Shell"]) + root.toggled = false + } + } } Process { diff --git a/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh b/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh index 4f129f29d..2f988f145 100755 --- a/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh +++ b/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh @@ -23,7 +23,7 @@ else exit 1 fi -if [ -z "$MONITOR_SOURCE" ]; then +if [ -z "$MONITOR_SOURCE" ] || ! command -v songrec >/dev/null 2>&1; then exit 1 fi @@ -46,7 +46,6 @@ while true; do fi ffmpeg -f s16le -ar 44100 -ac 2 -i "$TMP_RAW" -acodec libmp3lame -y -hide_banner -loglevel error "$TMP_MP3" 2>/dev/null - RESULT=$(songrec audio-file-to-recognized-song "$TMP_MP3" 2>/dev/null || true) if echo "$RESULT" | grep -q '"matches": \[' && [ ${#RESULT} -gt $MIN_VALID_RESULT_LENGTH ]; then From 9df78087f05a638cc2cb50d2811070fa562ff24e Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 28 Oct 2025 08:51:18 +0100 Subject: [PATCH 32/94] music recognition: add different icon for microphone source --- .../quickToggles/androidStyle/AndroidMusicRecognition.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml index 621bf7cf0..d3757071a 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml @@ -19,7 +19,7 @@ AndroidQuickToggleButton { name: Translation.tr("Identify Music") statusText: toggled ? Translation.tr("Listening...") : monitorSource === "monitor" ? Translation.tr("System sound") : Translation.tr("Microphone") toggled: false - buttonIcon: toggled ? "music_cast" : "music_note" + buttonIcon: toggled ? "music_cast" : (monitorSource === "monitor" ? "music_note" : "frame_person_mic") property var recognizedTrack: ({ title:"", subtitle:"", url:""}) From 7b42efd37ae348ab78bbae3f62e50e2a6a56b5ac Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 28 Oct 2025 08:52:58 +0100 Subject: [PATCH 33/94] rename music recognition script to be consistent w/ other scripts --- .../quickToggles/androidStyle/AndroidMusicRecognition.qml | 2 +- .../{musicRecognition.sh => recognize-music.sh} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename dots/.config/quickshell/ii/scripts/musicRecognition/{musicRecognition.sh => recognize-music.sh} (100%) diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml index d3757071a..18b90f6ff 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml @@ -63,7 +63,7 @@ AndroidQuickToggleButton { Process { id: recognizeMusicProc running: false - command: [`${Directories.scriptPath}/musicRecognition/musicRecognition.sh`, "-i", root.timeoutInterval, "-t", root.timeoutDuration, "-s", root.monitorSource] + command: [`${Directories.scriptPath}/musicRecognition/recognize-music.sh`, "-i", root.timeoutInterval, "-t", root.timeoutDuration, "-s", root.monitorSource] stdout: StdioCollector { onStreamFinished: { handleRecognition(this.text) diff --git a/dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh b/dots/.config/quickshell/ii/scripts/musicRecognition/recognize-music.sh similarity index 100% rename from dots/.config/quickshell/ii/scripts/musicRecognition/musicRecognition.sh rename to dots/.config/quickshell/ii/scripts/musicRecognition/recognize-music.sh From 107dc8cc2495a3fcd4f612a172443e97afe560aa Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 28 Oct 2025 08:57:51 +0100 Subject: [PATCH 34/94] music recognition: move tmp path to a cleaner place --- .../ii/scripts/musicRecognition/recognize-music.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dots/.config/quickshell/ii/scripts/musicRecognition/recognize-music.sh b/dots/.config/quickshell/ii/scripts/musicRecognition/recognize-music.sh index 2f988f145..09b0361af 100755 --- a/dots/.config/quickshell/ii/scripts/musicRecognition/recognize-music.sh +++ b/dots/.config/quickshell/ii/scripts/musicRecognition/recognize-music.sh @@ -4,8 +4,9 @@ INTERVAL=2 TOTAL_DURATION=30 MIN_VALID_RESULT_LENGTH=300 SOURCE_TYPE="monitor" # monitor | input -TMP_RAW="/tmp/songrec_recording.raw" -TMP_MP3="/tmp/songrec_recording.mp3" +TMP_PATH="/tmp/quickshell/media/songrec" +TMP_RAW="$TMP_PATH/recording.raw" +TMP_MP3="$TMP_PATH/recording.mp3" while getopts "i:t:s:" opt; do case $opt in @@ -20,6 +21,7 @@ if [ "$SOURCE_TYPE" = "monitor" ]; then elif [ "$SOURCE_TYPE" = "input" ]; then MONITOR_SOURCE=$(pactl info | grep "Default Source:" | awk '{print $3}' || true) else + echo "Invalid source type" exit 1 fi @@ -33,6 +35,7 @@ cleanup() { } trap cleanup EXIT +mkdir -p "$TMP_PATH" parec --device="$MONITOR_SOURCE" --format=s16le --rate=44100 --channels=2 > "$TMP_RAW" & START_TIME=$(date +%s) From 066971e7207b2672f886493f6d8822d3bd52d11f Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 28 Oct 2025 09:02:19 +0100 Subject: [PATCH 35/94] music recognition: adjust message and icon --- .../quickshell/ii/modules/common/widgets/notification_utils.js | 3 ++- .../quickToggles/androidStyle/AndroidMusicRecognition.qml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js b/dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js index dbdeebde9..f817a460b 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js +++ b/dots/.config/quickshell/ii/modules/common/widgets/notification_utils.js @@ -17,7 +17,8 @@ function findSuitableMaterialSymbol(summary = "") { 'time': 'scheduleb', 'installed': 'download', 'configuration reloaded': 'reset_wrench', - 'unable': 'indeterminate_question_box', + 'unable': 'question_mark', + "couldn't": 'question_mark', 'config': 'reset_wrench', 'update': 'update', 'ai response': 'neurology', diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml index 18b90f6ff..a1b9c6738 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMusicRecognition.qml @@ -33,7 +33,7 @@ AndroidQuickToggleButton { } musicReconizedProc.running = true } catch(e) { - Quickshell.execDetached(["notify-send", Translation.tr("Unable to recognize music"), Translation.tr("Please make sure your music is playing and try again"), "-a", "Shell"]) + Quickshell.execDetached(["notify-send", Translation.tr("Couldn't recognize music"), Translation.tr("Perhaps what you're listening to is too niche"), "-a", "Shell"]) } finally { root.toggled = false } From 44da20ed4aaca2b63a3dc6c6378f912f91b04bb3 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 28 Oct 2025 09:14:08 +0100 Subject: [PATCH 36/94] settings: reorder servicesconfig sections to be alphabetical --- .../ii/modules/settings/ServicesConfig.qml | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml b/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml index 11fc82966..4636d666b 100644 --- a/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/ServicesConfig.qml @@ -24,6 +24,34 @@ ContentPage { } } + ContentSection { + icon: "music_cast" + title: Translation.tr("Music Recognition") + + ConfigSpinBox { + icon: "timer_off" + text: Translation.tr("Total duration timeout (s)") + value: Config.options.musicRecognition.timeout + from: 10 + to: 100 + stepSize: 2 + onValueChanged: { + Config.options.musicRecognition.timeout = value; + } + } + ConfigSpinBox { + icon: "av_timer" + text: Translation.tr("Polling interval (s)") + value: Config.options.musicRecognition.interval + from: 2 + to: 10 + stepSize: 1 + onValueChanged: { + Config.options.musicRecognition.interval = value; + } + } + } + ContentSection { icon: "cell_tower" title: Translation.tr("Networking") @@ -57,34 +85,6 @@ ContentPage { } - ContentSection { - icon: "music_cast" - title: Translation.tr("Music Recognition") - - ConfigSpinBox { - icon: "timer_off" - text: Translation.tr("Total duration timeout (s)") - value: Config.options.musicRecognition.timeout - from: 10 - to: 100 - stepSize: 2 - onValueChanged: { - Config.options.musicRecognition.timeout = value; - } - } - ConfigSpinBox { - icon: "av_timer" - text: Translation.tr("Polling interval (s)") - value: Config.options.musicRecognition.interval - from: 2 - to: 10 - stepSize: 1 - onValueChanged: { - Config.options.musicRecognition.interval = value; - } - } - } - ContentSection { icon: "search" title: Translation.tr("Search") From 6c6a4edf590c79ec1ae7de97db685053c84c1c4a Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 28 Oct 2025 20:41:04 +0100 Subject: [PATCH 37/94] shapes submodule --- .gitmodules | 3 +++ dots/.config/quickshell/ii/modules/common/widgets/shapes | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 dots/.config/quickshell/ii/modules/common/widgets/shapes diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..6daa3761e --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "dots/.config/quickshell/ii/modules/common/widgets/shapes"] + path = dots/.config/quickshell/ii/modules/common/widgets/shapes + url = https://github.com/end-4/rounded-polygon-qmljs.git diff --git a/dots/.config/quickshell/ii/modules/common/widgets/shapes b/dots/.config/quickshell/ii/modules/common/widgets/shapes new file mode 160000 index 000000000..19a61bed7 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/widgets/shapes @@ -0,0 +1 @@ +Subproject commit 19a61bed7e5ac338cfcfbf3329963704e6d658dc From fc32ce56d0b6833c98df47b86b4308d3e5fb4fd6 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 28 Oct 2025 22:08:19 +0100 Subject: [PATCH 38/94] booru response: less stupid layout.fillwidth --- .../quickshell/ii/modules/sidebarLeft/anime/BooruResponse.qml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/anime/BooruResponse.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/anime/BooruResponse.qml index 9258dbc9d..6b1711a40 100644 --- a/dots/.config/quickshell/ii/modules/sidebarLeft/anime/BooruResponse.qml +++ b/dots/.config/quickshell/ii/modules/sidebarLeft/anime/BooruResponse.qml @@ -100,9 +100,7 @@ Rectangle { id: tagsFlickable visible: root.responseData.tags.length > 0 Layout.alignment: Qt.AlignLeft - Layout.fillWidth: { - return true - } + Layout.fillWidth: true implicitHeight: tagRowLayout.implicitHeight contentWidth: tagRowLayout.implicitWidth From 7982f43a62dc1dcbed364e1b76f9fd50bccfe909 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 28 Oct 2025 22:10:04 +0100 Subject: [PATCH 39/94] lock: freaking fancy password chars --- .../modules/common/widgets/MaterialCookie.qml | 1 - .../modules/common/widgets/MaterialShape.qml | 87 +++++++++++++++++ .../ii/modules/common/widgets/shapes | 2 +- .../ii/modules/lock/LockSurface.qml | 22 +++++ .../ii/modules/lock/PasswordChars.qml | 96 +++++++++++++++++++ 5 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 dots/.config/quickshell/ii/modules/common/widgets/MaterialShape.qml create mode 100644 dots/.config/quickshell/ii/modules/lock/PasswordChars.qml diff --git a/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml b/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml index a0cdfeafc..79048ca63 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml @@ -3,7 +3,6 @@ import QtQuick.Shapes import Quickshell import qs.modules.common - Item { id: root diff --git a/dots/.config/quickshell/ii/modules/common/widgets/MaterialShape.qml b/dots/.config/quickshell/ii/modules/common/widgets/MaterialShape.qml new file mode 100644 index 000000000..30d953478 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/widgets/MaterialShape.qml @@ -0,0 +1,87 @@ +import qs.modules.common.widgets.shapes +import "shapes/material-shapes.js" as MaterialShapes + +ShapeCanvas { + id: root + enum Shape { + Circle, + Square, + Slanted, + Arch, + Fan, + Arrow, + SemiCircle, + Oval, + Pill, + Triangle, + Diamond, + ClamShell, + Pentagon, + Gem, + Sunny, + VerySunny, + Cookie4Sided, + Cookie6Sided, + Cookie7Sided, + Cookie9Sided, + Cookie12Sided, + Ghostish, + Clover4Leaf, + Clover8Leaf, + Burst, + SoftBurst, + Boom, + SoftBoom, + Flower, + Puffy, + PuffyDiamond, + PixelCircle, + PixelTriangle, + Bun, + Heart + } + required property var shape + property double implicitSize + implicitHeight: implicitSize + implicitWidth: implicitSize + roundedPolygon: { + switch (root.shape) { + case MaterialShape.Shape.Circle: return MaterialShapes.getCircle(); + case MaterialShape.Shape.Square: return MaterialShapes.getSquare(); + case MaterialShape.Shape.Slanted: return MaterialShapes.getSlanted(); + case MaterialShape.Shape.Arch: return MaterialShapes.getArch(); + case MaterialShape.Shape.Fan: return MaterialShapes.getFan(); + case MaterialShape.Shape.Arrow: return MaterialShapes.getArrow(); + case MaterialShape.Shape.SemiCircle: return MaterialShapes.getSemiCircle(); + case MaterialShape.Shape.Oval: return MaterialShapes.getOval(); + case MaterialShape.Shape.Pill: return MaterialShapes.getPill(); + case MaterialShape.Shape.Triangle: return MaterialShapes.getTriangle(); + case MaterialShape.Shape.Diamond: return MaterialShapes.getDiamond(); + case MaterialShape.Shape.ClamShell: return MaterialShapes.getClamShell(); + case MaterialShape.Shape.Pentagon: return MaterialShapes.getPentagon(); + case MaterialShape.Shape.Gem: return MaterialShapes.getGem(); + case MaterialShape.Shape.Sunny: return MaterialShapes.getSunny(); + case MaterialShape.Shape.VerySunny: return MaterialShapes.getVerySunny(); + case MaterialShape.Shape.Cookie4Sided: return MaterialShapes.getCookie4Sided(); + case MaterialShape.Shape.Cookie6Sided: return MaterialShapes.getCookie6Sided(); + case MaterialShape.Shape.Cookie7Sided: return MaterialShapes.getCookie7Sided(); + case MaterialShape.Shape.Cookie9Sided: return MaterialShapes.getCookie9Sided(); + case MaterialShape.Shape.Cookie12Sided: return MaterialShapes.getCookie12Sided(); + case MaterialShape.Shape.Ghostish: return MaterialShapes.getGhostish(); + case MaterialShape.Shape.Clover4Leaf: return MaterialShapes.getClover4Leaf(); + case MaterialShape.Shape.Clover8Leaf: return MaterialShapes.getClover8Leaf(); + case MaterialShape.Shape.Burst: return MaterialShapes.getBurst(); + case MaterialShape.Shape.SoftBurst: return MaterialShapes.getSoftBurst(); + case MaterialShape.Shape.Boom: return MaterialShapes.getBoom(); + case MaterialShape.Shape.SoftBoom: return MaterialShapes.getSoftBoom(); + case MaterialShape.Shape.Flower: return MaterialShapes.getFlower(); + case MaterialShape.Shape.Puffy: return MaterialShapes.getPuffy(); + case MaterialShape.Shape.PuffyDiamond: return MaterialShapes.getPuffyDiamond(); + case MaterialShape.Shape.PixelCircle: return MaterialShapes.getPixelCircle(); + case MaterialShape.Shape.PixelTriangle: return MaterialShapes.getPixelTriangle(); + case MaterialShape.Shape.Bun: return MaterialShapes.getBun(); + case MaterialShape.Shape.Heart: return MaterialShapes.getHeart(); + default: return MaterialShapes.getCircle(); + } + } +} diff --git a/dots/.config/quickshell/ii/modules/common/widgets/shapes b/dots/.config/quickshell/ii/modules/common/widgets/shapes index 19a61bed7..3c4e4a374 160000 --- a/dots/.config/quickshell/ii/modules/common/widgets/shapes +++ b/dots/.config/quickshell/ii/modules/common/widgets/shapes @@ -1 +1 @@ -Subproject commit 19a61bed7e5ac338cfcfbf3329963704e6d658dc +Subproject commit 3c4e4a37451fc32c1755efd710d9e3a24b79986c diff --git a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml index 5feba6c72..bf5895e8a 100644 --- a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml +++ b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Layouts +import Qt5Compat.GraphicalEffects import Quickshell.Services.UPower import qs import qs.services @@ -7,6 +8,7 @@ import qs.modules.common import qs.modules.common.widgets import qs.modules.common.functions import qs.modules.bar as Bar +import Quickshell import Quickshell.Services.SystemTray MouseArea { @@ -124,6 +126,26 @@ MouseArea { Keys.onPressed: event => { root.context.resetClearTimer(); } + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Rectangle { + width: passwordBox.width - 8 + height: passwordBox.height + radius: height / 2 + } + } + + // We're drawing dots manually + color: ColorUtils.transparentize(Appearance.colors.colOnLayer1) + PasswordChars { + anchors { + fill: parent + leftMargin: passwordBox.padding + rightMargin: passwordBox.padding + } + length: root.context.currentText.length + } } ToolbarButton { diff --git a/dots/.config/quickshell/ii/modules/lock/PasswordChars.qml b/dots/.config/quickshell/ii/modules/lock/PasswordChars.qml new file mode 100644 index 000000000..058173000 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/lock/PasswordChars.qml @@ -0,0 +1,96 @@ +pragma ComponentBehavior: Bound +import QtQuick +import qs +import qs.services +import qs.modules.common +import qs.modules.common.widgets +import qs.modules.common.functions +import Quickshell + +StyledFlickable { + id: root + required property int length + contentWidth: dotsRow.implicitWidth + contentX: (Math.max(contentWidth - width, 0)) + Behavior on contentX { + animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this) + } + rightMargin: 14 + Row { + id: dotsRow + anchors { + left: parent.left + verticalCenter: parent.verticalCenter + leftMargin: 4 + } + spacing: 10 + Repeater { + model: ScriptModel { + values: Array(root.length) + } + delegate: Item { + id: charItem + required property int index + implicitWidth: 10 + implicitHeight: 10 + MaterialShape { + id: materialShape + anchors.centerIn: parent + property list charShapes: [ + MaterialShape.Shape.Clover4Leaf, + MaterialShape.Shape.Arrow, + MaterialShape.Shape.Pill, + MaterialShape.Shape.SoftBurst, + MaterialShape.Shape.Diamond, + MaterialShape.Shape.ClamShell, + MaterialShape.Shape.Pentagon, + ] + shape: charShapes[charItem.index % charShapes.length] + // Animate on appearance + color: Appearance.colors.colPrimary + implicitSize: 0 + opacity: 0 + scale: 0.5 + Component.onCompleted: { + appearAnim.start(); + } + ParallelAnimation { + id: appearAnim + NumberAnimation { + target: materialShape + properties: "opacity" + to: 1 + duration: 50 + easing.type: Appearance.animation.elementMoveFast.type + easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve + } + NumberAnimation { + target: materialShape + properties: "scale" + to: 1 + duration: 200 + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animationCurves.expressiveFastSpatial + } + NumberAnimation { + target: materialShape + properties: "implicitSize" + to: 34 + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animationCurves.expressiveFastSpatial + } + ColorAnimation { + target: materialShape + properties: "color" + from: Appearance.colors.colPrimary + to: Appearance.colors.colOnLayer1 + duration: 1000 + easing.type: Appearance.animation.elementMoveFast.type + easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve + } + } + } + } + } + } +} From 97b3f7ec55615d72887afcb8f354dec8679edd86 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 28 Oct 2025 22:48:08 +0100 Subject: [PATCH 40/94] settings: make right-clicking config file button copy path (#2112) --- .../ii/modules/common/widgets/NoticeBox.qml | 23 +++++++++++---- .../ii/modules/settings/QuickConfig.qml | 28 +++++++++++++++++++ dots/.config/quickshell/ii/settings.qml | 21 ++++++++++++-- 3 files changed, 63 insertions(+), 9 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/NoticeBox.qml b/dots/.config/quickshell/ii/modules/common/widgets/NoticeBox.qml index 6b110a9ae..c6a1d29c6 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/NoticeBox.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/NoticeBox.qml @@ -7,6 +7,7 @@ Rectangle { id: root property alias materialIcon: icon.text property alias text: noticeText.text + default property alias data: buttonRow.data radius: Appearance.rounding.normal color: Appearance.colors.colPrimaryContainer @@ -28,13 +29,23 @@ Rectangle { color: Appearance.colors.colOnPrimaryContainer } - StyledText { - id: noticeText + ColumnLayout { Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - text: "Notice message" - color: Appearance.colors.colOnPrimaryContainer - wrapMode: Text.WordWrap + spacing: 4 + + StyledText { + id: noticeText + Layout.fillWidth: true + text: "Notice message" + color: Appearance.colors.colOnPrimaryContainer + wrapMode: Text.WordWrap + } + + RowLayout { + id: buttonRow + visible: children.length > 0 + Layout.fillWidth: true + } } } } diff --git a/dots/.config/quickshell/ii/modules/settings/QuickConfig.qml b/dots/.config/quickshell/ii/modules/settings/QuickConfig.qml index aff06a384..c9c540afa 100644 --- a/dots/.config/quickshell/ii/modules/settings/QuickConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/QuickConfig.qml @@ -332,5 +332,33 @@ ContentPage { NoticeBox { Layout.fillWidth: true text: Translation.tr('Not all options are available in this app. You should also check the config file by hitting the "Config file" button on the topleft corner or opening %1 manually.').arg(Directories.shellConfigPath) + + Item { + Layout.fillWidth: true + } + RippleButtonWithIcon { + id: copyPathButton + property bool justCopied: false + Layout.fillWidth: false + buttonRadius: Appearance.rounding.small + materialIcon: justCopied ? "check" : "content_copy" + mainText: justCopied ? Translation.tr("Path copied") : Translation.tr("Copy path") + onClicked: { + copyPathButton.justCopied = true + Quickshell.clipboardText = FileUtils.trimFileProtocol(`${Directories.config}/illogical-impulse/config.json`); + revertTextTimer.restart(); + } + colBackground: ColorUtils.transparentize(Appearance.colors.colPrimaryContainer) + colBackgroundHover: Appearance.colors.colPrimaryContainerHover + colRipple: Appearance.colors.colPrimaryContainerActive + + Timer { + id: revertTextTimer + interval: 1500 + onTriggered: { + copyPathButton.justCopied = false + } + } + } } } diff --git a/dots/.config/quickshell/ii/settings.qml b/dots/.config/quickshell/ii/settings.qml index 6ab96c937..5d07c0502 100644 --- a/dots/.config/quickshell/ii/settings.qml +++ b/dots/.config/quickshell/ii/settings.qml @@ -10,6 +10,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Window +import Quickshell import qs.services import qs.modules.common import qs.modules.common.widgets @@ -169,15 +170,29 @@ ApplicationWindow { FloatingActionButton { id: fab - iconText: "edit" - buttonText: Translation.tr("Config file") + property bool justCopied: false + iconText: justCopied ? "check" : "edit" + buttonText: justCopied ? Translation.tr("Path copied") : Translation.tr("Config file") expanded: navRail.expanded downAction: () => { Qt.openUrlExternally(`${Directories.config}/illogical-impulse/config.json`); } + altAction: () => { + Quickshell.clipboardText = CF.FileUtils.trimFileProtocol(`${Directories.config}/illogical-impulse/config.json`); + fab.justCopied = true; + revertTextTimer.restart() + } + + Timer { + id: revertTextTimer + interval: 1500 + onTriggered: { + fab.justCopied = false; + } + } StyledToolTip { - text: Translation.tr("Open the shell config file.\nIf the button doesn't work or doesn't open in your favorite editor,\nyou can manually open ~/.config/illogical-impulse/config.json") + text: Translation.tr("Open the shell config file\nAlternatively right-click to copy path") } } From 4672138b009f25c1c2d546ca700e0c8f5730f809 Mon Sep 17 00:00:00 2001 From: clsty Date: Wed, 29 Oct 2025 08:15:47 +0800 Subject: [PATCH 41/94] Add auto_get_git_submodule() --- sdata/lib/functions.sh | 22 ++++++++++++++++++++++ sdata/subcmd-install/3.files.sh | 2 ++ 2 files changed, 24 insertions(+) diff --git a/sdata/lib/functions.sh b/sdata/lib/functions.sh index 496397f83..3282637bb 100644 --- a/sdata/lib/functions.sh +++ b/sdata/lib/functions.sh @@ -287,3 +287,25 @@ function check_disk_space() { return 0 } + +function auto_get_git_submodule(){ + local git_submodules_list=() + + while IFS= read -r path; do + [ -z "$path" ] && continue + git_submodules_list+=("$path") + done < <(git submodule status --recursive 2>/dev/null | awk '{print $2}') + + local missing=0 + + for p in "${git_submodules_list[@]}"; do + if [ ! -d "$p" ] || [ -z "$(ls -A "$p" 2>/dev/null)" ]; then + missing=1 + break + fi + done + + if [ "$missing" -eq 1 ]; then + x git submodule update --init --recursive + fi +} diff --git a/sdata/subcmd-install/3.files.sh b/sdata/subcmd-install/3.files.sh index cb294ce29..5b2ca8020 100644 --- a/sdata/subcmd-install/3.files.sh +++ b/sdata/subcmd-install/3.files.sh @@ -81,6 +81,8 @@ function auto_backup_configs(){ } ##################################################################################### +showfun auto_get_git_submodule +v auto_get_git_submodule # In case some dirs does not exists v mkdir -p $XDG_BIN_HOME $XDG_CACHE_HOME $XDG_CONFIG_HOME $XDG_DATA_HOME From 21276f4d1e290339dc7575df8217046b2ea070b1 Mon Sep 17 00:00:00 2001 From: clsty Date: Wed, 29 Oct 2025 15:39:18 +0800 Subject: [PATCH 42/94] Improve order of inst scripts --- sdata/subcmd-install/3.files.sh | 2 +- sdata/subcmd-install/options.sh | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sdata/subcmd-install/3.files.sh b/sdata/subcmd-install/3.files.sh index 5b2ca8020..ff1ec909f 100644 --- a/sdata/subcmd-install/3.files.sh +++ b/sdata/subcmd-install/3.files.sh @@ -115,6 +115,7 @@ case $SKIP_MISCCONF in elif [ -f "dots/.config/$i" ];then warning_rsync; v rsync -av "dots/.config/$i" "$XDG_CONFIG_HOME/$i" fi done + warning_rsync; v rsync -av "dots/.local/share/konsole/" "${XDG_DATA_HOME:-$HOME/.local/share}"/konsole/ ;; esac @@ -190,7 +191,6 @@ declare -a arg_excludes=() # since the files here come from different places, not only about one program. # v rsync -av "dots/.local/bin/" "$XDG_BIN_HOME" # No longer needed since scripts are no longer in ~/.local/bin warning_rsync; v rsync -av "dots/.local/share/icons/" "${XDG_DATA_HOME:-$HOME/.local/share}"/icons/ -warning_rsync; v rsync -av "dots/.local/share/konsole/" "${XDG_DATA_HOME:-$HOME/.local/share}"/konsole/ # Prevent hyprland from not fully loaded sleep 1 diff --git a/sdata/subcmd-install/options.sh b/sdata/subcmd-install/options.sh index 46a31d71f..347cb819a 100644 --- a/sdata/subcmd-install/options.sh +++ b/sdata/subcmd-install/options.sh @@ -14,11 +14,11 @@ Options for install: --skip-allsetups Skip the whole process setting up permissions/services etc --skip-allfiles Skip the whole process copying configuration files -s, --skip-sysupdate Skip system package upgrade e.g. \"sudo pacman -Syu\" + --skip-plasmaintg Skip installing plasma-browser-integration --skip-backup Skip backup conflicting files --skip-quickshell Skip installing the config for Quickshell --skip-hyprland Skip installing the config for Hyprland --skip-fish Skip installing the config for Fish - --skip-plasmaintg Skip installing plasma-browser-integration --skip-miscconf Skip copying the dirs and files to \".configs\" except for Quickshell, Fish and Hyprland --exp-files Use experimental script for the third step copying files @@ -34,7 +34,7 @@ cleancache(){ # `man getopt` to see more para=$(getopt \ -o hfk:cs \ - -l help,force,fontset:,clean,skip-allgreeting,skip-alldeps,skip-allsetups,skip-allfiles,skip-sysupdate,skip-backup,skip-quickshell,skip-fish,skip-hyprland,skip-plasmaintg,skip-miscconf,exp-files,via-nix \ + -l help,force,fontset:,clean,skip-allgreeting,skip-alldeps,skip-allsetups,skip-allfiles,skip-sysupdate,skip-plasmaintg,skip-backup,skip-quickshell,skip-fish,skip-hyprland,skip-miscconf,exp-files,via-nix \ -n "$0" -- "$@") [ $? != 0 ] && echo "$0: Error when getopt, please recheck parameters." && exit 1 ##################################################################################### @@ -64,12 +64,12 @@ while true ; do --skip-allsetups) SKIP_ALLSETUPS=true;shift;; --skip-allfiles) SKIP_ALLFILES=true;shift;; -s|--skip-sysupdate) SKIP_SYSUPDATE=true;shift;; + --skip-plasmaintg) SKIP_PLASMAINTG=true;shift;; --skip-backup) SKIP_BACKUP=true;shift;; --skip-hyprland) SKIP_HYPRLAND=true;shift;; --skip-fish) SKIP_FISH=true;shift;; --skip-quickshell) SKIP_QUICKSHELL=true;shift;; --skip-miscconf) SKIP_MISCCONF=true;shift;; - --skip-plasmaintg) SKIP_PLASMAINTG=true;shift;; --exp-files) EXPERIMENTAL_FILES_SCRIPT=true;shift;; --via-nix) INSTALL_VIA_NIX=true;shift;; From 44e384a256537bd3d8b31aa1d55342d9e5ed5e8a Mon Sep 17 00:00:00 2001 From: clsty Date: Wed, 29 Oct 2025 16:09:35 +0800 Subject: [PATCH 43/94] Add --core option --- sdata/subcmd-install/options.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sdata/subcmd-install/options.sh b/sdata/subcmd-install/options.sh index 347cb819a..06b8e147a 100644 --- a/sdata/subcmd-install/options.sh +++ b/sdata/subcmd-install/options.sh @@ -21,6 +21,7 @@ Options for install: --skip-fish Skip installing the config for Fish --skip-miscconf Skip copying the dirs and files to \".configs\" except for Quickshell, Fish and Hyprland + --core Alias of --skip-{plasmaintg,fish,miscconf} --exp-files Use experimental script for the third step copying files --fontset (Unavailable yet) Use a set of pre-defined font and config --via-nix (Unavailable yet) Use Nix to install dependencies @@ -34,7 +35,7 @@ cleancache(){ # `man getopt` to see more para=$(getopt \ -o hfk:cs \ - -l help,force,fontset:,clean,skip-allgreeting,skip-alldeps,skip-allsetups,skip-allfiles,skip-sysupdate,skip-plasmaintg,skip-backup,skip-quickshell,skip-fish,skip-hyprland,skip-miscconf,exp-files,via-nix \ + -l help,force,fontset:,clean,skip-allgreeting,skip-alldeps,skip-allsetups,skip-allfiles,skip-sysupdate,skip-plasmaintg,skip-backup,skip-quickshell,skip-fish,skip-hyprland,skip-miscconf,core,exp-files,via-nix \ -n "$0" -- "$@") [ $? != 0 ] && echo "$0: Error when getopt, please recheck parameters." && exit 1 ##################################################################################### @@ -70,6 +71,7 @@ while true ; do --skip-fish) SKIP_FISH=true;shift;; --skip-quickshell) SKIP_QUICKSHELL=true;shift;; --skip-miscconf) SKIP_MISCCONF=true;shift;; + --core) SKIP_PLASMAINTG=true;SKIP_FISH=true;SKIP_MISCCONF=true;shift;; --exp-files) EXPERIMENTAL_FILES_SCRIPT=true;shift;; --via-nix) INSTALL_VIA_NIX=true;shift;; From 41cf490681d63e03fd989b2441007b6c4fd96776 Mon Sep 17 00:00:00 2001 From: clsty Date: Wed, 29 Oct 2025 17:01:45 +0800 Subject: [PATCH 44/94] Update online script url --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 85a0330c7..ffedf84a6 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@
Installation (illogical-impulse Quickshell) - - Just run `bash <(curl -s https://ii.clsty.link/setup)` + - Just run `bash <(curl -s https://ii.clsty.link/get)` - Or, clone this repo and run `./setup install` - See [document](https://ii.clsty.link/en/ii-qs/01setup/) for details. - **Default keybinds**: Should be somewhat familiar to Windows or GNOME users. Important ones: From 26361718a77e2c5e45d639794419961f7016e141 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:23:14 +0100 Subject: [PATCH 45/94] background: only opaque when wallpaper safety triggered --- dots/.config/quickshell/ii/modules/background/Background.qml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/background/Background.qml b/dots/.config/quickshell/ii/modules/background/Background.qml index 4aed1c08c..71bae0d77 100644 --- a/dots/.config/quickshell/ii/modules/background/Background.qml +++ b/dots/.config/quickshell/ii/modules/background/Background.qml @@ -96,7 +96,10 @@ Variants { left: true right: true } - color: CF.ColorUtils.transparentize(CF.ColorUtils.mix(Appearance.colors.colLayer0, Appearance.colors.colPrimary, 0.75), (bgRoot.wallpaperIsVideo ? 1 : 0)) + color: { + if (!bgRoot.wallpaperSafetyTriggered || bgRoot.wallpaperIsVideo) return "transparent"; + return CF.ColorUtils.mix(Appearance.colors.colLayer0, Appearance.colors.colPrimary, 0.75) + } Behavior on color { animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) } From f95165185c19000f9e120c3aaf9ad015c03d6dba Mon Sep 17 00:00:00 2001 From: clsty Date: Wed, 29 Oct 2025 17:23:26 +0800 Subject: [PATCH 46/94] Implement --fontset (#2307) --- sdata/subcmd-install/3.files.sh | 13 +++++++++++-- sdata/subcmd-install/options.sh | 16 +++++++++------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/sdata/subcmd-install/3.files.sh b/sdata/subcmd-install/3.files.sh index ff1ec909f..2c3f989ba 100644 --- a/sdata/subcmd-install/3.files.sh +++ b/sdata/subcmd-install/3.files.sh @@ -104,11 +104,11 @@ fi # original dotfiles and new ones in the SAME DIRECTORY # (eg. in ~/.config/hypr) won't be mixed together -# MISC (For dots/.config/* but not quickshell, not fish, not Hyprland) +# MISC (For dots/.config/* but not quickshell, not fish, not Hyprland, not fontconfig) case $SKIP_MISCCONF in true) sleep 0;; *) - for i in $(find dots/.config/ -mindepth 1 -maxdepth 1 ! -name 'quickshell' ! -name 'fish' ! -name 'hypr' -exec basename {} \;); do + for i in $(find dots/.config/ -mindepth 1 -maxdepth 1 ! -name 'quickshell' ! -name 'fish' ! -name 'hypr' ! -name 'fontconfig' -exec basename {} \;); do # i="dots/.config/$i" echo "[$0]: Found target: dots/.config/$i" if [ -d "dots/.config/$i" ];then warning_rsync; v rsync -av --delete "dots/.config/$i/" "$XDG_CONFIG_HOME/$i/" @@ -134,6 +134,15 @@ case $SKIP_FISH in ;; esac +case $SKIP_FONTCONFIG in + true) sleep 0;; + *) + case "$II_FONTSET_NAME" in + "") warning_rsync; v rsync -av --delete dots/.config/fontconfig/ "$XDG_CONFIG_HOME"/fontconfig/ ;; + *) warning_rsync; v rsync -av --delete dots-extra/fontsets/$II_FONTSET_NAME/ "$XDG_CONFIG_HOME"/fontconfig/ ;; + esac;; +esac + # For Hyprland declare -a arg_excludes=() arg_excludes+=(--exclude '/custom') diff --git a/sdata/subcmd-install/options.sh b/sdata/subcmd-install/options.sh index 06b8e147a..9d09b6541 100644 --- a/sdata/subcmd-install/options.sh +++ b/sdata/subcmd-install/options.sh @@ -19,9 +19,10 @@ Options for install: --skip-quickshell Skip installing the config for Quickshell --skip-hyprland Skip installing the config for Hyprland --skip-fish Skip installing the config for Fish + --skip-fontconfig Skip installing the config for fontconfig --skip-miscconf Skip copying the dirs and files to \".configs\" except for Quickshell, Fish and Hyprland - --core Alias of --skip-{plasmaintg,fish,miscconf} + --core Alias of --skip-{plasmaintg,fish,miscconf,fontconfig} --exp-files Use experimental script for the third step copying files --fontset (Unavailable yet) Use a set of pre-defined font and config --via-nix (Unavailable yet) Use Nix to install dependencies @@ -35,7 +36,7 @@ cleancache(){ # `man getopt` to see more para=$(getopt \ -o hfk:cs \ - -l help,force,fontset:,clean,skip-allgreeting,skip-alldeps,skip-allsetups,skip-allfiles,skip-sysupdate,skip-plasmaintg,skip-backup,skip-quickshell,skip-fish,skip-hyprland,skip-miscconf,core,exp-files,via-nix \ + -l help,force,fontset:,clean,skip-allgreeting,skip-alldeps,skip-allsetups,skip-allfiles,skip-sysupdate,skip-plasmaintg,skip-backup,skip-quickshell,skip-fish,skip-hyprland,skip-fontconfig,skip-miscconf,core,exp-files,via-nix \ -n "$0" -- "$@") [ $? != 0 ] && echo "$0: Error when getopt, please recheck parameters." && exit 1 ##################################################################################### @@ -70,17 +71,18 @@ while true ; do --skip-hyprland) SKIP_HYPRLAND=true;shift;; --skip-fish) SKIP_FISH=true;shift;; --skip-quickshell) SKIP_QUICKSHELL=true;shift;; + --skip-fontconfig) SKIP_FONTCONFIG=true;shift;; --skip-miscconf) SKIP_MISCCONF=true;shift;; - --core) SKIP_PLASMAINTG=true;SKIP_FISH=true;SKIP_MISCCONF=true;shift;; + --core) SKIP_PLASMAINTG=true;SKIP_FISH=true;SKIP_FONTCONFIG=true;SKIP_MISCCONF=true;shift;; --exp-files) EXPERIMENTAL_FILES_SCRIPT=true;shift;; --via-nix) INSTALL_VIA_NIX=true;shift;; ## Ones with parameter --fontset) - case $2 in - "default"|"zh-CN"|"vi") fontset="$2";; - *) echo -e "Wrong argument for $1.";exit 1;; - esac;echo "The fontset is ${fontset}.";shift 2;; + if [[ -d "${REPO_ROOT}/dots-extra/fontsets/$2" ]]; + then echo "Using fontset \"$2\".";II_FONTSET_NAME="$2";shift 2 + else echo "Wrong argument for $1.";exit 1 + fi;; ## Ending --) break ;; From ede90eb282a283fa1eb07c249081b14666f95787 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:24:11 +0100 Subject: [PATCH 47/94] sidebar: anime: pull to load more --- .../widgets/MaterialLoadingIndicator.qml | 90 +++++++++++++++++++ .../ii/modules/sidebarLeft/Anime.qml | 67 +++++++------- 2 files changed, 124 insertions(+), 33 deletions(-) create mode 100644 dots/.config/quickshell/ii/modules/common/widgets/MaterialLoadingIndicator.qml diff --git a/dots/.config/quickshell/ii/modules/common/widgets/MaterialLoadingIndicator.qml b/dots/.config/quickshell/ii/modules/common/widgets/MaterialLoadingIndicator.qml new file mode 100644 index 000000000..e810ca2e1 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/widgets/MaterialLoadingIndicator.qml @@ -0,0 +1,90 @@ +pragma ComponentBehavior: Bound +import QtQuick +import qs.modules.common +import qs.modules.common.functions +import qs.modules.common.widgets + +Rectangle { + id: root + + property bool loading: true + property double pullProgress: 0 + + // Size, color + property double implicitSize: 48 + implicitWidth: implicitSize + implicitHeight: implicitSize + radius: Math.min(width, height) / 2 + color: Appearance.colors.colPrimaryContainer + property double baseShapeSize: root.implicitSize * 1.3 + property double leapZoomSize: root.baseShapeSize * 1.3 + property double leapZoomProgress: 0 + + // Shape + property list shapes: [ + MaterialShape.Shape.SoftBurst, + MaterialShape.Shape.Cookie9Sided, + MaterialShape.Shape.Pentagon, + MaterialShape.Shape.Pill, + MaterialShape.Shape.Sunny, + MaterialShape.Shape.Cookie4Sided, + MaterialShape.Shape.Oval, + ] + property int shapeIndex: 0 + property double pullRotation: root.loading ? 0 : -(root.pullProgress * 360) + property double continuousRotation: 0 + property double leapRotation: 0 + rotation: pullRotation + continuousRotation + leapRotation + + RotationAnimation on continuousRotation { + running: root.loading + duration: 12000 + easing.type: Easing.Linear + loops: Animation.Infinite + from: 0 + to: 360 + } + Timer { + interval: 800 + running: root.loading + repeat: true + onTriggered: leapAnimation.start() + } + ParallelAnimation { + id: leapAnimation + PropertyAction { target: root; property: "shapeIndex"; value: (root.shapeIndex + 1) % root.shapes.length } + RotationAnimation { + target: root + direction: RotationAnimation.Shortest + property: "leapRotation" + to: (root.leapRotation + 90) % 360 + duration: 350 + easing.type: Easing.InOutQuad + } + NumberAnimation { + target: root + property: "leapZoomProgress" + from: 0 + to: 1 + duration: 750 + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animationCurves.standard + } + } + + MaterialShape { + id: shape + anchors.centerIn: parent + shape: root.shapes[root.shapeIndex] + implicitSize: { + const leapZoomDiff = root.leapZoomSize - root.baseShapeSize + const progressFirstHalf = Math.min(root.leapZoomProgress, 0.5) * 2; + const progressSecondHalf = Math.max(root.leapZoomProgress - 0.5, 0) * 2; + print("progress", root.leapZoomProgress, "zoom", root.baseShapeSize + leapZoomDiff * progressFirstHalf - leapZoomDiff * progressSecondHalf) + return root.baseShapeSize + leapZoomDiff * progressFirstHalf - leapZoomDiff * progressSecondHalf; + } + color: Appearance.colors.colOnPrimaryContainer + + animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml index c673f6304..1b101d42e 100644 --- a/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml +++ b/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml @@ -23,12 +23,21 @@ Item { property var suggestionQuery: "" property var suggestionList: [] + property bool pullLoading: false + property int pullLoadingGap: 80 + property real normalizedPullDistance: Math.max(0, (1 - Math.exp(-booruResponseListView.verticalOvershoot / 50))) + Connections { target: Booru function onTagSuggestion(query, suggestions) { root.suggestionQuery = query; root.suggestionList = suggestions; } + function onRunningRequestsChanged() { + if (Booru.runningRequests === 0) { + root.pullLoading = false; + } + } } property var allCommands: [ @@ -53,6 +62,8 @@ Item { if (root.responses.length > 0) { const lastResponse = root.responses[root.responses.length - 1]; root.handleInput(`${lastResponse.tags.join(" ")} ${parseInt(lastResponse.page) + 1}`); + } else { + root.handleInput(""); } } }, @@ -176,6 +187,14 @@ Item { downloadPath: root.downloadPath nsfwPath: root.nsfwPath } + + onDragEnded: { // Pull to load more + const gap = booruResponseListView.verticalOvershoot + if (gap > root.pullLoadingGap) { + root.pullLoading = true + root.handleInput(`${root.commandPrefix}next`) + } + } } PagePlaceholder { @@ -192,42 +211,24 @@ Item { target: booruResponseListView } - Item { // Queries awaiting response + MaterialLoadingIndicator { + id: loadingIndicator z: 4 - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.margins: 10 - implicitHeight: pendingBackground.implicitHeight - opacity: Booru.runningRequests > 0 ? 1 : 0 - visible: opacity > 0 - - Behavior on opacity { - animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this) - } - - Rectangle { - id: pendingBackground - color: Appearance.m3colors.m3inverseSurface - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - implicitHeight: pendingText.implicitHeight + 12 * 2 - radius: Appearance.rounding.verysmall - - StyledText { - id: pendingText - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 12 - anchors.rightMargin: 12 - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: Appearance.font.pixelSize.smaller - color: Appearance.m3colors.m3inverseOnSurface - wrapMode: Text.Wrap - text: Translation.tr("%1 queries pending").arg(Booru.runningRequests) + anchors { + horizontalCenter: parent.horizontalCenter + bottom: parent.bottom + bottomMargin: 20 + (root.pullLoading ? 0 : Math.max(0, (root.normalizedPullDistance - 0.5) * 36)) + Behavior on bottomMargin { + NumberAnimation { + duration: 200 + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animationCurves.expressiveFastSpatial + } } } + loading: root.pullLoading || Booru.runningRequests > 0 + pullProgress: Math.min(1, booruResponseListView.verticalOvershoot / root.pullLoadingGap) + scale: root.pullLoading ? 1 : Math.min(1, root.normalizedPullDistance * 2) } } From e1a8ba09f11a97d067eb5c503cf2bbf587012841 Mon Sep 17 00:00:00 2001 From: clsty Date: Wed, 29 Oct 2025 17:31:01 +0800 Subject: [PATCH 48/94] Move arabic fontconfig into dots-extra/fontsets/ar --- dots-extra/fontsets/ar/conf.d | 19 +++++++++++++++++++ dots/.config/fontconfig/conf.d | 16 +++------------- 2 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 dots-extra/fontsets/ar/conf.d diff --git a/dots-extra/fontsets/ar/conf.d b/dots-extra/fontsets/ar/conf.d new file mode 100644 index 000000000..016af78bc --- /dev/null +++ b/dots-extra/fontsets/ar/conf.d @@ -0,0 +1,19 @@ + + + + + + none + + + + + + + sans-serif + + + Noto Sans Arabic + + + diff --git a/dots/.config/fontconfig/conf.d b/dots/.config/fontconfig/conf.d index 016af78bc..f450859f1 100644 --- a/dots/.config/fontconfig/conf.d +++ b/dots/.config/fontconfig/conf.d @@ -1,19 +1,9 @@ - - - none - - - - - - - sans-serif - - - Noto Sans Arabic + + + none From e9c3eca68a99e520843561074bc4fe8bc02a7af5 Mon Sep 17 00:00:00 2001 From: clsty Date: Wed, 29 Oct 2025 17:44:32 +0800 Subject: [PATCH 49/94] Update 3.files.sh about warning_rsync() --- sdata/subcmd-install/3.files.sh | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/sdata/subcmd-install/3.files.sh b/sdata/subcmd-install/3.files.sh index 2c3f989ba..71c04e163 100644 --- a/sdata/subcmd-install/3.files.sh +++ b/sdata/subcmd-install/3.files.sh @@ -6,9 +6,15 @@ printf "${STY_CYAN}[$0]: 3. Copying config files\n${STY_RST}" # TODO: https://github.com/end-4/dots-hyprland/issues/2137 -function warning_rsync(){ +function warning_rsync_delete(){ printf "${STY_YELLOW}" - printf "The commands using rsync will overwrite the destination when it exists already.\n" + printf "The command below uses --delete for rsync which overwrites the destination folder.\n" + printf "${STY_RST}" +} + +function warning_rsync_normal(){ + printf "${STY_YELLOW}" + printf "The command below uses rsync which overwrites the destination.\n" printf "${STY_RST}" } @@ -85,7 +91,7 @@ showfun auto_get_git_submodule v auto_get_git_submodule # In case some dirs does not exists -v mkdir -p $XDG_BIN_HOME $XDG_CACHE_HOME $XDG_CONFIG_HOME $XDG_DATA_HOME +v mkdir -p $XDG_BIN_HOME $XDG_CACHE_HOME $XDG_CONFIG_HOME $XDG_DATA_HOME/icons if [[ ! "${SKIP_BACKUP}" == true ]]; then case $ask in @@ -111,11 +117,11 @@ case $SKIP_MISCCONF in for i in $(find dots/.config/ -mindepth 1 -maxdepth 1 ! -name 'quickshell' ! -name 'fish' ! -name 'hypr' ! -name 'fontconfig' -exec basename {} \;); do # i="dots/.config/$i" echo "[$0]: Found target: dots/.config/$i" - if [ -d "dots/.config/$i" ];then warning_rsync; v rsync -av --delete "dots/.config/$i/" "$XDG_CONFIG_HOME/$i/" - elif [ -f "dots/.config/$i" ];then warning_rsync; v rsync -av "dots/.config/$i" "$XDG_CONFIG_HOME/$i" + if [ -d "dots/.config/$i" ];then warning_rsync_delete; v rsync -av --delete "dots/.config/$i/" "$XDG_CONFIG_HOME/$i/" + elif [ -f "dots/.config/$i" ];then warning_rsync_normal; v rsync -av "dots/.config/$i" "$XDG_CONFIG_HOME/$i" fi done - warning_rsync; v rsync -av "dots/.local/share/konsole/" "${XDG_DATA_HOME:-$HOME/.local/share}"/konsole/ + warning_rsync_delete; v rsync -av "dots/.local/share/konsole/" "${XDG_DATA_HOME:-$HOME/.local/share}"/konsole/ ;; esac @@ -123,14 +129,14 @@ case $SKIP_QUICKSHELL in true) sleep 0;; *) # Should overwriting the whole directory not only ~/.config/quickshell/ii/ cuz https://github.com/end-4/dots-hyprland/issues/2294#issuecomment-3448671064 - warning_rsync; v rsync -av --delete dots/.config/quickshell/ "$XDG_CONFIG_HOME"/quickshell/ + warning_rsync_delete; v rsync -av --delete dots/.config/quickshell/ "$XDG_CONFIG_HOME"/quickshell/ ;; esac case $SKIP_FISH in true) sleep 0;; *) - warning_rsync; v rsync -av --delete dots/.config/fish/ "$XDG_CONFIG_HOME"/fish/ + warning_rsync_delete; v rsync -av --delete dots/.config/fish/ "$XDG_CONFIG_HOME"/fish/ ;; esac @@ -138,8 +144,8 @@ case $SKIP_FONTCONFIG in true) sleep 0;; *) case "$II_FONTSET_NAME" in - "") warning_rsync; v rsync -av --delete dots/.config/fontconfig/ "$XDG_CONFIG_HOME"/fontconfig/ ;; - *) warning_rsync; v rsync -av --delete dots-extra/fontsets/$II_FONTSET_NAME/ "$XDG_CONFIG_HOME"/fontconfig/ ;; + "") warning_rsync_delete; v rsync -av --delete dots/.config/fontconfig/ "$XDG_CONFIG_HOME"/fontconfig/ ;; + *) warning_rsync_delete; v rsync -av --delete dots-extra/fontsets/$II_FONTSET_NAME/ "$XDG_CONFIG_HOME"/fontconfig/ ;; esac;; esac @@ -152,7 +158,7 @@ arg_excludes+=(--exclude '/hyprland.conf') case $SKIP_HYPRLAND in true) sleep 0;; *) - warning_rsync; v rsync -av --delete "${arg_excludes[@]}" dots/.config/hypr/ "$XDG_CONFIG_HOME"/hypr/ + warning_rsync_delete; v rsync -av --delete "${arg_excludes[@]}" dots/.config/hypr/ "$XDG_CONFIG_HOME"/hypr/ t="$XDG_CONFIG_HOME/hypr/hyprland.conf" if [ -f $t ];then echo -e "${STY_BLUE}[$0]: \"$t\" already exists.${STY_RST}" @@ -189,7 +195,7 @@ case $SKIP_HYPRLAND in echo -e "${STY_BLUE}[$0]: \"$t\" already exists, will not do anything.${STY_RST}" else echo -e "${STY_YELLOW}[$0]: \"$t\" does not exist yet.${STY_RST}" - warning_rsync; v rsync -av --delete dots/.config/hypr/custom/ $t/ + v rsync -av --delete dots/.config/hypr/custom/ $t/ fi ;; esac @@ -199,7 +205,7 @@ declare -a arg_excludes=() # some foldes (eg. .local/bin) should be processed separately to avoid `--delete' for rsync, # since the files here come from different places, not only about one program. # v rsync -av "dots/.local/bin/" "$XDG_BIN_HOME" # No longer needed since scripts are no longer in ~/.local/bin -warning_rsync; v rsync -av "dots/.local/share/icons/" "${XDG_DATA_HOME:-$HOME/.local/share}"/icons/ +v cp -f "dots/.local/share/icons/illogical-impulse.svg" "${XDG_DATA_HOME}"/icons/illogical-impulse.svg # Prevent hyprland from not fully loaded sleep 1 From d5e9b20aecf6ea59c1b86441b6594d6aec863c4a Mon Sep 17 00:00:00 2001 From: clsty Date: Wed, 29 Oct 2025 17:49:28 +0800 Subject: [PATCH 50/94] Update help --- sdata/subcmd-install/options.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdata/subcmd-install/options.sh b/sdata/subcmd-install/options.sh index 9d09b6541..c99bf1b52 100644 --- a/sdata/subcmd-install/options.sh +++ b/sdata/subcmd-install/options.sh @@ -24,7 +24,8 @@ Options for install: Quickshell, Fish and Hyprland --core Alias of --skip-{plasmaintg,fish,miscconf,fontconfig} --exp-files Use experimental script for the third step copying files - --fontset (Unavailable yet) Use a set of pre-defined font and config + --fontset Use a set of pre-defined font and config. + Possible values of : $(ls -A ${REPO_ROOT}/dots-extra/fontsets) --via-nix (Unavailable yet) Use Nix to install dependencies " } From 7b278aeff7ea5b0a86dd0ad8a85e5bfee3cde507 Mon Sep 17 00:00:00 2001 From: clsty Date: Wed, 29 Oct 2025 17:50:12 +0800 Subject: [PATCH 51/94] Update help --- sdata/subcmd-install/options.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdata/subcmd-install/options.sh b/sdata/subcmd-install/options.sh index c99bf1b52..dba8a4430 100644 --- a/sdata/subcmd-install/options.sh +++ b/sdata/subcmd-install/options.sh @@ -24,7 +24,7 @@ Options for install: Quickshell, Fish and Hyprland --core Alias of --skip-{plasmaintg,fish,miscconf,fontconfig} --exp-files Use experimental script for the third step copying files - --fontset Use a set of pre-defined font and config. + --fontset Use a set of pre-defined font and config (currently only fontconfig). Possible values of : $(ls -A ${REPO_ROOT}/dots-extra/fontsets) --via-nix (Unavailable yet) Use Nix to install dependencies " From 8b10ec2cfb1ca7a435f4688431d0c2ab4beb8686 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 11:04:00 +0100 Subject: [PATCH 52/94] sidebar: anime: fix loading indicator showing when navigating w/ keys --- .../cookieClock/dateIndicator/BubbleDate.qml | 7 ++++--- .../common/widgets/MaterialLoadingIndicator.qml | 5 ++--- .../quickshell/ii/modules/common/widgets/shapes | 2 +- .../quickshell/ii/modules/lock/PasswordChars.qml | 2 +- .../quickshell/ii/modules/sidebarLeft/Anime.qml | 16 +++++++++------- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/background/cookieClock/dateIndicator/BubbleDate.qml b/dots/.config/quickshell/ii/modules/background/cookieClock/dateIndicator/BubbleDate.qml index 35659e4fc..3a7313600 100644 --- a/dots/.config/quickshell/ii/modules/background/cookieClock/dateIndicator/BubbleDate.qml +++ b/dots/.config/quickshell/ii/modules/background/cookieClock/dateIndicator/BubbleDate.qml @@ -13,13 +13,14 @@ Item { text: Qt.locale().toString(DateTime.clock.date, root.isMonth ? "MM" : "d") - MaterialCookie { + MaterialShape { + id: bubble z: 5 - sides: root.isMonth ? 1 : 4 + // sides: root.isMonth ? 1 : 4 + shape: root.isMonth ? MaterialShape.Shape.Pill : MaterialShape.Shape.Pentagon anchors.centerIn: parent color: root.isMonth ? Appearance.colors.colPrimaryContainer : Appearance.colors.colTertiaryContainer implicitSize: targetSize - constantlyRotate: Config.options.background.clock.cookie.constantlyRotate } StyledText { diff --git a/dots/.config/quickshell/ii/modules/common/widgets/MaterialLoadingIndicator.qml b/dots/.config/quickshell/ii/modules/common/widgets/MaterialLoadingIndicator.qml index e810ca2e1..502cd1a3f 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/MaterialLoadingIndicator.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/MaterialLoadingIndicator.qml @@ -16,8 +16,8 @@ Rectangle { implicitHeight: implicitSize radius: Math.min(width, height) / 2 color: Appearance.colors.colPrimaryContainer - property double baseShapeSize: root.implicitSize * 1.3 - property double leapZoomSize: root.baseShapeSize * 1.3 + property double baseShapeSize: root.implicitSize * 0.7 + property double leapZoomSize: root.baseShapeSize * 1.2 property double leapZoomProgress: 0 // Shape @@ -80,7 +80,6 @@ Rectangle { const leapZoomDiff = root.leapZoomSize - root.baseShapeSize const progressFirstHalf = Math.min(root.leapZoomProgress, 0.5) * 2; const progressSecondHalf = Math.max(root.leapZoomProgress - 0.5, 0) * 2; - print("progress", root.leapZoomProgress, "zoom", root.baseShapeSize + leapZoomDiff * progressFirstHalf - leapZoomDiff * progressSecondHalf) return root.baseShapeSize + leapZoomDiff * progressFirstHalf - leapZoomDiff * progressSecondHalf; } color: Appearance.colors.colOnPrimaryContainer diff --git a/dots/.config/quickshell/ii/modules/common/widgets/shapes b/dots/.config/quickshell/ii/modules/common/widgets/shapes index 3c4e4a374..2e9263e01 160000 --- a/dots/.config/quickshell/ii/modules/common/widgets/shapes +++ b/dots/.config/quickshell/ii/modules/common/widgets/shapes @@ -1 +1 @@ -Subproject commit 3c4e4a37451fc32c1755efd710d9e3a24b79986c +Subproject commit 2e9263e011e8dcf00a66da5a2e3fe4df160b41b9 diff --git a/dots/.config/quickshell/ii/modules/lock/PasswordChars.qml b/dots/.config/quickshell/ii/modules/lock/PasswordChars.qml index 058173000..79ffc9464 100644 --- a/dots/.config/quickshell/ii/modules/lock/PasswordChars.qml +++ b/dots/.config/quickshell/ii/modules/lock/PasswordChars.qml @@ -75,7 +75,7 @@ StyledFlickable { NumberAnimation { target: materialShape properties: "implicitSize" - to: 34 + to: 18 easing.type: Easing.BezierSpline easing.bezierCurve: Appearance.animationCurves.expressiveFastSpatial } diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml index 1b101d42e..4b398311e 100644 --- a/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml +++ b/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml @@ -25,7 +25,7 @@ Item { property bool pullLoading: false property int pullLoadingGap: 80 - property real normalizedPullDistance: Math.max(0, (1 - Math.exp(-booruResponseListView.verticalOvershoot / 50))) + property real normalizedPullDistance: Math.max(0, (1 - Math.exp(-booruResponseListView.verticalOvershoot / 50)) * booruResponseListView.dragging) Connections { target: Booru @@ -96,10 +96,7 @@ Item { } } else if (inputText.trim() == "+") { - if (root.responses.length > 0) { - const lastResponse = root.responses[root.responses.length - 1] - root.handleInput(lastResponse.tags.join(" ") + ` ${parseInt(lastResponse.page) + 1}`); - } + root.handleInput(`${root.commandPrefix}next`); } else { // Create tag list @@ -126,13 +123,18 @@ Item { tagInputField.forceActiveFocus() if (event.modifiers === Qt.NoModifier) { if (event.key === Qt.Key_PageUp) { + if (booruResponseListView.atYBeginning) return; booruResponseListView.contentY = Math.max(0, booruResponseListView.contentY - booruResponseListView.height / 2) event.accepted = true } else if (event.key === Qt.Key_PageDown) { + if (booruResponseListView.atYEnd) return; booruResponseListView.contentY = Math.min(booruResponseListView.contentHeight - booruResponseListView.height / 2, booruResponseListView.contentY + booruResponseListView.height / 2) event.accepted = true } } + if ((event.modifiers & Qt.ControlModifier) && (event.modifiers & Qt.ShiftModifier) && event.key === Qt.Key_O) { + Booru.clearResponses() + } } @@ -217,7 +219,7 @@ Item { anchors { horizontalCenter: parent.horizontalCenter bottom: parent.bottom - bottomMargin: 20 + (root.pullLoading ? 0 : Math.max(0, (root.normalizedPullDistance - 0.5) * 36)) + bottomMargin: 20 + (root.pullLoading ? 0 : Math.max(0, (root.normalizedPullDistance - 0.5) * 50)) Behavior on bottomMargin { NumberAnimation { duration: 200 @@ -227,7 +229,7 @@ Item { } } loading: root.pullLoading || Booru.runningRequests > 0 - pullProgress: Math.min(1, booruResponseListView.verticalOvershoot / root.pullLoadingGap) + pullProgress: Math.min(1, booruResponseListView.verticalOvershoot / root.pullLoadingGap * booruResponseListView.dragging) scale: root.pullLoading ? 1 : Math.min(1, root.normalizedPullDistance * 2) } } From 05f3e52f55c97c6552fd88481a8f830b6fa0743f Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 11:17:03 +0100 Subject: [PATCH 53/94] make notifs and page placeholder use new material shapes --- ...Symbol.qml => MaterialShapeWrappedMaterialSymbol.qml} | 4 ++-- .../ii/modules/common/widgets/NotificationAppIcon.qml | 9 ++++++--- .../.config/quickshell/ii/modules/sidebarLeft/AiChat.qml | 1 + dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml | 1 + .../ii/modules/sidebarLeft/PagePlaceholder.qml | 7 ++++--- 5 files changed, 14 insertions(+), 8 deletions(-) rename dots/.config/quickshell/ii/modules/common/widgets/{CookieWrappedMaterialSymbol.qml => MaterialShapeWrappedMaterialSymbol.qml} (90%) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/CookieWrappedMaterialSymbol.qml b/dots/.config/quickshell/ii/modules/common/widgets/MaterialShapeWrappedMaterialSymbol.qml similarity index 90% rename from dots/.config/quickshell/ii/modules/common/widgets/CookieWrappedMaterialSymbol.qml rename to dots/.config/quickshell/ii/modules/common/widgets/MaterialShapeWrappedMaterialSymbol.qml index 996388a3c..b8c3469d6 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/CookieWrappedMaterialSymbol.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/MaterialShapeWrappedMaterialSymbol.qml @@ -2,7 +2,7 @@ import QtQuick import qs.modules.common import qs.modules.common.widgets -MaterialCookie { +MaterialShape { id: root property alias text: symbol.text property alias iconSize: symbol.iconSize @@ -13,7 +13,7 @@ MaterialCookie { color: Appearance.colors.colSecondaryContainer colSymbol: Appearance.colors.colOnSecondaryContainer - sides: 5 + shape: MaterialShape.Shape.Clover4Leaf implicitSize: Math.max(symbol.implicitWidth, symbol.implicitHeight) + padding * 2 diff --git a/dots/.config/quickshell/ii/modules/common/widgets/NotificationAppIcon.qml b/dots/.config/quickshell/ii/modules/common/widgets/NotificationAppIcon.qml index 8635f4f78..795a708be 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/NotificationAppIcon.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/NotificationAppIcon.qml @@ -6,7 +6,7 @@ import Quickshell import Quickshell.Widgets import Quickshell.Services.Notifications -MaterialCookie { // App icon +MaterialShape { // App icon id: root property var appIcon: "" property var summary: "" @@ -21,8 +21,11 @@ MaterialCookie { // App icon property real smallAppIconSize: implicitSize * smallAppIconScale implicitSize: 38 * scale - sides: isUrgent ? 10 : 0 - amplitude: implicitSize / 24 + property list urgentShapes: [ + MaterialShape.Shape.VerySunny, + MaterialShape.Shape.SoftBurst, + ] + shape: isUrgent ? urgentShapes[Math.floor(Math.random() * urgentShapes.length)] : MaterialShape.Shape.Circle color: isUrgent ? Appearance.colors.colPrimary : Appearance.colors.colSecondaryContainer Loader { diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml index 6d00752bc..eff0483d3 100644 --- a/dots/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml +++ b/dots/.config/quickshell/ii/modules/sidebarLeft/AiChat.qml @@ -369,6 +369,7 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\) icon: "neurology" title: Translation.tr("Large language models") description: Translation.tr("Type /key to get started with online models\nCtrl+O to expand the sidebar\nCtrl+P to detach sidebar into a window") + shape: MaterialShape.Shape.PixelCircle } ScrollToBottomButton { diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml index 4b398311e..c7a8c19a3 100644 --- a/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml +++ b/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml @@ -206,6 +206,7 @@ Item { icon: "bookmark_heart" title: Translation.tr("Anime boorus") description: "" + shape: MaterialShape.Shape.Bun } ScrollToBottomButton { diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/PagePlaceholder.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/PagePlaceholder.qml index 9c41e64d0..c43eedbc4 100644 --- a/dots/.config/quickshell/ii/modules/sidebarLeft/PagePlaceholder.qml +++ b/dots/.config/quickshell/ii/modules/sidebarLeft/PagePlaceholder.qml @@ -7,9 +7,10 @@ Item { id: root property bool shown: true - property alias icon: cookieWrappedMaterialSymbol.text + property alias icon: shapeWidget.text property alias title: widgetNameText.text property alias description: widgetDescriptionText.text + property alias shape: shapeWidget.shape opacity: shown ? 1 : 0 visible: opacity > 0 @@ -27,8 +28,8 @@ Item { anchors.centerIn: parent spacing: 5 - CookieWrappedMaterialSymbol { - id: cookieWrappedMaterialSymbol + MaterialShapeWrappedMaterialSymbol { + id: shapeWidget Layout.alignment: Qt.AlignHCenter iconSize: 60 rotation: -60 * (1 - root.opacity) From 4ad001fd9e75a9e62c438163129685572ed49c29 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 11:24:20 +0100 Subject: [PATCH 54/94] make notif empty placeholder icon wrapped --- .../widgets}/PagePlaceholder.qml | 6 ++- .../notifications/NotificationList.qml | 37 +++---------------- 2 files changed, 11 insertions(+), 32 deletions(-) rename dots/.config/quickshell/ii/modules/{sidebarLeft => common/widgets}/PagePlaceholder.qml (87%) diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/PagePlaceholder.qml b/dots/.config/quickshell/ii/modules/common/widgets/PagePlaceholder.qml similarity index 87% rename from dots/.config/quickshell/ii/modules/sidebarLeft/PagePlaceholder.qml rename to dots/.config/quickshell/ii/modules/common/widgets/PagePlaceholder.qml index c43eedbc4..f0a12aa77 100644 --- a/dots/.config/quickshell/ii/modules/sidebarLeft/PagePlaceholder.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/PagePlaceholder.qml @@ -11,6 +11,7 @@ Item { property alias title: widgetNameText.text property alias description: widgetDescriptionText.text property alias shape: shapeWidget.shape + property alias descriptionHorizontalAlignment: widgetDescriptionText.horizontalAlignment opacity: shown ? 1 : 0 visible: opacity > 0 @@ -31,11 +32,13 @@ Item { MaterialShapeWrappedMaterialSymbol { id: shapeWidget Layout.alignment: Qt.AlignHCenter - iconSize: 60 + padding: 12 + iconSize: 56 rotation: -60 * (1 - root.opacity) } StyledText { id: widgetNameText + visible: title !== "" Layout.alignment: Qt.AlignHCenter font.pixelSize: Appearance.font.pixelSize.larger font.family: Appearance.font.family.title @@ -44,6 +47,7 @@ Item { } StyledText { id: widgetDescriptionText + visible: description !== "" Layout.fillWidth: true font.pixelSize: Appearance.font.pixelSize.small color: Appearance.m3colors.m3outline diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/notifications/NotificationList.qml b/dots/.config/quickshell/ii/modules/sidebarRight/notifications/NotificationList.qml index a1748a67d..99c1fb9a5 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/notifications/NotificationList.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/notifications/NotificationList.qml @@ -31,37 +31,12 @@ Item { } // Placeholder when list is empty - Item { - anchors.fill: listview - - visible: opacity > 0 - opacity: (Notifications.list.length === 0) ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Appearance.animation.menuDecel.duration - easing.type: Appearance.animation.menuDecel.type - } - } - - ColumnLayout { - anchors.centerIn: parent - spacing: 5 - - MaterialSymbol { - Layout.alignment: Qt.AlignHCenter - iconSize: 55 - color: Appearance.m3colors.m3outline - text: "notifications_active" - } - StyledText { - Layout.alignment: Qt.AlignHCenter - font.pixelSize: Appearance.font.pixelSize.normal - color: Appearance.m3colors.m3outline - horizontalAlignment: Text.AlignHCenter - text: Translation.tr("No notifications") - } - } + PagePlaceholder { + shown: Notifications.list.length === 0 + icon: "notifications_active" + description: Translation.tr("Nothing") + shape: MaterialShape.Shape.Ghostish + descriptionHorizontalAlignment: Text.AlignHCenter } ButtonGroup { From f5c421ab99b7ffea4be4ea7b8c3a519b9699cb95 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 11:24:59 +0100 Subject: [PATCH 55/94] pageplaceholder: rotate less --- .../quickshell/ii/modules/common/widgets/PagePlaceholder.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/PagePlaceholder.qml b/dots/.config/quickshell/ii/modules/common/widgets/PagePlaceholder.qml index f0a12aa77..36378b53b 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/PagePlaceholder.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/PagePlaceholder.qml @@ -34,7 +34,7 @@ Item { Layout.alignment: Qt.AlignHCenter padding: 12 iconSize: 56 - rotation: -60 * (1 - root.opacity) + rotation: -30 * (1 - root.opacity) } StyledText { id: widgetNameText From db3d8ddfc235a62c23c92803b5cd38558a5daea9 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 11:53:12 +0100 Subject: [PATCH 56/94] sidebar: corner triggers open only when reaching thru vertical edge --- .../quickshell/ii/modules/common/Config.qml | 5 +- .../modules/screenCorners/ScreenCorners.qml | 8 ++-- .../ii/modules/settings/InterfaceConfig.qml | 48 ++++++++++++++----- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml index da8ad85d8..0bca2b820 100644 --- a/dots/.config/quickshell/ii/modules/common/Config.qml +++ b/dots/.config/quickshell/ii/modules/common/Config.qml @@ -425,10 +425,11 @@ Singleton { property bool bottom: false property bool valueScroll: true property bool clickless: false - property real cornerRegionWidth: 250 - property real cornerRegionHeight: 2 + property int cornerRegionWidth: 250 + property int cornerRegionHeight: 5 property bool visualize: false property bool clicklessCornerEnd: true + property int clicklessCornerVerticalOffset: 1 } property JsonObject quickToggles: JsonObject { diff --git a/dots/.config/quickshell/ii/modules/screenCorners/ScreenCorners.qml b/dots/.config/quickshell/ii/modules/screenCorners/ScreenCorners.qml index 55173b664..cbb8087ae 100644 --- a/dots/.config/quickshell/ii/modules/screenCorners/ScreenCorners.qml +++ b/dots/.config/quickshell/ii/modules/screenCorners/ScreenCorners.qml @@ -79,10 +79,12 @@ Scope { implicitWidth: Config.options.sidebar.cornerOpen.cornerRegionWidth implicitHeight: Config.options.sidebar.cornerOpen.cornerRegionHeight hoverEnabled: true - onMouseXChanged: { + onPositionChanged: { if (!Config.options.sidebar.cornerOpen.clicklessCornerEnd) return; - if ((cornerWidget.isRight && mouseArea.mouseX >= mouseArea.width - 2) - || (cornerWidget.isLeft && mouseArea.mouseX <= 2)) + const verticalOffset = Config.options.sidebar.cornerOpen.clicklessCornerVerticalOffset; + const correctX = (cornerWidget.isRight && mouseArea.mouseX >= mouseArea.width - 2) || (cornerWidget.isLeft && mouseArea.mouseX <= 2); + const correctY = (cornerWidget.isTop && mouseArea.mouseY > verticalOffset || cornerWidget.isBottom && mouseArea.mouseY < mouseArea.height - verticalOffset); + if (correctX && correctY) screenCorners.actionForCorner[cornerPanelWindow.corner](); } onEntered: { diff --git a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml index bd08cfffd..662cfd389 100644 --- a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml @@ -787,22 +787,22 @@ ContentPage { } } } + ConfigSwitch { + buttonIcon: "highlight_mouse_cursor" + text: Translation.tr("Hover to trigger") + checked: Config.options.sidebar.cornerOpen.clickless + onCheckedChanged: { + Config.options.sidebar.cornerOpen.clickless = checked; + } + + StyledToolTip { + text: Translation.tr("When this is off you'll have to click") + } + } Row { - ConfigSwitch { - buttonIcon: "highlight_mouse_cursor" - text: Translation.tr("Hover to trigger") - checked: Config.options.sidebar.cornerOpen.clickless - onCheckedChanged: { - Config.options.sidebar.cornerOpen.clickless = checked; - } - - StyledToolTip { - text: Translation.tr("When this is off you'll have to click") - } - } ConfigSwitch { enabled: !Config.options.sidebar.cornerOpen.clickless - text: Translation.tr("but force at absolute corner") + text: Translation.tr("Force hover open at absolute corner") checked: Config.options.sidebar.cornerOpen.clicklessCornerEnd onCheckedChanged: { Config.options.sidebar.cornerOpen.clicklessCornerEnd = checked; @@ -812,7 +812,29 @@ ContentPage { text: Translation.tr("When the previous option is off and this is on,\nyou can still hover the corner's end to open sidebar,\nand the remaining area can be used for volume/brightness scroll") } } + ConfigSpinBox { + icon: "arrow_cool_down" + text: Translation.tr("with vertical offset") + value: Config.options.sidebar.cornerOpen.clicklessCornerVerticalOffset + from: 0 + to: 20 + stepSize: 1 + onValueChanged: { + Config.options.sidebar.cornerOpen.clicklessCornerVerticalOffset = value; + } + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.NoButton + StyledToolTip { + extraVisibleCondition: mouseArea.containsMouse + text: Translation.tr("Why this is cool:\nFor non-0 values, it won't trigger when you reach the\nscreen corner along the horizontal edge, but it will when\nyou do along the vertical edge") + } + } + } } + ConfigRow { uniform: true ConfigSwitch { From 981e3be9b0f858c711fce98c2c76ae94e135fc74 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 12:05:21 +0100 Subject: [PATCH 57/94] adjust secondary tab rounding --- .../quickshell/ii/modules/common/widgets/SecondaryTabButton.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/SecondaryTabButton.qml b/dots/.config/quickshell/ii/modules/common/widgets/SecondaryTabButton.qml index 347774cff..b1036c777 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/SecondaryTabButton.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/SecondaryTabButton.qml @@ -91,7 +91,7 @@ TabButton { background: Rectangle { id: buttonBackground - radius: Appearance?.rounding.small ?? 7 + radius: Appearance?.rounding.normal implicitHeight: 37 color: (root.hovered ? root.colBackgroundHover : root.colBackground) layer.enabled: true From d835d8bc302159bfa9b386413ffc56a857d16755 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 12:05:38 +0100 Subject: [PATCH 58/94] adjust button wiggle anim --- dots/.config/quickshell/ii/modules/common/Appearance.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/Appearance.qml b/dots/.config/quickshell/ii/modules/common/Appearance.qml index 8a0446f0e..38589b161 100644 --- a/dots/.config/quickshell/ii/modules/common/Appearance.qml +++ b/dots/.config/quickshell/ii/modules/common/Appearance.qml @@ -317,9 +317,9 @@ Singleton { } property QtObject clickBounce: QtObject { - property int duration: 200 + property int duration: 400 property int type: Easing.BezierSpline - property list bezierCurve: animationCurves.expressiveFastSpatial + property list bezierCurve: animationCurves.expressiveDefaultSpatial property int velocity: 850 property Component numberAnimation: Component { NumberAnimation { duration: root.animation.clickBounce.duration From 8eb50a8917189cb196e9fb99c00507d05e77c463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E5=AE=B6=E5=85=B4?= Date: Wed, 29 Oct 2025 13:57:16 +0800 Subject: [PATCH 59/94] fix: correctly resume from suspend by waiting pipewire resume (#2320) --- dots/.config/quickshell/ii/services/Audio.qml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/dots/.config/quickshell/ii/services/Audio.qml b/dots/.config/quickshell/ii/services/Audio.qml index 4ce6521c6..9bb096208 100644 --- a/dots/.config/quickshell/ii/services/Audio.qml +++ b/dots/.config/quickshell/ii/services/Audio.qml @@ -29,12 +29,18 @@ Singleton { property real lastVolume: 0 function onVolumeChanged() { if (!Config.options.audio.protection.enable) return; + const newVolume = sink.audio.volume; + // when resuming from suspend, we should not write volume to avoid pipewire volume reset issues + if (isNaN(newVolume) || newVolume === undefined || newVolume === null) { + lastReady = false; + lastVolume = 0; + return; + } if (!lastReady) { - lastVolume = sink.audio.volume; + lastVolume = newVolume; lastReady = true; return; } - const newVolume = sink.audio.volume; const maxAllowedIncrease = Config.options.audio.protection.maxAllowedIncrease / 100; const maxAllowed = Config.options.audio.protection.maxAllowed / 100; @@ -45,9 +51,6 @@ Singleton { root.sinkProtectionTriggered(Translation.tr("Exceeded max allowed")); sink.audio.volume = Math.min(lastVolume, maxAllowed); } - if (sink.ready && (isNaN(sink.audio.volume) || sink.audio.volume === undefined || sink.audio.volume === null)) { - sink.audio.volume = 0; - } lastVolume = sink.audio.volume; } } From 7476655302961c57791db601827234c232c86a83 Mon Sep 17 00:00:00 2001 From: clsty Date: Wed, 29 Oct 2025 21:52:58 +0800 Subject: [PATCH 60/94] Fix firstrun logic --- sdata/subcmd-install/3.files.sh | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/sdata/subcmd-install/3.files.sh b/sdata/subcmd-install/3.files.sh index 71c04e163..17f048a8f 100644 --- a/sdata/subcmd-install/3.files.sh +++ b/sdata/subcmd-install/3.files.sh @@ -159,16 +159,24 @@ case $SKIP_HYPRLAND in true) sleep 0;; *) warning_rsync_delete; v rsync -av --delete "${arg_excludes[@]}" dots/.config/hypr/ "$XDG_CONFIG_HOME"/hypr/ + # When hypr/custom does not exist, we assume that it's the firstrun. + if [ -d "$XDG_CONFIG_HOME/hypr/custom" ];then ii_firstrun=false;else ii_firstrun=true;fi t="$XDG_CONFIG_HOME/hypr/hyprland.conf" if [ -f $t ];then echo -e "${STY_BLUE}[$0]: \"$t\" already exists.${STY_RST}" - v mv $t $t.old - v cp -f dots/.config/hypr/hyprland.conf $t - existed_hypr_conf_firstrun=y + if $ii_firstrun;then + echo -e "${STY_BLUE}[$0]: It seems to be the firstrun.${STY_RST}" + v mv $t $t.old + v cp -f dots/.config/hypr/hyprland.conf $t + existed_hypr_conf_firstrun=y + else + echo -e "${STY_BLUE}[$0]: It seems not a firstrun.${STY_RST}" + v cp -f dots/.config/hypr/hyprland.conf $t.new + existed_hypr_conf=y + fi else echo -e "${STY_YELLOW}[$0]: \"$t\" does not exist yet.${STY_RST}" v cp dots/.config/hypr/hyprland.conf $t - existed_hypr_conf=n fi t="$XDG_CONFIG_HOME/hypr/hypridle.conf" if [ -f $t ];then From eb6fca66975317e6f55530aaebc326ac901ef48e Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 15:17:23 +0100 Subject: [PATCH 61/94] fix binding loop in Anime.qml --- .../ii/modules/sidebarLeft/Anime.qml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml index c7a8c19a3..1e1d483c9 100644 --- a/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml +++ b/dots/.config/quickshell/ii/modules/sidebarLeft/Anime.qml @@ -119,16 +119,17 @@ Item { } } + property real pageKeyScrollAmount: booruResponseListView.height / 2 Keys.onPressed: (event) => { tagInputField.forceActiveFocus() if (event.modifiers === Qt.NoModifier) { if (event.key === Qt.Key_PageUp) { if (booruResponseListView.atYBeginning) return; - booruResponseListView.contentY = Math.max(0, booruResponseListView.contentY - booruResponseListView.height / 2) + booruResponseListView.contentY = Math.max(0, booruResponseListView.contentY - root.pageKeyScrollAmount) event.accepted = true } else if (event.key === Qt.Key_PageDown) { if (booruResponseListView.atYEnd) return; - booruResponseListView.contentY = Math.min(booruResponseListView.contentHeight - booruResponseListView.height / 2, booruResponseListView.contentY + booruResponseListView.height / 2) + booruResponseListView.contentY = Math.min(booruResponseListView.contentHeight, booruResponseListView.contentY + root.pageKeyScrollAmount) event.accepted = true } } @@ -171,17 +172,20 @@ Item { mouseScrollFactor: Config.options.interactions.scrolling.mouseScrollFactor * 1.4 property int lastResponseLength: 0 - - model: ScriptModel { - values: { - if(root.responses.length > booruResponseListView.lastResponseLength) { + Connections { + target: root + function onResponsesChanged() { + if (root.responses.length > booruResponseListView.lastResponseLength) { if (booruResponseListView.lastResponseLength > 0 && root.responses[booruResponseListView.lastResponseLength].provider != "system") booruResponseListView.contentY = booruResponseListView.contentY + root.scrollOnNewResponse booruResponseListView.lastResponseLength = root.responses.length } - return root.responses } } + + model: ScriptModel { + values: root.responses + } delegate: BooruResponse { responseData: modelData tagInputField: root.inputField From e279e4d9724b587bb44797fab98319d6020e0f84 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 15:59:15 +0100 Subject: [PATCH 62/94] make switches more bouncy --- .../ii/modules/common/widgets/StyledSwitch.qml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledSwitch.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledSwitch.qml index f16e213fd..871ce550f 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledSwitch.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledSwitch.qml @@ -45,13 +45,25 @@ Switch { anchors.leftMargin: root.checked ? ((root.pressed || root.down) ? (22 * root.scale) : 24 * root.scale) : ((root.pressed || root.down) ? (2 * root.scale) : 8 * root.scale) Behavior on anchors.leftMargin { - animation: Appearance.animation.elementMove.numberAnimation.createObject(this) + NumberAnimation { + duration: Appearance.animationCurves.expressiveFastSpatialDuration + easing.type: Easing.BezierCurve + easing.bezierCurve: Appearance.animationCurves.expressiveFastSpatial + } } Behavior on width { - animation: Appearance.animation.elementMove.numberAnimation.createObject(this) + NumberAnimation { + duration: Appearance.animationCurves.expressiveFastSpatialDuration + easing.type: Easing.BezierCurve + easing.bezierCurve: Appearance.animationCurves.expressiveFastSpatial + } } Behavior on height { - animation: Appearance.animation.elementMove.numberAnimation.createObject(this) + NumberAnimation { + duration: Appearance.animationCurves.expressiveFastSpatialDuration + easing.type: Easing.BezierCurve + easing.bezierCurve: Appearance.animationCurves.expressiveFastSpatial + } } Behavior on color { animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) From cc1e5e4636ddcedc84bc8cf2ac92210b00fc1c80 Mon Sep 17 00:00:00 2001 From: clsty Date: Wed, 29 Oct 2025 23:21:31 +0800 Subject: [PATCH 63/94] Improve backup_clashing_targets() --- sdata/subcmd-install/3.files.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sdata/subcmd-install/3.files.sh b/sdata/subcmd-install/3.files.sh index 17f048a8f..4138c9d87 100644 --- a/sdata/subcmd-install/3.files.sh +++ b/sdata/subcmd-install/3.files.sh @@ -19,18 +19,20 @@ function warning_rsync_normal(){ } function backup_clashing_targets(){ - # For dirs/files under target_dir, only backup those which clashes with the ones under source_dir + # For dirs/files under target_dir, only backup those which clashes with the ones under source_dir + # However, ignore the ones listed in ignored_list # Deal with arguments local source_dir="$1" local target_dir="$2" local backup_dir="$3" + local -a ignored_list=("${@:4}") # Find clash dirs/files, save as clash_list local clash_list=() local source_list=($(ls -A "$source_dir")) local target_list=($(ls -A "$target_dir")) - declare -A target_map + local -A target_map for i in "${target_list[@]}"; do target_map["$i"]=1 done @@ -39,6 +41,12 @@ function backup_clashing_targets(){ clash_list+=("$i") fi done + local -A delk + for del in "${ignored_list[@]}" ; do delk[$del]=1 ; done + for k in "${!clash_list[@]}" ; do + [ "${delk[${clash_list[$k]}]-}" ] && unset 'clash_list[k]' + done + clash_list=("${clash_list[@]}") # Construct args_includes for rsync local args_includes=() From c550a792b833e4ba40a2afd43c5b478e03d214cf Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 00:42:13 +0800 Subject: [PATCH 64/94] Improve backup functions --- sdata/lib/functions.sh | 46 ++++++++++++++++++++++++ sdata/subcmd-install/3.files.sh | 64 +++++---------------------------- 2 files changed, 54 insertions(+), 56 deletions(-) diff --git a/sdata/lib/functions.sh b/sdata/lib/functions.sh index 3282637bb..ff2b80caf 100644 --- a/sdata/lib/functions.sh +++ b/sdata/lib/functions.sh @@ -309,3 +309,49 @@ function auto_get_git_submodule(){ x git submodule update --init --recursive fi } + +function backup_clashing_targets(){ + # For non-recursive dirs/files under target_dir, only backup those which clashes with the ones under source_dir + # However, ignore the ones listed in ignored_list + + # Deal with arguments + local source_dir="$1" + local target_dir="$2" + local backup_dir="$3" + local -a ignored_list=("${@:4}") + + # Find clash dirs/files, save as clash_list + local clash_list=() + local source_list=($(ls -A "$source_dir")) + local target_list=($(ls -A "$target_dir")) + local -A target_map + for i in "${target_list[@]}"; do + target_map["$i"]=1 + done + for i in "${source_list[@]}"; do + if [[ -n "${target_map[$i]}" ]]; then + clash_list+=("$i") + fi + done + local -A delk + for del in "${ignored_list[@]}" ; do delk[$del]=1 ; done + for k in "${!clash_list[@]}" ; do + [ "${delk[${clash_list[$k]}]-}" ] && unset 'clash_list[k]' + done + clash_list=("${clash_list[@]}") + + # Construct args_includes for rsync + local args_includes=() + for i in "${clash_list[@]}"; do + if [[ -d "$target_dir/$i" ]]; then + args_includes+=(--include="/$i/") + args_includes+=(--include="/$i/**") + else + args_includes+=(--include="/$i") + fi + done + args_includes+=(--exclude='*') + + x mkdir -p $backup_dir + x rsync -av --progress "${args_includes[@]}" "$target_dir/" "$backup_dir/" +} diff --git a/sdata/subcmd-install/3.files.sh b/sdata/subcmd-install/3.files.sh index 4138c9d87..3a9c315d8 100644 --- a/sdata/subcmd-install/3.files.sh +++ b/sdata/subcmd-install/3.files.sh @@ -18,50 +18,10 @@ function warning_rsync_normal(){ printf "${STY_RST}" } -function backup_clashing_targets(){ - # For dirs/files under target_dir, only backup those which clashes with the ones under source_dir - # However, ignore the ones listed in ignored_list - - # Deal with arguments - local source_dir="$1" - local target_dir="$2" - local backup_dir="$3" - local -a ignored_list=("${@:4}") - - # Find clash dirs/files, save as clash_list - local clash_list=() - local source_list=($(ls -A "$source_dir")) - local target_list=($(ls -A "$target_dir")) - local -A target_map - for i in "${target_list[@]}"; do - target_map["$i"]=1 - done - for i in "${source_list[@]}"; do - if [[ -n "${target_map[$i]}" ]]; then - clash_list+=("$i") - fi - done - local -A delk - for del in "${ignored_list[@]}" ; do delk[$del]=1 ; done - for k in "${!clash_list[@]}" ; do - [ "${delk[${clash_list[$k]}]-}" ] && unset 'clash_list[k]' - done - clash_list=("${clash_list[@]}") - - # Construct args_includes for rsync - local args_includes=() - for i in "${clash_list[@]}"; do - if [[ -d "$target_dir/$i" ]]; then - args_includes+=(--include="/$i/") - args_includes+=(--include="/$i/**") - else - args_includes+=(--include="/$i") - fi - done - args_includes+=(--exclude='*') - - x mkdir -p $backup_dir - x rsync -av --progress "${args_includes[@]}" "$target_dir/" "$backup_dir/" +function backup_configs(){ + backup_clashing_targets dots/.config $XDG_CONFIG_HOME "${BACKUP_DIR}/.config" + backup_clashing_targets dots/.local/share $XDG_DATA_HOME "${BACKUP_DIR}/.local/share" + printf "${STY_BLUE}Backup into \"${BACKUP_DIR}\" finished.${STY_RST}\n" } function ask_backup_configs(){ @@ -71,27 +31,19 @@ function ask_backup_configs(){ printf "${STY_RST}" while true;do echo " y = Yes, backup" - echo " n = No, skip to next" + echo " n/s = No, skip to next" local p; read -p "====> " p case $p in [yY]) echo -e "${STY_BLUE}OK, doing backup...${STY_RST}" ;local backup=true;break ;; - [nN]) echo -e "${STY_BLUE}Alright, skipping...${STY_RST}" ;local backup=false;break ;; + [nNsS]) echo -e "${STY_BLUE}Alright, skipping...${STY_RST}" ;local backup=false;break ;; *) echo -e "${STY_RED}Please enter [y/n].${STY_RST}";; esac done - if $backup;then - backup_clashing_targets dots/.config $XDG_CONFIG_HOME "${BACKUP_DIR}/.config" - backup_clashing_targets dots/.local/share $XDG_DATA_HOME "${BACKUP_DIR}/.local/share" - printf "${STY_BLUE}Backup into \"${BACKUP_DIR}\" finished.${STY_RST}\n" - fi + if $backup;then backup_configs;fi } function auto_backup_configs(){ # Backup when $BACKUP_DIR does not exist - if [[ ! -d "$BACKUP_DIR" ]]; then - backup_clashing_targets dots/.config $XDG_CONFIG_HOME "${BACKUP_DIR}/.config" - backup_clashing_targets dots/.local/share $XDG_DATA_HOME "${BACKUP_DIR}/.local/share" - printf "${STY_BLUE}Backup into \"${BACKUP_DIR}\" finished.${STY_RST}\n" - fi + if [[ ! -d "$BACKUP_DIR" ]]; then backup_configs;fi } ##################################################################################### From 727227cf8bb60e35b5e7e36688a96f105cf71313 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 20:31:14 +0100 Subject: [PATCH 65/94] add option to not animate digital bg clock (closes #2055) --- .../ii/modules/background/Background.qml | 2 +- .../quickshell/ii/modules/common/Config.qml | 3 +++ .../ii/modules/settings/InterfaceConfig.qml | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/background/Background.qml b/dots/.config/quickshell/ii/modules/background/Background.qml index 71bae0d77..fc0bb0cfb 100644 --- a/dots/.config/quickshell/ii/modules/background/Background.qml +++ b/dots/.config/quickshell/ii/modules/background/Background.qml @@ -445,7 +445,7 @@ Variants { color: bgRoot.colText style: Text.Raised styleColor: Appearance.colors.colShadow - animateChange: true + animateChange: Config.options.background.clock.digital.animateChange } component ClockStatusText: Row { id: statusTextRow diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml index 0bca2b820..f43b86187 100644 --- a/dots/.config/quickshell/ii/modules/common/Config.qml +++ b/dots/.config/quickshell/ii/modules/common/Config.qml @@ -165,6 +165,9 @@ Singleton { property bool dateInClock: true property bool constantlyRotate: false } + property JsonObject digital: JsonObject { + property bool animateChange: true + } } property string wallpaperPath: "" diff --git a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml index 662cfd389..cf7e98171 100644 --- a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml @@ -55,6 +55,20 @@ ContentPage { } } + ContentSubsection { + visible: Config.options.background.clock.style === "digital" + title: Translation.tr("Digital clock settings") + + ConfigSwitch { + buttonIcon: "animation" + text: Translation.tr("Animate time change") + checked: Config.options.background.clock.digital.animateChange + onCheckedChanged: { + Config.options.background.clock.digital.animateChange = checked; + } + } + } + ContentSubsection { visible: Config.options.background.clock.style === "cookie" title: Translation.tr("Cookie clock settings") From 06775806d5a3dbbcadafc581c73b1dfd600fae59 Mon Sep 17 00:00:00 2001 From: Matt Van Harn Date: Wed, 29 Oct 2025 15:53:01 -0400 Subject: [PATCH 66/94] Add YAML-based file installation system (issue #2137) - Replace hardcoded Bash logic with declarative YAML configuration - Implement user preference wizard for shell/terminal/keybindings - Add conditional file copying based on user preferences - Support multiple sync modes: sync, soft, hard, hard-backup, soft-backup, skip, skip-if-exists - Implement MD5 hash comparison for idempotent backups - Add fontconfig fontset support via II_FONTSET_NAME - Complete coverage of all config directories and files from original script This is an experimental feature enabled via --exp-files flag. --- sdata/subcmd-install/3.files-exp.sh | 393 ++++++++++++++++++++++++++++ sdata/subcmd-install/3.files.yaml | 116 ++++++++ 2 files changed, 509 insertions(+) create mode 100644 sdata/subcmd-install/3.files-exp.sh create mode 100644 sdata/subcmd-install/3.files.yaml diff --git a/sdata/subcmd-install/3.files-exp.sh b/sdata/subcmd-install/3.files-exp.sh new file mode 100644 index 000000000..350c0d8db --- /dev/null +++ b/sdata/subcmd-install/3.files-exp.sh @@ -0,0 +1,393 @@ +# This script is meant to be sourced. +# It's not for directly running. + +# TODO: https://github.com/end-4/dots-hyprland/issues/2137 + +printf "${STY_CYAN}[$0]: 3. Copying config files (experimental YAML-based)${STY_RST}\n" + +# Configuration file +CONFIG_FILE="sdata/subcmd-install/3.files.yaml" + +# ============================================================================= +# ORIGINAL FUNCTIONS +# ============================================================================= + +function warning_rsync_delete(){ + printf "${STY_YELLOW}" + printf "The command below uses --delete for rsync which overwrites the destination folder.\n" + printf "${STY_RST}" +} + +function warning_rsync_normal(){ + printf "${STY_YELLOW}" + printf "The command below uses rsync which overwrites the destination.\n" + printf "${STY_RST}" +} + +function backup_clashing_targets(){ + # For dirs/files under target_dir, only backup those which clashes with the ones under source_dir + + # Deal with arguments + local source_dir="$1" + local target_dir="$2" + local backup_dir="$3" + + # Find clash dirs/files, save as clash_list + local clash_list=() + local source_list=($(ls -A "$source_dir")) + local target_list=($(ls -A "$target_dir")) + declare -A target_map + for i in "${target_list[@]}"; do + target_map["$i"]=1 + done + for i in "${source_list[@]}"; do + if [[ -n "${target_map[$i]}" ]]; then + clash_list+=("$i") + fi + done + + # Construct args_includes for rsync + for i in "${clash_list[@]}"; do + current_target=$target_dir/$i + if [[ -d $current_target ]]; then + args_includes+=(--include="$current_target/") + args_includes+=(--include="$current_target/**") + else + args_includes+=(--include="$current_target") + fi + done + args_includes+=(--exclude="*") + + x mkdir -p $backup_dir + x rsync -av --progress "${args_includes[@]}" "$target_dir/" "$backup_dir/" +} + +function ask_backup_configs(){ + printf "${STY_RED}" + printf "Would you like to backup clashing dirs/files under \"$XDG_CONFIG_HOME\" and \"$XDG_DATA_HOME\" to \"$BACKUP_DIR\"?" + read -p "[y/N] " backup_confirm + case $backup_confirm in + [yY][eE][sS]|[yY]) + showfun backup_clashing_targets + v backup_clashing_targets dots/.config $XDG_CONFIG_HOME "${BACKUP_DIR}/.config" + v backup_clashing_targets dots/.local/share $XDG_DATA_HOME "${BACKUP_DIR}/.local/share" + ;; + *) echo "Skipping backup..." ;; + esac + printf "${STY_RST}" +} + +# ============================================================================= +# CONFIGURATION FUNCTIONS +# ============================================================================= + +# User preference wizard +wizard_update_preferences() { + echo -e "${STY_CYAN}=== Dotfiles Customization ===${STY_RESET}" + + # Get current preferences + current_shell=$(yq '.user_preferences.shell // "fish"' "$CONFIG_FILE") + current_terminal=$(yq '.user_preferences.terminal // "kitty"' "$CONFIG_FILE") + current_keybindings=$(yq '.user_preferences.keybindings // "default"' "$CONFIG_FILE") + + echo "Current preferences:" + echo " Shell: $current_shell" + echo " Terminal: $current_terminal" + echo " Keybindings: $current_keybindings" + echo + + # Shell selection + echo "Which shell do you prefer?" + echo "1) fish (default)" + echo "2) zsh" + read -p "Enter choice [1-2]: " shell_choice + + case "$shell_choice" in + 1|"") shell="fish" ;; + 2) shell="zsh" ;; + *) echo "Invalid choice, using fish"; shell="fish" ;; + esac + + # Terminal selection + echo + echo "Which terminal do you prefer?" + echo "1) kitty (default)" + echo "2) foot" + read -p "Enter choice [1-2]: " terminal_choice + + case "$terminal_choice" in + 1|"") terminal="kitty" ;; + 2) terminal="foot" ;; + *) echo "Invalid choice, using kitty"; terminal="kitty" ;; + esac + + # Keybindings selection + echo + echo "Which keybinding style do you prefer?" + echo "1) default (arrow keys)" + echo "2) vim (H/J/K/L)" + read -p "Enter choice [1-2]: " keybind_choice + + case "$keybind_choice" in + 1|"") keybindings="default" ;; + 2) keybindings="vim" ;; + *) echo "Invalid choice, using default"; keybindings="default" ;; + esac + + # Update YAML in-place + yq -i ".user_preferences.shell = \"$shell\"" "$CONFIG_FILE" + yq -i ".user_preferences.terminal = \"$terminal\"" "$CONFIG_FILE" + yq -i ".user_preferences.keybindings = \"$keybindings\"" "$CONFIG_FILE" + + echo + echo "Preferences updated!" +} + +# Get user preference +get_pref() { + yq -r ".user_preferences.$1" "$CONFIG_FILE" +} + +# Check if pattern should be processed based on user preferences +should_process_pattern() { + local pattern="$1" + local condition=$(echo "$pattern" | yq '.condition // "true"') + + # If no condition or condition is "true", always process + if [[ "$condition" == "true" ]]; then + return 0 + fi + + # Extract the preference type and value from condition + local type=$(echo "$condition" | yq '.type') + local value=$(echo "$condition" | yq '.value') + + [[ "$(get_pref "$type")" == "$value" ]] + +} + +# Compare hashes of files/directories, return true if they are the same, false otherwise +files_are_same() { + local path1="$1" + local path2="$2" + + # Check if paths exist + if [[ ! -e "$path1" || ! -e "$path2" ]]; then + return 1 + fi + + # For directories, use find + md5sum to compare recursively + # For files, use md5sum directly + if [[ -d "$path1" && -d "$path2" ]]; then + # Compare directory contents using find and md5sum + local hash1=$(find "$path1" -type f -exec md5sum {} \; | sort -k 2 | md5sum | awk '{print $1}') + local hash2=$(find "$path2" -type f -exec md5sum {} \; | sort -k 2 | md5sum | awk '{print $1}') + [[ "$hash1" == "$hash2" ]] + elif [[ -f "$path1" && -f "$path2" ]]; then + # Compare file hashes + local hash1=$(md5sum "$path1" | awk '{print $1}') + local hash2=$(md5sum "$path2" | awk '{print $1}') + [[ "$hash1" == "$hash2" ]] + else + # One is a file, one is a directory - different types + return 1 + fi +} + +# Find next backup number +get_next_backup_number() { + local base_path="$1" + local counter=1 + + while [[ -e "${base_path}.old.${counter}" ]]; do + ((counter++)) + done + + echo $counter +} + +# ============================================================================= +# MAIN EXECUTION +# ============================================================================= + +# Ensure directories exist +v mkdir -p $XDG_BIN_HOME $XDG_CACHE_HOME $XDG_CONFIG_HOME $XDG_DATA_HOME + +# Handle backup +case $ask in + false) sleep 0 ;; + *) ask_backup_configs ;; +esac + +# Run user preference wizard +case $ask in + false) sleep 0 ;; + *) wizard_update_preferences ;; +esac + +# Read patterns from YAML file +readarray patterns < <(yq -o=j -I=0 '.patterns[]' "$CONFIG_FILE") + +# Process each pattern +for pattern in "${patterns[@]}"; do + from=$(echo "$pattern" | yq '.from' - | envsubst) + to=$(echo "$pattern" | yq '.to' - | envsubst) + mode=$(echo "$pattern" | yq '.mode' - | envsubst) + condition=$(echo "$pattern" | yq '.condition // "true"') + + # Handle fontconfig fontset override + # If II_FONTSET_NAME is set and this is the fontconfig pattern, use the fontset instead + if [[ "$from" == "dots/.config/fontconfig" ]] && [[ -n "${II_FONTSET_NAME:-}" ]]; then + from="dots-extra/fontsets/${II_FONTSET_NAME}" + echo "Using fontset \"${II_FONTSET_NAME}\" for fontconfig" + fi + + # Check if pattern should be processed + if ! should_process_pattern "$pattern"; then + # Format condition message nicely + if [[ "$condition" != "true" ]]; then + cond_type=$(echo "$condition" | yq -r '.type // ""') + cond_value=$(echo "$condition" | yq -r '.value // ""') + if [[ -n "$cond_type" && -n "$cond_value" ]]; then + echo "Skipping $from -> $to (condition not met: $cond_type == '$cond_value')" + else + echo "Skipping $from -> $to (condition not met)" + fi + else + echo "Skipping $from -> $to (condition not met)" + fi + continue + fi + + echo "Processing: $from -> $to (mode: $mode)" + + # Build exclude arguments for rsync + excludes=() + if echo "$pattern" | yq -e '.excludes' >/dev/null 2>&1; then + while IFS= read -r exclude; do + excludes+=(--exclude "$exclude") + done < <(echo "$pattern" | yq -r '.excludes[]') + fi + + # Check if source exists + if [[ ! -e "$from" ]]; then + echo "Warning: Source does not exist: $from (skipping)" + continue + fi + + # Ensure destination directory exists for files + if [[ -f "$from" ]]; then + v mkdir -p "$(dirname "$to")" + fi + + # Execute based on mode + case $mode in + "sync") + if [[ -d "$from" ]]; then + warning_rsync_delete + v rsync -av --delete "${excludes[@]}" "$from/" "$to/" + else + warning_rsync_normal + # For files, don't use trailing slash and don't use --delete + v rsync -av "${excludes[@]}" "$from" "$to" + fi + ;; + "soft") + warning_rsync_normal + if [[ -d "$from" ]]; then + v rsync -av "${excludes[@]}" "$from/" "$to/" + else + # For files, don't use trailing slash + v rsync -av "${excludes[@]}" "$from" "$to" + fi + ;; + "hard") + v cp -r "$from" "$to" + ;; + "hard-backup") + if [[ -e "$to" ]]; then + if files_are_same "$from" "$to"; then + echo "Files are identical, skipping backup" + else + backup_number=$(get_next_backup_number "$to") + v mv "$to" "$to.old.$backup_number" + v cp -r "$from" "$to" + fi + else + v cp -r "$from" "$to" + fi + ;; + "soft-backup") + if [[ -e "$to" ]]; then + if files_are_same "$from" "$to"; then + echo "Files are identical, skipping backup" + else + v cp -r "$from" "$to.new" + fi + else + v cp -r "$from" "$to" + fi + ;; + "skip") + echo "Skipping $from" + ;; + "skip-if-exists") + if [[ -e "$to" ]]; then + echo "Skipping $from (destination exists)" + else + v cp -r "$from" "$to" + fi + ;; + *) + echo "Unknown mode: $mode" + ;; + esac +done + +# Prevent hyprland from not fully loaded +sleep 1 +try hyprctl reload + +# Rest of original script logic... +# (Keep the existing warning messages and file checks) + +warn_files=() +warn_files_tests=() +warn_files_tests+=(/usr/local/lib/{GUtils-1.0.typelib,Gvc-1.0.typelib,libgutils.so,libgvc.so}) +warn_files_tests+=(/usr/local/share/fonts/TTF/Rubik{,-Italic}'[wght]'.ttf) +warn_files_tests+=(/usr/local/share/licenses/ttf-rubik) +warn_files_tests+=(/usr/local/share/fonts/TTF/Gabarito-{Black,Bold,ExtraBold,Medium,Regular,SemiBold}.ttf) +warn_files_tests+=(/usr/local/share/licenses/ttf-gabarito) +warn_files_tests+=(/usr/local/share/icons/OneUI{,-dark,-light}) +warn_files_tests+=(/usr/local/share/icons/Bibata-Modern-Classic) +warn_files_tests+=(/usr/local/bin/{LaTeX,res}) +for i in ${warn_files_tests[@]}; do + echo $i + test -f $i && warn_files+=($i) + test -d $i && warn_files+=($i) +done + +##################################################################################### +# TODO: output the logs below to a temp file and cat that file, also show the path of the file so users will be able to read it again. +printf "\n" +printf "\n" +printf "\n" +printf "${STY_CYAN}[$0]: Finished${STY_RESET}\n" +printf "\n" +printf "${STY_CYAN}When starting Hyprland from your display manager (login screen) ${STY_RED} DO NOT SELECT UWSM ${STY_RESET}\n" +printf "\n" +printf "${STY_CYAN}If you are already running Hyprland,${STY_RESET}\n" +printf "${STY_CYAN}Press ${STY_BG_CYAN} Ctrl+Super+T ${STY_BG_CYAN} to select a wallpaper${STY_RESET}\n" +printf "${STY_CYAN}Press ${STY_BG_CYAN} Super+/ ${STY_CYAN} for a list of keybinds${STY_RESET}\n" +printf "\n" +printf "${STY_CYAN}For suggestions/hints after installation:${STY_RESET}\n" +printf "${STY_CYAN}${STY_UNDERLINE} https://ii.clsty.link/en/ii-qs/01setup/#post-installation ${STY_RESET}\n" +printf "\n" + +if [[ -z "${ILLOGICAL_IMPULSE_VIRTUAL_ENV}" ]]; then + printf "\n${STY_RED}[$0]: \!! Important \!! : Please ensure environment variable ${STY_RESET} \$ILLOGICAL_IMPULSE_VIRTUAL_ENV ${STY_RED} is set to proper value (by default \"~/.local/state/quickshell/.venv\"), or Quickshell config will not work. We have already provided this configuration in ~/.config/hypr/hyprland/env.conf, but you need to ensure it is included in hyprland.conf, and also a restart is needed for applying it.${STY_RESET}\n" +fi + +if [[ ! -z "${warn_files[@]}" ]]; then + printf "\n${STY_RED}[$0]: \!! Important \!! : Please delete ${STY_RESET} ${warn_files[*]} ${STY_RED} manually as soon as possible, since we\'re now using AUR package or local PKGBUILD to install them for Arch(based) Linux distros, and they'll take precedence over our installation, or at least take up more space.${STY_RESET}\n" +fi diff --git a/sdata/subcmd-install/3.files.yaml b/sdata/subcmd-install/3.files.yaml new file mode 100644 index 000000000..a9f2985f2 --- /dev/null +++ b/sdata/subcmd-install/3.files.yaml @@ -0,0 +1,116 @@ +version: "1.0" +user_preferences: + shell: "fish" # fish | zsh + terminal: "foot" # kitty | foot + keybindings: "default" # default | vim +patterns: + # Always install these files + - from: "dots/.config/quickshell" + to: "$XDG_CONFIG_HOME/quickshell" + mode: "sync" + # Conditionally install these files + - from: "dots/.config/fish" + to: "$XDG_CONFIG_HOME/fish" + mode: "sync" + condition: + type: "shell" + value: "fish" + - from: "dots/.config/zshrc.d" + to: "$XDG_CONFIG_HOME/zshrc.d" + mode: "sync" + condition: + type: "shell" + value: "zsh" + - from: "dots/.config/foot" + to: "$XDG_CONFIG_HOME/foot" + mode: "sync" + condition: + type: "terminal" + value: "foot" + - from: "dots/.config/kitty" + to: "$XDG_CONFIG_HOME/kitty" + mode: "sync" + condition: + type: "terminal" + value: "kitty" + # Hyprland + - from: "dots/.config/hypr" + to: "$XDG_CONFIG_HOME/hypr" + mode: "sync" + excludes: ["custom", "hyprlock.conf", "hypridle.conf", "hyprland.conf"] + # Hyprland special files + - from: "dots/.config/hypr/hyprland.conf" + to: "$XDG_CONFIG_HOME/hypr/hyprland.conf" + mode: "hard-backup" + - from: "dots/.config/hypr/hypridle.conf" + to: "$XDG_CONFIG_HOME/hypr/hypridle.conf" + mode: "soft-backup" + - from: "dots/.config/hypr/hyprlock.conf" + to: "$XDG_CONFIG_HOME/hypr/hyprlock.conf" + mode: "soft-backup" + - from: "dots/.config/hypr/custom" + to: "$XDG_CONFIG_HOME/hypr/custom" + mode: "skip-if-exists" + - from: "dots/.local/share/icons" + to: "$XDG_DATA_HOME/icons" + mode: "soft" + - from: "dots/.local/share/konsole" + to: "$XDG_DATA_HOME/konsole" + mode: "soft" + # Fontconfig (default - fontsets handled separately if II_FONTSET_NAME is set) + - from: "dots/.config/fontconfig" + to: "$XDG_CONFIG_HOME/fontconfig" + mode: "sync" + # MISC config directories (other .config directories) + - from: "dots/.config/fuzzel" + to: "$XDG_CONFIG_HOME/fuzzel" + mode: "sync" + - from: "dots/.config/kde-material-you-colors" + to: "$XDG_CONFIG_HOME/kde-material-you-colors" + mode: "sync" + - from: "dots/.config/Kvantum" + to: "$XDG_CONFIG_HOME/Kvantum" + mode: "sync" + - from: "dots/.config/matugen" + to: "$XDG_CONFIG_HOME/matugen" + mode: "sync" + - from: "dots/.config/mpv" + to: "$XDG_CONFIG_HOME/mpv" + mode: "sync" + - from: "dots/.config/qt5ct" + to: "$XDG_CONFIG_HOME/qt5ct" + mode: "sync" + - from: "dots/.config/qt6ct" + to: "$XDG_CONFIG_HOME/qt6ct" + mode: "sync" + - from: "dots/.config/wlogout" + to: "$XDG_CONFIG_HOME/wlogout" + mode: "sync" + - from: "dots/.config/xdg-desktop-portal" + to: "$XDG_CONFIG_HOME/xdg-desktop-portal" + mode: "sync" + # MISC config files (individual files in .config) + - from: "dots/.config/chrome-flags.conf" + to: "$XDG_CONFIG_HOME/chrome-flags.conf" + mode: "soft" + - from: "dots/.config/code-flags.conf" + to: "$XDG_CONFIG_HOME/code-flags.conf" + mode: "soft" + - from: "dots/.config/darklyrc" + to: "$XDG_CONFIG_HOME/darklyrc" + mode: "soft" + - from: "dots/.config/dolphinrc" + to: "$XDG_CONFIG_HOME/dolphinrc" + mode: "soft" + - from: "dots/.config/kdeglobals" + to: "$XDG_CONFIG_HOME/kdeglobals" + mode: "soft" + - from: "dots/.config/konsolerc" + to: "$XDG_CONFIG_HOME/konsolerc" + mode: "soft" + - from: "dots/.config/starship.toml" + to: "$XDG_CONFIG_HOME/starship.toml" + mode: "soft" + - from: "dots/.config/thorium-flags.conf" + to: "$XDG_CONFIG_HOME/thorium-flags.conf" + mode: "soft" From ee1fbf72cc717456e40dba774f27a473b100eb43 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 22:06:53 +0100 Subject: [PATCH 67/94] vscode theming with Material Code extension (#2146) --- .../colors/code/material-code-set-color.sh | 16 ++++++++++++++++ .../quickshell/ii/scripts/colors/switchwall.sh | 12 +----------- 2 files changed, 17 insertions(+), 11 deletions(-) create mode 100755 dots/.config/quickshell/ii/scripts/colors/code/material-code-set-color.sh diff --git a/dots/.config/quickshell/ii/scripts/colors/code/material-code-set-color.sh b/dots/.config/quickshell/ii/scripts/colors/code/material-code-set-color.sh new file mode 100755 index 000000000..df622d592 --- /dev/null +++ b/dots/.config/quickshell/ii/scripts/colors/code/material-code-set-color.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +COLOR_FILE_PATH="${XDG_STATE_HOME:-$HOME/.local/state}/quickshell/user/generated/color.txt" +CODE_SETTINGS_PATH="${XDG_CONFIG_HOME:-$HOME/.config}/Code/User/settings.json" + +new_color=$(cat "$COLOR_FILE_PATH") + +# Try to update the key if it exists +if grep -q '"material-code.primaryColor"' "$CODE_SETTINGS_PATH"; then + sed -i -E \ + "s/(\"material-code.primaryColor\"\s*:\s*\")[^\"]*(\")/\1${new_color}\2/" \ + "$CODE_SETTINGS_PATH" +else # If the key is not already there, add it + sed -i '$ s/}/,\n "material-code.primaryColor": "'${new_color}'"\n}/' "$CODE_SETTINGS_PATH" + sed -i '$ s/,\n,/,/' "$CODE_SETTINGS_PATH" +fi + diff --git a/dots/.config/quickshell/ii/scripts/colors/switchwall.sh b/dots/.config/quickshell/ii/scripts/colors/switchwall.sh index 5d1a57c7a..31f260760 100755 --- a/dots/.config/quickshell/ii/scripts/colors/switchwall.sh +++ b/dots/.config/quickshell/ii/scripts/colors/switchwall.sh @@ -55,18 +55,8 @@ post_process() { local screen_height="$2" local wallpaper_path="$3" - handle_kde_material_you_colors & - - # Determine the largest region on the wallpaper that's sufficiently un-busy to put widgets in - # if [ ! -f "$MATUGEN_DIR/scripts/least_busy_region.py" ]; then - # echo "Error: least_busy_region.py script not found in $MATUGEN_DIR/scripts/" - # else - # "$MATUGEN_DIR/scripts/least_busy_region.py" \ - # --screen-width "$screen_width" --screen-height "$screen_height" \ - # --width 300 --height 200 \ - # "$wallpaper_path" > "$STATE_DIR"/user/generated/wallpaper/least_busy_region.json - # fi + "$SCRIPT_DIR/code/material-code-set-color.sh" & } check_and_prompt_upscale() { From 947a13556a5a08ceccbe6273545f42d8402e981d Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 23:05:32 +0100 Subject: [PATCH 68/94] media controls: make rounding consistent with other panels --- .../quickshell/ii/modules/mediaControls/MediaControls.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/mediaControls/MediaControls.qml b/dots/.config/quickshell/ii/modules/mediaControls/MediaControls.qml index 62426a36f..75dca5926 100644 --- a/dots/.config/quickshell/ii/modules/mediaControls/MediaControls.qml +++ b/dots/.config/quickshell/ii/modules/mediaControls/MediaControls.qml @@ -21,7 +21,7 @@ Scope { readonly property real osdWidth: Appearance.sizes.osdWidth readonly property real widgetWidth: Appearance.sizes.mediaControlsWidth readonly property real widgetHeight: Appearance.sizes.mediaControlsHeight - property real popupRounding: Appearance.rounding.screenRounding - Appearance.sizes.elevationMargin + 1 + property real popupRounding: Appearance.rounding.screenRounding - Appearance.sizes.hyprlandGapsOut + 1 property list visualizerPoints: [] property bool hasPlasmaIntegration: false From 389fd5e42ccd6325498930cdfed2b90ddccad912 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 23:05:50 +0100 Subject: [PATCH 69/94] update material shapes for less weird spinny --- dots/.config/quickshell/ii/modules/common/widgets/shapes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/shapes b/dots/.config/quickshell/ii/modules/common/widgets/shapes index 2e9263e01..8369a081b 160000 --- a/dots/.config/quickshell/ii/modules/common/widgets/shapes +++ b/dots/.config/quickshell/ii/modules/common/widgets/shapes @@ -1 +1 @@ -Subproject commit 2e9263e011e8dcf00a66da5a2e3fe4df160b41b9 +Subproject commit 8369a081ba4694bb3433c6e25fe7329522a2187e From a3a62f98264e13e4fb18d66c288748bc96b28298 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 29 Oct 2025 23:21:13 +0100 Subject: [PATCH 70/94] make vscode theming work with some not-vs-vscode --- .../colors/code/material-code-set-color.sh | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/dots/.config/quickshell/ii/scripts/colors/code/material-code-set-color.sh b/dots/.config/quickshell/ii/scripts/colors/code/material-code-set-color.sh index df622d592..b29fa7775 100755 --- a/dots/.config/quickshell/ii/scripts/colors/code/material-code-set-color.sh +++ b/dots/.config/quickshell/ii/scripts/colors/code/material-code-set-color.sh @@ -1,16 +1,30 @@ #!/usr/bin/env bash COLOR_FILE_PATH="${XDG_STATE_HOME:-$HOME/.local/state}/quickshell/user/generated/color.txt" -CODE_SETTINGS_PATH="${XDG_CONFIG_HOME:-$HOME/.config}/Code/User/settings.json" + +# Define an array of possible VSCode settings file paths for various forks +settings_paths=( + "${XDG_CONFIG_HOME:-$HOME/.config}/Code/User/settings.json" + "${XDG_CONFIG_HOME:-$HOME/.config}/VSCodium/User/settings.json" + "${XDG_CONFIG_HOME:-$HOME/.config}/Code - OSS/User/settings.json" + "${XDG_CONFIG_HOME:-$HOME/.config}/Code - Insiders/User/settings.json" + "${XDG_CONFIG_HOME:-$HOME/.config}/Cursor/User/settings.json" + # Add more paths as needed for other forks +) new_color=$(cat "$COLOR_FILE_PATH") -# Try to update the key if it exists -if grep -q '"material-code.primaryColor"' "$CODE_SETTINGS_PATH"; then - sed -i -E \ - "s/(\"material-code.primaryColor\"\s*:\s*\")[^\"]*(\")/\1${new_color}\2/" \ - "$CODE_SETTINGS_PATH" -else # If the key is not already there, add it - sed -i '$ s/}/,\n "material-code.primaryColor": "'${new_color}'"\n}/' "$CODE_SETTINGS_PATH" - sed -i '$ s/,\n,/,/' "$CODE_SETTINGS_PATH" -fi +# Loop through each settings file path +for CODE_SETTINGS_PATH in "${settings_paths[@]}"; do + if [[ -f "$CODE_SETTINGS_PATH" ]]; then + # Try to update the key if it exists + if grep -q '"material-code.primaryColor"' "$CODE_SETTINGS_PATH"; then + sed -i -E \ + "s/(\"material-code.primaryColor\"\s*:\s*\")[^\"]*(\")/\1${new_color}\2/" \ + "$CODE_SETTINGS_PATH" + else # If the key is not already there, add it + sed -i '$ s/}/,\n "material-code.primaryColor": "'${new_color}'"\n}/' "$CODE_SETTINGS_PATH" + sed -i '$ s/,\n,/,/' "$CODE_SETTINGS_PATH" + fi + fi +done From 714895976f36fd4ebf9cf4eef15d8417746414c2 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 00:03:18 +0100 Subject: [PATCH 71/94] primarytabbar: use synchronizer to simplify bindings --- .../ii/modules/cheatsheet/Cheatsheet.qml | 20 ++++++++--------- .../modules/common/widgets/PrimaryTabBar.qml | 22 +++++++++---------- .../regionSelector/RegionSelection.qml | 2 +- .../sidebarLeft/SidebarLeftContent.qml | 8 +++---- 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/cheatsheet/Cheatsheet.qml b/dots/.config/quickshell/ii/modules/cheatsheet/Cheatsheet.qml index eaa59ee3d..00dac8b89 100644 --- a/dots/.config/quickshell/ii/modules/cheatsheet/Cheatsheet.qml +++ b/dots/.config/quickshell/ii/modules/cheatsheet/Cheatsheet.qml @@ -5,6 +5,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import Qt5Compat.GraphicalEffects +import Qt.labs.synchronizer import Quickshell.Io import Quickshell import Quickshell.Wayland @@ -22,7 +23,6 @@ Scope { // Scope "name": Translation.tr("Elements") }, ] - property int selectedTab: 0 Loader { id: cheatsheetLoader @@ -31,6 +31,7 @@ Scope { // Scope sourceComponent: PanelWindow { // Window id: cheatsheetRoot visible: cheatsheetLoader.active + property int selectedTab: 0 anchors { top: true @@ -85,16 +86,16 @@ Scope { // Scope } if (event.modifiers === Qt.ControlModifier) { if (event.key === Qt.Key_PageDown) { - root.selectedTab = Math.min(root.selectedTab + 1, root.tabButtonList.length - 1); + cheatsheetRoot.selectedTab = Math.min(cheatsheetRoot.selectedTab + 1, root.tabButtonList.length - 1); event.accepted = true; } else if (event.key === Qt.Key_PageUp) { - root.selectedTab = Math.max(root.selectedTab - 1, 0); + cheatsheetRoot.selectedTab = Math.max(cheatsheetRoot.selectedTab - 1, 0); event.accepted = true; } else if (event.key === Qt.Key_Tab) { - root.selectedTab = (root.selectedTab + 1) % root.tabButtonList.length; + cheatsheetRoot.selectedTab = (cheatsheetRoot.selectedTab + 1) % root.tabButtonList.length; event.accepted = true; } else if (event.key === Qt.Key_Backtab) { - root.selectedTab = (root.selectedTab - 1 + root.tabButtonList.length) % root.tabButtonList.length; + cheatsheetRoot.selectedTab = (cheatsheetRoot.selectedTab - 1 + root.tabButtonList.length) % root.tabButtonList.length; event.accepted = true; } } @@ -140,9 +141,8 @@ Scope { // Scope PrimaryTabBar { // Tab strip id: tabBar tabButtonList: root.tabButtonList - externalTrackedTab: root.selectedTab - function onCurrentIndexChanged(currentIndex) { - root.selectedTab = currentIndex; + Synchronizer on currentIndex { + property alias source: cheatsheetRoot.selectedTab } } @@ -164,12 +164,12 @@ Scope { // Scope animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } - currentIndex: tabBar.externalTrackedTab + currentIndex: cheatsheetRoot.selectedTab onCurrentIndexChanged: { contentWidthBehavior.enabled = true; contentHeightBehavior.enabled = true; tabBar.enableIndicatorAnimation = true; - root.selectedTab = currentIndex; + cheatsheetRoot.selectedTab = currentIndex; } clip: true diff --git a/dots/.config/quickshell/ii/modules/common/widgets/PrimaryTabBar.qml b/dots/.config/quickshell/ii/modules/common/widgets/PrimaryTabBar.qml index 7d792de56..474bdc591 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/PrimaryTabBar.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/PrimaryTabBar.qml @@ -3,16 +3,20 @@ import qs.services import QtQuick import QtQuick.Controls import QtQuick.Layouts +import Qt.labs.synchronizer ColumnLayout { id: root spacing: 0 required property var tabButtonList // Something like [{"icon": "notifications", "name": Translation.tr("Notifications")}, {"icon": "volume_up", "name": Translation.tr("Volume mixer")}] - required property var externalTrackedTab + property int currentIndex property bool enableIndicatorAnimation: false property color colIndicator: Appearance?.colors.colPrimary ?? "#65558F" property color colBorder: Appearance?.m3colors.m3outlineVariant ?? "#C6C6D0" - signal currentIndexChanged(int index) + + onCurrentIndexChanged: { + enableIndicatorAnimation = true + } property bool centerTabBar: parent.width > 500 Layout.fillWidth: !centerTabBar @@ -22,9 +26,8 @@ ColumnLayout { TabBar { id: tabBar Layout.fillWidth: true - currentIndex: root.externalTrackedTab - onCurrentIndexChanged: { - root.onCurrentIndexChanged(currentIndex) + Synchronizer on currentIndex { + property alias source: root.currentIndex } background: Item { @@ -42,10 +45,11 @@ ColumnLayout { Repeater { model: root.tabButtonList delegate: PrimaryTabButton { - selected: (index == root.externalTrackedTab) + selected: (index == root.currentIndex) buttonText: modelData.name buttonIcon: modelData.icon minimumWidth: 160 + onClicked: root.currentIndex = index } } } @@ -54,12 +58,6 @@ ColumnLayout { id: tabIndicator Layout.fillWidth: true height: 3 - Connections { - target: root - function onExternalTrackedTabChanged() { - root.enableIndicatorAnimation = true - } - } Rectangle { id: indicator diff --git a/dots/.config/quickshell/ii/modules/regionSelector/RegionSelection.qml b/dots/.config/quickshell/ii/modules/regionSelector/RegionSelection.qml index 05610f9dd..5ecce47ba 100644 --- a/dots/.config/quickshell/ii/modules/regionSelector/RegionSelection.qml +++ b/dots/.config/quickshell/ii/modules/regionSelector/RegionSelection.qml @@ -5,11 +5,11 @@ import qs.modules.common.widgets import qs.services import QtQuick import QtQuick.Controls +import Qt.labs.synchronizer import Quickshell import Quickshell.Io import Quickshell.Wayland import Quickshell.Hyprland -import Qt.labs.synchronizer PanelWindow { id: root diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeftContent.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeftContent.qml index ae19f07a8..ff1c34509 100644 --- a/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeftContent.qml +++ b/dots/.config/quickshell/ii/modules/sidebarLeft/SidebarLeftContent.qml @@ -5,6 +5,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import Qt5Compat.GraphicalEffects +import Qt.labs.synchronizer Item { id: root @@ -58,9 +59,8 @@ Item { id: tabBar visible: root.tabButtonList.length > 1 tabButtonList: root.tabButtonList - externalTrackedTab: root.selectedTab - function onCurrentIndexChanged(currentIndex) { - root.selectedTab = currentIndex + Synchronizer on currentIndex { + property alias source: root.selectedTab } } @@ -71,7 +71,7 @@ Item { Layout.fillHeight: true spacing: 10 - currentIndex: tabBar.externalTrackedTab + currentIndex: root.selectedTab onCurrentIndexChanged: { tabBar.enableIndicatorAnimation = true root.selectedTab = currentIndex From 128808a56dbdb2024c0a7d6571c7d4849f4ace33 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 00:03:31 +0100 Subject: [PATCH 72/94] styledswitch: fix wrong easing type --- .../quickshell/ii/modules/common/widgets/StyledSwitch.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledSwitch.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledSwitch.qml index 871ce550f..56c1425d9 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledSwitch.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledSwitch.qml @@ -47,21 +47,21 @@ Switch { Behavior on anchors.leftMargin { NumberAnimation { duration: Appearance.animationCurves.expressiveFastSpatialDuration - easing.type: Easing.BezierCurve + easing.type: Easing.BezierSpline easing.bezierCurve: Appearance.animationCurves.expressiveFastSpatial } } Behavior on width { NumberAnimation { duration: Appearance.animationCurves.expressiveFastSpatialDuration - easing.type: Easing.BezierCurve + easing.type: Easing.BezierSpline easing.bezierCurve: Appearance.animationCurves.expressiveFastSpatial } } Behavior on height { NumberAnimation { duration: Appearance.animationCurves.expressiveFastSpatialDuration - easing.type: Easing.BezierCurve + easing.type: Easing.BezierSpline easing.bezierCurve: Appearance.animationCurves.expressiveFastSpatial } } From fcc2ee3551a6c2f0bff0ac4e1a0e26ffd247fbef Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 00:40:23 +0100 Subject: [PATCH 73/94] ai: cleaner message block delegate, add regen button --- .../modules/sidebarLeft/aiChat/AiMessage.qml | 78 ++++++++++++++----- .../sidebarLeft/aiChat/MessageCodeBlock.qml | 14 ++-- .../sidebarLeft/aiChat/MessageTextBlock.qml | 16 ++-- .../sidebarLeft/aiChat/MessageThinkBlock.qml | 14 ++-- dots/.config/quickshell/ii/services/Ai.qml | 12 +++ 5 files changed, 90 insertions(+), 44 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/AiMessage.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/AiMessage.qml index 62f1dc794..3cccb9d8f 100644 --- a/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/AiMessage.qml +++ b/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/AiMessage.qml @@ -105,7 +105,7 @@ Rectangle { anchors.right: parent.right anchors.leftMargin: 10 anchors.rightMargin: 10 - spacing: 7 + spacing: 12 Item { Layout.alignment: Qt.AlignVCenter @@ -177,6 +177,20 @@ Rectangle { ButtonGroup { spacing: 5 + AiMessageControlButton { + id: regenButton + buttonIcon: "refresh" + visible: messageData?.role === 'assistant' + + onClicked: { + Ai.regenerate(root.messageIndex) + } + + StyledToolTip { + text: Translation.tr("Regenerate") + } + } + AiMessageControlButton { id: copyButton buttonIcon: activated ? "inventory" : "content_copy" @@ -254,28 +268,50 @@ Rectangle { spacing: 0 Repeater { - model: root.messageBlocks.length - delegate: Loader { - required property int index - property var thisBlock: root.messageBlocks[index] - Layout.fillWidth: true - // property var segment: thisBlock - property var segmentContent: thisBlock.content - property var segmentLang: thisBlock.lang - property var messageData: root.messageData - property var editing: root.editing - property var renderMarkdown: root.renderMarkdown - property var enableMouseSelection: root.enableMouseSelection - property bool thinking: root.messageData?.thinking ?? true - property bool done: root.messageData?.done ?? false - property bool completed: thisBlock.completed ?? false + model: ScriptModel { + values: Array.from({ length: root.messageBlocks.length }, (msg, i) => { + return ({ + type: root.messageBlocks[i].type + }) + }); + } - property bool forceDisableChunkSplitting: root.messageData.content.includes("```") - - source: thisBlock.type === "code" ? "MessageCodeBlock.qml" : - thisBlock.type === "think" ? "MessageThinkBlock.qml" : - "MessageTextBlock.qml" + delegate: DelegateChooser { + id: messageDelegate + role: "type" + DelegateChoice { roleValue: "code"; MessageCodeBlock { + required property int index + property var thisBlock: root.messageBlocks[index] + editing: root.editing + renderMarkdown: root.renderMarkdown + enableMouseSelection: root.enableMouseSelection + segmentContent: thisBlock.content + segmentLang: thisBlock.lang + messageData: root.messageData + } } + DelegateChoice { roleValue: "think"; MessageThinkBlock { + required property int index + property var thisBlock: root.messageBlocks[index] + editing: root.editing + renderMarkdown: root.renderMarkdown + enableMouseSelection: root.enableMouseSelection + segmentContent: thisBlock.content + messageData: root.messageData + done: root.messageData?.done ?? false + completed: thisBlock.completed ?? false + } } + DelegateChoice { roleValue: "text"; MessageTextBlock { + required property int index + property var thisBlock: root.messageBlocks[index] + editing: root.editing + renderMarkdown: root.renderMarkdown + enableMouseSelection: root.enableMouseSelection + segmentContent: thisBlock.content + messageData: root.messageData + done: root.messageData?.done ?? false + forceDisableChunkSplitting: root.messageData.content.includes("```") + } } } } } diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/MessageCodeBlock.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/MessageCodeBlock.qml index c72905688..a6f69063d 100644 --- a/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/MessageCodeBlock.qml +++ b/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/MessageCodeBlock.qml @@ -13,22 +13,20 @@ import org.kde.syntaxhighlighting ColumnLayout { id: root // These are needed on the parent loader - property bool editing: parent?.editing ?? false - property bool renderMarkdown: parent?.renderMarkdown ?? true - property bool enableMouseSelection: parent?.enableMouseSelection ?? false - property var segmentContent: parent?.segmentContent ?? ({}) - property var segmentLang: parent?.segmentLang ?? "txt" + property bool editing: false + property bool renderMarkdown: true + property bool enableMouseSelection: false + property var segmentContent: ({}) + property var segmentLang: "txt" + property var messageData: {} property bool isCommandRequest: segmentLang === "command" property var displayLang: (isCommandRequest ? "bash" : segmentLang) - property var messageData: parent?.messageData ?? {} property real codeBlockBackgroundRounding: Appearance.rounding.small property real codeBlockHeaderPadding: 3 property real codeBlockComponentSpacing: 2 spacing: codeBlockComponentSpacing - anchors.left: parent.left - anchors.right: parent.right Rectangle { // Code background Layout.fillWidth: true diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/MessageTextBlock.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/MessageTextBlock.qml index a245b6979..2c471d3f8 100644 --- a/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/MessageTextBlock.qml +++ b/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/MessageTextBlock.qml @@ -14,17 +14,17 @@ import Quickshell.Hyprland ColumnLayout { id: root // These are needed on the parent loader - property bool editing: parent?.editing ?? false - property bool renderMarkdown: parent?.renderMarkdown ?? true - property bool enableMouseSelection: parent?.enableMouseSelection ?? false - property string segmentContent: parent?.segmentContent ?? ({}) - property var messageData: parent?.messageData ?? {} - property bool done: parent?.done ?? true - property list renderedLatexHashes: [] + property bool editing: false + property bool renderMarkdown: true + property bool enableMouseSelection: false + property var segmentContent: ({}) + property var messageData: {} + property bool done: true + property bool forceDisableChunkSplitting: false + property list renderedLatexHashes: [] property string renderedSegmentContent: "" property string shownText: "" - property bool forceDisableChunkSplitting: parent?.forceDisableChunkSplitting ?? false property bool fadeChunkSplitting: !forceDisableChunkSplitting && !editing && !/\n\|/.test(shownText) && Config.options.sidebar.ai.textFadeIn Layout.fillWidth: true diff --git a/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/MessageThinkBlock.qml b/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/MessageThinkBlock.qml index 8407a0b56..1463c6e60 100644 --- a/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/MessageThinkBlock.qml +++ b/dots/.config/quickshell/ii/modules/sidebarLeft/aiChat/MessageThinkBlock.qml @@ -11,13 +11,13 @@ import Qt5Compat.GraphicalEffects Item { id: root // These are needed on the parent loader - property bool editing: parent?.editing ?? false - property bool renderMarkdown: parent?.renderMarkdown ?? true - property bool enableMouseSelection: parent?.enableMouseSelection ?? false - property string segmentContent: parent?.segmentContent ?? ({}) - property var messageData: parent?.messageData ?? {} - property bool done: parent?.done ?? true - property bool completed: parent?.completed ?? false + property bool editing: false + property bool renderMarkdown: true + property bool enableMouseSelection: false + property var segmentContent: ({}) + property var messageData: {} + property bool done: true + property bool completed: false property real thinkBlockBackgroundRounding: Appearance.rounding.small property real thinkBlockHeaderPaddingVertical: 3 diff --git a/dots/.config/quickshell/ii/services/Ai.qml b/dots/.config/quickshell/ii/services/Ai.qml index 26657b0d1..47b1d151f 100644 --- a/dots/.config/quickshell/ii/services/Ai.qml +++ b/dots/.config/quickshell/ii/services/Ai.qml @@ -769,6 +769,18 @@ Singleton { root.pendingFilePath = CF.FileUtils.trimFileProtocol(filePath); } + function regenerate(messageIndex) { + if (messageIndex < 0 || messageIndex >= messageIDs.length) return; + const id = root.messageIDs[messageIndex]; + const message = root.messageByID[id]; + if (message.role !== "assistant") return; + // Remove all messages after this one + for (let i = root.messageIDs.length - 1; i >= messageIndex; i--) { + root.removeMessage(i); + } + requester.makeRequest(); + } + function createFunctionOutputMessage(name, output, includeOutputInChat = true) { return aiMessageComponent.createObject(root, { "role": "user", From 649be3741c0b4980d5b11d31ad8db25f7333aa64 Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 08:59:33 +0800 Subject: [PATCH 74/94] Add go-yq as dependency --- .../illogical-impulse-basic/PKGBUILD | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/sdata/dist-arch/illogical-impulse-basic/PKGBUILD b/sdata/dist-arch/illogical-impulse-basic/PKGBUILD index c338727f9..a403480e8 100644 --- a/sdata/dist-arch/illogical-impulse-basic/PKGBUILD +++ b/sdata/dist-arch/illogical-impulse-basic/PKGBUILD @@ -1,20 +1,22 @@ pkgname=illogical-impulse-basic pkgver=1.0 -pkgrel=1 +pkgrel=2 pkgdesc='Illogical Impulse Basic Dependencies' arch=(any) license=(None) depends=( - axel - bc - coreutils - cliphist - cmake - curl - rsync - wget - ripgrep - jq - meson - xdg-user-dirs + axel + bc + coreutils + cliphist + cmake + curl + wget + ripgrep + jq + meson + xdg-user-dirs + # Used in install script + rsync + go-yq # https://github.com/mikefarah/yq ) From bd8daf4015ebb3bcc567750c43315c297b9fced5 Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 09:00:11 +0800 Subject: [PATCH 75/94] Update backup logic in 3.files-exp.sh --- sdata/subcmd-install/3.files-exp.sh | 215 ++++------------------------ 1 file changed, 31 insertions(+), 184 deletions(-) diff --git a/sdata/subcmd-install/3.files-exp.sh b/sdata/subcmd-install/3.files-exp.sh index 350c0d8db..f35229535 100644 --- a/sdata/subcmd-install/3.files-exp.sh +++ b/sdata/subcmd-install/3.files-exp.sh @@ -24,200 +24,47 @@ function warning_rsync_normal(){ printf "${STY_RST}" } -function backup_clashing_targets(){ - # For dirs/files under target_dir, only backup those which clashes with the ones under source_dir - - # Deal with arguments - local source_dir="$1" - local target_dir="$2" - local backup_dir="$3" - - # Find clash dirs/files, save as clash_list - local clash_list=() - local source_list=($(ls -A "$source_dir")) - local target_list=($(ls -A "$target_dir")) - declare -A target_map - for i in "${target_list[@]}"; do - target_map["$i"]=1 - done - for i in "${source_list[@]}"; do - if [[ -n "${target_map[$i]}" ]]; then - clash_list+=("$i") - fi - done - - # Construct args_includes for rsync - for i in "${clash_list[@]}"; do - current_target=$target_dir/$i - if [[ -d $current_target ]]; then - args_includes+=(--include="$current_target/") - args_includes+=(--include="$current_target/**") - else - args_includes+=(--include="$current_target") - fi - done - args_includes+=(--exclude="*") - - x mkdir -p $backup_dir - x rsync -av --progress "${args_includes[@]}" "$target_dir/" "$backup_dir/" +function backup_configs(){ + backup_clashing_targets dots/.config $XDG_CONFIG_HOME "${BACKUP_DIR}/.config" + backup_clashing_targets dots/.local/share $XDG_DATA_HOME "${BACKUP_DIR}/.local/share" + printf "${STY_BLUE}Backup into \"${BACKUP_DIR}\" finished.${STY_RST}\n" } function ask_backup_configs(){ + showfun backup_clashing_targets printf "${STY_RED}" printf "Would you like to backup clashing dirs/files under \"$XDG_CONFIG_HOME\" and \"$XDG_DATA_HOME\" to \"$BACKUP_DIR\"?" - read -p "[y/N] " backup_confirm - case $backup_confirm in - [yY][eE][sS]|[yY]) - showfun backup_clashing_targets - v backup_clashing_targets dots/.config $XDG_CONFIG_HOME "${BACKUP_DIR}/.config" - v backup_clashing_targets dots/.local/share $XDG_DATA_HOME "${BACKUP_DIR}/.local/share" - ;; - *) echo "Skipping backup..." ;; - esac printf "${STY_RST}" + while true;do + echo " y = Yes, backup" + echo " n/s = No, skip to next" + local p; read -p "====> " p + case $p in + [yY]) echo -e "${STY_BLUE}OK, doing backup...${STY_RST}" ;local backup=true;break ;; + [nNsS]) echo -e "${STY_BLUE}Alright, skipping...${STY_RST}" ;local backup=false;break ;; + *) echo -e "${STY_RED}Please enter [y/n].${STY_RST}";; + esac + done + if $backup;then backup_configs;fi +} +function auto_backup_configs(){ + # Backup when $BACKUP_DIR does not exist + if [[ ! -d "$BACKUP_DIR" ]]; then backup_configs;fi } -# ============================================================================= -# CONFIGURATION FUNCTIONS -# ============================================================================= +##################################################################################### +showfun auto_get_git_submodule +v auto_get_git_submodule -# User preference wizard -wizard_update_preferences() { - echo -e "${STY_CYAN}=== Dotfiles Customization ===${STY_RESET}" - - # Get current preferences - current_shell=$(yq '.user_preferences.shell // "fish"' "$CONFIG_FILE") - current_terminal=$(yq '.user_preferences.terminal // "kitty"' "$CONFIG_FILE") - current_keybindings=$(yq '.user_preferences.keybindings // "default"' "$CONFIG_FILE") - - echo "Current preferences:" - echo " Shell: $current_shell" - echo " Terminal: $current_terminal" - echo " Keybindings: $current_keybindings" - echo - - # Shell selection - echo "Which shell do you prefer?" - echo "1) fish (default)" - echo "2) zsh" - read -p "Enter choice [1-2]: " shell_choice - - case "$shell_choice" in - 1|"") shell="fish" ;; - 2) shell="zsh" ;; - *) echo "Invalid choice, using fish"; shell="fish" ;; - esac - - # Terminal selection - echo - echo "Which terminal do you prefer?" - echo "1) kitty (default)" - echo "2) foot" - read -p "Enter choice [1-2]: " terminal_choice - - case "$terminal_choice" in - 1|"") terminal="kitty" ;; - 2) terminal="foot" ;; - *) echo "Invalid choice, using kitty"; terminal="kitty" ;; - esac - - # Keybindings selection - echo - echo "Which keybinding style do you prefer?" - echo "1) default (arrow keys)" - echo "2) vim (H/J/K/L)" - read -p "Enter choice [1-2]: " keybind_choice - - case "$keybind_choice" in - 1|"") keybindings="default" ;; - 2) keybindings="vim" ;; - *) echo "Invalid choice, using default"; keybindings="default" ;; - esac - - # Update YAML in-place - yq -i ".user_preferences.shell = \"$shell\"" "$CONFIG_FILE" - yq -i ".user_preferences.terminal = \"$terminal\"" "$CONFIG_FILE" - yq -i ".user_preferences.keybindings = \"$keybindings\"" "$CONFIG_FILE" - - echo - echo "Preferences updated!" -} +# In case some dirs does not exists +v mkdir -p $XDG_BIN_HOME $XDG_CACHE_HOME $XDG_CONFIG_HOME $XDG_DATA_HOME/icons -# Get user preference -get_pref() { - yq -r ".user_preferences.$1" "$CONFIG_FILE" -} - -# Check if pattern should be processed based on user preferences -should_process_pattern() { - local pattern="$1" - local condition=$(echo "$pattern" | yq '.condition // "true"') - - # If no condition or condition is "true", always process - if [[ "$condition" == "true" ]]; then - return 0 - fi - - # Extract the preference type and value from condition - local type=$(echo "$condition" | yq '.type') - local value=$(echo "$condition" | yq '.value') - - [[ "$(get_pref "$type")" == "$value" ]] - -} - -# Compare hashes of files/directories, return true if they are the same, false otherwise -files_are_same() { - local path1="$1" - local path2="$2" - - # Check if paths exist - if [[ ! -e "$path1" || ! -e "$path2" ]]; then - return 1 - fi - - # For directories, use find + md5sum to compare recursively - # For files, use md5sum directly - if [[ -d "$path1" && -d "$path2" ]]; then - # Compare directory contents using find and md5sum - local hash1=$(find "$path1" -type f -exec md5sum {} \; | sort -k 2 | md5sum | awk '{print $1}') - local hash2=$(find "$path2" -type f -exec md5sum {} \; | sort -k 2 | md5sum | awk '{print $1}') - [[ "$hash1" == "$hash2" ]] - elif [[ -f "$path1" && -f "$path2" ]]; then - # Compare file hashes - local hash1=$(md5sum "$path1" | awk '{print $1}') - local hash2=$(md5sum "$path2" | awk '{print $1}') - [[ "$hash1" == "$hash2" ]] - else - # One is a file, one is a directory - different types - return 1 - fi -} - -# Find next backup number -get_next_backup_number() { - local base_path="$1" - local counter=1 - - while [[ -e "${base_path}.old.${counter}" ]]; do - ((counter++)) - done - - echo $counter -} - -# ============================================================================= -# MAIN EXECUTION -# ============================================================================= - -# Ensure directories exist -v mkdir -p $XDG_BIN_HOME $XDG_CACHE_HOME $XDG_CONFIG_HOME $XDG_DATA_HOME - -# Handle backup -case $ask in - false) sleep 0 ;; - *) ask_backup_configs ;; -esac +if [[ ! "${SKIP_BACKUP}" == true ]]; then + case $ask in + false) auto_backup_configs ;; + *) ask_backup_configs ;; + esac +fi # Run user preference wizard case $ask in From d51ce6a46f9cfa81fed30de8da8d1955d44e2f45 Mon Sep 17 00:00:00 2001 From: jwihardi Date: Wed, 29 Oct 2025 22:35:39 -0400 Subject: [PATCH 76/94] gentoo added yq-go --- .../illogical-impulse-basic-1.0-r1.ebuild | 1 + 1 file changed, 1 insertion(+) diff --git a/sdata/dist-gentoo/illogical-impulse-basic/illogical-impulse-basic-1.0-r1.ebuild b/sdata/dist-gentoo/illogical-impulse-basic/illogical-impulse-basic-1.0-r1.ebuild index 535e80725..eeae5c57b 100644 --- a/sdata/dist-gentoo/illogical-impulse-basic/illogical-impulse-basic-1.0-r1.ebuild +++ b/sdata/dist-gentoo/illogical-impulse-basic/illogical-impulse-basic-1.0-r1.ebuild @@ -25,4 +25,5 @@ RDEPEND=" dev-python/jq dev-build/meson x11-misc/xdg-user-dirs + app-misc/yq-go " From 34c46910b23bd9ebccfbcb5339baa0e832b8d980 Mon Sep 17 00:00:00 2001 From: jwihardi Date: Wed, 29 Oct 2025 22:38:03 -0400 Subject: [PATCH 77/94] updated version number wups, removed revision 1 --- ...-basic-1.0-r1.ebuild => illogical-impulse-basic-1.0-r2.ebuild} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename sdata/dist-gentoo/illogical-impulse-basic/{illogical-impulse-basic-1.0-r1.ebuild => illogical-impulse-basic-1.0-r2.ebuild} (100%) diff --git a/sdata/dist-gentoo/illogical-impulse-basic/illogical-impulse-basic-1.0-r1.ebuild b/sdata/dist-gentoo/illogical-impulse-basic/illogical-impulse-basic-1.0-r2.ebuild similarity index 100% rename from sdata/dist-gentoo/illogical-impulse-basic/illogical-impulse-basic-1.0-r1.ebuild rename to sdata/dist-gentoo/illogical-impulse-basic/illogical-impulse-basic-1.0-r2.ebuild From 60a0dcfdcf0d39c3044528310dfd9fecb76ec120 Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 11:57:58 +0800 Subject: [PATCH 78/94] No more prompt about how to use ii on AGS --- sdata/subcmd-install/0.greeting.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sdata/subcmd-install/0.greeting.sh b/sdata/subcmd-install/0.greeting.sh index 413aacf64..a948e5f3c 100644 --- a/sdata/subcmd-install/0.greeting.sh +++ b/sdata/subcmd-install/0.greeting.sh @@ -9,10 +9,8 @@ printf "${STY_CYAN}[$0]: Hi there! Before we start:${STY_RST}\n" printf "\n" printf "${STY_PURPLE}${STY_BOLD}[NEW] illogical-impulse is now powered by Quickshell.${STY_RST}\n" printf "${STY_PURPLE}" +printf '# NOTE: illogical-impulse on AGS is no longer supported.\n' printf '# If you were using the old version with AGS and would like to keep it, do not run this script.\n' -printf '# The AGS version, although uses less memory, has much worse performance (it uses Gtk3). \n' -printf '# If you aren'\''t running on ewaste, the Quickshell version is recommended. \n' -printf "# If you would like the AGS version anyway, run the following to switch to its branch first:\n ${STY_INVERT} git checkout ii-ags && ./install.sh ${STY_RST}\n" printf "\n" pause printf "${STY_CYAN}${STY_BOLD}Quick overview about what this script does:${STY_RST}\n" From 0ac39d4356689dcbb59f82f4a9178484bf219960 Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 12:15:21 +0800 Subject: [PATCH 79/94] Add subcmd checkdeps --- sdata/subcmd-checkdeps/0.run.sh | 19 ++++++++++++ sdata/subcmd-checkdeps/options.sh | 48 +++++++++++++++++++++++++++++++ setup | 3 +- 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 sdata/subcmd-checkdeps/0.run.sh create mode 100644 sdata/subcmd-checkdeps/options.sh diff --git a/sdata/subcmd-checkdeps/0.run.sh b/sdata/subcmd-checkdeps/0.run.sh new file mode 100644 index 000000000..b61d68bed --- /dev/null +++ b/sdata/subcmd-checkdeps/0.run.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# Check whether pkgs exist in AUR or repos of Arch. +# +# Do NOT abuse this since it consumes extra bandwidth from AUR server. + +pkglistfile=$(mktemp) +pkglistfile_orig=${LIST_FILE_PATH} +mkdir -p ./cache +pkglistfile_orig_s=./cache/dependencies_stripped.conf +remove_bashcomments_emptylines $pkglistfile_orig $pkglistfile_orig_s + +cat $pkglistfile_orig_s | sed "s_\ _\n_g" > $pkglistfile + +echo "The non-existent pkgs in $pkglistfile_orig are listed as follows." +# Borrowed from https://bbs.archlinux.org/viewtopic.php?pid=1490795#p1490795 +comm -23 <(sort -u $pkglistfile) <(sort -u <(wget -q -O - https://aur.archlinux.org/packages.gz | gunzip) <(pacman -Ssq)) +echo "End of list. If nothing appears, then all pkgs exist." +rm $pkglistfile + diff --git a/sdata/subcmd-checkdeps/options.sh b/sdata/subcmd-checkdeps/options.sh new file mode 100644 index 000000000..903a9c71d --- /dev/null +++ b/sdata/subcmd-checkdeps/options.sh @@ -0,0 +1,48 @@ +# Handle args for subcmd: exp-uninstall +# shellcheck shell=bash + +showhelp(){ +echo -e "Syntax: $0 checkdeps [OPTIONS]... + +Experimental unintallation. + +Options: + -h, --help Show this help message + --file A file in plain text containing package names +" +} +# `man getopt` to see more +para=$(getopt \ + -o h \ + -l help,file: \ + -n "$0" -- "$@") +[ $? != 0 ] && echo "$0: Error when getopt, please recheck parameters." && exit 1 +##################################################################################### +## getopt Phase 1 +# ignore parameter's order, execute options below first +eval set -- "$para" +while true ; do + case "$1" in + -h|--help) showhelp;exit;; + --) break ;; + *) shift ;; + esac +done +##################################################################################### +## getopt Phase 2 + +eval set -- "$para" +while true ; do + case "$1" in + ## Ones with parameter + --file) + if [[ -f "$2" ]]; + then echo "Using list file \"$2\".";LIST_FILE_PATH="$2";shift 2 + else echo "Wrong argument for $1.";exit 1 + fi;; + + ## Ending + --) break ;; + *) echo -e "$0: Wrong parameters.";exit 1;; + esac +done diff --git a/setup b/setup index 170e43464..cae0a1928 100755 --- a/setup +++ b/setup @@ -24,6 +24,7 @@ Subcommands: exp-uninstall (Experimental) Uninstall illogical-impulse. exp-update (Experimental) Update illogical-impulse without fully reinstall. exp-update-old (Experimental) exp-update but use behaves like old version. + checkdeps (For dev only) Check whether pkgs exist in AUR or repos of Arch. help Show this help message. For each , use -h for details: @@ -34,7 +35,7 @@ case $1 in # Global help help|--help|-h)showhelp_global;exit;; # Correct subcommand - install|exp-uninstall|exp-update|exp-update-old) + install|exp-uninstall|exp-update|exp-update-old|checkdeps) SUBCMD_NAME=$1 SUBCMD_DIR=./sdata/subcmd-$1 shift;; From 634fb09d2e2c01efb942a170838976a4508ff0df Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 12:25:15 +0800 Subject: [PATCH 80/94] Update checkdeps --- sdata/lib/functions.sh | 3 ++- sdata/subcmd-checkdeps/0.run.sh | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdata/lib/functions.sh b/sdata/lib/functions.sh index ff2b80caf..450698fb8 100644 --- a/sdata/lib/functions.sh +++ b/sdata/lib/functions.sh @@ -69,7 +69,8 @@ function pause(){ fi } function remove_bashcomments_emptylines(){ - mkdir -p "$(dirname "$2")" && cat "$1" | sed -e 's/#.*//' -e '/^[[:space:]]*$/d' > "$2" + mkdir -p "$(dirname "$2")" + cat "$1" | sed -e 's/#.*//' -e '/^[[:space:]]*$/d' > "$2" } function prevent_sudo_or_root(){ case $(whoami) in diff --git a/sdata/subcmd-checkdeps/0.run.sh b/sdata/subcmd-checkdeps/0.run.sh index b61d68bed..cc8465a91 100644 --- a/sdata/subcmd-checkdeps/0.run.sh +++ b/sdata/subcmd-checkdeps/0.run.sh @@ -5,8 +5,7 @@ pkglistfile=$(mktemp) pkglistfile_orig=${LIST_FILE_PATH} -mkdir -p ./cache -pkglistfile_orig_s=./cache/dependencies_stripped.conf +pkglistfile_orig_s=${REPO_ROOT}/cache/dependencies_stripped.conf remove_bashcomments_emptylines $pkglistfile_orig $pkglistfile_orig_s cat $pkglistfile_orig_s | sed "s_\ _\n_g" > $pkglistfile From 8b25e2b037af33d2ecc0a5dd66b978cbdfce5fda Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 12:27:19 +0800 Subject: [PATCH 81/94] Update checkdeps --- sdata/lib/functions.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sdata/lib/functions.sh b/sdata/lib/functions.sh index 450698fb8..472c8f57a 100644 --- a/sdata/lib/functions.sh +++ b/sdata/lib/functions.sh @@ -70,6 +70,9 @@ function pause(){ } function remove_bashcomments_emptylines(){ mkdir -p "$(dirname "$2")" + echo "pwd=$(pwd)" + echo "input=$1" + echo "output=$2" cat "$1" | sed -e 's/#.*//' -e '/^[[:space:]]*$/d' > "$2" } function prevent_sudo_or_root(){ From f32431035576a0cdc5fe7529b95875d63b4e197c Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 12:33:34 +0800 Subject: [PATCH 82/94] Update checkdeps --- sdata/lib/functions.sh | 2 +- sdata/subcmd-checkdeps/options.sh | 31 +++++++++---------------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/sdata/lib/functions.sh b/sdata/lib/functions.sh index 472c8f57a..b236b8324 100644 --- a/sdata/lib/functions.sh +++ b/sdata/lib/functions.sh @@ -69,10 +69,10 @@ function pause(){ fi } function remove_bashcomments_emptylines(){ - mkdir -p "$(dirname "$2")" echo "pwd=$(pwd)" echo "input=$1" echo "output=$2" + mkdir -p "$(dirname "$2")" cat "$1" | sed -e 's/#.*//' -e '/^[[:space:]]*$/d' > "$2" } function prevent_sudo_or_root(){ diff --git a/sdata/subcmd-checkdeps/options.sh b/sdata/subcmd-checkdeps/options.sh index 903a9c71d..48d085c88 100644 --- a/sdata/subcmd-checkdeps/options.sh +++ b/sdata/subcmd-checkdeps/options.sh @@ -1,20 +1,19 @@ -# Handle args for subcmd: exp-uninstall +# Handle args for subcmd: checkdeps # shellcheck shell=bash showhelp(){ -echo -e "Syntax: $0 checkdeps [OPTIONS]... +echo -e "Syntax: $0 checkdeps [OPTIONS] ... -Experimental unintallation. +Check whether pkgs listed in exist in AUR or repos of Arch. Options: -h, --help Show this help message - --file A file in plain text containing package names " } # `man getopt` to see more para=$(getopt \ -o h \ - -l help,file: \ + -l help \ -n "$0" -- "$@") [ $? != 0 ] && echo "$0: Error when getopt, please recheck parameters." && exit 1 ##################################################################################### @@ -28,21 +27,9 @@ while true ; do *) shift ;; esac done -##################################################################################### -## getopt Phase 2 -eval set -- "$para" -while true ; do - case "$1" in - ## Ones with parameter - --file) - if [[ -f "$2" ]]; - then echo "Using list file \"$2\".";LIST_FILE_PATH="$2";shift 2 - else echo "Wrong argument for $1.";exit 1 - fi;; - - ## Ending - --) break ;; - *) echo -e "$0: Wrong parameters.";exit 1;; - esac -done +if [[ -f "$1" ]]; then + echo "Using list file \"$1\".";LIST_FILE_PATH="$1";shift 2 +else + echo "Wrong path of list file.";exit 1 +fi From 5509e217591a5dd12d867ca73bf56cb469186efe Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 12:37:05 +0800 Subject: [PATCH 83/94] Update checkdeps --- sdata/subcmd-checkdeps/options.sh | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/sdata/subcmd-checkdeps/options.sh b/sdata/subcmd-checkdeps/options.sh index 48d085c88..909c055e7 100644 --- a/sdata/subcmd-checkdeps/options.sh +++ b/sdata/subcmd-checkdeps/options.sh @@ -28,8 +28,16 @@ while true ; do esac done -if [[ -f "$1" ]]; then - echo "Using list file \"$1\".";LIST_FILE_PATH="$1";shift 2 -else - echo "Wrong path of list file.";exit 1 -fi +eval set -- "$para" +while true ; do + case "$1" in + --) break ;; + *) + if [[ -f "$1" ]]; then + echo "Using list file \"$1\".";LIST_FILE_PATH="$1";shift 1 + else + echo "Wrong path of list file.";exit 1 + fi + ;; + esac +done From dabd8dc1368df403ff59135bcd6ccf60afd6b16b Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 12:44:27 +0800 Subject: [PATCH 84/94] Update checkdeps --- sdata/subcmd-checkdeps/options.sh | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/sdata/subcmd-checkdeps/options.sh b/sdata/subcmd-checkdeps/options.sh index 909c055e7..562b2e364 100644 --- a/sdata/subcmd-checkdeps/options.sh +++ b/sdata/subcmd-checkdeps/options.sh @@ -17,27 +17,17 @@ para=$(getopt \ -n "$0" -- "$@") [ $? != 0 ] && echo "$0: Error when getopt, please recheck parameters." && exit 1 ##################################################################################### -## getopt Phase 1 -# ignore parameter's order, execute options below first eval set -- "$para" while true ; do case "$1" in -h|--help) showhelp;exit;; - --) break ;; - *) shift ;; + --) shift;break ;; + *) sleep 0 ;; esac done -eval set -- "$para" -while true ; do - case "$1" in - --) break ;; - *) - if [[ -f "$1" ]]; then - echo "Using list file \"$1\".";LIST_FILE_PATH="$1";shift 1 - else - echo "Wrong path of list file.";exit 1 - fi - ;; - esac -done +if [[ -f "$1" ]]; then + echo "Using list file \"$1\".";LIST_FILE_PATH="$1";shift 1 +else + echo "Wrong path \"$1\" of list file.";exit 1 +fi From e5934c3eedb6a7b6bc26e54d11d451e532c5c180 Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 12:47:06 +0800 Subject: [PATCH 85/94] Update checkdeps --- sdata/subcmd-checkdeps/0.run.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sdata/subcmd-checkdeps/0.run.sh b/sdata/subcmd-checkdeps/0.run.sh index cc8465a91..3e41a9f35 100644 --- a/sdata/subcmd-checkdeps/0.run.sh +++ b/sdata/subcmd-checkdeps/0.run.sh @@ -6,6 +6,15 @@ pkglistfile=$(mktemp) pkglistfile_orig=${LIST_FILE_PATH} pkglistfile_orig_s=${REPO_ROOT}/cache/dependencies_stripped.conf +if ! $(command -v wget);then + echo "Please install wget first.";exit 1 +fi +if ! $(command -v gunzip);then + echo "Please install gunzip first.";exit 1 +fi +if ! $(command -v pacman);then + echo "pacman not found, aborting...";exit 1 +fi remove_bashcomments_emptylines $pkglistfile_orig $pkglistfile_orig_s cat $pkglistfile_orig_s | sed "s_\ _\n_g" > $pkglistfile @@ -15,4 +24,3 @@ echo "The non-existent pkgs in $pkglistfile_orig are listed as follows." comm -23 <(sort -u $pkglistfile) <(sort -u <(wget -q -O - https://aur.archlinux.org/packages.gz | gunzip) <(pacman -Ssq)) echo "End of list. If nothing appears, then all pkgs exist." rm $pkglistfile - From 86a10e9af55ea3066a73056e18a43a802eab938b Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 12:50:17 +0800 Subject: [PATCH 86/94] Update checkdeps --- sdata/subcmd-checkdeps/0.run.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sdata/subcmd-checkdeps/0.run.sh b/sdata/subcmd-checkdeps/0.run.sh index 3e41a9f35..0316b11b5 100644 --- a/sdata/subcmd-checkdeps/0.run.sh +++ b/sdata/subcmd-checkdeps/0.run.sh @@ -6,11 +6,11 @@ pkglistfile=$(mktemp) pkglistfile_orig=${LIST_FILE_PATH} pkglistfile_orig_s=${REPO_ROOT}/cache/dependencies_stripped.conf -if ! $(command -v wget);then - echo "Please install wget first.";exit 1 +if ! $(command -v curl);then + echo "Please install curl first.";exit 1 fi -if ! $(command -v gunzip);then - echo "Please install gunzip first.";exit 1 +if ! $(command -v gzip);then + echo "Please install gzip first.";exit 1 fi if ! $(command -v pacman);then echo "pacman not found, aborting...";exit 1 @@ -21,6 +21,7 @@ cat $pkglistfile_orig_s | sed "s_\ _\n_g" > $pkglistfile echo "The non-existent pkgs in $pkglistfile_orig are listed as follows." # Borrowed from https://bbs.archlinux.org/viewtopic.php?pid=1490795#p1490795 -comm -23 <(sort -u $pkglistfile) <(sort -u <(wget -q -O - https://aur.archlinux.org/packages.gz | gunzip) <(pacman -Ssq)) +#comm -23 <(sort -u $pkglistfile) <(sort -u <(wget -q -O - https://aur.archlinux.org/packages.gz | gunzip) <(pacman -Ssq)) +comm -23 <(sort -u $pkglistfile) <(curl https://aur.archlinux.org/packages.gz | gzip -cd | sort) echo "End of list. If nothing appears, then all pkgs exist." rm $pkglistfile From bdc55dd082c7382ccd08d758b8e752fc71ada6d4 Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 12:52:16 +0800 Subject: [PATCH 87/94] Update checkdeps --- sdata/subcmd-checkdeps/0.run.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdata/subcmd-checkdeps/0.run.sh b/sdata/subcmd-checkdeps/0.run.sh index 0316b11b5..11ff87eb8 100644 --- a/sdata/subcmd-checkdeps/0.run.sh +++ b/sdata/subcmd-checkdeps/0.run.sh @@ -6,13 +6,13 @@ pkglistfile=$(mktemp) pkglistfile_orig=${LIST_FILE_PATH} pkglistfile_orig_s=${REPO_ROOT}/cache/dependencies_stripped.conf -if ! $(command -v curl);then +if ! "$(command -v curl)";then echo "Please install curl first.";exit 1 fi -if ! $(command -v gzip);then +if ! "$(command -v gzip)";then echo "Please install gzip first.";exit 1 fi -if ! $(command -v pacman);then +if ! "$(command -v pacman)";then echo "pacman not found, aborting...";exit 1 fi remove_bashcomments_emptylines $pkglistfile_orig $pkglistfile_orig_s From f50a3fe6869370297912b665a892ab45e9a9f7cf Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 12:57:01 +0800 Subject: [PATCH 88/94] Update checkdeps --- sdata/subcmd-checkdeps/0.run.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sdata/subcmd-checkdeps/0.run.sh b/sdata/subcmd-checkdeps/0.run.sh index 11ff87eb8..21421ef33 100644 --- a/sdata/subcmd-checkdeps/0.run.sh +++ b/sdata/subcmd-checkdeps/0.run.sh @@ -6,15 +6,15 @@ pkglistfile=$(mktemp) pkglistfile_orig=${LIST_FILE_PATH} pkglistfile_orig_s=${REPO_ROOT}/cache/dependencies_stripped.conf -if ! "$(command -v curl)";then - echo "Please install curl first.";exit 1 -fi -if ! "$(command -v gzip)";then - echo "Please install gzip first.";exit 1 -fi -if ! "$(command -v pacman)";then - echo "pacman not found, aborting...";exit 1 -fi +#if ! "$(command -v curl)";then +# echo "Please install curl first.";exit 1 +#fi +#if ! "$(command -v gzip)";then +# echo "Please install gzip first.";exit 1 +#fi +#if ! "$(command -v pacman)";then +# echo "pacman not found, aborting...";exit 1 +#fi remove_bashcomments_emptylines $pkglistfile_orig $pkglistfile_orig_s cat $pkglistfile_orig_s | sed "s_\ _\n_g" > $pkglistfile From f10bbacf7b927baa2c78157b2b28d1a2a908a8c8 Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 12:58:24 +0800 Subject: [PATCH 89/94] Update checkdeps --- sdata/subcmd-checkdeps/0.run.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sdata/subcmd-checkdeps/0.run.sh b/sdata/subcmd-checkdeps/0.run.sh index 21421ef33..3c95097b5 100644 --- a/sdata/subcmd-checkdeps/0.run.sh +++ b/sdata/subcmd-checkdeps/0.run.sh @@ -21,7 +21,6 @@ cat $pkglistfile_orig_s | sed "s_\ _\n_g" > $pkglistfile echo "The non-existent pkgs in $pkglistfile_orig are listed as follows." # Borrowed from https://bbs.archlinux.org/viewtopic.php?pid=1490795#p1490795 -#comm -23 <(sort -u $pkglistfile) <(sort -u <(wget -q -O - https://aur.archlinux.org/packages.gz | gunzip) <(pacman -Ssq)) -comm -23 <(sort -u $pkglistfile) <(curl https://aur.archlinux.org/packages.gz | gzip -cd | sort) +comm -23 <(sort -u $pkglistfile) <(sort -u <(curl https://aur.archlinux.org/packages.gz | gzip -cd | sort) <(pacman -Ssq)) echo "End of list. If nothing appears, then all pkgs exist." rm $pkglistfile From b0f09b20d4cc981b6226842690c4694eb0b24d62 Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 13:27:26 +0800 Subject: [PATCH 90/94] Fix message format --- sdata/subcmd-install/3.files.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdata/subcmd-install/3.files.sh b/sdata/subcmd-install/3.files.sh index 3a9c315d8..ead48593f 100644 --- a/sdata/subcmd-install/3.files.sh +++ b/sdata/subcmd-install/3.files.sh @@ -27,7 +27,7 @@ function backup_configs(){ function ask_backup_configs(){ showfun backup_clashing_targets printf "${STY_RED}" - printf "Would you like to backup clashing dirs/files under \"$XDG_CONFIG_HOME\" and \"$XDG_DATA_HOME\" to \"$BACKUP_DIR\"?" + printf "Would you like to backup clashing dirs/files under \"$XDG_CONFIG_HOME\" and \"$XDG_DATA_HOME\" to \"$BACKUP_DIR\"?\n" printf "${STY_RST}" while true;do echo " y = Yes, backup" From ae87646e40309e3fe897dc5cae9284812b1b55f7 Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 15:45:49 +0800 Subject: [PATCH 91/94] Update submodule in exp-update (#2334) --- sdata/subcmd-exp-update-old/0.run.sh | 1 + sdata/subcmd-exp-update/0.run.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/sdata/subcmd-exp-update-old/0.run.sh b/sdata/subcmd-exp-update-old/0.run.sh index 76ddd9ed9..dc4b97075 100644 --- a/sdata/subcmd-exp-update-old/0.run.sh +++ b/sdata/subcmd-exp-update-old/0.run.sh @@ -541,6 +541,7 @@ if git remote get-url origin &>/dev/null; then log_info "Pulling changes from origin/$current_branch..." if git pull; then log_success "Successfully pulled latest changes" + git submodule update --init --recursive else log_warning "Failed to pull changes from remote. Continuing with local repository..." log_info "You may need to resolve conflicts manually later." diff --git a/sdata/subcmd-exp-update/0.run.sh b/sdata/subcmd-exp-update/0.run.sh index 632d63082..2ab21379c 100644 --- a/sdata/subcmd-exp-update/0.run.sh +++ b/sdata/subcmd-exp-update/0.run.sh @@ -844,6 +844,7 @@ if git remote get-url origin &>/dev/null; then else if git pull --ff-only; then log_success "Successfully pulled latest changes" + git submodule update --init --recursive # Verify we actually got new commits if git rev-parse --verify HEAD@{1} &>/dev/null; then if [[ "$(git rev-parse HEAD)" == "$(git rev-parse HEAD@{1})" ]]; then From 175379dfdba0c51675ac1cbdd12f3f1b893d9177 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 09:03:11 +0100 Subject: [PATCH 92/94] locksurface: adjust fingerprint icon size/spacing --- .../ii/modules/lock/LockSurface.qml | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml index 1f7c47c75..8a3a73f60 100644 --- a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml +++ b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml @@ -101,22 +101,17 @@ MouseArea { // Fingerprint Loader { Layout.leftMargin: 10 + Layout.rightMargin: 6 Layout.alignment: Qt.AlignVCenter - active: root.context.fingerprintsConfigured // Bind to actual fingerprint availability - visible: root.context.fingerprintsConfigured + active: root.context.fingerprintsConfigured + visible: active - sourceComponent: Row { - spacing: 8 - - MaterialSymbol { - id: fingerprintIcon - anchors.verticalCenter: parent.verticalCenter - fill: 1 - text: "fingerprint" - iconSize: Appearance.font.pixelSize.huge - color: Appearance.colors.colOnSurfaceVariant - animateChange: true - } + sourceComponent: MaterialSymbol { + id: fingerprintIcon + fill: 1 + text: "fingerprint" + iconSize: Appearance.font.pixelSize.hugeass + color: Appearance.colors.colOnSurfaceVariant } } From e3db8372a7f1d8de4c2d0ff311c468e3db2248c4 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 09:04:58 +0100 Subject: [PATCH 93/94] lock: remove useless comment, declare fingerprint check proc running directly --- dots/.config/quickshell/ii/modules/lock/LockContext.qml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/lock/LockContext.qml b/dots/.config/quickshell/ii/modules/lock/LockContext.qml index 8b245237b..dcfd9a85d 100644 --- a/dots/.config/quickshell/ii/modules/lock/LockContext.qml +++ b/dots/.config/quickshell/ii/modules/lock/LockContext.qml @@ -2,7 +2,7 @@ import qs import qs.modules.common import QtQuick import Quickshell -import Quickshell.Io // Required for StdioCollector +import Quickshell.Io import Quickshell.Services.Pam Scope { @@ -22,10 +22,6 @@ Scope { property bool fingerprintsConfigured: false property var targetAction: LockContext.ActionEnum.Unlock - Component.onCompleted: { - fingerprintCheckProcess.running = true; - } - function resetTargetAction() { root.targetAction = LockContext.ActionEnum.Unlock; } @@ -77,7 +73,8 @@ Scope { } Process { - id: fingerprintCheckProcess + id: fingerprintCheckProc + running: true command: ["bash", "-c", "fprintd-list $(whoami)"] stdout: StdioCollector { id: fingerprintOutputCollector From c7bc853ab3ad51aa2c5184c8b80658c110485805 Mon Sep 17 00:00:00 2001 From: "Celestial.y" Date: Thu, 30 Oct 2025 16:55:44 +0800 Subject: [PATCH 94/94] Update nix install-deps.sh --- sdata/dist-nix/install-deps.sh | 127 +++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/sdata/dist-nix/install-deps.sh b/sdata/dist-nix/install-deps.sh index 77697e501..59ffec887 100644 --- a/sdata/dist-nix/install-deps.sh +++ b/sdata/dist-nix/install-deps.sh @@ -2,3 +2,130 @@ # It's not for directly running. # This file is currently WIP. + +function install_home-manager(){ + # https://nix-community.github.io/home-manager/index.xhtml#sec-install-standalone + local cmd=home-manager + # Maybe installed already, just not sourced yet + try source $HOME/.nix-profile/etc/profile.d/hm-session-vars.sh + command -v $cmd && return + + x nix-channel --add https://nixos.org/channels/nixos-25.05 nixpkgs-home + x nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.05.tar.gz home-manager + x nix-channel --update + x env NIX_PATH="nixpkgs=$HOME/.nix-defexpr/channels/nixpkgs-home" nix-shell '' -A install + + command -v $cmd && return + echo "Failed in installing $cmd." + echo "Please install it by yourself and then retry." + return 1 +} +function install_nix(){ + # https://github.com/NixOS/experimental-nix-installer + local cmd=nix + + x mkdir -p ${REPO_ROOT}/cache + x curl -JLo ${REPO_ROOT}/cache/nix-installer https://artifacts.nixos.org/experimental-installer + x sh ${REPO_ROOT}/cache/nix-installer install + try source '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' + + command -v $cmd && return + echo "Failed in installing $cmd." + echo "Please install it by yourself and then retry." + return 1 +} +function install_curl(){ + local cmd=curl + + if [[ "$OS_DISTRO_ID" == "arch" || "$OS_DISTRO_ID_LIKE" == "arch" || "$OS_DISTRO_ID" == "cachyos" ]]; then + x sudo pacman -Syu + x sudo pacman -S --noconfirm $cmd + elif [[ "$OS_DISTRO_ID" == "debian" || "$OS_DISTRO_ID_LIKE" == "debian" ]]; then + x sudo apt update + x sudo apt install $cmd + fi + + command -v $cmd && return + echo "Failed in installing $cmd." + echo "Please install it by yourself and then retry." + return 1 +} +function install_zsh(){ + local cmd=zsh + + if [[ "$OS_DISTRO_ID" == "arch" || "$OS_DISTRO_ID_LIKE" == "arch" || "$OS_DISTRO_ID" == "cachyos" ]]; then + x sudo pacman -Syu + x sudo pacman -S --noconfirm $cmd + elif [[ "$OS_DISTRO_ID" == "debian" || "$OS_DISTRO_ID_LIKE" == "debian" ]]; then + x sudo apt update + x sudo apt install $cmd + fi + + command -v $cmd && return + echo "Failed in installing $cmd." + echo "Please install it by yourself and then retry." + return 1 +} +function install_swaylock(){ + local cmd=swaylock + echo "Detecting command \"$cmd\"..." + command -v $cmd && return + echo "Command \"$cmd\" not found, try to install..." + + if [[ "$OS_DISTRO_ID" == "arch" || "$OS_DISTRO_ID_LIKE" == "arch" || "$OS_DISTRO_ID" == "cachyos" ]]; then + x sudo pacman -Syu + x sudo pacman -S --noconfirm $cmd + elif [[ "$OS_DISTRO_ID" == "debian" || "$OS_DISTRO_ID_LIKE" == "debian" ]]; then + x sudo apt update + x sudo apt install $cmd + fi + + command -v $cmd && return + echo "Failed in installing $cmd." + echo "Please install it by yourself and then retry." + return 1 +} + +function hm_deps(){ + SETUP_HM_DIR="${REPO_ROOT}/sdata/dist-nix/home-manager" + SETUP_USERNAME_NIXFILE="${SETUP_HM_DIR}/username.nix" + echo "\"$(whoami)\"" > "${SETUP_USERNAME_NIXFILE}" + x git add "${SETUP_USERNAME_NIXFILE}" + cd $SETUP_HM_DIR + x home-manager switch --flake .#illogical_impulse \ + --extra-experimental-features nix-command \ + --extra-experimental-features flakes + cd $REPO_ROOT + x git reset "${SETUP_USERNAME_NIXFILE}" +} + +################################################## +################################################## +if ! command -v curl >/dev/null 2>&1;then + echo -e "${STY_YELLOW}[$0]: \"curl\" not found.${STY_RST}" + showfun install_curl + v install_curl +fi +if ! command -v zsh >/dev/null 2>&1;then + echo -e "${STY_YELLOW}[$0]: \"zsh\" not found.${STY_RST}" + showfun install_zsh + v install_zsh +fi +if ! command -v swaylock >/dev/null 2>&1;then + echo -e "${STY_YELLOW}[$0]: \"swaylock\" not found.${STY_RST}" + showfun install_swaylock + v install_swaylock +fi +if ! command -v nix >/dev/null 2>&1;then + echo -e "${STY_YELLOW}[$0]: \"nix\" not found.${STY_RST}" + showfun install_nix + v install_nix +fi +if ! command -v home-manager >/dev/null 2>&1;then + echo -e "${STY_YELLOW}[$0]: \"home-manager\" not found.${STY_RST}" + showfun install_home-manager + v install_home-manager +fi + +showfun hm_deps +v hm_deps \ No newline at end of file