From 3faa20a29b63dafa8458529d644aab348cadd91b Mon Sep 17 00:00:00 2001 From: Trung Coder <110972143+laiviettrung@users.noreply.github.com> Date: Sun, 26 Oct 2025 21:22:08 +0700 Subject: [PATCH 01/59] Small animation for quickshell lock --- .../ii/modules/lock/LockSurface.qml | 62 ++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml index 5feba6c72..2594513a1 100644 --- a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml +++ b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml @@ -99,32 +99,52 @@ MouseArea { opacity: root.toolbarOpacity ToolbarTextField { - id: passwordBox - placeholderText: GlobalStates.screenUnlockFailed ? Translation.tr("Incorrect password") : Translation.tr("Enter password") + id: passwordBox + placeholderText: GlobalStates.screenUnlockFailed ? Translation.tr("Incorrect password") : Translation.tr("Enter password") + clip: true + font.pixelSize: Appearance.font.pixelSize.small + enabled: !root.context.unlockInProgress + echoMode: TextInput.Password + inputMethodHints: Qt.ImhSensitiveData + onTextChanged: root.context.currentText = this.text + onAccepted: root.context.tryUnlock() + Connections { + target: root.context + function onCurrentTextChanged() { + passwordBox.text = root.context.currentText; + } + } + Keys.onPressed: event => { + root.context.resetClearTimer(); + } - // Style - clip: true - font.pixelSize: Appearance.font.pixelSize.small + // Idk but it work lol + property bool isShaking: false + function startShake() { + shakeAnim.running = false; // reset if running + x = 0; // reset position + shakeAnim.running = true; + } - // Password - enabled: !root.context.unlockInProgress - echoMode: TextInput.Password - inputMethodHints: Qt.ImhSensitiveData + SequentialAnimation { + id: shakeAnim + running: false + NumberAnimation { target: passwordBox; property: "x"; to: -40; duration: 50 } + NumberAnimation { target: passwordBox; property: "x"; to: 40; duration: 50 } + NumberAnimation { target: passwordBox; property: "x"; to: -20; duration: 40 } + NumberAnimation { target: passwordBox; property: "x"; to: 20; duration: 40 } + NumberAnimation { target: passwordBox; property: "x"; to: 0; duration: 30 } + } - // Synchronizing (across monitors) and unlocking - onTextChanged: root.context.currentText = this.text - onAccepted: root.context.tryUnlock() - Connections { - target: root.context - function onCurrentTextChanged() { - passwordBox.text = root.context.currentText; - } - } - - Keys.onPressed: event => { - root.context.resetClearTimer(); + Connections { + target: GlobalStates + function onScreenUnlockFailedChanged() { + if (GlobalStates.screenUnlockFailed) { + passwordBox.startShake(); } } + } +} ToolbarButton { id: confirmButton 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 02/59] =?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 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 03/59] =?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 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 04/59] 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 05/59] 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 06/59] 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 07/59] 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 08/59] 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 09/59] 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 10/59] 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 11/59] 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 12/59] 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 13/59] 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 14/59] 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 15/59] 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 16/59] 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 17/59] 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 18/59] 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 19/59] 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 20/59] 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 21/59] 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 22/59] 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 23/59] 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 24/59] 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 25/59] 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 26/59] 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 27/59] 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 28/59] 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 29/59] 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 30/59] 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 31/59] 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 32/59] 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 33/59] 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 34/59] 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 35/59] 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 36/59] 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 37/59] 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 38/59] 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 39/59] 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 From 06514ed7b703ad554bc891a57cd2a49e035ffa95 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 09:58:52 +0100 Subject: [PATCH 40/59] lock: simplify shake anim impl --- .../ii/modules/lock/LockSurface.qml | 77 +++++++++---------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml index 2594513a1..f31595825 100644 --- a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml +++ b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml @@ -99,52 +99,47 @@ MouseArea { opacity: root.toolbarOpacity ToolbarTextField { - id: passwordBox - placeholderText: GlobalStates.screenUnlockFailed ? Translation.tr("Incorrect password") : Translation.tr("Enter password") - clip: true - font.pixelSize: Appearance.font.pixelSize.small - enabled: !root.context.unlockInProgress - echoMode: TextInput.Password - inputMethodHints: Qt.ImhSensitiveData - onTextChanged: root.context.currentText = this.text - onAccepted: root.context.tryUnlock() - Connections { - target: root.context - function onCurrentTextChanged() { - passwordBox.text = root.context.currentText; - } - } - Keys.onPressed: event => { - root.context.resetClearTimer(); - } + id: passwordBox + placeholderText: GlobalStates.screenUnlockFailed ? Translation.tr("Incorrect password") : Translation.tr("Enter password") - // Idk but it work lol - property bool isShaking: false - function startShake() { - shakeAnim.running = false; // reset if running - x = 0; // reset position - shakeAnim.running = true; - } + // Style + clip: true + font.pixelSize: Appearance.font.pixelSize.small - SequentialAnimation { - id: shakeAnim - running: false - NumberAnimation { target: passwordBox; property: "x"; to: -40; duration: 50 } - NumberAnimation { target: passwordBox; property: "x"; to: 40; duration: 50 } - NumberAnimation { target: passwordBox; property: "x"; to: -20; duration: 40 } - NumberAnimation { target: passwordBox; property: "x"; to: 20; duration: 40 } - NumberAnimation { target: passwordBox; property: "x"; to: 0; duration: 30 } - } + // Password + enabled: !root.context.unlockInProgress + echoMode: TextInput.Password + inputMethodHints: Qt.ImhSensitiveData - Connections { - target: GlobalStates - function onScreenUnlockFailedChanged() { - if (GlobalStates.screenUnlockFailed) { - passwordBox.startShake(); + // Synchronizing (across monitors) and unlocking + onTextChanged: root.context.currentText = this.text + onAccepted: root.context.tryUnlock() + Connections { + target: root.context + function onCurrentTextChanged() { + passwordBox.text = root.context.currentText; + } + } + + Keys.onPressed: event => { + root.context.resetClearTimer(); + } + + SequentialAnimation { + id: wrongPasswordShakeAnim + NumberAnimation { target: passwordBox; property: "x"; to: -30; duration: 50 } + NumberAnimation { target: passwordBox; property: "x"; to: 30; duration: 50 } + NumberAnimation { target: passwordBox; property: "x"; to: -15; duration: 40 } + NumberAnimation { target: passwordBox; property: "x"; to: 15; duration: 40 } + NumberAnimation { target: passwordBox; property: "x"; to: 0; duration: 30 } + } + Connections { + target: GlobalStates + function onScreenUnlockFailedChanged() { + if (GlobalStates.screenUnlockFailed) wrongPasswordShakeAnim.restart(); + } } } - } -} ToolbarButton { id: confirmButton From 287172cd5d9e8f17b87dd5623948616b0856992f Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:07:20 +0100 Subject: [PATCH 41/59] update shapes submodule --- .../quickshell/ii/modules/common/widgets/MaterialShape.qml | 1 + dots/.config/quickshell/ii/modules/common/widgets/shapes | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/MaterialShape.qml b/dots/.config/quickshell/ii/modules/common/widgets/MaterialShape.qml index 30d953478..225fc4139 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/MaterialShape.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/MaterialShape.qml @@ -44,6 +44,7 @@ ShapeCanvas { property double implicitSize implicitHeight: implicitSize implicitWidth: implicitSize + polygonIsNormalized: true roundedPolygon: { switch (root.shape) { case MaterialShape.Shape.Circle: return MaterialShapes.getCircle(); diff --git a/dots/.config/quickshell/ii/modules/common/widgets/shapes b/dots/.config/quickshell/ii/modules/common/widgets/shapes index 8369a081b..8aa62a41b 160000 --- a/dots/.config/quickshell/ii/modules/common/widgets/shapes +++ b/dots/.config/quickshell/ii/modules/common/widgets/shapes @@ -1 +1 @@ -Subproject commit 8369a081ba4694bb3433c6e25fe7329522a2187e +Subproject commit 8aa62a41bd4cdc4899bdfdc0d9cf103ac34c51f6 From b484e3311c6998de98196f96f8f73af4035693ba Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:07:33 +0100 Subject: [PATCH 42/59] use new QtCore import instead of Qt.labs.platform --- dots/.config/quickshell/ii/modules/common/Directories.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/common/Directories.qml b/dots/.config/quickshell/ii/modules/common/Directories.qml index 411ed6c7f..59f3dab53 100644 --- a/dots/.config/quickshell/ii/modules/common/Directories.qml +++ b/dots/.config/quickshell/ii/modules/common/Directories.qml @@ -2,7 +2,7 @@ pragma Singleton pragma ComponentBehavior: Bound import qs.modules.common.functions -import Qt.labs.platform +import QtCore import QtQuick import Quickshell From dfbbe3fccae849e471cf9e1f3ed6c7ef3d9d4acf Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:07:57 +0100 Subject: [PATCH 43/59] lock: make window hiding anim work with floating windows --- .../quickshell/ii/modules/lock/Lock.qml | 180 ++++++++++-------- 1 file changed, 99 insertions(+), 81 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/lock/Lock.qml b/dots/.config/quickshell/ii/modules/lock/Lock.qml index 458f7c63c..1a273cb0b 100644 --- a/dots/.config/quickshell/ii/modules/lock/Lock.qml +++ b/dots/.config/quickshell/ii/modules/lock/Lock.qml @@ -1,4 +1,6 @@ +pragma ComponentBehavior: Bound import qs +import qs.services import qs.modules.common import qs.modules.common.functions import qs.modules.lock @@ -9,9 +11,9 @@ import Quickshell.Wayland import Quickshell.Hyprland Scope { - id: root + id: root - function unlockKeyring() { + function unlockKeyring() { Quickshell.execDetached({ environment: ({ UNLOCK_PASSWORD: root.currentText @@ -20,120 +22,136 @@ Scope { }) } - // This stores all the information shared between the lock surfaces on each screen. - // https://github.com/quickshell-mirror/quickshell-examples/tree/master/lockscreen - LockContext { - id: lockContext + property var windowData: [] + function saveWindowPositionAndTile() { + root.windowData = HyprlandData.windowList.filter(w => w.floating) + root.windowData.forEach(w => { + Hyprland.dispatch(`settiled address:${w.address}`) + }) + } + function restoreWindowPositionAndTile() { + root.windowData.forEach(w => { + Hyprland.dispatch(`setfloating address:${w.address}`) + Hyprland.dispatch(`movewindowpixel exact ${w.at[0]} ${w.at[1]}, address:${w.address}`) + }) + } - Connections { - target: GlobalStates - function onScreenLockedChanged() { - if (GlobalStates.screenLocked) { - lockContext.reset(); - lockContext.tryFingerUnlock(); - } - } - } + // This stores all the information shared between the lock surfaces on each screen. + // https://github.com/quickshell-mirror/quickshell-examples/tree/master/lockscreen + LockContext { + id: lockContext - onUnlocked: (targetAction) => { - // Perform the target action if it's not just unlocking - if (targetAction == LockContext.ActionEnum.Poweroff) { - Session.poweroff(); - return; - } else if (targetAction == LockContext.ActionEnum.Reboot) { - Session.reboot(); - return; - } + Connections { + target: GlobalStates + function onScreenLockedChanged() { + if (GlobalStates.screenLocked) { + lockContext.reset(); + lockContext.tryFingerUnlock(); + } + } + } - // Unlock the keyring if configured to do so - if (Config.options.lock.security.unlockKeyring) root.unlockKeyring(); + onUnlocked: (targetAction) => { + // Perform the target action if it's not just unlocking + if (targetAction == LockContext.ActionEnum.Poweroff) { + Session.poweroff(); + return; + } else if (targetAction == LockContext.ActionEnum.Reboot) { + Session.reboot(); + return; + } - // Unlock the screen before exiting, or the compositor will display a - // fallback lock you can't interact with. - GlobalStates.screenLocked = false; - - // Refocus last focused window on unlock (hack) - Quickshell.execDetached(["bash", "-c", `sleep 0.2; hyprctl --batch "dispatch togglespecialworkspace; dispatch togglespecialworkspace"`]) + // Unlock the keyring if configured to do so + if (Config.options.lock.security.unlockKeyring) root.unlockKeyring(); + + // Unlock the screen before exiting, or the compositor will display a + // fallback lock you can't interact with. + GlobalStates.screenLocked = false; + + // Refocus last focused window on unlock (hack) + Quickshell.execDetached(["bash", "-c", `sleep 0.2; hyprctl --batch "dispatch togglespecialworkspace; dispatch togglespecialworkspace"`]) // Reset lockContext.reset(); - } - } + } + } - WlSessionLock { - id: lock - locked: GlobalStates.screenLocked + WlSessionLock { + id: lock + locked: GlobalStates.screenLocked - WlSessionLockSurface { - color: "transparent" - Loader { - active: GlobalStates.screenLocked - anchors.fill: parent - opacity: active ? 1 : 0 - Behavior on opacity { - animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) - } - sourceComponent: LockSurface { - context: lockContext - } - } - } - } + WlSessionLockSurface { + color: "transparent" + Loader { + active: GlobalStates.screenLocked + anchors.fill: parent + opacity: active ? 1 : 0 + Behavior on opacity { + animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) + } + sourceComponent: LockSurface { + context: lockContext + } + } + } + } - // Blur layer hack - Variants { + // Blur layer hack + Variants { model: Quickshell.screens - delegate: Scope { - required property ShellScreen modelData - property bool shouldPush: GlobalStates.screenLocked - property string targetMonitorName: modelData.name - property int verticalMovementDistance: modelData.height - property int horizontalSqueeze: modelData.width * 0.2 - onShouldPushChanged: { - if (shouldPush) { - Quickshell.execDetached(["bash", "-c", `hyprctl keyword monitor ${targetMonitorName}, addreserved, ${verticalMovementDistance}, ${-verticalMovementDistance}, ${horizontalSqueeze}, ${horizontalSqueeze}`]) - } else { - Quickshell.execDetached(["bash", "-c", `hyprctl keyword monitor ${targetMonitorName}, addreserved, 0, 0, 0, 0`]) - } - } - } - } + delegate: Scope { + required property ShellScreen modelData + property bool shouldPush: GlobalStates.screenLocked + property string targetMonitorName: modelData.name + property int verticalMovementDistance: modelData.height + property int horizontalSqueeze: modelData.width * 0.2 + onShouldPushChanged: { + if (shouldPush) { + root.saveWindowPositionAndTile(); + Quickshell.execDetached(["bash", "-c", `hyprctl keyword monitor ${targetMonitorName}, addreserved, ${verticalMovementDistance}, ${-verticalMovementDistance}, ${horizontalSqueeze}, ${horizontalSqueeze}`]) + } else { + Quickshell.execDetached(["bash", "-c", `hyprctl keyword monitor ${targetMonitorName}, addreserved, 0, 0, 0, 0`]) + root.restoreWindowPositionAndTile(); + } + } + } + } - IpcHandler { + IpcHandler { target: "lock" function activate(): void { GlobalStates.screenLocked = true; } - function focus(): void { - lockContext.shouldReFocus(); - } + function focus(): void { + lockContext.shouldReFocus(); + } } - GlobalShortcut { + GlobalShortcut { name: "lock" description: "Locks the screen" onPressed: { - if (Config.options.lock.useHyprlock) { - Quickshell.execDetached(["bash", "-c", "pidof hyprlock || hyprlock"]); - return; - } + if (Config.options.lock.useHyprlock) { + Quickshell.execDetached(["bash", "-c", "pidof hyprlock || hyprlock"]); + return; + } GlobalStates.screenLocked = true; } } - GlobalShortcut { + GlobalShortcut { name: "lockFocus" description: "Re-focuses the lock screen. This is because Hyprland after waking up for whatever reason" - + "decides to keyboard-unfocus the lock screen" + + "decides to keyboard-unfocus the lock screen" onPressed: { lockContext.shouldReFocus(); } } - Connections { + Connections { target: Config function onReadyChanged() { if (Config.options.lock.launchOnStartup && Config.ready && Persistent.ready && Persistent.isNewHyprlandInstance) { From 40b1e8297f35f4120359f849038d6849fda65628 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:24:41 +0100 Subject: [PATCH 44/59] lock: fix weird hiding anim with floating windows --- dots/.config/quickshell/ii/modules/lock/Lock.qml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/lock/Lock.qml b/dots/.config/quickshell/ii/modules/lock/Lock.qml index 1a273cb0b..ead478bdc 100644 --- a/dots/.config/quickshell/ii/modules/lock/Lock.qml +++ b/dots/.config/quickshell/ii/modules/lock/Lock.qml @@ -24,16 +24,21 @@ Scope { property var windowData: [] function saveWindowPositionAndTile() { - root.windowData = HyprlandData.windowList.filter(w => w.floating) + Hyprland.dispatch(`keyword dwindle:pseudotile true`) + root.windowData = HyprlandData.windowList.filter(w => (w.floating && w.workspace.id === HyprlandData.activeWorkspace.id)) root.windowData.forEach(w => { + Hyprland.dispatch(`pseudo address:${w.address}`) Hyprland.dispatch(`settiled address:${w.address}`) + Hyprland.dispatch(`movetoworkspacesilent ${w.workspace.id},address:${w.address}`) }) } function restoreWindowPositionAndTile() { root.windowData.forEach(w => { Hyprland.dispatch(`setfloating address:${w.address}`) Hyprland.dispatch(`movewindowpixel exact ${w.at[0]} ${w.at[1]}, address:${w.address}`) + Hyprland.dispatch(`pseudo address:${w.address}`) }) + Hyprland.dispatch(`keyword dwindle:pseudotile false`) } // This stores all the information shared between the lock surfaces on each screen. From 5c71c53787c2270ff4c184d368a6492339212958 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:42:54 +0100 Subject: [PATCH 45/59] make region selector use materialshape instead of materialcookie --- .../modules/regionSelector/OptionsToolbar.qml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/regionSelector/OptionsToolbar.qml b/dots/.config/quickshell/ii/modules/regionSelector/OptionsToolbar.qml index e737e9cac..d4e54ddda 100644 --- a/dots/.config/quickshell/ii/modules/regionSelector/OptionsToolbar.qml +++ b/dots/.config/quickshell/ii/modules/regionSelector/OptionsToolbar.qml @@ -23,13 +23,25 @@ Toolbar { // Signals signal dismiss() - MaterialCookie { + MaterialShape { Layout.fillHeight: true Layout.leftMargin: 2 Layout.rightMargin: 2 implicitSize: 36 // Intentionally smaller because this one is brighter than others - sides: 10 - amplitude: implicitSize / 44 + shape: switch (root.action) { + case RegionSelection.SnipAction.Copy: + case RegionSelection.SnipAction.Edit: + return MaterialShape.Shape.Cookie4Sided; + case RegionSelection.SnipAction.Search: + return MaterialShape.Shape.Pentagon; + case RegionSelection.SnipAction.CharRecognition: + return MaterialShape.Shape.Sunny; + case RegionSelection.SnipAction.Record: + case RegionSelection.SnipAction.RecordWithSound: + return MaterialShape.Shape.Gem; + default: + return MaterialShape.Shape.Cookie12Sided; + } color: Appearance.colors.colPrimary MaterialSymbol { anchors.centerIn: parent From a200951b75c3607d9a532be9501c1912f55c4737 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 12:23:45 +0100 Subject: [PATCH 46/59] format --- .../androidStyle/AndroidPowerProfileToggle.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml index 916e9be51..064180ae5 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml @@ -17,10 +17,10 @@ AndroidQuickToggleButton { case PowerProfile.Performance: return "local_fire_department" } statusText: switch(PowerProfiles.profile) { - case PowerProfile.PowerSaver: return "Power Saver" - case PowerProfile.Balanced: return "Balanced" - case PowerProfile.Performance: return "Performance" - } + case PowerProfile.PowerSaver: return "Power Saver" + case PowerProfile.Balanced: return "Balanced" + case PowerProfile.Performance: return "Performance" + } onClicked: (event) => { if (PowerProfiles.hasPerformanceProfile) { From 403344e120a170776813b428ee9628cfeaf3f90c Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 12:24:10 +0100 Subject: [PATCH 47/59] make materialcookie use rounded polygons --- .../background/cookieClock/CookieClock.qml | 176 +++++++++--------- .../cookieClock/minuteMarks/MinuteMarks.qml | 10 +- .../modules/common/widgets/MaterialCookie.qml | 75 +++----- 3 files changed, 121 insertions(+), 140 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/background/cookieClock/CookieClock.qml b/dots/.config/quickshell/ii/modules/background/cookieClock/CookieClock.qml index d08056909..8ad1d921b 100644 --- a/dots/.config/quickshell/ii/modules/background/cookieClock/CookieClock.qml +++ b/dots/.config/quickshell/ii/modules/background/cookieClock/CookieClock.qml @@ -86,118 +86,124 @@ Item { DropShadow { source: cookie anchors.fill: source - horizontalOffset: 0 - verticalOffset: 1 radius: 8 samples: radius * 2 + 1 color: root.colShadow transparentBorder: true + + RotationAnimation on rotation { + running: Config.options.background.clock.cookie.constantlyRotate + duration: 30000 + easing.type: Easing.Linear + loops: Animation.Infinite + from: 360 + to: 0 + } } MaterialCookie { id: cookie z: 0 + visible: false // The DropShadow already draws it implicitSize: root.implicitSize - amplitude: implicitSize / 70 sides: Config.options.background.clock.cookie.sides color: root.colBackground - constantlyRotate: Config.options.background.clock.cookie.constantlyRotate - - // Hour/minutes numbers/dots/lines - MinuteMarks { - anchors.fill: parent + } + + // Hour/minutes numbers/dots/lines + MinuteMarks { + anchors.fill: parent + color: root.colOnBackground + } + + // Stupid extra hour marks in the middle + FadeLoader { + id: hourMarksLoader + anchors.centerIn: parent + shown: Config.options.background.clock.cookie.hourMarks + sourceComponent: HourMarks { + implicitSize: 135 * (1.75 - 0.75 * hourMarksLoader.opacity) color: root.colOnBackground + colOnBackground: ColorUtils.mix(root.colBackgroundInfo, root.colOnBackground, 0.5) + } + } + + // Number column in the middle + FadeLoader { + id: timeColumnLoader + anchors.centerIn: parent + shown: Config.options.background.clock.cookie.timeIndicators + scale: 1.4 - 0.4 * timeColumnLoader.shown + Behavior on scale { + animation: Appearance.animation.elementResize.numberAnimation.createObject(this) } - // Stupid extra hour marks in the middle - FadeLoader { - id: hourMarksLoader - anchors.centerIn: parent - shown: Config.options.background.clock.cookie.hourMarks - sourceComponent: HourMarks { - implicitSize: 135 * (1.75 - 0.75 * hourMarksLoader.opacity) - color: root.colOnBackground - colOnBackground: ColorUtils.mix(root.colBackgroundInfo, root.colOnBackground, 0.5) - } + sourceComponent: TimeColumn { + color: root.colBackgroundInfo } + } - // Number column in the middle - FadeLoader { - id: timeColumnLoader - anchors.centerIn: parent - shown: Config.options.background.clock.cookie.timeIndicators - scale: 1.4 - 0.4 * timeColumnLoader.shown - Behavior on scale { - animation: Appearance.animation.elementResize.numberAnimation.createObject(this) - } - - sourceComponent: TimeColumn { - color: root.colBackgroundInfo - } + // Hour hand + FadeLoader { + anchors.fill: parent + z: 1 + shown: Config.options.background.clock.cookie.hourHandStyle !== "hide" + sourceComponent: HourHand { + clockHour: root.clockHour + clockMinute: root.clockMinute + style: Config.options.background.clock.cookie.hourHandStyle + color: root.colHourHand } + } - // Hour hand - FadeLoader { + // Minute hand + FadeLoader { + anchors.fill: parent + z: 2 + shown: Config.options.background.clock.cookie.minuteHandStyle !== "hide" + sourceComponent: MinuteHand { anchors.fill: parent - z: 1 - shown: Config.options.background.clock.cookie.hourHandStyle !== "hide" - sourceComponent: HourHand { - clockHour: root.clockHour - clockMinute: root.clockMinute - style: Config.options.background.clock.cookie.hourHandStyle - color: root.colHourHand - } + clockMinute: root.clockMinute + style: Config.options.background.clock.cookie.minuteHandStyle + color: root.colMinuteHand } + } - // Minute hand - FadeLoader { - anchors.fill: parent - z: 2 - shown: Config.options.background.clock.cookie.minuteHandStyle !== "hide" - sourceComponent: MinuteHand { - anchors.fill: parent - clockMinute: root.clockMinute - style: Config.options.background.clock.cookie.minuteHandStyle - color: root.colMinuteHand - } + // Second hand + FadeLoader { + id: secondHandLoader + z: (Config.options.background.clock.cookie.secondHandStyle === "line") ? 2 : 3 + shown: Config.options.time.secondPrecision && Config.options.background.clock.cookie.secondHandStyle !== "hide" + anchors.fill: parent + sourceComponent: SecondHand { + id: secondHand + clockSecond: root.clockSecond + style: Config.options.background.clock.cookie.secondHandStyle + color: root.colSecondHand } + } - // Second hand - FadeLoader { - id: secondHandLoader - z: (Config.options.background.clock.cookie.secondHandStyle === "line") ? 2 : 3 - shown: Config.options.time.secondPrecision && Config.options.background.clock.cookie.secondHandStyle !== "hide" - anchors.fill: parent - sourceComponent: SecondHand { - id: secondHand - clockSecond: root.clockSecond - style: Config.options.background.clock.cookie.secondHandStyle - color: root.colSecondHand - } + // Center dot + FadeLoader { + z: 4 + anchors.centerIn: parent + shown: Config.options.background.clock.cookie.minuteHandStyle !== "bold" + sourceComponent: Rectangle { + color: Config.options.background.clock.cookie.minuteHandStyle === "medium" ? root.colBackground : root.colMinuteHand + implicitWidth: 6 + implicitHeight: implicitWidth + radius: width / 2 } + } - // Center dot - FadeLoader { - z: 4 - anchors.centerIn: parent - shown: Config.options.background.clock.cookie.minuteHandStyle !== "bold" - sourceComponent: Rectangle { - color: Config.options.background.clock.cookie.minuteHandStyle === "medium" ? root.colBackground : root.colMinuteHand - implicitWidth: 6 - implicitHeight: implicitWidth - radius: width / 2 - } - } + // Date + FadeLoader { + anchors.fill: parent + shown: Config.options.background.clock.cookie.dateStyle !== "hide" - // Date - FadeLoader { - anchors.fill: parent - shown: Config.options.background.clock.cookie.dateStyle !== "hide" - - sourceComponent: DateIndicator { - color: root.colBackgroundInfo - style: Config.options.background.clock.cookie.dateStyle - } + sourceComponent: DateIndicator { + color: root.colBackgroundInfo + style: Config.options.background.clock.cookie.dateStyle } } } diff --git a/dots/.config/quickshell/ii/modules/background/cookieClock/minuteMarks/MinuteMarks.qml b/dots/.config/quickshell/ii/modules/background/cookieClock/minuteMarks/MinuteMarks.qml index be0389677..07cf0dc5e 100644 --- a/dots/.config/quickshell/ii/modules/background/cookieClock/minuteMarks/MinuteMarks.qml +++ b/dots/.config/quickshell/ii/modules/background/cookieClock/minuteMarks/MinuteMarks.qml @@ -14,7 +14,10 @@ Item { // 12 Dots FadeLoader { id: dotsLoader - anchors.fill: parent + anchors { + fill: parent + margins: 10 + } shown: root.style === "dots" sourceComponent: Dots { color: root.color @@ -37,7 +40,10 @@ Item { // Lines FadeLoader { id: linesLoader - anchors.fill: parent + anchors { + fill: parent + margins: 10 + } shown: root.style === "full" sourceComponent: Lines { color: root.color diff --git a/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml b/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml index 79048ca63..88bc0b50e 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml @@ -2,69 +2,38 @@ import QtQuick import QtQuick.Shapes import Quickshell import qs.modules.common +import qs.modules.common.widgets.shapes +import "shapes/geometry/offset.js" as Offset +import "shapes/shapes/corner-rounding.js" as CornerRounding +import "shapes/shapes/rounded-polygon.js" as RoundedPolygon +import "shapes/material-shapes.js" as MaterialShapes Item { id: root - - property real sides: 12 + property int sides: 12 property int implicitSize: 100 - property real amplitude: implicitSize / 50 - property int renderPoints: 360 - property color color: "#605790" - property alias strokeWidth: shapePath.strokeWidth - property bool constantlyRotate: false + property alias color: shapeCanvas.color implicitWidth: implicitSize implicitHeight: implicitSize - property real shapeRotation: 0 + property var cornerRounding: new CornerRounding.CornerRounding(1.1 / Math.max(sides, 1)) - Loader { - active: constantlyRotate - sourceComponent: FrameAnimation { - running: true - onTriggered: { - shapeRotation += 0.05 - } - } - } - - Behavior on sides { - animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) - } - - Shape { - id: shape + ShapeCanvas { + id: shapeCanvas anchors.fill: parent - preferredRendererType: Shape.CurveRenderer - - ShapePath { - id: shapePath - strokeWidth: 0 - fillColor: root.color - pathHints: ShapePath.PathSolid & ShapePath.PathNonIntersecting - - PathPolyline { - property var pointsList: { - var points = [] - var cx = shape.width / 2 // center x - var cy = shape.height / 2 // center y - var steps = root.renderPoints - var radius = root.implicitSize / 2 - root.amplitude - for (var i = 0; i <= steps; i++) { - var angle = (i / steps) * 2 * Math.PI - var rotatedAngle = angle * root.sides + Math.PI/2 + (root.shapeRotation * root.constantlyRotate) - var wave = Math.sin(rotatedAngle) * root.amplitude - var x = Math.cos(angle) * (radius + wave) + cx - var y = Math.sin(angle) * (radius + wave) + cy - points.push(Qt.point(x, y)) - } - return points - } - - path: pointsList - } - + roundedPolygon: switch(sides) { + case 0: return MaterialShapes.getCircle(); + case 1: return MaterialShapes.getCircle(); + case 4: return MaterialShapes.getCookie4Sided(); + case 6: return MaterialShapes.getCookie6Sided(); + case 7: return MaterialShapes.getCookie7Sided(); + case 9: return MaterialShapes.getCookie9Sided(); + case 12: return MaterialShapes.getCookie12Sided(); + default: return RoundedPolygon.RoundedPolygon.star(sides, 1, 0.8, root.cornerRounding) + .transformed((x, y) => MaterialShapes.rotate30.map(new Offset.Offset(x, y))) + .normalized(); } } } + From 1b996e37a741c5056234fe48f30ea06fca3726b7 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 12:38:30 +0100 Subject: [PATCH 48/59] adjust clock appearance --- .../ii/modules/background/cookieClock/CookieClock.qml | 4 ++-- .../quickshell/ii/modules/background/cookieClock/HourHand.qml | 2 +- .../ii/modules/background/cookieClock/MinuteHand.qml | 2 +- .../ii/modules/background/cookieClock/SecondHand.qml | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/background/cookieClock/CookieClock.qml b/dots/.config/quickshell/ii/modules/background/cookieClock/CookieClock.qml index 8ad1d921b..12a4d9b96 100644 --- a/dots/.config/quickshell/ii/modules/background/cookieClock/CookieClock.qml +++ b/dots/.config/quickshell/ii/modules/background/cookieClock/CookieClock.qml @@ -50,9 +50,9 @@ Item { print("[Cookie clock] Setting clock preset for category: " + category) // "abstract", "anime", "city", "minimalist", "landscape", "plants", "person", "space" if (category == "abstract") { - applyStyle(10, "dots", "fill", "medium", "dot", "bubble") + applyStyle(9, "none", "fill", "medium", "dot", "bubble") } else if (category == "anime") { - applyStyle(12, "dots", "fill", "bold", "dot", "bubble") + applyStyle(7, "none", "fill", "bold", "dot", "bubble") } else if (category == "city" || category == "space") { applyStyle(23, "full", "hollow", "thin", "classic", "bubble") } else if (category == "minimalist") { diff --git a/dots/.config/quickshell/ii/modules/background/cookieClock/HourHand.qml b/dots/.config/quickshell/ii/modules/background/cookieClock/HourHand.qml index c38960256..c80d8839d 100644 --- a/dots/.config/quickshell/ii/modules/background/cookieClock/HourHand.qml +++ b/dots/.config/quickshell/ii/modules/background/cookieClock/HourHand.qml @@ -9,7 +9,7 @@ Item { required property int clockHour required property int clockMinute property real handLength: 72 - property real handWidth: 18 + property real handWidth: 20 property string style: "fill" property color color: Appearance.colors.colPrimary diff --git a/dots/.config/quickshell/ii/modules/background/cookieClock/MinuteHand.qml b/dots/.config/quickshell/ii/modules/background/cookieClock/MinuteHand.qml index 0b8a78d16..ca3884d19 100644 --- a/dots/.config/quickshell/ii/modules/background/cookieClock/MinuteHand.qml +++ b/dots/.config/quickshell/ii/modules/background/cookieClock/MinuteHand.qml @@ -10,7 +10,7 @@ Item { required property int clockMinute property string style: "medium" property real handLength: 95 - property real handWidth: style === "bold" ? 18 : style === "medium" ? 12 : 5 + property real handWidth: style === "bold" ? 20 : style === "medium" ? 12 : 5 property color color: Appearance.colors.colSecondary rotation: -90 + (360 / 60) * root.clockMinute diff --git a/dots/.config/quickshell/ii/modules/background/cookieClock/SecondHand.qml b/dots/.config/quickshell/ii/modules/background/cookieClock/SecondHand.qml index a4643a259..2e16138e7 100644 --- a/dots/.config/quickshell/ii/modules/background/cookieClock/SecondHand.qml +++ b/dots/.config/quickshell/ii/modules/background/cookieClock/SecondHand.qml @@ -10,7 +10,7 @@ Item { required property int clockSecond property real handWidth: 2 - property real handLength: 100 + property real handLength: 95 property real dotSize: 20 property string style: "hide" property color color: Appearance.colors.colSecondary @@ -29,7 +29,7 @@ Item { anchors { left: parent.left verticalCenter: parent.verticalCenter - leftMargin: 10 + leftMargin: 10 + (root.style === "dot" ? root.dotSize : 0) } implicitWidth: root.style === "dot" ? root.dotSize : root.handLength implicitHeight: root.style === "dot" ? root.dotSize : root.handWidth From 0bd22f89a7d4be107397aaef1cfb1a01a95ffcf1 Mon Sep 17 00:00:00 2001 From: dancincomrade Date: Thu, 30 Oct 2025 22:04:15 +0800 Subject: [PATCH 49/59] fix: replace pulseaudio with pipewire-pulseaudio --- sdata/dist-arch/illogical-impulse-audio/PKGBUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/sdata/dist-arch/illogical-impulse-audio/PKGBUILD b/sdata/dist-arch/illogical-impulse-audio/PKGBUILD index 6cab7de53..6b1a5efc7 100644 --- a/sdata/dist-arch/illogical-impulse-audio/PKGBUILD +++ b/sdata/dist-arch/illogical-impulse-audio/PKGBUILD @@ -8,6 +8,7 @@ depends=( cava pavucontrol-qt wireplumber + pipewire-pulse libdbusmenu-gtk3 playerctl ) From fceda9bd356359b05210d09c49c716aae8bb8578 Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 22:09:09 +0800 Subject: [PATCH 50/59] Rename var --- sdata/subcmd-install/3.files-exp.sh | 8 ++++---- sdata/subcmd-install/3.files.sh | 4 ++-- sdata/subcmd-install/3.files.yaml | 2 +- sdata/subcmd-install/options.sh | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sdata/subcmd-install/3.files-exp.sh b/sdata/subcmd-install/3.files-exp.sh index f35229535..778fd3ba7 100644 --- a/sdata/subcmd-install/3.files-exp.sh +++ b/sdata/subcmd-install/3.files-exp.sh @@ -83,10 +83,10 @@ for pattern in "${patterns[@]}"; do 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" + # If FONTSET_DIR_NAME is set and this is the fontconfig pattern, use the fontset instead + if [[ "$from" == "dots/.config/fontconfig" ]] && [[ -n "${FONTSET_DIR_NAME:-}" ]]; then + from="dots-extra/fontsets/${FONTSET_DIR_NAME}" + echo "Using fontset \"${FONTSET_DIR_NAME}\" for fontconfig" fi # Check if pattern should be processed diff --git a/sdata/subcmd-install/3.files.sh b/sdata/subcmd-install/3.files.sh index ead48593f..8e92fed2c 100644 --- a/sdata/subcmd-install/3.files.sh +++ b/sdata/subcmd-install/3.files.sh @@ -103,9 +103,9 @@ esac case $SKIP_FONTCONFIG in true) sleep 0;; *) - case "$II_FONTSET_NAME" in + case "$FONTSET_DIR_NAME" in "") 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/ ;; + *) warning_rsync_delete; v rsync -av --delete dots-extra/fontsets/$FONTSET_DIR_NAME/ "$XDG_CONFIG_HOME"/fontconfig/ ;; esac;; esac diff --git a/sdata/subcmd-install/3.files.yaml b/sdata/subcmd-install/3.files.yaml index a9f2985f2..59ed69ebc 100644 --- a/sdata/subcmd-install/3.files.yaml +++ b/sdata/subcmd-install/3.files.yaml @@ -57,7 +57,7 @@ patterns: - from: "dots/.local/share/konsole" to: "$XDG_DATA_HOME/konsole" mode: "soft" - # Fontconfig (default - fontsets handled separately if II_FONTSET_NAME is set) + # Fontconfig (default - fontsets handled separately if FONTSET_DIR_NAME is set) - from: "dots/.config/fontconfig" to: "$XDG_CONFIG_HOME/fontconfig" mode: "sync" diff --git a/sdata/subcmd-install/options.sh b/sdata/subcmd-install/options.sh index dba8a4430..ec466dfe9 100644 --- a/sdata/subcmd-install/options.sh +++ b/sdata/subcmd-install/options.sh @@ -81,7 +81,7 @@ while true ; do ## Ones with parameter --fontset) if [[ -d "${REPO_ROOT}/dots-extra/fontsets/$2" ]]; - then echo "Using fontset \"$2\".";II_FONTSET_NAME="$2";shift 2 + then echo "Using fontset \"$2\".";FONTSET_DIR_NAME="$2";shift 2 else echo "Wrong argument for $1.";exit 1 fi;; From e622928d9d8b6b5713257bfd4ab2dd199b252012 Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 22:18:42 +0800 Subject: [PATCH 51/59] Update dist-nix --- sdata/dist-nix/README.md | 75 +----------------------- sdata/dist-nix/home-manager/flake.nix | 41 +++++++++++++ sdata/dist-nix/home-manager/home.nix | 57 ++++++++++++++++++ sdata/dist-nix/home-manager/username.nix | 1 + sdata/dist-nix/install-deps.sh | 4 +- 5 files changed, 102 insertions(+), 76 deletions(-) create mode 100644 sdata/dist-nix/home-manager/flake.nix create mode 100644 sdata/dist-nix/home-manager/home.nix create mode 100644 sdata/dist-nix/home-manager/username.nix diff --git a/sdata/dist-nix/README.md b/sdata/dist-nix/README.md index 458556d72..20f80025d 100644 --- a/sdata/dist-nix/README.md +++ b/sdata/dist-nix/README.md @@ -6,24 +6,10 @@ **NOTE: The sdata/dist-nix is not for NixOS but every distro, using Nix and home-manager.** ## plan -TODO: -Write a proper `flake.nix` and optionally `home.nix` and other files under `./sdata/dist-nix/iiqs-hm/` to install all dependencies that `./sdata/dist-arch/install-deps.sh` does. (**excluding** the screenlock) - -TODO: -In this script, implement the process below: -1. Warning user about "this script is only experimental and must only use it at your own risks.", and prompt `y/N` (default N) before proceeding. -2. If nix not installed: - 1. install nix via [NixOS/experimental-nix-installer](https://github.com/NixOS/experimental-nix-installer) - 2. Enable nix for shell - - Update: Skip this step cuz the nix-installer will handle it automatically e.g. in `/etc/zsh/zshrc`. - 3. Ensure the experimental feature, Nix Flake, is enabled. -3. cd to `iiqs-hm` and use something like `home-manager switch --flake .#iiqs` to install the dependencies. -4. Install screen lock using system package manager of the current distro. - Note that this script must be idempotent. TODO: -Write guide for people already use nix, so they can manually grab things from this repo to their own Nix/home-manager configurations to install the dependencies. +- [ ] Write a proper `flake.nix` and `home.nix` and other files under `dist-nix/home-manager/` to install all dependencies that `dist-arch/` does. (**excluding** the screenlock) ## Attentions ### PAM @@ -37,61 +23,4 @@ The problem could be solved by using the system-provided libpam instead. See also https://github.com/caelestia-dots/shell/issues/668 ### NixGL -On non-NixOS distros, packages installed via home-manager have problem accessing GPU, especially Hyprland because it requires GPU acceleration to launch. `nixGL` should be used to address the problem. Example code in `home.nix`: -``` -{ config, lib, pkgs, nixgl, ... }: -{ - nixGL.packages = nixgl.packages; - nixGL.defaultWrapper = "mesa"; - - # other lines not showed here ... - - home = { - packages = with pkgs; [ - cowsay # normal packages that does not need nixGL - lolcat - # other lines not showed here ... - ] - ++ [ - (config.lib.nixGL.wrap pkgs.firefox-bin) - (config.lib.nixGL.wrap pkgs.hyprland) - # other lines not showed here ... - ]; - # other lines not showed here ... - }; -} -``` - -And in `flake.nix`: -```nix -{ - inputs = { - nixpkgs.url = "nixpkgs/nixos-25.05"; - home-manager = { - url = "github:nix-community/home-manager/release-25.05"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - hyprland = { - url = "github:hyprwm/Hyprland"; - }; - nixgl.url = "github:nix-community/nixGL"; - }; - outputs = { nixpkgs, home-manager, nixgl, ... }: - let - lib = nixpkgs.lib; - system = "x86_64-linux"; - pkgs = import nixpkgs { - inherit system; - overlays = [ nixgl.overlay ]; - }; - in { - homeConfigurations = { - mydot = home-manager.lib.homeManagerConfiguration { - inherit pkgs; - extraSpecialArgs = { inherit nixgl; }; - modules = [ ./home.nix ]; - }; - }; - }; -} -``` +On non-NixOS distros, packages installed via home-manager have problem accessing GPU, especially Hyprland because it requires GPU acceleration to launch. `nixGL` should be used to address the problem. diff --git a/sdata/dist-nix/home-manager/flake.nix b/sdata/dist-nix/home-manager/flake.nix new file mode 100644 index 000000000..3422f5c4b --- /dev/null +++ b/sdata/dist-nix/home-manager/flake.nix @@ -0,0 +1,41 @@ +# flake.nix +{ + description = "illogical-impulse"; + + inputs = { + nixpkgs.url = "nixpkgs/nixos-25.05"; + + home-manager = { + url = "github:nix-community/home-manager/release-25.05"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + hyprland = { + url = "github:hyprwm/Hyprland"; + }; + nixgl.url = "github:nix-community/nixGL"; + }; + + outputs = { nixpkgs, home-manager, nixgl, ... }: + let + home_attrs = rec { + username = import ./username.nix; + homeDirectory = "/home/${username}"; + stateVersion = "25.05"; + }; + system = "x86_64-linux"; + lib = nixpkgs.lib; + pkgs = import nixpkgs { + inherit system; + }; + in { + homeConfigurations = { + illogical_impulse = home-manager.lib.homeManagerConfiguration { + inherit pkgs; + extraSpecialArgs = { inherit nixgl home_attrs; }; + modules = [ + ./home.nix + ]; + }; + }; + }; +} diff --git a/sdata/dist-nix/home-manager/home.nix b/sdata/dist-nix/home-manager/home.nix new file mode 100644 index 000000000..6f17bd4f0 --- /dev/null +++ b/sdata/dist-nix/home-manager/home.nix @@ -0,0 +1,57 @@ +{ config, lib, pkgs, nixgl, home_attrs, ... }: +{ + programs.home-manager.enable = true; + nixGL.packages = nixgl.packages; + nixGL.defaultWrapper = "mesa"; + + xdg.portal = { + enable = true; + extraPortals = with pkgs; [ + xdg-desktop-portal-gnome + xdg-desktop-portal-gtk + xdg-desktop-portal-wlr + ]; + config.hyprland = { + default = [ "hyprland" "gtk" ]; + "org.freedesktop.impl.portal.ScreenCast" = [ + "gnome" + ]; + }; + }; + ## Allow fontconfig to discover fonts in home.packages + fonts.fontconfig.enable = true; + + # home.sessionVariables.NIXOS_OZONE_WL = "1"; + wayland.windowManager.hyprland = { + ## Make sure home-manager not generate ~/.config/hypr/hyprland.conf + systemd.enable = false; plugins = []; settings = {}; extraConfig = ""; + enable = true; + ## Use NixGL + package = config.lib.nixGL.wrap pkgs.hyprland; + }; + + home = { + packages = with pkgs; [ + ##### Sure ##### + ## Basic cli tool + ## inetutils: provides hostname, ifconfig, ping, etc. + ## libnotify: provides notify-send + jq rsync inetutils libnotify + ## Media related + brightnessctl playerctl pavucontrol + ## Clipboard/Emoji + wl-clipboard cliphist + ## Terminal and shell + foot cowsay lolcat + + ##### Fonts/Icons/Cursors/Decoration ##### + fontconfig + + ##### Other basic things ##### + dbus xorg.xlsclients networkmanager + + ##### Not work, to be solved ##### + # swaylock pamtester + ]; + }//home_attrs; +} diff --git a/sdata/dist-nix/home-manager/username.nix b/sdata/dist-nix/home-manager/username.nix new file mode 100644 index 000000000..e16c76dff --- /dev/null +++ b/sdata/dist-nix/home-manager/username.nix @@ -0,0 +1 @@ +"" diff --git a/sdata/dist-nix/install-deps.sh b/sdata/dist-nix/install-deps.sh index 59ffec887..6b11606c2 100644 --- a/sdata/dist-nix/install-deps.sh +++ b/sdata/dist-nix/install-deps.sh @@ -1,8 +1,6 @@ # This script is meant to be sourced. # 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 @@ -128,4 +126,4 @@ if ! command -v home-manager >/dev/null 2>&1;then fi showfun hm_deps -v hm_deps \ No newline at end of file +v hm_deps From a97b7706d8455b01c72eb15f344b73ab9f781164 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:23:58 +0100 Subject: [PATCH 52/59] make cookie clock more round --- .../quickshell/ii/modules/common/widgets/MaterialCookie.qml | 2 +- dots/.config/quickshell/ii/modules/lock/PasswordChars.qml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml b/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml index 88bc0b50e..d5b3663cb 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml @@ -17,7 +17,7 @@ Item { implicitWidth: implicitSize implicitHeight: implicitSize - property var cornerRounding: new CornerRounding.CornerRounding(1.1 / Math.max(sides, 1)) + property var cornerRounding: new CornerRounding.CornerRounding(1.3 / Math.max(sides, 1)) ShapeCanvas { id: shapeCanvas diff --git a/dots/.config/quickshell/ii/modules/lock/PasswordChars.qml b/dots/.config/quickshell/ii/modules/lock/PasswordChars.qml index 79ffc9464..400c2495a 100644 --- a/dots/.config/quickshell/ii/modules/lock/PasswordChars.qml +++ b/dots/.config/quickshell/ii/modules/lock/PasswordChars.qml @@ -15,7 +15,6 @@ StyledFlickable { Behavior on contentX { animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this) } - rightMargin: 14 Row { id: dotsRow anchors { From a122d6e905d2dcb04bc275692d9577f68a053514 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:27:14 +0100 Subject: [PATCH 53/59] uhh more round --- .../quickshell/ii/modules/common/widgets/MaterialCookie.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml b/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml index d5b3663cb..a1f4be235 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/MaterialCookie.qml @@ -17,7 +17,7 @@ Item { implicitWidth: implicitSize implicitHeight: implicitSize - property var cornerRounding: new CornerRounding.CornerRounding(1.3 / Math.max(sides, 1)) + property var cornerRounding: new CornerRounding.CornerRounding((sides < 17 ? 1.5 : 1.1) / Math.max(sides, 1)) ShapeCanvas { id: shapeCanvas From df307d3d4546a9872389e14193c891fe4fda07da Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 22:28:31 +0800 Subject: [PATCH 54/59] Update dist-nix --- sdata/dist-nix/home-manager/flake.lock | 542 +++++++++++++++++++++++ sdata/dist-nix/home-manager/username.nix | 1 - sdata/dist-nix/install-deps.sh | 2 +- 3 files changed, 543 insertions(+), 2 deletions(-) create mode 100644 sdata/dist-nix/home-manager/flake.lock delete mode 100644 sdata/dist-nix/home-manager/username.nix diff --git a/sdata/dist-nix/home-manager/flake.lock b/sdata/dist-nix/home-manager/flake.lock new file mode 100644 index 000000000..3c2f0f3f0 --- /dev/null +++ b/sdata/dist-nix/home-manager/flake.lock @@ -0,0 +1,542 @@ +{ + "nodes": { + "aquamarine": { + "inputs": { + "hyprutils": [ + "hyprland", + "hyprutils" + ], + "hyprwayland-scanner": [ + "hyprland", + "hyprwayland-scanner" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1760101617, + "narHash": "sha256-8jf/3ZCi+B7zYpIyV04+3wm72BD7Z801IlOzsOACR7I=", + "owner": "hyprwm", + "repo": "aquamarine", + "rev": "1826a9923881320306231b1c2090379ebf9fa4f8", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "aquamarine", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1747046372, + "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "hyprland", + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1758463745, + "narHash": "sha256-uhzsV0Q0I9j2y/rfweWeGif5AWe0MGrgZ/3TjpDYdGA=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "3b955f5f0a942f9f60cdc9cacb7844335d0f21c3", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "release-25.05", + "repo": "home-manager", + "type": "github" + } + }, + "hyprcursor": { + "inputs": { + "hyprlang": [ + "hyprland", + "hyprlang" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1753964049, + "narHash": "sha256-lIqabfBY7z/OANxHoPeIrDJrFyYy9jAM4GQLzZ2feCM=", + "owner": "hyprwm", + "repo": "hyprcursor", + "rev": "44e91d467bdad8dcf8bbd2ac7cf49972540980a5", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprcursor", + "type": "github" + } + }, + "hyprgraphics": { + "inputs": { + "hyprutils": [ + "hyprland", + "hyprutils" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1760445448, + "narHash": "sha256-fXGjL6dw31FPFRrmIemzGiNSlfvEJTJNsmadZi+qNhI=", + "owner": "hyprwm", + "repo": "hyprgraphics", + "rev": "50fb9f069219f338a11cf0bcccb9e58357d67757", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprgraphics", + "type": "github" + } + }, + "hyprland": { + "inputs": { + "aquamarine": "aquamarine", + "hyprcursor": "hyprcursor", + "hyprgraphics": "hyprgraphics", + "hyprland-protocols": "hyprland-protocols", + "hyprland-qtutils": "hyprland-qtutils", + "hyprlang": "hyprlang", + "hyprutils": "hyprutils", + "hyprwayland-scanner": "hyprwayland-scanner", + "nixpkgs": "nixpkgs", + "pre-commit-hooks": "pre-commit-hooks", + "systems": "systems", + "xdph": "xdph" + }, + "locked": { + "lastModified": 1761780088, + "narHash": "sha256-ylKrWQeIAGyysfHbgZpcWUs9UsbiOBIVXTPqaiV3lf0=", + "owner": "hyprwm", + "repo": "Hyprland", + "rev": "6ade4d58cab67e18aa758ef664e36421cab4d8b2", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "Hyprland", + "type": "github" + } + }, + "hyprland-protocols": { + "inputs": { + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1759610243, + "narHash": "sha256-+KEVnKBe8wz+a6dTLq8YDcF3UrhQElwsYJaVaHXJtoI=", + "owner": "hyprwm", + "repo": "hyprland-protocols", + "rev": "bd153e76f751f150a09328dbdeb5e4fab9d23622", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprland-protocols", + "type": "github" + } + }, + "hyprland-qt-support": { + "inputs": { + "hyprlang": [ + "hyprland", + "hyprland-qtutils", + "hyprlang" + ], + "nixpkgs": [ + "hyprland", + "hyprland-qtutils", + "nixpkgs" + ], + "systems": [ + "hyprland", + "hyprland-qtutils", + "systems" + ] + }, + "locked": { + "lastModified": 1749154592, + "narHash": "sha256-DO7z5CeT/ddSGDEnK9mAXm1qlGL47L3VAHLlLXoCjhE=", + "owner": "hyprwm", + "repo": "hyprland-qt-support", + "rev": "4c8053c3c888138a30c3a6c45c2e45f5484f2074", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprland-qt-support", + "type": "github" + } + }, + "hyprland-qtutils": { + "inputs": { + "hyprland-qt-support": "hyprland-qt-support", + "hyprlang": [ + "hyprland", + "hyprlang" + ], + "hyprutils": [ + "hyprland", + "hyprland-qtutils", + "hyprlang", + "hyprutils" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1759080228, + "narHash": "sha256-RgDoAja0T1hnF0pTc56xPfLfFOO8Utol2iITwYbUhTk=", + "owner": "hyprwm", + "repo": "hyprland-qtutils", + "rev": "629b15c19fa4082e4ce6be09fdb89e8c3312aed7", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprland-qtutils", + "type": "github" + } + }, + "hyprlang": { + "inputs": { + "hyprutils": [ + "hyprland", + "hyprutils" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1758927902, + "narHash": "sha256-LZgMds7M94+vuMql2bERQ6LiFFdhgsEFezE4Vn+Ys3A=", + "owner": "hyprwm", + "repo": "hyprlang", + "rev": "4dafa28d4f79877d67a7d1a654cddccf8ebf15da", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprlang", + "type": "github" + } + }, + "hyprutils": { + "inputs": { + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1759619523, + "narHash": "sha256-r1ed7AR2ZEb2U8gy321/Xcp1ho2tzn+gG1te/Wxsj1A=", + "owner": "hyprwm", + "repo": "hyprutils", + "rev": "3df7bde01efb3a3e8e678d1155f2aa3f19e177ef", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprutils", + "type": "github" + } + }, + "hyprwayland-scanner": { + "inputs": { + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1755184602, + "narHash": "sha256-RCBQN8xuADB0LEgaKbfRqwm6CdyopE1xIEhNc67FAbw=", + "owner": "hyprwm", + "repo": "hyprwayland-scanner", + "rev": "b3b0f1f40ae09d4447c20608e5a4faf8bf3c492d", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprwayland-scanner", + "type": "github" + } + }, + "nixgl": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1752054764, + "narHash": "sha256-Ob/HuUhANoDs+nvYqyTKrkcPXf4ZgXoqMTQoCK0RFgQ=", + "owner": "nix-community", + "repo": "nixGL", + "rev": "a8e1ce7d49a149ed70df676785b07f63288f53c5", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixGL", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1761114652, + "narHash": "sha256-f/QCJM/YhrV/lavyCVz8iU3rlZun6d+dAiC3H+CDle4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "01f116e4df6a15f4ccdffb1bcd41096869fb385c", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1746378225, + "narHash": "sha256-OeRSuL8PUjIfL3Q0fTbNJD/fmv1R+K2JAOqWJd3Oceg=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "93e8cdce7afc64297cfec447c311470788131cd9", + "type": "github" + }, + "original": { + "owner": "nixos", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1761597516, + "narHash": "sha256-wxX7u6D2rpkJLWkZ2E932SIvDJW8+ON/0Yy8+a5vsDU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "daf6dc47aa4b44791372d6139ab7b25269184d55", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-25.05", + "type": "indirect" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "hyprland", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1760663237, + "narHash": "sha256-BflA6U4AM1bzuRMR8QqzPXqh8sWVCNDzOdsxXEguJIc=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "ca5b894d3e3e151ffc1db040b6ce4dcc75d31c37", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "home-manager": "home-manager", + "hyprland": "hyprland", + "nixgl": "nixgl", + "nixpkgs": "nixpkgs_3" + } + }, + "systems": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "xdph": { + "inputs": { + "hyprland-protocols": [ + "hyprland", + "hyprland-protocols" + ], + "hyprlang": [ + "hyprland", + "hyprlang" + ], + "hyprutils": [ + "hyprland", + "hyprutils" + ], + "hyprwayland-scanner": [ + "hyprland", + "hyprwayland-scanner" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1760713634, + "narHash": "sha256-5HXelmz2x/uO26lvW7MudnadbAfoBnve4tRBiDVLtOM=", + "owner": "hyprwm", + "repo": "xdg-desktop-portal-hyprland", + "rev": "753bbbdf6a052994da94062e5b753288cef28dfb", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "xdg-desktop-portal-hyprland", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/sdata/dist-nix/home-manager/username.nix b/sdata/dist-nix/home-manager/username.nix deleted file mode 100644 index e16c76dff..000000000 --- a/sdata/dist-nix/home-manager/username.nix +++ /dev/null @@ -1 +0,0 @@ -"" diff --git a/sdata/dist-nix/install-deps.sh b/sdata/dist-nix/install-deps.sh index 6b11606c2..726a51259 100644 --- a/sdata/dist-nix/install-deps.sh +++ b/sdata/dist-nix/install-deps.sh @@ -94,7 +94,7 @@ function hm_deps(){ --extra-experimental-features nix-command \ --extra-experimental-features flakes cd $REPO_ROOT - x git reset "${SETUP_USERNAME_NIXFILE}" + x git rm -f "${SETUP_USERNAME_NIXFILE}" } ################################################## From f81f4925a90bd22ffc403045bc33f18e5c42592b Mon Sep 17 00:00:00 2001 From: dancincomrade Date: Thu, 30 Oct 2025 22:29:11 +0800 Subject: [PATCH 55/59] chore(audio): increment pkgrel by 1 due to new deps added to PKGBUILD --- sdata/dist-arch/illogical-impulse-audio/PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdata/dist-arch/illogical-impulse-audio/PKGBUILD b/sdata/dist-arch/illogical-impulse-audio/PKGBUILD index 6b1a5efc7..4a9294122 100644 --- a/sdata/dist-arch/illogical-impulse-audio/PKGBUILD +++ b/sdata/dist-arch/illogical-impulse-audio/PKGBUILD @@ -1,6 +1,6 @@ pkgname=illogical-impulse-audio pkgver=1.0 -pkgrel=1 +pkgrel=2 pkgdesc='Illogical Impulse Audio Dependencies' arch=(any) license=(None) From e7e25cd25b6d245eddfbfa71e8ebb02361785daf Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 30 Oct 2025 22:42:56 +0800 Subject: [PATCH 56/59] Update showhelp() --- sdata/subcmd-install/options.sh | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/sdata/subcmd-install/options.sh b/sdata/subcmd-install/options.sh index ec466dfe9..d60705354 100644 --- a/sdata/subcmd-install/options.sh +++ b/sdata/subcmd-install/options.sh @@ -1,7 +1,7 @@ # Handle args for subcmd: install # shellcheck shell=bash showhelp(){ -echo -e "Syntax: $0 install [OPTIONS]... +printf "Syntax: $0 install [OPTIONS]... Idempotent installation for dotfiles. @@ -23,11 +23,17 @@ Options for install: --skip-miscconf Skip copying the dirs and files to \".configs\" except for 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 (currently only fontconfig). Possible values of : $(ls -A ${REPO_ROOT}/dots-extra/fontsets) - --via-nix (Unavailable yet) Use Nix to install dependencies -" +${STY_CYAN} +New features (experimental): + --exp-files Use yaml-based config for the third step copying files. + This feature is ${STY_YELLOW}still on early stage${STY_CYAN}, feedback and contribution welcomed, + see https://github.com/end-4/dots-hyprland/issues/2137 for details. + --via-nix Use Nix and Home-manager to install dependencies. + This feature is ${STY_RED}working in progress${STY_CYAN}. Contribution is welcomed, + see https://github.com/end-4/dots-hyprland/issues/1061 for details. +${STY_RST}" } cleancache(){ From fd72cd5e22622f711f7c9c98ed6f6ce10fd2c256 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:45:26 +0100 Subject: [PATCH 57/59] add config option to use old sine wave cookie clock --- .../background/cookieClock/CookieClock.qml | 28 ++++++-- .../quickshell/ii/modules/common/Config.qml | 1 + .../ii/modules/common/widgets/SineCookie.qml | 70 +++++++++++++++++++ .../ii/modules/settings/InterfaceConfig.qml | 12 ++++ 4 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 dots/.config/quickshell/ii/modules/common/widgets/SineCookie.qml diff --git a/dots/.config/quickshell/ii/modules/background/cookieClock/CookieClock.qml b/dots/.config/quickshell/ii/modules/background/cookieClock/CookieClock.qml index 12a4d9b96..07f83401d 100644 --- a/dots/.config/quickshell/ii/modules/background/cookieClock/CookieClock.qml +++ b/dots/.config/quickshell/ii/modules/background/cookieClock/CookieClock.qml @@ -83,8 +83,9 @@ Item { } } + property bool useSineCookie: Config.options.background.clock.cookie.useSineCookie DropShadow { - source: cookie + source: useSineCookie ? sineCookieLoader : roundedPolygonCookieLoader anchors.fill: source radius: 8 samples: radius * 2 + 1 @@ -100,14 +101,27 @@ Item { to: 0 } } - - MaterialCookie { - id: cookie + Loader { + id: sineCookieLoader z: 0 visible: false // The DropShadow already draws it - implicitSize: root.implicitSize - sides: Config.options.background.clock.cookie.sides - color: root.colBackground + active: useSineCookie + sourceComponent: SineCookie { + implicitSize: root.implicitSize + sides: Config.options.background.clock.cookie.sides + color: root.colBackground + } + } + Loader { + id: roundedPolygonCookieLoader + z: 0 + visible: false // The DropShadow already draws it + active: !useSineCookie + sourceComponent: MaterialCookie { + implicitSize: root.implicitSize + sides: Config.options.background.clock.cookie.sides + color: root.colBackground + } } // Hour/minutes numbers/dots/lines diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml index f43b86187..f6c183b2a 100644 --- a/dots/.config/quickshell/ii/modules/common/Config.qml +++ b/dots/.config/quickshell/ii/modules/common/Config.qml @@ -164,6 +164,7 @@ Singleton { property bool hourMarks: false property bool dateInClock: true property bool constantlyRotate: false + property bool useSineCookie: false } property JsonObject digital: JsonObject { property bool animateChange: true diff --git a/dots/.config/quickshell/ii/modules/common/widgets/SineCookie.qml b/dots/.config/quickshell/ii/modules/common/widgets/SineCookie.qml new file mode 100644 index 000000000..79048ca63 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/widgets/SineCookie.qml @@ -0,0 +1,70 @@ +import QtQuick +import QtQuick.Shapes +import Quickshell +import qs.modules.common + +Item { + id: root + + property real sides: 12 + property int implicitSize: 100 + property real amplitude: implicitSize / 50 + property int renderPoints: 360 + property color color: "#605790" + property alias strokeWidth: shapePath.strokeWidth + property bool constantlyRotate: false + + implicitWidth: implicitSize + implicitHeight: implicitSize + + property real shapeRotation: 0 + + Loader { + active: constantlyRotate + sourceComponent: FrameAnimation { + running: true + onTriggered: { + shapeRotation += 0.05 + } + } + } + + Behavior on sides { + animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) + } + + Shape { + id: shape + anchors.fill: parent + preferredRendererType: Shape.CurveRenderer + + ShapePath { + id: shapePath + strokeWidth: 0 + fillColor: root.color + pathHints: ShapePath.PathSolid & ShapePath.PathNonIntersecting + + PathPolyline { + property var pointsList: { + var points = [] + var cx = shape.width / 2 // center x + var cy = shape.height / 2 // center y + var steps = root.renderPoints + var radius = root.implicitSize / 2 - root.amplitude + for (var i = 0; i <= steps; i++) { + var angle = (i / steps) * 2 * Math.PI + var rotatedAngle = angle * root.sides + Math.PI/2 + (root.shapeRotation * root.constantlyRotate) + var wave = Math.sin(rotatedAngle) * root.amplitude + var x = Math.cos(angle) * (radius + wave) + cx + var y = Math.sin(angle) * (radius + wave) + cy + points.push(Qt.point(x, y)) + } + return points + } + + path: pointsList + } + + } + } +} diff --git a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml index cf7e98171..9dee53acc 100644 --- a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml @@ -85,6 +85,18 @@ ContentPage { } } + ConfigSwitch { + buttonIcon: "airwave" + text: Translation.tr("Use old sine wave cookie implementation") + checked: Config.options.background.clock.cookie.useSineCookie + onCheckedChanged: { + Config.options.background.clock.cookie.useSineCookie = checked; + } + StyledToolTip { + text: "Looks a bit softer and more consistent with different number of sides,\nbut has less impressive morphing" + } + } + ConfigSpinBox { icon: "add_triangle" text: Translation.tr("Sides") From d64528674417074368066f89d63ccf37aaf61105 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:56:17 +0100 Subject: [PATCH 58/59] lock: add setting to toggle new shape password chars --- dots/.config/quickshell/ii/modules/common/Config.qml | 1 + .../.config/quickshell/ii/modules/lock/LockSurface.qml | 10 +++++++--- .../quickshell/ii/modules/settings/InterfaceConfig.qml | 9 +++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml index f6c183b2a..18cd92fc3 100644 --- a/dots/.config/quickshell/ii/modules/common/Config.qml +++ b/dots/.config/quickshell/ii/modules/common/Config.qml @@ -328,6 +328,7 @@ Singleton { property bool unlockKeyring: true property bool requirePasswordToPower: false } + property bool materialShapeChars: true } property JsonObject media: JsonObject { diff --git a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml index 628f4d2fa..4fc147de4 100644 --- a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml +++ b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml @@ -170,14 +170,18 @@ MouseArea { } // We're drawing dots manually - color: ColorUtils.transparentize(Appearance.colors.colOnLayer1) - PasswordChars { + property bool materialShapeChars: Config.options.lock.materialShapeChars + color: ColorUtils.transparentize(Appearance.colors.colOnLayer1, materialShapeChars ? 1 : 0) + Loader { + active: passwordBox.materialShapeChars anchors { fill: parent leftMargin: passwordBox.padding rightMargin: passwordBox.padding } - length: root.context.currentText.length + sourceComponent: PasswordChars { + length: root.context.currentText.length + } } } diff --git a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml index 9dee53acc..13a909cbb 100644 --- a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml @@ -556,6 +556,15 @@ ContentPage { Config.options.lock.showLockedText = checked; } } + + ConfigSwitch { + buttonIcon: "shapes" + text: Translation.tr('Use varying shapes for password characters') + checked: Config.options.lock.materialShapeChars + onCheckedChanged: { + Config.options.lock.materialShapeChars = checked; + } + } } ContentSubsection { title: Translation.tr("Style: Blurred") From 0551c010b586dbf5578c32de2735698cca0801a7 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 30 Oct 2025 16:04:55 +0100 Subject: [PATCH 59/59] fix clock hands rotating in the wrong direction --- .../ii/modules/background/cookieClock/HourHand.qml | 8 ++++++++ .../ii/modules/background/cookieClock/MinuteHand.qml | 8 ++++++-- .../ii/modules/background/cookieClock/SecondHand.qml | 3 ++- dots/.config/quickshell/ii/services/Audio.qml | 4 ++-- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/background/cookieClock/HourHand.qml b/dots/.config/quickshell/ii/modules/background/cookieClock/HourHand.qml index c80d8839d..5c355d345 100644 --- a/dots/.config/quickshell/ii/modules/background/cookieClock/HourHand.qml +++ b/dots/.config/quickshell/ii/modules/background/cookieClock/HourHand.qml @@ -19,6 +19,14 @@ Item { } rotation: -90 + (360 / 12) * (root.clockHour + root.clockMinute / 60) + Behavior on rotation { + animation: RotationAnimation { + direction: RotationAnimation.Clockwise + duration: 300 + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animationCurves.emphasized + } + } Rectangle { anchors.verticalCenter: parent.verticalCenter diff --git a/dots/.config/quickshell/ii/modules/background/cookieClock/MinuteHand.qml b/dots/.config/quickshell/ii/modules/background/cookieClock/MinuteHand.qml index ca3884d19..764c14f2b 100644 --- a/dots/.config/quickshell/ii/modules/background/cookieClock/MinuteHand.qml +++ b/dots/.config/quickshell/ii/modules/background/cookieClock/MinuteHand.qml @@ -14,9 +14,13 @@ Item { property color color: Appearance.colors.colSecondary rotation: -90 + (360 / 60) * root.clockMinute - Behavior on rotation { - animation: Appearance.animation.elementResize.numberAnimation.createObject(this) + animation: RotationAnimation { + direction: RotationAnimation.Clockwise + duration: 300 + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.animationCurves.emphasized + } } Rectangle { diff --git a/dots/.config/quickshell/ii/modules/background/cookieClock/SecondHand.qml b/dots/.config/quickshell/ii/modules/background/cookieClock/SecondHand.qml index 2e16138e7..93ca1cf48 100644 --- a/dots/.config/quickshell/ii/modules/background/cookieClock/SecondHand.qml +++ b/dots/.config/quickshell/ii/modules/background/cookieClock/SecondHand.qml @@ -19,7 +19,8 @@ Item { Behavior on rotation { enabled: Config.options.background.clock.cookie.constantlyRotate // Animating every second is expensive... - animation: NumberAnimation { + animation: RotationAnimation { + direction: RotationAnimation.Clockwise duration: 1000 // 1 second easing.type: Easing.InOutQuad } diff --git a/dots/.config/quickshell/ii/services/Audio.qml b/dots/.config/quickshell/ii/services/Audio.qml index 9bb096208..5fca1a51a 100644 --- a/dots/.config/quickshell/ii/services/Audio.qml +++ b/dots/.config/quickshell/ii/services/Audio.qml @@ -1,9 +1,9 @@ +pragma Singleton +pragma ComponentBehavior: Bound import qs.modules.common import QtQuick import Quickshell import Quickshell.Services.Pipewire -pragma Singleton -pragma ComponentBehavior: Bound /** * A nice wrapper for default Pipewire audio sink and source.