From 10cde177dbd55aafd1f508c81b46cb2902ddf23d Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 24 Feb 2024 11:26:17 +0700 Subject: [PATCH 001/517] add tip for language --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4bee3a78e..2e62ec8b4 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,8 @@ bash <(curl -s "https://end-4.github.io/dots-hyprland-wiki/setup.sh") ``` - Manual installation, other distros and more: - - See the [Wiki](https://end-4.github.io/dots-hyprland-wiki/en/i-i/01setup/). + - See the [Wiki](https://end-4.github.io/dots-hyprland-wiki/en/i-i/01setup/) + - (_Available in: English, Vietnamese, and Simplified Chinese. Translations are welcome._) - If you'd like to suggest fixes or maybe a new widget, feel free to [open an issue](https://github.com/end-4/dots-hyprland/issues/new/choose)! From 93963f909bc6bb955b79c26a6d9b2b4a24555171 Mon Sep 17 00:00:00 2001 From: clsty Date: Sat, 24 Feb 2024 18:15:20 +0800 Subject: [PATCH 002/517] Wave goodbye to swaylock --- {.config => Import Manually}/swaylock/config | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {.config => Import Manually}/swaylock/config (100%) diff --git a/.config/swaylock/config b/Import Manually/swaylock/config similarity index 100% rename from .config/swaylock/config rename to Import Manually/swaylock/config From f2d6bfefe16e341bb6822e2a3338a0c2c263bb81 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 25 Feb 2024 09:03:35 +0700 Subject: [PATCH 003/517] mention discussions in readme --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2e62ec8b4..2aeecbfe6 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,13 @@ - Manual installation, other distros and more: - See the [Wiki](https://end-4.github.io/dots-hyprland-wiki/en/i-i/01setup/) - (_Available in: English, Vietnamese, and Simplified Chinese. Translations are welcome._) - - If you'd like to suggest fixes or maybe a new widget, feel free to [open an issue](https://github.com/end-4/dots-hyprland/issues/new/choose)! + + +
+ Help improve these dotfiles! + + - Join the [discussions](https://github.com/end-4/dots-hyprland/discussions) + - If you'd like to suggest fixes or a new widget, feel free to [open an issue](https://github.com/end-4/dots-hyprland/issues/new/choose)
### [illogical_impulse](https://github.com/end-4/dots-hyprland/tree/illogical-impulse) From 477b22636f0ddff4267a3218c9c64c9635a6dd22 Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 25 Feb 2024 11:27:19 +0800 Subject: [PATCH 004/517] Add bibata-cursor --- install.sh | 8 ++++++++ scriptdata/dependencies.conf | 2 +- scriptdata/installers | 13 +++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 21649bdf1..d09f97b82 100755 --- a/install.sh +++ b/install.sh @@ -119,6 +119,14 @@ if $(test -d /usr/local/share/icons/OneUI); then else ask_OneUI=true fi if $ask_OneUI;then showfun install-OneUI;v install-OneUI;fi + +if $(test -d /usr/local/share/icons/Bibata-Modern-Classic); then + echo -e "\e[33m[$0]: Cursor theme \"Bibata-Modern-Classic\" already exists, no need to install.\e[0m" + echo -e "\e[34mYou can reinstall it in order to update to the latest version anyway.\e[0m" + ask_bibata=$ask +else ask_bibata=true +fi +if $ask_bibata;then showfun install-bibata;v install-bibata;fi ##################################################################################### printf "\e[36m[$0]: 3. Copying\e[97m\n" diff --git a/scriptdata/dependencies.conf b/scriptdata/dependencies.conf index 60244e33a..129dd260b 100644 --- a/scriptdata/dependencies.conf +++ b/scriptdata/dependencies.conf @@ -2,7 +2,7 @@ ### PKGs on same line will be send to `yay` together, unless `-f` is specified. ### Basic -coreutils cliphist curl fuzzel rsync wget ripgrep gojq npm meson typescript gjs dart-sass +coreutils cliphist curl fuzzel rsync wget ripgrep gojq npm meson typescript gjs dart-sass axel ### Python # Add `python-setuptools-scm` and `python-wheel` explicitly to fix #197 diff --git a/scriptdata/installers b/scriptdata/installers index 8e707b29f..db3b29e88 100644 --- a/scriptdata/installers +++ b/scriptdata/installers @@ -73,3 +73,16 @@ install-OneUI (){ x sudo cp -r OneUI-light /usr/local/share/icons x cd $base } + +install-bibata (){ + x mkdir -p $base/cache/bibata-cursor + x cd $base/cache/bibata-cursor + name="Bibata-Modern-Classic" + file="$name.tar.xz" + # Use axel because `curl -O` always downloads a file with 0 byte size, idk why + x axel https://github.com/ful1e5/Bibata_Cursor/releases/latest/download/$file + tar -xf $file + x sudo mkdir -p /usr/local/share/icons + x sudo cp -r $name /usr/local/share/icons + x cd $base +} From 4b69574774a91c21a3c41465169f892f24838830 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 25 Feb 2024 13:17:53 +0700 Subject: [PATCH 005/517] idle: turn off screen before sleeping a bit --- .config/hypr/hypridle.conf | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.config/hypr/hypridle.conf b/.config/hypr/hypridle.conf index 6b2852514..3efbd108a 100644 --- a/.config/hypr/hypridle.conf +++ b/.config/hypr/hypridle.conf @@ -3,19 +3,21 @@ $suspend_cmd = systemctl suspend general { lock_cmd = $lock_cmd - # unlock_cmd before_sleep_cmd = $lock_cmd - # after_sleep_cmd } listener { - timeout = 300 + timeout = 180 # 3mins on-timeout = $lock_cmd - # on-resume } listener { - timeout = 450 - on-timeout = $suspend_cmd - # on-resume + timeout = 240 # 4mins + on-timeout = hyprctl dispatch dpms off + on-resume = hyprctl dispatch dpms on +} + +listener { + timeout = 540 # 9mins + on-timeout = $suspend_cmd } From 4d6eca3ee8fba643489e2c3aaf6f266fc84046f8 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:20:59 +0700 Subject: [PATCH 006/517] styles: compile to cache (more) three's still something compiling styles to ags folder... idk --- .config/ags/config.js | 4 ++-- .config/ags/modules/indicators/musiccontrols.js | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.config/ags/config.js b/.config/ags/config.js index 07b849f19..59d5e74ba 100644 --- a/.config/ags/config.js +++ b/.config/ags/config.js @@ -17,6 +17,7 @@ import Session from './modules/session/main.js'; import SideLeft from './modules/sideleft/main.js'; import SideRight from './modules/sideright/main.js'; +const COMPILED_STYLE_DIR = `${GLib.get_user_cache_dir()}/ags/user/generated` const range = (length, start = 1) => Array.from({ length }, (_, i) => i + start); function forMonitors(widget) { const n = Gdk.Display.get_default()?.get_n_monitors() || 1; @@ -27,7 +28,6 @@ function forMonitors(widget) { Utils.exec(`bash -c 'echo "" > ${App.configDir}/scss/_musicwal.scss'`); // reset music styles Utils.exec(`bash -c 'echo "" > ${App.configDir}/scss/_musicmaterial.scss'`); // reset music styles async function applyStyle() { - const COMPILED_STYLE_DIR = `${GLib.get_user_cache_dir()}/ags/user/generated` Utils.exec(`mkdir -p ${COMPILED_STYLE_DIR}`); Utils.exec(`sass ${App.configDir}/scss/main.scss ${COMPILED_STYLE_DIR}/style.css`); App.resetCss(); @@ -56,7 +56,7 @@ const Windows = () => [ ]; const CLOSE_ANIM_TIME = 210; // Longer than actual anim time to make sure widgets animate fully export default { - css: `${App.configDir}/style.css`, + css: `${COMPILED_STYLE_DIR}/style.css`, stackTraceOnError: true, closeWindowDelay: { // For animations 'sideright': CLOSE_ANIM_TIME, diff --git a/.config/ags/modules/indicators/musiccontrols.js b/.config/ags/modules/indicators/musiccontrols.js index 5bf8971bb..c4e54853d 100644 --- a/.config/ags/modules/indicators/musiccontrols.js +++ b/.config/ags/modules/indicators/musiccontrols.js @@ -9,6 +9,8 @@ const { Box, EventBox, Icon, Scrollable, Label, Button, Revealer } = Widget; import { AnimatedCircProg } from "../.commonwidgets/cairo_circularprogress.js"; import { showMusicControls } from '../../variables.js'; +const COMPILED_STYLE_DIR = `${GLib.get_user_cache_dir()}/ags/user/generated` + function expandTilde(path) { if (path.startsWith('~')) { return GLib.get_home_dir() + path.slice(1); @@ -187,7 +189,7 @@ const CoverArt = ({ player, ...rest }) => { // Note that cover path still remains, so we're checking title if (!player || player.trackTitle == "") { self.css = `background-image: none;`; - App.applyCss(`${App.configDir}/style.css`); + App.applyCss(`${COMPILED_STYLE_DIR}/style.css`); return; } From 61043a20526387350f9ea45196b9b071b0601cd9 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:19:21 +0700 Subject: [PATCH 007/517] generate styles to cache folder when switching themes --- .config/ags/scripts/color_generation/applycolor.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/ags/scripts/color_generation/applycolor.sh b/.config/ags/scripts/color_generation/applycolor.sh index 95df7f338..bb892cada 100755 --- a/.config/ags/scripts/color_generation/applycolor.sh +++ b/.config/ags/scripts/color_generation/applycolor.sh @@ -188,9 +188,9 @@ apply_gtk() { # Using gradience-cli } apply_ags() { - sass "$HOME"/.config/ags/scss/main.scss "$HOME"/.config/ags/style.css + sass "$HOME"/.config/ags/scss/main.scss "$HOME"/.cache/ags/user/generated/style.css ags run-js 'openColorScheme.value = true; Utils.timeout(2000, () => openColorScheme.value = false);' - ags run-js "App.resetCss(); App.applyCss('${HOME}/.config/ags/style.css');" + ags run-js "App.resetCss(); App.applyCss('${HOME}/.cache/ags/user/generated/style.css');" } apply_ags & From 7584c3fcb262288af396cffae0720cff1735d1bc Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 26 Feb 2024 22:34:35 +0700 Subject: [PATCH 008/517] Update rules.conf --- .config/hypr/hyprland/rules.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.config/hypr/hyprland/rules.conf b/.config/hypr/hyprland/rules.conf index cad82a903..f7c195c1a 100644 --- a/.config/hypr/hyprland/rules.conf +++ b/.config/hypr/hyprland/rules.conf @@ -4,7 +4,8 @@ windowrule = noblur,.* # Disables blur for windows. Substantially improves perf # windowrule = opacity 0.89 override 0.89 override, .* # Applies transparency to EVERY WINDOW windowrule = float, ^(steam)$ windowrule = float, ^(guifetch)$ # FlafyDev/guifetch -windowrulev2 = tile,class:(wpsoffice) +windowrulev2 = tile,class:(wps) +windowrulev2 = tile,class:(dev.warp.Warp) # Dialogs From 0c84b6d16611a93ffcd81179a465a4a01076d59a Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 26 Feb 2024 22:36:00 +0700 Subject: [PATCH 009/517] remove comments --- .config/ags/modules/indicators/musiccontrols.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.config/ags/modules/indicators/musiccontrols.js b/.config/ags/modules/indicators/musiccontrols.js index c4e54853d..6575c69ff 100644 --- a/.config/ags/modules/indicators/musiccontrols.js +++ b/.config/ags/modules/indicators/musiccontrols.js @@ -188,7 +188,6 @@ const CoverArt = ({ player, ...rest }) => { // Player closed // Note that cover path still remains, so we're checking title if (!player || player.trackTitle == "") { - self.css = `background-image: none;`; App.applyCss(`${COMPILED_STYLE_DIR}/style.css`); return; } @@ -196,14 +195,12 @@ const CoverArt = ({ player, ...rest }) => { const coverPath = player.coverPath; const stylePath = `${player.coverPath}${lightDark}${COVER_COLORSCHEME_SUFFIX}`; if (player.coverPath == lastCoverPath) { // Since 'notify::cover-path' emits on cover download complete - // Utils.timeout(200, () => { self.css = `background-image: url('${coverPath}');`; }); Utils.timeout(200, () => self.attribute.showImage(self, coverPath)); } lastCoverPath = player.coverPath; // If a colorscheme has already been generated, skip generation if (fileExists(stylePath)) { - // Utils.timeout(200, () => { self.css = `background-image: url('${coverPath}');`; }); self.attribute.showImage(self, coverPath) App.applyCss(stylePath); return; @@ -216,7 +213,6 @@ const CoverArt = ({ player, ...rest }) => { exec(`wal -i "${player.coverPath}" -n -t -s -e -q ${lightDark}`) exec(`cp ${GLib.get_user_cache_dir()}/wal/colors.scss ${App.configDir}/scss/_musicwal.scss`); exec(`sass ${App.configDir}/scss/_music.scss ${stylePath}`); - // self.css = `background-image: url('${coverPath}');`; Utils.timeout(200, () => self.attribute.showImage(self, coverPath)); App.applyCss(`${stylePath}`); }) From 01679e18497f8e1ecdffddfaef5e03f07b1b6c0f Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 26 Feb 2024 22:40:50 +0700 Subject: [PATCH 010/517] use grimblast (#290) --- .config/ags/scripts/grimblast.sh | 278 ++++++++++++++++++ .../templates/hypr/hyprland/colors.conf | 2 +- 2 files changed, 279 insertions(+), 1 deletion(-) create mode 100755 .config/ags/scripts/grimblast.sh diff --git a/.config/ags/scripts/grimblast.sh b/.config/ags/scripts/grimblast.sh new file mode 100755 index 000000000..b7a4775a8 --- /dev/null +++ b/.config/ags/scripts/grimblast.sh @@ -0,0 +1,278 @@ +#!/usr/bin/env bash +## Grimblast: a helper for screenshots within hyprland +## Requirements: +## - `grim`: screenshot utility for wayland +## - `slurp`: to select an area +## - `hyprctl`: to read properties of current window (provided by Hyprland) +## - `hyprpicker`: to freeze the screen when selecting area +## - `wl-copy`: clipboard utility (provided by wl-clipboard) +## - `jq`: json utility to parse hyprctl output +## - `notify-send`: to show notifications (provided by libnotify) +## Those are needed to be installed, if unsure, run `grimblast check` +## +## See `man 1 grimblast` or `grimblast usage` for further details. + +## Author: Misterio (https://github.com/misterio77) + +## This tool is based on grimshot, with swaymsg commands replaced by their +## hyprctl equivalents. +## https://github.com/swaywm/sway/blob/master/contrib/grimshot + +getTargetDirectory() { + test -f "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs" && + . "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs" + + echo "${XDG_SCREENSHOTS_DIR:-${XDG_PICTURES_DIR:-$HOME}}" +} + +tmp_editor_directory() { + echo "/tmp" +} + +#Detect if $GRIMBLAST_EDITOR env exist +env_editor_confirm() { + if [ -n "$GRIMBLAST_EDITOR" ]; then + echo "GRIMBLAST_EDITOR is set. Continuing..." + else + echo "GRIMBLAST_EDITOR is not set. Defaulting to gimp" + GRIMBLAST_EDITOR=gimp + fi +} + +NOTIFY=no +CURSOR= +FREEZE= +WAIT=no +SCALE= +HYPRPICKER_PID=-1 + +while [ $# -gt 0 ]; do + key="$1" + + case $key in + -n | --notify) + NOTIFY=yes + shift # past argument + ;; + -c | --cursor) + CURSOR=yes + shift # past argument + ;; + -f | --freeze) + FREEZE=yes + shift # past argument + ;; + -w | --wait) + shift + WAIT=$1 + if echo "$WAIT" | grep "[^0-9]" -q; then + echo "Invalid value for wait '$WAIT'" >&2 + exit 3 + fi + shift + ;; + -s | --scale) + shift # past argument + if [ $# -gt 0 ]; then + SCALE="$1" # assign the next argument to SCALE + shift # past argument + else + echo "Error: Missing argument for --scale option." + exit 1 + fi + ;; + *) # unknown option + break # done with parsing --flags + ;; + esac +done + +ACTION=${1:-usage} +SUBJECT=${2:-screen} +FILE=${3:-$(getTargetDirectory)/$(date -Ins).png} +FILE_EDITOR=${3:-$(tmp_editor_directory)/$(date -Ins).png} + +if [ "$ACTION" != "save" ] && [ "$ACTION" != "copy" ] && [ "$ACTION" != "edit" ] && [ "$ACTION" != "copysave" ] && [ "$ACTION" != "check" ]; then + echo "Usage:" + echo " grimblast [--notify] [--cursor] [--freeze] [--wait N] [--scale ] (copy|save|copysave|edit) [active|screen|output|area] [FILE|-]" + echo " grimblast check" + echo " grimblast usage" + echo "" + echo "Commands:" + echo " copy: Copy the screenshot data into the clipboard." + echo " save: Save the screenshot to a regular file or '-' to pipe to STDOUT." + echo " copysave: Combine the previous 2 options." + echo " edit: Open screenshot in the image editor of your choice (default is gimp). See man page for info." + echo " check: Verify if required tools are installed and exit." + echo " usage: Show this message and exit." + echo "" + echo "Targets:" + echo " active: Currently active window." + echo " screen: All visible outputs." + echo " output: Currently active output." + echo " area: Manually select a region or window." + exit +fi + +notify() { + notify-send -t 3000 -a grimblast "$@" +} + +notifyOk() { + [ "$NOTIFY" = "no" ] && return + + notify "$@" +} + +notifyError() { + if [ $NOTIFY = "yes" ]; then + TITLE=${2:-"Screenshot"} + MESSAGE=${1:-"Error taking screenshot with grim"} + notify -u critical "$TITLE" "$MESSAGE" + else + echo "$1" + fi +} + +resetFade() { + if [[ -n $FADE && -n $FADEOUT ]]; then + hyprctl keyword animation "$FADE" >/dev/null + hyprctl keyword animation "$FADEOUT" >/dev/null + fi +} + +killHyprpicker() { + if [ ! $HYPRPICKER_PID -eq -1 ]; then + kill $HYPRPICKER_PID + fi +} + +die() { + killHyprpicker + MSG=${1:-Bye} + notifyError "Error: $MSG" + exit 2 +} + +check() { + COMMAND=$1 + if command -v "$COMMAND" >/dev/null 2>&1; then + RESULT="OK" + else + RESULT="NOT FOUND" + fi + echo " $COMMAND: $RESULT" +} + +takeScreenshot() { + FILE=$1 + GEOM=$2 + OUTPUT=$3 + if [ -n "$OUTPUT" ]; then + grim ${CURSOR:+-c} ${SCALE:+-s "$SCALE"} -o "$OUTPUT" "$FILE" || die "Unable to invoke grim" + elif [ -z "$GEOM" ]; then + grim ${CURSOR:+-c} ${SCALE:+-s "$SCALE"} "$FILE" || die "Unable to invoke grim" + else + grim ${CURSOR:+-c} ${SCALE:+-s "$SCALE"} -g "$GEOM" "$FILE" || die "Unable to invoke grim" + resetFade + fi +} + +wait() { + if [ "$WAIT" != "no" ]; then + sleep "$WAIT" + fi +} + +if [ "$ACTION" = "check" ]; then + echo "Checking if required tools are installed. If something is missing, install it to your system and make it available in PATH..." + check grim + check slurp + check hyprctl + check hyprpicker + check wl-copy + check jq + check notify-send + exit +elif [ "$SUBJECT" = "active" ]; then + wait + FOCUSED=$(hyprctl activewindow -j) + GEOM=$(echo "$FOCUSED" | jq -r '"\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"') + APP_ID=$(echo "$FOCUSED" | jq -r '.class') + WHAT="$APP_ID window" +elif [ "$SUBJECT" = "screen" ]; then + wait + GEOM="" + WHAT="Screen" +elif [ "$SUBJECT" = "output" ]; then + wait + GEOM="" + OUTPUT=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true)' | jq -r '.name') + WHAT="$OUTPUT" +elif [ "$SUBJECT" = "area" ]; then + if [ "$FREEZE" = "yes" ] && [ "$(command -v "hyprpicker")" ] >/dev/null 2>&1; then + hyprpicker -r -z & + sleep 0.2 + HYPRPICKER_PID=$! + fi + + # get fade & fadeOut animation and unset it + # this removes the black border seen around screenshots + FADE="$(hyprctl -j animations | jq -jr '.[0][] | select(.name == "fade") | .name, ",", (if .enabled == true then "1" else "0" end), ",", (.speed|floor), ",", .bezier')" + FADEOUT="$(hyprctl -j animations | jq -jr '.[0][] | select(.name == "fadeOut") | .name, ",", (if .enabled == true then "1" else "0" end), ",", (.speed|floor), ",", .bezier')" + hyprctl keyword animation 'fade,0,1,default' >/dev/null + hyprctl keyword animation 'fadeOut,0,1,default' >/dev/null + + WORKSPACES="$(hyprctl monitors -j | jq -r 'map(.activeWorkspace.id)')" + WINDOWS="$(hyprctl clients -j | jq -r --argjson workspaces "$WORKSPACES" 'map(select([.workspace.id] | inside($workspaces)))')" + # shellcheck disable=2086 # if we don't split, spaces mess up slurp + GEOM=$(echo "$WINDOWS" | jq -r '.[] | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"' | slurp $SLURP_ARGS) + + # Check if user exited slurp without selecting the area + if [ -z "$GEOM" ]; then + killHyprpicker + resetFade + exit 1 + fi + WHAT="Area" + wait +elif [ "$SUBJECT" = "window" ]; then + die "Subject 'window' is now included in 'area'" +else + die "Unknown subject to take a screen shot from" "$SUBJECT" +fi + +if [ "$ACTION" = "copy" ]; then + takeScreenshot - "$GEOM" "$OUTPUT" | wl-copy --type image/png || die "Clipboard error" + notifyOk "$WHAT copied to buffer" +elif [ "$ACTION" = "save" ]; then + if takeScreenshot "$FILE" "$GEOM" "$OUTPUT"; then + TITLE="Screenshot of $SUBJECT" + MESSAGE=$(basename "$FILE") + notifyOk "$TITLE" "$MESSAGE" -i "$FILE" + echo "$FILE" + else + notifyError "Error taking screenshot with grim" + fi +elif [ "$ACTION" = "edit" ]; then + env_editor_confirm + if takeScreenshot "$FILE_EDITOR" "$GEOM" "$OUTPUT"; then + TITLE="Screenshot of $SUBJECT" + MESSAGE="Open screenshot in image editor" + notifyOk "$TITLE" "$MESSAGE" -i "$FILE_EDITOR" + $GRIMBLAST_EDITOR "$FILE_EDITOR" + echo "$FILE_EDITOR" + else + notifyError "Error taking screenshot" + fi +else + if [ "$ACTION" = "copysave" ]; then + takeScreenshot - "$GEOM" "$OUTPUT" | tee "$FILE" | wl-copy --type image/png || die "Clipboard error" + notifyOk "$WHAT copied to buffer and saved to $FILE" -i "$FILE" + echo "$FILE" + else + notifyError "Error taking screenshot with grim" + fi +fi + +killHyprpicker diff --git a/.config/ags/scripts/templates/hypr/hyprland/colors.conf b/.config/ags/scripts/templates/hypr/hyprland/colors.conf index 3a0bf4a34..8c0689f31 100644 --- a/.config/ags/scripts/templates/hypr/hyprland/colors.conf +++ b/.config/ags/scripts/templates/hypr/hyprland/colors.conf @@ -1,4 +1,4 @@ -$SLURP_COMMAND="$(slurp -d -c {{ $onSecondaryContainer }}BB -b {{ $secondaryContainer }}44 -s 00000000)" +# exec = export SLURP_ARGS='-d -c {{ $onSecondaryContainer }}BB -b {{ $secondaryContainer }}44 -s 00000000' general { col.active_border = rgba({{ $onSurface }}39) From 09e1e13fea79a30f8b460fd06e7357eca8cd3288 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 26 Feb 2024 22:41:35 +0700 Subject: [PATCH 011/517] use grimblast --- .config/ags/modules/bar/system.js | 2 +- .config/hypr/hyprland/keybinds.conf | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.config/ags/modules/bar/system.js b/.config/ags/modules/bar/system.js index 9a8fc86a8..5efdc0fdc 100644 --- a/.config/ags/modules/bar/system.js +++ b/.config/ags/modules/bar/system.js @@ -75,7 +75,7 @@ const Utilities = () => Box({ children: [ UtilButton({ name: 'Screen snip', icon: 'screenshot_region', onClicked: () => { - Utils.execAsync(['bash', '-c', `grim -g "$(slurp -d -c e2e2e2BB -b 31313122 -s 00000000)" - | wl-copy &`]) + Utils.execAsync(`${App.configDir}/scripts/grimblast.sh`) .catch(print) } }), diff --git a/.config/hypr/hyprland/keybinds.conf b/.config/hypr/hyprland/keybinds.conf index 275d0dba4..3b49f83b6 100644 --- a/.config/hypr/hyprland/keybinds.conf +++ b/.config/hypr/hyprland/keybinds.conf @@ -38,9 +38,9 @@ bind = Control+Shift+Alt, Delete, exec, pkill wlogout || wlogout -p layer-shell bind = Control+Shift+Alt+Super, Delete, exec, systemctl poweroff # Screenshot, Record, OCR, Color picker, Clipboard history -bind = Super+Shift+Alt, S, exec, grim -g $SLURP_COMMAND - | swappy -f - +bind = Super+Shift+Alt, S, exec, grim -g $(slurp $SLURP_ARGS) - | swappy -f - bindl=,Print,exec,grim - | wl-copy -bind = Super+Shift, S, exec, grim -g $SLURP_COMMAND - | wl-copy +bind = Super+Shift, S, exec, ~/.config/ags/scripts/grimblast.sh --freeze copy area bind = Super+Alt, R, exec, ~/.config/ags/scripts/record-script.sh bind = Control+Alt, R, exec, ~/.config/ags/scripts/record-script.sh --fullscreen bind = Super+Shift+Alt, R, exec, ~/.config/ags/scripts/record-script.sh --fullscreen-sound @@ -49,11 +49,11 @@ bind = Super, V, exec, pkill fuzzel || cliphist list | fuzzel --no-fuzzy --dmenu # Text-to-image # Normal -bind = Control+Super+Shift,S,exec,grim -g $SLURP_COMMAND "tmp.png" && tesseract "tmp.png" - | wl-copy && rm "tmp.png" +bind = Control+Super+Shift,S,exec,grim -g $(slurp $SLURP_ARGS) "tmp.png" && tesseract "tmp.png" - | wl-copy && rm "tmp.png" # English -bind = Super+Shift,T,exec,grim -g $SLURP_COMMAND "tmp.png" && tesseract -l eng "tmp.png" - | wl-copy && rm "tmp.png" +bind = Super+Shift,T,exec,grim -g $(slurp $SLURP_ARGS) "tmp.png" && tesseract -l eng "tmp.png" - | wl-copy && rm "tmp.png" # Japanese -bind = Super+Shift,J,exec,grim -g $SLURP_COMMAND "tmp.png" && tesseract -l jpn "tmp.png" - | wl-copy && rm "tmp.png" +bind = Super+Shift,J,exec,grim -g $(slurp $SLURP_ARGS) "tmp.png" && tesseract -l jpn "tmp.png" - | wl-copy && rm "tmp.png" # Media bindl= Super+Shift, N, exec, playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` @@ -100,7 +100,8 @@ bind = Control+Super, O, exec, hyprctl plugin unload "~/.config/hypr/plugins/dro # bind = SuperAlt, f12, exec, notify-send "Hyprland version: $(hyprctl version | head -2 | tail -1 | cut -f2 -d ' ')" "owo" -a 'Hyprland keybind' # bind = Super+Alt, f12, exec, notify-send "Millis since epoch" "$(date +%s%N | cut -b1-13)" -a 'Hyprland keybind' bind = Super+Alt, f12, exec, notify-send 'Test notification' "Here's a really long message to test truncation and wrapping\nYou can middle click or flick this notification to dismiss it!" -a 'Shell' -A "Test1=I got it!" -A "Test2=Another action" -bind = Super+Alt, Equal, exec, notify-send "Urgent notification" "Ah hell no" -u critical -a 'Hyprland keybind' +# bind = Super+Alt, Equal, exec, notify-send "Urgent notification" "Ah hell no" -u critical -a 'Hyprland keybind' +bind = Super+Alt, Equal, exec, notify-send 'hmm' ${SLURP_ARGS} ############################ Keybinds for Hyprland ############################ # Swap windows From 9b3ce245da98205aae854653ba4151e907490430 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 26 Feb 2024 22:43:27 +0700 Subject: [PATCH 012/517] ai: add latex rendering --- .config/ags/modules/.miscutils/md2pango.js | 3 + .../modules/sideleft/apis/ai_chatmessage.js | 66 ++++++++++++++++++- .config/ags/scss/_sidebars.scss | 9 +++ install.sh | 9 +++ scriptdata/installers | 15 +++++ 5 files changed, 100 insertions(+), 2 deletions(-) diff --git a/.config/ags/modules/.miscutils/md2pango.js b/.config/ags/modules/.miscutils/md2pango.js index 054752b14..8f56e3aeb 100644 --- a/.config/ags/modules/.miscutils/md2pango.js +++ b/.config/ags/modules/.miscutils/md2pango.js @@ -83,4 +83,7 @@ console.log('uwu'); \`\`\` - Random instruction thing - To update arch lincox, run \`sudo pacman -Syu\` +\`\`\`tex +\\frac{d}{dx} \\left( \\frac{x-438}{x^2+23x-7} \\right) = \\frac{-x^2 + 869}{(x^2+23x-7)^2} +\`\`\` `; \ No newline at end of file diff --git a/.config/ags/modules/sideleft/apis/ai_chatmessage.js b/.config/ags/modules/sideleft/apis/ai_chatmessage.js index 5bc44f847..2b8864826 100644 --- a/.config/ags/modules/sideleft/apis/ai_chatmessage.js +++ b/.config/ags/modules/sideleft/apis/ai_chatmessage.js @@ -3,12 +3,12 @@ import GtkSource from "gi://GtkSource?version=3.0"; import App from 'resource:///com/github/Aylur/ags/app.js'; import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; -const { Box, Button, Label, Scrollable } = Widget; +const { Box, Button, Label, Icon, Scrollable } = Widget; const { execAsync, exec } = Utils; import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; import md2pango from '../../.miscutils/md2pango.js'; - +const LATEX_DIR = `${GLib.get_user_cache_dir()}/ags/media/latex`; const CUSTOM_SOURCEVIEW_SCHEME_PATH = `${App.configDir}/assets/themes/sourceviewtheme.xml`; const CUSTOM_SCHEME_ID = 'custom'; const USERNAME = GLib.get_user_name(); @@ -82,7 +82,69 @@ const TextBlock = (content = '') => Label({ label: content, }); +Utils.execAsync(['bash', '-c', `rm ${LATEX_DIR}/*`]) + .then(() => Utils.execAsync(['bash', '-c', `mkdir -p ${LATEX_DIR}`])) + .catch(print); +const Latex = (content = '') => { + const latexViewArea = Box({ + // vscroll: 'never', + // hscroll: 'automatic', + attribute: { + render: async (self, text) => { + if (text.length == 0) return; + const styleContext = self.get_style_context(); + const fontSize = styleContext.get_property('font-size', Gtk.StateFlags.NORMAL); + + const timeSinceEpoch = Date.now(); + const fileName = `${timeSinceEpoch}.tex`; + const outFileName = `${timeSinceEpoch}-symbolic.svg`; + const scriptFileName = `${timeSinceEpoch}-render.sh`; + const filePath = `${LATEX_DIR}/${fileName}`; + const outFilePath = `${LATEX_DIR}/${outFileName}`; + const scriptFilePath = `${LATEX_DIR}/${scriptFileName}`; + + Utils.writeFile(text, filePath).catch(print); + // Since MicroTex doesn't support file path input properly, we gotta cat it + // And escaping such a command is a fucking pain so I decided to just generate a script + // Note: MicroTex doesn't support `&=` + // You can add this line in the middle for debugging: echo "$text" > ${filePath}.tmp + const renderScript = `#!/usr/bin/env bash +text=$(cat ${filePath} | sed 's/$/ \\\\\\\\/g' | sed 's/&=/=/g') +LaTeX -headless -input="$text" -output=${outFilePath} -textsize=${fontSize * 1.1} -padding=0 -maxwidth=${latexViewArea.get_allocated_width() * 0.85} +`; + Utils.writeFile(renderScript, scriptFilePath).catch(print); + Utils.exec(`chmod a+x ${scriptFilePath}`) + Utils.timeout(100, () => { + Utils.exec(`bash ${scriptFilePath}`); + Gtk.IconTheme.get_default().append_search_path(LATEX_DIR); + self.child?.destroy(); + self.child = Gtk.Image.new_from_file(outFilePath); + }) + } + }, + setup: (self) => self.attribute.render(self, content).catch(print), + }); + const wholeThing = Box({ + className: 'sidebar-chat-latex', + homogeneous: true, + attribute: { + 'updateText': (text) => { + latexViewArea.attribute.render(latexViewArea, text).catch(print); + } + }, + children: [Scrollable({ + vscroll: 'never', + hscroll: 'automatic', + child: latexViewArea + })] + }) + return wholeThing; +} + const CodeBlock = (content = '', lang = 'txt') => { + if (lang == 'tex' || lang == 'latex') { + return Latex(content); + } const topBar = Box({ className: 'sidebar-chat-codeblock-topbar', children: [ diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss index 51a3b5dde..a4a98d5a4 100644 --- a/.config/ags/scss/_sidebars.scss +++ b/.config/ags/scss/_sidebars.scss @@ -655,6 +655,15 @@ $colorpicker_rounding: 0.341rem; @include readingfont; } +.sidebar-chat-latex { + margin: 0rem 0.682rem; + @if $darkmode ==true { + background-color: white; + } + color: $onBackground; + // background-color: $termbg; +} + .sidebar-chat-codeblock { @include normal-rounding; // @include elevation2; diff --git a/install.sh b/install.sh index d09f97b82..8b2a1d02a 100755 --- a/install.sh +++ b/install.sh @@ -127,6 +127,15 @@ if $(test -d /usr/local/share/icons/Bibata-Modern-Classic); then else ask_bibata=true fi if $ask_bibata;then showfun install-bibata;v install-bibata;fi + +if $(test -d /usr/local/bin/LaTex); then + echo -e "\e[33m[$0]: Program \"MicroTex\" already exists, no need to install.\e[0m" + echo -e "\e[34mYou can reinstall it in order to update to the latest version anyway.\e[0m" + ask_MicroTex=$ask +else ask_MicroTex=true +fi +if $ask_MicroTex;then showfun install-MicroTex;v install-MicroTex;fi + ##################################################################################### printf "\e[36m[$0]: 3. Copying\e[97m\n" diff --git a/scriptdata/installers b/scriptdata/installers index db3b29e88..aad02b94f 100644 --- a/scriptdata/installers +++ b/scriptdata/installers @@ -86,3 +86,18 @@ install-bibata (){ x sudo cp -r $name /usr/local/share/icons x cd $base } + +install-MicroTex (){ + x mkdir -p $base/cache/MicroTex + x cd $base/cache/MicroTex + try git init -b master + try git remote add origin https://github.com/NanoMichael/MicroTeX.git + x git pull origin master && git submodule update --init --recursive + x mkdir -p build + x cd build + x cmake .. + x make -j32 + x sudo mkdir -p /usr/local/bin + x sudo cp ./LaTeX /usr/local/bin/ + x cd $base +} From ccfb4859cf24d5861429a5cbc0918e8cbad5919b Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 26 Feb 2024 22:45:51 +0700 Subject: [PATCH 013/517] ai: make latex block nicer --- .config/ags/scss/_sidebars.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss index a4a98d5a4..14103427b 100644 --- a/.config/ags/scss/_sidebars.scss +++ b/.config/ags/scss/_sidebars.scss @@ -656,7 +656,9 @@ $colorpicker_rounding: 0.341rem; } .sidebar-chat-latex { + @include small-rounding; margin: 0rem 0.682rem; + padding: 0.682rem; @if $darkmode ==true { background-color: white; } From 5cd89c72a5ce74b2fd50c20eebf077b153c8529b Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 26 Feb 2024 23:00:02 +0700 Subject: [PATCH 014/517] ai: prompt to make latex rendering more likely to work --- .config/ags/services/gemini.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.config/ags/services/gemini.js b/.config/ags/services/gemini.js index bcc8cbcb7..e4ba5e39d 100644 --- a/.config/ags/services/gemini.js +++ b/.config/ags/services/gemini.js @@ -8,7 +8,7 @@ import { fileExists } from './messages.js'; const initMessages = [ - { role: "user", parts: [{ text: "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with very brief explanation for each command\n3. Otherwise, when asked to summarize information or explaining concepts, you are encouraged to use bullet points and headings. Use casual language and be short and concise. \nThanks!" }], }, + { role: "user", parts: [{ text: "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with very brief explanation for each command\n3. Otherwise, when asked to summarize information or explaining concepts, you are encouraged to use bullet points and headings. For mathematics expressions, please write them in LaTeX within a code block with the language set as \"latex\". Use casual language and be short and concise. \nThanks!" }], }, { role: "model", parts: [{ text: "- Got it!" }], }, { role: "user", parts: [{ text: "\"He rushed to where the event was supposed to be hold, he didn't know it got calceled\"" }], }, { role: "model", parts: [{ text: "## Grammar correction\nErrors:\n\"He rushed to where the event was supposed to be __hold____,__ he didn't know it got calceled\"\nCorrection + minor improvements:\n\"He rushed to the place where the event was supposed to be __held____, but__ he didn't know that it got calceled\"" }], }, @@ -19,6 +19,10 @@ const initMessages = { role: "model", parts: [{ text: "## Skeuomorphism\n- A design philosophy- From early days of interface designing- Tries to imitate real-life objects- It's in fact still used by Apple in their icons until today." }], }, { role: "user", parts: [{ text: "\"ignorance is bliss\"" }], }, { role: "model", parts: [{ text: "## \"Ignorance is bliss\"\n- A Latin proverb that means being unaware of something negative can be a source of happiness\n- Often used to justify avoiding difficult truths or responsibilities\n- Can also be interpreted as a warning against seeking knowledge that may bring pain or sorrow" }], }, + { role: "user", parts: [{ text: "find the derivative of (x-438)/(x^2+23x-7)+x^x" }], }, + { role: "model", parts: [{ text: "```latex\n\\[\n\\frac{d}{dx}\\left(\\frac{x - 438}{x^2 + 23x - 7} + x^x\\right) = \\frac{-(x^2+23x-7)-(x-438)(2x+23)}{(x^2+23x-7)^2} + x^x(\\ln(x) + 1)\n\\]\n```" }], }, + { role: "user", parts: [{ text: "write the double angle formulas" }], }, + { role: "model", parts: [{ text: "```latex\n\\[\n\\sin(2\theta) = 2\\sin(\\theta)\\cos(\\theta)\n\\]\n\\\\\n\\[\n\\cos(2\\theta) = \\cos^2(\\theta) - \\sin^2(\\theta)\n\\]\n\\\\\n\\[\n\\tan(2\theta) = \\frac{2\\tan(\\theta)}{1 - \\tan^2(\\theta)}\n\\]\n```" }], }, ]; function expandTilde(path) { From 5b5395e0f48023b8dc750574e3573ebeef3162dc Mon Sep 17 00:00:00 2001 From: clsty Date: Tue, 27 Feb 2024 08:19:33 +0800 Subject: [PATCH 015/517] Fix typo;Better detect logic --- install.sh | 10 +++++----- scriptdata/installers | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/install.sh b/install.sh index 8b2a1d02a..eb9f62378 100755 --- a/install.sh +++ b/install.sh @@ -128,13 +128,13 @@ else ask_bibata=true fi if $ask_bibata;then showfun install-bibata;v install-bibata;fi -if $(test -d /usr/local/bin/LaTex); then - echo -e "\e[33m[$0]: Program \"MicroTex\" already exists, no need to install.\e[0m" +if command -v LaTeX >/dev/null 2>&1;then + echo -e "\e[33m[$0]: Program \"MicroTeX\" already exists, no need to install.\e[0m" echo -e "\e[34mYou can reinstall it in order to update to the latest version anyway.\e[0m" - ask_MicroTex=$ask -else ask_MicroTex=true + ask_MicroTeX=$ask +else ask_MicroTeX=true fi -if $ask_MicroTex;then showfun install-MicroTex;v install-MicroTex;fi +if $ask_MicroTeX;then showfun install-MicroTeX;v install-MicroTeX;fi ##################################################################################### printf "\e[36m[$0]: 3. Copying\e[97m\n" diff --git a/scriptdata/installers b/scriptdata/installers index aad02b94f..8d2fe7bab 100644 --- a/scriptdata/installers +++ b/scriptdata/installers @@ -87,9 +87,9 @@ install-bibata (){ x cd $base } -install-MicroTex (){ - x mkdir -p $base/cache/MicroTex - x cd $base/cache/MicroTex +install-MicroTeX (){ + x mkdir -p $base/cache/MicroTeX + x cd $base/cache/MicroTeX try git init -b master try git remote add origin https://github.com/NanoMichael/MicroTeX.git x git pull origin master && git submodule update --init --recursive From b5dabc2fee79fe008d698b9f0e4496b3c189f7a3 Mon Sep 17 00:00:00 2001 From: clsty Date: Tue, 27 Feb 2024 11:50:05 +0800 Subject: [PATCH 016/517] replace jq with gojq --- .config/ags/scripts/grimblast.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.config/ags/scripts/grimblast.sh b/.config/ags/scripts/grimblast.sh index b7a4775a8..db8bb5069 100755 --- a/.config/ags/scripts/grimblast.sh +++ b/.config/ags/scripts/grimblast.sh @@ -17,7 +17,7 @@ ## This tool is based on grimshot, with swaymsg commands replaced by their ## hyprctl equivalents. ## https://github.com/swaywm/sway/blob/master/contrib/grimshot - +jq=gojq getTargetDirectory() { test -f "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs" && . "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs" @@ -191,14 +191,14 @@ if [ "$ACTION" = "check" ]; then check hyprctl check hyprpicker check wl-copy - check jq + check $jq check notify-send exit elif [ "$SUBJECT" = "active" ]; then wait FOCUSED=$(hyprctl activewindow -j) - GEOM=$(echo "$FOCUSED" | jq -r '"\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"') - APP_ID=$(echo "$FOCUSED" | jq -r '.class') + GEOM=$(echo "$FOCUSED" | $jq -r '"\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"') + APP_ID=$(echo "$FOCUSED" | $jq -r '.class') WHAT="$APP_ID window" elif [ "$SUBJECT" = "screen" ]; then wait @@ -207,7 +207,7 @@ elif [ "$SUBJECT" = "screen" ]; then elif [ "$SUBJECT" = "output" ]; then wait GEOM="" - OUTPUT=$(hyprctl monitors -j | jq -r '.[] | select(.focused == true)' | jq -r '.name') + OUTPUT=$(hyprctl monitors -j | $jq -r '.[] | select(.focused == true)' | $jq -r '.name') WHAT="$OUTPUT" elif [ "$SUBJECT" = "area" ]; then if [ "$FREEZE" = "yes" ] && [ "$(command -v "hyprpicker")" ] >/dev/null 2>&1; then @@ -218,15 +218,15 @@ elif [ "$SUBJECT" = "area" ]; then # get fade & fadeOut animation and unset it # this removes the black border seen around screenshots - FADE="$(hyprctl -j animations | jq -jr '.[0][] | select(.name == "fade") | .name, ",", (if .enabled == true then "1" else "0" end), ",", (.speed|floor), ",", .bezier')" - FADEOUT="$(hyprctl -j animations | jq -jr '.[0][] | select(.name == "fadeOut") | .name, ",", (if .enabled == true then "1" else "0" end), ",", (.speed|floor), ",", .bezier')" + FADE="$(hyprctl -j animations | $jq -jr '.[0][] | select(.name == "fade") | .name, ",", (if .enabled == true then "1" else "0" end), ",", (.speed|floor), ",", .bezier')" + FADEOUT="$(hyprctl -j animations | $jq -jr '.[0][] | select(.name == "fadeOut") | .name, ",", (if .enabled == true then "1" else "0" end), ",", (.speed|floor), ",", .bezier')" hyprctl keyword animation 'fade,0,1,default' >/dev/null hyprctl keyword animation 'fadeOut,0,1,default' >/dev/null - WORKSPACES="$(hyprctl monitors -j | jq -r 'map(.activeWorkspace.id)')" - WINDOWS="$(hyprctl clients -j | jq -r --argjson workspaces "$WORKSPACES" 'map(select([.workspace.id] | inside($workspaces)))')" + WORKSPACES="$(hyprctl monitors -j | $jq -r 'map(.activeWorkspace.id)')" + WINDOWS="$(hyprctl clients -j | $jq -r --argjson workspaces "$WORKSPACES" 'map(select([.workspace.id] | inside($workspaces)))')" # shellcheck disable=2086 # if we don't split, spaces mess up slurp - GEOM=$(echo "$WINDOWS" | jq -r '.[] | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"' | slurp $SLURP_ARGS) + GEOM=$(echo "$WINDOWS" | $jq -r '.[] | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"' | slurp $SLURP_ARGS) # Check if user exited slurp without selecting the area if [ -z "$GEOM" ]; then From f4401abac2c1653c5deb4d425a91e428f10ec754 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:27:47 +0700 Subject: [PATCH 017/517] ai: allow selecting chatgpt-compatible chatbot provider (#152) --- .../ags/assets/icons/ai-openai-symbolic.svg | 1 + .../ags/assets/icons/ai-oxygen-symbolic.svg | 54 ++++++ .config/ags/assets/icons/ai-zukijourney.png | Bin 0 -> 312911 bytes .config/ags/modules/.miscutils/md2pango.js | 2 +- .config/ags/modules/sideleft/apis/chatgpt.js | 161 ++++++++++++++---- .config/ags/modules/sideleft/apis/gemini.js | 61 +++---- .config/ags/modules/sideleft/apiwidgets.js | 6 +- .config/ags/scss/_lib_classes.scss | 2 +- .config/ags/scss/_sidebars.scss | 11 ++ .config/ags/services/gemini.js | 6 +- .config/ags/services/{chatgpt.js => gpt.js} | 89 +++++++--- 11 files changed, 295 insertions(+), 98 deletions(-) create mode 120000 .config/ags/assets/icons/ai-openai-symbolic.svg create mode 100644 .config/ags/assets/icons/ai-oxygen-symbolic.svg create mode 100644 .config/ags/assets/icons/ai-zukijourney.png rename .config/ags/services/{chatgpt.js => gpt.js} (75%) diff --git a/.config/ags/assets/icons/ai-openai-symbolic.svg b/.config/ags/assets/icons/ai-openai-symbolic.svg new file mode 120000 index 000000000..c9ee0b32f --- /dev/null +++ b/.config/ags/assets/icons/ai-openai-symbolic.svg @@ -0,0 +1 @@ +openai-symbolic.svg \ No newline at end of file diff --git a/.config/ags/assets/icons/ai-oxygen-symbolic.svg b/.config/ags/assets/icons/ai-oxygen-symbolic.svg new file mode 100644 index 000000000..5e1cc1937 --- /dev/null +++ b/.config/ags/assets/icons/ai-oxygen-symbolic.svg @@ -0,0 +1,54 @@ + + + + + + + + + + diff --git a/.config/ags/assets/icons/ai-zukijourney.png b/.config/ags/assets/icons/ai-zukijourney.png new file mode 100644 index 0000000000000000000000000000000000000000..917335e7284b2ffc8fc222c126016e23bbbc07ce GIT binary patch literal 312911 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[Ig=D> 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 z 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 z %PiUM7hXe-F%^gF$f_)^i$BAXNT)*$vBUv4a~f7)<=-*f%Jfrs^q<@lPLmoLb) zWy2LjOIBKj!=rESn2wZriEAZ!VL2WhySIDBZoo;4Pl;8S-XvsNoW(owNjp0Fz;HO8 zzqk6X+Y3ov@XL-1VP5ddj!#z%KlKxTDYd=DyM)J~JB7z`6i1w^s3`HeNA=L+QB@%H z0x^R34y`AZrynhCcc32z+O8$rdA4Rx_qN6M_Y5wP?;S6k1F5-wwL<2SGLtOVOPahS zI8VNkXJ?pPN$fDqN8S7}1dlT?bS+LKOz@~hL#Ydj_0V%LN9tumP>M1ol$1E{QTbzKt&$)a z1NB78x+-B9$)zF}(=kvL1-(ziv85#t?^+%zNAYgtXS;^iH!tz+K;46WagBfBDa$~# z0!VbGqp37u$mp;r<>`-+-CO(4OrjPQ(Fc+bT>ova zFC=-vuP9sy^MYS-`1RlS8=oDNKmPCk(d42b+ZHHVOfz|q22miX>4yVK7WCHQy~A2V z+y#8}Jlt(LZg=cd_cp#19fz~yb>(SlGv1dt*t0l3viAyP2wcyJ$d%Hi`tJPDwhmqj>Q6; zDN#jg&wl9WZAWMwJAb4z1Gx}v4oi-CN49&zmA&SmkNh3~(BFL_$P0c&<3gAh{EEkK z`?r4Ze31SJzvJIYdMn8nl0s-iQsk7=VeLok-ZQ)&A;96`$eVW`vHzr}-`-=~NTEt< zGa{8j<^o-pEJu7Jn!vk{-m+K<>eWkJj36}G zVnwq*GK>YS_dMM`4RLA}_hy=7-W~ST#ndvDQc?qXE^%f=6(!kKMJ_XBp3z9peO+>t z0^uzfI1D|7^?Y1N?7^dQ0XneCU!f#u5m2H)E6B7a%Oc0#OhTV-VA~xT#+LBVA&?xd zc6|SD{(%cYUhoZt3t?XH4TXQ>NB_`g97;y zK(8CT@HBae%STjIP~2>&j7NOWCP#x{r}{J9548W$AvI2_@==3{@#E7>ki~U`$K;!_4fy27tloXu0w2A)W*^b z5#KauET#e3b$Gy=k*;sSdsMFQW@O*BxG)Dt`$wmsex70WPu66V52Skfyj2-hKVXAr zD6Xi@4kr>T=lS5$vC2J>Y!W{gJUKNPUKIk?smah}2a@wQf-NJ3epW z;{DrqJY03SpPTM?b9JDJA2NJST@m=}E0;(LGZzwnud_y78Pel&S4DC~&w zj^^PbMiGd{qLN_fT2wB%-=Aic69Mjz-L%W7B>Q7WT^97CIg`}h8`eN(9U%nLFwYcK z#+S@3K3lQW8~S8;=RKYOIgUQ(uz!c_eg=TU;#afoDz0vSEwErQewiV^#Yc;ek=yPK z`{vsLFhbz~KaQAVN0bsJJ#|%n`YE5`LZBZf!c7h=5NTMie(yx?07fA0_fj?X;o|A*iD`_jRTXF@p<<*AZ{ zxtg3w@}O}7S1~Xc!$w86aly(TxfKs&DNvBeLO^9}LcTz^{|{mJvwWO?2d~1< z@bcJlT>X92<68h8QU$)l_8PYs*)4uGI=>>C2mE*h?>UBWChfXPo0f# z*URQyY1UP74w81>Q)D?sCJENz+#Ex;5FFYiuZk_LH+Z*Y6$C}tp*n}r3;g15WgInM zk$)F!G4NeZWA7Glqgez)SQJoqh~fjfRG@*a=}Er8&rV2>#Au#XnI}SbKFt4gC@HC{ z;&IkFjyUgs-sgY81s6=X5atCJ{59~q{^$Sv>xkq}eD^<>PHkDGCe>-_r;2nt4qSWB z;5;bk)N2~EC861dioNN{{hq5j$B2R|m3+s-qPrdX`UBFi;vlZkd&_|mTKKltl68E` zOMOKiB&q+1`+m#&OyHb9dl{XoOk*8|R_Cuh{rEfo@=sof@q!C3xZr{dF1X-=UmX0u X>l-)x)|NV700000NkvXXu0mjfBj_ds literal 0 HcmV?d00001 diff --git a/.config/ags/modules/.miscutils/md2pango.js b/.config/ags/modules/.miscutils/md2pango.js index 8f56e3aeb..1c868757b 100644 --- a/.config/ags/modules/.miscutils/md2pango.js +++ b/.config/ags/modules/.miscutils/md2pango.js @@ -84,6 +84,6 @@ console.log('uwu'); - Random instruction thing - To update arch lincox, run \`sudo pacman -Syu\` \`\`\`tex -\\frac{d}{dx} \\left( \\frac{x-438}{x^2+23x-7} \\right) = \\frac{-x^2 + 869}{(x^2+23x-7)^2} +\\frac{d}{dx} \\left( \\frac{x-438}{x^2+23x-7} \\right) = \\frac{-x^2 + 869}{(x^2+23x-7)^2} hmmmmmm \\frac{d}{dx} \\left( \\frac{x-438}{x^2+23x-7} \\right) = \\frac{-x^2 + 869}{(x^2+23x-7)^2} \`\`\` `; \ No newline at end of file diff --git a/.config/ags/modules/sideleft/apis/chatgpt.js b/.config/ags/modules/sideleft/apis/chatgpt.js index d85d5de65..6ea650ad4 100644 --- a/.config/ags/modules/sideleft/apis/chatgpt.js +++ b/.config/ags/modules/sideleft/apis/chatgpt.js @@ -4,12 +4,13 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; const { Box, Button, Icon, Label, Revealer, Scrollable } = Widget; -import ChatGPT from '../../../services/chatgpt.js'; +import ChatGPT from '../../../services/gpt.js'; import { setupCursorHover, setupCursorHoverInfo } from '../../.widgetutils/cursorhover.js'; import { SystemMessage, ChatMessage } from "./ai_chatmessage.js"; import { ConfigToggle, ConfigSegmentedSelection, ConfigGap } from '../../.commonwidgets/configwidgets.js'; import { markdownTest } from '../../.miscutils/md2pango.js'; import { MarginRevealer } from '../../.widgethacks/advancedrevealers.js'; +import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; Gtk.IconTheme.get_default().append_search_path(`${App.configDir}/assets/icons`); @@ -19,6 +20,94 @@ export const chatGPTTabIcon = Icon({ icon: `openai-symbolic`, }); +const ProviderSwitcher = () => { + const ProviderChoice = (id, provider) => { + const providerSelected = MaterialIcon('check', 'norm', { + setup: (self) => self.hook(ChatGPT, (self) => { + self.toggleClassName('invisible', ChatGPT.providerID !== id); + }, 'providerChanged') + }); + return Button({ + tooltipText: provider.description, + onClicked: () => { + ChatGPT.providerID = id; + providerList.revealChild = false; + indicatorChevron.label = 'expand_more'; + }, + child: Box({ + className: 'spacing-h-10 txt', + children: [ + Icon({ + icon: provider['logo_name'], + className: 'txt-large' + }), + Label({ + hexpand: true, + xalign: 0, + className: 'txt-small', + label: provider.name, + }), + providerSelected + ], + }), + setup: setupCursorHover, + }); + } + const indicatorChevron = MaterialIcon('expand_more', 'norm'); + const indicatorButton = Button({ + tooltipText: 'Select ChatGPT-compatible API provider', + child: Box({ + className: 'spacing-h-10 txt', + children: [ + MaterialIcon('cloud', 'norm'), + Label({ + hexpand: true, + xalign: 0, + className: 'txt-small', + label: ChatGPT.providerID, + setup: (self) => self.hook(ChatGPT, (self) => { + self.label = `${ChatGPT.providers[ChatGPT.providerID]['name']}`; + }, 'providerChanged') + }), + indicatorChevron, + ] + }), + onClicked: () => { + providerList.revealChild = !providerList.revealChild; + indicatorChevron.label = (providerList.revealChild ? 'expand_less' : 'expand_more'); + }, + setup: setupCursorHover, + }); + const providerList = Revealer({ + revealChild: false, + transition: 'slide_down', + transitionDuration: 180, + child: Box({ + vertical: true, className: 'spacing-v-5 sidebar-chat-providerswitcher-list', + children: [ + Box({ className: 'separator-line margin-top-5 margin-bottom-5' }), + Box({ + className: 'spacing-v-5', + vertical: true, + setup: (self) => self.hook(ChatGPT, (self) => { + self.children = Object.entries(ChatGPT.providers) + .map(([id, provider]) => ProviderChoice(id, provider)); + }, 'initialized'), + }) + ] + }) + }) + return Box({ + hpack: 'center', + vertical: true, + className: 'sidebar-chat-providerswitcher', + children: [ + indicatorButton, + providerList, + ] + }) +} + const ChatGPTInfo = () => { const openAiLogo = Icon({ hpack: 'center', @@ -34,7 +123,7 @@ const ChatGPTInfo = () => { className: 'txt txt-title-small sidebar-chat-welcome-txt', wrap: true, justify: Gtk.Justification.CENTER, - label: 'Assistant (ChatGPT 3.5)', + label: 'Assistant (GPTs)', }), Box({ className: 'spacing-h-5', @@ -134,11 +223,11 @@ export const OpenaiApiKeyInstructions = () => Box({ wrap: true, className: 'txt sidebar-chat-welcome-txt', justify: Gtk.Justification.CENTER, - label: 'An OpenAI API key is required\nYou can grab one here, then enter it below' + label: 'An API key is required\nYou can grab one here, then enter it below' }), setup: setupCursorHover, onClicked: () => { - Utils.execAsync(['bash', '-c', `xdg-open https://platform.openai.com/api-keys &`]); + Utils.execAsync(['bash', '-c', `xdg-open ${ChatGPT.getKeyUrl}`]); } }) })] @@ -180,34 +269,6 @@ const clearChat = () => { } } -export const chatGPTView = Scrollable({ - className: 'sidebar-chat-viewport', - vexpand: true, - child: Box({ - vertical: true, - children: [ - chatGPTWelcome, - chatContent, - ] - }), - setup: (scrolledWindow) => { - // Show scrollbar - scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); - const vScrollbar = scrolledWindow.get_vscrollbar(); - vScrollbar.get_style_context().add_class('sidebar-scrollbar'); - // Avoid click-to-scroll-widget-to-view behavior - Utils.timeout(1, () => { - const viewport = scrolledWindow.child; - viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined)); - }) - // Always scroll to bottom with new content - const adjustment = scrolledWindow.get_vadjustment(); - adjustment.connect("changed", () => { - adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size()); - }) - } -}); - const CommandButton = (command) => Button({ className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small', onClicked: () => sendMessage(command), @@ -267,4 +328,38 @@ export const sendMessage = (text) => { else { ChatGPT.send(text); } -} \ No newline at end of file +} + +export const chatGPTView = Box({ + vertical: true, + children: [ + ProviderSwitcher(), + Scrollable({ + className: 'sidebar-chat-viewport', + vexpand: true, + child: Box({ + vertical: true, + children: [ + chatGPTWelcome, + chatContent, + ] + }), + setup: (scrolledWindow) => { + // Show scrollbar + scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + const vScrollbar = scrolledWindow.get_vscrollbar(); + vScrollbar.get_style_context().add_class('sidebar-scrollbar'); + // Avoid click-to-scroll-widget-to-view behavior + Utils.timeout(1, () => { + const viewport = scrolledWindow.child; + viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined)); + }) + // Always scroll to bottom with new content + const adjustment = scrolledWindow.get_vadjustment(); + adjustment.connect("changed", () => { + adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size()); + }) + } + }) + ] +}); \ No newline at end of file diff --git a/.config/ags/modules/sideleft/apis/gemini.js b/.config/ags/modules/sideleft/apis/gemini.js index 1db6029cf..5d323ef15 100644 --- a/.config/ags/modules/sideleft/apis/gemini.js +++ b/.config/ags/modules/sideleft/apis/gemini.js @@ -172,34 +172,6 @@ const clearChat = () => { } } -export const geminiView = Scrollable({ - className: 'sidebar-chat-viewport', - vexpand: true, - child: Box({ - vertical: true, - children: [ - geminiWelcome, - chatContent, - ] - }), - setup: (scrolledWindow) => { - // Show scrollbar - scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); - const vScrollbar = scrolledWindow.get_vscrollbar(); - vScrollbar.get_style_context().add_class('sidebar-scrollbar'); - // Avoid click-to-scroll-widget-to-view behavior - Utils.timeout(1, () => { - const viewport = scrolledWindow.child; - viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined)); - }) - // Always scroll to bottom with new content - const adjustment = scrolledWindow.get_vadjustment(); - adjustment.connect("changed", () => { - adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size()); - }) - } -}); - const CommandButton = (command) => Button({ className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small', onClicked: () => sendMessage(command), @@ -259,4 +231,35 @@ export const sendMessage = (text) => { else { Gemini.send(text); } -} \ No newline at end of file +} + +export const geminiView = Box({ + homogeneous: true, + children: [Scrollable({ + className: 'sidebar-chat-viewport', + vexpand: true, + child: Box({ + vertical: true, + children: [ + geminiWelcome, + chatContent, + ] + }), + setup: (scrolledWindow) => { + // Show scrollbar + scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + const vScrollbar = scrolledWindow.get_vscrollbar(); + vScrollbar.get_style_context().add_class('sidebar-scrollbar'); + // Avoid click-to-scroll-widget-to-view behavior + Utils.timeout(1, () => { + const viewport = scrolledWindow.child; + viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined)); + }) + // Always scroll to bottom with new content + const adjustment = scrolledWindow.get_vadjustment(); + adjustment.connect("changed", () => { + adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size()); + }) + } + })] +}); \ No newline at end of file diff --git a/.config/ags/modules/sideleft/apiwidgets.js b/.config/ags/modules/sideleft/apiwidgets.js index c141e32ca..9ae344a1c 100644 --- a/.config/ags/modules/sideleft/apiwidgets.js +++ b/.config/ags/modules/sideleft/apiwidgets.js @@ -6,7 +6,7 @@ const { execAsync, exec } = Utils; import { setupCursorHover, setupCursorHoverInfo } from '../.widgetutils/cursorhover.js'; import { contentStack } from './sideleft.js'; // APIs -import ChatGPT from '../../services/chatgpt.js'; +import ChatGPT from '../../services/gpt.js'; import Gemini from '../../services/gemini.js'; import { geminiView, geminiCommands, sendMessage as geminiSendMessage, geminiTabIcon } from './apis/gemini.js'; import { chatGPTView, chatGPTCommands, sendMessage as chatGPTSendMessage, chatGPTTabIcon } from './apis/chatgpt.js'; @@ -26,12 +26,12 @@ const APIS = [ placeholderText: 'Message Gemini...', }, { - name: 'Assistant (ChatGPT 3.5)', + name: 'Assistant (GPTs)', sendCommand: chatGPTSendMessage, contentWidget: chatGPTView, commandBar: chatGPTCommands, tabIcon: chatGPTTabIcon, - placeholderText: 'Message ChatGPT...', + placeholderText: 'Message the model...', }, { name: 'Waifus', diff --git a/.config/ags/scss/_lib_classes.scss b/.config/ags/scss/_lib_classes.scss index 6cd3f893b..988dee7a2 100644 --- a/.config/ags/scss/_lib_classes.scss +++ b/.config/ags/scss/_lib_classes.scss @@ -167,7 +167,7 @@ } .separator-line { - background-color: $outline; + background-color: mix($subtext, $surface, 50%); min-width: 0.068rem; min-height: 0.068rem; } diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss index 14103427b..1989c9cb8 100644 --- a/.config/ags/scss/_sidebars.scss +++ b/.config/ags/scss/_sidebars.scss @@ -557,6 +557,17 @@ $colorpicker_rounding: 0.341rem; color: $onSecondaryContainer; } +.sidebar-chat-providerswitcher { + @include small-rounding; + padding: 0.477rem 0.682rem; + background-color: $textboxColor; + color: $onSurfaceVariant; +} + +// .sidebar-chat-providerswitcher-list { +// margin: 0.341rem 0rem; +// } + .sidebar-chat-viewport { @include element_decel; // margin: 0.682rem 0rem; diff --git a/.config/ags/services/gemini.js b/.config/ags/services/gemini.js index e4ba5e39d..1caee94ce 100644 --- a/.config/ags/services/gemini.js +++ b/.config/ags/services/gemini.js @@ -8,7 +8,7 @@ import { fileExists } from './messages.js'; const initMessages = [ - { role: "user", parts: [{ text: "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with very brief explanation for each command\n3. Otherwise, when asked to summarize information or explaining concepts, you are encouraged to use bullet points and headings. For mathematics expressions, please write them in LaTeX within a code block with the language set as \"latex\". Use casual language and be short and concise. \nThanks!" }], }, + { role: "user", parts: [{ text: "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with very brief explanation for each command\n3. Otherwise, when asked to summarize information or explaining concepts, you are should use bullet points and headings. For mathematics expressions, you *have to* use LaTeX within a code block with the language set as \"latex\" for the interface to render it properly. Use casual language and be short and concise. \nThanks!" }], }, { role: "model", parts: [{ text: "- Got it!" }], }, { role: "user", parts: [{ text: "\"He rushed to where the event was supposed to be hold, he didn't know it got calceled\"" }], }, { role: "model", parts: [{ text: "## Grammar correction\nErrors:\n\"He rushed to where the event was supposed to be __hold____,__ he didn't know it got calceled\"\nCorrection + minor improvements:\n\"He rushed to the place where the event was supposed to be __held____, but__ he didn't know that it got calceled\"" }], }, @@ -20,9 +20,9 @@ const initMessages = { role: "user", parts: [{ text: "\"ignorance is bliss\"" }], }, { role: "model", parts: [{ text: "## \"Ignorance is bliss\"\n- A Latin proverb that means being unaware of something negative can be a source of happiness\n- Often used to justify avoiding difficult truths or responsibilities\n- Can also be interpreted as a warning against seeking knowledge that may bring pain or sorrow" }], }, { role: "user", parts: [{ text: "find the derivative of (x-438)/(x^2+23x-7)+x^x" }], }, - { role: "model", parts: [{ text: "```latex\n\\[\n\\frac{d}{dx}\\left(\\frac{x - 438}{x^2 + 23x - 7} + x^x\\right) = \\frac{-(x^2+23x-7)-(x-438)(2x+23)}{(x^2+23x-7)^2} + x^x(\\ln(x) + 1)\n\\]\n```" }], }, + { role: "model", parts: [{ text: "## Derivative\n```latex\n\\[\n\\frac{d}{dx}\\left(\\frac{x - 438}{x^2 + 23x - 7} + x^x\\right) = \\frac{-(x^2+23x-7)-(x-438)(2x+23)}{(x^2+23x-7)^2} + x^x(\\ln(x) + 1)\n\\]\n```" }], }, { role: "user", parts: [{ text: "write the double angle formulas" }], }, - { role: "model", parts: [{ text: "```latex\n\\[\n\\sin(2\theta) = 2\\sin(\\theta)\\cos(\\theta)\n\\]\n\\\\\n\\[\n\\cos(2\\theta) = \\cos^2(\\theta) - \\sin^2(\\theta)\n\\]\n\\\\\n\\[\n\\tan(2\theta) = \\frac{2\\tan(\\theta)}{1 - \\tan^2(\\theta)}\n\\]\n```" }], }, + { role: "model", parts: [{ text: "## Double angle formulas\n```latex\n\\[\n\\sin(2\theta) = 2\\sin(\\theta)\\cos(\\theta)\n\\]\n\\\\\n\\[\n\\cos(2\\theta) = \\cos^2(\\theta) - \\sin^2(\\theta)\n\\]\n\\\\\n\\[\n\\tan(2\theta) = \\frac{2\\tan(\\theta)}{1 - \\tan^2(\\theta)}\n\\]\n```" }], }, ]; function expandTilde(path) { diff --git a/.config/ags/services/chatgpt.js b/.config/ags/services/gpt.js similarity index 75% rename from .config/ags/services/chatgpt.js rename to .config/ags/services/gpt.js index b4264dd37..63a55e6c6 100644 --- a/.config/ags/services/chatgpt.js +++ b/.config/ags/services/gpt.js @@ -6,6 +6,41 @@ import GLib from 'gi://GLib'; import Soup from 'gi://Soup?version=3.0'; import { fileExists } from './messages.js'; +const PROVIDERS = { // There's this list hmm https://github.com/zukixa/cool-ai-stuff/ + 'openai': { + 'name': 'OpenAI', + 'logo_name': 'openai-symbolic', + 'description': 'Official OpenAI API.\nPricing: Free for the first $5 or 3 months, whichever is less.', + 'base_url': 'https://api.openai.com/v1/chat/completions', + 'key_get_url': 'https://platform.openai.com/api-keys', + 'key_file': 'openai_key.txt', + }, + 'oxygen': { + 'name': 'Oxygen', + 'logo_name': 'ai-oxygen-symbolic', + 'description': 'An API from Tornado Softwares\nPricing: Free: 100/day\nRequires you to join their Discord for a key', + 'base_url': 'https://app.oxyapi.uk/v1/chat/completions', + 'key_get_url': 'https://discord.com/invite/kM6MaCqGKA', + 'key_file': 'oxygen_key.txt', + }, + 'zukijourney': { + 'name': 'zukijourney', + 'logo_name': 'ai-zukijourney', + 'description': 'An API from @zukixa on GitHub.\nNote: Keys are IP-locked so it\'s buggy sometimes\nPricing: Free: 10/min, 800/day.\nRequires you to join their Discord for a key', + 'base_url': 'https://zukijourney.xyzbot.net/v1/chat/completions', + 'key_get_url': 'https://discord.com/invite/Y4J6XXnmQ6', + 'key_file': 'zuki_key.txt', + }, + 'zukijourney_roleplay': { + 'name': 'zukijourney (roleplay)', + 'logo_name': 'ai-zukijourney', + 'description': 'An API from @zukixa on GitHub.\nNote: Keys are IP-locked so it\'s buggy sometimes\nPricing: Free: 10/min, 800/day.\nRequires you to join their Discord for a key', + 'base_url': 'https://zukijourney.xyzbot.net/unf/chat/completions', + 'key_get_url': 'https://discord.com/invite/Y4J6XXnmQ6', + 'key_file': 'zuki_key.txt', + }, +} + // Custom prompt const initMessages = [ @@ -21,28 +56,9 @@ const initMessages = { role: "assistant", content: "## Skeuomorphism\n- A design philosophy- From early days of interface designing- Tries to imitate real-life objects- It's in fact still used by Apple in their icons until today.", }, ]; -function expandTilde(path) { - if (path.startsWith('~')) { - return GLib.get_home_dir() + path.slice(1); - } else { - return path; - } -} - // We're using many models to not be restricted to 3 messages per minute. // The whole chat will be sent every request anyway. Utils.exec(`mkdir -p ${GLib.get_user_cache_dir()}/ags/user/ai`); -const KEY_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/ai/openai_key.txt`; -const APIDOM_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/openai_api_dom.txt`; -function replaceapidom(URL) { - //Utils.writeFile(URL, "/tmp/openai-url-old.log"); // For debugging - if (fileExists(expandTilde(APIDOM_FILE_LOCATION))) { - var contents = Utils.readFile(expandTilde(APIDOM_FILE_LOCATION)).trim(); - var URL = URL.toString().replace("api.openai.com", contents); - } - //Utils.writeFile(URL, "/tmp/openai-url.log"); // For debugging - return URL; -} const CHAT_MODELS = ["gpt-3.5-turbo-1106", "gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-3.5-turbo-0613"] const ONE_CYCLE_COUNT = 3; @@ -113,25 +129,33 @@ class ChatGPTService extends Service { 'clear': [], 'newMsg': ['int'], 'hasKey': ['boolean'], + 'providerChanged': [], }); } _assistantPrompt = true; - _messages = []; - _cycleModels = true; + _currentProvider = 'openai'; + _cycleModels = false; _requestCount = 0; _temperature = 0.9; + _messages = []; _modelIndex = 0; _key = ''; + _key_file_location = `${GLib.get_user_cache_dir()}/ags/user/ai/${PROVIDERS[this._currentProvider]['key_file']}`; + _url = GLib.Uri.parse(PROVIDERS[this._currentProvider]['base_url'], GLib.UriFlags.NONE); + _decoder = new TextDecoder(); - url = GLib.Uri.parse(replaceapidom('https://api.openai.com/v1/chat/completions'), GLib.UriFlags.NONE); + _initChecks() { + this._key_file_location = `${GLib.get_user_cache_dir()}/ags/user/ai/${PROVIDERS[this._currentProvider]['key_file']}`; + if (fileExists(this._key_file_location)) this._key = Utils.readFile(this._key_file_location).trim(); + else this.emit('hasKey', false); + this._url = GLib.Uri.parse(PROVIDERS[this._currentProvider]['base_url'], GLib.UriFlags.NONE); + } constructor() { super(); - - if (fileExists(expandTilde(KEY_FILE_LOCATION))) this._key = Utils.readFile(expandTilde(KEY_FILE_LOCATION)).trim(); - else this.emit('hasKey', false); + this._initChecks(); if (this._assistantPrompt) this._messages = [...initMessages]; else this._messages = []; @@ -140,12 +164,20 @@ class ChatGPTService extends Service { } get modelName() { return CHAT_MODELS[this._modelIndex] } + get getKeyUrl() { return PROVIDERS[this._currentProvider]['key_get_url'] } + get providerID() { return this._currentProvider } + set providerID(value) { + this._currentProvider = value; + this.emit('providerChanged'); + this._initChecks(); + } + get providers() { return PROVIDERS } - get keyPath() { return KEY_FILE_LOCATION } + get keyPath() { return this._key_file_location } get key() { return this._key } set key(keyValue) { this._key = keyValue; - Utils.writeFile(this._key, expandTilde(KEY_FILE_LOCATION)) + Utils.writeFile(this._key, this._key_file_location) .then(this.emit('hasKey', true)) .catch(err => print(err)); } @@ -197,6 +229,7 @@ class ChatGPTService extends Service { return; } aiResponse.addDelta(result.choices[0].delta.content); + // print(result.choices[0]) } catch { aiResponse.addDelta(line + '\n'); @@ -229,7 +262,7 @@ class ChatGPTService extends Service { const session = new Soup.Session(); const message = new Soup.Message({ method: 'POST', - uri: this.url, + uri: this._url, }); message.request_headers.append('Authorization', `Bearer ${this._key}`); message.set_request_body_from_bytes('application/json', new GLib.Bytes(JSON.stringify(body))); From d028fd162bbe156daa4e7f72424ec167c926e4f8 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 27 Feb 2024 12:03:48 +0700 Subject: [PATCH 018/517] bar: custom module (#220) --- .config/ags/modules/bar/music.js | 94 +++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 33 deletions(-) diff --git a/.config/ags/modules/bar/music.js b/.config/ags/modules/bar/music.js index f0865b879..2f9c9cc4c 100644 --- a/.config/ags/modules/bar/music.js +++ b/.config/ags/modules/bar/music.js @@ -1,12 +1,17 @@ +const { GLib } = imports.gi; import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js'; -const { Box, Label, Overlay, Revealer } = Widget; +const { Box, Button, EventBox, Label, Overlay, Revealer, Scrollable } = Widget; const { execAsync, exec } = Utils; import { AnimatedCircProg } from "../.commonwidgets/cairo_circularprogress.js"; import { MaterialIcon } from '../.commonwidgets/materialicon.js'; import { showMusicControls } from '../../variables.js'; +const CUSTOM_MODULE_CONTENT_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-poll.sh`; +const CUSTOM_MODULE_LEFTCLICK_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-leftclick.sh`; +const CUSTOM_MODULE_RIGHTCLICK_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-rightclick.sh`; + function trimTrackTitle(title) { if (!title) return ''; const cleanPatterns = [ @@ -17,10 +22,10 @@ function trimTrackTitle(title) { return title; } -const BarGroup = ({ child }) => Widget.Box({ +const BarGroup = ({ child }) => Box({ className: 'bar-group-margin bar-sides', children: [ - Widget.Box({ + Box({ className: 'bar-group bar-group-standalone bar-group-pad-system', children: [child], }), @@ -34,7 +39,7 @@ const BarResource = (name, icon, command) => { hpack: 'center', }); const resourceProgress = Overlay({ - child: Widget.Box({ + child: Box({ vpack: 'center', className: 'bar-batt', homogeneous: true, @@ -93,14 +98,14 @@ const switchToRelativeWorkspace = async (self, num) => { export default () => { // TODO: use cairo to make button bounce smaller on click, if that's possible - const playingState = Widget.Box({ // Wrap a box cuz overlay can't have margins itself + const playingState = Box({ // Wrap a box cuz overlay can't have margins itself homogeneous: true, - children: [Widget.Overlay({ - child: Widget.Box({ + children: [Overlay({ + child: Box({ vpack: 'center', className: 'bar-music-playstate', homogeneous: true, - children: [Widget.Label({ + children: [Label({ vpack: 'center', className: 'bar-music-playstate-txt', justification: 'center', @@ -121,9 +126,9 @@ export default () => { ] })] }); - const trackTitle = Widget.Scrollable({ + const trackTitle = Scrollable({ hexpand: true, - child: Widget.Label({ + child: Label({ className: 'txt-smallie txt-onSurfaceVariant', setup: (self) => self.hook(Mpris, label => { const mpris = Mpris.getPlayer(''); @@ -142,30 +147,53 @@ export default () => { trackTitle, ] }) - const systemResources = BarGroup({ - child: Box({ - children: [ - BarResource('RAM Usage', 'memory', `LANG=C free | awk '/^Mem/ {printf("%.2f\\n", ($3/$2) * 100)}'`), - Revealer({ - revealChild: true, - transition: 'slide_left', - transitionDuration: 200, - child: Box({ - className: 'spacing-h-10 margin-left-10', - children: [ - BarResource('Swap Usage', 'swap_horiz', `LANG=C free | awk '/^Swap/ {if ($2 > 0) printf("%.2f\\n", ($3/$2) * 100); else print "0";}'`), - BarResource('CPU Usage', 'settings_motion_mode', `LANG=C top -bn1 | grep Cpu | sed 's/\\,/\\./g' | awk '{print $2}'`), - ] - }), - setup: (self) => self.hook(Mpris, label => { - const mpris = Mpris.getPlayer(''); - self.revealChild = (!mpris); + const SystemResourcesOrCustomModule = () => { + // Check if ~/.cache/ags/user/scripts/custom-module-poll.sh exists + if (GLib.file_test(CUSTOM_MODULE_CONTENT_SCRIPT, GLib.FileTest.EXISTS)) { + return BarGroup({ + child: Button({ + child: Label({ + className: 'txt-smallie txt-onSurfaceVariant', + useMarkup: true, + setup: (self) => Utils.timeout(1, () => { + self.label = exec(CUSTOM_MODULE_CONTENT_SCRIPT); + self.poll(5000, (self) => { + const content = exec(CUSTOM_MODULE_CONTENT_SCRIPT); + self.label = content; + }) + }) }), + onPrimaryClickRelease: () => execAsync(CUSTOM_MODULE_LEFTCLICK_SCRIPT).catch(print), + onSecondaryClickRelease: () => execAsync(CUSTOM_MODULE_RIGHTCLICK_SCRIPT).catch(print), }) - ], - }) - }); - return Widget.EventBox({ + }); + } else { + return BarGroup({ + child: Box({ + children: [ + BarResource('RAM Usage', 'memory', `LANG=C free | awk '/^Mem/ {printf("%.2f\\n", ($3/$2) * 100)}'`), + Revealer({ + revealChild: true, + transition: 'slide_left', + transitionDuration: 200, + child: Box({ + className: 'spacing-h-10 margin-left-10', + children: [ + BarResource('Swap Usage', 'swap_horiz', `LANG=C free | awk '/^Swap/ {if ($2 > 0) printf("%.2f\\n", ($3/$2) * 100); else print "0";}'`), + BarResource('CPU Usage', 'settings_motion_mode', `LANG=C top -bn1 | grep Cpu | sed 's/\\,/\\./g' | awk '{print $2}'`), + ] + }), + setup: (self) => self.hook(Mpris, label => { + const mpris = Mpris.getPlayer(''); + self.revealChild = (!mpris); + }), + }) + ], + }) + }); + } + } + return EventBox({ onScrollUp: (self) => switchToRelativeWorkspace(self, -1), onScrollDown: (self) => switchToRelativeWorkspace(self, +1), onPrimaryClickRelease: () => showMusicControls.setValue(!showMusicControls.value), @@ -175,7 +203,7 @@ export default () => { className: 'spacing-h-5', children: [ BarGroup({ child: musicStuff }), - systemResources, + SystemResourcesOrCustomModule(), ] }) }); From 4296b64cf5f56ba0931a3849cfeff32ca378fde7 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 27 Feb 2024 12:06:47 +0700 Subject: [PATCH 019/517] ai: ignore latex dir clear error --- .config/ags/modules/sideleft/apis/ai_chatmessage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/modules/sideleft/apis/ai_chatmessage.js b/.config/ags/modules/sideleft/apis/ai_chatmessage.js index 2b8864826..cf2498ac8 100644 --- a/.config/ags/modules/sideleft/apis/ai_chatmessage.js +++ b/.config/ags/modules/sideleft/apis/ai_chatmessage.js @@ -84,7 +84,7 @@ const TextBlock = (content = '') => Label({ Utils.execAsync(['bash', '-c', `rm ${LATEX_DIR}/*`]) .then(() => Utils.execAsync(['bash', '-c', `mkdir -p ${LATEX_DIR}`])) - .catch(print); + .catch(() => {}); const Latex = (content = '') => { const latexViewArea = Box({ // vscroll: 'never', From a2c77423d99424ce8dd8ef023665c66a2b77ce8b Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 27 Feb 2024 12:07:12 +0700 Subject: [PATCH 020/517] bar: custom module: add scroll (#220) --- .config/ags/modules/bar/music.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.config/ags/modules/bar/music.js b/.config/ags/modules/bar/music.js index 2f9c9cc4c..ebfa55115 100644 --- a/.config/ags/modules/bar/music.js +++ b/.config/ags/modules/bar/music.js @@ -11,6 +11,8 @@ import { showMusicControls } from '../../variables.js'; const CUSTOM_MODULE_CONTENT_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-poll.sh`; const CUSTOM_MODULE_LEFTCLICK_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-leftclick.sh`; const CUSTOM_MODULE_RIGHTCLICK_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-rightclick.sh`; +const CUSTOM_MODULE_SCROLLUP_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-scrollup.sh`; +const CUSTOM_MODULE_SCROLLDOWN_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-scrolldown.sh`; function trimTrackTitle(title) { if (!title) return ''; @@ -165,6 +167,8 @@ export default () => { }), onPrimaryClickRelease: () => execAsync(CUSTOM_MODULE_LEFTCLICK_SCRIPT).catch(print), onSecondaryClickRelease: () => execAsync(CUSTOM_MODULE_RIGHTCLICK_SCRIPT).catch(print), + onScrollUp: () => execAsync(CUSTOM_MODULE_SCROLLUP_SCRIPT).catch(print), + onScrollDown: () => execAsync(CUSTOM_MODULE_SCROLLDOWN_SCRIPT).catch(print), }) }); } else { From 5e2bc9ef3448f13698fc34b749e7cd4ebc51f7db Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 27 Feb 2024 12:09:02 +0700 Subject: [PATCH 021/517] and middle click (#220) --- .config/ags/modules/bar/music.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.config/ags/modules/bar/music.js b/.config/ags/modules/bar/music.js index ebfa55115..6df353c6d 100644 --- a/.config/ags/modules/bar/music.js +++ b/.config/ags/modules/bar/music.js @@ -11,6 +11,7 @@ import { showMusicControls } from '../../variables.js'; const CUSTOM_MODULE_CONTENT_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-poll.sh`; const CUSTOM_MODULE_LEFTCLICK_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-leftclick.sh`; const CUSTOM_MODULE_RIGHTCLICK_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-rightclick.sh`; +const CUSTOM_MODULE_MIDDLECLICK_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-middleclick.sh`; const CUSTOM_MODULE_SCROLLUP_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-scrollup.sh`; const CUSTOM_MODULE_SCROLLDOWN_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-scrolldown.sh`; @@ -167,6 +168,7 @@ export default () => { }), onPrimaryClickRelease: () => execAsync(CUSTOM_MODULE_LEFTCLICK_SCRIPT).catch(print), onSecondaryClickRelease: () => execAsync(CUSTOM_MODULE_RIGHTCLICK_SCRIPT).catch(print), + onMiddleClickRelease: () => execAsync(CUSTOM_MODULE_MIDDLECLICK_SCRIPT).catch(print), onScrollUp: () => execAsync(CUSTOM_MODULE_SCROLLUP_SCRIPT).catch(print), onScrollDown: () => execAsync(CUSTOM_MODULE_SCROLLDOWN_SCRIPT).catch(print), }) From 3de63a3d8678172ff9aa5d14e08ff19a4e95fcf3 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 27 Feb 2024 13:07:28 +0700 Subject: [PATCH 022/517] fix brightness keybind (closes #253) --- .config/hypr/hyprland/keybinds.conf | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.config/hypr/hyprland/keybinds.conf b/.config/hypr/hyprland/keybinds.conf index 3b49f83b6..d892c0224 100644 --- a/.config/hypr/hyprland/keybinds.conf +++ b/.config/hypr/hyprland/keybinds.conf @@ -6,10 +6,9 @@ bindle=, XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ bindle=, XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- # Brightness +# Uncomment these if you can't get AGS to work #bindle=, XF86MonBrightnessUp, exec, brightnessctl set '12.75+' #bindle=, XF86MonBrightnessDown, exec, brightnessctl set '12.75-' -bindle=, XF86MonBrightnessUp, exec, ags run-js 'brightness.screen_value += 0.05;' -bindle=, XF86MonBrightnessDown, exec, ags run-js 'brightness.screen_value -= 0.05;' #################################### Applications ################################### # Apps: just normal apps @@ -87,10 +86,10 @@ bind = Super, K, exec, ags -t 'osk' bind = Control+Alt, Delete, exec, ags -t 'session' bindle = , XF86AudioRaiseVolume, exec, ags run-js 'indicator.popup(1);' bindle = , XF86AudioLowerVolume, exec, ags run-js 'indicator.popup(1);' +bindle=, XF86MonBrightnessUp, exec, ags run-js 'brightness.screen_value += 0.05; indicator.popup(1);' +bindle=, XF86MonBrightnessDown, exec, ags run-js 'brightness.screen_value -= 0.05; indicator.popup(1);' bindl = , XF86AudioMute, exec, ags run-js 'indicator.popup(1);' bindl = Super+Shift,M, exec, ags run-js 'indicator.popup(1);' -bindle = , XF86MonBrightnessUp, exec, ags run-js 'indicator.popup(1);' -bindle = , XF86MonBrightnessDown, exec, ags run-js 'indicator.popup(1);' ###################################### Plugins ######################################### bind = Control+Super, P, exec, hyprctl plugin load "~/.config/hypr/plugins/droidbars.so" From fcb6cd4d395f135447c59dea1576012f3db93ca0 Mon Sep 17 00:00:00 2001 From: clsty Date: Tue, 27 Feb 2024 14:33:32 +0800 Subject: [PATCH 023/517] Fix make deps for microtex --- scriptdata/dependencies.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scriptdata/dependencies.conf b/scriptdata/dependencies.conf index 129dd260b..f6efe73e1 100644 --- a/scriptdata/dependencies.conf +++ b/scriptdata/dependencies.conf @@ -4,6 +4,9 @@ ### Basic coreutils cliphist curl fuzzel rsync wget ripgrep gojq npm meson typescript gjs dart-sass axel +# Make deps of MicroTeX +tinyxml2 gtkmm3 gtksourceviewmm cairomm + ### Python # Add `python-setuptools-scm` and `python-wheel` explicitly to fix #197 python-build python-material-color-utilities python-pillow python-poetry python-pywal python-setuptools-scm python-wheel From b943d365a79c9357460fd66c19eacdf94af9ab08 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 27 Feb 2024 14:59:06 +0700 Subject: [PATCH 024/517] bar: custom module: custom interval (#220) --- .config/ags/modules/bar/music.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.config/ags/modules/bar/music.js b/.config/ags/modules/bar/music.js index 6df353c6d..9dc4b013a 100644 --- a/.config/ags/modules/bar/music.js +++ b/.config/ags/modules/bar/music.js @@ -8,6 +8,7 @@ import { AnimatedCircProg } from "../.commonwidgets/cairo_circularprogress.js"; import { MaterialIcon } from '../.commonwidgets/materialicon.js'; import { showMusicControls } from '../../variables.js'; +const CUSTOM_MODULE_CONTENT_INTERVAL_FILE = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-interval.txt`; const CUSTOM_MODULE_CONTENT_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-poll.sh`; const CUSTOM_MODULE_LEFTCLICK_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-leftclick.sh`; const CUSTOM_MODULE_RIGHTCLICK_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-rightclick.sh`; @@ -153,6 +154,7 @@ export default () => { const SystemResourcesOrCustomModule = () => { // Check if ~/.cache/ags/user/scripts/custom-module-poll.sh exists if (GLib.file_test(CUSTOM_MODULE_CONTENT_SCRIPT, GLib.FileTest.EXISTS)) { + const interval = Number(Utils.readFile(CUSTOM_MODULE_CONTENT_INTERVAL_FILE)) || 5000; return BarGroup({ child: Button({ child: Label({ @@ -160,7 +162,7 @@ export default () => { useMarkup: true, setup: (self) => Utils.timeout(1, () => { self.label = exec(CUSTOM_MODULE_CONTENT_SCRIPT); - self.poll(5000, (self) => { + self.poll(interval, (self) => { const content = exec(CUSTOM_MODULE_CONTENT_SCRIPT); self.label = content; }) From 617ef905392196710db7bd57427cff724dccadc9 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 27 Feb 2024 17:48:12 +0700 Subject: [PATCH 025/517] deps: add cmake --- scriptdata/dependencies.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scriptdata/dependencies.conf b/scriptdata/dependencies.conf index f6efe73e1..7ffeed1cf 100644 --- a/scriptdata/dependencies.conf +++ b/scriptdata/dependencies.conf @@ -2,7 +2,7 @@ ### PKGs on same line will be send to `yay` together, unless `-f` is specified. ### Basic -coreutils cliphist curl fuzzel rsync wget ripgrep gojq npm meson typescript gjs dart-sass axel +coreutils cliphist cmake curl fuzzel rsync wget ripgrep gojq npm meson typescript gjs dart-sass axel # Make deps of MicroTeX tinyxml2 gtkmm3 gtksourceviewmm cairomm From 93ce991c8aa8618b3bba479862bfb85a626c19de Mon Sep 17 00:00:00 2001 From: clsty Date: Wed, 28 Feb 2024 10:36:16 +0800 Subject: [PATCH 026/517] Minor fix for inst script --- install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index eb9f62378..836c14f9d 100755 --- a/install.sh +++ b/install.sh @@ -139,8 +139,8 @@ if $ask_MicroTeX;then showfun install-MicroTeX;v install-MicroTeX;fi ##################################################################################### printf "\e[36m[$0]: 3. Copying\e[97m\n" -# In case ~/.local/bin does not exists -v mkdir -p "$HOME/.local/bin" "$HOME/.local/share" +# In case some folders does not exists +v mkdir -p "$HOME"/.{config,cache,local/{bin,share}} # `--delete' for rsync to make sure that # original dotfiles and new ones in the SAME DIRECTORY From 4fdb76242885a497fbab523d41c9535116470d9e Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 28 Feb 2024 23:05:29 +0700 Subject: [PATCH 027/517] add sidebars to noanim --- .config/hypr/hyprland/rules.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.config/hypr/hyprland/rules.conf b/.config/hypr/hyprland/rules.conf index f7c195c1a..996fa2fd1 100644 --- a/.config/hypr/hyprland/rules.conf +++ b/.config/hypr/hyprland/rules.conf @@ -22,6 +22,9 @@ layerrule = xray 1, .* layerrule = noanim, selection layerrule = noanim, overview layerrule = noanim, anyrun +layerrule = noanim, sideleft +layerrule = noanim, sideright +layerrule = noanim, osk layerrule = blur, eww layerrule = ignorealpha 0.8, eww From e1ce65379a840831df89c752492193475a0228c4 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 29 Feb 2024 12:15:55 +0700 Subject: [PATCH 028/517] readme: new preview --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2aeecbfe6..16c9af056 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ ### [illogical_impulse](https://github.com/end-4/dots-hyprland/tree/illogical-impulse) -![image](https://github.com/end-4/dots-hyprland/assets/97237370/abd05702-a248-4f53-ac82-500219aa19f1) +![image](https://github.com/end-4/dots-hyprland/assets/97237370/90c13b64-cde3-4363-9716-718d35845d95) ![image](https://github.com/end-4/dots-hyprland/assets/97237370/9e7adedd-fae8-4cc8-9c81-d7ad489d7559) ![image](https://github.com/end-4/dots-hyprland/assets/97237370/354431f6-8939-487f-9292-0bac71cf9ca8) ![image](https://github.com/end-4/dots-hyprland/assets/97237370/98fe2c03-a128-45c0-8155-3a6080db3b84) From 67be4f8f3bc1386935235d02d0124bab8810ac85 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 29 Feb 2024 16:40:44 +0700 Subject: [PATCH 029/517] hyprlock: add battery --- .../ags/scripts/templates/hypr/hyprlock.conf | 18 ++++++++++-- .config/hypr/hyprlock.conf | 28 +++++++++++++------ .config/hypr/hyprlock/status.sh | 22 +++++++++++++++ 3 files changed, 57 insertions(+), 11 deletions(-) create mode 100755 .config/hypr/hyprlock/status.sh diff --git a/.config/ags/scripts/templates/hypr/hyprlock.conf b/.config/ags/scripts/templates/hypr/hyprlock.conf index 3ad0f0d6f..5a42af563 100644 --- a/.config/ags/scripts/templates/hypr/hyprlock.conf +++ b/.config/ags/scripts/templates/hypr/hyprlock.conf @@ -40,7 +40,7 @@ label { # Clock halign = center valign = center } -label { +label { # Greeting monitor = text = hi $USER !!! color = $text_color @@ -51,7 +51,7 @@ label { halign = center valign = center } -label { +label { # lock icon monitor = text = lock color = $text_color @@ -62,7 +62,7 @@ label { halign = center valign = bottom } -label { +label { # "locked" text monitor = text = locked color = $text_color @@ -72,4 +72,16 @@ label { position = 0, 50 halign = center valign = bottom +} + +label { # Status + monitor = + text = cmd[update:5000] ~/.config/hypr/hyprlock/status.sh + color = $text_color + font_size = 14 + font_family = $font_family + + position = 30, -30 + halign = left + valign = top } \ No newline at end of file diff --git a/.config/hypr/hyprlock.conf b/.config/hypr/hyprlock.conf index f2299434d..71d9034be 100644 --- a/.config/hypr/hyprlock.conf +++ b/.config/hypr/hyprlock.conf @@ -1,13 +1,13 @@ -$text_color = rgba(eae0e4FF) -$entry_background_color = rgba(120F1111) -$entry_border_color = rgba(9a8d9555) -$entry_color = rgba(d1c2cbFF) +$text_color = rgba(ede0deFF) +$entry_background_color = rgba(130F0F11) +$entry_border_color = rgba(a08c8955) +$entry_color = rgba(d8c2bfFF) $font_family = Gabarito $font_family_clock = Gabarito $font_material_symbols = Material Symbols Rounded background { - color = rgba(120F1177) + color = rgba(130F0F77) # path = {{ SWWW_WALL }} path = screenshot blur_size = 5 @@ -40,7 +40,7 @@ label { # Clock halign = center valign = center } -label { +label { # Greeting monitor = text = hi $USER !!! color = $text_color @@ -51,7 +51,7 @@ label { halign = center valign = center } -label { +label { # lock icon monitor = text = lock color = $text_color @@ -62,7 +62,7 @@ label { halign = center valign = bottom } -label { +label { # "locked" text monitor = text = locked color = $text_color @@ -72,4 +72,16 @@ label { position = 0, 50 halign = center valign = bottom +} + +label { # Status + monitor = + text = cmd[update:5000] ~/.config/hypr/hyprlock/status.sh + color = $text_color + font_size = 14 + font_family = $font_family + + position = 30, -30 + halign = left + valign = top } \ No newline at end of file diff --git a/.config/hypr/hyprlock/status.sh b/.config/hypr/hyprlock/status.sh new file mode 100755 index 000000000..794c468f4 --- /dev/null +++ b/.config/hypr/hyprlock/status.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +############ Variables ############ +enable_battery=false + +####### Check availability ######## +for battery in /sys/class/power_supply/*BAT*; do + if [[ -f "$battery/uevent" ]]; then + enable_battery=true + break + fi +done + +############# Output ############# +if [[ $enable_battery == true ]]; then + if [[ $(cat /sys/class/power_supply/*/status | head -1) == "Charging" ]]; then + echo -n "(+) " + fi + echo -n "$(cat /sys/class/power_supply/*/capacity | head -1)"% remaining +fi + +echo '' \ No newline at end of file From 461b4f5c6b33292437b5544794a4b00e4559f41d Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 29 Feb 2024 17:07:49 +0700 Subject: [PATCH 030/517] internal: rename chatgpt to gpt --- .../modules/sideleft/apis/ai_chatmessage.js | 11 +-- .config/ags/modules/sideleft/apis/chatgpt.js | 80 +++++++++---------- .config/ags/modules/sideleft/apis/gemini.js | 40 +++++----- .config/ags/modules/sideleft/apiwidgets.js | 8 +- 4 files changed, 66 insertions(+), 73 deletions(-) diff --git a/.config/ags/modules/sideleft/apis/ai_chatmessage.js b/.config/ags/modules/sideleft/apis/ai_chatmessage.js index cf2498ac8..1c79b3a1c 100644 --- a/.config/ags/modules/sideleft/apis/ai_chatmessage.js +++ b/.config/ags/modules/sideleft/apis/ai_chatmessage.js @@ -12,7 +12,7 @@ const LATEX_DIR = `${GLib.get_user_cache_dir()}/ags/media/latex`; const CUSTOM_SOURCEVIEW_SCHEME_PATH = `${App.configDir}/assets/themes/sourceviewtheme.xml`; const CUSTOM_SCHEME_ID = 'custom'; const USERNAME = GLib.get_user_name(); -const CHATGPT_CURSOR = ' ...'; +const AI_MESSAGE_CURSOR = ' ...'; /////////////////////// Custom source view colorscheme ///////////////////////// @@ -34,13 +34,6 @@ loadCustomColorScheme(CUSTOM_SOURCEVIEW_SCHEME_PATH); ////////////////////////////////////////////////////////////////////////////// -function copyToClipboard(text) { - const clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD); - const textVariant = new GLib.Variant('s', text); - clipboard.set_text(textVariant, -1); - clipboard.store(); -} - function substituteLang(str) { const subs = [ { from: 'javascript', to: 'js' }, @@ -265,7 +258,7 @@ const MessageContent = (content) => { const lastLabel = kids[kids.length - 1]; let blockContent = lines.slice(lastProcessed, lines.length).join('\n'); if (!inCode) - lastLabel.label = `${md2pango(blockContent)}${useCursor ? CHATGPT_CURSOR : ''}`; + lastLabel.label = `${md2pango(blockContent)}${useCursor ? AI_MESSAGE_CURSOR : ''}`; else lastLabel.attribute.updateText(blockContent); } diff --git a/.config/ags/modules/sideleft/apis/chatgpt.js b/.config/ags/modules/sideleft/apis/chatgpt.js index 6ea650ad4..c3e657aab 100644 --- a/.config/ags/modules/sideleft/apis/chatgpt.js +++ b/.config/ags/modules/sideleft/apis/chatgpt.js @@ -4,7 +4,7 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; const { Box, Button, Icon, Label, Revealer, Scrollable } = Widget; -import ChatGPT from '../../../services/gpt.js'; +import GPTService from '../../../services/gpt.js'; import { setupCursorHover, setupCursorHoverInfo } from '../../.widgetutils/cursorhover.js'; import { SystemMessage, ChatMessage } from "./ai_chatmessage.js"; import { ConfigToggle, ConfigSegmentedSelection, ConfigGap } from '../../.commonwidgets/configwidgets.js'; @@ -23,14 +23,14 @@ export const chatGPTTabIcon = Icon({ const ProviderSwitcher = () => { const ProviderChoice = (id, provider) => { const providerSelected = MaterialIcon('check', 'norm', { - setup: (self) => self.hook(ChatGPT, (self) => { - self.toggleClassName('invisible', ChatGPT.providerID !== id); + setup: (self) => self.hook(GPTService, (self) => { + self.toggleClassName('invisible', GPTService.providerID !== id); }, 'providerChanged') }); return Button({ tooltipText: provider.description, onClicked: () => { - ChatGPT.providerID = id; + GPTService.providerID = id; providerList.revealChild = false; indicatorChevron.label = 'expand_more'; }, @@ -64,9 +64,9 @@ const ProviderSwitcher = () => { hexpand: true, xalign: 0, className: 'txt-small', - label: ChatGPT.providerID, - setup: (self) => self.hook(ChatGPT, (self) => { - self.label = `${ChatGPT.providers[ChatGPT.providerID]['name']}`; + label: GPTService.providerID, + setup: (self) => self.hook(GPTService, (self) => { + self.label = `${GPTService.providers[GPTService.providerID]['name']}`; }, 'providerChanged') }), indicatorChevron, @@ -89,8 +89,8 @@ const ProviderSwitcher = () => { Box({ className: 'spacing-v-5', vertical: true, - setup: (self) => self.hook(ChatGPT, (self) => { - self.children = Object.entries(ChatGPT.providers) + setup: (self) => self.hook(GPTService, (self) => { + self.children = Object.entries(GPTService.providers) .map(([id, provider]) => ProviderChoice(id, provider)); }, 'initialized'), }) @@ -108,7 +108,7 @@ const ProviderSwitcher = () => { }) } -const ChatGPTInfo = () => { +const GPTInfo = () => { const openAiLogo = Icon({ hpack: 'center', className: 'sidebar-chat-welcome-logo', @@ -147,14 +147,14 @@ const ChatGPTInfo = () => { }); } -export const ChatGPTSettings = () => MarginRevealer({ +const GPTSettings = () => MarginRevealer({ transition: 'slide_down', revealChild: true, extraSetup: (self) => self - .hook(ChatGPT, (self) => Utils.timeout(200, () => { + .hook(GPTService, (self) => Utils.timeout(200, () => { self.attribute.hide(); }), 'newMsg') - .hook(ChatGPT, (self) => Utils.timeout(200, () => { + .hook(GPTService, (self) => Utils.timeout(200, () => { self.attribute.show(); }), 'clear') , @@ -166,7 +166,7 @@ export const ChatGPTSettings = () => MarginRevealer({ hpack: 'center', icon: 'casino', name: 'Randomness', - desc: 'ChatGPT\'s temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1', + desc: 'The model\'s temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1', options: [ { value: 0.00, name: 'Precise', }, { value: 0.50, name: 'Balanced', }, @@ -174,7 +174,7 @@ export const ChatGPTSettings = () => MarginRevealer({ ], initIndex: 2, onChange: (value, name) => { - ChatGPT.temperature = value; + GPTService.temperature = value; }, }), ConfigGap({ vertical: true, size: 10 }), // Note: size can only be 5, 10, or 15 @@ -187,18 +187,18 @@ export const ChatGPTSettings = () => MarginRevealer({ icon: 'cycle', name: 'Cycle models', desc: 'Helps avoid exceeding the API rate of 3 messages per minute.\nTurn this on if you message rapidly.', - initValue: ChatGPT.cycleModels, + initValue: GPTService.cycleModels, onChange: (self, newValue) => { - ChatGPT.cycleModels = newValue; + GPTService.cycleModels = newValue; }, }), ConfigToggle({ icon: 'model_training', name: 'Enhancements', - desc: 'Tells ChatGPT:\n- It\'s a Linux sidebar assistant\n- Be brief and use bullet points', - initValue: ChatGPT.assistantPrompt, + desc: 'Tells the model:\n- It\'s a Linux sidebar assistant\n- Be brief and use bullet points', + initValue: GPTService.assistantPrompt, onChange: (self, newValue) => { - ChatGPT.assistantPrompt = newValue; + GPTService.assistantPrompt = newValue; }, }), ] @@ -213,8 +213,8 @@ export const OpenaiApiKeyInstructions = () => Box({ transition: 'slide_down', transitionDuration: 150, setup: (self) => self - .hook(ChatGPT, (self, hasKey) => { - self.revealChild = (ChatGPT.key.length == 0); + .hook(GPTService, (self, hasKey) => { + self.revealChild = (GPTService.key.length == 0); }, 'hasKey') , child: Button({ @@ -227,13 +227,13 @@ export const OpenaiApiKeyInstructions = () => Box({ }), setup: setupCursorHover, onClicked: () => { - Utils.execAsync(['bash', '-c', `xdg-open ${ChatGPT.getKeyUrl}`]); + Utils.execAsync(['bash', '-c', `xdg-open ${GPTService.getKeyUrl}`]); } }) })] }); -const chatGPTWelcome = Box({ +const GPTWelcome = () => Box({ vexpand: true, homogeneous: true, child: Box({ @@ -241,9 +241,9 @@ const chatGPTWelcome = Box({ vpack: 'center', vertical: true, children: [ - ChatGPTInfo(), + GPTInfo(), OpenaiApiKeyInstructions(), - ChatGPTSettings(), + GPTSettings(), ] }) }); @@ -252,16 +252,16 @@ export const chatContent = Box({ className: 'spacing-v-15', vertical: true, setup: (self) => self - .hook(ChatGPT, (box, id) => { - const message = ChatGPT.messages[id]; + .hook(GPTService, (box, id) => { + const message = GPTService.messages[id]; if (!message) return; - box.add(ChatMessage(message, 'ChatGPT')) + box.add(ChatMessage(message, `Model (${GPTService.providers[GPTService.providerID]['name']})`)) }, 'newMsg') , }); const clearChat = () => { - ChatGPT.clear(); + GPTService.clear(); const children = chatContent.get_children(); for (let i = 0; i < children.length; i++) { const child = children[i]; @@ -289,16 +289,16 @@ export const chatGPTCommands = Box({ export const sendMessage = (text) => { // Check if text or API key is empty if (text.length == 0) return; - if (ChatGPT.key.length == 0) { - ChatGPT.key = text; - chatContent.add(SystemMessage(`Key saved to\n\`${ChatGPT.keyPath}\``, 'API Key', chatGPTView)); + if (GPTService.key.length == 0) { + GPTService.key = text; + chatContent.add(SystemMessage(`Key saved to\n\`${GPTService.keyPath}\``, 'API Key', chatGPTView)); text = ''; return; } // Commands if (text.startsWith('/')) { if (text.startsWith('/clear')) clearChat(); - else if (text.startsWith('/model')) chatContent.add(SystemMessage(`Currently using \`${ChatGPT.modelName}\``, '/model', chatGPTView)) + else if (text.startsWith('/model')) chatContent.add(SystemMessage(`Currently using \`${GPTService.modelName}\``, '/model', chatGPTView)) else if (text.startsWith('/prompt')) { const firstSpaceIndex = text.indexOf(' '); const prompt = text.slice(firstSpaceIndex + 1); @@ -306,18 +306,18 @@ export const sendMessage = (text) => { chatContent.add(SystemMessage(`Usage: \`/prompt MESSAGE\``, '/prompt', chatGPTView)) } else { - ChatGPT.addMessage('user', prompt) + GPTService.addMessage('user', prompt) } } else if (text.startsWith('/key')) { const parts = text.split(' '); if (parts.length == 1) chatContent.add(SystemMessage( - `Key stored in:\n\`${ChatGPT.keyPath}\`\nTo update this key, type \`/key YOUR_API_KEY\``, + `Key stored in:\n\`${GPTService.keyPath}\`\nTo update this key, type \`/key YOUR_API_KEY\``, '/key', chatGPTView)); else { - ChatGPT.key = parts[1]; - chatContent.add(SystemMessage(`Updated API Key at\n\`${ChatGPT.keyPath}\``, '/key', chatGPTView)); + GPTService.key = parts[1]; + chatContent.add(SystemMessage(`Updated API Key at\n\`${GPTService.keyPath}\``, '/key', chatGPTView)); } } else if (text.startsWith('/test')) @@ -326,7 +326,7 @@ export const sendMessage = (text) => { chatContent.add(SystemMessage(`Invalid command.`, 'Error', chatGPTView)) } else { - ChatGPT.send(text); + GPTService.send(text); } } @@ -340,7 +340,7 @@ export const chatGPTView = Box({ child: Box({ vertical: true, children: [ - chatGPTWelcome, + GPTWelcome(), chatContent, ] }), diff --git a/.config/ags/modules/sideleft/apis/gemini.js b/.config/ags/modules/sideleft/apis/gemini.js index 5d323ef15..7da16e435 100644 --- a/.config/ags/modules/sideleft/apis/gemini.js +++ b/.config/ags/modules/sideleft/apis/gemini.js @@ -4,7 +4,7 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; const { Box, Button, Icon, Label, Revealer, Scrollable } = Widget; -import Gemini from '../../../services/gemini.js'; +import GeminiService from '../../../services/gemini.js'; import { setupCursorHover, setupCursorHoverInfo } from '../../.widgetutils/cursorhover.js'; import { SystemMessage, ChatMessage } from "./ai_chatmessage.js"; import { ConfigToggle, ConfigSegmentedSelection, ConfigGap } from '../../.commonwidgets/configwidgets.js'; @@ -63,10 +63,10 @@ export const GeminiSettings = () => MarginRevealer({ transition: 'slide_down', revealChild: true, extraSetup: (self) => self - .hook(Gemini, (self) => Utils.timeout(200, () => { + .hook(GeminiService, (self) => Utils.timeout(200, () => { self.attribute.hide(); }), 'newMsg') - .hook(Gemini, (self) => Utils.timeout(200, () => { + .hook(GeminiService, (self) => Utils.timeout(200, () => { self.attribute.show(); }), 'clear') , @@ -86,7 +86,7 @@ export const GeminiSettings = () => MarginRevealer({ ], initIndex: 2, onChange: (value, name) => { - Gemini.temperature = value; + GeminiService.temperature = value; }, }), ConfigGap({ vertical: true, size: 10 }), // Note: size can only be 5, 10, or 15 @@ -99,9 +99,9 @@ export const GeminiSettings = () => MarginRevealer({ icon: 'model_training', name: 'Enhancements', desc: 'Tells Gemini:\n- It\'s a Linux sidebar assistant\n- Be brief and use bullet points', - initValue: Gemini.assistantPrompt, + initValue: GeminiService.assistantPrompt, onChange: (self, newValue) => { - Gemini.assistantPrompt = newValue; + GeminiService.assistantPrompt = newValue; }, }), ] @@ -116,8 +116,8 @@ export const GoogleAiInstructions = () => Box({ transition: 'slide_down', transitionDuration: 150, setup: (self) => self - .hook(Gemini, (self, hasKey) => { - self.revealChild = (Gemini.key.length == 0); + .hook(GeminiService, (self, hasKey) => { + self.revealChild = (GeminiService.key.length == 0); }, 'hasKey') , child: Button({ @@ -155,8 +155,8 @@ export const chatContent = Box({ className: 'spacing-v-15', vertical: true, setup: (self) => self - .hook(Gemini, (box, id) => { - const message = Gemini.messages[id]; + .hook(GeminiService, (box, id) => { + const message = GeminiService.messages[id]; if (!message) return; box.add(ChatMessage(message, MODEL_NAME)) }, 'newMsg') @@ -164,7 +164,7 @@ export const chatContent = Box({ }); const clearChat = () => { - Gemini.clear(); + GeminiService.clear(); const children = chatContent.get_children(); for (let i = 0; i < children.length; i++) { const child = children[i]; @@ -192,16 +192,16 @@ export const geminiCommands = Box({ export const sendMessage = (text) => { // Check if text or API key is empty if (text.length == 0) return; - if (Gemini.key.length == 0) { - Gemini.key = text; - chatContent.add(SystemMessage(`Key saved to\n\`${Gemini.keyPath}\``, 'API Key', geminiView)); + if (GeminiService.key.length == 0) { + GeminiService.key = text; + chatContent.add(SystemMessage(`Key saved to\n\`${GeminiService.keyPath}\``, 'API Key', geminiView)); text = ''; return; } // Commands if (text.startsWith('/')) { if (text.startsWith('/clear')) clearChat(); - else if (text.startsWith('/model')) chatContent.add(SystemMessage(`Currently using \`${Gemini.modelName}\``, '/model', geminiView)) + else if (text.startsWith('/model')) chatContent.add(SystemMessage(`Currently using \`${GeminiService.modelName}\``, '/model', geminiView)) else if (text.startsWith('/prompt')) { const firstSpaceIndex = text.indexOf(' '); const prompt = text.slice(firstSpaceIndex + 1); @@ -209,18 +209,18 @@ export const sendMessage = (text) => { chatContent.add(SystemMessage(`Usage: \`/prompt MESSAGE\``, '/prompt', geminiView)) } else { - Gemini.addMessage('user', prompt) + GeminiService.addMessage('user', prompt) } } else if (text.startsWith('/key')) { const parts = text.split(' '); if (parts.length == 1) chatContent.add(SystemMessage( - `Key stored in:\n\`${Gemini.keyPath}\`\nTo update this key, type \`/key YOUR_API_KEY\``, + `Key stored in:\n\`${GeminiService.keyPath}\`\nTo update this key, type \`/key YOUR_API_KEY\``, '/key', geminiView)); else { - Gemini.key = parts[1]; - chatContent.add(SystemMessage(`Updated API Key at\n\`${Gemini.keyPath}\``, '/key', geminiView)); + GeminiService.key = parts[1]; + chatContent.add(SystemMessage(`Updated API Key at\n\`${GeminiService.keyPath}\``, '/key', geminiView)); } } else if (text.startsWith('/test')) @@ -229,7 +229,7 @@ export const sendMessage = (text) => { chatContent.add(SystemMessage(`Invalid command.`, 'Error', geminiView)) } else { - Gemini.send(text); + GeminiService.send(text); } } diff --git a/.config/ags/modules/sideleft/apiwidgets.js b/.config/ags/modules/sideleft/apiwidgets.js index 9ae344a1c..ac89b6a66 100644 --- a/.config/ags/modules/sideleft/apiwidgets.js +++ b/.config/ags/modules/sideleft/apiwidgets.js @@ -6,7 +6,7 @@ const { execAsync, exec } = Utils; import { setupCursorHover, setupCursorHoverInfo } from '../.widgetutils/cursorhover.js'; import { contentStack } from './sideleft.js'; // APIs -import ChatGPT from '../../services/gpt.js'; +import GPTService from '../../services/gpt.js'; import Gemini from '../../services/gemini.js'; import { geminiView, geminiCommands, sendMessage as geminiSendMessage, geminiTabIcon } from './apis/gemini.js'; import { chatGPTView, chatGPTCommands, sendMessage as chatGPTSendMessage, chatGPTTabIcon } from './apis/chatgpt.js'; @@ -65,9 +65,9 @@ export const chatEntry = TextView({ acceptsTab: false, className: 'sidebar-chat-entry txt txt-smallie', setup: (self) => self - .hook(ChatGPT, (self) => { - if (APIS[currentApiId].name != 'Assistant (ChatGPT 3.5)') return; - self.placeholderText = (ChatGPT.key.length > 0 ? 'Message ChatGPT...' : 'Enter OpenAI API Key...'); + .hook(GPTService, (self) => { + if (APIS[currentApiId].name != 'Assistant (GPTs)') return; + self.placeholderText = (GPTService.key.length > 0 ? 'Message the model...' : 'Enter API Key...'); }, 'hasKey') .hook(Gemini, (self) => { if (APIS[currentApiId].name != 'Assistant (Gemini Pro)') return; From db5b866c2a36a999654901085f86c0d442e8c33b Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Thu, 29 Feb 2024 18:42:54 +0530 Subject: [PATCH 031/517] Set terminal trsperancy to 100 (for end-4) and remove apply_foot --- .../scripts/color_generation/applycolor.sh | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/.config/ags/scripts/color_generation/applycolor.sh b/.config/ags/scripts/color_generation/applycolor.sh index a8304abe8..c99e6ff06 100755 --- a/.config/ags/scripts/color_generation/applycolor.sh +++ b/.config/ags/scripts/color_generation/applycolor.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -term_alpha=80 #Set this to < 100 make all your terminals transparent +term_alpha=100 #Set this to < 100 make all your terminals transparent # sleep 0 # idk i wanted some delay or colors dont get applied properly if [ ! -d "$HOME"/.cache/ags/user/generated ]; then mkdir -p "$HOME"/.cache/ags/user/generated @@ -87,23 +87,6 @@ apply_fuzzel() { cp "$HOME"/.cache/ags/user/generated/fuzzel/fuzzel.ini "$HOME"/.config/fuzzel/fuzzel.ini } -#apply_foot() { -# if [ ! -f "scripts/templates/foot/foot.ini" ]; then -# echo "Template file not found for Foot. Skipping that." -# return -# fi -# # Copy template -# mkdir -p "$HOME"/.cache/ags/user/generated/foot -# cp "scripts/templates/foot/foot.ini" "$HOME"/.cache/ags/user/generated/foot/foot.ini -# # Apply colors -# for i in "${!colorlist[@]}"; do -# # sed -i "s/${colorlist[$i]} #/${colorvalues[$i]#\#}/g" "$HOME"/.cache/ags/user/generated/foot/foot.ini -# sed -i "s/{{ ${colorlist[$i]} }}/${colorvalues[$i]#\#}/g" "$HOME"/.cache/ags/user/generated/foot/foot.ini -# done -# -# cp "$HOME"/.cache/ags/user/generated/foot/foot.ini "$HOME/.config/foot/foot.ini" -#} - apply_term() { # Check if terminal escape sequence template exists if [ ! -f "scripts/templates/terminal/sequences.txt" ]; then @@ -204,7 +187,6 @@ apply_ags & apply_hyprland & apply_hyprlock & apply_gtk & -# apply_foot & # apply_gtklock & apply_fuzzel & apply_term & From 1d27fda709c4462302d45f5410a0d203d91cf774 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Thu, 29 Feb 2024 18:58:42 +0530 Subject: [PATCH 032/517] Removed fish/sequences.txt --- .config/ags/scripts/color_generation/applycolor.sh | 9 ++------- .config/fish/config.fish | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/.config/ags/scripts/color_generation/applycolor.sh b/.config/ags/scripts/color_generation/applycolor.sh index c99e6ff06..f5aad6a0d 100755 --- a/.config/ags/scripts/color_generation/applycolor.sh +++ b/.config/ags/scripts/color_generation/applycolor.sh @@ -100,17 +100,12 @@ apply_term() { for i in "${!colorlist[@]}"; do sed -i "s/${colorlist[$i]} #/${colorvalues[$i]#\#}/g" "$HOME"/.cache/ags/user/generated/terminal/sequences.txt done - cp "$HOME"/.cache/ags/user/generated/terminal/sequences.txt "$HOME"/.config/fish/sequences.txt - if [$term_alpha == 100]; then - sed -i "s/\[\$alpha\]//g" "$HOME/.cache/ags/user/generated/terminal/sequences.txt" - else - sed -i "s/\$alpha/$term_alpha/g" "$HOME/.cache/ags/user/generated/terminal/sequences.txt" - fi + sed -i "s/\$alpha/$term_alpha/g" "$HOME/.cache/ags/user/generated/terminal/sequences.txt" for file in /dev/pts/*; do if [[ $file =~ ^/dev/pts/[0-9]+$ ]]; then - cat "$HOME"/.config/fish/sequences.txt > "$file" + cat "$HOME"/.cache/ags/user/generated/terminal/sequences.txt > "$file" fi done } diff --git a/.config/fish/config.fish b/.config/fish/config.fish index 5d3855340..2eab1b489 100755 --- a/.config/fish/config.fish +++ b/.config/fish/config.fish @@ -13,8 +13,8 @@ if status is-interactive end starship init fish | source -if test -f ~/.config/fish/sequences.txt - cat ~/.config/fish/sequences.txt +if test -f ~/.cache/ags/user/generated/terminal/sequences.txt + cat ~/.cache/ags/user/generated/terminal/sequences.txt end alias pamcan=pacman From 481387d4cdfa958b779ec7aa96d37e5211f18296 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Thu, 29 Feb 2024 19:06:09 +0530 Subject: [PATCH 033/517] Removed foot color generation template --- .config/ags/scripts/templates/foot/foot.ini | 133 -------------------- 1 file changed, 133 deletions(-) delete mode 100644 .config/ags/scripts/templates/foot/foot.ini diff --git a/.config/ags/scripts/templates/foot/foot.ini b/.config/ags/scripts/templates/foot/foot.ini deleted file mode 100644 index 045a3b174..000000000 --- a/.config/ags/scripts/templates/foot/foot.ini +++ /dev/null @@ -1,133 +0,0 @@ -shell=fish -term=xterm-256color - -title=foot - -font=SpaceMono Nerd Font:size=11 -letter-spacing=0 -# horizontal-letter-offset=0 -# vertical-letter-offset=0 -# underline-offset= -# box-drawings-uses-font-glyphs=no -dpi-aware=no - -# initial-window-size-pixels=700x500 # Or, -# initial-window-size-chars= -# initial-window-mode=windowed -pad=25x25 # optionally append 'center' -# resize-delay-ms=100 - -# notify=notify-send -a ${app-id} -i ${app-id} ${title} ${body} - -bold-text-in-bright=no -# word-delimiters=,│`|:"'()[]{}<> -# selection-target=primary -# workers= - -[scrollback] -lines=10000 - -[url] -# launch=xdg-open ${url} -# label-letters=sadfjklewcmpgh -# osc8-underline=url-mode -# protocols=http, https, ftp, ftps, file, gemini, gopher -# uri-characters=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.,~:;/?#@!$&%*+="' - -[cursor] -style=beam -color={{ $background }} {{ $onBackground }} -# blink=no -beam-thickness=1.5 -# underline-thickness= - - -[colors] -alpha=1 -background={{ $background }} -foreground={{ $onBackground }} -regular0={{ $background }} -regular1={{ $error }} -regular2={{ $inversePrimary }} -regular3={{ $onPrimaryContainer }} -regular4={{ $onPrimaryContainer }} -regular5={{ $onSecondaryContainer }} -regular6={{ $primary }} -regular7={{ $onSurfaceVariant }} -bright0={{ $background }} -bright1={{ $error }} -bright2={{ $inversePrimary }} -bright3={{ $onPrimaryContainer }} -bright4={{ $onPrimaryContainer }} -bright5={{ $onSecondaryContainer }} -bright6={{ $primary }} -bright7={{ $onSurfaceVariant }} - -[csd] -# preferred=server -# size=26 -# font= -# color= -# button-width=26 -# button-color= -# button-minimize-color= -# button-maximize-color= -# button-close-color= - -[key-bindings] -scrollback-up-page=Page_Up -# scrollback-up-half-page=none -# scrollback-up-line=none -scrollback-down-page=Page_Down -# scrollback-down-half-page=none -# scrollback-down-line=none -clipboard-copy=Control+c -clipboard-paste=Control+v -# primary-paste=Shift+Insert -search-start=Control+f -# font-increase=Control+plus Control+equal Control+KP_Add -# font-decrease=Control+minus Control+KP_Subtract -# font-reset=Control+0 Control+KP_0 -# spawn-terminal=Control+Shift+n -# minimize=none -# maximize=none -# fullscreen=none -# pipe-visible=[sh -c "xurls | fuzzel | xargs -r firefox"] none -# pipe-scrollback=[sh -c "xurls | fuzzel | xargs -r firefox"] none -# pipe-selected=[xargs -r firefox] none -# show-urls-launch=Control+Shift+u -# show-urls-copy=none - -[search-bindings] -cancel=Escape -find-prev=Shift+F3 -find-next=F3 Control+G -# commit=Return -# cursor-left=Left Control+b -# cursor-left-word=Control+Left Mod1+b -# cursor-right=Right Control+f -# cursor-right-word=Control+Right Mod1+f -# cursor-home=Home Control+a -# cursor-end=End Control+e -# delete-prev=BackSpace -# delete-prev-word=Control+BackSpace -# delete-next=Delete -# delete-next-word=Mod1+d Control+Delete -# extend-to-word-boundary=Control+w -# extend-to-next-whitespace=Control+Shift+w -# clipboard-paste=Control+v Control+y -# primary-paste=Shift+Insert - -[url-bindings] -# cancel=Control+g Control+c Control+d Escape -# toggle-url-visible=t - -[mouse-bindings] -# primary-paste=BTN_MIDDLE -# select-begin=BTN_LEFT -# select-begin-block=Control+BTN_LEFT -# select-extend=BTN_RIGHT -# select-extend-character-wise=Control+BTN_RIGHT -# select-word=BTN_LEFT-2 -# select-word-whitespace=Control+BTN_LEFT-2 -# select-row=BTN_LEFT-3 From 79fba3e1644784851bbd4b0a8fc9a60460aae5ca Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 29 Feb 2024 23:04:09 +0700 Subject: [PATCH 034/517] change order of center left section of bar; introduce focus mode --- .../modules/bar/focus/workspaces_hyprland.js | 196 ++++++++++++++++++ .../bar/{ => focus}/workspaces_sway.js | 2 +- .config/ags/modules/bar/main.js | 72 ++++++- .config/ags/modules/bar/{ => normal}/music.js | 33 +-- .../ags/modules/bar/{ => normal}/spaceleft.js | 4 +- .../modules/bar/{ => normal}/spaceright.js | 4 +- .../ags/modules/bar/{ => normal}/system.js | 6 +- .config/ags/modules/bar/{ => normal}/tray.js | 0 .../bar/{ => normal}/workspaces_hyprland.js | 0 .../ags/modules/bar/normal/workspaces_sway.js | 184 ++++++++++++++++ .config/ags/scss/_bar.scss | 42 +++- .config/ags/scss/_lib_mixins.scss | 2 +- .config/ags/services/gpt.js | 12 +- .config/ags/variables.js | 13 +- .config/hypr/hyprland/keybinds.conf | 1 + 15 files changed, 524 insertions(+), 47 deletions(-) create mode 100644 .config/ags/modules/bar/focus/workspaces_hyprland.js rename .config/ags/modules/bar/{ => focus}/workspaces_sway.js (99%) rename .config/ags/modules/bar/{ => normal}/music.js (93%) rename .config/ags/modules/bar/{ => normal}/spaceleft.js (95%) rename .config/ags/modules/bar/{ => normal}/spaceright.js (96%) rename .config/ags/modules/bar/{ => normal}/system.js (98%) rename .config/ags/modules/bar/{ => normal}/tray.js (100%) rename .config/ags/modules/bar/{ => normal}/workspaces_hyprland.js (100%) create mode 100644 .config/ags/modules/bar/normal/workspaces_sway.js diff --git a/.config/ags/modules/bar/focus/workspaces_hyprland.js b/.config/ags/modules/bar/focus/workspaces_hyprland.js new file mode 100644 index 000000000..b5477c725 --- /dev/null +++ b/.config/ags/modules/bar/focus/workspaces_hyprland.js @@ -0,0 +1,196 @@ +const { GLib, Gdk, Gtk } = imports.gi; +const Lang = imports.lang; +const Cairo = imports.cairo; +const Pango = imports.gi.Pango; +const PangoCairo = imports.gi.PangoCairo; +import App from 'resource:///com/github/Aylur/ags/app.js'; +import * as Utils from 'resource:///com/github/Aylur/ags/utils.js' +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; +const { Box, DrawingArea, EventBox } = Widget; +import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js'; + +const NUM_OF_WORKSPACES_SHOWN = 10; // Limit = 53 I think +const dummyWs = Box({ className: 'bar-ws-focus' }); // Not shown. Only for getting size props +const dummyActiveWs = Box({ className: 'bar-ws-focus bar-ws-focus-active' }); // Not shown. Only for getting size props +const dummyOccupiedWs = Box({ className: 'bar-ws-focus bar-ws-focus-occupied' }); // Not shown. Only for getting size props + +const WS_TAKEN_WIDTH_MULTIPLIER = 1.4; + +// Font size = workspace id +const WorkspaceContents = (count = 10) => { + return DrawingArea({ + className: 'menu-decel', + // css: `transition: 300ms cubic-bezier(0.1, 1, 0, 1);`, + attribute: { + immediateActiveWs: 0, + initialized: false, + workspaceMask: 0, + workspaceGroup: 0, + updateMask: (self) => { + const offset = Math.floor((Hyprland.active.workspace.id - 1) / count) * NUM_OF_WORKSPACES_SHOWN; + // if (self.attribute.initialized) return; // We only need this to run once + const workspaces = Hyprland.workspaces; + let workspaceMask = 0; + for (let i = 0; i < workspaces.length; i++) { + const ws = workspaces[i]; + if (ws.id <= offset || ws.id > offset + count) continue; // Out of range, ignore + if (workspaces[i].windows > 0) + workspaceMask |= (1 << (ws.id - offset)); + } + // console.log('Mask:', workspaceMask.toString(2)); + self.attribute.workspaceMask = workspaceMask; + // self.attribute.initialized = true; + self.queue_draw(); + }, + toggleMask: (self, occupied, name) => { + if (occupied) self.attribute.workspaceMask |= (1 << parseInt(name)); + else self.attribute.workspaceMask &= ~(1 << parseInt(name)); + self.queue_draw(); + }, + }, + setup: (area) => area + .hook(Hyprland.active.workspace, (self) => { + const newActiveWs = (Hyprland.active.workspace.id - 1) % count + 1; + self.setCss(`font-size: ${newActiveWs}px;`); + self.attribute.immediateActiveWs = newActiveWs; + const previousGroup = self.attribute.workspaceGroup; + const currentGroup = Math.floor((Hyprland.active.workspace.id - 1) / count); + if (currentGroup !== previousGroup) { + self.attribute.updateMask(self); + self.attribute.workspaceGroup = currentGroup; + } + }) + .hook(Hyprland, (self) => self.attribute.updateMask(self), 'notify::workspaces') + .on('draw', Lang.bind(area, (area, cr) => { + const offset = Math.floor((Hyprland.active.workspace.id - 1) / count) * NUM_OF_WORKSPACES_SHOWN; + + const allocation = area.get_allocation(); + const { width, height } = allocation; + + const workspaceStyleContext = dummyWs.get_style_context(); + const workspaceDiameter = workspaceStyleContext.get_property('min-width', Gtk.StateFlags.NORMAL); + const workspaceRadius = workspaceDiameter / 2; + const wsbg = workspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL); + + const occupiedWorkspaceStyleContext = dummyOccupiedWs.get_style_context(); + const occupiedbg = occupiedWorkspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL); + + const activeWorkspaceStyleContext = dummyActiveWs.get_style_context(); + const activeWorkspaceWidth = activeWorkspaceStyleContext.get_property('min-width', Gtk.StateFlags.NORMAL); + // const activeWorkspaceWidth = 100; + const activebg = activeWorkspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL); + + const widgetStyleContext = area.get_style_context(); + const activeWs = widgetStyleContext.get_property('font-size', Gtk.StateFlags.NORMAL); + const immediateActiveWs = area.attribute.immediateActiveWs; + + // Draw + area.set_size_request(workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER * (count - 1) + activeWorkspaceWidth, -1); + for (let i = 1; i <= count; i++) { + if (i == immediateActiveWs) continue; + if (area.attribute.workspaceMask & (1 << i)) + cr.setSourceRGBA(occupiedbg.red, occupiedbg.green, occupiedbg.blue, occupiedbg.alpha); + else + cr.setSourceRGBA(wsbg.red, wsbg.green, wsbg.blue, wsbg.alpha); + + const centerX = (i <= activeWs) ? + (-workspaceRadius + (workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER * i)) + : -workspaceRadius + workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER * (count - 1) + activeWorkspaceWidth - ((count - i) * workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER); + cr.arc(centerX, height / 2, workspaceRadius, 0, 2 * Math.PI); + cr.fill(); + // What if shrinking + if (i == immediateActiveWs - 1 && immediateActiveWs > activeWs) { // To right + const widthPercentage = 1 - (immediateActiveWs - activeWs); + const leftX = centerX; + const wsWidth = (activeWorkspaceWidth - (workspaceDiameter * 1.5)) * (1 - widthPercentage); + cr.rectangle(leftX, height / 2 - workspaceRadius, wsWidth, workspaceDiameter); + cr.fill(); + cr.arc(leftX + wsWidth, height / 2, workspaceRadius, 0, Math.PI * 2); + cr.fill(); + } + else if (i == immediateActiveWs + 1 && immediateActiveWs < activeWs) { // To left + const widthPercentage = activeWs - immediateActiveWs; + const rightX = centerX; + const wsWidth = (activeWorkspaceWidth - (workspaceDiameter * 1.5)) * widthPercentage; + const leftX = rightX - wsWidth; + cr.rectangle(leftX, height / 2 - workspaceRadius, wsWidth, workspaceDiameter); + cr.fill(); + cr.arc(rightX, height / 2, workspaceRadius, 0, Math.PI * 2); + cr.fill(); + } + } + + let widthPercentage, leftX, rightX, activeWsWidth; + cr.setSourceRGBA(activebg.red, activebg.green, activebg.blue, activebg.alpha); + if (immediateActiveWs > activeWs) { // To right + widthPercentage = immediateActiveWs - activeWs; + rightX = -workspaceRadius + workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER * (count - 1) + activeWorkspaceWidth - ((count - immediateActiveWs) * workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER); + activeWsWidth = (activeWorkspaceWidth - (workspaceDiameter * 1.5)) * (1 - widthPercentage); + leftX = rightX - activeWsWidth; + + cr.arc(leftX, height / 2, workspaceRadius, 0, Math.PI * 2); // Should be 0.5 * Math.PI, 1.5 * Math.PI in theory but it leaves a weird 1px gap + cr.fill(); + cr.rectangle(leftX, height / 2 - workspaceRadius, activeWsWidth, workspaceDiameter); + cr.fill(); + cr.arc(leftX + activeWsWidth, height / 2, workspaceRadius, 0, Math.PI * 2); + cr.fill(); + } + else { // To left + widthPercentage = 1 - (activeWs - immediateActiveWs); + leftX = -workspaceRadius + (workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER * immediateActiveWs); + activeWsWidth = (activeWorkspaceWidth - (workspaceDiameter * 1.5)) * widthPercentage + + cr.arc(leftX, height / 2, workspaceRadius, 0, Math.PI * 2); // Should be 0.5 * Math.PI, 1.5 * Math.PI in theory but it leaves a weird 1px gap + cr.fill(); + cr.rectangle(leftX, height / 2 - workspaceRadius, activeWsWidth, workspaceDiameter); + cr.fill(); + cr.arc(leftX + activeWsWidth, height / 2, workspaceRadius, 0, Math.PI * 2); + cr.fill(); + } + })) + , + }) +} + +export default () => EventBox({ + onScrollUp: () => Hyprland.messageAsync(`dispatch workspace -1`).catch(print), + onScrollDown: () => Hyprland.messageAsync(`dispatch workspace +1`).catch(print), + onMiddleClickRelease: () => App.toggleWindow('overview'), + onSecondaryClickRelease: () => App.toggleWindow('osk'), + attribute: { + clicked: false, + ws_group: 0, + }, + child: Box({ + homogeneous: true, + // className: 'bar-group-margin', + children: [Box({ + // className: 'bar-group bar-group-standalone bar-group-pad', + css: 'min-width: 2px;', + children: [WorkspaceContents(NUM_OF_WORKSPACES_SHOWN)], + })] + }), + setup: (self) => { + self.add_events(Gdk.EventMask.POINTER_MOTION_MASK); + self.on('motion-notify-event', (self, event) => { + if (!self.attribute.clicked) return; + const [_, cursorX, cursorY] = event.get_coords(); + const widgetWidth = self.get_allocation().width; + const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES_SHOWN / widgetWidth); + Utils.execAsync([`${App.configDir}/scripts/hyprland/workspace_action.sh`, 'workspace', `${wsId}`]) + .catch(print); + }) + self.on('button-press-event', (self, event) => { + if (!(event.get_button()[1] === 1)) return; // We're only interested in left-click here + self.attribute.clicked = true; + const [_, cursorX, cursorY] = event.get_coords(); + const widgetWidth = self.get_allocation().width; + // const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES_PER_GROUP / widgetWidth) + self.attribute.ws_group * NUM_OF_WORKSPACES_PER_GROUP; + // Hyprland.messageAsync(`dispatch workspace ${wsId}`).catch(print); + const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES_SHOWN / widgetWidth); + Utils.execAsync([`${App.configDir}/scripts/hyprland/workspace_action.sh`, 'workspace', `${wsId}`]) + .catch(print); + }) + self.on('button-release-event', (self) => self.attribute.clicked = false); + } +}) diff --git a/.config/ags/modules/bar/workspaces_sway.js b/.config/ags/modules/bar/focus/workspaces_sway.js similarity index 99% rename from .config/ags/modules/bar/workspaces_sway.js rename to .config/ags/modules/bar/focus/workspaces_sway.js index 53612eb93..632b4b563 100644 --- a/.config/ags/modules/bar/workspaces_sway.js +++ b/.config/ags/modules/bar/focus/workspaces_sway.js @@ -4,7 +4,7 @@ const Cairo = imports.cairo; const Pango = imports.gi.Pango; const PangoCairo = imports.gi.PangoCairo; import Widget from "resource:///com/github/Aylur/ags/widget.js"; -import Sway from "../../services/sway.js"; +import Sway from "../../../services/sway.js"; import * as Utils from "resource:///com/github/Aylur/ags/utils.js"; const { execAsync, exec } = Utils; const { Box, DrawingArea, EventBox } = Widget; diff --git a/.config/ags/modules/bar/main.js b/.config/ags/modules/bar/main.js index d3d51ff1a..7719919b6 100644 --- a/.config/ags/modules/bar/main.js +++ b/.config/ags/modules/bar/main.js @@ -1,19 +1,35 @@ const { Gtk } = imports.gi; import Widget from 'resource:///com/github/Aylur/ags/widget.js'; +import Battery from 'resource:///com/github/Aylur/ags/service/battery.js'; -import WindowTitle from "./spaceleft.js"; -import Indicators from "./spaceright.js"; -import Music from "./music.js"; -import System from "./system.js"; +import WindowTitle from "./normal/spaceleft.js"; +import Indicators from "./normal/spaceright.js"; +import Music from "./normal/music.js"; +import System from "./normal/system.js"; import { enableClickthrough } from "../.widgetutils/clickthrough.js"; import { RoundedCorner } from "../.commonwidgets/cairo_roundedcorner.js"; +import { currentShellMode } from '../../variables.js'; -const OptionalWorkspaces = async () => { +const BATTERY_LOW = 20; + +const NormalOptionalWorkspaces = async () => { try { - return (await import('./workspaces_hyprland.js')).default(); + return (await import('./normal/workspaces_hyprland.js')).default(); } catch { try { - return (await import('./workspaces_sway.js')).default(); + return (await import('./normal/workspaces_sway.js')).default(); + } catch { + return null; + } + } +}; + +const FocusOptionalWorkspaces = async () => { + try { + return (await import('./focus/workspaces_hyprland.js')).default(); + } catch { + try { + return (await import('./focus/workspaces_sway.js')).default(); } catch { return null; } @@ -25,7 +41,7 @@ export const Bar = async (monitor = 0) => { className: 'bar-sidemodule', children: children, }); - const barContent = Widget.CenterBox({ + const normalBarContent = Widget.CenterBox({ className: 'bar-bg', setup: (self) => { const styleContext = self.get_style_context(); @@ -39,20 +55,54 @@ export const Bar = async (monitor = 0) => { SideModule([Music()]), Widget.Box({ homogeneous: true, - children: [await OptionalWorkspaces()], + children: [await NormalOptionalWorkspaces()], }), SideModule([System()]), ] }), endWidget: Indicators(), }); + const focusedBarContent = Widget.CenterBox({ + className: 'bar-bg-focus', + startWidget: Widget.Box({}), + centerWidget: Widget.Box({ + className: 'spacing-h-4', + children: [ + SideModule([]), + Widget.Box({ + homogeneous: true, + children: [await FocusOptionalWorkspaces()], + }), + SideModule([]), + ] + }), + endWidget: Widget.Box({}), + setup: (self) => { + self.hook(Battery, (self) => { + if(!Battery.available) return; + print(Battery.percent) + self.toggleClassName('bar-bg-focus-batterylow', Battery.percent <= BATTERY_LOW); + }) + } + }); return Widget.Window({ monitor, name: `bar${monitor}`, anchor: ['top', 'left', 'right'], exclusivity: 'exclusive', visible: true, - child: barContent, + child: Widget.Stack({ + homogeneous: false, + transition: 'slide_up_down', + transitionDuration: 200, + children: { + 'normal': normalBarContent, + 'focus': focusedBarContent, + }, + setup: (self) => self.hook(currentShellMode, (self) => { + self.shown = currentShellMode.value; + }) + }), }); } @@ -73,4 +123,4 @@ export const BarCornerTopright = (id = '') => Widget.Window({ visible: true, child: RoundedCorner('topright', { className: 'corner', }), setup: enableClickthrough, -}); \ No newline at end of file +}); diff --git a/.config/ags/modules/bar/music.js b/.config/ags/modules/bar/normal/music.js similarity index 93% rename from .config/ags/modules/bar/music.js rename to .config/ags/modules/bar/normal/music.js index 9dc4b013a..0d96b6b11 100644 --- a/.config/ags/modules/bar/music.js +++ b/.config/ags/modules/bar/normal/music.js @@ -4,9 +4,9 @@ import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js'; const { Box, Button, EventBox, Label, Overlay, Revealer, Scrollable } = Widget; const { execAsync, exec } = Utils; -import { AnimatedCircProg } from "../.commonwidgets/cairo_circularprogress.js"; -import { MaterialIcon } from '../.commonwidgets/materialicon.js'; -import { showMusicControls } from '../../variables.js'; +import { AnimatedCircProg } from "../../.commonwidgets/cairo_circularprogress.js"; +import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; +import { showMusicControls } from '../../../variables.js'; const CUSTOM_MODULE_CONTENT_INTERVAL_FILE = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-interval.txt`; const CUSTOM_MODULE_CONTENT_SCRIPT = `${GLib.get_home_dir()}/.cache/ags/user/scripts/custom-module-poll.sh`; @@ -42,16 +42,19 @@ const BarResource = (name, icon, command) => { vpack: 'center', hpack: 'center', }); - const resourceProgress = Overlay({ - child: Box({ - vpack: 'center', - className: 'bar-batt', - homogeneous: true, - children: [ - MaterialIcon(icon, 'small'), - ], - }), - overlays: [resourceCircProg] + const resourceProgress = Box({ + homogeneous: true, + children: [Overlay({ + child: Box({ + vpack: 'center', + className: 'bar-batt', + homogeneous: true, + children: [ + MaterialIcon(icon, 'small'), + ], + }), + overlays: [resourceCircProg] + })] }); const resourceLabel = Label({ className: 'txt-smallie txt-onSurfaceVariant', @@ -59,8 +62,8 @@ const BarResource = (name, icon, command) => { const widget = Box({ className: 'spacing-h-4 txt-onSurfaceVariant', children: [ - resourceLabel, resourceProgress, + resourceLabel, ], setup: (self) => self .poll(5000, () => execAsync(['bash', '-c', command]) @@ -210,8 +213,8 @@ export default () => { child: Box({ className: 'spacing-h-5', children: [ - BarGroup({ child: musicStuff }), SystemResourcesOrCustomModule(), + BarGroup({ child: musicStuff }), ] }) }); diff --git a/.config/ags/modules/bar/spaceleft.js b/.config/ags/modules/bar/normal/spaceleft.js similarity index 95% rename from .config/ags/modules/bar/spaceleft.js rename to .config/ags/modules/bar/normal/spaceleft.js index 4f2b8540a..4f43189a3 100644 --- a/.config/ags/modules/bar/spaceleft.js +++ b/.config/ags/modules/bar/normal/spaceleft.js @@ -1,7 +1,7 @@ import App from 'resource:///com/github/Aylur/ags/app.js'; import Widget from 'resource:///com/github/Aylur/ags/widget.js'; -import Brightness from '../../services/brightness.js'; -import Indicator from '../../services/indicator.js'; +import Brightness from '../../../services/brightness.js'; +import Indicator from '../../../services/indicator.js'; const WindowTitle = async () => { try { diff --git a/.config/ags/modules/bar/spaceright.js b/.config/ags/modules/bar/normal/spaceright.js similarity index 96% rename from .config/ags/modules/bar/spaceright.js rename to .config/ags/modules/bar/normal/spaceright.js index ca0d6d4a3..257680821 100644 --- a/.config/ags/modules/bar/spaceright.js +++ b/.config/ags/modules/bar/normal/spaceright.js @@ -5,8 +5,8 @@ import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; import Audio from 'resource:///com/github/Aylur/ags/service/audio.js'; import SystemTray from 'resource:///com/github/Aylur/ags/service/systemtray.js'; const { execAsync } = Utils; -import Indicator from '../../services/indicator.js'; -import { StatusIcons } from '../.commonwidgets/statusicons.js'; +import Indicator from '../../../services/indicator.js'; +import { StatusIcons } from '../../.commonwidgets/statusicons.js'; import { Tray } from "./tray.js"; export default () => { diff --git a/.config/ags/modules/bar/system.js b/.config/ags/modules/bar/normal/system.js similarity index 98% rename from .config/ags/modules/bar/system.js rename to .config/ags/modules/bar/normal/system.js index 5efdc0fdc..63e5fdb3c 100644 --- a/.config/ags/modules/bar/system.js +++ b/.config/ags/modules/bar/normal/system.js @@ -5,9 +5,9 @@ const { Box, Label, Button, Overlay, Revealer, Scrollable, Stack, EventBox } = W const { exec, execAsync } = Utils; const { GLib } = imports.gi; import Battery from 'resource:///com/github/Aylur/ags/service/battery.js'; -import { MaterialIcon } from '../.commonwidgets/materialicon.js'; -import { AnimatedCircProg } from "../.commonwidgets/cairo_circularprogress.js"; -import { WWO_CODE, WEATHER_SYMBOL, NIGHT_WEATHER_SYMBOL } from '../.commondata/weather.js'; +import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; +import { AnimatedCircProg } from "../../.commonwidgets/cairo_circularprogress.js"; +import { WWO_CODE, WEATHER_SYMBOL, NIGHT_WEATHER_SYMBOL } from '../../.commondata/weather.js'; const BATTERY_LOW = 20; const WEATHER_CACHE_FOLDER = `${GLib.get_user_cache_dir()}/ags/weather`; diff --git a/.config/ags/modules/bar/tray.js b/.config/ags/modules/bar/normal/tray.js similarity index 100% rename from .config/ags/modules/bar/tray.js rename to .config/ags/modules/bar/normal/tray.js diff --git a/.config/ags/modules/bar/workspaces_hyprland.js b/.config/ags/modules/bar/normal/workspaces_hyprland.js similarity index 100% rename from .config/ags/modules/bar/workspaces_hyprland.js rename to .config/ags/modules/bar/normal/workspaces_hyprland.js diff --git a/.config/ags/modules/bar/normal/workspaces_sway.js b/.config/ags/modules/bar/normal/workspaces_sway.js new file mode 100644 index 000000000..632b4b563 --- /dev/null +++ b/.config/ags/modules/bar/normal/workspaces_sway.js @@ -0,0 +1,184 @@ +const { GLib, Gdk, Gtk } = imports.gi; +const Lang = imports.lang; +const Cairo = imports.cairo; +const Pango = imports.gi.Pango; +const PangoCairo = imports.gi.PangoCairo; +import Widget from "resource:///com/github/Aylur/ags/widget.js"; +import Sway from "../../../services/sway.js"; +import * as Utils from "resource:///com/github/Aylur/ags/utils.js"; +const { execAsync, exec } = Utils; +const { Box, DrawingArea, EventBox } = Widget; + +const NUM_OF_WORKSPACES = 10; +const dummyWs = Box({ className: 'bar-ws' }); // Not shown. Only for getting size props +const dummyActiveWs = Box({ className: 'bar-ws bar-ws-active' }); // Not shown. Only for getting size props +const dummyOccupiedWs = Box({ className: 'bar-ws bar-ws-occupied' }); // Not shown. Only for getting size props + +const switchToWorkspace = (arg) => Utils.execAsync(`swaymsg workspace ${arg}`).catch(print); +const switchToRelativeWorkspace = (self, num) => + execAsync([`${App.configDir}/scripts/sway/swayToRelativeWs.sh`, `${num}`]).catch(print); + +const WorkspaceContents = (count = 10) => { + return DrawingArea({ + css: `transition: 90ms cubic-bezier(0.1, 1, 0, 1);`, + attribute: { + initialized: false, + workspaceMask: 0, + updateMask: (self) => { + if (self.attribute.initialized) return; // We only need this to run once + const workspaces = Sway.workspaces; + let workspaceMask = 0; + // console.log('----------------') + for (let i = 0; i < workspaces.length; i++) { + const ws = workspaces[i]; + // console.log(ws.name, ',', ws.num); + if (!Number(ws.name)) return; + const id = Number(ws.name); + if (id <= 0) continue; // Ignore scratchpads + if (id > count) return; // Not rendered + if (workspaces[i].windows > 0) { + workspaceMask |= (1 << id); + } + } + self.attribute.workspaceMask = workspaceMask; + self.attribute.initialized = true; + }, + toggleMask: (self, occupied, name) => { + if (occupied) self.attribute.workspaceMask |= (1 << parseInt(name)); + else self.attribute.workspaceMask &= ~(1 << parseInt(name)); + }, + }, + setup: (area) => area + .hook(Sway.active.workspace, (area) => { + area.setCss(`font-size: ${Sway.active.workspace.name}px;`) + }) + .hook(Sway, (self) => self.attribute.updateMask(self), 'notify::workspaces') + // .hook(Hyprland, (self, name) => self.attribute.toggleMask(self, true, name), 'workspace-added') + // .hook(Hyprland, (self, name) => self.attribute.toggleMask(self, false, name), 'workspace-removed') + .on('draw', Lang.bind(area, (area, cr) => { + const allocation = area.get_allocation(); + const { width, height } = allocation; + + const workspaceStyleContext = dummyWs.get_style_context(); + const workspaceDiameter = workspaceStyleContext.get_property('min-width', Gtk.StateFlags.NORMAL); + const workspaceRadius = workspaceDiameter / 2; + const workspaceFontSize = workspaceStyleContext.get_property('font-size', Gtk.StateFlags.NORMAL) / 4 * 3; + const workspaceFontFamily = workspaceStyleContext.get_property('font-family', Gtk.StateFlags.NORMAL); + const wsbg = workspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL); + const wsfg = workspaceStyleContext.get_property('color', Gtk.StateFlags.NORMAL); + + const occupiedWorkspaceStyleContext = dummyOccupiedWs.get_style_context(); + const occupiedbg = occupiedWorkspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL); + const occupiedfg = occupiedWorkspaceStyleContext.get_property('color', Gtk.StateFlags.NORMAL); + + const activeWorkspaceStyleContext = dummyActiveWs.get_style_context(); + const activebg = activeWorkspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL); + const activefg = activeWorkspaceStyleContext.get_property('color', Gtk.StateFlags.NORMAL); + area.set_size_request(workspaceDiameter * count, -1); + const widgetStyleContext = area.get_style_context(); + const activeWs = widgetStyleContext.get_property('font-size', Gtk.StateFlags.NORMAL); + + const activeWsCenterX = -(workspaceDiameter / 2) + (workspaceDiameter * activeWs); + const activeWsCenterY = height / 2; + + // Font + const layout = PangoCairo.create_layout(cr); + const fontDesc = Pango.font_description_from_string(`${workspaceFontFamily[0]} ${workspaceFontSize}`); + layout.set_font_description(fontDesc); + cr.setAntialias(Cairo.Antialias.BEST); + // Get kinda min radius for number indicators + layout.set_text("0".repeat(count.toString().length), -1); + const [layoutWidth, layoutHeight] = layout.get_pixel_size(); + const indicatorRadius = Math.max(layoutWidth, layoutHeight) / 2 * 1.2; // a bit smaller than sqrt(2)*radius + const indicatorGap = workspaceRadius - indicatorRadius; + + // Draw workspace numbers + for (let i = 1; i <= count; i++) { + if (area.attribute.workspaceMask & (1 << i)) { + // Draw bg highlight + cr.setSourceRGBA(occupiedbg.red, occupiedbg.green, occupiedbg.blue, occupiedbg.alpha); + const wsCenterX = -(workspaceRadius) + (workspaceDiameter * i); + const wsCenterY = height / 2; + if (!(area.attribute.workspaceMask & (1 << (i - 1)))) { // Left + cr.arc(wsCenterX, wsCenterY, workspaceRadius, 0.5 * Math.PI, 1.5 * Math.PI); + cr.fill(); + } + else { + cr.rectangle(wsCenterX - workspaceRadius, wsCenterY - workspaceRadius, workspaceRadius, workspaceRadius * 2) + cr.fill(); + } + if (!(area.attribute.workspaceMask & (1 << (i + 1)))) { // Right + cr.arc(wsCenterX, wsCenterY, workspaceRadius, -0.5 * Math.PI, 0.5 * Math.PI); + cr.fill(); + } + else { + cr.rectangle(wsCenterX, wsCenterY - workspaceRadius, workspaceRadius, workspaceRadius * 2) + cr.fill(); + } + + // Set color for text + cr.setSourceRGBA(occupiedfg.red, occupiedfg.green, occupiedfg.blue, occupiedfg.alpha); + } + else + cr.setSourceRGBA(wsfg.red, wsfg.green, wsfg.blue, wsfg.alpha); + layout.set_text(`${i}`, -1); + const [layoutWidth, layoutHeight] = layout.get_pixel_size(); + const x = -workspaceRadius + (workspaceDiameter * i) - (layoutWidth / 2); + const y = (height - layoutHeight) / 2; + cr.moveTo(x, y); + // cr.showText(text); + PangoCairo.show_layout(cr, layout); + cr.stroke(); + } + + // Draw active ws + // base + cr.setSourceRGBA(activebg.red, activebg.green, activebg.blue, activebg.alpha); + cr.arc(activeWsCenterX, activeWsCenterY, indicatorRadius, 0, 2 * Math.PI); + cr.fill(); + // inner decor + cr.setSourceRGBA(activefg.red, activefg.green, activefg.blue, activefg.alpha); + cr.arc(activeWsCenterX, activeWsCenterY, indicatorRadius * 0.2, 0, 2 * Math.PI); + cr.fill(); + })) + , + }) +} + +export default () => EventBox({ + onScrollUp: (self) => switchToRelativeWorkspace(self, -1), + onScrollDown: (self) => switchToRelativeWorkspace(self, +1), + onMiddleClickRelease: () => App.toggleWindow('overview'), + onSecondaryClickRelease: () => App.toggleWindow('osk'), + attribute: { clicked: false }, + child: Box({ + homogeneous: true, + className: 'bar-group-margin', + children: [Box({ + className: 'bar-group bar-group-standalone bar-group-pad', + css: 'min-width: 2px;', + children: [ + WorkspaceContents(10), + ] + })] + }), + setup: (self) => { + self.add_events(Gdk.EventMask.POINTER_MOTION_MASK); + self.on('motion-notify-event', (self, event) => { + if (!self.attribute.clicked) return; + const [_, cursorX, cursorY] = event.get_coords(); + const widgetWidth = self.get_allocation().width; + const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES / widgetWidth); + switchToWorkspace(wsId); + }) + self.on('button-press-event', (self, event) => { + if (!(event.get_button()[1] === 1)) return; // We're only interested in left-click here + self.attribute.clicked = true; + const [_, cursorX, cursorY] = event.get_coords(); + const widgetWidth = self.get_allocation().width; + const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES / widgetWidth); + switchToWorkspace(wsId); + }) + self.on('button-release-event', (self) => self.attribute.clicked = false); + } +}); diff --git a/.config/ags/scss/_bar.scss b/.config/ags/scss/_bar.scss index f83566092..ccb35c5bc 100644 --- a/.config/ags/scss/_bar.scss +++ b/.config/ags/scss/_bar.scss @@ -4,6 +4,8 @@ $black: black; $white: white; $bar_ws_width: 1.774rem; +$bar_ws_width_focus: 0.614rem; +$bar_ws_width_focus_active: 2.045rem; $bar_subgroup_bg: $surfaceVariant; @mixin bar-group-rounding { @@ -19,6 +21,15 @@ $bar_subgroup_bg: $surfaceVariant; min-height: 2.727rem; } +.bar-bg-focus { + background-color: $t_background; + min-height: 1.364rem; +} + +.bar-bg-focus-batterylow { + background-color: mix($background, $errorContainer, 80%); +} + .bar-sidespace { min-width: 1.5rem; } @@ -84,6 +95,7 @@ $bar_subgroup_bg: $surfaceVariant; .bar-ws { min-width: $bar_ws_width; color: mix($onBackground, $background, 40%); + @if $darkmode ==true { color: mix($onBackground, $background, 45%); } @@ -99,6 +111,26 @@ $bar_subgroup_bg: $surfaceVariant; color: $onSurfaceVariant; } +// Focus is the bar mode name, not the workspace state! + +.bar-ws-focus { + background-color: $bar_subgroup_bg; + min-width: $bar_ws_width_focus; +} + +.bar-ws-focus-active { + min-width: $bar_ws_width_focus_active; + background-color: $onBackground; +} + +.bar-ws-focus-occupied { + background-color: mix($onBackground, $background, 40%); + + @if $darkmode ==true { + background-color: mix($onBackground, $background, 45%); + } +} + .bar-separator { @include full-rounding; min-width: 0.341rem; @@ -250,17 +282,17 @@ $bar_subgroup_bg: $surfaceVariant; padding: 0.341rem; } -.bar-space-button > box:first-child { +.bar-space-button>box:first-child { @include full-rounding; padding: 0rem 0.682rem; } -.bar-space-button:hover > box:first-child, -.bar-space-button:focus > box:first-child { +.bar-space-button:hover>box:first-child, +.bar-space-button:focus>box:first-child { background-color: $hovercolor; } -.bar-space-button:active > box:first-child { +.bar-space-button:active>box:first-child { background-color: $activecolor; } @@ -270,7 +302,7 @@ $bar_subgroup_bg: $surfaceVariant; } } -.bar-space-area-rightmost > box { +.bar-space-area-rightmost>box { padding-right: 2.386rem; } diff --git a/.config/ags/scss/_lib_mixins.scss b/.config/ags/scss/_lib_mixins.scss index ba5babffc..ece6a3dd2 100644 --- a/.config/ags/scss/_lib_mixins.scss +++ b/.config/ags/scss/_lib_mixins.scss @@ -60,7 +60,7 @@ $rounding_large: 1.705rem; @mixin readingfont { // The most readable fonts, for a comfortable reading experience - // in stuff like ChatGPT widget + // in stuff like AI chat on sidebar font-family: "Lexend", "Noto Sans", sans-serif; // font-weight: 500; } diff --git a/.config/ags/services/gpt.js b/.config/ags/services/gpt.js index 63a55e6c6..63727cf85 100644 --- a/.config/ags/services/gpt.js +++ b/.config/ags/services/gpt.js @@ -62,7 +62,7 @@ Utils.exec(`mkdir -p ${GLib.get_user_cache_dir()}/ags/user/ai`); const CHAT_MODELS = ["gpt-3.5-turbo-1106", "gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-3.5-turbo-0613"] const ONE_CYCLE_COUNT = 3; -class ChatGPTMessage extends Service { +class GPTMessage extends Service { static { Service.register(this, { @@ -122,7 +122,7 @@ class ChatGPTMessage extends Service { } } -class ChatGPTService extends Service { +class GPTService extends Service { static { Service.register(this, { 'initialized': [], @@ -240,14 +240,14 @@ class ChatGPTService extends Service { } addMessage(role, message) { - this._messages.push(new ChatGPTMessage(role, message)); + this._messages.push(new GPTMessage(role, message)); this.emit('newMsg', this._messages.length - 1); } send(msg) { - this._messages.push(new ChatGPTMessage('user', msg)); + this._messages.push(new GPTMessage('user', msg)); this.emit('newMsg', this._messages.length - 1); - const aiResponse = new ChatGPTMessage('assistant', 'thinking...', true, false) + const aiResponse = new GPTMessage('assistant', 'thinking...', true, false) this._messages.push(aiResponse); this.emit('newMsg', this._messages.length - 1); @@ -283,7 +283,7 @@ class ChatGPTService extends Service { } } -export default new ChatGPTService(); +export default new GPTService(); diff --git a/.config/ags/variables.js b/.config/ags/variables.js index a367114e1..29e390001 100644 --- a/.config/ags/variables.js +++ b/.config/ags/variables.js @@ -1,6 +1,6 @@ import Variable from 'resource:///com/github/Aylur/ags/variable.js'; import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js'; -const { exec } = Utils; +const { exec, execAsync } = Utils; import Gdk from 'gi://Gdk'; // Global vars for external control (through keybinds) @@ -8,9 +8,20 @@ export const showMusicControls = Variable(false, {}) export const showColorScheme = Variable(false, {}) globalThis['openMusicControls'] = showMusicControls; globalThis['openColorScheme'] = showColorScheme; + globalThis['mpris'] = Mpris; // Screen size export const SCREEN_WIDTH = Number(exec(`bash -c "xrandr --current | grep '*' | uniq | awk '{print $1}' | cut -d 'x' -f1 | head -1" | awk '{print $1}'`)); export const SCREEN_HEIGHT = Number(exec(`bash -c "xrandr --current | grep '*' | uniq | awk '{print $1}' | cut -d 'x' -f2 | head -1" | awk '{print $1}'`)); +// Mode switching +export const currentShellMode = Variable('normal', {}) // normal, focus +globalThis['currentMode'] = currentShellMode; +globalThis['cycleMode'] = () => { + if (currentShellMode.value === 'normal') { + currentShellMode.value = 'focus'; + } else { + currentShellMode.value = 'normal'; + } +} diff --git a/.config/hypr/hyprland/keybinds.conf b/.config/hypr/hyprland/keybinds.conf index d892c0224..6b099477d 100644 --- a/.config/hypr/hyprland/keybinds.conf +++ b/.config/hypr/hyprland/keybinds.conf @@ -73,6 +73,7 @@ bind = Control+Super, Slash, exec, pkill anyrun || anyrun bindr = Control+Super, R, exec, killall ags ydotool; ags & bindr = Control+Super+Alt, R, exec, hyprctl reload; killall ags ydotool; ags & bind = Control+Super, T, exec, ~/.config/ags/scripts/color_generation/switchwall.sh +bind = Control+Alt, Slash, exec, ags run-js 'cycleMode();' bindir = Super, Super_L, exec, ags -t 'overview' bind = Super, Tab, exec, ags -t 'overview' bind = Super, Slash, exec, ags -t 'cheatsheet' From 3554613bae47233e1fca6bc3c50e6196a1dad7bc Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 29 Feb 2024 23:04:26 +0700 Subject: [PATCH 035/517] colors: adjust light theme --- .config/ags/scss/_colors.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.config/ags/scss/_colors.scss b/.config/ags/scss/_colors.scss index 2cc6ef45b..b1277e8b4 100644 --- a/.config/ags/scss/_colors.scss +++ b/.config/ags/scss/_colors.scss @@ -14,9 +14,9 @@ $transparency_enabled: false; } @if $darkmode ==false { - $background: mix($background, $primary, 87%); - $surface: mix($surface, $primary, 93%); - $surfaceVariant: mix($surfaceVariant, #ffffff, 25%); + $background: mix($background, $primary, 85%); + $surface: mix($surface, $primary, 90%); + $surfaceVariant: mix($surfaceVariant, #ffffff, 50%); } } From 4626504e933f6a2bc51bf24c45a4363208590721 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 29 Feb 2024 23:04:54 +0700 Subject: [PATCH 036/517] uptime: use uptime command cuz faster than w --- .config/ags/modules/sideright/sideright.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/modules/sideright/sideright.js b/.config/ags/modules/sideright/sideright.js index c9ac81834..79c7a4001 100644 --- a/.config/ags/modules/sideright/sideright.js +++ b/.config/ags/modules/sideright/sideright.js @@ -30,7 +30,7 @@ const timeRow = Box({ className: 'txt-small txt', setup: (self) => self .poll(5000, label => { - execAsync(['bash', '-c', `w | sed -n '1p' | cut -d, -f1 | cut -d' ' -f4-`]) + execAsync(['bash', '-c', `uptime -p | sed -e 's/...//;s/ day\\| days/d/;s/ hour\\| hours/h/;s/ minute\\| minutes/m/;s/,[^,]*//2'`]) .then(upTimeString => { label.label = `Uptime ${upTimeString}`; }).catch(print); From 2d4e92ab4b651213ca935936e39f2e252d6d139a Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 29 Feb 2024 23:30:50 +0700 Subject: [PATCH 037/517] fix focus mode ws --- .../modules/bar/focus/workspaces_hyprland.js | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/.config/ags/modules/bar/focus/workspaces_hyprland.js b/.config/ags/modules/bar/focus/workspaces_hyprland.js index b5477c725..f6a8ad696 100644 --- a/.config/ags/modules/bar/focus/workspaces_hyprland.js +++ b/.config/ags/modules/bar/focus/workspaces_hyprland.js @@ -19,9 +19,10 @@ const WS_TAKEN_WIDTH_MULTIPLIER = 1.4; // Font size = workspace id const WorkspaceContents = (count = 10) => { return DrawingArea({ - className: 'menu-decel', + className: 'element-decel', // css: `transition: 300ms cubic-bezier(0.1, 1, 0, 1);`, attribute: { + lastImmediateActiveWs: 0, immediateActiveWs: 0, initialized: false, workspaceMask: 0, @@ -52,6 +53,7 @@ const WorkspaceContents = (count = 10) => { .hook(Hyprland.active.workspace, (self) => { const newActiveWs = (Hyprland.active.workspace.id - 1) % count + 1; self.setCss(`font-size: ${newActiveWs}px;`); + self.attribute.lastImmediateActiveWs = self.attribute.immediateActiveWs; self.attribute.immediateActiveWs = newActiveWs; const previousGroup = self.attribute.workspaceGroup; const currentGroup = Math.floor((Hyprland.active.workspace.id - 1) / count); @@ -82,16 +84,29 @@ const WorkspaceContents = (count = 10) => { const widgetStyleContext = area.get_style_context(); const activeWs = widgetStyleContext.get_property('font-size', Gtk.StateFlags.NORMAL); + const lastImmediateActiveWs = area.attribute.lastImmediateActiveWs; const immediateActiveWs = area.attribute.immediateActiveWs; // Draw area.set_size_request(workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER * (count - 1) + activeWorkspaceWidth, -1); for (let i = 1; i <= count; i++) { if (i == immediateActiveWs) continue; - if (area.attribute.workspaceMask & (1 << i)) - cr.setSourceRGBA(occupiedbg.red, occupiedbg.green, occupiedbg.blue, occupiedbg.alpha); - else - cr.setSourceRGBA(wsbg.red, wsbg.green, wsbg.blue, wsbg.alpha); + let colors = {}; + if (area.attribute.workspaceMask & (1 << i)) colors = occupiedbg; + else colors = wsbg; + + // if ((i == immediateActiveWs + 1 && immediateActiveWs < activeWs) || + // (i == immediateActiveWs + 1 && immediateActiveWs < activeWs)) { + // const widthPercentage = (i == immediateActiveWs - 1) ? + // 1 - (immediateActiveWs - activeWs) : + // activeWs - immediateActiveWs; + // cr.setSourceRGBA(colors.red * widthPercentage + activebg.red * (1 - widthPercentage), + // colors.green * widthPercentage + activebg.green * (1 - widthPercentage), + // colors.blue * widthPercentage + activebg.blue * (1 - widthPercentage), + // colors.alpha); + // } + // else + cr.setSourceRGBA(colors.red, colors.green, colors.blue, colors.alpha) const centerX = (i <= activeWs) ? (-workspaceRadius + (workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER * i)) @@ -115,7 +130,7 @@ const WorkspaceContents = (count = 10) => { const leftX = rightX - wsWidth; cr.rectangle(leftX, height / 2 - workspaceRadius, wsWidth, workspaceDiameter); cr.fill(); - cr.arc(rightX, height / 2, workspaceRadius, 0, Math.PI * 2); + cr.arc(leftX, height / 2, workspaceRadius, 0, Math.PI * 2); cr.fill(); } } From e8e368c82ff52aaecdfb25c8fa50d362c220a7bd Mon Sep 17 00:00:00 2001 From: clsty Date: Fri, 1 Mar 2024 16:16:53 +0800 Subject: [PATCH 038/517] Reminder to read Usage --- .github/ISSUE_TEMPLATE/1-issue.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/1-issue.md b/.github/ISSUE_TEMPLATE/1-issue.md index d94aeb41e..49a64d21d 100644 --- a/.github/ISSUE_TEMPLATE/1-issue.md +++ b/.github/ISSUE_TEMPLATE/1-issue.md @@ -7,7 +7,8 @@ assignees: '' --- -- **I have read the [wiki](https://end-4.github.io/dots-hyprland-wiki/en/i-i/03troubleshooting)** +- **(For usage) I have read the [wiki](https://end-4.github.io/dots-hyprland-wiki/en/i-i/02usage)** +- **(For troubleshooting) I have read the [wiki](https://end-4.github.io/dots-hyprland-wiki/en/i-i/03troubleshooting)** - Linux distro: --- From a3d4523f2f29e151d40023c648397b8ed73377dd Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Fri, 1 Mar 2024 21:53:31 +0700 Subject: [PATCH 039/517] bar: focus mode: fix workspaces --- .config/ags/modules/bar/focus/workspaces_hyprland.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.config/ags/modules/bar/focus/workspaces_hyprland.js b/.config/ags/modules/bar/focus/workspaces_hyprland.js index f6a8ad696..5d610ea33 100644 --- a/.config/ags/modules/bar/focus/workspaces_hyprland.js +++ b/.config/ags/modules/bar/focus/workspaces_hyprland.js @@ -15,6 +15,8 @@ const dummyActiveWs = Box({ className: 'bar-ws-focus bar-ws-focus-active' }); // const dummyOccupiedWs = Box({ className: 'bar-ws-focus bar-ws-focus-occupied' }); // Not shown. Only for getting size props const WS_TAKEN_WIDTH_MULTIPLIER = 1.4; +const floor = Math.floor; +const ceil = Math.ceil; // Font size = workspace id const WorkspaceContents = (count = 10) => { @@ -114,8 +116,8 @@ const WorkspaceContents = (count = 10) => { cr.arc(centerX, height / 2, workspaceRadius, 0, 2 * Math.PI); cr.fill(); // What if shrinking - if (i == immediateActiveWs - 1 && immediateActiveWs > activeWs) { // To right - const widthPercentage = 1 - (immediateActiveWs - activeWs); + if (i == floor(activeWs) && immediateActiveWs > activeWs) { // To right + const widthPercentage = 1 - (ceil(activeWs) - activeWs); const leftX = centerX; const wsWidth = (activeWorkspaceWidth - (workspaceDiameter * 1.5)) * (1 - widthPercentage); cr.rectangle(leftX, height / 2 - workspaceRadius, wsWidth, workspaceDiameter); @@ -123,8 +125,8 @@ const WorkspaceContents = (count = 10) => { cr.arc(leftX + wsWidth, height / 2, workspaceRadius, 0, Math.PI * 2); cr.fill(); } - else if (i == immediateActiveWs + 1 && immediateActiveWs < activeWs) { // To left - const widthPercentage = activeWs - immediateActiveWs; + else if (i == ceil(activeWs) && immediateActiveWs < activeWs) { // To left + const widthPercentage = activeWs - floor(activeWs); const rightX = centerX; const wsWidth = (activeWorkspaceWidth - (workspaceDiameter * 1.5)) * widthPercentage; const leftX = rightX - wsWidth; @@ -138,6 +140,7 @@ const WorkspaceContents = (count = 10) => { let widthPercentage, leftX, rightX, activeWsWidth; cr.setSourceRGBA(activebg.red, activebg.green, activebg.blue, activebg.alpha); if (immediateActiveWs > activeWs) { // To right + const immediateActiveWs = ceil(activeWs); widthPercentage = immediateActiveWs - activeWs; rightX = -workspaceRadius + workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER * (count - 1) + activeWorkspaceWidth - ((count - immediateActiveWs) * workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER); activeWsWidth = (activeWorkspaceWidth - (workspaceDiameter * 1.5)) * (1 - widthPercentage); @@ -151,6 +154,7 @@ const WorkspaceContents = (count = 10) => { cr.fill(); } else { // To left + const immediateActiveWs = floor(activeWs); widthPercentage = 1 - (activeWs - immediateActiveWs); leftX = -workspaceRadius + (workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER * immediateActiveWs); activeWsWidth = (activeWorkspaceWidth - (workspaceDiameter * 1.5)) * widthPercentage From 7ecbf9b24b7f89287ac594654a44ebd7e70407e9 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Fri, 1 Mar 2024 22:05:02 +0700 Subject: [PATCH 040/517] terminal sequences: remove extra newline --- .config/ags/scripts/templates/terminal/sequences.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/scripts/templates/terminal/sequences.txt b/.config/ags/scripts/templates/terminal/sequences.txt index 1d41c4a0e..6fb48e654 100644 --- a/.config/ags/scripts/templates/terminal/sequences.txt +++ b/.config/ags/scripts/templates/terminal/sequences.txt @@ -1 +1 @@ -]4;0;#$background #\]4;1;#$error #\]4;2;#$inversePrimary #\]4;3;#$onPrimaryContainer #\]4;4;#$onPrimaryContainer #\]4;5;#$onSecondaryContainer #\]4;6;#$primary #\]4;7;#$onSurfaceVariant #\]4;8;#$background #\]4;9;#$error #\]4;10;#$inversePrimary #\]4;11;#$onPrimaryContainer #\]4;12;#$onPrimaryContainer #\]4;13;#$onSecondaryContainer #\]4;14;#$primary #\]4;15;#$onSurfaceVariant #\]10;#$onSurfaceVariant #\]11;[$alpha]#$background #\]12;#$onSurfaceVariant #\]13;#$onSurfaceVariant #\]17;#$onSurfaceVariant #\]19;#$background #\]4;232;#$background #\]4;256;#$onSurfaceVariant #\]708;[$alpha]#$background #\ +]4;0;#$background #\]4;1;#$error #\]4;2;#$inversePrimary #\]4;3;#$onPrimaryContainer #\]4;4;#$onPrimaryContainer #\]4;5;#$onSecondaryContainer #\]4;6;#$primary #\]4;7;#$onSurfaceVariant #\]4;8;#$background #\]4;9;#$error #\]4;10;#$inversePrimary #\]4;11;#$onPrimaryContainer #\]4;12;#$onPrimaryContainer #\]4;13;#$onSecondaryContainer #\]4;14;#$primary #\]4;15;#$onSurfaceVariant #\]10;#$onSurfaceVariant #\]11;[$alpha]#$background #\]12;#$onSurfaceVariant #\]13;#$onSurfaceVariant #\]17;#$onSurfaceVariant #\]19;#$background #\]4;232;#$background #\]4;256;#$onSurfaceVariant #\]708;[$alpha]#$background #\ \ No newline at end of file From e1bb1c97909100bef43c47ed6daf321ab57fc3d8 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Fri, 1 Mar 2024 23:18:56 +0700 Subject: [PATCH 041/517] user config round 1 (#271) --- .config/ags/config.js | 2 + .config/ags/modules/.miscutils/icons.js | 13 +++ .../modules/bar/focus/workspaces_hyprland.js | 14 ++-- .../ags/modules/bar/focus/workspaces_sway.js | 5 +- .config/ags/modules/bar/main.js | 5 +- .config/ags/modules/bar/normal/system.js | 16 +--- .config/ags/modules/bar/normal/tray.js | 47 ----------- .../modules/bar/normal/workspaces_hyprland.js | 11 ++- .../ags/modules/bar/normal/workspaces_sway.js | 5 +- .config/ags/modules/indicators/colorscheme.js | 2 +- .../ags/modules/indicators/musiccontrols.js | 13 +-- .../onscreenkeyboard/data_keyboardlayouts.js | 2 +- .../onscreenkeyboard/onscreenkeyboard.js | 4 +- .../ags/modules/overview/overview_hyprland.js | 84 +++++++------------ .config/ags/modules/overview/searchbuttons.js | 2 +- .config/ags/modules/overview/windowcontent.js | 2 +- .config/ags/modules/session/sessionscreen.js | 68 +++++++-------- .config/ags/scss/_material.scss | 55 ++++++------ .config/ags/scss/_musicmaterial.scss | 1 + .config/ags/user_options.js | 43 ++++++++++ 20 files changed, 170 insertions(+), 224 deletions(-) create mode 100644 .config/ags/modules/.miscutils/icons.js create mode 100644 .config/ags/user_options.js diff --git a/.config/ags/config.js b/.config/ags/config.js index 59d5e74ba..415d5e518 100644 --- a/.config/ags/config.js +++ b/.config/ags/config.js @@ -4,6 +4,8 @@ import Gdk from 'gi://Gdk'; import GLib from 'gi://GLib'; import App from 'resource:///com/github/Aylur/ags/app.js' import * as Utils from 'resource:///com/github/Aylur/ags/utils.js' +// Stuff +import userOptions from './user_options.js'; // Widgets import { Bar, BarCornerTopleft, BarCornerTopright } from './modules/bar/main.js'; import Cheatsheet from './modules/cheatsheet/main.js'; diff --git a/.config/ags/modules/.miscutils/icons.js b/.config/ags/modules/.miscutils/icons.js new file mode 100644 index 000000000..fb1e20da3 --- /dev/null +++ b/.config/ags/modules/.miscutils/icons.js @@ -0,0 +1,13 @@ +const { Gtk } = imports.gi; + +export function iconExists(iconName) { + let iconTheme = Gtk.IconTheme.get_default(); + return iconTheme.has_icon(iconName); +} + +export function substitute(str) { + if(userOptions.icons.substitutions[str]) return userOptions.icons.substitutions[str]; + + if (!iconExists(str)) str = str.toLowerCase().replace(/\s+/g, '-'); // Turn into kebab-case + return str; +} \ No newline at end of file diff --git a/.config/ags/modules/bar/focus/workspaces_hyprland.js b/.config/ags/modules/bar/focus/workspaces_hyprland.js index 5d610ea33..12a3982a9 100644 --- a/.config/ags/modules/bar/focus/workspaces_hyprland.js +++ b/.config/ags/modules/bar/focus/workspaces_hyprland.js @@ -9,7 +9,6 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js'; const { Box, DrawingArea, EventBox } = Widget; import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js'; -const NUM_OF_WORKSPACES_SHOWN = 10; // Limit = 53 I think const dummyWs = Box({ className: 'bar-ws-focus' }); // Not shown. Only for getting size props const dummyActiveWs = Box({ className: 'bar-ws-focus bar-ws-focus-active' }); // Not shown. Only for getting size props const dummyOccupiedWs = Box({ className: 'bar-ws-focus bar-ws-focus-occupied' }); // Not shown. Only for getting size props @@ -21,8 +20,7 @@ const ceil = Math.ceil; // Font size = workspace id const WorkspaceContents = (count = 10) => { return DrawingArea({ - className: 'element-decel', - // css: `transition: 300ms cubic-bezier(0.1, 1, 0, 1);`, + className: 'menu-decel', attribute: { lastImmediateActiveWs: 0, immediateActiveWs: 0, @@ -30,7 +28,7 @@ const WorkspaceContents = (count = 10) => { workspaceMask: 0, workspaceGroup: 0, updateMask: (self) => { - const offset = Math.floor((Hyprland.active.workspace.id - 1) / count) * NUM_OF_WORKSPACES_SHOWN; + const offset = Math.floor((Hyprland.active.workspace.id - 1) / count) * userOptions.workspaces.shown; // if (self.attribute.initialized) return; // We only need this to run once const workspaces = Hyprland.workspaces; let workspaceMask = 0; @@ -66,7 +64,7 @@ const WorkspaceContents = (count = 10) => { }) .hook(Hyprland, (self) => self.attribute.updateMask(self), 'notify::workspaces') .on('draw', Lang.bind(area, (area, cr) => { - const offset = Math.floor((Hyprland.active.workspace.id - 1) / count) * NUM_OF_WORKSPACES_SHOWN; + const offset = Math.floor((Hyprland.active.workspace.id - 1) / count) * userOptions.workspaces.shown; const allocation = area.get_allocation(); const { width, height } = allocation; @@ -186,7 +184,7 @@ export default () => EventBox({ children: [Box({ // className: 'bar-group bar-group-standalone bar-group-pad', css: 'min-width: 2px;', - children: [WorkspaceContents(NUM_OF_WORKSPACES_SHOWN)], + children: [WorkspaceContents(userOptions.workspaces.shown)], })] }), setup: (self) => { @@ -195,7 +193,7 @@ export default () => EventBox({ if (!self.attribute.clicked) return; const [_, cursorX, cursorY] = event.get_coords(); const widgetWidth = self.get_allocation().width; - const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES_SHOWN / widgetWidth); + const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth); Utils.execAsync([`${App.configDir}/scripts/hyprland/workspace_action.sh`, 'workspace', `${wsId}`]) .catch(print); }) @@ -206,7 +204,7 @@ export default () => EventBox({ const widgetWidth = self.get_allocation().width; // const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES_PER_GROUP / widgetWidth) + self.attribute.ws_group * NUM_OF_WORKSPACES_PER_GROUP; // Hyprland.messageAsync(`dispatch workspace ${wsId}`).catch(print); - const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES_SHOWN / widgetWidth); + const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth); Utils.execAsync([`${App.configDir}/scripts/hyprland/workspace_action.sh`, 'workspace', `${wsId}`]) .catch(print); }) diff --git a/.config/ags/modules/bar/focus/workspaces_sway.js b/.config/ags/modules/bar/focus/workspaces_sway.js index 632b4b563..e40c7c098 100644 --- a/.config/ags/modules/bar/focus/workspaces_sway.js +++ b/.config/ags/modules/bar/focus/workspaces_sway.js @@ -9,7 +9,6 @@ import * as Utils from "resource:///com/github/Aylur/ags/utils.js"; const { execAsync, exec } = Utils; const { Box, DrawingArea, EventBox } = Widget; -const NUM_OF_WORKSPACES = 10; const dummyWs = Box({ className: 'bar-ws' }); // Not shown. Only for getting size props const dummyActiveWs = Box({ className: 'bar-ws bar-ws-active' }); // Not shown. Only for getting size props const dummyOccupiedWs = Box({ className: 'bar-ws bar-ws-occupied' }); // Not shown. Only for getting size props @@ -168,7 +167,7 @@ export default () => EventBox({ if (!self.attribute.clicked) return; const [_, cursorX, cursorY] = event.get_coords(); const widgetWidth = self.get_allocation().width; - const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES / widgetWidth); + const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth); switchToWorkspace(wsId); }) self.on('button-press-event', (self, event) => { @@ -176,7 +175,7 @@ export default () => EventBox({ self.attribute.clicked = true; const [_, cursorX, cursorY] = event.get_coords(); const widgetWidth = self.get_allocation().width; - const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES / widgetWidth); + const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth); switchToWorkspace(wsId); }) self.on('button-release-event', (self) => self.attribute.clicked = false); diff --git a/.config/ags/modules/bar/main.js b/.config/ags/modules/bar/main.js index 7719919b6..da3962ff1 100644 --- a/.config/ags/modules/bar/main.js +++ b/.config/ags/modules/bar/main.js @@ -10,8 +10,6 @@ import { enableClickthrough } from "../.widgetutils/clickthrough.js"; import { RoundedCorner } from "../.commonwidgets/cairo_roundedcorner.js"; import { currentShellMode } from '../../variables.js'; -const BATTERY_LOW = 20; - const NormalOptionalWorkspaces = async () => { try { return (await import('./normal/workspaces_hyprland.js')).default(); @@ -80,8 +78,7 @@ export const Bar = async (monitor = 0) => { setup: (self) => { self.hook(Battery, (self) => { if(!Battery.available) return; - print(Battery.percent) - self.toggleClassName('bar-bg-focus-batterylow', Battery.percent <= BATTERY_LOW); + self.toggleClassName('bar-bg-focus-batterylow', Battery.percent <= userOptions.battery.low); }) } }); diff --git a/.config/ags/modules/bar/normal/system.js b/.config/ags/modules/bar/normal/system.js index 63e5fdb3c..d2d4ee876 100644 --- a/.config/ags/modules/bar/normal/system.js +++ b/.config/ags/modules/bar/normal/system.js @@ -9,22 +9,14 @@ import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; import { AnimatedCircProg } from "../../.commonwidgets/cairo_circularprogress.js"; import { WWO_CODE, WEATHER_SYMBOL, NIGHT_WEATHER_SYMBOL } from '../../.commondata/weather.js'; -const BATTERY_LOW = 20; const WEATHER_CACHE_FOLDER = `${GLib.get_user_cache_dir()}/ags/weather`; Utils.exec(`mkdir -p ${WEATHER_CACHE_FOLDER}`); -let WEATHER_CITY = ''; -try { - WEATHER_CITY = GLib.getenv('AGS_WEATHER_CITY'); -} catch (e) { - print(e); -} - const BatBatteryProgress = () => { const _updateProgress = (circprog) => { // Set circular progress value circprog.css = `font-size: ${Math.abs(Battery.percent)}px;` - circprog.toggleClassName('bar-batt-circprog-low', Battery.percent <= BATTERY_LOW); + circprog.toggleClassName('bar-batt-circprog-low', Battery.percent <= userOptions.battery.low); circprog.toggleClassName('bar-batt-circprog-full', Battery.charged); } return AnimatedCircProg({ @@ -119,7 +111,7 @@ const BarBattery = () => Box({ MaterialIcon('settings_heart', 'small'), ], setup: (self) => self.hook(Battery, box => { - box.toggleClassName('bar-batt-low', Battery.percent <= BATTERY_LOW); + box.toggleClassName('bar-batt-low', Battery.percent <= userOptions.battery.low); box.toggleClassName('bar-batt-full', Battery.charged); }), }), @@ -192,8 +184,8 @@ const BatteryModule = () => Stack({ print(err); } }); - if (WEATHER_CITY != '' && WEATHER_CITY != null) { - updateWeatherForCity(WEATHER_CITY); + if (userOptions.weather.city != '' && userOptions.weather.city != null) { + updateWeatherForCity(userOptions.weather.city); } else { Utils.execAsync('curl ipinfo.io') diff --git a/.config/ags/modules/bar/normal/tray.js b/.config/ags/modules/bar/normal/tray.js index 7d1800725..53827ca74 100644 --- a/.config/ags/modules/bar/normal/tray.js +++ b/.config/ags/modules/bar/normal/tray.js @@ -1,4 +1,3 @@ -const { Gtk } = imports.gi; import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import SystemTray from 'resource:///com/github/Aylur/ags/service/systemtray.js'; const { Box, Icon, Button, Revealer } = Widget; @@ -23,52 +22,6 @@ const SysTrayItem = (item) => Button({ export const Tray = (props = {}) => { const trayContent = Box({ className: 'margin-right-5 spacing-h-15', - // attribute: { - // items: new Map(), - // addItem: (box, item) => { - // if (!item) return; - // console.log('init item:', item) - - // item.menu.className = 'menu'; - // if (box.attribute.items.has(item.id) || !item) - // return; - // const widget = SysTrayItem(item); - // box.attribute.items.set(item.id, widget); - // box.add(widget); - // box.show_all(); - // }, - // onAdded: (box, id) => { - // console.log('supposed to add', id) - // const item = SystemTray.getItem(id); - // if (!item) return; - // console.log('which is', box.attribute.items.get(id)) - - // item.menu.className = 'menu'; - // if (box.attribute.items.has(id) || !item) - // return; - // const widget = SysTrayItem(item); - // box.attribute.items.set(id, widget); - // box.add(widget); - // box.show_all(); - // }, - // onRemoved: (box, id) => { - // console.log('supposed to remove', id) - // if (!box.attribute.items.has(id)) return; - // console.log('which is', box.attribute.items.get(id)) - // box.attribute.items.get(id).destroy(); - // box.attribute.items.delete(id); - // }, - // }, - // setup: (self) => { - // // self.hook(SystemTray, (box, id) => box.attribute.onAdded(box, id), 'added') - // // .hook(SystemTray, (box, id) => box.attribute.onRemoved(box, id), 'removed'); - // // SystemTray.items.forEach(item => self.attribute.addItem(self, item)); - // // self.chidren = SystemTray.items.map(item => SysTrayItem(item)); - // console.log(SystemTray.items.map(item => SysTrayItem(item))) - // self.chidren = SystemTray.items.map(item => SysTrayItem(item)); - - // self.show_all(); - // }, setup: (self) => self .hook(SystemTray, (self) => { self.children = SystemTray.items.map(SysTrayItem); diff --git a/.config/ags/modules/bar/normal/workspaces_hyprland.js b/.config/ags/modules/bar/normal/workspaces_hyprland.js index f5edfa2f6..770ba6bc8 100644 --- a/.config/ags/modules/bar/normal/workspaces_hyprland.js +++ b/.config/ags/modules/bar/normal/workspaces_hyprland.js @@ -9,7 +9,6 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js'; const { Box, DrawingArea, EventBox } = Widget; import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js'; -const NUM_OF_WORKSPACES_SHOWN = 10; // Limit = 53 I think const dummyWs = Box({ className: 'bar-ws' }); // Not shown. Only for getting size props const dummyActiveWs = Box({ className: 'bar-ws bar-ws-active' }); // Not shown. Only for getting size props const dummyOccupiedWs = Box({ className: 'bar-ws bar-ws-occupied' }); // Not shown. Only for getting size props @@ -23,7 +22,7 @@ const WorkspaceContents = (count = 10) => { workspaceMask: 0, workspaceGroup: 0, updateMask: (self) => { - const offset = Math.floor((Hyprland.active.workspace.id - 1) / count) * NUM_OF_WORKSPACES_SHOWN; + const offset = Math.floor((Hyprland.active.workspace.id - 1) / count) * userOptions.workspaces.shown; // if (self.attribute.initialized) return; // We only need this to run once const workspaces = Hyprland.workspaces; let workspaceMask = 0; @@ -56,7 +55,7 @@ const WorkspaceContents = (count = 10) => { }) .hook(Hyprland, (self) => self.attribute.updateMask(self), 'notify::workspaces') .on('draw', Lang.bind(area, (area, cr) => { - const offset = Math.floor((Hyprland.active.workspace.id - 1) / count) * NUM_OF_WORKSPACES_SHOWN; + const offset = Math.floor((Hyprland.active.workspace.id - 1) / count) * userOptions.workspaces.shown; const allocation = area.get_allocation(); const { width, height } = allocation; @@ -162,7 +161,7 @@ export default () => EventBox({ children: [Box({ className: 'bar-group bar-group-standalone bar-group-pad', css: 'min-width: 2px;', - children: [WorkspaceContents(NUM_OF_WORKSPACES_SHOWN)], + children: [WorkspaceContents(userOptions.workspaces.shown)], })] }), setup: (self) => { @@ -171,7 +170,7 @@ export default () => EventBox({ if (!self.attribute.clicked) return; const [_, cursorX, cursorY] = event.get_coords(); const widgetWidth = self.get_allocation().width; - const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES_SHOWN / widgetWidth); + const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth); Utils.execAsync([`${App.configDir}/scripts/hyprland/workspace_action.sh`, 'workspace', `${wsId}`]) .catch(print); }) @@ -182,7 +181,7 @@ export default () => EventBox({ const widgetWidth = self.get_allocation().width; // const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES_PER_GROUP / widgetWidth) + self.attribute.ws_group * NUM_OF_WORKSPACES_PER_GROUP; // Hyprland.messageAsync(`dispatch workspace ${wsId}`).catch(print); - const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES_SHOWN / widgetWidth); + const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth); Utils.execAsync([`${App.configDir}/scripts/hyprland/workspace_action.sh`, 'workspace', `${wsId}`]) .catch(print); }) diff --git a/.config/ags/modules/bar/normal/workspaces_sway.js b/.config/ags/modules/bar/normal/workspaces_sway.js index 632b4b563..e40c7c098 100644 --- a/.config/ags/modules/bar/normal/workspaces_sway.js +++ b/.config/ags/modules/bar/normal/workspaces_sway.js @@ -9,7 +9,6 @@ import * as Utils from "resource:///com/github/Aylur/ags/utils.js"; const { execAsync, exec } = Utils; const { Box, DrawingArea, EventBox } = Widget; -const NUM_OF_WORKSPACES = 10; const dummyWs = Box({ className: 'bar-ws' }); // Not shown. Only for getting size props const dummyActiveWs = Box({ className: 'bar-ws bar-ws-active' }); // Not shown. Only for getting size props const dummyOccupiedWs = Box({ className: 'bar-ws bar-ws-occupied' }); // Not shown. Only for getting size props @@ -168,7 +167,7 @@ export default () => EventBox({ if (!self.attribute.clicked) return; const [_, cursorX, cursorY] = event.get_coords(); const widgetWidth = self.get_allocation().width; - const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES / widgetWidth); + const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth); switchToWorkspace(wsId); }) self.on('button-press-event', (self, event) => { @@ -176,7 +175,7 @@ export default () => EventBox({ self.attribute.clicked = true; const [_, cursorX, cursorY] = event.get_coords(); const widgetWidth = self.get_allocation().width; - const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES / widgetWidth); + const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth); switchToWorkspace(wsId); }) self.on('button-release-event', (self) => self.attribute.clicked = false); diff --git a/.config/ags/modules/indicators/colorscheme.js b/.config/ags/modules/indicators/colorscheme.js index 54ecef8ad..d5dfd4970 100644 --- a/.config/ags/modules/indicators/colorscheme.js +++ b/.config/ags/modules/indicators/colorscheme.js @@ -1,6 +1,6 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js'; -const { Box, EventBox, Icon, Scrollable, Label, Button, Revealer } = Widget; +const { Box, Label } = Widget; import { showColorScheme } from '../../variables.js'; const ColorBox = ({ diff --git a/.config/ags/modules/indicators/musiccontrols.js b/.config/ags/modules/indicators/musiccontrols.js index 6575c69ff..6fd44847a 100644 --- a/.config/ags/modules/indicators/musiccontrols.js +++ b/.config/ags/modules/indicators/musiccontrols.js @@ -11,18 +11,9 @@ import { showMusicControls } from '../../variables.js'; const COMPILED_STYLE_DIR = `${GLib.get_user_cache_dir()}/ags/user/generated` -function expandTilde(path) { - if (path.startsWith('~')) { - return GLib.get_home_dir() + path.slice(1); - } else { - return path; - } -} - const LIGHTDARK_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/colormode.txt`; -const lightDark = Utils.readFile(expandTilde(LIGHTDARK_FILE_LOCATION)).trim(); +const lightDark = Utils.readFile(LIGHTDARK_FILE_LOCATION).trim(); const COVER_COLORSCHEME_SUFFIX = '_colorscheme.css'; -const PREFERRED_PLAYER = 'plasma-browser-integration'; var lastCoverPath = ''; function isRealPlayer(player) { @@ -33,7 +24,7 @@ function isRealPlayer(player) { ); } -export const getPlayer = (name = PREFERRED_PLAYER) => Mpris.getPlayer(name) || Mpris.players[0] || null; +export const getPlayer = (name = userOptions.music.preferredPlayer) => Mpris.getPlayer(name) || Mpris.players[0] || null; function lengthStr(length) { const min = Math.floor(length / 60); const sec = Math.floor(length % 60); diff --git a/.config/ags/modules/onscreenkeyboard/data_keyboardlayouts.js b/.config/ags/modules/onscreenkeyboard/data_keyboardlayouts.js index cb92b8a3e..1a67b7a1f 100755 --- a/.config/ags/modules/onscreenkeyboard/data_keyboardlayouts.js +++ b/.config/ags/modules/onscreenkeyboard/data_keyboardlayouts.js @@ -1,7 +1,7 @@ // We're going to use ydotool // See /usr/include/linux/input-event-codes.h for keycodes -export const defaultOskLayout = "qwerty_full" +export const DEFAULT_OSK_LAYOUT = "qwerty_full" export const oskLayouts = { qwerty_full: { name: "QWERTY - Full", diff --git a/.config/ags/modules/onscreenkeyboard/onscreenkeyboard.js b/.config/ags/modules/onscreenkeyboard/onscreenkeyboard.js index 2bb9c7bcc..1bbc7b1f9 100644 --- a/.config/ags/modules/onscreenkeyboard/onscreenkeyboard.js +++ b/.config/ags/modules/onscreenkeyboard/onscreenkeyboard.js @@ -6,10 +6,10 @@ import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; const { Box, EventBox, Button, Revealer } = Widget; const { execAsync } = Utils; import { MaterialIcon } from '../.commonwidgets/materialicon.js'; -import { defaultOskLayout, oskLayouts } from './data_keyboardlayouts.js'; +import { DEFAULT_OSK_LAYOUT, oskLayouts } from './data_keyboardlayouts.js'; import { setupCursorHoverGrab } from '../.widgetutils/cursorhover.js'; -const keyboardLayout = defaultOskLayout; +const keyboardLayout = oskLayouts[userOptions.onScreenKeyboard.layout] ? userOptions.onScreenKeyboard.layout : DEFAULT_OSK_LAYOUT; const keyboardJson = oskLayouts[keyboardLayout]; execAsync(`ydotoold`).catch(print); // Start ydotool daemon diff --git a/.config/ags/modules/overview/overview_hyprland.js b/.config/ags/modules/overview/overview_hyprland.js index 512d3900c..55ef9f150 100644 --- a/.config/ags/modules/overview/overview_hyprland.js +++ b/.config/ags/modules/overview/overview_hyprland.js @@ -14,41 +14,13 @@ import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js'; const { execAsync, exec } = Utils; import { setupCursorHoverGrab } from '../.widgetutils/cursorhover.js'; import { dumpToWorkspace, swapWorkspace } from "./actions.js"; +import { substitute } from "../.miscutils/icons.js"; -const OVERVIEW_SCALE = 0.18; -const NUM_OF_WORKSPACE_ROWS = 2; -const NUM_OF_WORKSPACE_COLS = 5; -const OVERVIEW_WS_NUM_SCALE = 0.09; -const NUM_OF_WORKSPACES_SHOWN = NUM_OF_WORKSPACE_COLS * NUM_OF_WORKSPACE_ROWS; -const OVERVIEW_WS_NUM_MARGIN_SCALE = 0.07; +const NUM_OF_WORKSPACES_SHOWN = userOptions.overview.numOfCols * userOptions.overview.numOfRows; const TARGET = [Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags.SAME_APP, 0)]; const overviewTick = Variable(false); -function iconExists(iconName) { - let iconTheme = Gtk.IconTheme.get_default(); - return iconTheme.has_icon(iconName); -} - -function substitute(str) { - const subs = [ - { from: 'code-url-handler', to: 'visual-studio-code' }, - { from: 'Code', to: 'visual-studio-code' }, - { from: 'GitHub Desktop', to: 'github-desktop' }, - { from: 'wps', to: 'wps-office2019-kprometheus' }, - { from: 'gnome-tweaks', to: 'org.gnome.tweaks' }, - { from: 'Minecraft* 1.20.1', to: 'minecraft' }, - { from: '', to: 'image-missing' }, - ]; - - for (const { from, to } of subs) { - if (from === str) - return to; - } - - if (!iconExists(str)) str = str.toLowerCase().replace(/\s+/g, '-'); // Turn into kebab-case - return str; -} export default () => { const clientMap = new Map(); let workspaceGroup = 0; @@ -78,7 +50,7 @@ export default () => { }) const Window = ({ address, at: [x, y], size: [w, h], workspace: { id, name }, class: c, title, xwayland }, screenCoords) => { - const revealInfoCondition = (Math.min(w, h) * OVERVIEW_SCALE > 70); + const revealInfoCondition = (Math.min(w, h) * userOptions.overview.scale > 70); if (w <= 0 || h <= 0 || (c === '' && title === '')) return null; // Non-primary monitors if (screenCoords.x != 0) x -= screenCoords.x; @@ -94,23 +66,23 @@ export default () => { const appIcon = Widget.Icon({ icon: substitute(c), - size: Math.min(w, h) * OVERVIEW_SCALE / 2.5, + size: Math.min(w, h) * userOptions.overview.scale / 2.5, }); return Widget.Button({ attribute: { address, x, y, w, h, ws: id, updateIconSize: (self) => { - appIcon.size = Math.min(self.attribute.w, self.attribute.h) * OVERVIEW_SCALE / 2.5; + appIcon.size = Math.min(self.attribute.w, self.attribute.h) * userOptions.overview.scale / 2.5; }, }, className: 'overview-tasks-window', hpack: 'start', vpack: 'start', css: ` - margin-left: ${Math.round(x * OVERVIEW_SCALE)}px; - margin-top: ${Math.round(y * OVERVIEW_SCALE)}px; - margin-right: -${Math.round((x + w) * OVERVIEW_SCALE)}px; - margin-bottom: -${Math.round((y + h) * OVERVIEW_SCALE)}px; + margin-left: ${Math.round(x * userOptions.overview.scale)}px; + margin-top: ${Math.round(y * userOptions.overview.scale)}px; + margin-right: -${Math.round((x + w) * userOptions.overview.scale)}px; + margin-bottom: -${Math.round((y + h) * userOptions.overview.scale)}px; `, onClicked: (self) => { App.closeWindow('overview'); @@ -167,8 +139,8 @@ export default () => { truncate: 'end', className: `${xwayland ? 'txt txt-italic' : 'txt'}`, css: ` - font-size: ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * OVERVIEW_SCALE / 14.6}px; - margin: 0px ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * OVERVIEW_SCALE / 10}px; + font-size: ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * userOptions.overview.scale / 14.6}px; + margin: 0px ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * userOptions.overview.scale / 10}px; `, // If the title is too short, include the class label: (title.length <= 1 ? `${c}: ${title}` : title), @@ -211,12 +183,12 @@ export default () => { attribute: { put: (widget, x, y) => { if (!widget.attribute) return; - // Note: x and y are already multiplied by OVERVIEW_SCALE + // Note: x and y are already multiplied by userOptions.overview.scale const newCss = ` margin-left: ${Math.round(x)}px; margin-top: ${Math.round(y)}px; - margin-right: -${Math.round(x + (widget.attribute.w * OVERVIEW_SCALE))}px; - margin-bottom: -${Math.round(y + (widget.attribute.h * OVERVIEW_SCALE))}px; + margin-right: -${Math.round(x + (widget.attribute.w * userOptions.overview.scale))}px; + margin-bottom: -${Math.round(y + (widget.attribute.h * userOptions.overview.scale))}px; `; widget.css = newCss; fixed.pack_start(widget, false, false, 0); @@ -224,12 +196,12 @@ export default () => { move: (widget, x, y) => { if (!widget) return; if (!widget.attribute) return; - // Note: x and y are already multiplied by OVERVIEW_SCALE + // Note: x and y are already multiplied by userOptions.overview.scale const newCss = ` margin-left: ${Math.round(x)}px; margin-top: ${Math.round(y)}px; - margin-right: -${Math.round(x + (widget.attribute.w * OVERVIEW_SCALE))}px; - margin-bottom: -${Math.round(y + (widget.attribute.h * OVERVIEW_SCALE))}px; + margin-right: -${Math.round(x + (widget.attribute.w * userOptions.overview.scale))}px; + margin-bottom: -${Math.round(y + (widget.attribute.h * userOptions.overview.scale))}px; `; widget.css = newCss; }, @@ -239,16 +211,16 @@ export default () => { className: 'overview-tasks-workspace-number', label: `${index}`, css: ` - margin: ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * OVERVIEW_SCALE * OVERVIEW_WS_NUM_MARGIN_SCALE}px; - font-size: ${SCREEN_HEIGHT * OVERVIEW_SCALE * OVERVIEW_WS_NUM_SCALE}px; + margin: ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * userOptions.overview.scale * userOptions.overview.wsNumMarginScale}px; + font-size: ${SCREEN_HEIGHT * userOptions.overview.scale * userOptions.overview.wsNumScale}px; `, }) const widget = Widget.Box({ className: 'overview-tasks-workspace', vpack: 'center', css: ` - min-width: ${SCREEN_WIDTH * OVERVIEW_SCALE}px; - min-height: ${SCREEN_HEIGHT * OVERVIEW_SCALE}px; + min-width: ${SCREEN_WIDTH * userOptions.overview.scale}px; + min-height: ${SCREEN_HEIGHT * userOptions.overview.scale}px; `, children: [Widget.EventBox({ hexpand: true, @@ -295,8 +267,8 @@ export default () => { c.attribute.h = clientJson.size[1]; c.attribute.updateIconSize(c); fixed.attribute.move(c, - Math.max(0, clientJson.at[0] * OVERVIEW_SCALE), - Math.max(0, clientJson.at[1] * OVERVIEW_SCALE) + Math.max(0, clientJson.at[0] * userOptions.overview.scale), + Math.max(0, clientJson.at[1] * userOptions.overview.scale) ); return; } @@ -305,8 +277,8 @@ export default () => { if (newWindow === null) return; // clientMap.set(clientJson.address, newWindow); fixed.attribute.put(newWindow, - Math.max(0, newWindow.attribute.x * OVERVIEW_SCALE), - Math.max(0, newWindow.attribute.y * OVERVIEW_SCALE) + Math.max(0, newWindow.attribute.x * userOptions.overview.scale), + Math.max(0, newWindow.attribute.y * userOptions.overview.scale) ); clientMap.set(clientJson.address, newWindow); }; @@ -427,10 +399,10 @@ export default () => { child: Widget.Box({ vertical: true, className: 'overview-tasks', - children: Array.from({ length: NUM_OF_WORKSPACE_ROWS }, (_, index) => + children: Array.from({ length: userOptions.overview.numOfRows }, (_, index) => OverviewRow({ - startWorkspace: 1 + index * NUM_OF_WORKSPACE_COLS, - workspaces: NUM_OF_WORKSPACE_COLS, + startWorkspace: 1 + index * userOptions.overview.numOfCols, + workspaces: userOptions.overview.numOfCols, }) ) }), diff --git a/.config/ags/modules/overview/searchbuttons.js b/.config/ags/modules/overview/searchbuttons.js index 15130ad05..8fb40a23a 100644 --- a/.config/ags/modules/overview/searchbuttons.js +++ b/.config/ags/modules/overview/searchbuttons.js @@ -158,6 +158,6 @@ export const SearchButton = ({ text = '' }) => searchItem({ content: `${text}`, onActivate: () => { App.closeWindow('overview'); - execAsync(['bash', '-c', `xdg-open 'https://www.google.com/search?q=${text} -site:quora.com' &`]).catch(print); // quora is useless + execAsync(['bash', '-c', `xdg-open 'https://www.google.com/search?q=${text} ${['', ...userOptions.search.excludedSites].join(' -site:')}' &`]).catch(print); }, }); \ No newline at end of file diff --git a/.config/ags/modules/overview/windowcontent.js b/.config/ags/modules/overview/windowcontent.js index 4aeced3c8..179739a7e 100644 --- a/.config/ags/modules/overview/windowcontent.js +++ b/.config/ags/modules/overview/windowcontent.js @@ -140,7 +140,7 @@ export const SearchAndWindows = () => { else { App.closeWindow('overview'); - execAsync(['bash', '-c', `xdg-open 'https://www.google.com/search?q=${text} -site:quora.com' &`]).catch(print); // quora is useless + execAsync(['bash', '-c', `xdg-open 'https://www.google.com/search?q=${text} ${['', ...userOptions.search.excludedSites].join(' -site:')}' &`]).catch(print); } }, onChange: (entry) => { // this is when you type diff --git a/.config/ags/modules/session/sessionscreen.js b/.config/ags/modules/session/sessionscreen.js index b06659572..6ba475043 100644 --- a/.config/ags/modules/session/sessionscreen.js +++ b/.config/ags/modules/session/sessionscreen.js @@ -70,6 +70,32 @@ export default () => { const shutdownButton = SessionButton('Shutdown', 'power_settings_new', () => { App.closeWindow('session'); execAsync('systemctl poweroff') }); const rebootButton = SessionButton('Reboot', 'restart_alt', () => { App.closeWindow('session'); execAsync('systemctl reboot') }); const cancelButton = SessionButton('Cancel', 'close', () => App.closeWindow('session'), { className: 'session-button-cancel' }); + + const sessionDescription = Widget.Box({ + vertical: true, + css: 'margin-bottom: 0.682rem;', + children: [ + Widget.Label({ + className: 'txt-title txt', + label: 'Session', + }), + Widget.Label({ + justify: Gtk.Justification.CENTER, + className: 'txt-small txt', + label: 'Use arrow keys to navigate.\nEnter to select, Esc to cancel.' + }), + ] + }); + const SessionButtonRow = (children) => Widget.Box({ + hpack: 'center', + className: 'spacing-h-15', + children: children, + }); + const sessionButtonRows = [ + SessionButtonRow([lockButton, logoutButton, sleepButton]), + SessionButtonRow([hibernateButton, shutdownButton, rebootButton]), + SessionButtonRow([cancelButton]), + ] return Widget.Box({ className: 'session-bg', css: ` @@ -93,46 +119,8 @@ export default () => { vertical: true, className: 'spacing-v-15', children: [ - Widget.Box({ - vertical: true, - css: 'margin-bottom: 0.682rem;', - children: [ - Widget.Label({ - className: 'txt-title txt', - label: 'Session', - }), - Widget.Label({ - justify: Gtk.Justification.CENTER, - className: 'txt-small txt', - label: 'Use arrow keys to navigate.\nEnter to select, Esc to cancel.' - }), - ] - }), - Widget.Box({ - hpack: 'center', - className: 'spacing-h-15', - children: [ // lock, logout, sleep - lockButton, - logoutButton, - sleepButton, - ] - }), - Widget.Box({ - hpack: 'center', - className: 'spacing-h-15', - children: [ // hibernate, shutdown, reboot - hibernateButton, - shutdownButton, - rebootButton, - ] - }), - Widget.Box({ - hpack: 'center', - className: 'spacing-h-15', - children: [ // hibernate, shutdown, reboot - cancelButton, - ] - }), + sessionDescription, + ...sessionButtonRows, ] }) ] diff --git a/.config/ags/scss/_material.scss b/.config/ags/scss/_material.scss index cfab8e9f3..6bc96ab69 100644 --- a/.config/ags/scss/_material.scss +++ b/.config/ags/scss/_material.scss @@ -1,30 +1,29 @@ $darkmode: true; -$primary: #e2e2e2; -$onPrimary: #000000; -$primaryContainer: #6b6b6b; -$onPrimaryContainer: #e2e2e2; -$secondary: #e2e2e2; -$onSecondary: #000000; -$secondaryContainer: #313131; -$onSecondaryContainer: #e2e2e2; -$tertiary: #e2e2e2; -$onTertiary: #000000; -$tertiaryContainer: #000000; -$onTertiaryContainer: #e2e2e2; -$error: #e2e2e2; -$onError: #000000; -$errorContainer: #000000; -$onErrorContainer: #e2e2e2; -$colorbarbg: #000000; -$background: #000000; -$onBackground: #e2e2e2; -$surface: #161616; -$onSurface: #e2e2e2; -$surfaceVariant: #242424; -$onSurfaceVariant: #e2e2e2; -$outline: #a1a1a1; +$primary: #ffb4a9; +$onPrimary: #5f1410; +$primaryContainer: #7e2b24; +$onPrimaryContainer: #ffdad4; +$secondary: #e7bcb7; +$onSecondary: #442926; +$secondaryContainer: #5d3f3b; +$onSecondaryContainer: #ffdad5; +$tertiary: #e0c38c; +$onTertiary: #3f2e04; +$tertiaryContainer: #574419; +$onTertiaryContainer: #fddfa6; +$error: #ffb4a9; +$onError: #680003; +$errorContainer: #930006; +$onErrorContainer: #ffb4a9; +$colorbarbg: #130F0F; +$background: #130F0F; +$onBackground: #ede0de; +$surface: #211a19; +$onSurface: #ede0de; +$surfaceVariant: #534341; +$onSurfaceVariant: #d8c2bf; +$outline: #a08c89; $shadow: #000000; -$inverseSurface: #e2e2e2; -$inverseOnSurface: #000000; -$inversePrimary: #e2e2e2; - +$inverseSurface: #ede0de; +$inverseOnSurface: #362f2e; +$inversePrimary: #9c4239; diff --git a/.config/ags/scss/_musicmaterial.scss b/.config/ags/scss/_musicmaterial.scss index e69de29bb..8b1378917 100644 --- a/.config/ags/scss/_musicmaterial.scss +++ b/.config/ags/scss/_musicmaterial.scss @@ -0,0 +1 @@ + diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js new file mode 100644 index 000000000..65044da7f --- /dev/null +++ b/.config/ags/user_options.js @@ -0,0 +1,43 @@ + +let userConfigOptions = { + 'battery': { + 'low': 20, + 'critical': 10, + }, + 'music': { + 'preferredPlayer': 'plasma-browser-integration', + }, + 'onScreenKeyboard': { + 'layout': 'qwerty_full', // See modules/onscreenkeyboard/onscreenkeyboard.js for available layouts + }, + 'overview': { + 'scale': 0.18, + 'numOfRows': 2, + 'numOfCols': 5, + 'wsNumScale': 0.09, + 'wsNumMarginScale': 0.07, + }, + 'search': { + 'excludedSites': ['quora.com'], // Exclude bullshit + }, + 'weather': { + 'city': '', + }, + 'workspaces': { + 'shown': 10, + }, + icons: { + substitutions: { + 'code-url-handler': 'visual-studio-code', + 'Code': 'visual-studio-code', + 'GitHub Desktop': 'github-desktop', + 'wps': 'wps-office2019-kprometheus', + 'gnome-tweaks': 'org.gnome.tweaks', + 'Minecraft* 1.20.1': 'minecraft', + '': 'image-missing', + } + } +} + +globalThis['userOptions'] = userConfigOptions; +export default userOptions; \ No newline at end of file From b1b4fd4394866ee95e3bc1d0b5d4f42dbd2453a9 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Fri, 1 Mar 2024 23:49:18 +0700 Subject: [PATCH 042/517] user config round 2 (#271) --- .config/ags/modules/.miscutils/files.js | 14 +++++++++ .../ags/modules/indicators/musiccontrols.js | 12 +++----- .../modules/sideleft/apis/ai_chatmessage.js | 3 +- .config/ags/modules/sideleft/apis/waifu.js | 8 ++--- .config/ags/modules/sideleft/apiwidgets.js | 1 - .config/ags/modules/sideleft/sideleft.js | 2 +- .config/ags/modules/sideleft/toolbox.js | 4 +-- .../modules/sideleft/tools/quickscripts.js | 1 - .config/ags/modules/sideright/calendar.js | 5 ---- .config/ags/modules/sideright/quicktoggles.js | 10 +------ .config/ags/scss/_musicmaterial.scss | 30 ++++++++++++++++++- .config/ags/services/gemini.js | 20 ++++--------- .config/ags/services/gpt.js | 6 ++-- .config/ags/services/messages.js | 1 - .config/ags/user_options.js | 10 ++++++- 15 files changed, 71 insertions(+), 56 deletions(-) create mode 100644 .config/ags/modules/.miscutils/files.js diff --git a/.config/ags/modules/.miscutils/files.js b/.config/ags/modules/.miscutils/files.js new file mode 100644 index 000000000..00c17b916 --- /dev/null +++ b/.config/ags/modules/.miscutils/files.js @@ -0,0 +1,14 @@ +const { Gio, GLib, Gtk } = imports.gi; + +export function fileExists(filePath) { + let file = Gio.File.new_for_path(filePath); + return file.query_exists(null); +} + +export function expandTilde(path) { + if (path.startsWith('~')) { + return GLib.get_home_dir() + path.slice(1); + } else { + return path; + } +} \ No newline at end of file diff --git a/.config/ags/modules/indicators/musiccontrols.js b/.config/ags/modules/indicators/musiccontrols.js index 6fd44847a..f3e8b01e4 100644 --- a/.config/ags/modules/indicators/musiccontrols.js +++ b/.config/ags/modules/indicators/musiccontrols.js @@ -1,16 +1,16 @@ -const { Gdk, GdkPixbuf, Gio, GLib, Gtk } = imports.gi; +const { Gdk, GdkPixbuf, GLib, Gtk } = imports.gi; import App from 'resource:///com/github/Aylur/ags/app.js'; import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; -const { exec, execAsync } = Utils; import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js'; - +const { exec, execAsync } = Utils; const { Box, EventBox, Icon, Scrollable, Label, Button, Revealer } = Widget; + +import { fileExists } from '../.miscutils/files.js'; import { AnimatedCircProg } from "../.commonwidgets/cairo_circularprogress.js"; import { showMusicControls } from '../../variables.js'; const COMPILED_STYLE_DIR = `${GLib.get_user_cache_dir()}/ags/user/generated` - const LIGHTDARK_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/colormode.txt`; const lightDark = Utils.readFile(LIGHTDARK_FILE_LOCATION).trim(); const COVER_COLORSCHEME_SUFFIX = '_colorscheme.css'; @@ -31,10 +31,6 @@ function lengthStr(length) { const sec0 = sec < 10 ? '0' : ''; return `${min}:${sec0}${sec}`; } -function fileExists(filePath) { - let file = Gio.File.new_for_path(filePath); - return file.query_exists(null); -} function detectMediaSource(link) { if (link.startsWith("file://")) { diff --git a/.config/ags/modules/sideleft/apis/ai_chatmessage.js b/.config/ags/modules/sideleft/apis/ai_chatmessage.js index 1c79b3a1c..e7ad848f8 100644 --- a/.config/ags/modules/sideleft/apis/ai_chatmessage.js +++ b/.config/ags/modules/sideleft/apis/ai_chatmessage.js @@ -12,7 +12,6 @@ const LATEX_DIR = `${GLib.get_user_cache_dir()}/ags/media/latex`; const CUSTOM_SOURCEVIEW_SCHEME_PATH = `${App.configDir}/assets/themes/sourceviewtheme.xml`; const CUSTOM_SCHEME_ID = 'custom'; const USERNAME = GLib.get_user_name(); -const AI_MESSAGE_CURSOR = ' ...'; /////////////////////// Custom source view colorscheme ///////////////////////// @@ -258,7 +257,7 @@ const MessageContent = (content) => { const lastLabel = kids[kids.length - 1]; let blockContent = lines.slice(lastProcessed, lines.length).join('\n'); if (!inCode) - lastLabel.label = `${md2pango(blockContent)}${useCursor ? AI_MESSAGE_CURSOR : ''}`; + lastLabel.label = `${md2pango(blockContent)}${useCursor ? userOptions.ai.writingCursor : ''}`; else lastLabel.attribute.updateText(blockContent); } diff --git a/.config/ags/modules/sideleft/apis/waifu.js b/.config/ags/modules/sideleft/apis/waifu.js index e2efe341c..9bda586e8 100644 --- a/.config/ags/modules/sideleft/apis/waifu.js +++ b/.config/ags/modules/sideleft/apis/waifu.js @@ -6,6 +6,7 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; const { Box, Button, Label, Overlay, Revealer, Scrollable, Stack } = Widget; const { execAsync, exec } = Utils; +import { fileExists } from '../../.miscutils/files.js'; import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; import { MarginRevealer } from '../../.widgethacks/advancedrevealers.js'; import { setupCursorHover, setupCursorHoverInfo } from '../../.widgetutils/cursorhover.js'; @@ -20,18 +21,13 @@ async function getImageViewerApp(preferredApp) { } const IMAGE_REVEAL_DELAY = 13; // Some wait for inits n other weird stuff -const IMAGE_VIEWER_APP = getImageViewerApp('loupe'); // Gnome's image viewer cuz very comfortable zooming +const IMAGE_VIEWER_APP = getImageViewerApp(userOptions.apps.imageViewer); // Gnome's image viewer cuz very comfortable zooming const USER_CACHE_DIR = GLib.get_user_cache_dir(); // Create cache folder and clear pics from previous session Utils.exec(`bash -c 'mkdir -p ${USER_CACHE_DIR}/ags/media/waifus'`); Utils.exec(`bash -c 'rm ${USER_CACHE_DIR}/ags/media/waifus/*'`); -export function fileExists(filePath) { - let file = Gio.File.new_for_path(filePath); - return file.query_exists(null); -} - const CommandButton = (command) => Button({ className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small', onClicked: () => sendMessage(command), diff --git a/.config/ags/modules/sideleft/apiwidgets.js b/.config/ags/modules/sideleft/apiwidgets.js index ac89b6a66..c950c8a05 100644 --- a/.config/ags/modules/sideleft/apiwidgets.js +++ b/.config/ags/modules/sideleft/apiwidgets.js @@ -14,7 +14,6 @@ import { waifuView, waifuCommands, sendMessage as waifuSendMessage, waifuTabIcon import { enableClickthrough } from "../.widgetutils/clickthrough.js"; const TextView = Widget.subclass(Gtk.TextView, "AgsTextView"); - const EXPAND_INPUT_THRESHOLD = 30; const APIS = [ { diff --git a/.config/ags/modules/sideleft/sideleft.js b/.config/ags/modules/sideleft/sideleft.js index 82dbe204b..87a1b70ed 100644 --- a/.config/ags/modules/sideleft/sideleft.js +++ b/.config/ags/modules/sideleft/sideleft.js @@ -9,7 +9,7 @@ import { setupCursorHover } from '../.widgetutils/cursorhover.js'; import { NavigationIndicator } from '../.commonwidgets/cairo_navigationindicator.js'; import toolBox from './toolbox.js'; import apiWidgets from './apiwidgets.js'; -import apiwidgets, { chatEntry } from './apiwidgets.js'; +import { chatEntry } from './apiwidgets.js'; const contents = [ { diff --git a/.config/ags/modules/sideleft/toolbox.js b/.config/ags/modules/sideleft/toolbox.js index 9ecb98b92..a78c087a0 100644 --- a/.config/ags/modules/sideleft/toolbox.js +++ b/.config/ags/modules/sideleft/toolbox.js @@ -1,7 +1,5 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js'; -import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; -const { Box, Button, EventBox, Label, Revealer, Scrollable, Stack } = Widget; -const { execAsync, exec } = Utils; +const { Box, Scrollable } = Widget; import QuickScripts from './tools/quickscripts.js'; import ColorPicker from './tools/colorpicker.js'; diff --git a/.config/ags/modules/sideleft/tools/quickscripts.js b/.config/ags/modules/sideleft/tools/quickscripts.js index 5b3fbec8e..d1004e6a9 100644 --- a/.config/ags/modules/sideleft/tools/quickscripts.js +++ b/.config/ags/modules/sideleft/tools/quickscripts.js @@ -11,7 +11,6 @@ import { setupCursorHover } from '../../.widgetutils/cursorhover.js'; Gtk.IconTheme.get_default().append_search_path(`${App.configDir}/assets/icons`); import { distroID, isArchDistro, isDebianDistro, hasFlatpak } from '../../.miscutils/system.js'; - const scripts = [ { icon: 'nixos-symbolic', diff --git a/.config/ags/modules/sideright/calendar.js b/.config/ags/modules/sideright/calendar.js index 9d0a843ec..817d0b2df 100644 --- a/.config/ags/modules/sideright/calendar.js +++ b/.config/ags/modules/sideright/calendar.js @@ -11,11 +11,6 @@ import { getCalendarLayout } from "./calendar_layout.js"; let calendarJson = getCalendarLayout(undefined, true); let monthshift = 0; -function fileExists(filePath) { - let file = Gio.File.new_for_path(filePath); - return file.query_exists(null); -} - function getDateInXMonthsTime(x) { var currentDate = new Date(); // Get the current date var targetMonth = currentDate.getMonth() + x; // Calculate the target month diff --git a/.config/ags/modules/sideright/quicktoggles.js b/.config/ags/modules/sideright/quicktoggles.js index 5cbe8d850..aefc654a0 100644 --- a/.config/ags/modules/sideright/quicktoggles.js +++ b/.config/ags/modules/sideright/quicktoggles.js @@ -10,14 +10,6 @@ import { BluetoothIndicator, NetworkIndicator } from '../.commonwidgets/statusic import { setupCursorHover } from '../.widgetutils/cursorhover.js'; import { MaterialIcon } from '../.commonwidgets/materialicon.js'; -function expandTilde(path) { - if (path.startsWith('~')) { - return GLib.get_home_dir() + path.slice(1); - } else { - return path; - } -} - export const ToggleIconWifi = (props = {}) => Widget.Button({ className: 'txt-small sidebar-iconbutton', tooltipText: 'Wifi | Right-click to configure', @@ -123,7 +115,7 @@ export const ModuleInvertColors = async (props = {}) => { button.toggleClassName('sidebar-button-active', false); } else { - Hyprland.messageAsync(`j/keyword decoration:screen_shader ${expandTilde('~/.config/hypr/shaders/invert.frag')}`) + Hyprland.messageAsync(`j/keyword decoration:screen_shader ${GLib.get_home_dir()}/.config/hypr/shaders/invert.frag`) .catch(print); button.toggleClassName('sidebar-button-active', true); } diff --git a/.config/ags/scss/_musicmaterial.scss b/.config/ags/scss/_musicmaterial.scss index 8b1378917..346fdf6e3 100644 --- a/.config/ags/scss/_musicmaterial.scss +++ b/.config/ags/scss/_musicmaterial.scss @@ -1 +1,29 @@ - +$darkmode: true; +$primary: #8ccdff; +$onPrimary: #003350; +$primaryContainer: #004b73; +$onPrimaryContainer: #cae6ff; +$secondary: #b7c8d9; +$onSecondary: #22323f; +$secondaryContainer: #394856; +$onSecondaryContainer: #d3e4f6; +$tertiary: #d0bfe8; +$onTertiary: #362b4a; +$tertiaryContainer: #4e4162; +$onTertiaryContainer: #eddcff; +$error: #ffb4a9; +$onError: #680003; +$errorContainer: #930006; +$onErrorContainer: #ffb4a9; +$colorbarbg: #0F1012; +$background: #0F1012; +$onBackground: #e2e2e5; +$surface: #1a1c1e; +$onSurface: #e2e2e5; +$surfaceVariant: #41474d; +$onSurfaceVariant: #c2c7ce; +$outline: #8b9198; +$shadow: #000000; +$inverseSurface: #e2e2e5; +$inverseOnSurface: #2f3032; +$inversePrimary: #006497; diff --git a/.config/ags/services/gemini.js b/.config/ags/services/gemini.js index 1caee94ce..a553776b9 100644 --- a/.config/ags/services/gemini.js +++ b/.config/ags/services/gemini.js @@ -4,7 +4,7 @@ import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; import Gio from 'gi://Gio'; import GLib from 'gi://GLib'; import Soup from 'gi://Soup?version=3.0'; -import { fileExists } from './messages.js'; +import { fileExists } from '../modules/.miscutils/files.js'; const initMessages = [ @@ -25,20 +25,12 @@ const initMessages = { role: "model", parts: [{ text: "## Double angle formulas\n```latex\n\\[\n\\sin(2\theta) = 2\\sin(\\theta)\\cos(\\theta)\n\\]\n\\\\\n\\[\n\\cos(2\\theta) = \\cos^2(\\theta) - \\sin^2(\\theta)\n\\]\n\\\\\n\\[\n\\tan(2\theta) = \\frac{2\\tan(\\theta)}{1 - \\tan^2(\\theta)}\n\\]\n```" }], }, ]; -function expandTilde(path) { - if (path.startsWith('~')) { - return GLib.get_home_dir() + path.slice(1); - } else { - return path; - } -} - Utils.exec(`mkdir -p ${GLib.get_user_cache_dir()}/ags/user/ai`); const KEY_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/ai/google_key.txt`; const APIDOM_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/ai/google_api_dom.txt`; function replaceapidom(URL) { - if (fileExists(expandTilde(APIDOM_FILE_LOCATION))) { - var contents = Utils.readFile(expandTilde(APIDOM_FILE_LOCATION)).trim(); + if (fileExists(APIDOM_FILE_LOCATION)) { + var contents = Utils.readFile(APIDOM_FILE_LOCATION).trim(); var URL = URL.toString().replace("generativelanguage.googleapis.com", contents); } return URL; @@ -141,7 +133,7 @@ class GeminiService extends Service { _messages = []; _cycleModels = true; _requestCount = 0; - _temperature = 0.9; + _temperature = userOptions.ai.defaultTemperature; _modelIndex = 0; _key = ''; _decoder = new TextDecoder(); @@ -149,7 +141,7 @@ class GeminiService extends Service { constructor() { super(); - if (fileExists(expandTilde(KEY_FILE_LOCATION))) this._key = Utils.readFile(expandTilde(KEY_FILE_LOCATION)).trim(); + if (fileExists(KEY_FILE_LOCATION)) this._key = Utils.readFile(KEY_FILE_LOCATION).trim(); else this.emit('hasKey', false); if (this._assistantPrompt) this._messages = [...initMessages]; @@ -164,7 +156,7 @@ class GeminiService extends Service { get key() { return this._key } set key(keyValue) { this._key = keyValue; - Utils.writeFile(this._key, expandTilde(KEY_FILE_LOCATION)) + Utils.writeFile(this._key, KEY_FILE_LOCATION) .then(this.emit('hasKey', true)) .catch(err => print(err)); } diff --git a/.config/ags/services/gpt.js b/.config/ags/services/gpt.js index 63727cf85..5d48e67be 100644 --- a/.config/ags/services/gpt.js +++ b/.config/ags/services/gpt.js @@ -4,7 +4,7 @@ import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; import Gio from 'gi://Gio'; import GLib from 'gi://GLib'; import Soup from 'gi://Soup?version=3.0'; -import { fileExists } from './messages.js'; +import { fileExists } from '../modules/.miscutils/files.js'; const PROVIDERS = { // There's this list hmm https://github.com/zukixa/cool-ai-stuff/ 'openai': { @@ -134,10 +134,10 @@ class GPTService extends Service { } _assistantPrompt = true; - _currentProvider = 'openai'; + _currentProvider = userOptions.ai.defaultGPTProvider; _cycleModels = false; _requestCount = 0; - _temperature = 0.9; + _temperature = userOptions.ai.defaultTemperature; _messages = []; _modelIndex = 0; _key = ''; diff --git a/.config/ags/services/messages.js b/.config/ags/services/messages.js index 28bd86008..816813e80 100644 --- a/.config/ags/services/messages.js +++ b/.config/ags/services/messages.js @@ -2,7 +2,6 @@ const { Notify, GLib, Gio } = imports.gi; import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; import Battery from 'resource:///com/github/Aylur/ags/service/battery.js'; - export function fileExists(filePath) { let file = Gio.File.new_for_path(filePath); return file.query_exists(null); diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index 65044da7f..68fed973e 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -1,5 +1,13 @@ let userConfigOptions = { + 'ai': { + 'defaultGPTProvider': 'openai', + 'defaultTemperature': 0.9, + 'writingCursor': ' ...', // Warning: Using weird characters can mess up Markdown rendering + }, + 'apps': { + 'imageViewer': 'loupe', + }, 'battery': { 'low': 20, 'critical': 10, @@ -18,7 +26,7 @@ let userConfigOptions = { 'wsNumMarginScale': 0.07, }, 'search': { - 'excludedSites': ['quora.com'], // Exclude bullshit + 'excludedSites': ['quora.com'], }, 'weather': { 'city': '', From d019482993ad62b7b54f8aba24f3d70384c71c34 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 2 Mar 2024 10:47:23 +0700 Subject: [PATCH 043/517] user options: add search engine url --- .config/ags/modules/overview/searchbuttons.js | 4 ++-- .config/ags/modules/overview/windowcontent.js | 2 +- .config/ags/user_options.js | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.config/ags/modules/overview/searchbuttons.js b/.config/ags/modules/overview/searchbuttons.js index 8fb40a23a..e90957d14 100644 --- a/.config/ags/modules/overview/searchbuttons.js +++ b/.config/ags/modules/overview/searchbuttons.js @@ -153,11 +153,11 @@ export const CustomCommandButton = ({ text = '' }) => searchItem({ export const SearchButton = ({ text = '' }) => searchItem({ materialIconName: 'travel_explore', - name: 'Search Google', + name: 'Search the web', actionName: 'Go', content: `${text}`, onActivate: () => { App.closeWindow('overview'); - execAsync(['bash', '-c', `xdg-open 'https://www.google.com/search?q=${text} ${['', ...userOptions.search.excludedSites].join(' -site:')}' &`]).catch(print); + execAsync(['bash', '-c', `xdg-open '${userOptions.search.engineBaseUrl}${text} ${['', ...userOptions.search.excludedSites].join(' -site:')}' &`]).catch(print); }, }); \ No newline at end of file diff --git a/.config/ags/modules/overview/windowcontent.js b/.config/ags/modules/overview/windowcontent.js index 179739a7e..606c7c4eb 100644 --- a/.config/ags/modules/overview/windowcontent.js +++ b/.config/ags/modules/overview/windowcontent.js @@ -140,7 +140,7 @@ export const SearchAndWindows = () => { else { App.closeWindow('overview'); - execAsync(['bash', '-c', `xdg-open 'https://www.google.com/search?q=${text} ${['', ...userOptions.search.excludedSites].join(' -site:')}' &`]).catch(print); + execAsync(['bash', '-c', `xdg-open '${userOptions.search.engineBaseUrl}${text} ${['', ...userOptions.search.excludedSites].join(' -site:')}' &`]).catch(print); } }, onChange: (entry) => { // this is when you type diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index 68fed973e..943de4686 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -26,6 +26,7 @@ let userConfigOptions = { 'wsNumMarginScale': 0.07, }, 'search': { + 'engineBaseUrl': 'https://www.google.com/search?q=', 'excludedSites': ['quora.com'], }, 'weather': { From b9294c46dc5ca6f4bd3a1ea640010a823b14af03 Mon Sep 17 00:00:00 2001 From: clsty Date: Sat, 2 Mar 2024 19:07:21 +0800 Subject: [PATCH 044/517] Not overwrite user_options.js --- install.sh | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 836c14f9d..bd5cf558a 100755 --- a/install.sh +++ b/install.sh @@ -146,14 +146,24 @@ v mkdir -p "$HOME"/.{config,cache,local/{bin,share}} # original dotfiles and new ones in the SAME DIRECTORY # (eg. in ~/.config/hypr) won't be mixed together -for i in .config/* -do +# For .config/* but not AGS +for file in $(find .config/ -mindepth 1 -maxdepth 1 ! -name 'ags' -exec basename {} \;); do echo "[$0]: Found target: $i" if [ -d "$i" ];then v rsync -av --delete "$i/" "$HOME/$i/" elif [ -f "$i" ];then v rsync -av "$i" "$HOME/$i" fi done +# For AGS +v rsync -av --delete --exclude '/user_options.js' .config/ags/ "$HOME"/.config/ags/ +t="$HOME/.config/ags/user_options.js" +if [ -f $t ];then + echo -e "\e[34m[$0]: \"$t\" already exists.\e[0m" +else + echo -e "\e[33m[$0]: \"$t\" does not exist yet.\e[0m" + v cp .config/ags/user_options.js $t +fi + # target="$HOME/.config/hypr/colors.conf" # test -f $target || { \ # echo -e "\e[34m[$0]: File \"$target\" not found.\e[0m" && \ From d8a2f317b7036aa66b4f3c6940c539e4d2859750 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 2 Mar 2024 19:12:46 +0700 Subject: [PATCH 045/517] overview: fix workspace focus on click --- .config/ags/modules/overview/overview_hyprland.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.config/ags/modules/overview/overview_hyprland.js b/.config/ags/modules/overview/overview_hyprland.js index 55ef9f150..e7cefc7dd 100644 --- a/.config/ags/modules/overview/overview_hyprland.js +++ b/.config/ags/modules/overview/overview_hyprland.js @@ -18,6 +18,7 @@ import { substitute } from "../.miscutils/icons.js"; const NUM_OF_WORKSPACES_SHOWN = userOptions.overview.numOfCols * userOptions.overview.numOfRows; const TARGET = [Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags.SAME_APP, 0)]; +const POPUP_CLOSE_TIME = 100; // ms const overviewTick = Variable(false); @@ -86,7 +87,7 @@ export default () => { `, onClicked: (self) => { App.closeWindow('overview'); - Utils.timeout(100, () => Hyprland.messageAsync(`dispatch focuswindow address:${address}`)); + Utils.timeout(POPUP_CLOSE_TIME, () => Hyprland.messageAsync(`dispatch focuswindow address:${address}`)); }, onMiddleClickRelease: () => Hyprland.messageAsync(`dispatch closewindow address:${address}`), onSecondaryClick: (button) => { @@ -226,8 +227,8 @@ export default () => { hexpand: true, vexpand: true, onPrimaryClick: () => { - Hyprland.messageAsync(`dispatch workspace ${index}`) App.closeWindow('overview'); + Utils.timeout(POPUP_CLOSE_TIME, () => Hyprland.messageAsync(`dispatch workspace ${index}`)); }, setup: (eventbox) => { eventbox.drag_dest_set(Gtk.DestDefaults.ALL, TARGET, Gdk.DragAction.COPY); From 6ee8b2b1235052d9aaed2f3cd200a6e29f1813e0 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 2 Mar 2024 19:13:23 +0700 Subject: [PATCH 046/517] cleaner search path append --- .config/ags/modules/sideleft/apis/ai_chatmessage.js | 2 +- .config/ags/modules/sideleft/apis/chatgpt.js | 2 -- .config/ags/modules/sideleft/apis/gemini.js | 1 - .config/ags/modules/sideleft/tools/quickscripts.js | 1 - .config/ags/variables.js | 4 +++- 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.config/ags/modules/sideleft/apis/ai_chatmessage.js b/.config/ags/modules/sideleft/apis/ai_chatmessage.js index e7ad848f8..775252324 100644 --- a/.config/ags/modules/sideleft/apis/ai_chatmessage.js +++ b/.config/ags/modules/sideleft/apis/ai_chatmessage.js @@ -12,6 +12,7 @@ const LATEX_DIR = `${GLib.get_user_cache_dir()}/ags/media/latex`; const CUSTOM_SOURCEVIEW_SCHEME_PATH = `${App.configDir}/assets/themes/sourceviewtheme.xml`; const CUSTOM_SCHEME_ID = 'custom'; const USERNAME = GLib.get_user_name(); +Gtk.IconTheme.get_default().append_search_path(LATEX_DIR); /////////////////////// Custom source view colorscheme ///////////////////////// @@ -108,7 +109,6 @@ LaTeX -headless -input="$text" -output=${outFilePath} -textsize=${fontSize * 1.1 Utils.exec(`chmod a+x ${scriptFilePath}`) Utils.timeout(100, () => { Utils.exec(`bash ${scriptFilePath}`); - Gtk.IconTheme.get_default().append_search_path(LATEX_DIR); self.child?.destroy(); self.child = Gtk.Image.new_from_file(outFilePath); }) diff --git a/.config/ags/modules/sideleft/apis/chatgpt.js b/.config/ags/modules/sideleft/apis/chatgpt.js index c3e657aab..ab6067c42 100644 --- a/.config/ags/modules/sideleft/apis/chatgpt.js +++ b/.config/ags/modules/sideleft/apis/chatgpt.js @@ -12,8 +12,6 @@ import { markdownTest } from '../../.miscutils/md2pango.js'; import { MarginRevealer } from '../../.widgethacks/advancedrevealers.js'; import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; -Gtk.IconTheme.get_default().append_search_path(`${App.configDir}/assets/icons`); - export const chatGPTTabIcon = Icon({ hpack: 'center', className: 'sidebar-chat-apiswitcher-icon', diff --git a/.config/ags/modules/sideleft/apis/gemini.js b/.config/ags/modules/sideleft/apis/gemini.js index 7da16e435..2ed539d5f 100644 --- a/.config/ags/modules/sideleft/apis/gemini.js +++ b/.config/ags/modules/sideleft/apis/gemini.js @@ -11,7 +11,6 @@ import { ConfigToggle, ConfigSegmentedSelection, ConfigGap } from '../../.common import { markdownTest } from '../../.miscutils/md2pango.js'; import { MarginRevealer } from '../../.widgethacks/advancedrevealers.js'; -Gtk.IconTheme.get_default().append_search_path(`${App.configDir}/assets/icons`); const MODEL_NAME = `Gemini`; export const geminiTabIcon = Icon({ diff --git a/.config/ags/modules/sideleft/tools/quickscripts.js b/.config/ags/modules/sideleft/tools/quickscripts.js index d1004e6a9..fea8dc40f 100644 --- a/.config/ags/modules/sideleft/tools/quickscripts.js +++ b/.config/ags/modules/sideleft/tools/quickscripts.js @@ -8,7 +8,6 @@ import SidebarModule from './module.js'; import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; import { setupCursorHover } from '../../.widgetutils/cursorhover.js'; -Gtk.IconTheme.get_default().append_search_path(`${App.configDir}/assets/icons`); import { distroID, isArchDistro, isDebianDistro, hasFlatpak } from '../../.miscutils/system.js'; const scripts = [ diff --git a/.config/ags/variables.js b/.config/ags/variables.js index 29e390001..b743fe752 100644 --- a/.config/ags/variables.js +++ b/.config/ags/variables.js @@ -1,7 +1,9 @@ +const { Gtk } = imports.gi; import Variable from 'resource:///com/github/Aylur/ags/variable.js'; import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js'; const { exec, execAsync } = Utils; -import Gdk from 'gi://Gdk'; + +Gtk.IconTheme.get_default().append_search_path(`${App.configDir}/assets/icons`); // Global vars for external control (through keybinds) export const showMusicControls = Variable(false, {}) From abf79914d0e562cff52f01205845e75f1d21e0cf Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 2 Mar 2024 19:13:44 +0700 Subject: [PATCH 047/517] add and sort icon substitutions --- .config/ags/user_options.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index 943de4686..56ae15c11 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -3,7 +3,7 @@ let userConfigOptions = { 'ai': { 'defaultGPTProvider': 'openai', 'defaultTemperature': 0.9, - 'writingCursor': ' ...', // Warning: Using weird characters can mess up Markdown rendering + 'writingCursor': ' ...', // Warning: Using weird characters can mess up Markdown rendering }, 'apps': { 'imageViewer': 'loupe', @@ -19,7 +19,7 @@ let userConfigOptions = { 'layout': 'qwerty_full', // See modules/onscreenkeyboard/onscreenkeyboard.js for available layouts }, 'overview': { - 'scale': 0.18, + 'scale': 0.18, // Relative to screen size 'numOfRows': 2, 'numOfCols': 5, 'wsNumScale': 0.09, @@ -40,9 +40,10 @@ let userConfigOptions = { 'code-url-handler': 'visual-studio-code', 'Code': 'visual-studio-code', 'GitHub Desktop': 'github-desktop', - 'wps': 'wps-office2019-kprometheus', - 'gnome-tweaks': 'org.gnome.tweaks', 'Minecraft* 1.20.1': 'minecraft', + 'gnome-tweaks': 'org.gnome.tweaks', + 'wps': 'wps-office2019-kprometheus', + 'wpsoffice': 'wps-office2019-kprometheus', '': 'image-missing', } } From 15adebe857af53102c8035b99940ebb5d97913b9 Mon Sep 17 00:00:00 2001 From: clsty Date: Sat, 2 Mar 2024 21:27:09 +0800 Subject: [PATCH 048/517] Move general config into hyprland/general.conf --- .config/hypr/hyprland.conf | 167 +---------------------------- .config/hypr/hyprland/general.conf | 150 ++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 162 deletions(-) create mode 100644 .config/hypr/hyprland/general.conf diff --git a/.config/hypr/hyprland.conf b/.config/hypr/hyprland.conf index 4843a0a2d..dc56d1c13 100644 --- a/.config/hypr/hyprland.conf +++ b/.config/hypr/hyprland.conf @@ -1,169 +1,12 @@ -# This file contains general customization options -# For Environment variables see env.conf -# For Keybinds variables see keybinds.conf -# For Auto-run stuff see execs.conf -# For Window/layer rules see rules.conf - +# General customization options +source=~/.config/hypr/hyprland/general.conf +# Environment variables source=~/.config/hypr/hyprland/env.conf - -# MONITOR CONFIG -monitor=,preferred,auto,1 -monitor=,addreserved, 0, 0, 0, 0 - -# monitor=HDMI-A-1,1920x1080@60,1920x0,1,mirror,eDP-1 - -# Startup executions +# Startup executions, Auto-run stuff source=~/.config/hypr/hyprland/execs.conf - -input { - # Keyboard: Add a layout and uncomment kb_options for Win+Space switching shortcut - kb_layout = us - # kb_options = grp:win_space_toggle - numlock_by_default = true - repeat_delay = 250 - repeat_rate = 35 - - touchpad { - natural_scroll = yes - disable_while_typing = true - clickfinger_behavior = true - scroll_factor = 0.5 - } - - special_fallthrough = true - follow_mouse = 1 -} - -binds { - # focus_window_on_workspace_c# For Auto-run stuff see execs.confhange = true - scroll_event_delay = 0 -} - -gestures { - workspace_swipe = true - workspace_swipe_distance = 700 - workspace_swipe_fingers = 4 - workspace_swipe_cancel_ratio = 0.2 - workspace_swipe_min_speed_to_force = 5 - workspace_swipe_direction_lock = true - workspace_swipe_direction_lock_threshold = 10 - workspace_swipe_create_new = true -} - -general { - # Gaps and border - gaps_in = 4 - gaps_out = 5 - gaps_workspaces = 50 - border_size = 1 - - # Fallback colors - col.active_border = rgba(0DB7D4FF) - col.inactive_border = rgba(31313600) - - resize_on_border = true - no_focus_fallback = true - layout = dwindle - - #focus_to_other_workspaces = true # ahhhh i still haven't properly implemented this - allow_tearing = false # some guy told me tearing might make things smoother idk -} - -dwindle { - preserve_split = true - # no_gaps_when_only = 1 - smart_split = false - smart_resizing = false -} - -decoration { - rounding = 20 - - blur { - enabled = true - xray = true - special = false - new_optimizations = true - size = 5 - passes = 4 - brightness = 1 - noise = 0.01 - contrast = 1 - } - # Shadow - drop_shadow = false - shadow_ignore_window = true - shadow_range = 20 - shadow_offset = 0 2 - shadow_render_power = 2 - col.shadow = rgba(0000001A) - - # Shader - # screen_shader = ~/.config/hypr/shaders/nothing.frag - # screen_shader = ~/.config/hypr/shaders/vibrance.frag - - # Dim - dim_inactive = false - dim_strength = 0.1 - dim_special = 0 -} - -animations { - enabled = true - # Animation curves - - bezier = linear, 0, 0, 1, 1 - bezier = md3_standard, 0.2, 0, 0, 1 - bezier = md3_decel, 0.05, 0.7, 0.1, 1 - bezier = md3_accel, 0.3, 0, 0.8, 0.15 - bezier = overshot, 0.05, 0.9, 0.1, 1.1 - bezier = crazyshot, 0.1, 1.5, 0.76, 0.92 - bezier = hyprnostretch, 0.05, 0.9, 0.1, 1.0 - bezier = fluent_decel, 0.1, 1, 0, 1 - bezier = easeInOutCirc, 0.85, 0, 0.15, 1 - bezier = easeOutCirc, 0, 0.55, 0.45, 1 - bezier = easeOutExpo, 0.16, 1, 0.3, 1 - # Animation configs - animation = windows, 1, 3, md3_decel, popin 60% - animation = border, 1, 10, default - animation = fade, 1, 2.5, md3_decel - # animation = workspaces, 1, 3.5, md3_decel, slide - animation = workspaces, 1, 7, fluent_decel, slide - # animation = workspaces, 1, 7, fluent_decel, slidefade 15% - # animation = specialWorkspace, 1, 3, md3_decel, slidefadevert 15% - animation = specialWorkspace, 1, 3, md3_decel, slidevert -} - -misc { - vfr = 1 - vrr = 1 - # layers_hog_mouse_focus = true - focus_on_activate = true - animate_manual_resizes = false - animate_mouse_windowdragging = false - enable_swallow = false - swallow_regex = (foot|kitty|allacritty|Alacritty) - - disable_hyprland_logo = true - force_default_wallpaper = 0 - new_window_takes_over_fullscreen = 2 -} - -debug { - # overlay = true - # damage_tracking = 0 - - # damage_blink = yes -} - # Window and layer rules -layerrule = noanim, selection source=~/.config/hypr/hyprland/rules.conf - # Dynamic colors source=~/.config/hypr/hyprland/colors.conf - -# Keybinds +# Keybinds variables source=~/.config/hypr/hyprland/keybinds.conf - -windowrulev2=rounding 20, onworkspace:1 diff --git a/.config/hypr/hyprland/general.conf b/.config/hypr/hyprland/general.conf new file mode 100644 index 000000000..1949f6754 --- /dev/null +++ b/.config/hypr/hyprland/general.conf @@ -0,0 +1,150 @@ +# MONITOR CONFIG +monitor=,preferred,auto,1 +monitor=,addreserved, 0, 0, 0, 0 + +# monitor=HDMI-A-1,1920x1080@60,1920x0,1,mirror,eDP-1 + +input { + # Keyboard: Add a layout and uncomment kb_options for Win+Space switching shortcut + kb_layout = us + # kb_options = grp:win_space_toggle + numlock_by_default = true + repeat_delay = 250 + repeat_rate = 35 + + touchpad { + natural_scroll = yes + disable_while_typing = true + clickfinger_behavior = true + scroll_factor = 0.5 + } + + special_fallthrough = true + follow_mouse = 1 +} + +binds { + # focus_window_on_workspace_c# For Auto-run stuff see execs.confhange = true + scroll_event_delay = 0 +} + +gestures { + workspace_swipe = true + workspace_swipe_distance = 700 + workspace_swipe_fingers = 4 + workspace_swipe_cancel_ratio = 0.2 + workspace_swipe_min_speed_to_force = 5 + workspace_swipe_direction_lock = true + workspace_swipe_direction_lock_threshold = 10 + workspace_swipe_create_new = true +} + +general { + # Gaps and border + gaps_in = 4 + gaps_out = 5 + gaps_workspaces = 50 + border_size = 1 + + # Fallback colors + col.active_border = rgba(0DB7D4FF) + col.inactive_border = rgba(31313600) + + resize_on_border = true + no_focus_fallback = true + layout = dwindle + + #focus_to_other_workspaces = true # ahhhh i still haven't properly implemented this + allow_tearing = false # some guy told me tearing might make things smoother idk +} + +dwindle { + preserve_split = true + # no_gaps_when_only = 1 + smart_split = false + smart_resizing = false +} + +decoration { + rounding = 20 + + blur { + enabled = true + xray = true + special = false + new_optimizations = true + size = 5 + passes = 4 + brightness = 1 + noise = 0.01 + contrast = 1 + } + # Shadow + drop_shadow = false + shadow_ignore_window = true + shadow_range = 20 + shadow_offset = 0 2 + shadow_render_power = 2 + col.shadow = rgba(0000001A) + + # Shader + # screen_shader = ~/.config/hypr/shaders/nothing.frag + # screen_shader = ~/.config/hypr/shaders/vibrance.frag + + # Dim + dim_inactive = false + dim_strength = 0.1 + dim_special = 0 +} + +animations { + enabled = true + # Animation curves + + bezier = linear, 0, 0, 1, 1 + bezier = md3_standard, 0.2, 0, 0, 1 + bezier = md3_decel, 0.05, 0.7, 0.1, 1 + bezier = md3_accel, 0.3, 0, 0.8, 0.15 + bezier = overshot, 0.05, 0.9, 0.1, 1.1 + bezier = crazyshot, 0.1, 1.5, 0.76, 0.92 + bezier = hyprnostretch, 0.05, 0.9, 0.1, 1.0 + bezier = fluent_decel, 0.1, 1, 0, 1 + bezier = easeInOutCirc, 0.85, 0, 0.15, 1 + bezier = easeOutCirc, 0, 0.55, 0.45, 1 + bezier = easeOutExpo, 0.16, 1, 0.3, 1 + # Animation configs + animation = windows, 1, 3, md3_decel, popin 60% + animation = border, 1, 10, default + animation = fade, 1, 2.5, md3_decel + # animation = workspaces, 1, 3.5, md3_decel, slide + animation = workspaces, 1, 7, fluent_decel, slide + # animation = workspaces, 1, 7, fluent_decel, slidefade 15% + # animation = specialWorkspace, 1, 3, md3_decel, slidefadevert 15% + animation = specialWorkspace, 1, 3, md3_decel, slidevert +} + +misc { + vfr = 1 + vrr = 1 + # layers_hog_mouse_focus = true + focus_on_activate = true + animate_manual_resizes = false + animate_mouse_windowdragging = false + enable_swallow = false + swallow_regex = (foot|kitty|allacritty|Alacritty) + + disable_hyprland_logo = true + force_default_wallpaper = 0 + new_window_takes_over_fullscreen = 2 +} + +debug { + # overlay = true + # damage_tracking = 0 + + # damage_blink = yes +} + +# Window and layer rules +layerrule = noanim, selection +windowrulev2=rounding 20, onworkspace:1 From 8c80f745c5e446384dbec9a1f876205ec6a8ff3d Mon Sep 17 00:00:00 2001 From: clsty Date: Sat, 2 Mar 2024 21:47:03 +0800 Subject: [PATCH 049/517] Not overwrite "custom" folder (#271) --- install.sh | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/install.sh b/install.sh index bd5cf558a..21667d8aa 100755 --- a/install.sh +++ b/install.sh @@ -146,8 +146,8 @@ v mkdir -p "$HOME"/.{config,cache,local/{bin,share}} # original dotfiles and new ones in the SAME DIRECTORY # (eg. in ~/.config/hypr) won't be mixed together -# For .config/* but not AGS -for file in $(find .config/ -mindepth 1 -maxdepth 1 ! -name 'ags' -exec basename {} \;); do +# For .config/* but not AGS, not Hyprland +for file in $(find .config/ -mindepth 1 -maxdepth 1 ! -name 'ags' ! -name 'hypr' -exec basename {} \;); do echo "[$0]: Found target: $i" if [ -d "$i" ];then v rsync -av --delete "$i/" "$HOME/$i/" elif [ -f "$i" ];then v rsync -av "$i" "$HOME/$i" @@ -164,10 +164,20 @@ else v cp .config/ags/user_options.js $t fi -# target="$HOME/.config/hypr/colors.conf" -# test -f $target || { \ -# echo -e "\e[34m[$0]: File \"$target\" not found.\e[0m" && \ -# v cp "$HOME/.config/hypr/colors_default.conf" $target ; } +# For Hyprland +v rsync -av --delete --exclude '/custom' --exclude '/hyprland.conf' .config/hypr/ "$HOME"/.config/hypr/ +t="$HOME/.config/hypr/hyprland.conf" +if [ -f $t ];then + echo -e "\e[34m[$0]: \"$t\" already exists.\e[0m" + if [ ! -d "$HOME"/.config/hypr/custom ];then + echo -e "\e[33m[$0]: But it seems that you are not using a \"custom\" folder.\e[0m" + v cp .config/hypr/hyprland.conf $t + fi +else + echo -e "\e[33m[$0]: \"$t\" does not exist yet.\e[0m" + v cp .config/hypr/hyprland.conf $t +fi + # some foldes (eg. .local/bin) should be processed seperately to avoid `--delete' for rsync, # since the files here come from different places, not only about one program. From 4c0cc1237afb49c5802fefb46be3b81f3b3550d6 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 2 Mar 2024 22:35:43 +0700 Subject: [PATCH 050/517] hyprland: add custom config sourcing --- .config/hypr/custom/env.conf | 2 ++ .config/hypr/custom/execs.conf | 2 ++ .config/hypr/custom/general.conf | 2 ++ .config/hypr/custom/keybinds.conf | 2 ++ .config/hypr/custom/rules.conf | 3 +++ .config/hypr/hyprland.conf | 26 +++++++++++++++++++------- .config/hypr/hyprland/general.conf | 13 ++----------- .config/hypr/hyprland/keybinds.conf | 7 +++---- .config/hypr/hyprland/rules.conf | 1 + .config/hypr/hyprlock/status.sh | 13 ++++++++++--- 10 files changed, 46 insertions(+), 25 deletions(-) create mode 100644 .config/hypr/custom/env.conf create mode 100644 .config/hypr/custom/execs.conf create mode 100644 .config/hypr/custom/general.conf create mode 100644 .config/hypr/custom/keybinds.conf create mode 100644 .config/hypr/custom/rules.conf diff --git a/.config/hypr/custom/env.conf b/.config/hypr/custom/env.conf new file mode 100644 index 000000000..4390ed4fb --- /dev/null +++ b/.config/hypr/custom/env.conf @@ -0,0 +1,2 @@ +## You can put extra environment variables here +## https://wiki.hyprland.org/Configuring/Environment-variables/ diff --git a/.config/hypr/custom/execs.conf b/.config/hypr/custom/execs.conf new file mode 100644 index 000000000..cae4ef6c5 --- /dev/null +++ b/.config/hypr/custom/execs.conf @@ -0,0 +1,2 @@ +# You can make apps auto-start here +# Relevant Hyprland wiki section: https://wiki.hyprland.org/Configuring/Keywords/#executing diff --git a/.config/hypr/custom/general.conf b/.config/hypr/custom/general.conf new file mode 100644 index 000000000..f88b956b1 --- /dev/null +++ b/.config/hypr/custom/general.conf @@ -0,0 +1,2 @@ +## Put general config stuff here +## Here's a list of every variable: https://wiki.hyprland.org/Configuring/Variables/ \ No newline at end of file diff --git a/.config/hypr/custom/keybinds.conf b/.config/hypr/custom/keybinds.conf new file mode 100644 index 000000000..fb337e909 --- /dev/null +++ b/.config/hypr/custom/keybinds.conf @@ -0,0 +1,2 @@ +## You can put your preferred keybinds here +## https://wiki.hyprland.org/Configuring/Binds/ \ No newline at end of file diff --git a/.config/hypr/custom/rules.conf b/.config/hypr/custom/rules.conf new file mode 100644 index 000000000..870a1143e --- /dev/null +++ b/.config/hypr/custom/rules.conf @@ -0,0 +1,3 @@ +## You can put custom rules here +## Window/layer rules: https://wiki.hyprland.org/Configuring/Window-Rules/ +## Workspace rules: https://wiki.hyprland.org/Configuring/Workspace-Rules/ diff --git a/.config/hypr/hyprland.conf b/.config/hypr/hyprland.conf index dc56d1c13..2a8706bbd 100644 --- a/.config/hypr/hyprland.conf +++ b/.config/hypr/hyprland.conf @@ -1,12 +1,24 @@ -# General customization options -source=~/.config/hypr/hyprland/general.conf -# Environment variables +# This file sources other files in `hyprland` and `custom` folders +# You wanna add your stuff in file in `custom` + +# Defaults source=~/.config/hypr/hyprland/env.conf -# Startup executions, Auto-run stuff source=~/.config/hypr/hyprland/execs.conf -# Window and layer rules +source=~/.config/hypr/hyprland/general.conf source=~/.config/hypr/hyprland/rules.conf -# Dynamic colors source=~/.config/hypr/hyprland/colors.conf -# Keybinds variables source=~/.config/hypr/hyprland/keybinds.conf + +# Custom +source=~/.config/hypr/custom/env.conf +source=~/.config/hypr/custom/execs.conf +source=~/.config/hypr/custom/general.conf +source=~/.config/hypr/custom/rules.conf +source=~/.config/hypr/custom/keybinds.conf + +# Why is this even here?? cuz 🤓 +debug { + # overlay = true # Show fps n stuff + # damage_tracking = 0 + # damage_blink = yes +} diff --git a/.config/hypr/hyprland/general.conf b/.config/hypr/hyprland/general.conf index 1949f6754..496406cf8 100644 --- a/.config/hypr/hyprland/general.conf +++ b/.config/hypr/hyprland/general.conf @@ -1,7 +1,8 @@ # MONITOR CONFIG monitor=,preferred,auto,1 -monitor=,addreserved, 0, 0, 0, 0 +# monitor=,addreserved, 0, 0, 0, 0 # Custom reserved area +# HDMI port: mirror display. To see device name, use `hyprctl monitors` # monitor=HDMI-A-1,1920x1080@60,1920x0,1,mirror,eDP-1 input { @@ -138,13 +139,3 @@ misc { new_window_takes_over_fullscreen = 2 } -debug { - # overlay = true - # damage_tracking = 0 - - # damage_blink = yes -} - -# Window and layer rules -layerrule = noanim, selection -windowrulev2=rounding 20, onworkspace:1 diff --git a/.config/hypr/hyprland/keybinds.conf b/.config/hypr/hyprland/keybinds.conf index 6b099477d..1951e77c3 100644 --- a/.config/hypr/hyprland/keybinds.conf +++ b/.config/hypr/hyprland/keybinds.conf @@ -37,7 +37,7 @@ bind = Control+Shift+Alt, Delete, exec, pkill wlogout || wlogout -p layer-shell bind = Control+Shift+Alt+Super, Delete, exec, systemctl poweroff # Screenshot, Record, OCR, Color picker, Clipboard history -bind = Super+Shift+Alt, S, exec, grim -g $(slurp $SLURP_ARGS) - | swappy -f - +bind = Super+Shift+Alt, S, exec, grim -g $(slurp) - | swappy -f - bindl=,Print,exec,grim - | wl-copy bind = Super+Shift, S, exec, ~/.config/ags/scripts/grimblast.sh --freeze copy area bind = Super+Alt, R, exec, ~/.config/ags/scripts/record-script.sh @@ -99,9 +99,8 @@ bind = Control+Super, O, exec, hyprctl plugin unload "~/.config/hypr/plugins/dro ## Testing # bind = SuperAlt, f12, exec, notify-send "Hyprland version: $(hyprctl version | head -2 | tail -1 | cut -f2 -d ' ')" "owo" -a 'Hyprland keybind' # bind = Super+Alt, f12, exec, notify-send "Millis since epoch" "$(date +%s%N | cut -b1-13)" -a 'Hyprland keybind' -bind = Super+Alt, f12, exec, notify-send 'Test notification' "Here's a really long message to test truncation and wrapping\nYou can middle click or flick this notification to dismiss it!" -a 'Shell' -A "Test1=I got it!" -A "Test2=Another action" -# bind = Super+Alt, Equal, exec, notify-send "Urgent notification" "Ah hell no" -u critical -a 'Hyprland keybind' -bind = Super+Alt, Equal, exec, notify-send 'hmm' ${SLURP_ARGS} +bind = Super+Alt, f12, exec, notify-send 'Test notification' "Here's a really long message to test truncation and wrapping\nYou can middle click or flick this notification to dismiss it!" -a 'Shell' -A "Test1=I got it!" -A "Test2=Another action" -t 5000 +bind = Super+Alt, Equal, exec, notify-send "Urgent notification" "Ah hell no" -u critical -a 'Hyprland keybind' ############################ Keybinds for Hyprland ############################ # Swap windows diff --git a/.config/hypr/hyprland/rules.conf b/.config/hypr/hyprland/rules.conf index 996fa2fd1..99ef146c9 100644 --- a/.config/hypr/hyprland/rules.conf +++ b/.config/hypr/hyprland/rules.conf @@ -1,5 +1,6 @@ ######## Window rules ######## windowrule = noblur,.* # Disables blur for windows. Substantially improves performance. +layerrule = noanim, selection # windowrule = opacity 0.89 override 0.89 override, .* # Applies transparency to EVERY WINDOW windowrule = float, ^(steam)$ diff --git a/.config/hypr/hyprlock/status.sh b/.config/hypr/hyprlock/status.sh index 794c468f4..dd8063373 100755 --- a/.config/hypr/hyprlock/status.sh +++ b/.config/hypr/hyprlock/status.sh @@ -2,21 +2,28 @@ ############ Variables ############ enable_battery=false +battery_charging=false ####### Check availability ######## for battery in /sys/class/power_supply/*BAT*; do if [[ -f "$battery/uevent" ]]; then enable_battery=true + if [[ $(cat /sys/class/power_supply/*/status | head -1) == "Charging" ]]; then + battery_charging=true + fi break fi done ############# Output ############# if [[ $enable_battery == true ]]; then - if [[ $(cat /sys/class/power_supply/*/status | head -1) == "Charging" ]]; then + if [[ $battery_charging == true ]]; then echo -n "(+) " - fi - echo -n "$(cat /sys/class/power_supply/*/capacity | head -1)"% remaining + fi + echo -n "$(cat /sys/class/power_supply/*/capacity | head -1)"% + if [[ $battery_charging == false ]]; then + echo -n " remaining" + fi fi echo '' \ No newline at end of file From fefab9a791e13ea72850157ccd3240118ff3e52e Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 3 Mar 2024 01:20:30 +0700 Subject: [PATCH 051/517] fix 1px gaps inconsistency --- .config/ags/modules/bar/normal/music.js | 2 +- .config/ags/modules/bar/normal/system.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.config/ags/modules/bar/normal/music.js b/.config/ags/modules/bar/normal/music.js index 0d96b6b11..13ec6c717 100644 --- a/.config/ags/modules/bar/normal/music.js +++ b/.config/ags/modules/bar/normal/music.js @@ -211,7 +211,7 @@ export default () => { onSecondaryClickRelease: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print), onMiddleClickRelease: () => execAsync('playerctl play-pause').catch(print), child: Box({ - className: 'spacing-h-5', + className: 'spacing-h-4', children: [ SystemResourcesOrCustomModule(), BarGroup({ child: musicStuff }), diff --git a/.config/ags/modules/bar/normal/system.js b/.config/ags/modules/bar/normal/system.js index d2d4ee876..4e9c248c1 100644 --- a/.config/ags/modules/bar/normal/system.js +++ b/.config/ags/modules/bar/normal/system.js @@ -30,7 +30,7 @@ const BatBatteryProgress = () => { const BarClock = () => Widget.Box({ vpack: 'center', - className: 'spacing-h-5 txt-onSurfaceVariant bar-clock-box', + className: 'spacing-h-4 txt-onSurfaceVariant bar-clock-box', children: [ Widget.Label({ className: 'bar-clock', @@ -63,7 +63,7 @@ const UtilButton = ({ name, icon, onClicked }) => Button({ const Utilities = () => Box({ hpack: 'center', - className: 'spacing-h-5 txt-onSurfaceVariant', + className: 'spacing-h-4 txt-onSurfaceVariant', children: [ UtilButton({ name: 'Screen snip', icon: 'screenshot_region', onClicked: () => { @@ -136,7 +136,7 @@ const BatteryModule = () => Stack({ transitionDuration: 150, children: { 'laptop': Box({ - className: 'spacing-h-5', children: [ + className: 'spacing-h-4', children: [ BarGroup({ child: Utilities() }), BarGroup({ child: BarBattery() }), ] @@ -145,7 +145,7 @@ const BatteryModule = () => Stack({ child: Box({ hexpand: true, hpack: 'center', - className: 'spacing-h-5', + className: 'spacing-h-4', children: [ MaterialIcon('device_thermostat', 'small'), Label({ @@ -219,7 +219,7 @@ export default () => Widget.EventBox({ onScrollDown: (self) => switchToRelativeWorkspace(self, +1), onPrimaryClick: () => App.toggleWindow('sideright'), child: Widget.Box({ - className: 'spacing-h-5', + className: 'spacing-h-4', children: [ BarGroup({ child: BarClock() }), BatteryModule(), From 38cf72714e3782b119c1cc7ed3e193b3c7f62cbe Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 3 Mar 2024 01:20:56 +0700 Subject: [PATCH 052/517] update sidebar icon color --- .config/ags/scss/_sidebars.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss index 1989c9cb8..b6ecac92d 100644 --- a/.config/ags/scss/_sidebars.scss +++ b/.config/ags/scss/_sidebars.scss @@ -750,8 +750,8 @@ $colorpicker_rounding: 0.341rem; min-height: 4.773rem; min-width: 4.773rem; font-size: 3.076rem; - background-color: $onBackground; - color: $background; + background-color: $secondaryContainer; + color: $onSecondaryContainer; } .sidebar-chat-chip { From 36ca9724fa51f23a62930bdd26271a0e5e42d264 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 3 Mar 2024 01:21:09 +0700 Subject: [PATCH 053/517] more substitution --- .config/ags/user_options.js | 1 + 1 file changed, 1 insertion(+) diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index 56ae15c11..21886a4a3 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -42,6 +42,7 @@ let userConfigOptions = { 'GitHub Desktop': 'github-desktop', 'Minecraft* 1.20.1': 'minecraft', 'gnome-tweaks': 'org.gnome.tweaks', + 'pavucontrol-qt': 'pavucontrol', 'wps': 'wps-office2019-kprometheus', 'wpsoffice': 'wps-office2019-kprometheus', '': 'image-missing', From 1557df5e2404392653b845bb5d2e9508d7c9b88a Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 3 Mar 2024 07:09:17 +0800 Subject: [PATCH 054/517] Copy to *.new when not overwrite --- install.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/install.sh b/install.sh index 21667d8aa..afee7c159 100755 --- a/install.sh +++ b/install.sh @@ -159,6 +159,7 @@ v rsync -av --delete --exclude '/user_options.js' .config/ags/ "$HOME"/.config/a t="$HOME/.config/ags/user_options.js" if [ -f $t ];then echo -e "\e[34m[$0]: \"$t\" already exists.\e[0m" + v cp -f .config/ags/user_options.js $t.new else echo -e "\e[33m[$0]: \"$t\" does not exist yet.\e[0m" v cp .config/ags/user_options.js $t @@ -169,6 +170,7 @@ v rsync -av --delete --exclude '/custom' --exclude '/hyprland.conf' .config/hypr t="$HOME/.config/hypr/hyprland.conf" if [ -f $t ];then echo -e "\e[34m[$0]: \"$t\" already exists.\e[0m" + v cp -f .config/hypr/hyprland.conf $t.new if [ ! -d "$HOME"/.config/hypr/custom ];then echo -e "\e[33m[$0]: But it seems that you are not using a \"custom\" folder.\e[0m" v cp .config/hypr/hyprland.conf $t From b21e0dc13bc98985e6ddd8d5c48207e31ba5362b Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 3 Mar 2024 07:16:01 +0800 Subject: [PATCH 055/517] Sync custom folder if not exists --- install.sh | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/install.sh b/install.sh index afee7c159..395ce8127 100755 --- a/install.sh +++ b/install.sh @@ -171,14 +171,19 @@ t="$HOME/.config/hypr/hyprland.conf" if [ -f $t ];then echo -e "\e[34m[$0]: \"$t\" already exists.\e[0m" v cp -f .config/hypr/hyprland.conf $t.new - if [ ! -d "$HOME"/.config/hypr/custom ];then - echo -e "\e[33m[$0]: But it seems that you are not using a \"custom\" folder.\e[0m" - v cp .config/hypr/hyprland.conf $t - fi +fi else echo -e "\e[33m[$0]: \"$t\" does not exist yet.\e[0m" v cp .config/hypr/hyprland.conf $t fi +t="$HOME/.config/hypr/custom" +if [ -d $t ];then + echo -e "\e[34m[$0]: \"$t\" already exists, will not do anything.\e[0m" +fi +else + echo -e "\e[33m[$0]: \"$t\" does not exist yet.\e[0m" + v rsync -av --delete .config/hypr/custom/ $t/ +fi # some foldes (eg. .local/bin) should be processed seperately to avoid `--delete' for rsync, From a6a8c8dc6a1774dd44cb88c93d9abfb2a3e7947b Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 3 Mar 2024 07:18:35 +0800 Subject: [PATCH 056/517] Fix if fi --- install.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/install.sh b/install.sh index 395ce8127..091a16a53 100755 --- a/install.sh +++ b/install.sh @@ -171,7 +171,6 @@ t="$HOME/.config/hypr/hyprland.conf" if [ -f $t ];then echo -e "\e[34m[$0]: \"$t\" already exists.\e[0m" v cp -f .config/hypr/hyprland.conf $t.new -fi else echo -e "\e[33m[$0]: \"$t\" does not exist yet.\e[0m" v cp .config/hypr/hyprland.conf $t @@ -179,7 +178,6 @@ fi t="$HOME/.config/hypr/custom" if [ -d $t ];then echo -e "\e[34m[$0]: \"$t\" already exists, will not do anything.\e[0m" -fi else echo -e "\e[33m[$0]: \"$t\" does not exist yet.\e[0m" v rsync -av --delete .config/hypr/custom/ $t/ From 1dbd19207c43b50dcfe842fbba75ed57013fc086 Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 3 Mar 2024 07:27:00 +0800 Subject: [PATCH 057/517] Remove duplicated line --- .config/hypr/hyprland/rules.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/.config/hypr/hyprland/rules.conf b/.config/hypr/hyprland/rules.conf index 99ef146c9..996fa2fd1 100644 --- a/.config/hypr/hyprland/rules.conf +++ b/.config/hypr/hyprland/rules.conf @@ -1,6 +1,5 @@ ######## Window rules ######## windowrule = noblur,.* # Disables blur for windows. Substantially improves performance. -layerrule = noanim, selection # windowrule = opacity 0.89 override 0.89 override, .* # Applies transparency to EVERY WINDOW windowrule = float, ^(steam)$ From 9263af26deda09a96c448845f438d96b5d5a1ba8 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 3 Mar 2024 07:49:39 +0700 Subject: [PATCH 058/517] make weather widget readable in light mode (#298) me forgor --- .config/ags/modules/bar/normal/system.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/modules/bar/normal/system.js b/.config/ags/modules/bar/normal/system.js index 4e9c248c1..66dd07892 100644 --- a/.config/ags/modules/bar/normal/system.js +++ b/.config/ags/modules/bar/normal/system.js @@ -145,7 +145,7 @@ const BatteryModule = () => Stack({ child: Box({ hexpand: true, hpack: 'center', - className: 'spacing-h-4', + className: 'spacing-h-4 txt-onSurfaceVariant', children: [ MaterialIcon('device_thermostat', 'small'), Label({ From b1c400577efb03d225ed9e46b6d9841fb3e41084 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 3 Mar 2024 15:55:51 +0700 Subject: [PATCH 059/517] osd: volume: show device --- .../ags/modules/indicators/indicatorvalues.js | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/.config/ags/modules/indicators/indicatorvalues.js b/.config/ags/modules/indicators/indicatorvalues.js index 9ea2deafa..ffc75ec79 100644 --- a/.config/ags/modules/indicators/indicatorvalues.js +++ b/.config/ags/modules/indicators/indicatorvalues.js @@ -6,18 +6,18 @@ import { MarginRevealer } from '../.widgethacks/advancedrevealers.js'; import Brightness from '../../services/brightness.js'; import Indicator from '../../services/indicator.js'; -const OsdValue = (name, labelSetup, progressSetup, props = {}) => { +const OsdValue = ({ name, nameSetup = undefined, labelSetup, progressSetup, ...rest }) => { const valueName = Label({ xalign: 0, yalign: 0, hexpand: true, className: 'osd-label', label: `${name}`, + setup: nameSetup, }); const valueNumber = Label({ hexpand: false, className: 'osd-value-txt', setup: labelSetup, }); return Box({ // Volume - ...props, vertical: true, hexpand: true, className: 'osd-bg osd-value', @@ -41,29 +41,48 @@ const OsdValue = (name, labelSetup, progressSetup, props = {}) => { setup: progressSetup, }) ], + ...rest, }); } export default () => { - const brightnessIndicator = OsdValue('Brightness', - (self) => self.hook(Brightness, self => { + const brightnessIndicator = OsdValue({ + name: 'Brightness', + labelSetup: (self) => self.hook(Brightness, self => { self.label = `${Math.round(Brightness.screen_value * 100)}`; }, 'notify::screen-value'), - (self) => self.hook(Brightness, (progress) => { + progressSetup: (self) => self.hook(Brightness, (progress) => { const updateValue = Brightness.screen_value; progress.value = updateValue; }, 'notify::screen-value'), - ) + }); - const volumeIndicator = OsdValue('Volume', - (self) => self.hook(Audio, (label) => { + const volumeIndicator = OsdValue({ + name: 'Volume', + attribute: { + headphones: undefined, + }, + nameSetup: (self) => Utils.timeout(1, () => { + const updateAudioDevice = (self) => { + const usingHeadphones = (Audio.speaker?.stream?.port)?.includes('Headphones'); + if (volumeIndicator.attribute.headphones === undefined || + volumeIndicator.attribute.headphones !== usingHeadphones) { + volumeIndicator.attribute.headphones = usingHeadphones; + self.label = usingHeadphones ? 'Headphones' : 'Speakers'; + Indicator.popup(1); + } + } + self.hook(Audio, updateAudioDevice); + Utils.timeout(1000, updateAudioDevice); + }), + labelSetup: (self) => self.hook(Audio, (label) => { label.label = `${Math.round(Audio.speaker?.volume * 100)}`; }), - (self) => self.hook(Audio, (progress) => { + progressSetup: (self) => self.hook(Audio, (progress) => { const updateValue = Audio.speaker?.volume; if (!isNaN(updateValue)) progress.value = updateValue; }), - ); + }); return MarginRevealer({ transition: 'slide_down', showClass: 'osd-show', From 116b0966e97bf511579b8af81d3b4d748a4f7c2e Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 3 Mar 2024 19:53:35 +0800 Subject: [PATCH 060/517] Fix permissions --- .config/anyrun/config.ron | 0 .config/anyrun/style.css | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 .config/anyrun/config.ron mode change 100755 => 100644 .config/anyrun/style.css diff --git a/.config/anyrun/config.ron b/.config/anyrun/config.ron old mode 100755 new mode 100644 diff --git a/.config/anyrun/style.css b/.config/anyrun/style.css old mode 100755 new mode 100644 From 97d9ae60bd6475d7ca1f3d7fe1ca44d13ae109e0 Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 3 Mar 2024 19:55:58 +0800 Subject: [PATCH 061/517] Fix permission --- .config/ags/modules/onscreenkeyboard/data_keyboardlayouts.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 .config/ags/modules/onscreenkeyboard/data_keyboardlayouts.js diff --git a/.config/ags/modules/onscreenkeyboard/data_keyboardlayouts.js b/.config/ags/modules/onscreenkeyboard/data_keyboardlayouts.js old mode 100755 new mode 100644 From a0e4764d40c9b2523dbb85105ff9eb899f174aec Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 3 Mar 2024 23:47:50 +0700 Subject: [PATCH 062/517] nuke gtklock stuff --- .config/ags/modules/session/sessionscreen.js | 1 - .../scripts/color_generation/applycolor.sh | 14 --- .../ags/scripts/templates/gtklock/main.scss | 89 ------------------- .config/gtklock/config.ini | 3 - .config/gtklock/style.css | 68 -------------- 5 files changed, 175 deletions(-) delete mode 100644 .config/ags/scripts/templates/gtklock/main.scss delete mode 100644 .config/gtklock/config.ini delete mode 100644 .config/gtklock/style.css diff --git a/.config/ags/modules/session/sessionscreen.js b/.config/ags/modules/session/sessionscreen.js index 6ba475043..8034020ca 100644 --- a/.config/ags/modules/session/sessionscreen.js +++ b/.config/ags/modules/session/sessionscreen.js @@ -61,7 +61,6 @@ const SessionButton = (name, icon, command, props = {}) => { export default () => { // lock, logout, sleep - // const lockButton = SessionButton('Lock', 'lock', () => { App.closeWindow('session'); execAsync('gtklock') }); const lockButton = SessionButton('Lock', 'lock', () => { App.closeWindow('session'); execAsync(['loginctl', 'lock-session']) }); const logoutButton = SessionButton('Logout', 'logout', () => { App.closeWindow('session'); execAsync(['bash', '-c', 'pkill Hyprland || pkill sway']) }); const sleepButton = SessionButton('Sleep', 'sleep', () => { App.closeWindow('session'); execAsync('systemctl suspend') }); diff --git a/.config/ags/scripts/color_generation/applycolor.sh b/.config/ags/scripts/color_generation/applycolor.sh index f5aad6a0d..b7656bdd8 100755 --- a/.config/ags/scripts/color_generation/applycolor.sh +++ b/.config/ags/scripts/color_generation/applycolor.sh @@ -57,19 +57,6 @@ get_light_dark() { echo "$lightdark" } -apply_gtklock() { - # Check if scripts/templates/gtklock/main.scss exists - if [ ! -f "scripts/templates/gtklock/main.scss" ]; then - echo "SCSS not found for Gtklock. Skipping that." - return - fi - - # Copy template - mkdir -p "$HOME"/.cache/ags/user/generated/gtklock - sass "scripts/templates/gtklock/main.scss" "$HOME"/.cache/ags/user/generated/gtklock/style.css - cp "$HOME"/.cache/ags/user/generated/gtklock/style.css "$HOME"/.config/gtklock/style.css -} - apply_fuzzel() { # Check if scripts/templates/fuzzel/fuzzel.ini exists if [ ! -f "scripts/templates/fuzzel/fuzzel.ini" ]; then @@ -182,6 +169,5 @@ apply_ags & apply_hyprland & apply_hyprlock & apply_gtk & -# apply_gtklock & apply_fuzzel & apply_term & diff --git a/.config/ags/scripts/templates/gtklock/main.scss b/.config/ags/scripts/templates/gtklock/main.scss deleted file mode 100644 index 5440e3ace..000000000 --- a/.config/ags/scripts/templates/gtklock/main.scss +++ /dev/null @@ -1,89 +0,0 @@ -// Could just sed but scss is better -@import '../../../scss/_material.scss'; // Which is ~/.config/ags/scss/_material.scss - -* { - all: unset; - border: 0rem; -} - -window { - background-color: transparentize($background, 0.6); - background-size: cover; - background-repeat: no-repeat; - background-position: center; -} - -#window-box { - border-radius: 1.5rem; - padding: 1.5rem; -} - -#input-label { - font-size: 1.5rem; - color: transparent; - background-color: transparent; - margin: -20rem; // bye bye -} - -#input-field { - background-color: $secondaryContainer; - color: $onSecondaryContainer; - caret-color: $onSecondaryContainer; - border-radius: 999px; - font-size: 1.3rem; - padding: 0.341rem 1.364rem; - margin: 0.477rem; - box-shadow: 2px 2px 4px rgba(22, 22, 22, 0.5); - min-height: 2.727rem; -} - -#unlock-button { - margin: -20rem; // bye bye - color: transparent; - background-color: transparent; -} - -#error-label { - color: $error; -} - -#clock-label { - font-family: 'Lexend'; - font-size: 6rem; - border-radius: 1.2rem; - padding: 0.5rem; - margin: 0.6rem; - margin-top: -35rem; // higher clock position - color: $onSecondaryContainer; - text-shadow: 1px 1px 2px rgba(22, 22, 30, 0.5); -} - -// #user-image {} - -// #powerbar-box {} - -#poweroff-button, -#reboot-button, -#suspend-button { - background-color: $secondaryContainer; - color: $onSecondaryContainer; - min-width: 3rem; - min-height: 3rem; - margin: 0.341rem; - border-radius: 9999px; -} - -#poweroff-button:hover, -#reboot-button:hover, -#suspend-button:hover, -#poweroff-button:focus, -#reboot-button:focus, -#suspend-button:focus { - background-color: mix($secondaryContainer, white, 80%); -} - -#poweroff-button:active, -#reboot-button:active, -#suspend-button:active { - background-color: mix($secondaryContainer, white, 70%); -} \ No newline at end of file diff --git a/.config/gtklock/config.ini b/.config/gtklock/config.ini deleted file mode 100644 index 2e047db88..000000000 --- a/.config/gtklock/config.ini +++ /dev/null @@ -1,3 +0,0 @@ -[main] -gtk-theme=Tokyonight-Dark-BL-LB -modules=/usr/lib/gtklock/powerbar-module.so diff --git a/.config/gtklock/style.css b/.config/gtklock/style.css deleted file mode 100644 index 68df184a9..000000000 --- a/.config/gtklock/style.css +++ /dev/null @@ -1,68 +0,0 @@ -* { - all: unset; - border: 0rem; } - -window { - background-color: rgba(29, 27, 31, 0.4); - background-size: cover; - background-repeat: no-repeat; - background-position: center; } - -#window-box { - border-radius: 1.5rem; - padding: 1.5rem; } - -#input-label { - font-size: 1.5rem; - color: transparent; - background-color: transparent; - margin: -20rem; } - -#input-field { - background-color: #4b4358; - color: #e9def8; - caret-color: #e9def8; - border-radius: 999px; - font-size: 1.3rem; - padding: 0.341rem 1.364rem; - margin: 0.477rem; - box-shadow: 2px 2px 4px rgba(22, 22, 22, 0.5); - min-height: 2.727rem; } - -#unlock-button { - margin: -20rem; - color: transparent; - background-color: transparent; } - -#error-label { - color: #ffb4a9; } - -#clock-label { - font-family: 'Lexend'; - font-size: 6rem; - border-radius: 1.2rem; - padding: 0.5rem; - margin: 0.6rem; - margin-top: -35rem; - color: #e9def8; - text-shadow: 1px 1px 2px rgba(22, 22, 30, 0.5); } - -#poweroff-button, -#reboot-button, -#suspend-button { - background-color: #4b4358; - color: #e9def8; - min-width: 3rem; - min-height: 3rem; - margin: 0.341rem; - border-radius: 9999px; } - -#poweroff-button:hover, -#reboot-button:hover, -#suspend-button:hover { - background-color: #6f6979; } - -#poweroff-button:active, -#reboot-button:active, -#suspend-button:active { - background-color: #817b8a; } From 95b2e11254c209c64a480ad81965b72a4ea5d417 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 3 Mar 2024 23:48:28 +0700 Subject: [PATCH 063/517] ags: reimplement tabs --- .../cairo_navigationindicator.js | 2 +- .../modules/.commonwidgets/tabcontainer.js | 87 +++++++++++++ .config/ags/modules/sideleft/apiwidgets.js | 8 +- .config/ags/modules/sideleft/sideleft.js | 119 +++--------------- .config/ags/modules/sideright/calendar.js | 1 + .config/ags/modules/sideright/todolist.js | 87 ++----------- .config/ags/scss/_common.scss | 23 ++++ .config/ags/scss/_sidebars.scss | 36 +----- 8 files changed, 145 insertions(+), 218 deletions(-) create mode 100644 .config/ags/modules/.commonwidgets/tabcontainer.js diff --git a/.config/ags/modules/.commonwidgets/cairo_navigationindicator.js b/.config/ags/modules/.commonwidgets/cairo_navigationindicator.js index 173c13b51..fd8d5990f 100644 --- a/.config/ags/modules/.commonwidgets/cairo_navigationindicator.js +++ b/.config/ags/modules/.commonwidgets/cairo_navigationindicator.js @@ -6,7 +6,7 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js'; // background-color/color for background/indicator color // padding for pad of indicator // font-size for selected index (0-based) -export const NavigationIndicator = (count, vertical, props) => Widget.DrawingArea({ +export const NavigationIndicator = ({count, vertical, ...props}) => Widget.DrawingArea({ ...props, setup: (area) => { const styleContext = area.get_style_context(); diff --git a/.config/ags/modules/.commonwidgets/tabcontainer.js b/.config/ags/modules/.commonwidgets/tabcontainer.js new file mode 100644 index 000000000..1719686ab --- /dev/null +++ b/.config/ags/modules/.commonwidgets/tabcontainer.js @@ -0,0 +1,87 @@ +import Variable from 'resource:///com/github/Aylur/ags/variable.js'; +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; +const { Box, Button, Label, Overlay, Stack } = Widget; +import { MaterialIcon } from './materialicon.js'; +import { NavigationIndicator } from './cairo_navigationindicator.js'; +import { setupCursorHover } from '../.widgetutils/cursorhover.js'; + +export const TabContainer = ({ icons, names, children, className = '', setup = () => {}, ...rest }) => { + const shownIndex = Variable(0); + let previousShownIndex = 0; + const count = Math.min(icons.length, names.length, children.length); + const tabs = Box({ + homogeneous: true, + children: Array.from({ length: count }, (_, i) => Button({ // Tab button + className: 'tab-btn', + onClicked: () => shownIndex.value = i, + setup: setupCursorHover, + child: Box({ + hpack: 'center', + vpack: 'center', + className: 'spacing-h-5 txt-small', + children: [ + MaterialIcon(icons[i], 'norm'), + Label({ + label: names[i], + }) + ] + }) + })), + setup: (self) => self.hook(shownIndex, (self) => { + self.children[previousShownIndex].toggleClassName('tab-btn-active', false); + self.children[shownIndex.value].toggleClassName('tab-btn-active', true); + previousShownIndex = shownIndex.value; + }), + }); + const tabIndicatorLine = Box({ + hexpand: true, + vertical: true, + homogeneous: true, + setup: (self) => self.hook(shownIndex, (self) => { + self.children[0].css = `font-size: ${shownIndex.value}px;`; + }), + children: [NavigationIndicator({ + className: 'tab-indicator', + count: count, + css: `font-size: ${shownIndex.value}px;`, + })], + }); + const tabSection = Box({ + vertical: true, + hexpand: true, + children: [ + tabs, + tabIndicatorLine + ] + }); + const contentStack = Stack({ + transition: 'slide_left_right', + children: children.reduce((acc, currentValue, index) => { + acc[index] = currentValue; + return acc; + }, {}), + setup: (self) => self.hook(shownIndex, (self) => { + self.shown = `${shownIndex.value}`; + }), + }); + const mainBox = Box({ + attribute: { + children: children, + shown: shownIndex, + names: names, + }, + vertical: true, + className: `spacing-v-5 ${className}`, + setup: (self) => { + self.pack_start(tabSection, false, false, 0); + self.pack_end(contentStack, true, true, 0); + setup(self); + }, + ...rest, + }); + mainBox.nextTab = () => shownIndex.value = Math.min(shownIndex.value + 1, count - 1); + mainBox.prevTab = () => shownIndex.value = Math.max(shownIndex.value - 1, 0); + mainBox.cycleTab = () => shownIndex.value = (shownIndex.value + 1) % count; + + return mainBox; +} diff --git a/.config/ags/modules/sideleft/apiwidgets.js b/.config/ags/modules/sideleft/apiwidgets.js index c950c8a05..216dc9008 100644 --- a/.config/ags/modules/sideleft/apiwidgets.js +++ b/.config/ags/modules/sideleft/apiwidgets.js @@ -4,7 +4,7 @@ import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; const { Box, Button, CenterBox, Entry, EventBox, Icon, Label, Overlay, Revealer, Scrollable, Stack } = Widget; const { execAsync, exec } = Utils; import { setupCursorHover, setupCursorHoverInfo } from '../.widgetutils/cursorhover.js'; -import { contentStack } from './sideleft.js'; +import { widgetContent } from './sideleft.js'; // APIs import GPTService from '../../services/gpt.js'; import Gemini from '../../services/gemini.js'; @@ -81,13 +81,11 @@ export const chatEntry = TextView({ // Global keybinds if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) && event.get_keyval()[1] === Gdk.KEY_Page_Down) { - const toSwitchTab = contentStack.get_visible_child(); - toSwitchTab.attribute.nextTab(); + widgetContent.nextTab(); } else if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) && event.get_keyval()[1] === Gdk.KEY_Page_Up) { - const toSwitchTab = contentStack.get_visible_child(); - toSwitchTab.attribute.prevTab(); + widgetContent.prevTab(); } }) , diff --git a/.config/ags/modules/sideleft/sideleft.js b/.config/ags/modules/sideleft/sideleft.js index 87a1b70ed..5ae293849 100644 --- a/.config/ags/modules/sideleft/sideleft.js +++ b/.config/ags/modules/sideleft/sideleft.js @@ -6,10 +6,10 @@ const { Box, Button, EventBox, Label, Revealer, Scrollable, Stack } = Widget; const { execAsync, exec } = Utils; import { MaterialIcon } from '../.commonwidgets/materialicon.js'; import { setupCursorHover } from '../.widgetutils/cursorhover.js'; -import { NavigationIndicator } from '../.commonwidgets/cairo_navigationindicator.js'; import toolBox from './toolbox.js'; import apiWidgets from './apiwidgets.js'; import { chatEntry } from './apiwidgets.js'; +import { TabContainer } from '../.commonwidgets/tabcontainer.js'; const contents = [ { @@ -25,78 +25,6 @@ const contents = [ friendlyName: 'Tools', }, ] -let currentTabId = 0; - -export const contentStack = Stack({ - vexpand: true, - transition: 'slide_left_right', - transitionDuration: 160, - children: contents.reduce((acc, item) => { - acc[item.name] = item.content; - return acc; - }, {}), -}) - -function switchToTab(id) { - const allTabs = navTabs.get_children(); - const tabButton = allTabs[id]; - allTabs[currentTabId].toggleClassName('sidebar-selector-tab-active', false); - allTabs[id].toggleClassName('sidebar-selector-tab-active', true); - contentStack.shown = contents[id].name; - if (tabButton) { - // Fancy highlighter line width - const buttonWidth = tabButton.get_allocated_width(); - const highlightWidth = tabButton.get_children()[0].get_allocated_width(); - navIndicator.css = ` - font-size: ${id}px; - padding: 0px ${(buttonWidth - highlightWidth) / 2}px; - `; - } - currentTabId = id; -} -const SidebarTabButton = (navIndex) => Widget.Button({ - // hexpand: true, - className: 'sidebar-selector-tab', - onClicked: (self) => { - switchToTab(navIndex); - }, - child: Box({ - hpack: 'center', - className: 'spacing-h-5', - children: [ - MaterialIcon(contents[navIndex].materialIcon, 'larger'), - Label({ - className: 'txt txt-smallie', - label: `${contents[navIndex].friendlyName}`, - }) - ] - }), - setup: (button) => Utils.timeout(1, () => { - setupCursorHover(button); - button.toggleClassName('sidebar-selector-tab-active', currentTabId == navIndex); - }), -}); - -const navTabs = Box({ - homogeneous: true, - children: contents.map((item, id) => - SidebarTabButton(id, item.materialIcon, item.friendlyName) - ), -}); - -const navIndicator = NavigationIndicator(2, false, { // The line thing - className: 'sidebar-selector-highlight', - css: 'font-size: 0px; padding: 0rem 4.160rem;', // Shushhhh -}); - -const navBar = Box({ - vertical: true, - hexpand: true, - children: [ - navTabs, - navIndicator, - ] -}); const pinButton = Button({ attribute: { @@ -131,6 +59,17 @@ const pinButton = Button({ }, }) +export const widgetContent = TabContainer({ + icons: contents.map((item) => item.materialIcon), + names: contents.map((item) => item.friendlyName), + children: contents.map((item) => item.content), + className: 'sidebar-left spacing-v-10', + setup: (self) => self.hook(App, (self, currentName, visible) => { + if (currentName === 'sideleft') + self.toggleClassName('sidebar-pinned', pinButton.attribute.enabled && visible); + }), +}); + export default () => Box({ // vertical: true, vexpand: true, @@ -142,27 +81,7 @@ export default () => Box({ onSecondaryClick: () => App.closeWindow('sideleft'), onMiddleClick: () => App.closeWindow('sideleft'), }), - Box({ - vertical: true, - vexpand: true, - className: 'sidebar-left spacing-v-10', - children: [ - Box({ - className: 'spacing-h-10', - children: [ - navBar, - pinButton, - ] - }), - contentStack, - ], - setup: (self) => self - .hook(App, (self, currentName, visible) => { - if (currentName === 'sideleft') - self.toggleClassName('sidebar-pinned', pinButton.attribute.enabled && visible); - }) - , - }), + widgetContent, ], setup: (self) => self .on('key-press-event', (widget, event) => { // Handle keybinds @@ -172,13 +91,13 @@ export default () => Box({ pinButton.attribute.toggle(pinButton); // Switch sidebar tab else if (event.get_keyval()[1] === Gdk.KEY_Tab) - switchToTab((currentTabId + 1) % contents.length); + widgetContent.cycleTab(); else if (event.get_keyval()[1] === Gdk.KEY_Page_Up) - switchToTab(Math.max(currentTabId - 1, 0)); + widgetContent.prevTab(); else if (event.get_keyval()[1] === Gdk.KEY_Page_Down) - switchToTab(Math.min(currentTabId + 1, contents.length - 1)); + widgetContent.nextTab(); } - if (contentStack.shown == 'apis') { // If api tab is focused + if (widgetContent.attribute.names[widgetContent.attribute.shown.value] == 'APIs') { // If api tab is focused // Focus entry when typing if (( !(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) && @@ -196,12 +115,12 @@ export default () => Box({ // Switch API type else if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) && event.get_keyval()[1] === Gdk.KEY_Page_Down) { - const toSwitchTab = contentStack.get_visible_child(); + const toSwitchTab = widgetContent.attribute.children[widgetContent.attribute.shown.value]; toSwitchTab.attribute.nextTab(); } else if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) && event.get_keyval()[1] === Gdk.KEY_Page_Up) { - const toSwitchTab = contentStack.get_visible_child(); + const toSwitchTab = widgetContent.attribute.children[widgetContent.attribute.shown.value]; toSwitchTab.attribute.prevTab(); } } diff --git a/.config/ags/modules/sideright/calendar.js b/.config/ags/modules/sideright/calendar.js index 817d0b2df..43847e890 100644 --- a/.config/ags/modules/sideright/calendar.js +++ b/.config/ags/modules/sideright/calendar.js @@ -200,3 +200,4 @@ export const ModuleCalendar = () => Box({ box.pack_end(contentStack, false, false, 0); } }) + diff --git a/.config/ags/modules/sideright/todolist.js b/.config/ags/modules/sideright/todolist.js index b84bed2a6..7cc417a4a 100644 --- a/.config/ags/modules/sideright/todolist.js +++ b/.config/ags/modules/sideright/todolist.js @@ -2,6 +2,7 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; const { Box, Button, Label, Revealer } = Widget; import { MaterialIcon } from '../.commonwidgets/materialicon.js'; +import { TabContainer } from '../.commonwidgets/tabcontainer.js'; import Todo from "../../services/todo.js"; import { setupCursorHover } from '../.widgetutils/cursorhover.js'; import { NavigationIndicator } from '../.commonwidgets/cairo_navigationindicator.js'; @@ -199,81 +200,11 @@ const UndoneTodoList = () => { }); } -const todoItemsBox = Widget.Stack({ - vpack: 'fill', - transition: 'slide_left_right', - children: { - 'undone': UndoneTodoList(), - 'done': todoItems(true), - }, -}); - -export const TodoWidget = () => { - const TodoTabButton = (isDone, navIndex) => Widget.Button({ - hexpand: true, - className: 'sidebar-selector-tab', - onClicked: (button) => { - todoItemsBox.shown = `${isDone ? 'done' : 'undone'}`; - const kids = button.get_parent().get_children(); - for (let i = 0; i < kids.length; i++) { - if (kids[i] != button) kids[i].toggleClassName('sidebar-selector-tab-active', false); - else button.toggleClassName('sidebar-selector-tab-active', true); - } - // Fancy highlighter line width - const buttonWidth = button.get_allocated_width(); - const highlightWidth = button.get_children()[0].get_allocated_width(); - navIndicator.css = ` - font-size: ${navIndex}px; - padding: 0px ${(buttonWidth - highlightWidth) / 2}px; - `; - }, - child: Box({ - hpack: 'center', - className: 'spacing-h-5', - children: [ - MaterialIcon(`${isDone ? 'task_alt' : 'format_list_bulleted'}`, 'larger'), - Label({ - className: 'txt txt-smallie', - label: `${isDone ? 'Done' : 'Unfinished'}`, - }) - ] - }), - setup: (button) => Utils.timeout(1, () => { - setupCursorHover(button); - button.toggleClassName('sidebar-selector-tab-active', defaultTodoSelected === `${isDone ? 'done' : 'undone'}`); - }), - }); - const undoneButton = TodoTabButton(false, 0); - const doneButton = TodoTabButton(true, 1); - const navIndicator = NavigationIndicator(2, false, { // The line thing - className: 'sidebar-selector-highlight', - css: 'font-size: 0px; padding: 0rem 1.636rem;', // Shush - }) - return Widget.Box({ - hexpand: true, - vertical: true, - className: 'spacing-v-10', - setup: (box) => { // undone/done selector rail - box.pack_start(Widget.Box({ - vertical: true, - children: [ - Widget.Box({ - className: 'sidebar-selectors spacing-h-5', - homogeneous: true, - setup: (box) => { - box.pack_start(undoneButton, false, true, 0); - box.pack_start(doneButton, false, true, 0); - } - }), - Widget.Box({ - className: 'sidebar-selector-highlight-offset', - homogeneous: true, - children: [navIndicator] - }) - ] - }), false, false, 0); - box.pack_end(todoItemsBox, true, true, 0); - }, - }); -}; - +export const TodoWidget = () => TabContainer({ + icons: ['format_list_bulleted', 'task_alt'], + names: ['Unfinished', 'Done'], + children: [ + UndoneTodoList(), + todoItems(true), + ] +}) diff --git a/.config/ags/scss/_common.scss b/.config/ags/scss/_common.scss index f7530f59b..00a509efd 100644 --- a/.config/ags/scss/_common.scss +++ b/.config/ags/scss/_common.scss @@ -231,4 +231,27 @@ popover { .gap-h-15 { min-width: 1.023rem; +} + +.tab-btn { + @include small-rounding; + @include element_decel; + min-height: 2.5rem; + color: $onSurface; +} + +.tab-btn:hover, +.tab-btn:focus { + background-color: $hovercolor; +} + +.tab-btn-active>box>label { + color: $primary; +} + +.tab-indicator { + transition: 180ms ease-in-out; // Doesn't look that good, but it syncs with the GtkStack + min-height: 0.205rem; + padding: 0rem 1.023rem; + color: $primary; } \ No newline at end of file diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss index b6ecac92d..6ed2bab3a 100644 --- a/.config/ags/scss/_sidebars.scss +++ b/.config/ags/scss/_sidebars.scss @@ -301,38 +301,6 @@ $onChatgpt: $onPrimary; color: mix($onSurfaceVariant, $surfaceVariant, 85%); } -.sidebar-selector-tab { - @include small-rounding; - @include element_decel; - min-height: 2.5rem; - color: $onSurface; -} - -.sidebar-selector-tab:hover, -.sidebar-selector-tab:focus { - background-color: $hovercolor; -} - -.sidebar-selector-tab:active { - background-color: $activecolor; -} - -.sidebar-selector-tab-active>box>label { - color: $primary; -} - -.sidebar-selector-highlight-offset { - margin-top: -0.205rem; - margin-bottom: 0.205rem; -} - -.sidebar-selector-highlight { - transition: 180ms ease-in-out; // Doesn't look that good, but it syncs with the GtkStack - color: $primary; - // padding: 0rem 2.045rem; - min-height: 0.205rem; -} - .sidebar-todo-item { padding-right: 0.545rem; } @@ -373,10 +341,10 @@ $onChatgpt: $onPrimary; .sidebar-todo-new { @include full-rounding; @include element_decel; - color: $onSecondaryContainer; + background-color: $textboxColor; + color: $onSurfaceVariant; margin: 0.341rem; padding: 0.205rem 0.545rem; - border: 0.068rem solid $onSurface; } .sidebar-todo-new, From 140fb8d663a58dbbd43e9da32b338e1bb2116b3f Mon Sep 17 00:00:00 2001 From: Ali Elnwegy Date: Mon, 4 Mar 2024 15:23:57 +0100 Subject: [PATCH 064/517] fix: Fixed bar corners not appearing on multi monitor setup --- .config/ags/modules/bar/main.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.config/ags/modules/bar/main.js b/.config/ags/modules/bar/main.js index da3962ff1..601221c37 100644 --- a/.config/ags/modules/bar/main.js +++ b/.config/ags/modules/bar/main.js @@ -103,8 +103,9 @@ export const Bar = async (monitor = 0) => { }); } -export const BarCornerTopleft = (id = '') => Widget.Window({ - name: `barcornertl${id}`, +export const BarCornerTopleft = (monitor = 0) => Widget.Window({ + monitor, + name: `barcornertl${monitor}`, layer: 'top', anchor: ['top', 'left'], exclusivity: 'normal', @@ -112,8 +113,9 @@ export const BarCornerTopleft = (id = '') => Widget.Window({ child: RoundedCorner('topleft', { className: 'corner', }), setup: enableClickthrough, }); -export const BarCornerTopright = (id = '') => Widget.Window({ - name: `barcornertr${id}`, +export const BarCornerTopright = (monitor = 0) => Wmonitorget.Window({ + monitor, + name: `barcornertr${monitor}`, layer: 'top', anchor: ['top', 'right'], exclusivity: 'normal', From 84af931cc79394fb589af566ff8e09898d5a93c8 Mon Sep 17 00:00:00 2001 From: Ali Elnwegy <50055099+alin742@users.noreply.github.com> Date: Mon, 4 Mar 2024 15:36:31 +0100 Subject: [PATCH 065/517] fix: Fixed typo --- .config/ags/modules/bar/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/modules/bar/main.js b/.config/ags/modules/bar/main.js index 601221c37..2c6514ce8 100644 --- a/.config/ags/modules/bar/main.js +++ b/.config/ags/modules/bar/main.js @@ -113,7 +113,7 @@ export const BarCornerTopleft = (monitor = 0) => Widget.Window({ child: RoundedCorner('topleft', { className: 'corner', }), setup: enableClickthrough, }); -export const BarCornerTopright = (monitor = 0) => Wmonitorget.Window({ +export const BarCornerTopright = (monitor = 0) => Widget.Window({ monitor, name: `barcornertr${monitor}`, layer: 'top', From 71cc428004d4e137d41d95882390bc28b1beaaf4 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 4 Mar 2024 21:58:14 +0700 Subject: [PATCH 066/517] fix messed up keybinds for apis widget --- .config/ags/modules/sideleft/apiwidgets.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.config/ags/modules/sideleft/apiwidgets.js b/.config/ags/modules/sideleft/apiwidgets.js index 216dc9008..e65fad538 100644 --- a/.config/ags/modules/sideleft/apiwidgets.js +++ b/.config/ags/modules/sideleft/apiwidgets.js @@ -4,7 +4,6 @@ import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; const { Box, Button, CenterBox, Entry, EventBox, Icon, Label, Overlay, Revealer, Scrollable, Stack } = Widget; const { execAsync, exec } = Utils; import { setupCursorHover, setupCursorHoverInfo } from '../.widgetutils/cursorhover.js'; -import { widgetContent } from './sideleft.js'; // APIs import GPTService from '../../services/gpt.js'; import Gemini from '../../services/gemini.js'; @@ -81,11 +80,13 @@ export const chatEntry = TextView({ // Global keybinds if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) && event.get_keyval()[1] === Gdk.KEY_Page_Down) { - widgetContent.nextTab(); + apiWidgets.attribute.nextTab(); + return true; } else if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) && event.get_keyval()[1] === Gdk.KEY_Page_Up) { - widgetContent.prevTab(); + apiWidgets.attribute.prevTab(); + return true; } }) , @@ -203,7 +204,7 @@ const apiSwitcher = CenterBox({ }), }) -export default Widget.Box({ +const apiWidgets = Widget.Box({ attribute: { 'nextTab': () => switchToTab(Math.min(currentApiId + 1, APIS.length - 1)), 'prevTab': () => switchToTab(Math.max(0, currentApiId - 1)), @@ -218,3 +219,5 @@ export default Widget.Box({ textboxArea, ], }); + +export default apiWidgets; From 9de662f125870772770cdb57306e5d8ab2a90eeb Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 4 Mar 2024 22:35:07 +0700 Subject: [PATCH 067/517] ags: add config option for gtk anim duration --- .../modules/.commonwidgets/configwidgets.js | 2 +- .../modules/.commonwidgets/notification.js | 22 +++++++------- .config/ags/modules/bar/main.js | 2 +- .config/ags/modules/bar/normal/music.js | 2 +- .config/ags/modules/bar/normal/system.js | 4 +-- .config/ags/modules/bar/normal/tray.js | 4 +-- .../ags/modules/desktopbackground/system.js | 2 +- .../modules/desktopbackground/wallpaper.js | 2 +- .config/ags/modules/dock/dock.js | 7 ++--- .config/ags/modules/indicators/colorscheme.js | 2 +- .../ags/modules/indicators/musiccontrols.js | 8 ++--- .../ags/modules/overview/overview_hyprland.js | 2 +- .config/ags/modules/overview/searchbuttons.js | 8 ++--- .config/ags/modules/overview/searchitem.js | 4 +-- .config/ags/modules/overview/windowcontent.js | 6 ++-- .config/ags/modules/session/sessionscreen.js | 2 +- .config/ags/modules/sideleft/apis/chatgpt.js | 4 +-- .config/ags/modules/sideleft/apis/gemini.js | 2 +- .config/ags/modules/sideleft/apis/waifu.js | 6 ++-- .config/ags/modules/sideleft/apiwidgets.js | 6 ++-- .config/ags/modules/sideleft/tools/module.js | 2 +- .config/ags/modules/sideright/calendar.js | 2 +- .../ags/modules/sideright/notificationlist.js | 2 +- .config/ags/modules/sideright/todolist.js | 10 +++---- .config/ags/scss/_musicmaterial.scss | 30 +------------------ .config/ags/user_options.js | 4 +++ 26 files changed, 60 insertions(+), 87 deletions(-) diff --git a/.config/ags/modules/.commonwidgets/configwidgets.js b/.config/ags/modules/.commonwidgets/configwidgets.js index ba181c604..92ad8b44f 100644 --- a/.config/ags/modules/.commonwidgets/configwidgets.js +++ b/.config/ags/modules/.commonwidgets/configwidgets.js @@ -86,7 +86,7 @@ export const ConfigSegmentedSelection = ({ const selectedIcon = Revealer({ revealChild: id == initIndex, transition: 'slide_right', - transitionDuration: 150, + transitionDuration: userOptions.animations.durationSmall, child: MaterialIcon('check', 'norm') }); return Button({ diff --git a/.config/ags/modules/.commonwidgets/notification.js b/.config/ags/modules/.commonwidgets/notification.js index 319495b8b..93fd686cb 100644 --- a/.config/ags/modules/.commonwidgets/notification.js +++ b/.config/ags/modules/.commonwidgets/notification.js @@ -79,10 +79,10 @@ export default ({ const destroyWithAnims = () => { widget.sensitive = false; notificationBox.setCss(middleClickClose); - Utils.timeout(200, () => { + Utils.timeout(userOptions.animations.durationSmall, () => { if (wholeThing) wholeThing.revealChild = false; }, wholeThing); - Utils.timeout(400, () => { + Utils.timeout(userOptions.animations.durationSmall * 2, () => { command(); if (wholeThing) { wholeThing.destroy(); @@ -135,7 +135,7 @@ export default ({ }, revealChild: false, transition: 'slide_down', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, child: Box({ // Box to make sure css-based spacing works homogeneous: true, }), @@ -144,7 +144,7 @@ export default ({ const display = Gdk.Display.get_default(); const notifTextPreview = Revealer({ transition: 'slide_down', - transitionDuration: 120, + transitionDuration: userOptions.animations.durationSmall, revealChild: true, child: Label({ xalign: 0, @@ -159,7 +159,7 @@ export default ({ }); const notifTextExpanded = Revealer({ transition: 'slide_up', - transitionDuration: 120, + transitionDuration: userOptions.animations.durationSmall, revealChild: false, child: Box({ vertical: true, @@ -305,17 +305,17 @@ export default ({ const maxOffset = 10.227; const endMargin = 20.455; const disappearHeight = 6.818; - const leftAnim1 = `transition: 200ms cubic-bezier(0.05, 0.7, 0.1, 1); + const leftAnim1 = `transition: ${userOptions.animations.durationSmall}ms cubic-bezier(0.05, 0.7, 0.1, 1); margin-left: -${Number(maxOffset + endMargin)}rem; margin-right: ${Number(maxOffset + endMargin)}rem; opacity: 0;`; - const rightAnim1 = `transition: 200ms cubic-bezier(0.05, 0.7, 0.1, 1); + const rightAnim1 = `transition: ${userOptions.animations.durationSmall}ms cubic-bezier(0.05, 0.7, 0.1, 1); margin-left: ${Number(maxOffset + endMargin)}rem; margin-right: -${Number(maxOffset + endMargin)}rem; opacity: 0;`; - const middleClickClose = `transition: 200ms cubic-bezier(0.85, 0, 0.15, 1); + const middleClickClose = `transition: ${userOptions.animations.durationSmall}ms cubic-bezier(0.85, 0, 0.15, 1); margin-left: ${Number(maxOffset + endMargin)}rem; margin-right: -${Number(maxOffset + endMargin)}rem; opacity: 0;`; @@ -400,10 +400,10 @@ export default ({ self.setCss(leftAnim1); widget.sensitive = false; } - Utils.timeout(200, () => { + Utils.timeout(userOptions.animations.durationSmall, () => { if (wholeThing) wholeThing.revealChild = false; }, wholeThing); - Utils.timeout(400, () => { + Utils.timeout(userOptions.animations.durationSmall * 2, () => { command(); if (wholeThing) { wholeThing.destroy(); @@ -432,7 +432,7 @@ export default ({ if (isPopup) Utils.timeout(popupTimeout, () => { if (wholeThing) { wholeThing.revealChild = false; - Utils.timeout(200, () => { + Utils.timeout(userOptions.animations.durationSmall, () => { if (wholeThing) { wholeThing.destroy(); wholeThing = null; diff --git a/.config/ags/modules/bar/main.js b/.config/ags/modules/bar/main.js index 2c6514ce8..0c3aed1b5 100644 --- a/.config/ags/modules/bar/main.js +++ b/.config/ags/modules/bar/main.js @@ -91,7 +91,7 @@ export const Bar = async (monitor = 0) => { child: Widget.Stack({ homogeneous: false, transition: 'slide_up_down', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, children: { 'normal': normalBarContent, 'focus': focusedBarContent, diff --git a/.config/ags/modules/bar/normal/music.js b/.config/ags/modules/bar/normal/music.js index 13ec6c717..d50fa46e6 100644 --- a/.config/ags/modules/bar/normal/music.js +++ b/.config/ags/modules/bar/normal/music.js @@ -186,7 +186,7 @@ export default () => { Revealer({ revealChild: true, transition: 'slide_left', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, child: Box({ className: 'spacing-h-10 margin-left-10', children: [ diff --git a/.config/ags/modules/bar/normal/system.js b/.config/ags/modules/bar/normal/system.js index 66dd07892..2e4c2e1b6 100644 --- a/.config/ags/modules/bar/normal/system.js +++ b/.config/ags/modules/bar/normal/system.js @@ -88,7 +88,7 @@ const BarBattery = () => Box({ className: 'spacing-h-4 txt-onSurfaceVariant', children: [ Revealer({ - transitionDuration: 150, + transitionDuration: userOptions.animations.durationSmall, revealChild: false, transition: 'slide_right', child: MaterialIcon('bolt', 'norm', { tooltipText: "Charging" }), @@ -133,7 +133,7 @@ const BarGroup = ({ child }) => Widget.Box({ }); const BatteryModule = () => Stack({ transition: 'slide_up_down', - transitionDuration: 150, + transitionDuration: userOptions.animations.durationLarge, children: { 'laptop': Box({ className: 'spacing-h-4', children: [ diff --git a/.config/ags/modules/bar/normal/tray.js b/.config/ags/modules/bar/normal/tray.js index 53827ca74..5ebbbd275 100644 --- a/.config/ags/modules/bar/normal/tray.js +++ b/.config/ags/modules/bar/normal/tray.js @@ -3,8 +3,6 @@ import SystemTray from 'resource:///com/github/Aylur/ags/service/systemtray.js'; const { Box, Icon, Button, Revealer } = Widget; const { Gravity } = imports.gi.Gdk; -const revealerDuration = 200; - const SysTrayItem = (item) => Button({ className: 'bar-systray-item', child: Icon({ @@ -32,7 +30,7 @@ export const Tray = (props = {}) => { const trayRevealer = Widget.Revealer({ revealChild: true, transition: 'slide_left', - transitionDuration: revealerDuration, + transitionDuration: userOptions.animations.durationLarge, child: trayContent, }); return Box({ diff --git a/.config/ags/modules/desktopbackground/system.js b/.config/ags/modules/desktopbackground/system.js index 6bc915df4..a65402b7c 100644 --- a/.config/ags/modules/desktopbackground/system.js +++ b/.config/ags/modules/desktopbackground/system.js @@ -11,7 +11,7 @@ const ResourceValue = (name, icon, interval, valueUpdateCmd, displayFunc, props children: [ Revealer({ transition: 'slide_left', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, child: Box({ vpack: 'center', vertical: true, diff --git a/.config/ags/modules/desktopbackground/wallpaper.js b/.config/ags/modules/desktopbackground/wallpaper.js index da98c2176..695f381a6 100644 --- a/.config/ags/modules/desktopbackground/wallpaper.js +++ b/.config/ags/modules/desktopbackground/wallpaper.js @@ -99,7 +99,7 @@ export default (monitor = 0) => { }); const stack = Stack({ transition: 'crossfade', - transitionDuration: 180, + transitionDuration: userOptions.animations.durationLarge, children: { 'disabled': Box({}), 'image': wallpaperImage, diff --git a/.config/ags/modules/dock/dock.js b/.config/ags/modules/dock/dock.js index 11d3fe9dc..d35fe757c 100644 --- a/.config/ags/modules/dock/dock.js +++ b/.config/ags/modules/dock/dock.js @@ -10,7 +10,6 @@ const { execAsync, exec } = Utils; const { Box, Revealer } = Widget; import { setupCursorHover } from '../.widgetutils/cursorhover.js'; -const ANIMATION_TIME = 150; const pinnedApps = [ 'firefox', 'org.gnome.Nautilus', @@ -48,7 +47,7 @@ const AppButton = ({ icon, ...rest }) => Widget.Revealer({ }, revealChild: false, transition: 'slide_right', - transitionDuration: ANIMATION_TIME, + transitionDuration: userOptions.animations.durationLarge, child: Widget.Button({ ...rest, className: 'dock-app-btn', @@ -128,7 +127,7 @@ const Taskbar = () => Widget.Box({ if (!removedButton) return; removedButton.revealChild = false; - Utils.timeout(ANIMATION_TIME, () => { + Utils.timeout(userOptions.animations.durationLarge, () => { removedButton.destroy(); box.attribute.map.delete(address); box.children = Array.from(box.attribute.map.values()); @@ -230,7 +229,7 @@ export default () => { }, revealChild: false, transition: 'slide_up', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, child: dockContent, // setup: (self) => self // .hook(Hyprland, (self) => self.attribute.updateShow(self)) diff --git a/.config/ags/modules/indicators/colorscheme.js b/.config/ags/modules/indicators/colorscheme.js index d5dfd4970..e0c46c1aa 100644 --- a/.config/ags/modules/indicators/colorscheme.js +++ b/.config/ags/modules/indicators/colorscheme.js @@ -43,7 +43,7 @@ const ColorschemeContent = () => Box({ export default () => Widget.Revealer({ transition: 'slide_down', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, child: ColorschemeContent(), setup: (self) => self.hook(showColorScheme, (revealer) => { revealer.revealChild = showColorScheme.value; diff --git a/.config/ags/modules/indicators/musiccontrols.js b/.config/ags/modules/indicators/musiccontrols.js index f3e8b01e4..8852c5740 100644 --- a/.config/ags/modules/indicators/musiccontrols.js +++ b/.config/ags/modules/indicators/musiccontrols.js @@ -227,7 +227,7 @@ const CoverArt = ({ player, ...rest }) => { const TrackControls = ({ player, ...rest }) => Widget.Revealer({ revealChild: false, transition: 'slide_right', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, child: Widget.Box({ ...rest, vpack: 'center', @@ -263,7 +263,7 @@ const TrackControls = ({ player, ...rest }) => Widget.Revealer({ const TrackSource = ({ player, ...rest }) => Widget.Revealer({ revealChild: false, transition: 'slide_left', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, child: Widget.Box({ ...rest, className: 'osd-music-pill spacing-h-5', @@ -292,7 +292,7 @@ const TrackTime = ({ player, ...rest }) => { return Widget.Revealer({ revealChild: false, transition: 'slide_left', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, child: Widget.Box({ ...rest, vpack: 'center', @@ -382,7 +382,7 @@ const MusicControlsWidget = (player) => Box({ export default () => Revealer({ transition: 'slide_down', - transitionDuration: 150, + transitionDuration: userOptions.animations.durationLarge, revealChild: false, child: Box({ setup: (self) => self.hook(Mpris, box => { diff --git a/.config/ags/modules/overview/overview_hyprland.js b/.config/ags/modules/overview/overview_hyprland.js index e7cefc7dd..0fe062541 100644 --- a/.config/ags/modules/overview/overview_hyprland.js +++ b/.config/ags/modules/overview/overview_hyprland.js @@ -396,7 +396,7 @@ export default () => { return Widget.Revealer({ revealChild: true, transition: 'slide_down', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, child: Widget.Box({ vertical: true, className: 'overview-tasks', diff --git a/.config/ags/modules/overview/searchbuttons.js b/.config/ags/modules/overview/searchbuttons.js index e90957d14..480d2283d 100644 --- a/.config/ags/modules/overview/searchbuttons.js +++ b/.config/ags/modules/overview/searchbuttons.js @@ -10,7 +10,7 @@ export const DirectoryButton = ({ parentPath, name, type, icon }) => { const actionText = Widget.Revealer({ revealChild: false, transition: "crossfade", - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, child: Widget.Label({ className: 'overview-search-results-txt txt txt-small txt-action', label: 'Open', @@ -19,7 +19,7 @@ export const DirectoryButton = ({ parentPath, name, type, icon }) => { const actionTextRevealer = Widget.Revealer({ revealChild: false, transition: "slide_left", - transitionDuration: 300, + transitionDuration: userOptions.animations.durationSmall, child: actionText, }); return Widget.Button({ @@ -78,7 +78,7 @@ export const DesktopEntryButton = (app) => { const actionText = Widget.Revealer({ revealChild: false, transition: "crossfade", - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, child: Widget.Label({ className: 'overview-search-results-txt txt txt-small txt-action', label: 'Launch', @@ -87,7 +87,7 @@ export const DesktopEntryButton = (app) => { const actionTextRevealer = Widget.Revealer({ revealChild: false, transition: "slide_left", - transitionDuration: 300, + transitionDuration: userOptions.animations.durationSmall, child: actionText, }); return Widget.Button({ diff --git a/.config/ags/modules/overview/searchitem.js b/.config/ags/modules/overview/searchitem.js index 276885ad0..2a3303a48 100644 --- a/.config/ags/modules/overview/searchitem.js +++ b/.config/ags/modules/overview/searchitem.js @@ -4,7 +4,7 @@ export const searchItem = ({ materialIconName, name, actionName, content, onActi const actionText = Widget.Revealer({ revealChild: false, transition: "crossfade", - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, child: Widget.Label({ className: 'overview-search-results-txt txt txt-small txt-action', label: `${actionName}`, @@ -13,7 +13,7 @@ export const searchItem = ({ materialIconName, name, actionName, content, onActi const actionTextRevealer = Widget.Revealer({ revealChild: false, transition: "slide_left", - transitionDuration: 300, + transitionDuration: userOptions.animations.durationSmall, child: actionText, }) return Widget.Button({ diff --git a/.config/ags/modules/overview/windowcontent.js b/.config/ags/modules/overview/windowcontent.js index 606c7c4eb..3486c1fe7 100644 --- a/.config/ags/modules/overview/windowcontent.js +++ b/.config/ags/modules/overview/windowcontent.js @@ -61,7 +61,7 @@ export const SearchAndWindows = () => { vexpand: true, }); const resultsRevealer = Widget.Revealer({ - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, revealChild: false, transition: 'slide_down', // duration: 200, @@ -70,7 +70,7 @@ export const SearchAndWindows = () => { }); const entryPromptRevealer = Widget.Revealer({ transition: 'crossfade', - transitionDuration: 150, + transitionDuration: userOptions.animations.durationLarge, revealChild: true, hpack: 'center', child: Widget.Label({ @@ -81,7 +81,7 @@ export const SearchAndWindows = () => { const entryIconRevealer = Widget.Revealer({ transition: 'crossfade', - transitionDuration: 150, + transitionDuration: userOptions.animations.durationLarge, revealChild: false, hpack: 'end', child: Widget.Label({ diff --git a/.config/ags/modules/session/sessionscreen.js b/.config/ags/modules/session/sessionscreen.js index 8034020ca..1f90636ea 100644 --- a/.config/ags/modules/session/sessionscreen.js +++ b/.config/ags/modules/session/sessionscreen.js @@ -11,7 +11,7 @@ const { exec, execAsync } = Utils; const SessionButton = (name, icon, command, props = {}) => { const buttonDescription = Widget.Revealer({ vpack: 'end', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationSmall, transition: 'slide_down', revealChild: false, child: Widget.Label({ diff --git a/.config/ags/modules/sideleft/apis/chatgpt.js b/.config/ags/modules/sideleft/apis/chatgpt.js index ab6067c42..fa16acec1 100644 --- a/.config/ags/modules/sideleft/apis/chatgpt.js +++ b/.config/ags/modules/sideleft/apis/chatgpt.js @@ -79,7 +79,7 @@ const ProviderSwitcher = () => { const providerList = Revealer({ revealChild: false, transition: 'slide_down', - transitionDuration: 180, + transitionDuration: userOptions.animations.durationLarge, child: Box({ vertical: true, className: 'spacing-v-5 sidebar-chat-providerswitcher-list', children: [ @@ -209,7 +209,7 @@ export const OpenaiApiKeyInstructions = () => Box({ homogeneous: true, children: [Revealer({ transition: 'slide_down', - transitionDuration: 150, + transitionDuration: userOptions.animations.durationLarge, setup: (self) => self .hook(GPTService, (self, hasKey) => { self.revealChild = (GPTService.key.length == 0); diff --git a/.config/ags/modules/sideleft/apis/gemini.js b/.config/ags/modules/sideleft/apis/gemini.js index 2ed539d5f..cd755c33a 100644 --- a/.config/ags/modules/sideleft/apis/gemini.js +++ b/.config/ags/modules/sideleft/apis/gemini.js @@ -113,7 +113,7 @@ export const GoogleAiInstructions = () => Box({ homogeneous: true, children: [Revealer({ transition: 'slide_down', - transitionDuration: 150, + transitionDuration: userOptions.animations.durationLarge, setup: (self) => self .hook(GeminiService, (self, hasKey) => { self.revealChild = (GeminiService.key.length == 0); diff --git a/.config/ags/modules/sideleft/apis/waifu.js b/.config/ags/modules/sideleft/apis/waifu.js index 9bda586e8..7f12e8175 100644 --- a/.config/ags/modules/sideleft/apis/waifu.js +++ b/.config/ags/modules/sideleft/apis/waifu.js @@ -70,7 +70,7 @@ const WaifuImage = (taglist) => { const downloadState = Stack({ homogeneous: false, transition: 'slide_up_down', - transitionDuration: 150, + transitionDuration: userOptions.animations.durationSmall, children: { 'api': ImageState('api', 'Calling API'), 'download': ImageState('downloading', 'Downloading image'), @@ -128,7 +128,7 @@ const WaifuImage = (taglist) => { }); const blockImageRevealer = Revealer({ transition: 'slide_down', - transitionDuration: 150, + transitionDuration: userOptions.animations.durationLarge, revealChild: false, child: Overlay({ child: Box({ @@ -328,7 +328,7 @@ export const waifuView = Scrollable({ const waifuTags = Revealer({ revealChild: false, transition: 'crossfade', - transitionDuration: 150, + transitionDuration: userOptions.animations.durationLarge, child: Box({ className: 'spacing-h-5', children: [ diff --git a/.config/ags/modules/sideleft/apiwidgets.js b/.config/ags/modules/sideleft/apiwidgets.js index e65fad538..4fcaf74bd 100644 --- a/.config/ags/modules/sideleft/apiwidgets.js +++ b/.config/ags/modules/sideleft/apiwidgets.js @@ -136,7 +136,7 @@ const chatPlaceholder = Label({ const chatPlaceholderRevealer = Revealer({ revealChild: true, transition: 'crossfade', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, child: chatPlaceholder, setup: enableClickthrough, }); @@ -157,7 +157,7 @@ const textboxArea = Box({ // Entry area const apiContentStack = Stack({ vexpand: true, transition: 'slide_left_right', - transitionDuration: 160, + transitionDuration: userOptions.animations.durationLarge, children: APIS.reduce((acc, api) => { acc[api.name] = api.contentWidget; return acc; @@ -166,7 +166,7 @@ const apiContentStack = Stack({ const apiCommandStack = Stack({ transition: 'slide_up_down', - transitionDuration: 160, + transitionDuration: userOptions.animations.durationLarge, children: APIS.reduce((acc, api) => { acc[api.name] = api.commandBar; return acc; diff --git a/.config/ags/modules/sideleft/tools/module.js b/.config/ags/modules/sideleft/tools/module.js index cf6037e42..4bb275995 100644 --- a/.config/ags/modules/sideleft/tools/module.js +++ b/.config/ags/modules/sideleft/tools/module.js @@ -38,7 +38,7 @@ export default ({ const content = Revealer({ revealChild: revealChild, transition: 'slide_down', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, child: Box({ className: 'margin-top-5', homogeneous: true, diff --git a/.config/ags/modules/sideright/calendar.js b/.config/ags/modules/sideright/calendar.js index 43847e890..d47d2db79 100644 --- a/.config/ags/modules/sideright/calendar.js +++ b/.config/ags/modules/sideright/calendar.js @@ -147,7 +147,7 @@ const contentStack = Widget.Stack({ // 'stars': Widget.Label({ label: 'GitHub feed will be here' }), }, transition: 'slide_up_down', - transitionDuration: 180, + transitionDuration: userOptions.animations.durationLarge, setup: (stack) => Utils.timeout(1, () => { stack.shown = defaultShown; }) diff --git a/.config/ags/modules/sideright/notificationlist.js b/.config/ags/modules/sideright/notificationlist.js index 91a4dc33f..992bed57f 100644 --- a/.config/ags/modules/sideright/notificationlist.js +++ b/.config/ags/modules/sideright/notificationlist.js @@ -121,7 +121,7 @@ export default (props) => { }); const listContents = Stack({ transition: 'crossfade', - transitionDuration: 150, + transitionDuration: userOptions.animations.durationLarge, children: { 'empty': notifEmptyContent, 'list': notifList, diff --git a/.config/ags/modules/sideright/todolist.js b/.config/ags/modules/sideright/todolist.js index 7cc417a4a..75cbdfa73 100644 --- a/.config/ags/modules/sideright/todolist.js +++ b/.config/ags/modules/sideright/todolist.js @@ -67,7 +67,7 @@ const todoListItem = (task, id, isDone, isEven = false) => { const widgetRevealer = Widget.Revealer({ revealChild: true, transition: 'slide_down', - transitionDuration: 150, + transitionDuration: userOptions.animations.durationLarge, child: todoContent, }) return widgetRevealer; @@ -112,7 +112,7 @@ const todoItems = (isDone) => Widget.Scrollable({ const UndoneTodoList = () => { const newTaskButton = Revealer({ transition: 'slide_left', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, revealChild: true, child: Button({ className: 'txt-small sidebar-todo-new', @@ -131,7 +131,7 @@ const UndoneTodoList = () => { }); const cancelAddTask = Revealer({ transition: 'slide_right', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, revealChild: false, child: Button({ className: 'txt-norm icon-material sidebar-todo-add', @@ -162,13 +162,13 @@ const UndoneTodoList = () => { }); const newTaskEntryRevealer = Revealer({ transition: 'slide_right', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, revealChild: false, child: newTaskEntry, }); const confirmAddTask = Revealer({ transition: 'slide_right', - transitionDuration: 200, + transitionDuration: userOptions.animations.durationLarge, revealChild: false, child: Button({ className: 'txt-norm icon-material sidebar-todo-add', diff --git a/.config/ags/scss/_musicmaterial.scss b/.config/ags/scss/_musicmaterial.scss index 346fdf6e3..8b1378917 100644 --- a/.config/ags/scss/_musicmaterial.scss +++ b/.config/ags/scss/_musicmaterial.scss @@ -1,29 +1 @@ -$darkmode: true; -$primary: #8ccdff; -$onPrimary: #003350; -$primaryContainer: #004b73; -$onPrimaryContainer: #cae6ff; -$secondary: #b7c8d9; -$onSecondary: #22323f; -$secondaryContainer: #394856; -$onSecondaryContainer: #d3e4f6; -$tertiary: #d0bfe8; -$onTertiary: #362b4a; -$tertiaryContainer: #4e4162; -$onTertiaryContainer: #eddcff; -$error: #ffb4a9; -$onError: #680003; -$errorContainer: #930006; -$onErrorContainer: #ffb4a9; -$colorbarbg: #0F1012; -$background: #0F1012; -$onBackground: #e2e2e5; -$surface: #1a1c1e; -$onSurface: #e2e2e5; -$surfaceVariant: #41474d; -$onSurfaceVariant: #c2c7ce; -$outline: #8b9198; -$shadow: #000000; -$inverseSurface: #e2e2e5; -$inverseOnSurface: #2f3032; -$inversePrimary: #006497; + diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index 21886a4a3..21ca51b3c 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -5,6 +5,10 @@ let userConfigOptions = { 'defaultTemperature': 0.9, 'writingCursor': ' ...', // Warning: Using weird characters can mess up Markdown rendering }, + 'animations': { + 'durationSmall': 110, + 'durationLarge': 180, + }, 'apps': { 'imageViewer': 'loupe', }, From 62783209333cb4e7330608afcb8cca60cd7332ec Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 5 Mar 2024 11:18:45 +0700 Subject: [PATCH 068/517] music controls: back to css image prob will fix incremental lag over time --- .../ags/modules/indicators/musiccontrols.js | 104 ++++++++++-------- 1 file changed, 56 insertions(+), 48 deletions(-) diff --git a/.config/ags/modules/indicators/musiccontrols.js b/.config/ags/modules/indicators/musiccontrols.js index 8852c5740..9afd224d1 100644 --- a/.config/ags/modules/indicators/musiccontrols.js +++ b/.config/ags/modules/indicators/musiccontrols.js @@ -119,62 +119,63 @@ const CoverArt = ({ player, ...rest }) => { label: 'music_note', })] }); - const coverArtDrawingArea = Widget.DrawingArea({ className: 'osd-music-cover-art' }); - const coverArtDrawingAreaStyleContext = coverArtDrawingArea.get_style_context(); + // const coverArtDrawingArea = Widget.DrawingArea({ className: 'osd-music-cover-art' }); + // const coverArtDrawingAreaStyleContext = coverArtDrawingArea.get_style_context(); const realCoverArt = Box({ className: 'osd-music-cover-art', homogeneous: true, - children: [coverArtDrawingArea], + // children: [coverArtDrawingArea], attribute: { 'pixbuf': null, - 'showImage': (self, imagePath) => { - const borderRadius = coverArtDrawingAreaStyleContext.get_property('border-radius', Gtk.StateFlags.NORMAL); - const frameHeight = coverArtDrawingAreaStyleContext.get_property('min-height', Gtk.StateFlags.NORMAL); - const frameWidth = coverArtDrawingAreaStyleContext.get_property('min-width', Gtk.StateFlags.NORMAL); - let imageHeight = frameHeight; - let imageWidth = frameWidth; - // Get image dimensions - execAsync(['identify', '-format', '{"w":%w,"h":%h}', imagePath]) - .then((output) => { - const imageDimensions = JSON.parse(output); - const imageAspectRatio = imageDimensions.w / imageDimensions.h; - const displayedAspectRatio = imageWidth / imageHeight; - if (imageAspectRatio >= displayedAspectRatio) { - imageWidth = imageHeight * imageAspectRatio; - } else { - imageHeight = imageWidth / imageAspectRatio; - } - // Real stuff - // TODO: fix memory leak(?) - // if (self.attribute.pixbuf) { - // self.attribute.pixbuf.unref(); - // self.attribute.pixbuf = null; - // } - self.attribute.pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(imagePath, imageWidth, imageHeight); + // 'showImage': (self, imagePath) => { + // const borderRadius = coverArtDrawingAreaStyleContext.get_property('border-radius', Gtk.StateFlags.NORMAL); + // const frameHeight = coverArtDrawingAreaStyleContext.get_property('min-height', Gtk.StateFlags.NORMAL); + // const frameWidth = coverArtDrawingAreaStyleContext.get_property('min-width', Gtk.StateFlags.NORMAL); + // let imageHeight = frameHeight; + // let imageWidth = frameWidth; + // // Get image dimensions + // execAsync(['identify', '-format', '{"w":%w,"h":%h}', imagePath]) + // .then((output) => { + // const imageDimensions = JSON.parse(output); + // const imageAspectRatio = imageDimensions.w / imageDimensions.h; + // const displayedAspectRatio = imageWidth / imageHeight; + // if (imageAspectRatio >= displayedAspectRatio) { + // imageWidth = imageHeight * imageAspectRatio; + // } else { + // imageHeight = imageWidth / imageAspectRatio; + // } + // // Real stuff + // // TODO: fix memory leak(?) + // // if (self.attribute.pixbuf) { + // // self.attribute.pixbuf.unref(); + // // self.attribute.pixbuf = null; + // // } + // self.attribute.pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(imagePath, imageWidth, imageHeight); - coverArtDrawingArea.set_size_request(frameWidth, frameHeight); - coverArtDrawingArea.connect("draw", (widget, cr) => { - // Clip a rounded rectangle area - cr.arc(borderRadius, borderRadius, borderRadius, Math.PI, 1.5 * Math.PI); - cr.arc(frameWidth - borderRadius, borderRadius, borderRadius, 1.5 * Math.PI, 2 * Math.PI); - cr.arc(frameWidth - borderRadius, frameHeight - borderRadius, borderRadius, 0, 0.5 * Math.PI); - cr.arc(borderRadius, frameHeight - borderRadius, borderRadius, 0.5 * Math.PI, Math.PI); - cr.closePath(); - cr.clip(); - // Paint image as bg, centered - Gdk.cairo_set_source_pixbuf(cr, self.attribute.pixbuf, - frameWidth / 2 - imageWidth / 2, - frameHeight / 2 - imageHeight / 2 - ); - cr.paint(); - }); - }).catch(print) - }, + // coverArtDrawingArea.set_size_request(frameWidth, frameHeight); + // coverArtDrawingArea.connect("draw", (widget, cr) => { + // // Clip a rounded rectangle area + // cr.arc(borderRadius, borderRadius, borderRadius, Math.PI, 1.5 * Math.PI); + // cr.arc(frameWidth - borderRadius, borderRadius, borderRadius, 1.5 * Math.PI, 2 * Math.PI); + // cr.arc(frameWidth - borderRadius, frameHeight - borderRadius, borderRadius, 0, 0.5 * Math.PI); + // cr.arc(borderRadius, frameHeight - borderRadius, borderRadius, 0.5 * Math.PI, Math.PI); + // cr.closePath(); + // cr.clip(); + // // Paint image as bg, centered + // Gdk.cairo_set_source_pixbuf(cr, self.attribute.pixbuf, + // frameWidth / 2 - imageWidth / 2, + // frameHeight / 2 - imageHeight / 2 + // ); + // cr.paint(); + // }); + // }).catch(print) + // }, 'updateCover': (self) => { // const player = Mpris.getPlayer(); // Maybe no need to re-get player.. can't remember why I had this // Player closed // Note that cover path still remains, so we're checking title if (!player || player.trackTitle == "") { + self.css = `background-image: none;`; // CSS image App.applyCss(`${COMPILED_STYLE_DIR}/style.css`); return; } @@ -182,13 +183,17 @@ const CoverArt = ({ player, ...rest }) => { const coverPath = player.coverPath; const stylePath = `${player.coverPath}${lightDark}${COVER_COLORSCHEME_SUFFIX}`; if (player.coverPath == lastCoverPath) { // Since 'notify::cover-path' emits on cover download complete - Utils.timeout(200, () => self.attribute.showImage(self, coverPath)); + Utils.timeout(200, () => { + // self.attribute.showImage(self, coverPath); + self.css = `background-image: url('${coverPath}');`; // CSS image + }); } lastCoverPath = player.coverPath; // If a colorscheme has already been generated, skip generation if (fileExists(stylePath)) { - self.attribute.showImage(self, coverPath) + // self.attribute.showImage(self, coverPath) + self.css = `background-image: url('${coverPath}');`; // CSS image App.applyCss(stylePath); return; } @@ -200,7 +205,10 @@ const CoverArt = ({ player, ...rest }) => { exec(`wal -i "${player.coverPath}" -n -t -s -e -q ${lightDark}`) exec(`cp ${GLib.get_user_cache_dir()}/wal/colors.scss ${App.configDir}/scss/_musicwal.scss`); exec(`sass ${App.configDir}/scss/_music.scss ${stylePath}`); - Utils.timeout(200, () => self.attribute.showImage(self, coverPath)); + Utils.timeout(200, () => { + // self.attribute.showImage(self, coverPath) + self.css = `background-image: url('${coverPath}');`; // CSS image + }); App.applyCss(`${stylePath}`); }) .catch(print); From 42581e89499ce24c3b25a5319bc688e0261eb258 Mon Sep 17 00:00:00 2001 From: tchofy <64620317+tchofy@users.noreply.github.com> Date: Tue, 5 Mar 2024 02:17:53 -0300 Subject: [PATCH 069/517] Include arguments to grimblast --- .config/ags/modules/bar/normal/system.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/modules/bar/normal/system.js b/.config/ags/modules/bar/normal/system.js index 2e4c2e1b6..61f0d5ee2 100644 --- a/.config/ags/modules/bar/normal/system.js +++ b/.config/ags/modules/bar/normal/system.js @@ -67,7 +67,7 @@ const Utilities = () => Box({ children: [ UtilButton({ name: 'Screen snip', icon: 'screenshot_region', onClicked: () => { - Utils.execAsync(`${App.configDir}/scripts/grimblast.sh`) + Utils.execAsync(`${App.configDir}/scripts/grimblast.sh copy area`) .catch(print) } }), From f5cf1fccdac0e24de0611721fa7c92cfe0e9dfa5 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 5 Mar 2024 22:17:23 +0700 Subject: [PATCH 070/517] waifu widget: reorganize --- .config/ags/modules/sideleft/apis/waifu.js | 109 ++++++++++----------- .config/ags/services/waifus.js | 57 +++++------ 2 files changed, 77 insertions(+), 89 deletions(-) diff --git a/.config/ags/modules/sideleft/apis/waifu.js b/.config/ags/modules/sideleft/apis/waifu.js index 7f12e8175..503c0992b 100644 --- a/.config/ags/modules/sideleft/apis/waifu.js +++ b/.config/ags/modules/sideleft/apis/waifu.js @@ -40,10 +40,63 @@ export const waifuTabIcon = Box({ className: 'sidebar-chat-apiswitcher-icon', homogeneous: true, children: [ - MaterialIcon('photo_library', 'norm'), + MaterialIcon('photo', 'norm'), ] }); +const WaifuInfo = () => { + const waifuLogo = Label({ + hpack: 'center', + className: 'sidebar-chat-welcome-logo', + label: 'photo', + }) + return Box({ + vertical: true, + vexpand: true, + className: 'spacing-v-15', + children: [ + waifuLogo, + Label({ + className: 'txt txt-title-small sidebar-chat-welcome-txt', + wrap: true, + justify: Gtk.Justification.CENTER, + label: 'Waifus', + }), + Box({ + className: 'spacing-h-5', + hpack: 'center', + children: [ + Label({ + className: 'txt-smallie txt-subtext', + wrap: true, + justify: Gtk.Justification.CENTER, + label: 'Powered by waifu.im + other APIs', + }), + Button({ + className: 'txt-subtext txt-norm icon-material', + label: 'info', + tooltipText: 'Type tags for a random pic.\nNSFW content will not be returned unless\nyou explicitly request such a tag.\n\nDisclaimer: Not affiliated with the providers\nnor responsible for any of their content.', + setup: setupCursorHoverInfo, + }), + ] + }), + ] + }); +} + +const waifuWelcome = Box({ + vexpand: true, + homogeneous: true, + child: Box({ + className: 'spacing-v-15', + vpack: 'center', + vertical: true, + children: [ + WaifuInfo(), + ] + }) +}); + const WaifuImage = (taglist) => { const ImageState = (icon, name) => Box({ className: 'spacing-h-5 txt', @@ -220,59 +273,6 @@ const WaifuImage = (taglist) => { return thisBlock; } -const WaifuInfo = () => { - const waifuLogo = Label({ - hpack: 'center', - className: 'sidebar-chat-welcome-logo', - label: 'photo_library', - }) - return Box({ - vertical: true, - vexpand: true, - className: 'spacing-v-15', - children: [ - waifuLogo, - Label({ - className: 'txt txt-title-small sidebar-chat-welcome-txt', - wrap: true, - justify: Gtk.Justification.CENTER, - label: 'Waifus', - }), - Box({ - className: 'spacing-h-5', - hpack: 'center', - children: [ - Label({ - className: 'txt-smallie txt-subtext', - wrap: true, - justify: Gtk.Justification.CENTER, - label: 'Powered by waifu.im', - }), - Button({ - className: 'txt-subtext txt-norm icon-material', - label: 'info', - tooltipText: 'A free Waifu API. An alternative to waifu.pics.', - setup: setupCursorHoverInfo, - }), - ] - }), - ] - }); -} - -const waifuWelcome = Box({ - vexpand: true, - homogeneous: true, - child: Box({ - className: 'spacing-v-15', - vpack: 'center', - vertical: true, - children: [ - WaifuInfo(), - ] - }) -}); - const waifuContent = Box({ className: 'spacing-v-15', vertical: true, @@ -398,7 +398,6 @@ function newSimpleImageCall(name, url, width, height, dominantColor = '#9392A6') } export const sendMessage = (text) => { - // Do something on send // Commands if (text.startsWith('/')) { if (text.startsWith('/clear')) clearChat(); diff --git a/.config/ags/services/waifus.js b/.config/ags/services/waifus.js index 25ed220c0..8512ed59f 100644 --- a/.config/ags/services/waifus.js +++ b/.config/ags/services/waifus.js @@ -1,20 +1,21 @@ -import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import Service from 'resource:///com/github/Aylur/ags/service.js'; import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; -// Usage from my python waifu fetcher, for reference -// Usage: waifu-get.py [OPTION]... [TAG]... -// Options: -// --im\tUse waifu.im API. You can use many tags -// --pics\tUse waifu.pics API. Use 1 tag only. -// --nekos\tUse nekos.life (old) API. No tags. -// --segs\tForce NSFW images - -// Tags: -// waifu.im (type): -// maid waifu marin-kitagawa mori-calliope raiden-shogun oppai selfies uniform -// waifu.im (nsfw tags): -// ecchi hentai ero ass paizuri oral milf +// Note: this service is made mainly for waifu.im. Others might work but not as properly +const APISERVICES = { + 'im': { + 'endpoint': 'https://api.waifu.im/search', + 'headers': { 'Accept-Version': 'v5' }, + }, + 'nekos': { + 'endpoint': 'https://nekos.life/api/neko', + 'headers': {}, + }, + 'pics': { + 'endpoint': 'https://api.waifu.pics/sfw/', + 'headers': {}, + }, +}; function paramStringFromObj(params) { return Object.entries(params) @@ -33,23 +34,12 @@ function paramStringFromObj(params) { } class WaifuService extends Service { - _endpoints = { - 'im': 'https://api.waifu.im/search', - 'nekos': 'https://nekos.life/api/neko', - 'pics': 'https://api.waifu.pics/sfw/', - } - _headers = { - 'im': { 'Accept-Version': 'v5' }, - 'nekos': {}, - 'pics': {}, - } _baseUrl = 'https://api.waifu.im/search'; _mode = 'im'; // Allowed: im _responses = []; _queries = []; _nsfw = false; _minHeight = 600; - _status = 0; static { Service.register(this, { @@ -74,7 +64,7 @@ class WaifuService extends Service { get mode() { return this._mode } set mode(value) { this._mode = value; - this._baseUrl = this._endpoints[this._mode]; + this._baseUrl = APISERVICES[this._mode].endpoint; } get nsfw() { return this._nsfw } set nsfw(value) { this._nsfw = value } @@ -90,14 +80,14 @@ class WaifuService extends Service { // Construct body/headers for (let i = 0; i < userArgs.length; i++) { const thisArg = userArgs[i].trim(); - if(thisArg.length == 0) continue; + if (thisArg.length == 0) continue; if (thisArg == '--im') this._mode = 'im'; else if (thisArg == '--nekos') this._mode = 'nekos'; else if (thisArg.includes('pics')) this._mode = 'pics'; else if (thisArg.includes('segs') || thisArg.includes('sex') || thisArg.includes('lewd')) this._nsfw = true; else { taglist.push(thisArg); - if(['ecchi', 'hentai', 'ero', 'ass', 'paizuri', 'oral', 'milf'].includes(thisArg)) this._nsfw = true; + if (['ecchi', 'hentai', 'ero', 'ass', 'paizuri', 'oral', 'milf'].includes(thisArg)) this._nsfw = true; } } const newMessageId = this._queries.length; @@ -111,19 +101,19 @@ class WaifuService extends Service { const paramString = paramStringFromObj(params); // Fetch // Note: body isn't included since passing directly to url is more reliable - const options = { + const options = { method: 'GET', - headers: this._headers[this._mode], + headers: APISERVICES[this._mode].headers, }; - var status = 0; - Utils.fetch(`${this._endpoints[this._mode]}?${paramString}`, options) + let status = 0; + Utils.fetch(`${APISERVICES[this._mode].endpoint}?${paramString}`, options) .then(result => { status = result.status; return result.text(); }) .then((dataString) => { // Store interesting stuff and emit const parsedData = JSON.parse(dataString); - if (!parsedData.images) this._responses.push({ + if (!parsedData.images) this._responses.push({ // Failed status: status, signature: -1, url: '', @@ -153,7 +143,6 @@ class WaifuService extends Service { this.emit('updateResponse', newMessageId); }) .catch(print); - } } From 980627bd783c76891269ee2799f94f9a951b1d7c Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 5 Mar 2024 22:17:54 +0700 Subject: [PATCH 071/517] add eyecare widget :trollface: yande.re --- .config/ags/modules/sideleft/apis/booru.js | 361 +++++++++++++++++++ .config/ags/modules/sideleft/apis/chatgpt.js | 4 +- .config/ags/modules/sideleft/apiwidgets.js | 39 +- .config/ags/scss/_sidebars.scss | 8 + .config/ags/services/booru.js | 120 ++++++ .config/ags/user_options.js | 3 + 6 files changed, 524 insertions(+), 11 deletions(-) create mode 100644 .config/ags/modules/sideleft/apis/booru.js create mode 100644 .config/ags/services/booru.js diff --git a/.config/ags/modules/sideleft/apis/booru.js b/.config/ags/modules/sideleft/apis/booru.js new file mode 100644 index 000000000..6fe174d57 --- /dev/null +++ b/.config/ags/modules/sideleft/apis/booru.js @@ -0,0 +1,361 @@ +// TODO: execAsync(['identify', '-format', '{"w":%w,"h":%h}', imagePath]) +// to detect img dimensions + +const { Gdk, GdkPixbuf, Gio, GLib, Gtk } = imports.gi; +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; +import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; +const { Box, Button, Label, Overlay, Revealer, Scrollable, Stack } = Widget; +const { execAsync, exec } = Utils; +import { fileExists } from '../../.miscutils/files.js'; +import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; +import { MarginRevealer } from '../../.widgethacks/advancedrevealers.js'; +import { setupCursorHover, setupCursorHoverInfo } from '../../.widgetutils/cursorhover.js'; +import BooruService from '../../../services/booru.js'; +const Grid = Widget.subclass(Gtk.Grid, "AgsGrid"); + +async function getImageViewerApp(preferredApp) { + Utils.execAsync(['bash', '-c', `command -v ${preferredApp}`]) + .then((output) => { + if (output != '') return preferredApp; + else return 'xdg-open'; + }); +} + +const IMAGE_REVEAL_DELAY = 13; // Some wait for inits n other weird stuff +const IMAGE_VIEWER_APP = getImageViewerApp(userOptions.apps.imageViewer); // Gnome's image viewer cuz very comfortable zooming +const USER_CACHE_DIR = GLib.get_user_cache_dir(); + +// Create cache folder and clear pics from previous session +Utils.exec(`bash -c 'mkdir -p ${USER_CACHE_DIR}/ags/media/waifus'`); +Utils.exec(`bash -c 'rm ${USER_CACHE_DIR}/ags/media/waifus/*'`); + +const CommandButton = (command) => Button({ + className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small', + onClicked: () => sendMessage(command), + setup: setupCursorHover, + label: command, +}); + +export const booruTabIcon = Box({ + hpack: 'center', + className: 'sidebar-chat-apiswitcher-icon', + homogeneous: true, + children: [ + MaterialIcon('gallery_thumbnail', 'norm'), + ] +}); + +const BooruInfo = () => { + const booruLogo = Label({ + hpack: 'center', + className: 'sidebar-chat-welcome-logo', + label: 'gallery_thumbnail', + }) + return Box({ + vertical: true, + vexpand: true, + className: 'spacing-v-15', + children: [ + booruLogo, + Label({ + className: 'txt txt-title-small sidebar-chat-welcome-txt', + wrap: true, + justify: Gtk.Justification.CENTER, + label: 'Anime booru', + }), + Box({ + className: 'spacing-h-5', + hpack: 'center', + children: [ + Label({ + className: 'txt-smallie txt-subtext', + wrap: true, + justify: Gtk.Justification.CENTER, + label: 'Powered by yande.re', + }), + Button({ + className: 'txt-subtext txt-norm icon-material', + label: 'info', + tooltipText: 'An image booru. May contain NSFW content.\nWatch your back.\n\nDisclaimer: Not affiliated with the provider\nnor responsible for any of its content.', + setup: setupCursorHoverInfo, + }), + ] + }), + ] + }); +} + +const booruWelcome = Box({ + vexpand: true, + homogeneous: true, + child: Box({ + className: 'spacing-v-15', + vpack: 'center', + vertical: true, + children: [ + BooruInfo(), + ] + }) +}); + +const BooruPage = (taglist) => { + const PageState = (icon, name) => Box({ + className: 'spacing-h-5 txt', + children: [ + Box({ hexpand: true }), + Label({ + className: 'sidebar-waifu-txt txt-smallie', + xalign: 0, + label: name, + }), + MaterialIcon(icon, 'norm'), + ] + }) + const ImageAction = ({ name, icon, action }) => Button({ + className: 'sidebar-waifu-image-action txt-norm icon-material', + tooltipText: name, + label: icon, + onClicked: action, + setup: setupCursorHover, + }) + const PreviewImage = (data) => { + return Box({ + className: 'sidebar-booru-image', + // css: 'border: 2px solid white;', + css: `background-image: url('${data.preview_url}');`, + // setup: (self) => { + // Utils.timeout(1000, () => { + // self.css = `background-image: url('${data.preview_url}');`; + // }) + // } + }) + } + const colorIndicator = Box({ + className: `sidebar-chat-indicator`, + }); + const downloadState = Stack({ + homogeneous: false, + transition: 'slide_up_down', + transitionDuration: userOptions.animations.durationSmall, + children: { + 'api': PageState('api', 'Calling API'), + 'download': PageState('downloading', 'Downloading image'), + 'done': PageState('done', 'Finished!'), + 'error': PageState('error', 'Error'), + }, + }); + const downloadIndicator = MarginRevealer({ + vpack: 'center', + transition: 'slide_left', + revealChild: true, + child: downloadState, + }); + const pageHeading = Box({ + hpack: 'fill', + className: 'sidebar-waifu-content spacing-h-5', + children: [ + ...taglist.map((tag) => CommandButton(tag)), + Box({ hexpand: true }), + downloadIndicator, + ] + }); + const pageActions = Revealer({ + transition: 'crossfade', + revealChild: false, + child: Box({ + vertical: true, + children: [ + Box({ + className: 'sidebar-waifu-image-actions spacing-h-3', + children: [ + Box({ hexpand: true }), + ImageAction({ + name: 'Go to source', + icon: 'link', + action: () => execAsync(['xdg-open', `${thisPage.attribute.imageData.source}`]).catch(print), + }), + ImageAction({ + name: 'Hoard', + icon: 'save', + action: () => execAsync(['bash', '-c', `mkdir -p ~/Pictures/homework${thisPage.attribute.isNsfw ? '/🌶️' : ''} && cp ${thisPage.attribute.imagePath} ~/Pictures/homework${thisPage.attribute.isNsfw ? '/🌶️/' : ''}`]).catch(print), + }), + ImageAction({ + name: 'Open externally', + icon: 'open_in_new', + action: () => execAsync([IMAGE_VIEWER_APP, `${thisPage.attribute.imagePath}`]).catch(print), + }), + ] + }) + ], + }) + }) + const pageImageGrid = Grid({ + columnHomogeneous: true, + rowHomogeneous: true, + className: 'sidebar-waifu-image', + // css: 'min-height: 90px;' + }); + const pageImageRevealer = Revealer({ + transition: 'slide_down', + transitionDuration: userOptions.animations.durationLarge, + revealChild: false, + child: pageImageGrid, + }); + const thisPage = Box({ + className: 'sidebar-chat-message', + attribute: { + 'imagePath': '', + 'isNsfw': false, + 'imageData': '', + 'update': (data, force = false) => { + const imageData = data; + thisPage.attribute.imageData = imageData; + if (data.length == 0) { + downloadState.shown = 'error'; + return; + } + const imageColumns = userOptions.sidebar.imageColumns; + const imageRows = data.length / imageColumns; + // Add stuff + for (let i = 0; i < imageRows; i++) { + for (let j = 0; j < imageColumns; j++) { + if (i * imageColumns + j >= 8) break; + // if (i * imageColumns + j >= data.length) break; + pageImageGrid.attach(PreviewImage(data[i * imageColumns + j]), j, i, 1, 1); + } + } + pageImageGrid.show_all(); + + // Reveal stuff + Utils.timeout(IMAGE_REVEAL_DELAY, + () => pageImageRevealer.revealChild = true + ); + Utils.timeout(IMAGE_REVEAL_DELAY + pageImageRevealer.transitionDuration, + () => pageActions.revealChild = true + ); + downloadIndicator.attribute.hide(); + }, + }, + children: [ + colorIndicator, + Box({ + vertical: true, + className: 'spacing-v-5', + children: [ + pageHeading, + Box({ + vertical: true, + children: [pageImageRevealer], + }) + ] + }) + ], + }); + return thisPage; +} + +const booruContent = Box({ + className: 'spacing-v-15', + vertical: true, + attribute: { + 'map': new Map(), + }, + setup: (self) => self + .hook(BooruService, (box, id) => { + if (id === undefined) return; + const newPage = BooruPage(BooruService.queries[id]); + box.add(newPage); + box.show_all(); + box.attribute.map.set(id, newPage); + }, 'newResponse') + .hook(BooruService, (box, id) => { + if (id === undefined) return; + const data = BooruService.responses[id]; + if (!data) return; + const page = box.attribute.map.get(id); + page?.attribute.update(data); + }, 'updateResponse') + , +}); + +export const booruView = Scrollable({ + className: 'sidebar-chat-viewport', + vexpand: true, + child: Box({ + vertical: true, + children: [ + booruWelcome, + booruContent, + ] + }), + setup: (scrolledWindow) => { + // Show scrollbar + scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + const vScrollbar = scrolledWindow.get_vscrollbar(); + vScrollbar.get_style_context().add_class('sidebar-scrollbar'); + // Avoid click-to-scroll-widget-to-view behavior + Utils.timeout(1, () => { + const viewport = scrolledWindow.child; + viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined)); + }) + // Always scroll to bottom with new content + const adjustment = scrolledWindow.get_vadjustment(); + adjustment.connect("changed", () => { + adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size()); + }) + } +}); + +const booruTags = Revealer({ + revealChild: false, + transition: 'crossfade', + transitionDuration: userOptions.animations.durationLarge, + child: Box({ + className: 'spacing-h-5', + children: [ + Scrollable({ + vscroll: 'never', + hscroll: 'automatic', + hexpand: true, + child: Box({ + className: 'spacing-h-5', + children: [ + CommandButton('hololive'), + ] + }) + }), + Box({ className: 'separator-line' }), + ] + }) +}); + +export const booruCommands = Box({ + className: 'spacing-h-5', + setup: (self) => { + self.pack_end(CommandButton('/clear'), false, false, 0); + self.pack_start(Button({ + className: 'sidebar-chat-chip-toggle', + setup: setupCursorHover, + label: 'Tags →', + onClicked: () => { + booruTags.revealChild = !booruTags.revealChild; + } + }), false, false, 0); + self.pack_start(booruTags, true, true, 0); + } +}); + +const clearChat = () => { // destroy!! + booruContent.attribute.map.forEach((value, key, map) => { + value.destroy(); + value = null; + }); +} + +export const sendMessage = (text) => { + // Commands + if (text.startsWith('/')) { + if (text.startsWith('/clear')) clearChat(); + } + else BooruService.fetch(text); +} \ No newline at end of file diff --git a/.config/ags/modules/sideleft/apis/chatgpt.js b/.config/ags/modules/sideleft/apis/chatgpt.js index fa16acec1..312c4db21 100644 --- a/.config/ags/modules/sideleft/apis/chatgpt.js +++ b/.config/ags/modules/sideleft/apis/chatgpt.js @@ -131,12 +131,12 @@ const GPTInfo = () => { className: 'txt-smallie txt-subtext', wrap: true, justify: Gtk.Justification.CENTER, - label: 'Powered by OpenAI', + label: 'Provider shown above', }), Button({ className: 'txt-subtext txt-norm icon-material', label: 'info', - tooltipText: 'Uses gpt-3.5-turbo.\nNot affiliated, endorsed, or sponsored by OpenAI.\n\nPrivacy: OpenAI claims they do not use your data when you use their API.', + tooltipText: 'Uses gpt-3.5-turbo.\nNot affiliated, endorsed, or sponsored by OpenAI.\n\nPrivacy: OpenAI claims they do not use your data\nwhen you use their API. Idk about others.', setup: setupCursorHoverInfo, }), ] diff --git a/.config/ags/modules/sideleft/apiwidgets.js b/.config/ags/modules/sideleft/apiwidgets.js index 4fcaf74bd..dfa4ca2c8 100644 --- a/.config/ags/modules/sideleft/apiwidgets.js +++ b/.config/ags/modules/sideleft/apiwidgets.js @@ -10,9 +10,12 @@ import Gemini from '../../services/gemini.js'; import { geminiView, geminiCommands, sendMessage as geminiSendMessage, geminiTabIcon } from './apis/gemini.js'; import { chatGPTView, chatGPTCommands, sendMessage as chatGPTSendMessage, chatGPTTabIcon } from './apis/chatgpt.js'; import { waifuView, waifuCommands, sendMessage as waifuSendMessage, waifuTabIcon } from './apis/waifu.js'; +import { booruView, booruCommands, sendMessage as booruSendMessage, booruTabIcon } from './apis/booru.js'; import { enableClickthrough } from "../.widgetutils/clickthrough.js"; const TextView = Widget.subclass(Gtk.TextView, "AgsTextView"); +import { widgetContent } from './sideleft.js'; + const EXPAND_INPUT_THRESHOLD = 30; const APIS = [ { @@ -39,6 +42,14 @@ const APIS = [ tabIcon: waifuTabIcon, placeholderText: 'Enter tags', }, + { + name: 'Booru', + sendCommand: booruSendMessage, + contentWidget: booruView, + commandBar: booruCommands, + tabIcon: booruTabIcon, + placeholderText: 'Enter tags', + }, ]; let currentApiId = 0; APIS[currentApiId].tabIcon.toggleClassName('sidebar-chat-apiswitcher-icon-enabled', true); @@ -77,16 +88,26 @@ export const chatEntry = TextView({ apiSendMessage(widget); return true; } - // Global keybinds - if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) && - event.get_keyval()[1] === Gdk.KEY_Page_Down) { - apiWidgets.attribute.nextTab(); - return true; + // Keybinds + if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK)) { + if (event.get_keyval()[1] === Gdk.KEY_Page_Down) { + apiWidgets.attribute.nextTab(); + return true; + } + else if (event.get_keyval()[1] === Gdk.KEY_Page_Up) { + apiWidgets.attribute.prevTab(); + return true; + } } - else if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) && - event.get_keyval()[1] === Gdk.KEY_Page_Up) { - apiWidgets.attribute.prevTab(); - return true; + else if (event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) { + if (event.get_keyval()[1] === Gdk.KEY_Page_Down) { + widgetContent.nextTab(); + return true; + } + else if (event.get_keyval()[1] === Gdk.KEY_Page_Up) { + widgetContent.prevTab(); + return true; + } } }) , diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss index 6ed2bab3a..52959ae45 100644 --- a/.config/ags/scss/_sidebars.scss +++ b/.config/ags/scss/_sidebars.scss @@ -847,3 +847,11 @@ $waifu_image_overlay_transparency: 0.7; .sidebar-waifu-image-action:active { background-color: rgba(60, 60, 60, $waifu_image_overlay_transparency); } + +.sidebar-booru-image { + min-width: 8.523rem; + min-height: 8.523rem; + background-size: cover; + background-repeat: no-repeat; + background-position: center; +} \ No newline at end of file diff --git a/.config/ags/services/booru.js b/.config/ags/services/booru.js new file mode 100644 index 000000000..9d8d5d2c2 --- /dev/null +++ b/.config/ags/services/booru.js @@ -0,0 +1,120 @@ +import Service from 'resource:///com/github/Aylur/ags/service.js'; +import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; + +const APISERVICES = { + 'yandere': { + endpoint: 'https://yande.re/post.json', + } +} + +const getWorkingImageSauce = (url) => { + if(url.includes('pximg.net')) { + return `https://www.pixiv.net/en/artworks/${url.substring(url.lastIndexOf('/')).replace(/_p\d+\.png$/, '')}`; + } + return url; +} + +function paramStringFromObj(params) { + return Object.entries(params) + .map(([key, value]) => { + if (Array.isArray(value)) { // If it's an array, repeat + if (value.length == 0) return ''; + let thisKey = `${encodeURIComponent(key)}=${encodeURIComponent(value[0])}` + for (let i = 1; i < value.length; i++) { + thisKey += `&${encodeURIComponent(key)}=${encodeURIComponent(value[i])}`; + } + return thisKey; + } + return `${key}=${value}`; + }) + .join('&'); +} + +class BooruService extends Service { + _baseUrl = 'https://yande.re/post.json'; + _mode = 'yandere'; + _responses = []; + _queries = []; + + static { + Service.register(this, { + 'initialized': [], + 'clear': [], + 'newResponse': ['int'], + 'updateResponse': ['int'], + }); + } + + constructor() { + super(); + this.emit('initialized'); + } + + clear() { + this._responses = []; + this._queries = []; + this.emit('clear'); + } + + get mode() { return this._mode } + set mode(value) { + this._mode = value; + this._baseUrl = APISERVICES[this._mode].endpoint; + } + get queries() { return this._queries } + get responses() { return this._responses } + + async fetch(msg) { + // Init + const userArgs = msg.split(/\s+/); + + let taglist = []; + // Construct body/headers + for (let i = 0; i < userArgs.length; i++) { + const thisArg = userArgs[i].trim(); + if (thisArg.length == 0 || thisArg == '.' || thisArg == '*') continue; + else taglist.push(thisArg); + } + const newMessageId = this._queries.length; + this._queries.push(taglist.length == 0 ? ['*'] : taglist); + this.emit('newResponse', newMessageId); + const params = { + 'tags': taglist.join('+'), + }; + const paramString = paramStringFromObj(params); + console.log('==========PARAMS LIST\n', params, '\n============\nSTR\n', paramString) + // Fetch + // Note: body isn't included since passing directly to url is more reliable + const options = { + method: 'GET', + headers: APISERVICES[this._mode].headers, + }; + let status = 0; + Utils.fetch(`${APISERVICES[this._mode].endpoint}?${paramString}`, options) + .then(result => { + status = result.status; + return result.text(); + }) + .then((dataString) => { // Store interesting stuff and emit + const parsedData = JSON.parse(dataString); + this._responses.push(parsedData.map(obj => { + return { + md5: obj.md5, + preview_url: obj.preview_url, + preview_width: obj.preview_width, + preview_height: obj.preview_height, + sample_url: obj.sample_url, + sample_width: obj.sample_width, + sample_height: obj.sample_height, + source: getWorkingImageSauce(obj.source), + } + })); + this.emit('updateResponse', newMessageId); + }) + .catch(print); + + } +} + +export default new BooruService(); + diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index 21ca51b3c..b906bcaaf 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -29,6 +29,9 @@ let userConfigOptions = { 'wsNumScale': 0.09, 'wsNumMarginScale': 0.07, }, + 'sidebar': { + 'imageColumns': 3, + }, 'search': { 'engineBaseUrl': 'https://www.google.com/search?q=', 'excludedSites': ['quora.com'], From 4ba07f6bbeb3bb9251563b2b46023c30de4a4483 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 5 Mar 2024 22:24:03 +0700 Subject: [PATCH 072/517] ags: add terminal config option --- .config/ags/modules/overview/miscfunctions.js | 2 +- .config/ags/modules/sideleft/tools/quickscripts.js | 2 +- .config/ags/user_options.js | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.config/ags/modules/overview/miscfunctions.js b/.config/ags/modules/overview/miscfunctions.js index ca592d01d..aa184f8ed 100644 --- a/.config/ags/modules/overview/miscfunctions.js +++ b/.config/ags/modules/overview/miscfunctions.js @@ -64,7 +64,7 @@ export function launchCustomCommand(command) { export function execAndClose(command, terminal) { App.closeWindow('overview'); if (terminal) { - execAsync([`bash`, `-c`, `foot fish -C "${command}"`, `&`]).catch(print); + execAsync([`bash`, `-c`, `${userOptions.apps.terminal} fish -C "${command}"`, `&`]).catch(print); } else execAsync(command).catch(print); diff --git a/.config/ags/modules/sideleft/tools/quickscripts.js b/.config/ags/modules/sideleft/tools/quickscripts.js index fea8dc40f..ed4b63db5 100644 --- a/.config/ags/modules/sideleft/tools/quickscripts.js +++ b/.config/ags/modules/sideleft/tools/quickscripts.js @@ -77,7 +77,7 @@ export default () => SidebarModule({ child: scriptStateIcon, onClicked: () => { App.closeWindow('sideleft'); - execAsync([`bash`, `-c`, `foot fish -C "${script.command}"`]).catch(print) + execAsync([`bash`, `-c`, `${userOptions.apps.terminal} fish -C "${script.command}"`]).catch(print) .then(() => { scriptStateIcon.label = 'done'; }) diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index b906bcaaf..f88cbb8c3 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -11,6 +11,7 @@ let userConfigOptions = { }, 'apps': { 'imageViewer': 'loupe', + 'terminal': 'foot', // This is only for shell actions }, 'battery': { 'low': 20, From 689b16b90acad4aefb4f30f4223750d8cf3e4e4f Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 5 Mar 2024 22:46:07 +0700 Subject: [PATCH 073/517] fix zukijourney api (?) (#305) --- .config/ags/services/gpt.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/ags/services/gpt.js b/.config/ags/services/gpt.js index 5d48e67be..d0cc8ac15 100644 --- a/.config/ags/services/gpt.js +++ b/.config/ags/services/gpt.js @@ -248,8 +248,6 @@ class GPTService extends Service { this._messages.push(new GPTMessage('user', msg)); this.emit('newMsg', this._messages.length - 1); const aiResponse = new GPTMessage('assistant', 'thinking...', true, false) - this._messages.push(aiResponse); - this.emit('newMsg', this._messages.length - 1); const body = { model: CHAT_MODELS[this._modelIndex], @@ -274,6 +272,8 @@ class GPTService extends Service { base_stream: stream }), aiResponse); }); + this._messages.push(aiResponse); + this.emit('newMsg', this._messages.length - 1); if (this._cycleModels) { this._requestCount++; From b2850714435037fdbd6aadc7654eb0bbe0cd367e Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 5 Mar 2024 22:50:06 +0700 Subject: [PATCH 074/517] update ags --- scriptdata/installers | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scriptdata/installers b/scriptdata/installers index 8d2fe7bab..c46015c6e 100644 --- a/scriptdata/installers +++ b/scriptdata/installers @@ -24,7 +24,7 @@ install-ags (){ try git init -b main try git remote add origin https://github.com/Aylur/ags.git x git pull origin main && git submodule update --init --recursive - x git checkout 7ba2efd705ea255b87e4812b22bb656b60d291d4 # "add fallback generic Attribute type to widget functions" + x git checkout e257efa0a13c50538bed77ca6e557dc4dd3a3482 # add Widget.keybind #248 x npm install x meson setup build x meson install -C build From 1f1283f0621bb9d2ce3eafbf36e64fbd65d25927 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 5 Mar 2024 23:07:05 +0700 Subject: [PATCH 075/517] allow city names with space #301 --- .config/ags/modules/bar/normal/system.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/modules/bar/normal/system.js b/.config/ags/modules/bar/normal/system.js index 61f0d5ee2..4201580ec 100644 --- a/.config/ags/modules/bar/normal/system.js +++ b/.config/ags/modules/bar/normal/system.js @@ -185,7 +185,7 @@ const BatteryModule = () => Stack({ } }); if (userOptions.weather.city != '' && userOptions.weather.city != null) { - updateWeatherForCity(userOptions.weather.city); + updateWeatherForCity(userOptions.weather.city.replace(/ /g, '%20')); } else { Utils.execAsync('curl ipinfo.io') From dd08a134fcf70f78977a3faacc8699b7639e90aa Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 5 Mar 2024 23:09:16 +0700 Subject: [PATCH 076/517] #301 but for auto detected city name also --- .config/ags/modules/bar/normal/system.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/modules/bar/normal/system.js b/.config/ags/modules/bar/normal/system.js index 4201580ec..9da2d5aed 100644 --- a/.config/ags/modules/bar/normal/system.js +++ b/.config/ags/modules/bar/normal/system.js @@ -154,7 +154,7 @@ const BatteryModule = () => Stack({ ], setup: (self) => self.poll(900000, async (self) => { const WEATHER_CACHE_PATH = WEATHER_CACHE_FOLDER + '/wttr.in.txt'; - const updateWeatherForCity = (city) => execAsync(`curl https://wttr.in/${city}?format=j1`) + const updateWeatherForCity = (city) => execAsync(`curl https://wttr.in/${city.replace(/ /g, '%20')}?format=j1`) .then(output => { const weather = JSON.parse(output); Utils.writeFile(JSON.stringify(weather), WEATHER_CACHE_PATH) From eeb2fb9bc71352d83d860de4ea4874c6c92ac725 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 5 Mar 2024 23:59:55 +0700 Subject: [PATCH 077/517] ags: allow configuring keybinds https://github.com/end-4/dots-hyprland-wiki/issues/5 --- .config/ags/modules/.widgetutils/keybind.js | 26 +++++++++++++++ .config/ags/modules/overview/windowcontent.js | 29 +++++++--------- .config/ags/modules/sideleft/apiwidgets.js | 33 ++++++++----------- .config/ags/modules/sideleft/sideleft.js | 28 +++++++--------- .config/ags/user_options.js | 26 +++++++++++++-- 5 files changed, 88 insertions(+), 54 deletions(-) create mode 100644 .config/ags/modules/.widgetutils/keybind.js diff --git a/.config/ags/modules/.widgetutils/keybind.js b/.config/ags/modules/.widgetutils/keybind.js new file mode 100644 index 000000000..f3d723a93 --- /dev/null +++ b/.config/ags/modules/.widgetutils/keybind.js @@ -0,0 +1,26 @@ +const { Gdk } = imports.gi; + +const MODS = { + 'NoMod': Gdk.ModifierType.NO_MODIFIER_MASK, + 'Shift': Gdk.ModifierType.SHIFT_MASK, + 'Ctrl': Gdk.ModifierType.CONTROL_MASK, + 'Alt': Gdk.ModifierType.ALT_MASK, + 'Hyper': Gdk.ModifierType.HYPER_MASK, + 'Meta': Gdk.ModifierType.META_MASK +} + +export const checkKeybind = (event, keybind) => { + const pressedModMask = event.get_state()[1]; + const pressedKey = event.get_keyval()[1]; + const keys = keybind.split('+'); + for (let i = 0; i < keys.length; i++) { + if (keys[i] in MODS) { + if (!(pressedModMask & MODS[keys[i]])) { + return false; + } + } else if (pressedKey !== Gdk[`KEY_${keys[i]}`]) { + return false; + } + } + return true; +} diff --git a/.config/ags/modules/overview/windowcontent.js b/.config/ags/modules/overview/windowcontent.js index 3486c1fe7..675464d01 100644 --- a/.config/ags/modules/overview/windowcontent.js +++ b/.config/ags/modules/overview/windowcontent.js @@ -10,6 +10,7 @@ import { CalculationResultButton, CustomCommandButton, DirectoryButton, DesktopEntryButton, ExecuteCommandButton, SearchButton } from './searchbuttons.js'; +import { checkKeybind } from '../.widgetutils/keybind.js'; // Add math funcs const { abs, sin, cos, tan, cot, asin, acos, atan, acot } = Math; @@ -237,24 +238,18 @@ export const SearchAndWindows = () => { .on('key-press-event', (widget, event) => { // Typing const keyval = event.get_keyval()[1]; const modstate = event.get_state()[1]; - if (modstate & Gdk.ModifierType.CONTROL_MASK) { // Ctrl held - if (keyval == Gdk.KEY_b) - entry.set_position(Math.max(entry.get_position() - 1, 0)); - else if (keyval == Gdk.KEY_f) - entry.set_position(Math.min(entry.get_position() + 1, entry.get_text().length)); - else if (keyval == Gdk.KEY_n) { // simulate Down arrow - entry.get_root_window().simulate_key_press(Gdk.KEY_Down, Gdk.ModifierType.NONE); - // entry.get_root_window().simulate_key_release(Gdk.KEY_Down, Gdk.ModifierType.NONE); - } - else if (keyval == Gdk.KEY_k) { // Delete to end - const text = entry.get_text(); - const pos = entry.get_position(); - const newText = text.slice(0, pos); - entry.set_text(newText); - entry.set_position(newText.length); - } + if (checkKeybind(event, userOptions.keybinds.overview.altMoveLeft)) + entry.set_position(Math.max(entry.get_position() - 1, 0)); + else if (checkKeybind(event, userOptions.keybinds.overview.altMoveRight)) + entry.set_position(Math.min(entry.get_position() + 1, entry.get_text().length)); + else if (checkKeybind(event, userOptions.keybinds.overview.deleteToEnd)) { + const text = entry.get_text(); + const pos = entry.get_position(); + const newText = text.slice(0, pos); + entry.set_text(newText); + entry.set_position(newText.length); } - else { // Ctrl not held + else if (!(modstate & Gdk.ModifierType.CONTROL_MASK)) { // Ctrl not held if (keyval >= 32 && keyval <= 126 && widget != entry) { Utils.timeout(1, () => entry.grab_focus()); entry.set_text(entry.text + String.fromCharCode(keyval)); diff --git a/.config/ags/modules/sideleft/apiwidgets.js b/.config/ags/modules/sideleft/apiwidgets.js index dfa4ca2c8..b75b9ed9c 100644 --- a/.config/ags/modules/sideleft/apiwidgets.js +++ b/.config/ags/modules/sideleft/apiwidgets.js @@ -12,6 +12,7 @@ import { chatGPTView, chatGPTCommands, sendMessage as chatGPTSendMessage, chatGP import { waifuView, waifuCommands, sendMessage as waifuSendMessage, waifuTabIcon } from './apis/waifu.js'; import { booruView, booruCommands, sendMessage as booruSendMessage, booruTabIcon } from './apis/booru.js'; import { enableClickthrough } from "../.widgetutils/clickthrough.js"; +import { checkKeybind } from '../.widgetutils/keybind.js'; const TextView = Widget.subclass(Gtk.TextView, "AgsTextView"); import { widgetContent } from './sideleft.js'; @@ -83,31 +84,25 @@ export const chatEntry = TextView({ self.placeholderText = (Gemini.key.length > 0 ? 'Message Gemini...' : 'Enter Google AI API Key...'); }, 'hasKey') .on("key-press-event", (widget, event) => { - const keyval = event.get_keyval()[1]; + // Don't send when Shift+Enter if (event.get_keyval()[1] === Gdk.KEY_Return && event.get_state()[1] == Gdk.ModifierType.MOD2_MASK) { apiSendMessage(widget); return true; } // Keybinds - if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK)) { - if (event.get_keyval()[1] === Gdk.KEY_Page_Down) { - apiWidgets.attribute.nextTab(); - return true; - } - else if (event.get_keyval()[1] === Gdk.KEY_Page_Up) { - apiWidgets.attribute.prevTab(); - return true; - } + if (checkKeybind(event, userOptions.keybinds.sidebar.cycleTab)) + widgetContent.cycleTab(); + else if (checkKeybind(event, userOptions.keybinds.sidebar.nextTab)) + widgetContent.nextTab(); + else if (checkKeybind(event, userOptions.keybinds.sidebar.prevTab)) + widgetContent.prevTab(); + else if (checkKeybind(event, userOptions.keybinds.sidebar.apis.nextTab)) { + apiWidgets.attribute.nextTab(); + return true; } - else if (event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) { - if (event.get_keyval()[1] === Gdk.KEY_Page_Down) { - widgetContent.nextTab(); - return true; - } - else if (event.get_keyval()[1] === Gdk.KEY_Page_Up) { - widgetContent.prevTab(); - return true; - } + else if (checkKeybind(event, userOptions.keybinds.sidebar.apis.prevTab)) { + apiWidgets.attribute.prevTab(); + return true; } }) , diff --git a/.config/ags/modules/sideleft/sideleft.js b/.config/ags/modules/sideleft/sideleft.js index 5ae293849..377273517 100644 --- a/.config/ags/modules/sideleft/sideleft.js +++ b/.config/ags/modules/sideleft/sideleft.js @@ -10,6 +10,7 @@ import toolBox from './toolbox.js'; import apiWidgets from './apiwidgets.js'; import { chatEntry } from './apiwidgets.js'; import { TabContainer } from '../.commonwidgets/tabcontainer.js'; +import { checkKeybind } from '../.widgetutils/keybind.js'; const contents = [ { @@ -85,18 +86,15 @@ export default () => Box({ ], setup: (self) => self .on('key-press-event', (widget, event) => { // Handle keybinds - if (event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) { // Ctrl held - // Pin sidebar - if (event.get_keyval()[1] == Gdk.KEY_p) - pinButton.attribute.toggle(pinButton); - // Switch sidebar tab - else if (event.get_keyval()[1] === Gdk.KEY_Tab) - widgetContent.cycleTab(); - else if (event.get_keyval()[1] === Gdk.KEY_Page_Up) - widgetContent.prevTab(); - else if (event.get_keyval()[1] === Gdk.KEY_Page_Down) - widgetContent.nextTab(); - } + if (checkKeybind(event, userOptions.keybinds.sidebar.pin)) + pinButton.attribute.toggle(pinButton); + else if (checkKeybind(event, userOptions.keybinds.sidebar.cycleTab)) + widgetContent.cycleTab(); + else if (checkKeybind(event, userOptions.keybinds.sidebar.nextTab)) + widgetContent.nextTab(); + else if (checkKeybind(event, userOptions.keybinds.sidebar.prevTab)) + widgetContent.prevTab(); + if (widgetContent.attribute.names[widgetContent.attribute.shown.value] == 'APIs') { // If api tab is focused // Focus entry when typing if (( @@ -113,13 +111,11 @@ export default () => Box({ buffer.place_cursor(buffer.get_iter_at_offset(-1)); } // Switch API type - else if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) && - event.get_keyval()[1] === Gdk.KEY_Page_Down) { + else if (checkKeybind(event, userOptions.keybinds.sidebar.apis.nextTab)) { const toSwitchTab = widgetContent.attribute.children[widgetContent.attribute.shown.value]; toSwitchTab.attribute.nextTab(); } - else if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) && - event.get_keyval()[1] === Gdk.KEY_Page_Up) { + else if (checkKeybind(event, userOptions.keybinds.sidebar.apis.prevTab)) { const toSwitchTab = widgetContent.attribute.children[widgetContent.attribute.shown.value]; toSwitchTab.attribute.prevTab(); } diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index f88cbb8c3..79a8e7e2e 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -1,5 +1,6 @@ let userConfigOptions = { + // General stuff 'ai': { 'defaultGPTProvider': 'openai', 'defaultTemperature': 0.9, @@ -43,7 +44,8 @@ let userConfigOptions = { 'workspaces': { 'shown': 10, }, - icons: { + // Longer stuff + 'icons': { substitutions: { 'code-url-handler': 'visual-studio-code', 'Code': 'visual-studio-code', @@ -55,7 +57,27 @@ let userConfigOptions = { 'wpsoffice': 'wps-office2019-kprometheus', '': 'image-missing', } - } + }, + 'keybinds': { + // Format: Mod1+Mod2+key. CaSe SeNsItIvE! + // Modifiers: Shift Ctrl Alt Hyper Meta NoMod + // See https://docs.gtk.org/gdk3/index.html#constants for the other keys + 'overview': { + 'altMoveLeft': 'Ctrl+b', + 'altMoveRight': 'Ctrl+f', + 'deleteToEnd': 'Ctrl+k', + }, + 'sidebar': { + 'apis': { + 'nextTab': 'Page_Down', + 'prevTab': 'Page_Up', + }, + 'pin': 'Ctrl+p', + 'cycleTab': 'Ctrl+Tab', + 'nextTab': 'Ctrl+Page_Down', + 'prevTab': 'Ctrl+Page_Up', + }, + }, } globalThis['userOptions'] = userConfigOptions; From 12baf108be28cbc1aa37feee6116dd0eed057581 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 6 Mar 2024 00:02:20 +0700 Subject: [PATCH 078/517] add keybind note --- .config/ags/user_options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index 79a8e7e2e..edd56cab6 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -61,7 +61,7 @@ let userConfigOptions = { 'keybinds': { // Format: Mod1+Mod2+key. CaSe SeNsItIvE! // Modifiers: Shift Ctrl Alt Hyper Meta NoMod - // See https://docs.gtk.org/gdk3/index.html#constants for the other keys + // See https://docs.gtk.org/gdk3/index.html#constants for the other keys (they are listed as KEY_key) 'overview': { 'altMoveLeft': 'Ctrl+b', 'altMoveRight': 'Ctrl+f', From 5d28f309a5870efcc42edd699e7bf9d6db3933f4 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 6 Mar 2024 00:03:21 +0700 Subject: [PATCH 079/517] keybinds: remove NoMod --- .config/ags/modules/.widgetutils/keybind.js | 1 - .config/ags/user_options.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.config/ags/modules/.widgetutils/keybind.js b/.config/ags/modules/.widgetutils/keybind.js index f3d723a93..eda7877bd 100644 --- a/.config/ags/modules/.widgetutils/keybind.js +++ b/.config/ags/modules/.widgetutils/keybind.js @@ -1,7 +1,6 @@ const { Gdk } = imports.gi; const MODS = { - 'NoMod': Gdk.ModifierType.NO_MODIFIER_MASK, 'Shift': Gdk.ModifierType.SHIFT_MASK, 'Ctrl': Gdk.ModifierType.CONTROL_MASK, 'Alt': Gdk.ModifierType.ALT_MASK, diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index edd56cab6..11ffd5f40 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -60,7 +60,7 @@ let userConfigOptions = { }, 'keybinds': { // Format: Mod1+Mod2+key. CaSe SeNsItIvE! - // Modifiers: Shift Ctrl Alt Hyper Meta NoMod + // Modifiers: Shift Ctrl Alt Hyper Meta // See https://docs.gtk.org/gdk3/index.html#constants for the other keys (they are listed as KEY_key) 'overview': { 'altMoveLeft': 'Ctrl+b', From 1e0ad6ca24c2cfdc240854e252fdae6a0d62c9d3 Mon Sep 17 00:00:00 2001 From: clsty Date: Wed, 6 Mar 2024 13:19:35 +0800 Subject: [PATCH 080/517] Fix typo in install.sh --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 091a16a53..a832345e9 100755 --- a/install.sh +++ b/install.sh @@ -147,7 +147,7 @@ v mkdir -p "$HOME"/.{config,cache,local/{bin,share}} # (eg. in ~/.config/hypr) won't be mixed together # For .config/* but not AGS, not Hyprland -for file in $(find .config/ -mindepth 1 -maxdepth 1 ! -name 'ags' ! -name 'hypr' -exec basename {} \;); do +for i in $(find .config/ -mindepth 1 -maxdepth 1 ! -name 'ags' ! -name 'hypr' -exec basename {} \;); do echo "[$0]: Found target: $i" if [ -d "$i" ];then v rsync -av --delete "$i/" "$HOME/$i/" elif [ -f "$i" ];then v rsync -av "$i" "$HOME/$i" From b5181681b4877d74b145e9c512a9d06846657353 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:27:41 +0700 Subject: [PATCH 081/517] user config: add time format #307 --- .../modules/.commonwidgets/notification.js | 2 +- .config/ags/modules/bar/normal/system.js | 6 +- .../desktopbackground/timeandlaunches.js | 6 +- .config/ags/user_options.js | 63 ++++++++++--------- 4 files changed, 42 insertions(+), 35 deletions(-) diff --git a/.config/ags/modules/.commonwidgets/notification.js b/.config/ags/modules/.commonwidgets/notification.js index 93fd686cb..251320db3 100644 --- a/.config/ags/modules/.commonwidgets/notification.js +++ b/.config/ags/modules/.commonwidgets/notification.js @@ -218,7 +218,7 @@ export default ({ let notifTime = ''; const messageTime = GLib.DateTime.new_from_unix_local(notifObject.time); if (messageTime.get_day_of_year() == GLib.DateTime.new_now_local().get_day_of_year()) - notifTime = messageTime.format('%H:%M'); + notifTime = messageTime.format(userOptions.time.format); else if (messageTime.get_day_of_year() == GLib.DateTime.new_now_local().get_day_of_year() - 1) notifTime = 'Yesterday'; else diff --git a/.config/ags/modules/bar/normal/system.js b/.config/ags/modules/bar/normal/system.js index 9da2d5aed..ba0e4acf0 100644 --- a/.config/ags/modules/bar/normal/system.js +++ b/.config/ags/modules/bar/normal/system.js @@ -34,9 +34,9 @@ const BarClock = () => Widget.Box({ children: [ Widget.Label({ className: 'bar-clock', - label: GLib.DateTime.new_now_local().format("%H:%M"), - setup: (self) => self.poll(5000, label => { - label.label = GLib.DateTime.new_now_local().format("%H:%M"); + label: GLib.DateTime.new_now_local().format(userOptions.time.format), + setup: (self) => self.poll(userOptions.time.interval, label => { + label.label = GLib.DateTime.new_now_local().format(userOptions.time.format); }), }), Widget.Label({ diff --git a/.config/ags/modules/desktopbackground/timeandlaunches.js b/.config/ags/modules/desktopbackground/timeandlaunches.js index 05ca1ab13..4a4f19a36 100644 --- a/.config/ags/modules/desktopbackground/timeandlaunches.js +++ b/.config/ags/modules/desktopbackground/timeandlaunches.js @@ -17,9 +17,9 @@ const TimeAndDate = () => Box({ Label({ className: 'bg-time-clock', xalign: 0, - label: GLib.DateTime.new_now_local().format("%H:%M"), - setup: (self) => self.poll(5000, label => { - label.label = GLib.DateTime.new_now_local().format("%H:%M"); + label: GLib.DateTime.new_now_local().format(userOptions.time.format), + setup: (self) => self.poll(userOptions.time.interval, label => { + label.label = GLib.DateTime.new_now_local().format(userOptions.time.format); }), }), Label({ diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index 11ffd5f40..84b7f01a7 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -2,27 +2,27 @@ let userConfigOptions = { // General stuff 'ai': { - 'defaultGPTProvider': 'openai', + 'defaultGPTProvider': "openai", 'defaultTemperature': 0.9, - 'writingCursor': ' ...', // Warning: Using weird characters can mess up Markdown rendering + 'writingCursor': " ...", // Warning: Using weird characters can mess up Markdown rendering }, 'animations': { 'durationSmall': 110, 'durationLarge': 180, }, 'apps': { - 'imageViewer': 'loupe', - 'terminal': 'foot', // This is only for shell actions + 'imageViewer': "loupe", + 'terminal': "foot", // This is only for shell actions }, 'battery': { 'low': 20, 'critical': 10, }, 'music': { - 'preferredPlayer': 'plasma-browser-integration', + 'preferredPlayer': "plasma-browser-integration", }, 'onScreenKeyboard': { - 'layout': 'qwerty_full', // See modules/onscreenkeyboard/onscreenkeyboard.js for available layouts + 'layout': "qwerty_full", // See modules/onscreenkeyboard/onscreenkeyboard.js for available layouts }, 'overview': { 'scale': 0.18, // Relative to screen size @@ -32,14 +32,21 @@ let userConfigOptions = { 'wsNumMarginScale': 0.07, }, 'sidebar': { - 'imageColumns': 3, + 'imageColumns': 2, }, 'search': { - 'engineBaseUrl': 'https://www.google.com/search?q=', - 'excludedSites': ['quora.com'], + 'engineBaseUrl': "https://www.google.com/search?q=", + 'excludedSites': ["quora.com"], + }, + 'time': { + // See https://docs.gtk.org/glib/method.DateTime.format.html + // Here's the 12h format: "%I:%M%P" + // For seconds, add "%S" and set interval to 1000 + 'format': "%H:%M", + 'interval': 5000, }, 'weather': { - 'city': '', + 'city': "", }, 'workspaces': { 'shown': 10, @@ -47,15 +54,15 @@ let userConfigOptions = { // Longer stuff 'icons': { substitutions: { - 'code-url-handler': 'visual-studio-code', - 'Code': 'visual-studio-code', - 'GitHub Desktop': 'github-desktop', - 'Minecraft* 1.20.1': 'minecraft', - 'gnome-tweaks': 'org.gnome.tweaks', - 'pavucontrol-qt': 'pavucontrol', - 'wps': 'wps-office2019-kprometheus', - 'wpsoffice': 'wps-office2019-kprometheus', - '': 'image-missing', + 'code-url-handler': "visual-studio-code", + 'Code': "visual-studio-code", + 'GitHub Desktop': "github-desktop", + 'Minecraft* 1.20.1': "minecraft", + 'gnome-tweaks': "org.gnome.tweaks", + 'pavucontrol-qt': "pavucontrol", + 'wps': "wps-office2019-kprometheus", + 'wpsoffice': "wps-office2019-kprometheus", + '': "image-missing", } }, 'keybinds': { @@ -63,19 +70,19 @@ let userConfigOptions = { // Modifiers: Shift Ctrl Alt Hyper Meta // See https://docs.gtk.org/gdk3/index.html#constants for the other keys (they are listed as KEY_key) 'overview': { - 'altMoveLeft': 'Ctrl+b', - 'altMoveRight': 'Ctrl+f', - 'deleteToEnd': 'Ctrl+k', + 'altMoveLeft': "Ctrl+b", + 'altMoveRight': "Ctrl+f", + 'deleteToEnd': "Ctrl+k", }, 'sidebar': { 'apis': { - 'nextTab': 'Page_Down', - 'prevTab': 'Page_Up', + 'nextTab': "Page_Down", + 'prevTab': "Page_Up", }, - 'pin': 'Ctrl+p', - 'cycleTab': 'Ctrl+Tab', - 'nextTab': 'Ctrl+Page_Down', - 'prevTab': 'Ctrl+Page_Up', + 'pin': "Ctrl+p", + 'cycleTab': "Ctrl+Tab", + 'nextTab': "Ctrl+Page_Down", + 'prevTab': "Ctrl+Page_Up", }, }, } From ae5edea8cb82a6504c5de6d4825421607f2bce03 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:33:03 +0700 Subject: [PATCH 082/517] user config: add date format #307 --- .config/ags/modules/.commonwidgets/notification.js | 2 +- .config/ags/modules/bar/normal/system.js | 6 +++--- .config/ags/modules/desktopbackground/timeandlaunches.js | 6 +++--- .config/ags/user_options.js | 3 +++ 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.config/ags/modules/.commonwidgets/notification.js b/.config/ags/modules/.commonwidgets/notification.js index 251320db3..c8c4ffb31 100644 --- a/.config/ags/modules/.commonwidgets/notification.js +++ b/.config/ags/modules/.commonwidgets/notification.js @@ -222,7 +222,7 @@ export default ({ else if (messageTime.get_day_of_year() == GLib.DateTime.new_now_local().get_day_of_year() - 1) notifTime = 'Yesterday'; else - notifTime = messageTime.format('%d/%m'); + notifTime = messageTime.format(userOptions.time.dateFormat); const notifTextSummary = Label({ xalign: 0, className: 'txt-small txt-semibold titlefont', diff --git a/.config/ags/modules/bar/normal/system.js b/.config/ags/modules/bar/normal/system.js index ba0e4acf0..d7b0d9090 100644 --- a/.config/ags/modules/bar/normal/system.js +++ b/.config/ags/modules/bar/normal/system.js @@ -45,9 +45,9 @@ const BarClock = () => Widget.Box({ }), Widget.Label({ className: 'txt-smallie', - label: GLib.DateTime.new_now_local().format("%A, %d/%m"), - setup: (self) => self.poll(5000, label => { - label.label = GLib.DateTime.new_now_local().format("%A, %d/%m"); + label: GLib.DateTime.new_now_local().format(userOptions.time.dateFormatLong), + setup: (self) => self.poll(userOptions.time.dateInterval, (label) => { + label.label = GLib.DateTime.new_now_local().format(userOptions.time.dateFormatLong); }), }), ], diff --git a/.config/ags/modules/desktopbackground/timeandlaunches.js b/.config/ags/modules/desktopbackground/timeandlaunches.js index 4a4f19a36..f0e0214b4 100644 --- a/.config/ags/modules/desktopbackground/timeandlaunches.js +++ b/.config/ags/modules/desktopbackground/timeandlaunches.js @@ -25,9 +25,9 @@ const TimeAndDate = () => Box({ Label({ className: 'bg-time-date', xalign: 0, - label: GLib.DateTime.new_now_local().format("%A, %d/%m/%Y"), - setup: (self) => self.poll(5000, label => { - label.label = GLib.DateTime.new_now_local().format("%A, %d/%m/%Y"); + label: GLib.DateTime.new_now_local().format(userOptions.time.dateFormatLong), + setup: (self) => self.poll(userOptions.time.dateInterval, (label) => { + label.label = GLib.DateTime.new_now_local().format(userOptions.time.dateFormatLong); }), }), ] diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index 84b7f01a7..2be909313 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -44,6 +44,9 @@ let userConfigOptions = { // For seconds, add "%S" and set interval to 1000 'format': "%H:%M", 'interval': 5000, + 'dateFormatLong': "%A, %d/%m", // On bar + 'dateInterval': 5000, + 'dateFormat': "%d/%m", // On notif time }, 'weather': { 'city': "", From 6097e885342b427a37dc1515554af9669385db37 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 7 Mar 2024 14:21:47 +0700 Subject: [PATCH 083/517] fix distro id getting --- .config/ags/modules/.miscutils/system.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/modules/.miscutils/system.js b/.config/ags/modules/.miscutils/system.js index 4b24ed378..d5e73b38e 100644 --- a/.config/ags/modules/.miscutils/system.js +++ b/.config/ags/modules/.miscutils/system.js @@ -1,7 +1,7 @@ import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; const { execAsync, exec } = Utils; -export const distroID = exec(`bash -c 'cat /etc/os-release | grep "^ID=" | cut -d "=" -f 2'`).trim(); +export const distroID = exec(`bash -c 'cat /etc/os-release | grep "^ID=" | cut -d "=" -f 2 | sed "s/\\"//g"'`).trim(); export const isDebianDistro = (distroID == 'linuxmint' || distroID == 'ubuntu' || distroID == 'debian' || distroID == 'zorin' || distroID == 'popos' || distroID == 'raspbian' || distroID == 'kali'); export const isArchDistro = (distroID == 'arch' || distroID == 'endeavouros' || distroID == 'cachyos'); export const hasFlatpak = !!exec(`bash -c 'command -v flatpak'`); From 67f73c98ffe6f0c6bf37b473d95a67c46761bfa4 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 7 Mar 2024 14:22:42 +0700 Subject: [PATCH 084/517] booru: make images square --- .config/ags/scss/_sidebars.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss index 52959ae45..136ad63ec 100644 --- a/.config/ags/scss/_sidebars.scss +++ b/.config/ags/scss/_sidebars.scss @@ -849,8 +849,8 @@ $waifu_image_overlay_transparency: 0.7; } .sidebar-booru-image { - min-width: 8.523rem; - min-height: 8.523rem; + min-width: 12.818rem; + min-height: 12.818rem; background-size: cover; background-repeat: no-repeat; background-position: center; From 3ce6d0ec1dd380fb09de3d3be3ef4bbb0d43346b Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 7 Mar 2024 14:51:13 +0700 Subject: [PATCH 085/517] hyprland: mouse side button keybinds --- .config/hypr/hyprland/keybinds.conf | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.config/hypr/hyprland/keybinds.conf b/.config/hypr/hyprland/keybinds.conf index 1951e77c3..888fb011c 100644 --- a/.config/hypr/hyprland/keybinds.conf +++ b/.config/hypr/hyprland/keybinds.conf @@ -120,6 +120,8 @@ bind = Super, BracketRight, movefocus, r # Workspace, window, tab switch with keyboard bind = Control+Super, right, workspace, +1 bind = Control+Super, left, workspace, -1 +bind = Super, mouse:275, workspace, -1 +bind = Super, mouse:276, workspace, +1 bind = Control+Super, BracketLeft, workspace, -1 bind = Control+Super, BracketRight, workspace, +1 bind = Control+Super, up, workspace, -5 @@ -193,9 +195,14 @@ bindm = Super, mouse:273, resizewindow bindm = Super, Z, movewindow bind = Control+Super, Backslash, resizeactive, exact 640 480 +# Arrow keys with IJKL bindle = Alt, I, exec, ydotool key 103:1 103:0 bindle = Alt, K, exec, ydotool key 108:1 108:0 bindle = Alt, J, exec, ydotool key 105:1 105:0 bindle = Alt, L, exec, ydotool key 106:1 106:0 +# Control + Side mouse btn for switching tabs (Ctrl+PgUp/PgDn) +bind = Control, mouse:275, exec, ydotool key 29:1 104:1 104:0 29:0 +bind = Control, mouse:276, exec, ydotool key 29:1 109:1 109:0 29:0 + From 00605520e26206bcddffdca7c2542a4b5105a0a1 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 7 Mar 2024 15:08:22 +0700 Subject: [PATCH 086/517] volume device info: support bluetooth headphones --- .config/ags/modules/indicators/indicatorvalues.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.config/ags/modules/indicators/indicatorvalues.js b/.config/ags/modules/indicators/indicatorvalues.js index ffc75ec79..2ed7e3947 100644 --- a/.config/ags/modules/indicators/indicatorvalues.js +++ b/.config/ags/modules/indicators/indicatorvalues.js @@ -64,7 +64,8 @@ export default () => { }, nameSetup: (self) => Utils.timeout(1, () => { const updateAudioDevice = (self) => { - const usingHeadphones = (Audio.speaker?.stream?.port)?.includes('Headphones'); + console.log(Audio.speaker?.stream?.port); + const usingHeadphones = (Audio.speaker?.stream?.port)?.toLowerCase().includes('headphone'); if (volumeIndicator.attribute.headphones === undefined || volumeIndicator.attribute.headphones !== usingHeadphones) { volumeIndicator.attribute.headphones = usingHeadphones; From b23f0bb1df573091e805728982f98d7df59fceb9 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 7 Mar 2024 16:12:32 +0700 Subject: [PATCH 087/517] volume scroll: more precise control in single-digits --- .config/ags/modules/bar/normal/spaceright.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.config/ags/modules/bar/normal/spaceright.js b/.config/ags/modules/bar/normal/spaceright.js index 257680821..8536a19c2 100644 --- a/.config/ags/modules/bar/normal/spaceright.js +++ b/.config/ags/modules/bar/normal/spaceright.js @@ -58,12 +58,14 @@ export default () => { return Widget.EventBox({ onScrollUp: () => { if (!Audio.speaker) return; - Audio.speaker.volume += 0.03; + if(Audio.speaker.volume <= 0.09) Audio.speaker.volume += 0.01; + else Audio.speaker.volume += 0.03; Indicator.popup(1); }, onScrollDown: () => { if (!Audio.speaker) return; - Audio.speaker.volume -= 0.03; + if(Audio.speaker.volume <= 0.09) Audio.speaker.volume -= 0.01; + else Audio.speaker.volume -= 0.03; Indicator.popup(1); }, onHover: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', true) }, From c75650dcfdaa006e592bf14f00573272db63200b Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 7 Mar 2024 16:29:31 +0700 Subject: [PATCH 088/517] battery: remove full charge green color cuz so many of y'all are leaving your machine plugged regardless of the charge so won't cry when ya show it --- .config/ags/scss/_bar.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.config/ags/scss/_bar.scss b/.config/ags/scss/_bar.scss index ccb35c5bc..4797d4380 100644 --- a/.config/ags/scss/_bar.scss +++ b/.config/ags/scss/_bar.scss @@ -174,8 +174,8 @@ $bar_subgroup_bg: $surfaceVariant; } .bar-batt-full { - background-color: $successContainer; - color: $onSuccessContainer; + // background-color: $successContainer; + // color: $onSuccessContainer; } .bar-batt-circprog { @@ -193,8 +193,8 @@ $bar_subgroup_bg: $surfaceVariant; } .bar-batt-circprog-full { - background-color: $successContainer; - color: $onSuccessContainer; + // background-color: $successContainer; + // color: $onSuccessContainer; } .bar-music-playstate { From f4165ff55d663a298f335cc0a3427ef1e938ed2d Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 7 Mar 2024 16:32:17 +0700 Subject: [PATCH 089/517] keybinds: add easyeffects --- .config/hypr/hyprland/keybinds.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/.config/hypr/hyprland/keybinds.conf b/.config/hypr/hyprland/keybinds.conf index 888fb011c..3d2d0fd26 100644 --- a/.config/hypr/hyprland/keybinds.conf +++ b/.config/hypr/hyprland/keybinds.conf @@ -26,6 +26,7 @@ bind = Super+Shift, W, exec, wps # Apps: Settings and config bind = Super, I, exec, XDG_CURRENT_DESKTOP="gnome" gnome-control-center bind = Control+Super, V, exec, pavucontrol +bind = Control+Super+Shift, V, exec, easyeffects bind = Control+Shift, Escape, exec, gnome-system-monitor # Actions From 740e0699277d669211dc8582a018bc9f37f943fa Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 7 Mar 2024 16:32:41 +0700 Subject: [PATCH 090/517] remove ampersand cuz unecessary i think --- .config/hypr/hyprland/execs.conf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.config/hypr/hyprland/execs.conf b/.config/hypr/hyprland/execs.conf index 50273e124..ab5e95478 100644 --- a/.config/hypr/hyprland/execs.conf +++ b/.config/hypr/hyprland/execs.conf @@ -6,10 +6,10 @@ exec-once = ags & exec-once = fcitx5 # Core components (authentication, lock screen, notification daemon) -exec-once = gnome-keyring-daemon --start --components=secrets & -exec-once = /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 & -exec-once = hypridle & -exec-once = dbus-update-activation-environment --all & +exec-once = gnome-keyring-daemon --start --components=secrets +exec-once = /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 +exec-once = hypridle +exec-once = dbus-update-activation-environment --all exec-once = sleep 1 && dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP # Some fix idk # Clipboard: history From b25d595a2fc034ea5351dc3c6c05dc4bcee03e40 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 7 Mar 2024 17:06:26 +0700 Subject: [PATCH 091/517] fix notif clear (#286) --- .config/ags/modules/sideright/notificationlist.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.config/ags/modules/sideright/notificationlist.js b/.config/ags/modules/sideright/notificationlist.js index 992bed57f..7d2200f65 100644 --- a/.config/ags/modules/sideright/notificationlist.js +++ b/.config/ags/modules/sideright/notificationlist.js @@ -85,9 +85,8 @@ export default (props) => { self.toggleClassName('notif-listaction-btn-enabled', Notifications.dnd); }); const clearButton = ListActionButton('clear_all', 'Clear', () => { - // Manual destruction is not necessary - // since Notifications.clear() sends destroy signals to every notif Notifications.clear(); + notificationList.get_children().forEach(ch => ch.attribute.destroyWithAnims()) }); const listTitle = Box({ vpack: 'start', From 48f689668c5b4724764f027d478628bb795ac273 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 7 Mar 2024 22:00:49 +0700 Subject: [PATCH 092/517] workspace widget: side mouse btn for special ws --- .../modules/bar/normal/workspaces_hyprland.js | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/.config/ags/modules/bar/normal/workspaces_hyprland.js b/.config/ags/modules/bar/normal/workspaces_hyprland.js index 770ba6bc8..ba30f69e7 100644 --- a/.config/ags/modules/bar/normal/workspaces_hyprland.js +++ b/.config/ags/modules/bar/normal/workspaces_hyprland.js @@ -175,15 +175,17 @@ export default () => EventBox({ .catch(print); }) self.on('button-press-event', (self, event) => { - if (!(event.get_button()[1] === 1)) return; // We're only interested in left-click here - self.attribute.clicked = true; - const [_, cursorX, cursorY] = event.get_coords(); - const widgetWidth = self.get_allocation().width; - // const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES_PER_GROUP / widgetWidth) + self.attribute.ws_group * NUM_OF_WORKSPACES_PER_GROUP; - // Hyprland.messageAsync(`dispatch workspace ${wsId}`).catch(print); - const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth); - Utils.execAsync([`${App.configDir}/scripts/hyprland/workspace_action.sh`, 'workspace', `${wsId}`]) - .catch(print); + if (event.get_button()[1] === 1) { + self.attribute.clicked = true; + const [_, cursorX, cursorY] = event.get_coords(); + const widgetWidth = self.get_allocation().width; + const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth); + Utils.execAsync([`${App.configDir}/scripts/hyprland/workspace_action.sh`, 'workspace', `${wsId}`]) + .catch(print); + } + else if (event.get_button()[1] === 8) { + Hyprland.messageAsync(`dispatch togglespecialworkspace`).catch(print); + } }) self.on('button-release-event', (self) => self.attribute.clicked = false); } From 8d640a82d99dd50aa07329a9c5bb64b9cd674920 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 7 Mar 2024 23:21:20 +0700 Subject: [PATCH 093/517] swap middle/right click on overview widget right click is easier, and overview is more likely used than osk --- .config/ags/modules/bar/normal/workspaces_hyprland.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/ags/modules/bar/normal/workspaces_hyprland.js b/.config/ags/modules/bar/normal/workspaces_hyprland.js index ba30f69e7..20adf4f9f 100644 --- a/.config/ags/modules/bar/normal/workspaces_hyprland.js +++ b/.config/ags/modules/bar/normal/workspaces_hyprland.js @@ -149,8 +149,8 @@ const WorkspaceContents = (count = 10) => { export default () => EventBox({ onScrollUp: () => Hyprland.messageAsync(`dispatch workspace -1`).catch(print), onScrollDown: () => Hyprland.messageAsync(`dispatch workspace +1`).catch(print), - onMiddleClickRelease: () => App.toggleWindow('overview'), - onSecondaryClickRelease: () => App.toggleWindow('osk'), + onMiddleClick: () => App.toggleWindow('osk'), + onSecondaryClick: () => App.toggleWindow('overview'), attribute: { clicked: false, ws_group: 0, From 9e8a840430f165d69eebbb905ef96de314232188 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:03:20 +0700 Subject: [PATCH 094/517] overview: add ws numbers --- .../ags/modules/overview/overview_hyprland.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.config/ags/modules/overview/overview_hyprland.js b/.config/ags/modules/overview/overview_hyprland.js index 0fe062541..7a5b55c79 100644 --- a/.config/ags/modules/overview/overview_hyprland.js +++ b/.config/ags/modules/overview/overview_hyprland.js @@ -208,13 +208,19 @@ export default () => { }, } }) - const WorkspaceNumber = (index) => Widget.Label({ + const WorkspaceNumber = ({ index, ...rest }) => Widget.Label({ className: 'overview-tasks-workspace-number', label: `${index}`, css: ` margin: ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * userOptions.overview.scale * userOptions.overview.wsNumMarginScale}px; font-size: ${SCREEN_HEIGHT * userOptions.overview.scale * userOptions.overview.wsNumScale}px; `, + setup: (self) => self.hook(Hyprland.active.workspace, (self) => { + // Update when going to new ws group + const currentGroup = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN); + self.label = `${currentGroup * NUM_OF_WORKSPACES_SHOWN + index}`; + }), + ...rest, }) const widget = Widget.Box({ className: 'overview-tasks-workspace', @@ -238,7 +244,13 @@ export default () => { overviewTick.setValue(!overviewTick.value); }); }, - child: fixed, + child: Widget.Overlay({ + child: Widget.Box({}), + overlays: [ + WorkspaceNumber({ index: index, hpack: 'start', vpack: 'start' }), + fixed + ] + }), })], }); const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN; From 61a04fedcc6bbe2c9f403d61416b644495389c23 Mon Sep 17 00:00:00 2001 From: clsty Date: Fri, 8 Mar 2024 19:40:58 +0800 Subject: [PATCH 095/517] Reminder for GPU thingy --- install.sh | 1 + scriptdata/options | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/install.sh b/install.sh index a832345e9..2bcd030db 100755 --- a/install.sh +++ b/install.sh @@ -12,6 +12,7 @@ startask (){ printf "\e[34m[$0]: Hi there!\n" printf 'This script 1. only works for ArchLinux and Arch-based distros.\n' printf ' 2. has not been fully tested, use at your own risk.\n' +printf ' 3. does not provide GPU things and you must have set it up yourself.\n' printf "\e[31m" printf "Please CONFIRM that you HAVE ALREADY BACKED UP \"$HOME/.config/\" and \"$HOME/.local/\" folders!\n" printf "\e[97m" diff --git a/scriptdata/options b/scriptdata/options index 3fa45ec13..f3e37f578 100644 --- a/scriptdata/options +++ b/scriptdata/options @@ -3,10 +3,7 @@ # NOTE that you NOT need to `cd ..' because the `$0' is NOT this file, but the script file which will source this file. # The script that use this file should have two lines on its top as follows: -# cd "$(dirname "$0")" -# export base="$(pwd)" - -showhelp(){ +# cd "$(dirname "$0")" export base="$(pwd)" showhelp(){ echo -e "Syntax: $0 [Options]... Idempotent installation script for dotfiles. From 1bcc30992bf5face02274f140966b5ba8c5d7d3c Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Fri, 8 Mar 2024 22:32:55 +0700 Subject: [PATCH 096/517] bar: show bluetooth battery --- .../ags/modules/.commonwidgets/statusicons.js | 30 ++++++++++++++++++- .config/ags/scss/_bar.scss | 11 +++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/.config/ags/modules/.commonwidgets/statusicons.js b/.config/ags/modules/.commonwidgets/statusicons.js index dc3ba3e85..2b587f409 100644 --- a/.config/ags/modules/.commonwidgets/statusicons.js +++ b/.config/ags/modules/.commonwidgets/statusicons.js @@ -84,6 +84,31 @@ export const BluetoothIndicator = () => Widget.Stack({ , }); +const BluetoothDevices = () => Widget.Box({ + className: 'spacing-h-10', + setup: self => self.hook(Bluetooth, self => { + self.children = Bluetooth.connected_devices.map((device) => { + return Widget.Box({ + className: 'bar-bluetooth-device spacing-h-5', + vpack: 'center', + tooltipText: device.name, + children: [ + Widget.Icon(`${device.iconName}-symbolic`), + (device.batteryPercentage ? Widget.Label({ + className: 'txt-smallie', + label: `${device.batteryPercentage}`, + setup: (self) => { + self.hook(device, (self) => { + self.label = `${device.batteryPercentage}`; + }, 'notify::batteryPercentage') + } + }) : null), + ] + }); + }); + self.visible = Bluetooth.connected_devices.length > 0; + }, 'notify::connected-devices'), +}) const NetworkWiredIndicator = () => Widget.Stack({ transition: 'slide_up_down', @@ -247,7 +272,10 @@ export const StatusIcons = (props = {}) => Widget.Box({ optionalKeyboardLayoutInstance, NotificationIndicator(), NetworkIndicator(), - BluetoothIndicator(), + Widget.Box({ + className: 'spacing-h-5', + children: [BluetoothIndicator(), BluetoothDevices()] + }) ] }) }); diff --git a/.config/ags/scss/_bar.scss b/.config/ags/scss/_bar.scss index 4797d4380..e209a4579 100644 --- a/.config/ags/scss/_bar.scss +++ b/.config/ags/scss/_bar.scss @@ -350,4 +350,15 @@ $bar_subgroup_bg: $surfaceVariant; .bar-util-btn:active { background-color: mix($bar_subgroup_bg, $onSurfaceVariant, 80%); +} + +.bar-bluetooth-device { + @include full-rounding; + @include element_decel; + min-height: 1.032rem; + min-width: 1.032rem; + font-size: 1.032rem; + background-color: $surface; + color: $onSurface; + padding: 0.205rem 0.341rem; } \ No newline at end of file From 30c6917beae4ea083670e080329cc5847d9bf123 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Fri, 8 Mar 2024 22:33:03 +0700 Subject: [PATCH 097/517] remove debug print --- .config/ags/modules/indicators/indicatorvalues.js | 1 - 1 file changed, 1 deletion(-) diff --git a/.config/ags/modules/indicators/indicatorvalues.js b/.config/ags/modules/indicators/indicatorvalues.js index 2ed7e3947..e373e491f 100644 --- a/.config/ags/modules/indicators/indicatorvalues.js +++ b/.config/ags/modules/indicators/indicatorvalues.js @@ -64,7 +64,6 @@ export default () => { }, nameSetup: (self) => Utils.timeout(1, () => { const updateAudioDevice = (self) => { - console.log(Audio.speaker?.stream?.port); const usingHeadphones = (Audio.speaker?.stream?.port)?.toLowerCase().includes('headphone'); if (volumeIndicator.attribute.headphones === undefined || volumeIndicator.attribute.headphones !== usingHeadphones) { From f2bbefdc63ecf37a88838eaf6329a37d6021342a Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Fri, 8 Mar 2024 22:33:09 +0700 Subject: [PATCH 098/517] format --- .config/ags/modules/bar/normal/spaceright.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/ags/modules/bar/normal/spaceright.js b/.config/ags/modules/bar/normal/spaceright.js index 8536a19c2..8d63e7009 100644 --- a/.config/ags/modules/bar/normal/spaceright.js +++ b/.config/ags/modules/bar/normal/spaceright.js @@ -58,13 +58,13 @@ export default () => { return Widget.EventBox({ onScrollUp: () => { if (!Audio.speaker) return; - if(Audio.speaker.volume <= 0.09) Audio.speaker.volume += 0.01; + if (Audio.speaker.volume <= 0.09) Audio.speaker.volume += 0.01; else Audio.speaker.volume += 0.03; Indicator.popup(1); }, onScrollDown: () => { if (!Audio.speaker) return; - if(Audio.speaker.volume <= 0.09) Audio.speaker.volume -= 0.01; + if (Audio.speaker.volume <= 0.09) Audio.speaker.volume -= 0.01; else Audio.speaker.volume -= 0.03; Indicator.popup(1); }, From ab39d11e285c459093009667dfc02616a7c72aaa Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Fri, 8 Mar 2024 23:14:01 +0700 Subject: [PATCH 099/517] hmm overview drag n drop fx --- .config/ags/scss/_common.scss | 6 +++++- .config/ags/scss/main.scss | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.config/ags/scss/_common.scss b/.config/ags/scss/_common.scss index 00a509efd..59749dacf 100644 --- a/.config/ags/scss/_common.scss +++ b/.config/ags/scss/_common.scss @@ -254,4 +254,8 @@ popover { min-height: 0.205rem; padding: 0rem 1.023rem; color: $primary; -} \ No newline at end of file +} + +widget { + @include small-rounding; +} diff --git a/.config/ags/scss/main.scss b/.config/ags/scss/main.scss index ea1f378fe..793783916 100644 --- a/.config/ags/scss/main.scss +++ b/.config/ags/scss/main.scss @@ -2,7 +2,7 @@ // * { // all: unset; // } -*:not(popover) { all: unset; } +*:not(popover):not(widget) { all: unset; } // Colors @import './material'; // Material colors From 24a7c8f2261938c568195fbe29255a5a93a4b63c Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Fri, 8 Mar 2024 22:08:34 +0530 Subject: [PATCH 100/517] Add materialyoucolor-python, simplify scss --- .../ags/scripts/color_generation/colorgen.sh | 2 + .../generate_colors_material.py | 162 +++++++++++------- .config/ags/scss/_bar.scss | 43 +++-- .config/ags/scss/_colors.scss | 100 +++++------ .config/ags/scss/_lib_mixins.scss | 4 +- .config/ags/scss/_notifications.scss | 60 ++++--- .config/ags/scss/_overview.scss | 28 +-- .config/ags/scss/_sidebars.scss | 87 +++++----- 8 files changed, 265 insertions(+), 221 deletions(-) diff --git a/.config/ags/scripts/color_generation/colorgen.sh b/.config/ags/scripts/color_generation/colorgen.sh index 1748ffb9d..15f81adb4 100755 --- a/.config/ags/scripts/color_generation/colorgen.sh +++ b/.config/ags/scripts/color_generation/colorgen.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +source ${HOME}/virtualenvs/my_project_venv/bin/activate + # check if no arguments if [ $# -eq 0 ]; then echo "Usage: colorgen.sh /path/to/image (--apply)" diff --git a/.config/ags/scripts/color_generation/generate_colors_material.py b/.config/ags/scripts/color_generation/generate_colors_material.py index deb34bf83..9edd06ac4 100755 --- a/.config/ags/scripts/color_generation/generate_colors_material.py +++ b/.config/ags/scripts/color_generation/generate_colors_material.py @@ -4,6 +4,21 @@ from pathlib import Path import sys import subprocess +# Color in hue, chroma, tone form +from materialyoucolor.hct import Hct +from materialyoucolor.dynamiccolor.material_dynamic_colors import MaterialDynamicColors +# There are 9 different variants of scheme. +from materialyoucolor.scheme.scheme_tonal_spot import SchemeTonalSpot as Scheme +#from materialyoucolor.scheme.scheme_fruit_salad import SchemeFruitSalad as Scheme +#from materialyoucolor.scheme.scheme_expressive import SchemeExpressive as Scheme +#from materialyoucolor.scheme.scheme_monochrome import SchemeMonochrome as Scheme +#from materialyoucolor.scheme.scheme_rainbow import SchemeRainbow as Scheme +#from materialyoucolor.scheme.scheme_vibrant import SchemeVibrant as Scheme +#from materialyoucolor.scheme.scheme_neutral import SchemeNeutral as Scheme +#from materialyoucolor.scheme.scheme_fidelity import SchemeFidelity as Scheme +#from materialyoucolor.scheme.scheme_content import SchemeContent as Scheme +# Others you can import: SchemeExpressive, SchemeFruitSalad, SchemeMonochrome, SchemeRainbow, SchemeVibrant, SchemeNeutral, SchemeFidelity and SchemeContent + def darken(hex_color, factor=0.7): if not (hex_color.startswith('#') and len(hex_color) in (4, 7)): raise ValueError("Invalid hex color format") @@ -23,6 +38,10 @@ if len(sys.argv) > 1 and sys.argv[1] == '--path': hsize = int((float(img.size[1])*float(wpercent))) img = img.resize((basewidth,hsize),Image.Resampling.LANCZOS) newtheme = themeFromImage(img) + argb = sourceColorFromImage(img) + + scheme = Scheme(Hct.from_int(argb), True, 0.0) + # except FileNotFoundError: # print('[generate_colors_material.py] File not found', file=sys.stderr); # exit() @@ -36,7 +55,7 @@ else: # try: # imagePath = subprocess.check_output("ags run-js 'wallpaper.get(0)'", shell=True) imagePath = subprocess.check_output("swww query | awk -F 'image: ' '{print $2}'", shell=True) - imagePath = imagePath[:-1].decode("utf-8") + imagePath = imagePath[:-1].decode("utf-8") img = Image.open(imagePath) basewidth = 64 wpercent = (basewidth/float(img.size[0])) @@ -60,63 +79,90 @@ else: colorscheme = newtheme.get('schemes').get('dark') print('$darkmode: true;') -primary = hexFromArgb(colorscheme.get_primary()) -onPrimary = hexFromArgb(colorscheme.get_onPrimary()) -primaryContainer = hexFromArgb(colorscheme.get_primaryContainer()) -onPrimaryContainer = hexFromArgb(colorscheme.get_onPrimaryContainer()) -secondary = hexFromArgb(colorscheme.get_secondary()) -onSecondary = hexFromArgb(colorscheme.get_onSecondary()) -secondaryContainer = hexFromArgb(colorscheme.get_secondaryContainer()) -onSecondaryContainer = hexFromArgb(colorscheme.get_onSecondaryContainer()) -tertiary = hexFromArgb(colorscheme.get_tertiary()) -onTertiary = hexFromArgb(colorscheme.get_onTertiary()) -tertiaryContainer = hexFromArgb(colorscheme.get_tertiaryContainer()) -onTertiaryContainer = hexFromArgb(colorscheme.get_onTertiaryContainer()) -error = hexFromArgb(colorscheme.get_error()) -onError = hexFromArgb(colorscheme.get_onError()) -errorContainer = hexFromArgb(colorscheme.get_errorContainer()) -onErrorContainer = hexFromArgb(colorscheme.get_onErrorContainer()) -background = hexFromArgb(colorscheme.get_background()) -onBackground = hexFromArgb(colorscheme.get_onBackground()) -surface = hexFromArgb(colorscheme.get_surface()) -onSurface = hexFromArgb(colorscheme.get_onSurface()) -surfaceVariant = hexFromArgb(colorscheme.get_surfaceVariant()) -onSurfaceVariant = hexFromArgb(colorscheme.get_onSurfaceVariant()) -outline = hexFromArgb(colorscheme.get_outline()) -shadow = hexFromArgb(colorscheme.get_shadow()) -inverseSurface = hexFromArgb(colorscheme.get_inverseSurface()) -inverseOnSurface = hexFromArgb(colorscheme.get_inverseOnSurface()) -inversePrimary = hexFromArgb(colorscheme.get_inversePrimary()) +#primary = hexFromArgb(colorscheme.get_primary()) +#onPrimary = hexFromArgb(colorscheme.get_onPrimary()) +#primaryContainer = hexFromArgb(colorscheme.get_primaryContainer()) +#onPrimaryContainer = hexFromArgb(colorscheme.get_onPrimaryContainer()) +#secondary = hexFromArgb(colorscheme.get_secondary()) +#onSecondary = hexFromArgb(colorscheme.get_onSecondary()) +#secondaryContainer = hexFromArgb(colorscheme.get_secondaryContainer()) +#onSecondaryContainer = hexFromArgb(colorscheme.get_onSecondaryContainer()) +#tertiary = hexFromArgb(colorscheme.get_tertiary()) +#onTertiary = hexFromArgb(colorscheme.get_onTertiary()) +#tertiaryContainer = hexFromArgb(colorscheme.get_tertiaryContainer()) +#onTertiaryContainer = hexFromArgb(colorscheme.get_onTertiaryContainer()) +#error = hexFromArgb(colorscheme.get_error()) +#onError = hexFromArgb(colorscheme.get_onError()) +#errorContainer = hexFromArgb(colorscheme.get_errorContainer()) +#onErrorContainer = hexFromArgb(colorscheme.get_onErrorContainer()) +#background = hexFromArgb(colorscheme.get_background()) +#onBackground = hexFromArgb(colorscheme.get_onBackground()) +#surface = hexFromArgb(colorscheme.get_surface()) +#onSurface = hexFromArgb(colorscheme.get_onSurface()) +#surfaceVariant = hexFromArgb(colorscheme.get_surfaceVariant()) +#onSurfaceVariant = hexFromArgb(colorscheme.get_onSurfaceVariant()) +#outline = hexFromArgb(colorscheme.get_outline()) +#shadow = hexFromArgb(colorscheme.get_shadow()) +#inverseSurface = hexFromArgb(colorscheme.get_inverseSurface()) +#inverseOnSurface = hexFromArgb(colorscheme.get_inverseOnSurface()) +#inversePrimary = hexFromArgb(colorscheme.get_inversePrimary()) + # make material less boring -if darkmode: - background = darken(background, 0.6) +#if darkmode: +# background = darken(background, 0.6) -print('$primary: ' + primary + ';') -print('$onPrimary: ' + onPrimary + ';') -print('$primaryContainer: ' + primaryContainer + ';') -print('$onPrimaryContainer: ' + onPrimaryContainer + ';') -print('$secondary: ' + secondary + ';') -print('$onSecondary: ' + onSecondary + ';') -print('$secondaryContainer: ' + secondaryContainer + ';') -print('$onSecondaryContainer: ' + onSecondaryContainer + ';') -print('$tertiary: ' + tertiary + ';') -print('$onTertiary: ' + onTertiary + ';') -print('$tertiaryContainer: ' + tertiaryContainer + ';') -print('$onTertiaryContainer: ' + onTertiaryContainer + ';') -print('$error: ' + error + ';') -print('$onError: ' + onError + ';') -print('$errorContainer: ' + errorContainer + ';') -print('$onErrorContainer: ' + onErrorContainer + ';') -print('$colorbarbg: ' + background + ';') -print('$background: ' + background + ';') -print('$onBackground: ' + onBackground + ';') -print('$surface: ' + surface + ';') -print('$onSurface: ' + onSurface + ';') -print('$surfaceVariant: ' + surfaceVariant + ';') -print('$onSurfaceVariant: ' + onSurfaceVariant + ';') -print('$outline: ' + outline + ';') -print('$shadow: ' + shadow + ';') -print('$inverseSurface: ' + inverseSurface + ';') -print('$inverseOnSurface: ' + inverseOnSurface + ';') -print('$inversePrimary: ' + inversePrimary + ';') \ No newline at end of file +#print('$primary: ' + primary + ';') +#print('$onPrimary: ' + onPrimary + ';') +#print('$primaryContainer: ' + primaryContainer + ';') +#print('$onPrimaryContainer: ' + onPrimaryContainer + ';') +#print('$secondary: ' + secondary + ';') +#print('$onSecondary: ' + onSecondary + ';') +#print('$secondaryContainer: ' + secondaryContainer + ';') +#print('$onSecondaryContainer: ' + onSecondaryContainer + ';') +#print('$tertiary: ' + tertiary + ';') +#print('$onTertiary: ' + onTertiary + ';') +#print('$tertiaryContainer: ' + tertiaryContainer + ';') +#print('$onTertiaryContainer: ' + onTertiaryContainer + ';') +#print('$error: ' + error + ';') +#print('$onError: ' + onError + ';') +#print('$errorContainer: ' + errorContainer + ';') +#print('$onErrorContainer: ' + onErrorContainer + ';') +#print('$colorbarbg: ' + background + ';') +#print('$background: ' + background + ';') +#print('$onBackground: ' + onBackground + ';') +#print('$surface: ' + surface + ';') +#print('$onSurface: ' + onSurface + ';') +#print('$surfaceVariant: ' + surfaceVariant + ';') +#print('$onSurfaceVariant: ' + onSurfaceVariant + ';') +#print('$outline: ' + outline + ';') +#print('$shadow: ' + shadow + ';') +#print('$inverseSurface: ' + inverseSurface + ';') +#print('$inverseOnSurface: ' + inverseOnSurface + ';') +#print('$inversePrimary: ' + inversePrimary + ';') +#print('$indsddsdversePrimary: ' + inversePrimary + ';') + + + +if len(sys.argv) > 4: + if sys.argv[4] == '--debug': + for color in vars(MaterialDynamicColors).keys(): + color_name = getattr(MaterialDynamicColors, color) + if hasattr(color_name, "get_hct"): + rgba = color_name.get_hct(scheme).to_rgba() + r, g, b, a = rgba + hex_color = f"#{r:02X}{g:02X}{b:02X}" + print(color.ljust(32), "\x1B[38;2;{};{};{}m{}\x1B[0m".format(rgba[0], rgba[1], rgba[2], "\x1b[7m \x1b[7m"), hex_color) + + print('\nHey :\n') + + +for color in vars(MaterialDynamicColors).keys(): + color_name = getattr(MaterialDynamicColors, color) + if hasattr(color_name, "get_hct"): + rgba = color_name.get_hct(scheme).to_rgba() + r, g, b, a = rgba + hex_color = f"#{r:02X}{g:02X}{b:02X}" + print('$' + color + ': ' + hex_color + ';') + +print('$colorbarbg: ' + '#000000' + ';') diff --git a/.config/ags/scss/_bar.scss b/.config/ags/scss/_bar.scss index f83566092..5ae2501ae 100644 --- a/.config/ags/scss/_bar.scss +++ b/.config/ags/scss/_bar.scss @@ -15,7 +15,7 @@ $bar_subgroup_bg: $surfaceVariant; } .bar-bg { - background-color: $t_background; + background-color: $background; min-height: 2.727rem; } @@ -28,7 +28,7 @@ $bar_subgroup_bg: $surfaceVariant; } .bar-group { - background-color: $l_l_t_surfaceVariant; + background-color: $surfaceContainer; } .bar-group-pad { @@ -83,27 +83,23 @@ $bar_subgroup_bg: $surfaceVariant; .bar-ws { min-width: $bar_ws_width; - color: mix($onBackground, $background, 40%); - @if $darkmode ==true { - color: mix($onBackground, $background, 45%); - } + color: $outlineVariant; } .bar-ws-active { - background-color: $secondaryContainer; - color: $onSecondaryContainer; + background-color: $primary; + color: $onPrimary; } .bar-ws-occupied { - background-color: $bar_subgroup_bg; - color: $onSurfaceVariant; + background-color: $secondaryContainer; + color: $onSecondaryContainer; } .bar-separator { @include full-rounding; min-width: 0.341rem; min-height: 0.341rem; - background-color: mix($t_surface, $t_onSurface, 90%); margin: 0rem 0.341rem; } @@ -119,7 +115,7 @@ $bar_subgroup_bg: $surfaceVariant; .bar-date { @include titlefont; font-size: 1rem; - color: $onBackground; + //color: #AA0000;//$outlineVariant; } .bar-batt { @@ -187,8 +183,8 @@ $bar_subgroup_bg: $surfaceVariant; min-height: 1.77rem; min-width: 1.77rem; border-radius: 10rem; - background-color: $secondaryContainer; - color: $onSecondaryContainer; + background-color: $primaryContainer; + color: $onPrimaryContainer; } .bar-music-playstate-txt { @@ -231,7 +227,7 @@ $bar_subgroup_bg: $surfaceVariant; } .corner { - background-color: $t_background; + background-color: $background; @include large-rounding; } @@ -243,7 +239,7 @@ $bar_subgroup_bg: $surfaceVariant; .bar-topdesc { margin-top: -0.136rem; margin-bottom: -0.341rem; - color: $subtext; + color: $outline; } .bar-space-button { @@ -296,11 +292,12 @@ $bar_subgroup_bg: $surfaceVariant; } .bar-statusicons-hover { - background-color: mix($t_background, $t_onBackground, 90%); + background-color: $surfaceContainerHighest; } .bar-statusicons-active { - background-color: mix($t_background, $t_onBackground, 80%); + background-color: $primary; + color: $onPrimary; } .bar-util-btn { @@ -308,14 +305,16 @@ $bar_subgroup_bg: $surfaceVariant; @include element_decel; min-height: 1.77rem; min-width: 1.77rem; - background-color: $bar_subgroup_bg; + background-color: $secondaryContainer; + color: $onSecondaryContainer; } .bar-util-btn:hover, .bar-util-btn:focus { - background-color: mix($bar_subgroup_bg, $onSurfaceVariant, 90%); + background-color: $primaryContainer; } .bar-util-btn:active { - background-color: mix($bar_subgroup_bg, $onSurfaceVariant, 80%); -} \ No newline at end of file + background-color: $primary; + color: $onPrimary; +} diff --git a/.config/ags/scss/_colors.scss b/.config/ags/scss/_colors.scss index 2cc6ef45b..b74d52b95 100644 --- a/.config/ags/scss/_colors.scss +++ b/.config/ags/scss/_colors.scss @@ -3,38 +3,38 @@ // This is an attempt to improve that. $transparency_enabled: false; -@if $transparency_enabled ==false { - @if $darkmode ==true { - $primary: mix($primary, white, 70%); - $primaryContainer: mix($primaryContainer, white, 90%); - $background: mix(mix($background, $primary, 94%), #000000, 50%); - $surface: mix($surface, $primaryContainer, 98%); - $surfaceVariant: mix($surfaceVariant, #000000, 75%); - // $secondaryContainer: mix($secondaryContainer, $primaryContainer, 90%); - } - - @if $darkmode ==false { - $background: mix($background, $primary, 87%); - $surface: mix($surface, $primary, 93%); - $surfaceVariant: mix($surfaceVariant, #ffffff, 25%); - } -} - -@if $transparency_enabled ==true { - @if $darkmode ==true { - $background: mix(mix($background, $primary, 94%), #000000, 50%); - $surface: mix($surface, $primaryContainer, 98%); - $surfaceVariant: mix($surfaceVariant, #000000, 55%); - } - - @if $darkmode ==false { - $background: mix($background, $primary, 94%); - $surface: mix($surface, $primary, 93%); - $surfaceVariant: mix($surfaceVariant, #ffffff, 55%); - } -} - -// Amounts +//@if $transparency_enabled ==false { +// @if $darkmode ==true { +// $primary: mix($primary, white, 70%); +// $primaryContainer: mix($primaryContainer, white, 90%); +// $background: mix(mix($background, $primary, 94%), #000000, 50%); +// $surface: mix($surface, $primaryContainer, 98%); +// $surfaceVariant: mix($surfaceVariant, #000000, 75%); +// // $secondaryContainer: mix($secondaryContainer, $primaryContainer, 90%); +// } +// +// @if $darkmode ==false { +// $background: mix($background, $primary, 87%); +// $surface: mix($surface, $primary, 93%); +// $surfaceVariant: mix($surfaceVariant, #ffffff, 25%); +// } +//} +// +//@if $transparency_enabled ==true { +// @if $darkmode ==true { +// $background: mix(mix($background, $primary, 94%), #000000, 50%); +// $surface: mix($surface, $primaryContainer, 98%); +// $surfaceVariant: mix($surfaceVariant, #000000, 55%); +// } +// +// @if $darkmode ==false { +// $background: mix($background, $primary, 94%); +// $surface: mix($surface, $primary, 93%); +// $surfaceVariant: mix($surfaceVariant, #ffffff, 55%); +// } +//} +// +//// Amounts $transparentize_amount: 0.3; $transparentize_surface_amount_less: 0.6; $transparentize_surface_amount_less_less: 0.55; @@ -42,19 +42,19 @@ $transparentize_surface_amount: 0.7; $transparentize_surface_amount_more: 0.8; $transparentize_surface_amount_subtract_surface: $transparentize_surface_amount - $transparentize_amount; -@if $darkmode ==true { - // Less transparency - $transparentize_amount: 0.15; - $transparentize_surface_amount_less: 0.5; - $transparentize_surface_amount_less_less: 0.55; - $transparentize_surface_amount: 0.69; - $transparentize_surface_amount_more: 0.9; - $transparentize_surface_amount_subtract_surface: $transparentize_surface_amount - $transparentize_amount; -} - -@if $transparency_enabled ==false { - $transparentize_amount: 0; -} +//@if $darkmode ==true { +// // Less transparency +// $transparentize_amount: 0.15; +// $transparentize_surface_amount_less: 0.5; +// $transparentize_surface_amount_less_less: 0.55; +// $transparentize_surface_amount: 0.69; +// $transparentize_surface_amount_more: 0.9; +// $transparentize_surface_amount_subtract_surface: $transparentize_surface_amount - $transparentize_amount; +//} +// +//@if $transparency_enabled ==false { +// $transparentize_amount: 0; +//} // Extended material $success: #4f6354; @@ -114,13 +114,13 @@ $t_onSuccessContainer: transparentize($onErrorContainer, $transparentize_amount); // Others -$hovercolor: mix($t_surface, $t_onSurface, 50%); -$activecolor: mix($t_surface, $t_onSurface, 30%); -$subtext: mix($onBackground, $background, 70%); +//$hovercolor: #AA0000;//$surfaceContainerHigh; +//$activecolor: mix($t_surface, $t_onSurface, 30%); +$subtext: $outline; $actiontext: mix($onBackground, $background, 85%); // Terminal colors -$termbg: mix($t_surfaceVariant, $t_onSurfaceVariant, 80%); +$termbg: $surfaceContainerHigh; $termfg: $onSurfaceVariant; $term0: $t_background; $term1: $error; @@ -129,4 +129,4 @@ $term3: $onPrimaryContainer; $term4: $onPrimaryContainer; $term5: $onSecondaryContainer; $term6: $primary; -$term7: $onSurfaceVariant; \ No newline at end of file +$term7: $onSurfaceVariant; diff --git a/.config/ags/scss/_lib_mixins.scss b/.config/ags/scss/_lib_mixins.scss index ba5babffc..88f1cda4d 100644 --- a/.config/ags/scss/_lib_mixins.scss +++ b/.config/ags/scss/_lib_mixins.scss @@ -1,6 +1,6 @@ // Common colors -$hovercolor: rgba(128, 128, 128, 0.3); -$activecolor: rgba(128, 128, 128, 0.7); +$hovercolor: $surfaceContainerHigh; +$activecolor: $surfaceContainerHighest; $rounding_small: 0.818rem; $rounding_mediumsmall: 0.955rem; $rounding_medium: 1.159rem; diff --git a/.config/ags/scss/_notifications.scss b/.config/ags/scss/_notifications.scss index fa3a4ff05..234072be3 100644 --- a/.config/ags/scss/_notifications.scss +++ b/.config/ags/scss/_notifications.scss @@ -1,4 +1,4 @@ -$notif_surface: $t_background; +$notif_surface: $surfaceContainer; @mixin notif-rounding { @include normal-rounding; @@ -6,7 +6,7 @@ $notif_surface: $t_background; .notif-low { @include notif-rounding; - background-color: $l_l_t_surfaceVariant; + background-color: $surfaceContainerHigh; color: $onSurfaceVariant; padding: $rounding_small; padding-right: $rounding_small + 0.545rem; @@ -14,7 +14,7 @@ $notif_surface: $t_background; .notif-normal { @include notif-rounding; - background-color: $l_l_t_surfaceVariant; + background-color: $surfaceContainerHigh; color: $onSurfaceVariant; padding: $rounding_small; padding-right: $rounding_small + 0.545rem; @@ -29,21 +29,23 @@ $notif_surface: $t_background; } .notif-clicked-low { - background-color: mix($l_l_t_surfaceVariant, $t_onSurfaceVariant, 85%); + background-color: $surfaceContainerLow; } .notif-clicked-normal { - background-color: mix($l_l_t_surfaceVariant, $t_onSurfaceVariant, 85%); + background-color: $surfaceContainerLow; } .notif-clicked-critical { - background-color: mix($secondaryContainer, $onSecondaryContainer, 95%); + background-color: $onSecondary; + color: $onSecondaryContainer; } .popup-notif-low { @include notif-rounding; min-width: 30.682rem; background-color: $notif_surface; + border: 0.034rem solid $outlineVariant; color: $onSurfaceVariant; padding: $rounding_small; padding-right: $rounding_small + 0.545rem; @@ -53,6 +55,7 @@ $notif_surface: $t_background; @include notif-rounding; min-width: 30.682rem; background-color: $notif_surface; + border: 0.034rem solid $outlineVariant; color: $onSurfaceVariant; padding: $rounding_small; padding-right: $rounding_small + 0.545rem; @@ -62,29 +65,31 @@ $notif_surface: $t_background; @include notif-rounding; min-width: 30.682rem; background-color: $secondaryContainer; + border: 0.034rem solid $onSecondaryContainer; color: $onSecondaryContainer; padding: $rounding_small; padding-right: $rounding_small + 0.545rem; } .popup-notif-clicked-low { - background-color: mix($notif_surface, $onBackground, 94%); + background-color: $surfaceContainerLow; } .popup-notif-clicked-normal { - background-color: mix($notif_surface, $onBackground, 94%); + background-color: $surfaceContainerLow; } .popup-notif-clicked-critical { - background-color: mix($secondaryContainer, $onSecondaryContainer, 96%); + background-color: $onSecondary; + color: $onSecondaryContainer; } .notif-body-low { - color: mix($onSurfaceVariant, $surfaceVariant, 67%); + color: $outline; } .notif-body-normal { - color: mix($onSurfaceVariant, $surfaceVariant, 67%); + color: $outline; } .notif-body-critical { @@ -99,23 +104,23 @@ $notif_surface: $t_background; } .notif-icon-material { - background-color: $t_secondaryContainer; + background-color: $secondaryContainer; color: $onSecondaryContainer; } .notif-icon-material-low { - background-color: $t_secondaryContainer; + background-color: $secondaryContainer; color: $onSecondaryContainer; } .notif-icon-material-normal { - background-color: $t_secondaryContainer; + background-color: $secondaryContainer; color: $onSecondaryContainer; } .notif-icon-material-critical { - background-color: $t_onSecondaryContainer; - color: $secondaryContainer; + background-color: $secondary; + color: $onSecondary; } .notif-expand-btn { @@ -163,8 +168,7 @@ $notif_surface: $t_background; .osd-notif { @include notif-rounding; - background-color: transparentize($background, - $transparentize_surface_amount_subtract_surface ); + background-color: $background; min-width: 30.682rem; } @@ -201,43 +205,43 @@ $notif_surface: $t_background; } .notif-action-low { - background-color: mix($t_onSurfaceVariant, $t_surface, 10%); + background-color: $surfaceContainerHighest; color: $onSurfaceVariant; } .notif-action-low:focus, .notif-action-low:hover { - background-color: $hovercolor; + border: 0.040rem solid $outlineVariant; } .notif-action-low:active { - background-color: $activecolor; + background-color: $surfaceBright; } .notif-action-normal { - background-color: mix($t_onSurfaceVariant, $t_surface, 10%); + background-color: $surfaceContainerHighest; color: $onSurfaceVariant; } .notif-action-normal:focus, .notif-action-normal:hover { - background-color: $hovercolor; + border: 0.040rem solid $outlineVariant; } .notif-action-normal:active { - background-color: $activecolor; + background-color: $surfaceBright; } .notif-action-critical { - background-color: mix($t_onSecondaryContainer, $t_secondaryContainer, 10%); + background-color: mix($secondary, $onSecondary, 30%); color: $onSurfaceVariant; } .notif-action-critical:focus, .notif-action-critical:hover { - background-color: mix($t_onSecondaryContainer, $t_secondaryContainer, 18%); + border: 0.040rem solid $outline; } .notif-action-critical:active { - background-color: mix($t_onSecondaryContainer, $t_secondaryContainer, 23%); -} \ No newline at end of file + background-color: mix($secondary, $onSecondary, 40%); +} diff --git a/.config/ags/scss/_overview.scss b/.config/ags/scss/_overview.scss index 8afa43b81..137317abc 100644 --- a/.config/ags/scss/_overview.scss +++ b/.config/ags/scss/_overview.scss @@ -11,7 +11,7 @@ min-height: 3.409rem; padding: 0rem 1.364rem; padding-right: 2.864rem; - background-color: $t_background; + background-color: $background; color: $onBackground; selection { @@ -53,8 +53,8 @@ @include elevation2; min-width: 28.773rem; padding: 0.682rem; - background-color: $t_background; - color: $onBackground; + background-color: $surfaceContainerLow; + color: $onSurface; } .overview-search-results-icon { @@ -97,7 +97,7 @@ @include elevation-border; @include elevation2; padding: 0.341rem; - background-color: $t_background; + background-color: $background; color: $onBackground; } @@ -105,35 +105,37 @@ @include normal-rounding; // @include elevation-border; margin: 0.341rem; - background-color: mix($t_t_surface, $t_onSurface, 93%); + background-color: $surfaceContainerLow; } .overview-tasks-workspace-number { @include mainfont; - color: mix($t_onSurface, $t_surface, 93%); + color: $onSurfaceVariant; } .overview-tasks-window { @include normal-rounding; @include menu_decel; - background-color: $t_surfaceVariant; - color: $onSecondaryContainer; - border: 0.068rem solid $t_t_t_onSecondaryContainer; + background-color: $surfaceContainerHigh; + color: $onSurface; + border: 0.068rem solid $outlineVariant; } .overview-tasks-window:hover, .overview-tasks-window:focus { - background-color: mix($l_t_secondaryContainer, $primary, 95%); + background-color: $secondaryContainer; } .overview-tasks-window:active { - background-color: mix($l_t_secondaryContainer, $primary, 90%); + background-color: $tertiaryContainer; + background-color: mix($secondaryContainer, $hovercolor, 70%); } .overview-tasks-window-selected { - background-color: mix($l_t_secondaryContainer, $primary, 90%); + background-color: $tertiaryContainer; + background-color: mix($secondaryContainer, $hovercolor, 70%); } .overview-tasks-window-dragging { opacity: 0.2; -} \ No newline at end of file +} diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss index 1989c9cb8..218946e0a 100644 --- a/.config/ags/scss/_sidebars.scss +++ b/.config/ags/scss/_sidebars.scss @@ -1,5 +1,5 @@ $sidebar_chat_textboxareaColor: mix($onSurfaceVariant, $surfaceVariant, 40%); -$textboxColor: mix($surface, $surfaceVariant, 80%); +$textboxColor: $surfaceContainerHigh; $system: $secondary; $onSystem: $onSecondary; $chatgpt: $primary; @@ -16,7 +16,7 @@ $onChatgpt: $onPrimary; border-radius: $rounding_large - $elevation_margin + 0.068rem; min-width: 27.818rem; // COMMENT THIS LATER IF TEXT WRAP IS USED // min-height: 29.591rem; - background-color: $t_background; + background-color: $background; padding: 1.023rem; } @@ -37,7 +37,7 @@ $onChatgpt: $onPrimary; border-radius: $rounding_large - $elevation_margin + 0.068rem; min-width: 27.818rem; // COMMENT THIS LATER IF TEXT WRAP IS USED // min-height: 29.591rem; - background-color: $t_background; + background-color: $background; padding: 1.023rem; } @@ -54,12 +54,12 @@ $onChatgpt: $onPrimary; .sidebar-group { @include normal-rounding; @include group-padding; - background-color: $t_surface; + background-color: $surfaceContainer; } .sidebar-group-nopad { @include normal-rounding; - background-color: $t_surface; + background-color: $surfaceContainer; } .sidebar-group-invisible { @@ -73,7 +73,7 @@ $onChatgpt: $onPrimary; .sidebar-togglesbox { @include full-rounding; @include group-padding; - background-color: $t_surface; + background-color: $surfaceContainer; } .sidebar-iconbutton { @@ -96,8 +96,6 @@ $onChatgpt: $onPrimary; .sidebar-button { @include element_decel; padding: 0rem $rounding_small; - background-color: $t_secondaryContainer; - color: $onSecondaryContainer; } .sidebar-button:hover, @@ -206,16 +204,16 @@ $onChatgpt: $onPrimary; @include element_decel; min-width: 0.273rem; min-height: 2.045rem; - background-color: $t_onSurfaceVariant; + background-color: transparentize($onSurfaceVariant, 0.7); } slider:hover, slider:focus { - background-color: mix($t_onSurfaceVariant, $onSurfaceVariant, 80%); + background-color: transparentize($onSurfaceVariant, 0.6); } slider:active { - background-color: mix($onSurfaceVariant, $surfaceVariant, 50%); + background-color: transparentize($onSurface, 0.5); } } @@ -256,7 +254,7 @@ $onChatgpt: $onPrimary; } .sidebar-calendar-btn-othermonth { - color: mix($onSurface, $surface, 50%); + color: $outline; } .sidebar-calendar-header { @@ -267,19 +265,17 @@ $onChatgpt: $onPrimary; @include full-rounding; @include element_decel; padding: 0rem 0.682rem; - background-color: $t_surfaceVariant; - color: $onSurfaceVariant; + background-color: $surfaceContainer; + color: $outline; } .sidebar-calendar-monthyear-btn:hover, .sidebar-calendar-monthyear-btn:focus { background-color: $hovercolor; - color: mix($onSurfaceVariant, $surfaceVariant, 95%); } .sidebar-calendar-monthyear-btn:active { background-color: $activecolor; - color: mix($onSurfaceVariant, $surfaceVariant, 85%); } .sidebar-calendar-monthshift-btn { @@ -287,18 +283,16 @@ $onChatgpt: $onPrimary; @include element_decel; min-width: 2.045rem; min-height: 2.045rem; - background-color: $t_surfaceVariant; - color: $onSurfaceVariant; + background-color: $surfaceContainer; + color: $outline; } .sidebar-calendar-monthshift-btn:hover { background-color: $hovercolor; - color: mix($onSurfaceVariant, $surfaceVariant, 95%); } .sidebar-calendar-monthshift-btn:active { background-color: $activecolor; - color: mix($onSurfaceVariant, $surfaceVariant, 85%); } .sidebar-selector-tab { @@ -337,10 +331,6 @@ $onChatgpt: $onPrimary; padding-right: 0.545rem; } -.sidebar-todo-item-even { - background-color: $t_t_surfaceVariant; -} - .sidebar-todo-item-action { @include element_decel; border-radius: 9999px; @@ -373,7 +363,6 @@ $onChatgpt: $onPrimary; .sidebar-todo-new { @include full-rounding; @include element_decel; - color: $onSecondaryContainer; margin: 0.341rem; padding: 0.205rem 0.545rem; border: 0.068rem solid $onSurface; @@ -381,11 +370,13 @@ $onChatgpt: $onPrimary; .sidebar-todo-new, .sidebar-todo-new:focus { - background-color: mix($t_secondaryContainer, $t_onSecondaryContainer, 97%); + color: $onSecondaryContainer; + background-color: $secondaryContainer; } .sidebar-todo-new:active { - background-color: mix($t_secondaryContainer, $t_onSecondaryContainer, 80%); + color: $onPrimaryContainer; + background-color: $primaryContainer; } .sidebar-todo-add { @@ -399,11 +390,11 @@ $onChatgpt: $onPrimary; .sidebar-todo-add:hover, .sidebar-todo-add:focus { - background-color: mix($t_secondaryContainer, $t_onSecondaryContainer, 97%); + background-color: $surfaceContainerHigh; } .sidebar-todo-add:active { - background-color: mix($t_secondaryContainer, $t_onSecondaryContainer, 80%); + background-color: $surfaceContainerHighest; } .sidebar-todo-add-available { @@ -418,11 +409,11 @@ $onChatgpt: $onPrimary; .sidebar-todo-add-available:hover, .sidebar-todo-add-available:focus { - background-color: mix($primary, $onPrimary, 97%); + background-color: mix($primary, $hovercolor, 70%); } .sidebar-todo-add-available:active { - background-color: mix($primary, $onPrimary, 80%); + background-color: mix($primary, $hovercolor, 40%); } .sidebar-todo-entry { @@ -435,24 +426,24 @@ $onChatgpt: $onPrimary; min-height: 1.773rem; min-width: 0rem; padding: 0.205rem 0.682rem; - border: 0.068rem solid mix($onSurfaceVariant, $surfaceVariant, 50%); + border: 0.068rem solid $outline; } .sidebar-todo-entry:focus { - border: 0.068rem solid mix($onSurfaceVariant, $surfaceVariant, 90%); + border: 0.068rem solid $onSurfaceVariant; } .sidebar-module { @include normal-rounding; @include group-padding; - background-color: $l_l_t_surfaceVariant; + background-color: $surfaceContainer; padding: 0.682rem; } .sidebar-module-btn-arrow { @include full-rounding; @include icon-material; - background-color: $l_l_t_surfaceVariant; + background-color: $surfaceContainerHigh; min-width: 1.705rem; min-height: 1.705rem; @@ -464,7 +455,7 @@ $onChatgpt: $onPrimary; .sidebar-module-scripts-button { @include full-rounding; @include icon-material; - background-color: $l_l_t_surfaceVariant; + background-color: $surfaceContainer; min-width: 1.705rem; min-height: 1.705rem; @@ -540,7 +531,7 @@ $colorpicker_rounding: 0.341rem; .sidebar-chat-apiswitcher { @include full-rounding; @include group-padding; - background-color: $t_surface; + background-color: $surfaceContainer; } .sidebar-chat-apiswitcher-icon { @@ -605,11 +596,11 @@ $colorpicker_rounding: 0.341rem; .sidebar-chat-send:hover, .sidebar-chat-send:focus { - background-color: $surfaceVariant; + background-color: $surfaceBright; } .sidebar-chat-send:active { - background-color: mix($surfaceVariant, $onBackground, 80%); + background-color: $surfaceVariant; } .sidebar-chat-send-available { @@ -619,11 +610,11 @@ $colorpicker_rounding: 0.341rem; .sidebar-chat-send-available:hover, .sidebar-chat-send-available:focus { - background-color: mix($primary, $onPrimary, 97%); + background-color: mix($primary, $hovercolor, 70%); } .sidebar-chat-send-available:active { - background-color: mix($primary, $onPrimary, 80%); + background-color: mix($primary, $hovercolor, 40%); } .sidebar-chat-message { @@ -683,17 +674,17 @@ $colorpicker_rounding: 0.341rem; background-color: $termbg; color: $termfg; margin: 0rem 0.682rem; - border: 0.068rem solid $t_t_t_onSecondaryContainer; + border: 0.068rem solid $outlineVariant; } .sidebar-chat-codeblock-topbar { @include mainfont; margin: 0.273rem; margin-bottom: 0rem; - background-color: mix($t_secondaryContainer, $t_onSurfaceVariant, 30%); + background-color: $secondaryContainer; color: $onSecondaryContainer; border-radius: $rounding_medium - 0.273rem; - border: 0.068rem solid mix($secondaryContainer, $onSecondaryContainer, 90%); + border: 0.068rem solid $outlineVariant; border-top-left-radius: $rounding_small + 0.068rem; border-top-right-radius: $rounding_small + 0.068rem; padding: 0.341rem 0.477rem; @@ -712,11 +703,11 @@ $colorpicker_rounding: 0.341rem; .sidebar-chat-codeblock-topbar-btn:hover, .sidebar-chat-codeblock-topbar-btn:focus { - background-color: mix($t_secondaryContainer, $t_onSecondaryContainer, 80%); + background-color: mix($secondaryContainer, $onSecondaryContainer, 90%); } .sidebar-chat-codeblock-topbar-btn:active { - background-color: mix($t_secondaryContainer, $t_onSecondaryContainer, 60%); + background-color: mix($secondaryContainer, $onSecondaryContainer, 80%); } .sidebar-chat-codeblock-code { @@ -824,11 +815,11 @@ $colorpicker_rounding: 0.341rem; .sidebar-pin-enabled:hover, .sidebar-pin-enabled:focus { - background-color: mix($primary, $onPrimary, 90%); + background-color: mix($primary, $hovercolor, 70%); } .sidebar-pin-enabled:active { - background-color: mix($primary, $onPrimary, 80%); + background-color: mix($primary, $hovercolor, 40%); } .sidebar-waifu-heading { From 0a08fa7ab4dc0e79ab2a51a7d8d16cc5853e508d Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 9 Mar 2024 15:52:23 +0700 Subject: [PATCH 101/517] bar music control: bind side button, act immediately on click --- .config/ags/modules/bar/normal/music.js | 10 +++++++--- .config/ags/modules/bar/normal/spaceright.js | 8 ++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.config/ags/modules/bar/normal/music.js b/.config/ags/modules/bar/normal/music.js index d50fa46e6..a14efa74d 100644 --- a/.config/ags/modules/bar/normal/music.js +++ b/.config/ags/modules/bar/normal/music.js @@ -207,9 +207,13 @@ export default () => { return EventBox({ onScrollUp: (self) => switchToRelativeWorkspace(self, -1), onScrollDown: (self) => switchToRelativeWorkspace(self, +1), - onPrimaryClickRelease: () => showMusicControls.setValue(!showMusicControls.value), - onSecondaryClickRelease: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print), - onMiddleClickRelease: () => execAsync('playerctl play-pause').catch(print), + onPrimaryClick: () => showMusicControls.setValue(!showMusicControls.value), + onSecondaryClick: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print), + onMiddleClick: () => execAsync('playerctl play-pause').catch(print), + setup: (self) => self.on('button-press-event', (self, event) => { + if (event.get_button()[1] === 8) // Side button + execAsync('playerctl previous').catch(print) + }), child: Box({ className: 'spacing-h-4', children: [ diff --git a/.config/ags/modules/bar/normal/spaceright.js b/.config/ags/modules/bar/normal/spaceright.js index 8d63e7009..8bca0103f 100644 --- a/.config/ags/modules/bar/normal/spaceright.js +++ b/.config/ags/modules/bar/normal/spaceright.js @@ -71,8 +71,12 @@ export default () => { onHover: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', true) }, onHoverLost: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', false) }, onPrimaryClick: () => App.toggleWindow('sideright'), - onSecondaryClickRelease: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print), - onMiddleClickRelease: () => execAsync('playerctl play-pause').catch(print), + onSecondaryClick: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print), + onMiddleClick: () => execAsync('playerctl play-pause').catch(print), + setup: (self) => self.on('button-press-event', (self, event) => { + if (event.get_button()[1] === 8) + execAsync('playerctl previous').catch(print) + }), child: Widget.Box({ homogeneous: false, children: [ From e69615d56ff2a897728b09ad17282b188eaf031b Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 9 Mar 2024 14:40:15 +0700 Subject: [PATCH 102/517] fix tooltip styling --- .config/ags/scss/main.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/scss/main.scss b/.config/ags/scss/main.scss index 793783916..ea1f378fe 100644 --- a/.config/ags/scss/main.scss +++ b/.config/ags/scss/main.scss @@ -2,7 +2,7 @@ // * { // all: unset; // } -*:not(popover):not(widget) { all: unset; } +*:not(popover) { all: unset; } // Colors @import './material'; // Material colors From ec4e8a9acc12eb46f02b3b2d28ee2aa430852886 Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 10 Mar 2024 18:08:52 +0800 Subject: [PATCH 103/517] Fix unexpected joined line (#317) --- scriptdata/options | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scriptdata/options b/scriptdata/options index f3e37f578..7fdf19b24 100644 --- a/scriptdata/options +++ b/scriptdata/options @@ -3,7 +3,8 @@ # NOTE that you NOT need to `cd ..' because the `$0' is NOT this file, but the script file which will source this file. # The script that use this file should have two lines on its top as follows: -# cd "$(dirname "$0")" export base="$(pwd)" showhelp(){ +# cd "$(dirname "$0")" export base="$(pwd)" +showhelp(){ echo -e "Syntax: $0 [Options]... Idempotent installation script for dotfiles. From 3956a94dca36eb6b265ade0b3441b82ca5867f5e Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 10 Mar 2024 18:33:53 +0800 Subject: [PATCH 104/517] Reminder about not overwritten files --- install.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/install.sh b/install.sh index 2bcd030db..72e1cf6c7 100755 --- a/install.sh +++ b/install.sh @@ -161,9 +161,11 @@ t="$HOME/.config/ags/user_options.js" if [ -f $t ];then echo -e "\e[34m[$0]: \"$t\" already exists.\e[0m" v cp -f .config/ags/user_options.js $t.new + existed_ags_opt=y else echo -e "\e[33m[$0]: \"$t\" does not exist yet.\e[0m" v cp .config/ags/user_options.js $t + existed_ags_opt=n fi # For Hyprland @@ -172,9 +174,11 @@ t="$HOME/.config/hypr/hyprland.conf" if [ -f $t ];then echo -e "\e[34m[$0]: \"$t\" already exists.\e[0m" v cp -f .config/hypr/hyprland.conf $t.new + existed_hypr_conf=y else echo -e "\e[33m[$0]: \"$t\" does not exist yet.\e[0m" v cp .config/hypr/hyprland.conf $t + existed_hypr_conf=n fi t="$HOME/.config/hypr/custom" if [ -d $t ];then @@ -197,3 +201,12 @@ printf "\e[36m[$0]: Finished. See the \"Import Manually\" folder and grab anythi printf "\e[36mPress \e[30m\e[46m Ctrl+Super+T \e[0m\e[36m to select a wallpaper\e[97m\n" printf "\e[36mPress \e[30m\e[46m Super+/ \e[0m\e[36m for a list of keybinds\e[97m\n" echo "See https://end-4.github.io/dots-hyprland-wiki/en for more info." +case $existed_ags_opt in + y) printf "\n\e[33m[$0]: Warning: \"~/.config/ags/user_options.js\" already existed before and we didn't overwrite it. \e[97m\n" + printf "\e[33mPlease use \"~/.config/ags/user_options.js.new\" as a reference for a proper format.\e[97m\n" +;;esac +case $existed_hypr_conf in + y) printf "\n\e[33m[$0]: Warning: \"~/.config/hypr/hyprland.conf\" already existed before and we didn't overwrite it. \e[97m\n" + printf "\e[33mPlease use \"~/.config/hypr/hyprland.conf.new\" as a reference for a proper format.\e[97m\n" + printf "\e[33mIf this is your first time installation, you must overwrite \"~/.config/hypr/hyprland.conf\" with \"~/.config/hypr/hyprland.conf.new\".\e[97m\n" +;;esac From 8b026d1d7d5378a4ccf7d9bdc932518fdfc8d322 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 10 Mar 2024 17:44:44 +0700 Subject: [PATCH 105/517] chore: update ags and remove deprecated stuff --- .config/ags/config.js | 4 +- .../ags/modules/.widgethacks/popupwindow.js | 42 ++++++++++--------- .config/ags/modules/cheatsheet/main.js | 4 +- .config/ags/modules/overview/main.js | 6 +-- .config/ags/modules/session/main.js | 4 +- scriptdata/installers | 2 +- 6 files changed, 32 insertions(+), 30 deletions(-) diff --git a/.config/ags/config.js b/.config/ags/config.js index 415d5e518..f7ccabdbd 100644 --- a/.config/ags/config.js +++ b/.config/ags/config.js @@ -57,7 +57,7 @@ const Windows = () => [ forMonitors((id) => Corner(id, 'bottom right')), ]; const CLOSE_ANIM_TIME = 210; // Longer than actual anim time to make sure widgets animate fully -export default { +App.config({ css: `${COMPILED_STYLE_DIR}/style.css`, stackTraceOnError: true, closeWindowDelay: { // For animations @@ -66,7 +66,7 @@ export default { 'osk': CLOSE_ANIM_TIME, }, windows: Windows().flat(1), -}; +}); // Stuff that don't need to be toggled. And they're async so ugh... // Bar().catch(print); // Use this to debug the bar. Single monitor only. diff --git a/.config/ags/modules/.widgethacks/popupwindow.js b/.config/ags/modules/.widgethacks/popupwindow.js index 2b85ca7cf..26dad59c1 100644 --- a/.config/ags/modules/.widgethacks/popupwindow.js +++ b/.config/ags/modules/.widgethacks/popupwindow.js @@ -6,25 +6,27 @@ const { Box, Window } = Widget; export default ({ name, child, - showClassName, - hideClassName, + showClassName = "", + hideClassName = "", ...props -}) => Window({ - name, - popup: true, - visible: false, - layer: 'overlay', - ...props, +}) => { + return Window({ + name, + visible: false, + layer: 'overlay', + ...props, - child: Box({ - className: `${showClassName} ${hideClassName}`, - setup: (self) => self - .hook(App, (self, currentName, visible) => { - if (currentName === name) { - self.toggleClassName(hideClassName, !visible); - } - }) - , - child: child, - }), -}); \ No newline at end of file + child: Box({ + setup: (self) => { + self.hook(App, (self, currentName, visible) => { + if (currentName === name) { + self.toggleClassName(hideClassName, !visible); + } + }).keybind("Escape", () => App.closeWindow(name)) + if (showClassName !== "" && hideClassName !== "") + self.className = `${showClassName} ${hideClassName}`; + }, + child: child, + }), + }); +} \ No newline at end of file diff --git a/.config/ags/modules/cheatsheet/main.js b/.config/ags/modules/cheatsheet/main.js index 0d5b47896..d83a18b86 100644 --- a/.config/ags/modules/cheatsheet/main.js +++ b/.config/ags/modules/cheatsheet/main.js @@ -3,6 +3,7 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import Service from 'resource:///com/github/Aylur/ags/service.js'; import { Keybinds } from "./keybinds.js"; import { setupCursorHover } from "../.widgetutils/cursorhover.js"; +import PopupWindow from '../.widgethacks/popupwindow.js'; const cheatsheetHeader = () => Widget.CenterBox({ vertical: false, @@ -68,11 +69,10 @@ const clickOutsideToClose = Widget.EventBox({ onMiddleClick: () => App.closeWindow('cheatsheet'), }); -export default () => Widget.Window({ +export default () => PopupWindow({ name: 'cheatsheet', exclusivity: 'ignore', keymode: 'exclusive', - popup: true, visible: false, child: Widget.Box({ vertical: true, diff --git a/.config/ags/modules/overview/main.js b/.config/ags/modules/overview/main.js index 436b444e9..0bab9194f 100644 --- a/.config/ags/modules/overview/main.js +++ b/.config/ags/modules/overview/main.js @@ -1,11 +1,11 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import { SearchAndWindows } from "./windowcontent.js"; +import PopupWindow from '../.widgethacks/popupwindow.js'; -export default () => Widget.Window({ - name: 'overview', +export default (id = '') => PopupWindow({ + name: `overview${id}`, exclusivity: 'ignore', keymode: 'exclusive', - popup: true, visible: false, anchor: ['top'], layer: 'overlay', diff --git a/.config/ags/modules/session/main.js b/.config/ags/modules/session/main.js index acf66ddf9..26d33cca1 100644 --- a/.config/ags/modules/session/main.js +++ b/.config/ags/modules/session/main.js @@ -1,9 +1,9 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import SessionScreen from "./sessionscreen.js"; +import PopupWindow from '../.widgethacks/popupwindow.js'; -export default () => Widget.Window({ // On-screen keyboard +export default () => PopupWindow({ // On-screen keyboard name: 'session', - popup: true, visible: false, keymode: 'exclusive', layer: 'overlay', diff --git a/scriptdata/installers b/scriptdata/installers index c46015c6e..175da758c 100644 --- a/scriptdata/installers +++ b/scriptdata/installers @@ -24,7 +24,7 @@ install-ags (){ try git init -b main try git remote add origin https://github.com/Aylur/ags.git x git pull origin main && git submodule update --init --recursive - x git checkout e257efa0a13c50538bed77ca6e557dc4dd3a3482 # add Widget.keybind #248 + x git checkout b40b8d81c5543ef02caee67560ab1c13ebcee49a # "update examples" x npm install x meson setup build x meson install -C build From 00e8d9a6e0b1ee030dc5b9eabc2d3530c27dd33a Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 10 Mar 2024 19:17:10 +0800 Subject: [PATCH 106/517] Fix slurp quote (#316) --- .config/hypr/hyprland/keybinds.conf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.config/hypr/hyprland/keybinds.conf b/.config/hypr/hyprland/keybinds.conf index 3d2d0fd26..26c339cbf 100644 --- a/.config/hypr/hyprland/keybinds.conf +++ b/.config/hypr/hyprland/keybinds.conf @@ -38,7 +38,7 @@ bind = Control+Shift+Alt, Delete, exec, pkill wlogout || wlogout -p layer-shell bind = Control+Shift+Alt+Super, Delete, exec, systemctl poweroff # Screenshot, Record, OCR, Color picker, Clipboard history -bind = Super+Shift+Alt, S, exec, grim -g $(slurp) - | swappy -f - +bind = Super+Shift+Alt, S, exec, grim -g "$(slurp)" - | swappy -f - bindl=,Print,exec,grim - | wl-copy bind = Super+Shift, S, exec, ~/.config/ags/scripts/grimblast.sh --freeze copy area bind = Super+Alt, R, exec, ~/.config/ags/scripts/record-script.sh @@ -49,11 +49,11 @@ bind = Super, V, exec, pkill fuzzel || cliphist list | fuzzel --no-fuzzy --dmenu # Text-to-image # Normal -bind = Control+Super+Shift,S,exec,grim -g $(slurp $SLURP_ARGS) "tmp.png" && tesseract "tmp.png" - | wl-copy && rm "tmp.png" +bind = Control+Super+Shift,S,exec,grim -g "$(slurp $SLURP_ARGS)" "tmp.png" && tesseract "tmp.png" - | wl-copy && rm "tmp.png" # English -bind = Super+Shift,T,exec,grim -g $(slurp $SLURP_ARGS) "tmp.png" && tesseract -l eng "tmp.png" - | wl-copy && rm "tmp.png" +bind = Super+Shift,T,exec,grim -g "$(slurp $SLURP_ARGS)" "tmp.png" && tesseract -l eng "tmp.png" - | wl-copy && rm "tmp.png" # Japanese -bind = Super+Shift,J,exec,grim -g $(slurp $SLURP_ARGS) "tmp.png" && tesseract -l jpn "tmp.png" - | wl-copy && rm "tmp.png" +bind = Super+Shift,J,exec,grim -g "$(slurp $SLURP_ARGS)" "tmp.png" && tesseract -l jpn "tmp.png" - | wl-copy && rm "tmp.png" # Media bindl= Super+Shift, N, exec, playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` From bf50557800ae281a1c5ff318161ae3852754f7d3 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 10 Mar 2024 23:05:41 +0700 Subject: [PATCH 107/517] bar text: truncate instead of having horiz scroll (#320) --- .config/ags/modules/bar/normal/music.js | 22 ++++++++++----------- .config/ags/modules/bar/normal/spaceleft.js | 4 ++++ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.config/ags/modules/bar/normal/music.js b/.config/ags/modules/bar/normal/music.js index a14efa74d..bef38e79b 100644 --- a/.config/ags/modules/bar/normal/music.js +++ b/.config/ags/modules/bar/normal/music.js @@ -133,18 +133,18 @@ export default () => { ] })] }); - const trackTitle = Scrollable({ + const trackTitle = Label({ hexpand: true, - child: Label({ - className: 'txt-smallie txt-onSurfaceVariant', - setup: (self) => self.hook(Mpris, label => { - const mpris = Mpris.getPlayer(''); - if (mpris) - label.label = `${trimTrackTitle(mpris.trackTitle)} • ${mpris.trackArtists.join(', ')}`; - else - label.label = 'No media'; - }), - }) + className: 'txt-smallie txt-onSurfaceVariant', + truncate: 'end', + maxWidthChars: 10, // Doesn't matter, just needs to be non negative + setup: (self) => self.hook(Mpris, label => { + const mpris = Mpris.getPlayer(''); + if (mpris) + label.label = `${trimTrackTitle(mpris.trackTitle)} • ${mpris.trackArtists.join(', ')}`; + else + label.label = 'No media'; + }), }) const musicStuff = Box({ className: 'spacing-h-10', diff --git a/.config/ags/modules/bar/normal/spaceleft.js b/.config/ags/modules/bar/normal/spaceleft.js index 4f43189a3..475297790 100644 --- a/.config/ags/modules/bar/normal/spaceleft.js +++ b/.config/ags/modules/bar/normal/spaceleft.js @@ -14,6 +14,8 @@ const WindowTitle = async () => { children: [ Widget.Label({ xalign: 0, + truncate: 'end', + maxWidthChars: 10, // Doesn't matter, just needs to be non negative className: 'txt-smaller bar-topdesc txt', setup: (self) => self.hook(Hyprland.active.client, label => { // Hyprland.active.client label.label = Hyprland.active.client.class.length === 0 ? 'Desktop' : Hyprland.active.client.class; @@ -21,6 +23,8 @@ const WindowTitle = async () => { }), Widget.Label({ xalign: 0, + truncate: 'end', + maxWidthChars: 10, // Doesn't matter, just needs to be non negative className: 'txt txt-smallie', setup: (self) => self.hook(Hyprland.active.client, label => { // Hyprland.active.client label.label = Hyprland.active.client.title.length === 0 ? `Workspace ${Hyprland.active.workspace.id}` : Hyprland.active.client.title; From bbe11ab43f02f4566ed53506f87150aaf75fdcf3 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 11 Mar 2024 15:10:28 +0700 Subject: [PATCH 108/517] adjust bluetooth device indicator spacing --- .config/ags/modules/.commonwidgets/statusicons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/modules/.commonwidgets/statusicons.js b/.config/ags/modules/.commonwidgets/statusicons.js index 2b587f409..fd0bf14ae 100644 --- a/.config/ags/modules/.commonwidgets/statusicons.js +++ b/.config/ags/modules/.commonwidgets/statusicons.js @@ -85,7 +85,7 @@ export const BluetoothIndicator = () => Widget.Stack({ }); const BluetoothDevices = () => Widget.Box({ - className: 'spacing-h-10', + className: 'spacing-h-5', setup: self => self.hook(Bluetooth, self => { self.children = Bluetooth.connected_devices.map((device) => { return Widget.Box({ From 56898f503523f9c670f9fb17dabf6bc48130c444 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 11 Mar 2024 15:56:09 +0700 Subject: [PATCH 109/517] raw input: input:accel_profile instead of input:force_no_accel, as advised by hl wiki --- .config/ags/modules/overview/miscfunctions.js | 11 ++++++- .config/ags/modules/sideright/quicktoggles.js | 30 +++++++++++++++++++ .config/ags/modules/sideright/sideright.js | 5 ++-- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/.config/ags/modules/overview/miscfunctions.js b/.config/ags/modules/overview/miscfunctions.js index aa184f8ed..0e5d2229e 100644 --- a/.config/ags/modules/overview/miscfunctions.js +++ b/.config/ags/modules/overview/miscfunctions.js @@ -13,7 +13,16 @@ export function hasUnterminatedBackslash(inputString) { export function launchCustomCommand(command) { const args = command.split(' '); if (args[0] == '>raw') { // Mouse raw input - execAsync([`bash`, `-c`, `hyprctl keyword input:force_no_accel $(( 1 - $(hyprctl getoption input:force_no_accel -j | gojq ".int") ))`, `&`]).catch(print); + Utils.execAsync('hyprctl -j getoption input:accel_profile') + .then((output) => { + const value = JSON.parse(output)["str"].trim(); + if (value != "[[EMPTY]]" && value != "") { + execAsync(['bash', '-c', `hyprctl keyword input:accel_profile '[[EMPTY]]'`]).catch(print); + } + else { + execAsync(['bash', '-c', `hyprctl keyword input:accel_profile flat`]).catch(print); + } + }) } else if (args[0] == '>img') { // Change wallpaper execAsync([`bash`, `-c`, `${App.configDir}/scripts/color_generation/switchwall.sh`, `&`]).catch(print); diff --git a/.config/ags/modules/sideright/quicktoggles.js b/.config/ags/modules/sideright/quicktoggles.js index aefc654a0..69b01c8ed 100644 --- a/.config/ags/modules/sideright/quicktoggles.js +++ b/.config/ags/modules/sideright/quicktoggles.js @@ -130,6 +130,36 @@ export const ModuleInvertColors = async (props = {}) => { }; } +export const ModuleRawInput = async (props = {}) => { + try { + const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default; + return Widget.Button({ + className: 'txt-small sidebar-iconbutton', + tooltipText: 'Raw input', + onClicked: (button) => { + Hyprland.messageAsync('j/getoption input:accel_profile') + .then((output) => { + const value = JSON.parse(output)["str"].trim(); + if (value != "[[EMPTY]]" && value != "") { + execAsync(['bash', '-c', `hyprctl keyword input:accel_profile '[[EMPTY]]'`]).catch(print); + button.toggleClassName('sidebar-button-active', false); + } + else { + Hyprland.messageAsync(`j/keyword input:accel_profile flat`) + .catch(print); + button.toggleClassName('sidebar-button-active', true); + } + }) + }, + child: MaterialIcon('mouse', 'norm'), + setup: setupCursorHover, + ...props, + }) + } catch { + return null; + }; +} + export const ModuleIdleInhibitor = (props = {}) => Widget.Button({ // TODO: Make this work attribute: { enabled: false, diff --git a/.config/ags/modules/sideright/sideright.js b/.config/ags/modules/sideright/sideright.js index 79c7a4001..b08ad91f5 100644 --- a/.config/ags/modules/sideright/sideright.js +++ b/.config/ags/modules/sideright/sideright.js @@ -12,7 +12,8 @@ import { ModuleEditIcon, ModuleReloadIcon, ModuleSettingsIcon, - ModulePowerIcon + ModulePowerIcon, + ModuleRawInput } from "./quicktoggles.js"; import ModuleNotificationList from "./notificationlist.js"; import { ModuleCalendar } from "./calendar.js"; @@ -51,7 +52,7 @@ const togglesBox = Widget.Box({ children: [ ToggleIconWifi(), ToggleIconBluetooth(), - await HyprToggleIcon('mouse', 'Raw input', 'input:force_no_accel', {}), + await ModuleRawInput(), await HyprToggleIcon('front_hand', 'No touchpad while typing', 'input:touchpad:disable_while_typing', {}), ModuleNightLight(), await ModuleInvertColors(), From 1cdf66ce094416bb5b782e90cbe8048bf3f5cab5 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 11 Mar 2024 16:02:48 +0700 Subject: [PATCH 110/517] fix weird light theme --- .config/ags/scss/_colors.scss | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.config/ags/scss/_colors.scss b/.config/ags/scss/_colors.scss index b1277e8b4..3db57ab7c 100644 --- a/.config/ags/scss/_colors.scss +++ b/.config/ags/scss/_colors.scss @@ -10,13 +10,11 @@ $transparency_enabled: false; $background: mix(mix($background, $primary, 94%), #000000, 50%); $surface: mix($surface, $primaryContainer, 98%); $surfaceVariant: mix($surfaceVariant, #000000, 75%); - // $secondaryContainer: mix($secondaryContainer, $primaryContainer, 90%); } @if $darkmode ==false { - $background: mix($background, $primary, 85%); - $surface: mix($surface, $primary, 90%); - $surfaceVariant: mix($surfaceVariant, #ffffff, 50%); + $primaryContainer: mix($primaryContainer, white, 90%); + $surface: mix($surface, $primaryContainer, 98%); } } From dafd7b4a408ab56b146fc1d3f543727582169ef9 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 12 Mar 2024 14:43:30 +0700 Subject: [PATCH 111/517] allow user config (related: #271) (closes #318) --- .config/ags/config.js | 2 +- .../modules/.configuration/user_options.js | 104 ++++++++++++++++++ .config/ags/user_options.js | 84 +------------- 3 files changed, 110 insertions(+), 80 deletions(-) create mode 100644 .config/ags/modules/.configuration/user_options.js diff --git a/.config/ags/config.js b/.config/ags/config.js index f7ccabdbd..6a40909fb 100644 --- a/.config/ags/config.js +++ b/.config/ags/config.js @@ -5,7 +5,7 @@ import GLib from 'gi://GLib'; import App from 'resource:///com/github/Aylur/ags/app.js' import * as Utils from 'resource:///com/github/Aylur/ags/utils.js' // Stuff -import userOptions from './user_options.js'; +import userOptions from './modules/.configuration/user_options.js'; // Widgets import { Bar, BarCornerTopleft, BarCornerTopright } from './modules/bar/main.js'; import Cheatsheet from './modules/cheatsheet/main.js'; diff --git a/.config/ags/modules/.configuration/user_options.js b/.config/ags/modules/.configuration/user_options.js new file mode 100644 index 000000000..502f6cecb --- /dev/null +++ b/.config/ags/modules/.configuration/user_options.js @@ -0,0 +1,104 @@ + +import userOverrides from '../../user_options.js'; + +// Defaults +let configOptions = { + // General stuff + 'ai': { + 'defaultGPTProvider': "openai", + 'defaultTemperature': 0.9, + 'writingCursor': " ...", // Warning: Using weird characters can mess up Markdown rendering + }, + 'animations': { + 'durationSmall': 110, + 'durationLarge': 180, + }, + 'apps': { + 'imageViewer': "loupe", + 'terminal': "foot", // This is only for shell actions + }, + 'battery': { + 'low': 20, + 'critical': 10, + }, + 'music': { + 'preferredPlayer': "plasma-browser-integration", + }, + 'onScreenKeyboard': { + 'layout': "qwerty_full", // See modules/onscreenkeyboard/onscreenkeyboard.js for available layouts + }, + 'overview': { + 'scale': 0.18, // Relative to screen size + 'numOfRows': 2, + 'numOfCols': 5, + 'wsNumScale': 0.09, + 'wsNumMarginScale': 0.07, + }, + 'sidebar': { + 'imageColumns': 2, + 'imageBooruCount': 6, + }, + 'search': { + 'engineBaseUrl': "https://www.google.com/search?q=", + 'excludedSites': ["quora.com"], + }, + 'time': { + // See https://docs.gtk.org/glib/method.DateTime.format.html + // Here's the 12h format: "%I:%M%P" + // For seconds, add "%S" and set interval to 1000 + 'format': "%H:%M", + 'interval': 5000, + 'dateFormatLong': "%A, %d/%m", // On bar + 'dateInterval': 5000, + 'dateFormat': "%d/%m", // On notif time + }, + 'weather': { + 'city': "", + }, + 'workspaces': { + 'shown': 10, + }, + // Longer stuff + 'icons': { + substitutions: { + 'code-url-handler': "visual-studio-code", + 'Code': "visual-studio-code", + 'GitHub Desktop': "github-desktop", + 'Minecraft* 1.20.1': "minecraft", + 'gnome-tweaks': "org.gnome.tweaks", + 'pavucontrol-qt': "pavucontrol", + 'wps': "wps-office2019-kprometheus", + 'wpsoffice': "wps-office2019-kprometheus", + '': "image-missing", + } + }, + 'keybinds': { + // Format: Mod1+Mod2+key. CaSe SeNsItIvE! + // Modifiers: Shift Ctrl Alt Hyper Meta + // See https://docs.gtk.org/gdk3/index.html#constants for the other keys (they are listed as KEY_key) + 'overview': { + 'altMoveLeft': "Ctrl+b", + 'altMoveRight': "Ctrl+f", + 'deleteToEnd': "Ctrl+k", + }, + 'sidebar': { + 'apis': { + 'nextTab': "Page_Down", + 'prevTab': "Page_Up", + }, + 'pin': "Ctrl+p", + 'cycleTab': "Ctrl+Tab", + 'nextTab': "Ctrl+Page_Down", + 'prevTab': "Ctrl+Page_Up", + }, + }, +} + +// Load user's options +Object.entries(userOverrides).forEach((override) => { + const [key, value] = override; + configOptions[key] = value; +}); + +globalThis['userOptions'] = configOptions; +export default configOptions; \ No newline at end of file diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index 2be909313..c30241978 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -1,82 +1,9 @@ -let userConfigOptions = { - // General stuff - 'ai': { - 'defaultGPTProvider': "openai", - 'defaultTemperature': 0.9, - 'writingCursor': " ...", // Warning: Using weird characters can mess up Markdown rendering - }, - 'animations': { - 'durationSmall': 110, - 'durationLarge': 180, - }, - 'apps': { - 'imageViewer': "loupe", - 'terminal': "foot", // This is only for shell actions - }, - 'battery': { - 'low': 20, - 'critical': 10, - }, - 'music': { - 'preferredPlayer': "plasma-browser-integration", - }, - 'onScreenKeyboard': { - 'layout': "qwerty_full", // See modules/onscreenkeyboard/onscreenkeyboard.js for available layouts - }, - 'overview': { - 'scale': 0.18, // Relative to screen size - 'numOfRows': 2, - 'numOfCols': 5, - 'wsNumScale': 0.09, - 'wsNumMarginScale': 0.07, - }, - 'sidebar': { - 'imageColumns': 2, - }, - 'search': { - 'engineBaseUrl': "https://www.google.com/search?q=", - 'excludedSites': ["quora.com"], - }, - 'time': { - // See https://docs.gtk.org/glib/method.DateTime.format.html - // Here's the 12h format: "%I:%M%P" - // For seconds, add "%S" and set interval to 1000 - 'format': "%H:%M", - 'interval': 5000, - 'dateFormatLong': "%A, %d/%m", // On bar - 'dateInterval': 5000, - 'dateFormat': "%d/%m", // On notif time - }, - 'weather': { - 'city': "", - }, - 'workspaces': { - 'shown': 10, - }, - // Longer stuff - 'icons': { - substitutions: { - 'code-url-handler': "visual-studio-code", - 'Code': "visual-studio-code", - 'GitHub Desktop': "github-desktop", - 'Minecraft* 1.20.1': "minecraft", - 'gnome-tweaks': "org.gnome.tweaks", - 'pavucontrol-qt': "pavucontrol", - 'wps': "wps-office2019-kprometheus", - 'wpsoffice': "wps-office2019-kprometheus", - '': "image-missing", - } - }, +const userConfigOptions = { + // For every option, see ~/.config/ags/modules/.configuration/user_options.js (vscode users ctrl+click this file://./modules/.configuration/user_options.js) + // Options listed in this file will override the default ones in the above file + // Here's an example 'keybinds': { - // Format: Mod1+Mod2+key. CaSe SeNsItIvE! - // Modifiers: Shift Ctrl Alt Hyper Meta - // See https://docs.gtk.org/gdk3/index.html#constants for the other keys (they are listed as KEY_key) - 'overview': { - 'altMoveLeft': "Ctrl+b", - 'altMoveRight': "Ctrl+f", - 'deleteToEnd': "Ctrl+k", - }, 'sidebar': { 'apis': { 'nextTab': "Page_Down", @@ -90,5 +17,4 @@ let userConfigOptions = { }, } -globalThis['userOptions'] = userConfigOptions; -export default userOptions; \ No newline at end of file +export default userConfigOptions; \ No newline at end of file From 7567133f1483dea34fc13e49cc5f0024333b079e Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 12 Mar 2024 14:44:10 +0700 Subject: [PATCH 112/517] booru: improve styling; add action buttons --- .config/ags/modules/sideleft/apis/booru.js | 53 +++++++++++++++++----- .config/ags/scss/_sidebars.scss | 9 ++++ .config/ags/services/booru.js | 8 +++- 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/.config/ags/modules/sideleft/apis/booru.js b/.config/ags/modules/sideleft/apis/booru.js index 6fe174d57..a4929928c 100644 --- a/.config/ags/modules/sideleft/apis/booru.js +++ b/.config/ags/modules/sideleft/apis/booru.js @@ -102,7 +102,6 @@ const BooruPage = (taglist) => { const PageState = (icon, name) => Box({ className: 'spacing-h-5 txt', children: [ - Box({ hexpand: true }), Label({ className: 'sidebar-waifu-txt txt-smallie', xalign: 0, @@ -119,15 +118,35 @@ const BooruPage = (taglist) => { setup: setupCursorHover, }) const PreviewImage = (data) => { - return Box({ - className: 'sidebar-booru-image', - // css: 'border: 2px solid white;', - css: `background-image: url('${data.preview_url}');`, - // setup: (self) => { + return Overlay({ + child: Box({ + className: 'sidebar-booru-image', + css: `background-image: url('${data.preview_url}');`, + // setup: (self) => { // Utils.timeout(1000, () => { // self.css = `background-image: url('${data.preview_url}');`; // }) - // } + // } + }), + overlays: [ + Box({ + vpack: 'start', + className: 'sidebar-booru-image-actions spacing-h-3', + children: [ + Box({ hexpand: true }), + ImageAction({ + name: 'Go to file url', + icon: 'file_open', + action: () => execAsync(['xdg-open', `${data.file_url}`]).catch(print), + }), + ImageAction({ + name: 'Go to source', + icon: 'open_in_new', + action: () => execAsync(['xdg-open', `${data.source}`]).catch(print), + }), + ] + }) + ] }) } const colorIndicator = Box({ @@ -151,11 +170,21 @@ const BooruPage = (taglist) => { child: downloadState, }); const pageHeading = Box({ - hpack: 'fill', - className: 'sidebar-waifu-content spacing-h-5', + homogeneous: false, children: [ - ...taglist.map((tag) => CommandButton(tag)), - Box({ hexpand: true }), + Scrollable({ + hexpand: true, + vscroll: 'never', + hscroll: 'automatic', + child: Box({ + hpack: 'fill', + className: 'sidebar-waifu-content spacing-h-5', + children: [ + ...taglist.map((tag) => CommandButton(tag)), + Box({ hexpand: true }), + ] + }) + }), downloadIndicator, ] }); @@ -219,7 +248,7 @@ const BooruPage = (taglist) => { // Add stuff for (let i = 0; i < imageRows; i++) { for (let j = 0; j < imageColumns; j++) { - if (i * imageColumns + j >= 8) break; + if (i * imageColumns + j >= userOptions.sidebar.imageBooruCount) break; // if (i * imageColumns + j >= data.length) break; pageImageGrid.attach(PreviewImage(data[i * imageColumns + j]), j, i, 1, 1); } diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss index 136ad63ec..dad80e962 100644 --- a/.config/ags/scss/_sidebars.scss +++ b/.config/ags/scss/_sidebars.scss @@ -638,9 +638,11 @@ $colorpicker_rounding: 0.341rem; @include small-rounding; margin: 0rem 0.682rem; padding: 0.682rem; + @if $darkmode ==true { background-color: white; } + color: $onBackground; // background-color: $termbg; } @@ -849,9 +851,16 @@ $waifu_image_overlay_transparency: 0.7; } .sidebar-booru-image { + @include small-rounding; + margin: 0.273rem; min-width: 12.818rem; min-height: 12.818rem; background-size: cover; background-repeat: no-repeat; background-position: center; +} + +.sidebar-booru-image-actions { + @include element_decel; + margin: 0.545rem; } \ No newline at end of file diff --git a/.config/ags/services/booru.js b/.config/ags/services/booru.js index 9d8d5d2c2..8faae8e5a 100644 --- a/.config/ags/services/booru.js +++ b/.config/ags/services/booru.js @@ -82,7 +82,6 @@ class BooruService extends Service { 'tags': taglist.join('+'), }; const paramString = paramStringFromObj(params); - console.log('==========PARAMS LIST\n', params, '\n============\nSTR\n', paramString) // Fetch // Note: body isn't included since passing directly to url is more reliable const options = { @@ -97,8 +96,11 @@ class BooruService extends Service { }) .then((dataString) => { // Store interesting stuff and emit const parsedData = JSON.parse(dataString); + // console.log(parsedData) this._responses.push(parsedData.map(obj => { return { + id: obj.id, + tags: obj.tags, md5: obj.md5, preview_url: obj.preview_url, preview_width: obj.preview_width, @@ -106,6 +108,10 @@ class BooruService extends Service { sample_url: obj.sample_url, sample_width: obj.sample_width, sample_height: obj.sample_height, + file_url: obj.file_url, + file_ext: obj.file_ext, + file_width: obj.file_width, + file_height: obj.file_height, source: getWorkingImageSauce(obj.source), } })); From 1ec26083cb6585f41d2fb94f8dee1a71b7141dc0 Mon Sep 17 00:00:00 2001 From: clsty Date: Tue, 12 Mar 2024 16:29:16 +0800 Subject: [PATCH 113/517] Not making .new for AGS (#271,#318) --- install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 72e1cf6c7..b948110ec 100755 --- a/install.sh +++ b/install.sh @@ -160,7 +160,7 @@ v rsync -av --delete --exclude '/user_options.js' .config/ags/ "$HOME"/.config/a t="$HOME/.config/ags/user_options.js" if [ -f $t ];then echo -e "\e[34m[$0]: \"$t\" already exists.\e[0m" - v cp -f .config/ags/user_options.js $t.new +# v cp -f .config/ags/user_options.js $t.new existed_ags_opt=y else echo -e "\e[33m[$0]: \"$t\" does not exist yet.\e[0m" @@ -203,7 +203,7 @@ printf "\e[36mPress \e[30m\e[46m Super+/ \e[0m\e[36m for a list of keybinds\e[97 echo "See https://end-4.github.io/dots-hyprland-wiki/en for more info." case $existed_ags_opt in y) printf "\n\e[33m[$0]: Warning: \"~/.config/ags/user_options.js\" already existed before and we didn't overwrite it. \e[97m\n" - printf "\e[33mPlease use \"~/.config/ags/user_options.js.new\" as a reference for a proper format.\e[97m\n" +# printf "\e[33mPlease use \"~/.config/ags/user_options.js.new\" as a reference for a proper format.\e[97m\n" ;;esac case $existed_hypr_conf in y) printf "\n\e[33m[$0]: Warning: \"~/.config/hypr/hyprland.conf\" already existed before and we didn't overwrite it. \e[97m\n" From 8ee10d47d4fd3806b13c4b9c7c65b9c6cb7e986b Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 12 Mar 2024 15:44:54 +0700 Subject: [PATCH 114/517] fix user options by making loader recursive (#318) --- .../ags/modules/.configuration/user_options.js | 18 ++++++++++++------ .config/ags/user_options.js | 5 ----- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.config/ags/modules/.configuration/user_options.js b/.config/ags/modules/.configuration/user_options.js index 502f6cecb..e8a5bfa7d 100644 --- a/.config/ags/modules/.configuration/user_options.js +++ b/.config/ags/modules/.configuration/user_options.js @@ -72,7 +72,7 @@ let configOptions = { '': "image-missing", } }, - 'keybinds': { + 'keybinds': { // Format: Mod1+Mod2+key. CaSe SeNsItIvE! // Modifiers: Shift Ctrl Alt Hyper Meta // See https://docs.gtk.org/gdk3/index.html#constants for the other keys (they are listed as KEY_key) @@ -94,11 +94,17 @@ let configOptions = { }, } -// Load user's options -Object.entries(userOverrides).forEach((override) => { - const [key, value] = override; - configOptions[key] = value; -}); +// Override defaults with user's options +function overrideConfigRecursive(userOverrides, configOptions = {}) { + for (const [key, value] of Object.entries(userOverrides)) { + if (typeof value === 'object') { + overrideConfigRecursive(value, configOptions[key]); + } else { + configOptions[key] = value; + } + } +} +overrideConfigRecursive(userOverrides, configOptions); globalThis['userOptions'] = configOptions; export default configOptions; \ No newline at end of file diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index c30241978..085f37ef4 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -5,12 +5,7 @@ const userConfigOptions = { // Here's an example 'keybinds': { 'sidebar': { - 'apis': { - 'nextTab': "Page_Down", - 'prevTab': "Page_Up", - }, 'pin': "Ctrl+p", - 'cycleTab': "Ctrl+Tab", 'nextTab': "Ctrl+Page_Down", 'prevTab': "Ctrl+Page_Up", }, From 99964eb6dcfb8e56b3fed1e24698f7000414bd52 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:23:33 +0700 Subject: [PATCH 115/517] fix #323 --- .config/ags/scripts/templates/terminal/sequences.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/scripts/templates/terminal/sequences.txt b/.config/ags/scripts/templates/terminal/sequences.txt index 6fb48e654..a48ca9d00 100644 --- a/.config/ags/scripts/templates/terminal/sequences.txt +++ b/.config/ags/scripts/templates/terminal/sequences.txt @@ -1 +1 @@ -]4;0;#$background #\]4;1;#$error #\]4;2;#$inversePrimary #\]4;3;#$onPrimaryContainer #\]4;4;#$onPrimaryContainer #\]4;5;#$onSecondaryContainer #\]4;6;#$primary #\]4;7;#$onSurfaceVariant #\]4;8;#$background #\]4;9;#$error #\]4;10;#$inversePrimary #\]4;11;#$onPrimaryContainer #\]4;12;#$onPrimaryContainer #\]4;13;#$onSecondaryContainer #\]4;14;#$primary #\]4;15;#$onSurfaceVariant #\]10;#$onSurfaceVariant #\]11;[$alpha]#$background #\]12;#$onSurfaceVariant #\]13;#$onSurfaceVariant #\]17;#$onSurfaceVariant #\]19;#$background #\]4;232;#$background #\]4;256;#$onSurfaceVariant #\]708;[$alpha]#$background #\ \ No newline at end of file +]4;0;#$background #\]4;1;#$error #\]4;2;#$inversePrimary #\]4;3;#$onPrimaryContainer #\]4;4;#$onPrimaryContainer #\]4;5;#$onSecondaryContainer #\]4;6;#$primary #\]4;7;#$onSurfaceVariant #\]4;8;#$onSurfaceVariant #\]4;9;#$error #\]4;10;#$inversePrimary #\]4;11;#$onPrimaryContainer #\]4;12;#$onPrimaryContainer #\]4;13;#$onSecondaryContainer #\]4;14;#$primary #\]4;15;#$onSurfaceVariant #\]10;#$onSurfaceVariant #\]11;[$alpha]#$background #\]12;#$onSurfaceVariant #\]13;#$onSurfaceVariant #\]17;#$onSurfaceVariant #\]19;#$background #\]4;232;#$onSurfaceVariant #\]4;256;#$onSurfaceVariant #\]708;[$alpha]#$background #\ \ No newline at end of file From 48d0dce17caabb31803fc56f8a411cfb784a6e7a Mon Sep 17 00:00:00 2001 From: Cruleo Date: Tue, 12 Mar 2024 23:46:18 +0100 Subject: [PATCH 116/517] hypr: update config files to comply with hyprlang --- .config/hypr/custom/env.conf | 4 ++-- .config/hypr/custom/general.conf | 4 ++-- .config/hypr/custom/keybinds.conf | 4 ++-- .config/hypr/custom/rules.conf | 6 +++--- .config/hypr/hyprland/env.conf | 10 +++++----- .config/hypr/hyprland/keybinds.conf | 14 +++++++------- .config/hypr/hyprland/rules.conf | 4 ++-- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.config/hypr/custom/env.conf b/.config/hypr/custom/env.conf index 4390ed4fb..fcd59ec86 100644 --- a/.config/hypr/custom/env.conf +++ b/.config/hypr/custom/env.conf @@ -1,2 +1,2 @@ -## You can put extra environment variables here -## https://wiki.hyprland.org/Configuring/Environment-variables/ +# You can put extra environment variables here +# https://wiki.hyprland.org/Configuring/Environment-variables/ diff --git a/.config/hypr/custom/general.conf b/.config/hypr/custom/general.conf index f88b956b1..ded706ae7 100644 --- a/.config/hypr/custom/general.conf +++ b/.config/hypr/custom/general.conf @@ -1,2 +1,2 @@ -## Put general config stuff here -## Here's a list of every variable: https://wiki.hyprland.org/Configuring/Variables/ \ No newline at end of file +# Put general config stuff here +# Here's a list of every variable: https://wiki.hyprland.org/Configuring/Variables/ \ No newline at end of file diff --git a/.config/hypr/custom/keybinds.conf b/.config/hypr/custom/keybinds.conf index fb337e909..f34545cef 100644 --- a/.config/hypr/custom/keybinds.conf +++ b/.config/hypr/custom/keybinds.conf @@ -1,2 +1,2 @@ -## You can put your preferred keybinds here -## https://wiki.hyprland.org/Configuring/Binds/ \ No newline at end of file +# You can put your preferred keybinds here +# https://wiki.hyprland.org/Configuring/Binds/ \ No newline at end of file diff --git a/.config/hypr/custom/rules.conf b/.config/hypr/custom/rules.conf index 870a1143e..159de0915 100644 --- a/.config/hypr/custom/rules.conf +++ b/.config/hypr/custom/rules.conf @@ -1,3 +1,3 @@ -## You can put custom rules here -## Window/layer rules: https://wiki.hyprland.org/Configuring/Window-Rules/ -## Workspace rules: https://wiki.hyprland.org/Configuring/Workspace-Rules/ +# You can put custom rules here +# Window/layer rules: https://wiki.hyprland.org/Configuring/Window-Rules/ +# Workspace rules: https://wiki.hyprland.org/Configuring/Workspace-Rules/ diff --git a/.config/hypr/hyprland/env.conf b/.config/hypr/hyprland/env.conf index 79ccc344d..66ed2df2f 100644 --- a/.config/hypr/hyprland/env.conf +++ b/.config/hypr/hyprland/env.conf @@ -1,5 +1,5 @@ -########## Input method ########## -## See https://fcitx-im.org/wiki/Using_Fcitx_5_on_Wayland +# ######### Input method ########## +# See https://fcitx-im.org/wiki/Using_Fcitx_5_on_Wayland env = QT_IM_MODULE, fcitx env = XMODIFIERS, @im=fcitx # env = GTK_IM_MODULE, wayland # Crashes electron apps in xwayland @@ -8,14 +8,14 @@ env = SDL_IM_MODULE, fcitx env = GLFW_IM_MODULE, ibus env = INPUT_METHOD, fcitx -############# Themes ############# +# ############ Themes ############# env = QT_QPA_PLATFORM, wayland env = QT_QPA_PLATFORMTHEME, qt5ct # env = QT_STYLE_OVERRIDE,kvantum env = WLR_NO_HARDWARE_CURSORS, 1 -######### Screen tearing ######### +# ######## Screen tearing ######### # env = WLR_DRM_NO_ATOMIC, 1 -############# Others ############# +# ############ Others ############# diff --git a/.config/hypr/hyprland/keybinds.conf b/.config/hypr/hyprland/keybinds.conf index 26c339cbf..e8eedd610 100644 --- a/.config/hypr/hyprland/keybinds.conf +++ b/.config/hypr/hyprland/keybinds.conf @@ -1,4 +1,4 @@ -#################### It just works™ keybinds ################### +# ################### It just works™ keybinds ################### # Volume bindl = ,XF86AudioMute, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 0% bindl = Super+Shift,M, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 0% @@ -10,7 +10,7 @@ bindle=, XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- #bindle=, XF86MonBrightnessUp, exec, brightnessctl set '12.75+' #bindle=, XF86MonBrightnessDown, exec, brightnessctl set '12.75-' -#################################### Applications ################################### +# ################################### Applications ################################### # Apps: just normal apps bind = Super, C, exec, code --password-store=gnome --enable-features=UseOzonePlatform --ozone-platform=wayland bind = Super, T, exec, foot --override shell=fish @@ -62,7 +62,7 @@ bindl= Super+Shift, B, exec, playerctl previous bindl= Super+Shift, P, exec, playerctl play-pause bindl= ,XF86AudioPlay, exec, playerctl play-pause -#Lock screen +# Lock screen bind = Super, L, exec, loginctl lock-session bind = Super+Shift, L, exec, loginctl lock-session bindl = Super+Shift, L, exec, sleep 0.1 && systemctl suspend @@ -70,7 +70,7 @@ bindl = Super+Shift, L, exec, sleep 0.1 && systemctl suspend # App launcher bind = Control+Super, Slash, exec, pkill anyrun || anyrun -###################################### AGS keybinds ##################################### +# ##################################### AGS keybinds ##################################### bindr = Control+Super, R, exec, killall ags ydotool; ags & bindr = Control+Super+Alt, R, exec, hyprctl reload; killall ags ydotool; ags & bind = Control+Super, T, exec, ~/.config/ags/scripts/color_generation/switchwall.sh @@ -93,17 +93,17 @@ bindle=, XF86MonBrightnessDown, exec, ags run-js 'brightness.screen_value -= 0.0 bindl = , XF86AudioMute, exec, ags run-js 'indicator.popup(1);' bindl = Super+Shift,M, exec, ags run-js 'indicator.popup(1);' -###################################### Plugins ######################################### +# ##################################### Plugins ######################################### bind = Control+Super, P, exec, hyprctl plugin load "~/.config/hypr/plugins/droidbars.so" bind = Control+Super, O, exec, hyprctl plugin unload "~/.config/hypr/plugins/droidbars.so" -## Testing +# Testing # bind = SuperAlt, f12, exec, notify-send "Hyprland version: $(hyprctl version | head -2 | tail -1 | cut -f2 -d ' ')" "owo" -a 'Hyprland keybind' # bind = Super+Alt, f12, exec, notify-send "Millis since epoch" "$(date +%s%N | cut -b1-13)" -a 'Hyprland keybind' bind = Super+Alt, f12, exec, notify-send 'Test notification' "Here's a really long message to test truncation and wrapping\nYou can middle click or flick this notification to dismiss it!" -a 'Shell' -A "Test1=I got it!" -A "Test2=Another action" -t 5000 bind = Super+Alt, Equal, exec, notify-send "Urgent notification" "Ah hell no" -u critical -a 'Hyprland keybind' -############################ Keybinds for Hyprland ############################ +# ########################### Keybinds for Hyprland ############################ # Swap windows bind = Super+Shift, left, movewindow, l bind = Super+Shift, right, movewindow, r diff --git a/.config/hypr/hyprland/rules.conf b/.config/hypr/hyprland/rules.conf index 996fa2fd1..baf5033a3 100644 --- a/.config/hypr/hyprland/rules.conf +++ b/.config/hypr/hyprland/rules.conf @@ -1,4 +1,4 @@ -######## Window rules ######## +# ####### Window rules ######## windowrule = noblur,.* # Disables blur for windows. Substantially improves performance. # windowrule = opacity 0.89 override 0.89 override, .* # Applies transparency to EVERY WINDOW @@ -16,7 +16,7 @@ windowrule=float,title:^(Open Folder)(.*)$ windowrule=float,title:^(Save As)(.*)$ windowrule=float,title:^(Library)(.*)$ -######## Layer rules ######## +# ####### Layer rules ######## layerrule = xray 1, .* #layerrule = noanim, .* layerrule = noanim, selection From 0338de82c735bd3ee1e37f18107a90474b554992 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 13 Mar 2024 22:57:51 +0700 Subject: [PATCH 117/517] update ignores --- .config/ags/scss/_musicmaterial.scss | 1 - .config/ags/scss/_musicwal.scss | 1 - .gitignore | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 .config/ags/scss/_musicmaterial.scss delete mode 100644 .config/ags/scss/_musicwal.scss diff --git a/.config/ags/scss/_musicmaterial.scss b/.config/ags/scss/_musicmaterial.scss deleted file mode 100644 index 8b1378917..000000000 --- a/.config/ags/scss/_musicmaterial.scss +++ /dev/null @@ -1 +0,0 @@ - diff --git a/.config/ags/scss/_musicwal.scss b/.config/ags/scss/_musicwal.scss deleted file mode 100644 index 8b1378917..000000000 --- a/.config/ags/scss/_musicwal.scss +++ /dev/null @@ -1 +0,0 @@ - diff --git a/.gitignore b/.gitignore index e5b9f48bd..1eac6202d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -.config/ags/style.css +.config/ags/node_modules .config/ags/scss/_musicmaterial.scss .config/ags/scss/_musicwal.scss .config/ags/scss/_material.scss From ee7fdc9ab4d74d8ac6788345474c80974dc6dede Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 13 Mar 2024 23:10:07 +0700 Subject: [PATCH 118/517] update hyprland config --- .config/hypr/hyprland/general.conf | 2 ++ .config/hypr/hyprland/keybinds.conf | 8 +++--- .config/hypr/hyprland/rules.conf | 42 ++++++++++++++--------------- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/.config/hypr/hyprland/general.conf b/.config/hypr/hyprland/general.conf index 496406cf8..e0456003b 100644 --- a/.config/hypr/hyprland/general.conf +++ b/.config/hypr/hyprland/general.conf @@ -113,12 +113,14 @@ animations { bezier = easeInOutCirc, 0.85, 0, 0.15, 1 bezier = easeOutCirc, 0, 0.55, 0.45, 1 bezier = easeOutExpo, 0.16, 1, 0.3, 1 + bezier = softAcDecel, 0.26, 0.26, 0.15, 1 # Animation configs animation = windows, 1, 3, md3_decel, popin 60% animation = border, 1, 10, default animation = fade, 1, 2.5, md3_decel # animation = workspaces, 1, 3.5, md3_decel, slide animation = workspaces, 1, 7, fluent_decel, slide + # animation = workspaces, 1, 2.5, softAcDecel, slide # animation = workspaces, 1, 7, fluent_decel, slidefade 15% # animation = specialWorkspace, 1, 3, md3_decel, slidefadevert 15% animation = specialWorkspace, 1, 3, md3_decel, slidevert diff --git a/.config/hypr/hyprland/keybinds.conf b/.config/hypr/hyprland/keybinds.conf index e8eedd610..77bf038d4 100644 --- a/.config/hypr/hyprland/keybinds.conf +++ b/.config/hypr/hyprland/keybinds.conf @@ -13,8 +13,8 @@ bindle=, XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- # ################################### Applications ################################### # Apps: just normal apps bind = Super, C, exec, code --password-store=gnome --enable-features=UseOzonePlatform --ozone-platform=wayland -bind = Super, T, exec, foot --override shell=fish -#bind = Super, Return, exec, foot --override shell=fish +bind = Super, T, exec, foot +# bind = Super, Return, exec, foot --override shell=fish bind = Super, E, exec, nautilus --new-window bind = Super+Alt, E, exec, thunar bind = Super, W, exec, firefox @@ -202,8 +202,8 @@ bindle = Alt, K, exec, ydotool key 108:1 108:0 bindle = Alt, J, exec, ydotool key 105:1 105:0 bindle = Alt, L, exec, ydotool key 106:1 106:0 # Control + Side mouse btn for switching tabs (Ctrl+PgUp/PgDn) -bind = Control, mouse:275, exec, ydotool key 29:1 104:1 104:0 29:0 -bind = Control, mouse:276, exec, ydotool key 29:1 109:1 109:0 29:0 +# bind = Control, mouse:275, exec, ydotool key 29:1 104:1 104:0 29:0 +# bind = Control, mouse:276, exec, ydotool key 29:1 109:1 109:0 29:0 diff --git a/.config/hypr/hyprland/rules.conf b/.config/hypr/hyprland/rules.conf index baf5033a3..5210add59 100644 --- a/.config/hypr/hyprland/rules.conf +++ b/.config/hypr/hyprland/rules.conf @@ -18,7 +18,7 @@ windowrule=float,title:^(Library)(.*)$ # ####### Layer rules ######## layerrule = xray 1, .* -#layerrule = noanim, .* +# layerrule = noanim, .* layerrule = noanim, selection layerrule = noanim, overview layerrule = noanim, anyrun @@ -42,23 +42,23 @@ layerrule = blur, session layerrule = noanim, sideright layerrule = noanim, sideleft -#layerrule = blur, bar -#layerrule = ignorealpha 0.64, bar -#layerrule = blur, corner.* -#layerrule = ignorealpha 0.69, corner.* -#layerrule = blur, dock -#layerrule = ignorealpha 0.69, dock -#layerrule = blur, indicator.* -#layerrule = ignorealpha 0.69, indicator.* -#layerrule = blur, overview -#layerrule = ignorealpha 0.69, overview -#layerrule = blur, cheatsheet -#layerrule = ignorealpha 0.69, cheatsheet -#layerrule = blur, sideright -#layerrule = ignorealpha 0.69, sideright -#layerrule = blur, sideleft -#layerrule = ignorealpha 0.69, sideleft -#layerrule = blur, indicator* -#layerrule = ignorealpha 0.69, indicator* -#layerrule = blur, osk -#layerrule = ignorealpha 0.69, osk +# layerrule = blur, bar +# layerrule = ignorealpha 0.64, bar +# layerrule = blur, corner.* +# layerrule = ignorealpha 0.69, corner.* +# layerrule = blur, dock +# layerrule = ignorealpha 0.69, dock +# layerrule = blur, indicator.* +# layerrule = ignorealpha 0.69, indicator.* +# layerrule = blur, overview +# layerrule = ignorealpha 0.69, overview +# layerrule = blur, cheatsheet +# layerrule = ignorealpha 0.69, cheatsheet +# layerrule = blur, sideright +# layerrule = ignorealpha 0.69, sideright +# layerrule = blur, sideleft +# layerrule = ignorealpha 0.69, sideleft +# layerrule = blur, indicator* +# layerrule = ignorealpha 0.69, indicator* +# layerrule = blur, osk +# layerrule = ignorealpha 0.69, osk From d3761d1d0d5efcaf801abcead2cec6f1d89396fd Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 14 Mar 2024 12:06:33 +0700 Subject: [PATCH 119/517] separate scss color vars for bar elements (1) (#327) --- .config/ags/modules/bar/normal/music.js | 65 ++++---- .config/ags/modules/bar/normal/system.js | 8 +- .config/ags/scss/_bar.scss | 193 +++++++++++++---------- .config/ags/scss/_colors.scss | 40 ++++- .config/ags/scss/_lib_classes.scss | 4 + .config/ags/services/messages.js | 2 +- .config/ags/user_options.js | 2 +- 7 files changed, 191 insertions(+), 123 deletions(-) diff --git a/.config/ags/modules/bar/normal/music.js b/.config/ags/modules/bar/normal/music.js index bef38e79b..ea9c35404 100644 --- a/.config/ags/modules/bar/normal/music.js +++ b/.config/ags/modules/bar/normal/music.js @@ -36,9 +36,9 @@ const BarGroup = ({ child }) => Box({ ] }); -const BarResource = (name, icon, command) => { +const BarResource = (name, icon, command, circprogClassName = 'bar-batt-circprog', textClassName = 'txt-onSurfaceVariant', iconClassName = 'bar-batt') => { const resourceCircProg = AnimatedCircProg({ - className: 'bar-batt-circprog', + className: `${circprogClassName}`, vpack: 'center', hpack: 'center', }); @@ -47,7 +47,7 @@ const BarResource = (name, icon, command) => { children: [Overlay({ child: Box({ vpack: 'center', - className: 'bar-batt', + className: `${iconClassName}`, homogeneous: true, children: [ MaterialIcon(icon, 'small'), @@ -57,10 +57,10 @@ const BarResource = (name, icon, command) => { })] }); const resourceLabel = Label({ - className: 'txt-smallie txt-onSurfaceVariant', + className: `txt-smallie ${textClassName}`, }); const widget = Box({ - className: 'spacing-h-4 txt-onSurfaceVariant', + className: `spacing-h-4 ${textClassName}`, children: [ resourceProgress, resourceLabel, @@ -135,8 +135,8 @@ export default () => { }); const trackTitle = Label({ hexpand: true, - className: 'txt-smallie txt-onSurfaceVariant', - truncate: 'end', + className: 'txt-smallie bar-music-txt', + truncate: 'end', maxWidthChars: 10, // Doesn't matter, just needs to be non negative setup: (self) => self.hook(Mpris, label => { const mpris = Mpris.getPlayer(''); @@ -178,31 +178,32 @@ export default () => { onScrollDown: () => execAsync(CUSTOM_MODULE_SCROLLDOWN_SCRIPT).catch(print), }) }); - } else { - return BarGroup({ - child: Box({ - children: [ - BarResource('RAM Usage', 'memory', `LANG=C free | awk '/^Mem/ {printf("%.2f\\n", ($3/$2) * 100)}'`), - Revealer({ - revealChild: true, - transition: 'slide_left', - transitionDuration: userOptions.animations.durationLarge, - child: Box({ - className: 'spacing-h-10 margin-left-10', - children: [ - BarResource('Swap Usage', 'swap_horiz', `LANG=C free | awk '/^Swap/ {if ($2 > 0) printf("%.2f\\n", ($3/$2) * 100); else print "0";}'`), - BarResource('CPU Usage', 'settings_motion_mode', `LANG=C top -bn1 | grep Cpu | sed 's/\\,/\\./g' | awk '{print $2}'`), - ] - }), - setup: (self) => self.hook(Mpris, label => { - const mpris = Mpris.getPlayer(''); - self.revealChild = (!mpris); - }), - }) - ], - }) - }); - } + } else return BarGroup({ + child: Box({ + children: [ + BarResource('RAM Usage', 'memory', `LANG=C free | awk '/^Mem/ {printf("%.2f\\n", ($3/$2) * 100)}'`, + 'bar-ram-circprog', 'bar-ram-txt', 'bar-ram-icon'), + Revealer({ + revealChild: true, + transition: 'slide_left', + transitionDuration: userOptions.animations.durationLarge, + child: Box({ + className: 'spacing-h-10 margin-left-10', + children: [ + BarResource('Swap Usage', 'swap_horiz', `LANG=C free | awk '/^Swap/ {if ($2 > 0) printf("%.2f\\n", ($3/$2) * 100); else print "0";}'`, + 'bar-swap-circprog', 'bar-swap-txt', 'bar-swap-icon'), + BarResource('CPU Usage', 'settings_motion_mode', `LANG=C top -bn1 | grep Cpu | sed 's/\\,/\\./g' | awk '{print $2}'`, + 'bar-cpu-circprog', 'bar-cpu-txt', 'bar-cpu-icon'), + ] + }), + setup: (self) => self.hook(Mpris, label => { + const mpris = Mpris.getPlayer(''); + self.revealChild = (!mpris); + }), + }) + ], + }) + }); } return EventBox({ onScrollUp: (self) => switchToRelativeWorkspace(self, -1), diff --git a/.config/ags/modules/bar/normal/system.js b/.config/ags/modules/bar/normal/system.js index d7b0d9090..50ece2995 100644 --- a/.config/ags/modules/bar/normal/system.js +++ b/.config/ags/modules/bar/normal/system.js @@ -30,21 +30,21 @@ const BatBatteryProgress = () => { const BarClock = () => Widget.Box({ vpack: 'center', - className: 'spacing-h-4 txt-onSurfaceVariant bar-clock-box', + className: 'spacing-h-4 bar-clock-box', children: [ Widget.Label({ - className: 'bar-clock', + className: 'bar-time', label: GLib.DateTime.new_now_local().format(userOptions.time.format), setup: (self) => self.poll(userOptions.time.interval, label => { label.label = GLib.DateTime.new_now_local().format(userOptions.time.format); }), }), Widget.Label({ - className: 'txt-norm', + className: 'txt-norm txt-onLayer1', label: '•', }), Widget.Label({ - className: 'txt-smallie', + className: 'txt-smallie bar-date', label: GLib.DateTime.new_now_local().format(userOptions.time.dateFormatLong), setup: (self) => self.poll(userOptions.time.dateInterval, (label) => { label.label = GLib.DateTime.new_now_local().format(userOptions.time.dateFormatLong); diff --git a/.config/ags/scss/_bar.scss b/.config/ags/scss/_bar.scss index e209a4579..8f3e42443 100644 --- a/.config/ags/scss/_bar.scss +++ b/.config/ags/scss/_bar.scss @@ -1,12 +1,8 @@ // Made to be pixel-perfect with 11pt font size // 1rem = 11pt = 14.6666666667px - -$black: black; -$white: white; $bar_ws_width: 1.774rem; $bar_ws_width_focus: 0.614rem; $bar_ws_width_focus_active: 2.045rem; -$bar_subgroup_bg: $surfaceVariant; @mixin bar-group-rounding { @include small-rounding; @@ -17,12 +13,12 @@ $bar_subgroup_bg: $surfaceVariant; } .bar-bg { - background-color: $t_background; + background-color: $layer0; min-height: 2.727rem; } .bar-bg-focus { - background-color: $t_background; + background-color: $layer0; min-height: 1.364rem; } @@ -39,7 +35,7 @@ $bar_subgroup_bg: $surfaceVariant; } .bar-group { - background-color: $l_l_t_surfaceVariant; + background-color: $layer1; } .bar-group-pad { @@ -88,70 +84,57 @@ $bar_subgroup_bg: $surfaceVariant; border-bottom-right-radius: 1.364rem; } +.bar-sidemodule { + min-width: 26rem; +} + .bar-ws-width { min-width: 18.341rem; } .bar-ws { min-width: $bar_ws_width; - color: mix($onBackground, $background, 40%); - - @if $darkmode ==true { - color: mix($onBackground, $background, 45%); - } + color: $workspaceOnLayer1Inactive; } .bar-ws-active { - background-color: $secondaryContainer; - color: $onSecondaryContainer; + background-color: $workspaceSecondaryContainer; + color: $workspaceOnSecondaryContainer; } .bar-ws-occupied { - background-color: $bar_subgroup_bg; - color: $onSurfaceVariant; + background-color: $layer2; + color: $workspaceOnSurfaceVariant; } // Focus is the bar mode name, not the workspace state! .bar-ws-focus { - background-color: $bar_subgroup_bg; + background-color: $layer2; min-width: $bar_ws_width_focus; } .bar-ws-focus-active { min-width: $bar_ws_width_focus_active; - background-color: $onBackground; + background-color: $layer2; } .bar-ws-focus-occupied { - background-color: mix($onBackground, $background, 40%); - - @if $darkmode ==true { - background-color: mix($onBackground, $background, 45%); - } -} - -.bar-separator { - @include full-rounding; - min-width: 0.341rem; - min-height: 0.341rem; - background-color: mix($t_surface, $t_onSurface, 90%); - margin: 0rem 0.341rem; + background-color: $layer2; } .bar-clock-box { margin: 0rem 0.682rem; } -.bar-clock { +.bar-time { @include titlefont; font-size: 1.2727rem; + color: $timeOnLayer1; } .bar-date { - @include titlefont; - font-size: 1rem; - color: $onBackground; + color: $dateOnLayer1; } .bar-batt { @@ -164,20 +147,6 @@ $bar_subgroup_bg: $surfaceVariant; color: $onSecondaryContainer; } -.bar-sidemodule { - min-width: 26rem; -} - -.bar-batt-low { - background-color: $error; - color: $errorContainer; -} - -.bar-batt-full { - // background-color: $successContainer; - // color: $onSuccessContainer; -} - .bar-batt-circprog { @include fluent_decel_long; min-width: 0.068rem; // line width @@ -192,9 +161,79 @@ $bar_subgroup_bg: $surfaceVariant; color: $errorContainer; } -.bar-batt-circprog-full { - // background-color: $successContainer; - // color: $onSuccessContainer; + +.bar-batt-low { + background-color: $error; + color: $errorContainer; +} + +.bar-ram-icon { + @include full-rounding; + @include element_decel; + min-height: 1.77rem; + min-width: 1.77rem; + border-radius: 10rem; + background-color: $ramSecondaryContainer; + color: $ramOnSecondaryContainer; +} + +.bar-ram-circprog { + @include fluent_decel_long; + min-width: 0.068rem; // line width + min-height: 1.636rem; + padding: 0rem; + background-color: $ramSecondaryContainer; + color: $ramOnSecondaryContainer; +} + +.bar-ram-txt { + color: $ramOnLayer1; +} + +.bar-swap-icon { + @include full-rounding; + @include element_decel; + min-height: 1.77rem; + min-width: 1.77rem; + border-radius: 10rem; + background-color: $swapSecondaryContainer; + color: $swapOnSecondaryContainer; +} + +.bar-swap-circprog { + @include fluent_decel_long; + min-width: 0.068rem; // line width + min-height: 1.636rem; + padding: 0rem; + background-color: $swapSecondaryContainer; + color: $swapOnSecondaryContainer; +} + +.bar-swap-txt { + color: $swapOnLayer1; +} + +.bar-cpu-icon { + @include full-rounding; + @include element_decel; + min-height: 1.77rem; + min-width: 1.77rem; + border-radius: 10rem; + background-color: $cpuSecondaryContainer; + color: $cpuOnSecondaryContainer; +} + +.bar-cpu-circprog { + @include fluent_decel_long; + min-width: 0.068rem; // line width + min-height: 1.636rem; + padding: 0rem; + background-color: $cpuSecondaryContainer; + color: $cpuOnSecondaryContainer; +} + +.bar-cpu-txt { + color: $cpuOnLayer1; } .bar-music-playstate { @@ -202,8 +241,8 @@ $bar_subgroup_bg: $surfaceVariant; min-height: 1.77rem; min-width: 1.77rem; border-radius: 10rem; - background-color: $secondaryContainer; - color: $onSecondaryContainer; + background-color: $musicSecondaryContainer; + color: $musicOnSecondaryContainer; } .bar-music-circprog { @@ -211,16 +250,16 @@ $bar_subgroup_bg: $surfaceVariant; min-width: 0.068rem; // line width min-height: 1.636rem; padding: 0rem; - background-color: $secondaryContainer; - color: $onSecondaryContainer; + background-color: $musicSecondaryContainer; + color: $musicOnSecondaryContainer; } .bar-music-playstate-playing { min-height: 1.77rem; min-width: 1.77rem; border-radius: 10rem; - background-color: $secondaryContainer; - color: $onSecondaryContainer; + background-color: $musicSecondaryContainer; + color: $musicOnSecondaryContainer; } .bar-music-playstate-txt { @@ -228,6 +267,10 @@ $bar_subgroup_bg: $surfaceVariant; @include icon-material; } +.bar-music-txt { + color: $musicOnLayer1; +} + .bar-music-cover { background-position: center; background-repeat: no-repeat; @@ -240,11 +283,6 @@ $bar_subgroup_bg: $surfaceVariant; min-width: 34.091rem; } -.bar-music-extended-ctl-bg { - border-radius: 1.364rem; - background-color: rgba(30, 30, 30, 0.6); -} - .bar-music-hide-false { @include menu_decel; transition-duration: 100ms; @@ -263,7 +301,7 @@ $bar_subgroup_bg: $surfaceVariant; } .corner { - background-color: $t_background; + background-color: $layer0; @include large-rounding; } @@ -275,7 +313,7 @@ $bar_subgroup_bg: $surfaceVariant; .bar-topdesc { margin-top: -0.136rem; margin-bottom: -0.341rem; - color: $subtext; + color: $windowtitleOnLayer1Inactive; } .bar-space-button { @@ -287,15 +325,6 @@ $bar_subgroup_bg: $surfaceVariant; padding: 0rem 0.682rem; } -.bar-space-button:hover>box:first-child, -.bar-space-button:focus>box:first-child { - background-color: $hovercolor; -} - -.bar-space-button:active>box:first-child { - background-color: $activecolor; -} - .bar-space-button-leftmost { box { margin: 0rem 0.682rem; @@ -327,12 +356,8 @@ $bar_subgroup_bg: $surfaceVariant; padding: 0rem 0.614rem; } -.bar-statusicons-hover { - background-color: mix($t_background, $t_onBackground, 90%); -} - .bar-statusicons-active { - background-color: mix($t_background, $t_onBackground, 80%); + background-color: $layer0Active; } .bar-util-btn { @@ -340,16 +365,17 @@ $bar_subgroup_bg: $surfaceVariant; @include element_decel; min-height: 1.77rem; min-width: 1.77rem; - background-color: $bar_subgroup_bg; + background-color: $layer2; + color: $onLayer2; } .bar-util-btn:hover, .bar-util-btn:focus { - background-color: mix($bar_subgroup_bg, $onSurfaceVariant, 90%); + background-color: $layer2Hover; } .bar-util-btn:active { - background-color: mix($bar_subgroup_bg, $onSurfaceVariant, 80%); + background-color: $layer2Active; } .bar-bluetooth-device { @@ -358,7 +384,6 @@ $bar_subgroup_bg: $surfaceVariant; min-height: 1.032rem; min-width: 1.032rem; font-size: 1.032rem; - background-color: $surface; - color: $onSurface; + color: $onLayer0; padding: 0.205rem 0.341rem; } \ No newline at end of file diff --git a/.config/ags/scss/_colors.scss b/.config/ags/scss/_colors.scss index 3db57ab7c..2286d526d 100644 --- a/.config/ags/scss/_colors.scss +++ b/.config/ags/scss/_colors.scss @@ -116,6 +116,8 @@ $hovercolor: mix($t_surface, $t_onSurface, 50%); $activecolor: mix($t_surface, $t_onSurface, 30%); $subtext: mix($onBackground, $background, 70%); $actiontext: mix($onBackground, $background, 85%); +$black: black; +$white: white; // Terminal colors $termbg: mix($t_surfaceVariant, $t_onSurfaceVariant, 80%); @@ -127,4 +129,40 @@ $term3: $onPrimaryContainer; $term4: $onPrimaryContainer; $term5: $onSecondaryContainer; $term6: $primary; -$term7: $onSurfaceVariant; \ No newline at end of file +$term7: $onSurfaceVariant; + +/// Color mappings for more chaotic, dynamic colors like the average rice /// +// General +$layer0: $t_background; +$onLayer0: $onBackground; +$layer0Active: mix($t_background, $t_onBackground, 80%); +$layer1: $surface; +$onLayer1Inactive: mix($onBackground, $background, 45%); +$onLayer1: $onSurfaceVariant; +$layer2: $surfaceVariant; +$onLayer2: $onSurfaceVariant; +$layer2Hover: mix($layer2, $onSurfaceVariant, 90%); +$layer2Active: mix($layer2, $onSurfaceVariant, 80%); +// Elements +// For now they just use Material colors. I'll make a proper theme later +$windowtitleOnLayer1Inactive: $onLayer1; +$timeOnLayer1: $onLayer1; +$dateOnLayer1: $onLayer1; +$ramOnLayer1: $onLayer1; +$ramSecondaryContainer: $secondaryContainer; +$ramOnSecondaryContainer: $onSecondaryContainer; +$swapOnLayer1: $onLayer1; +$swapSecondaryContainer: $secondaryContainer; +$swapOnSecondaryContainer: $onSecondaryContainer; +$cpuOnLayer1: $onLayer1; +$cpuSecondaryContainer: $secondaryContainer; +$cpuOnSecondaryContainer: $onSecondaryContainer; +$musicOnLayer1: $onLayer1; +$musicSecondaryContainer: $secondaryContainer; +$musicOnSecondaryContainer: $onSecondaryContainer; + +$workspaceOnLayer1Inactive: $onLayer1Inactive; +$workspaceSecondaryContainer: $secondaryContainer; +$workspaceOnSecondaryContainer: $onSecondaryContainer; +$workspaceOnSurfaceVariant: $onSurfaceVariant; + diff --git a/.config/ags/scss/_lib_classes.scss b/.config/ags/scss/_lib_classes.scss index 988dee7a2..69262e7a8 100644 --- a/.config/ags/scss/_lib_classes.scss +++ b/.config/ags/scss/_lib_classes.scss @@ -50,6 +50,10 @@ color: $onSurfaceVariant; } +.txt-onLayer1 { + color: $onLayer1; +} + .txt-shadow { text-shadow: 1px 2px 8px rgba(0, 0, 0, 0.69); margin: 10px; diff --git a/.config/ags/services/messages.js b/.config/ags/services/messages.js index 816813e80..ad84bad8f 100644 --- a/.config/ags/services/messages.js +++ b/.config/ags/services/messages.js @@ -13,7 +13,7 @@ const FIRST_RUN_FILE_CONTENT = "Just a file to confirm that you have been greete const APP_NAME = "illogical-impulse"; const FIRST_RUN_NOTIF_TITLE = "Welcome!"; const FIRST_RUN_NOTIF_BODY = `Looks like this is your first run. For a list of keybinds, hit Super + /.`; - + export async function firstRunWelcome() { if (!fileExists(FIRST_RUN_PATH)) { Utils.writeFile(FIRST_RUN_FILE_CONTENT, FIRST_RUN_PATH) diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index 085f37ef4..b23d80ed0 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -3,7 +3,7 @@ const userConfigOptions = { // For every option, see ~/.config/ags/modules/.configuration/user_options.js (vscode users ctrl+click this file://./modules/.configuration/user_options.js) // Options listed in this file will override the default ones in the above file // Here's an example - 'keybinds': { + 'keybinds': { 'sidebar': { 'pin': "Ctrl+p", 'nextTab': "Ctrl+Page_Down", From 63c41123a3aec1f9b60ae87ba24b66b68711779f Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 14 Mar 2024 19:48:57 +0700 Subject: [PATCH 120/517] light >badapple (#330) --- .../scripts/color_generation/applycolor.sh | 35 ++++++++++--------- .../specials/_material_badapple-l.scss | 29 +++++++++++++++ .../specials/_material_badapple.scss | 1 - 3 files changed, 47 insertions(+), 18 deletions(-) create mode 100644 .config/ags/scripts/color_generation/specials/_material_badapple-l.scss diff --git a/.config/ags/scripts/color_generation/applycolor.sh b/.config/ags/scripts/color_generation/applycolor.sh index b7656bdd8..4e816c40c 100755 --- a/.config/ags/scripts/color_generation/applycolor.sh +++ b/.config/ags/scripts/color_generation/applycolor.sh @@ -18,23 +18,6 @@ colorvalues=() # wallpath_png=$(echo "$wallpath_png" | sed 's/\//\\\//g') # wallpath_png=$(sed 's/\//\\\\\//g' <<< "$wallpath_png") -if [[ "$1" = "--bad-apple" ]]; then - cp scripts/color_generation/specials/_material_badapple.scss scss/_material.scss - colornames=$(cat scripts/color_generation/specials/_material_badapple.scss | cut -d: -f1) - colorstrings=$(cat scripts/color_generation/specials/_material_badapple.scss | cut -d: -f2 | cut -d ' ' -f2 | cut -d ";" -f1) - IFS=$'\n' - # filearr=( $filelist ) # Get colors - colorlist=( $colornames ) # Array of color names - colorvalues=( $colorstrings ) # Array of color values -else - colornames=$(cat scss/_material.scss | cut -d: -f1) - colorstrings=$(cat scss/_material.scss | cut -d: -f2 | cut -d ' ' -f2 | cut -d ";" -f1) - IFS=$'\n' - # filearr=( $filelist ) # Get colors - colorlist=( $colornames ) # Array of color names - colorvalues=( $colorstrings ) # Array of color values -fi - transparentize() { local hex="$1" local alpha="$2" @@ -165,6 +148,24 @@ apply_ags() { ags run-js "App.resetCss(); App.applyCss('${HOME}/.cache/ags/user/generated/style.css');" } +if [[ "$1" = "--bad-apple" ]]; then + lightdark=$(get_light_dark) + cp scripts/color_generation/specials/_material_badapple"${lightdark}".scss scss/_material.scss + colornames=$(cat scripts/color_generation/specials/_material_badapple.scss | cut -d: -f1) + colorstrings=$(cat scripts/color_generation/specials/_material_badapple.scss | cut -d: -f2 | cut -d ' ' -f2 | cut -d ";" -f1) + IFS=$'\n' + # filearr=( $filelist ) # Get colors + colorlist=( $colornames ) # Array of color names + colorvalues=( $colorstrings ) # Array of color values +else + colornames=$(cat scss/_material.scss | cut -d: -f1) + colorstrings=$(cat scss/_material.scss | cut -d: -f2 | cut -d ' ' -f2 | cut -d ";" -f1) + IFS=$'\n' + # filearr=( $filelist ) # Get colors + colorlist=( $colornames ) # Array of color names + colorvalues=( $colorstrings ) # Array of color values +fi + apply_ags & apply_hyprland & apply_hyprlock & diff --git a/.config/ags/scripts/color_generation/specials/_material_badapple-l.scss b/.config/ags/scripts/color_generation/specials/_material_badapple-l.scss new file mode 100644 index 000000000..12c047b0f --- /dev/null +++ b/.config/ags/scripts/color_generation/specials/_material_badapple-l.scss @@ -0,0 +1,29 @@ +$darkmode: false; +$primary: #000000; +$onPrimary: #FFFFFF ; +$primaryContainer: #d4d4d4; +$onPrimaryContainer: #000000; +$secondary: #000000; +$onSecondary: #FFFFFF ; +$secondaryContainer: #bebebe; +$onSecondaryContainer: #000000; +$tertiary: #000000; +$onTertiary: #FFFFFF ; +$tertiaryContainer: #FFFFFF ; +$onTertiaryContainer: #000000; +$error: #000000; +$onError: #FFFFFF ; +$errorContainer: #FFFFFF ; +$onErrorContainer: #000000; +$colorbarbg: #FFFFFF ; +$background: #FFFFFF ; +$onBackground: #000000; +$surface: #f0f0f0; +$onSurface: #000000; +$surfaceVariant: #dddddd; +$onSurfaceVariant: #000000; +$outline: #525252; +$shadow: #000000 ; +$inverseSurface: #000000; +$inverseOnSurface: #FFFFFF; +$inversePrimary: #000000; diff --git a/.config/ags/scripts/color_generation/specials/_material_badapple.scss b/.config/ags/scripts/color_generation/specials/_material_badapple.scss index cfab8e9f3..24dd73ff5 100644 --- a/.config/ags/scripts/color_generation/specials/_material_badapple.scss +++ b/.config/ags/scripts/color_generation/specials/_material_badapple.scss @@ -27,4 +27,3 @@ $shadow: #000000; $inverseSurface: #e2e2e2; $inverseOnSurface: #000000; $inversePrimary: #e2e2e2; - From d1ec61193ec25375234f9fff3764d5fcb5a555ee Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 14 Mar 2024 19:51:59 +0700 Subject: [PATCH 121/517] oops forgot to apply light bad apple to other stuff #330 --- .config/ags/scripts/color_generation/applycolor.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/ags/scripts/color_generation/applycolor.sh b/.config/ags/scripts/color_generation/applycolor.sh index 4e816c40c..1317cd0e6 100755 --- a/.config/ags/scripts/color_generation/applycolor.sh +++ b/.config/ags/scripts/color_generation/applycolor.sh @@ -151,8 +151,8 @@ apply_ags() { if [[ "$1" = "--bad-apple" ]]; then lightdark=$(get_light_dark) cp scripts/color_generation/specials/_material_badapple"${lightdark}".scss scss/_material.scss - colornames=$(cat scripts/color_generation/specials/_material_badapple.scss | cut -d: -f1) - colorstrings=$(cat scripts/color_generation/specials/_material_badapple.scss | cut -d: -f2 | cut -d ' ' -f2 | cut -d ";" -f1) + colornames=$(cat scripts/color_generation/specials/_material_badapple"${lightdark}".scss | cut -d: -f1) + colorstrings=$(cat scripts/color_generation/specials/_material_badapple"${lightdark}".scss | cut -d: -f2 | cut -d ' ' -f2 | cut -d ";" -f1) IFS=$'\n' # filearr=( $filelist ) # Get colors colorlist=( $colornames ) # Array of color names From 5fc36cdc018cd62efeb6f37f77472cb028ec1298 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 14 Mar 2024 20:00:22 +0700 Subject: [PATCH 122/517] fix tray (#329) --- .config/ags/modules/bar/normal/spaceright.js | 65 ++++++++++---------- .config/ags/modules/bar/normal/tray.js | 4 +- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/.config/ags/modules/bar/normal/spaceright.js b/.config/ags/modules/bar/normal/spaceright.js index 8bca0103f..ecc928576 100644 --- a/.config/ags/modules/bar/normal/spaceright.js +++ b/.config/ags/modules/bar/normal/spaceright.js @@ -48,41 +48,44 @@ export default () => { children: [ Widget.Box({ hexpand: true, }), barTray, - separatorDot, - barStatusIcons, + Widget.EventBox({ + onScrollUp: () => { + if (!Audio.speaker) return; + if (Audio.speaker.volume <= 0.09) Audio.speaker.volume += 0.01; + else Audio.speaker.volume += 0.03; + Indicator.popup(1); + }, + onScrollDown: () => { + if (!Audio.speaker) return; + if (Audio.speaker.volume <= 0.09) Audio.speaker.volume -= 0.01; + else Audio.speaker.volume -= 0.03; + Indicator.popup(1); + }, + onHover: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', true) }, + onHoverLost: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', false) }, + onPrimaryClick: () => App.toggleWindow('sideright'), + onSecondaryClick: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print), + onMiddleClick: () => execAsync('playerctl play-pause').catch(print), + setup: (self) => self.on('button-press-event', (self, event) => { + if (event.get_button()[1] === 8) + execAsync('playerctl previous').catch(print) + }), + child: Widget.Box({ + children: [ + separatorDot, + barStatusIcons, + ], + }), + }), ], }), ] }); - return Widget.EventBox({ - onScrollUp: () => { - if (!Audio.speaker) return; - if (Audio.speaker.volume <= 0.09) Audio.speaker.volume += 0.01; - else Audio.speaker.volume += 0.03; - Indicator.popup(1); - }, - onScrollDown: () => { - if (!Audio.speaker) return; - if (Audio.speaker.volume <= 0.09) Audio.speaker.volume -= 0.01; - else Audio.speaker.volume -= 0.03; - Indicator.popup(1); - }, - onHover: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', true) }, - onHoverLost: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', false) }, - onPrimaryClick: () => App.toggleWindow('sideright'), - onSecondaryClick: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print), - onMiddleClick: () => execAsync('playerctl play-pause').catch(print), - setup: (self) => self.on('button-press-event', (self, event) => { - if (event.get_button()[1] === 8) - execAsync('playerctl previous').catch(print) - }), - child: Widget.Box({ - homogeneous: false, - children: [ - actualContent, - Widget.Box({ className: 'bar-corner-spacing' }), - ] - }) + return Widget.Box({ + children: [ + actualContent, + Widget.Box({ className: 'bar-corner-spacing' }), + ] }); } \ No newline at end of file diff --git a/.config/ags/modules/bar/normal/tray.js b/.config/ags/modules/bar/normal/tray.js index 5ebbbd275..6d55549d2 100644 --- a/.config/ags/modules/bar/normal/tray.js +++ b/.config/ags/modules/bar/normal/tray.js @@ -13,8 +13,8 @@ const SysTrayItem = (item) => Button({ setup: (self) => self .hook(item, (self) => self.tooltipMarkup = item['tooltip-markup']) , - onClicked: btn => item.menu.popup_at_widget(btn, Gravity.SOUTH, Gravity.NORTH, null), - onSecondaryClick: btn => item.menu.popup_at_widget(btn, Gravity.SOUTH, Gravity.NORTH, null), + onPrimaryClick: (_, event) => item.activate(event), + onSecondaryClick: (btn, event) => item.menu.popup_at_widget(btn, Gravity.SOUTH, Gravity.NORTH, null), }); export const Tray = (props = {}) => { From 3e0938e5973923c77604ad718063f4b51ce35447 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 14 Mar 2024 20:00:38 +0700 Subject: [PATCH 123/517] remove unecessary comments --- .config/ags/scripts/color_generation/applycolor.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.config/ags/scripts/color_generation/applycolor.sh b/.config/ags/scripts/color_generation/applycolor.sh index 1317cd0e6..7fab4e184 100755 --- a/.config/ags/scripts/color_generation/applycolor.sh +++ b/.config/ags/scripts/color_generation/applycolor.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash -term_alpha=100 #Set this to < 100 make all your terminals transparent -# sleep 0 # idk i wanted some delay or colors dont get applied properly +term_alpha=100 # Set this to < 100 make all your terminals transparent if [ ! -d "$HOME"/.cache/ags/user/generated ]; then mkdir -p "$HOME"/.cache/ags/user/generated fi @@ -154,14 +153,12 @@ if [[ "$1" = "--bad-apple" ]]; then colornames=$(cat scripts/color_generation/specials/_material_badapple"${lightdark}".scss | cut -d: -f1) colorstrings=$(cat scripts/color_generation/specials/_material_badapple"${lightdark}".scss | cut -d: -f2 | cut -d ' ' -f2 | cut -d ";" -f1) IFS=$'\n' - # filearr=( $filelist ) # Get colors colorlist=( $colornames ) # Array of color names colorvalues=( $colorstrings ) # Array of color values else colornames=$(cat scss/_material.scss | cut -d: -f1) colorstrings=$(cat scss/_material.scss | cut -d: -f2 | cut -d ' ' -f2 | cut -d ";" -f1) IFS=$'\n' - # filearr=( $filelist ) # Get colors colorlist=( $colornames ) # Array of color names colorvalues=( $colorstrings ) # Array of color values fi From 8afbe57aad4eb068750bfe2f3d4a23f095a319b0 Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 14 Mar 2024 22:50:07 +0800 Subject: [PATCH 124/517] Tip for (neo)vim users editing user_options.js --- .config/ags/user_options.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index b23d80ed0..41bede1ac 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -1,6 +1,8 @@ const userConfigOptions = { - // For every option, see ~/.config/ags/modules/.configuration/user_options.js (vscode users ctrl+click this file://./modules/.configuration/user_options.js) + // For every option, see ~/.config/ags/modules/.configuration/user_options.js + // (tip4vscode: `ctrl+click` this: file://./modules/.configuration/user_options.js) + // (tip4vim: `:vsp` to split window, move cursor to this path, press `gf`. `Ctrl-w` twice to switch between) // Options listed in this file will override the default ones in the above file // Here's an example 'keybinds': { @@ -12,4 +14,4 @@ const userConfigOptions = { }, } -export default userConfigOptions; \ No newline at end of file +export default userConfigOptions; From d6efa18bd692801ba340d60e939d94b4bc3c810f Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 14 Mar 2024 23:45:17 +0700 Subject: [PATCH 125/517] booru widget: no more lag --- .config/ags/modules/sideleft/apis/booru.js | 158 ++++++++++++--------- .config/ags/scss/_sidebars.scss | 16 ++- 2 files changed, 102 insertions(+), 72 deletions(-) diff --git a/.config/ags/modules/sideleft/apis/booru.js b/.config/ags/modules/sideleft/apis/booru.js index a4929928c..722462c0b 100644 --- a/.config/ags/modules/sideleft/apis/booru.js +++ b/.config/ags/modules/sideleft/apis/booru.js @@ -117,36 +117,91 @@ const BooruPage = (taglist) => { onClicked: action, setup: setupCursorHover, }) - const PreviewImage = (data) => { - return Overlay({ - child: Box({ - className: 'sidebar-booru-image', - css: `background-image: url('${data.preview_url}');`, - // setup: (self) => { - // Utils.timeout(1000, () => { - // self.css = `background-image: url('${data.preview_url}');`; - // }) - // } - }), - overlays: [ - Box({ - vpack: 'start', - className: 'sidebar-booru-image-actions spacing-h-3', - children: [ - Box({ hexpand: true }), - ImageAction({ - name: 'Go to file url', - icon: 'file_open', - action: () => execAsync(['xdg-open', `${data.file_url}`]).catch(print), - }), - ImageAction({ - name: 'Go to source', - icon: 'open_in_new', - action: () => execAsync(['xdg-open', `${data.source}`]).catch(print), - }), - ] - }) + const PreviewImage = (data, delay = 0) => { + const imageArea = Widget.DrawingArea({ + className: 'sidebar-booru-image-drawingarea', + }); + const imageBox = Box({ + className: 'sidebar-booru-image', + // css: `background-image: url('${data.preview_url}');`, + attribute: { + 'update': (self, data, force = false) => { + const imagePath = `${USER_CACHE_DIR}/ags/media/waifus/${data.md5}.${data.file_ext}`; + const widgetStyleContext = imageArea.get_style_context(); + const widgetWidth = widgetStyleContext.get_property('min-width', Gtk.StateFlags.NORMAL); + const widgetHeight = widgetStyleContext.get_property('min-height', Gtk.StateFlags.NORMAL); + imageArea.set_size_request(widgetWidth, widgetHeight); + const showImage = () => { + const imageDimensionsStr = exec(`identify -format {\\"w\\":%w,\\"h\\":%h} '${imagePath}'`) + const imageDimensionsJson = JSON.parse(imageDimensionsStr); + let imageWidth = imageDimensionsJson.w; + let imageHeight = imageDimensionsJson.h; + + // Fill + const scale = imageWidth / imageHeight; + if (imageWidth > imageHeight) { + imageWidth = widgetHeight * scale; + imageHeight = widgetHeight; + } else { + imageHeight = widgetWidth / scale; + imageWidth = widgetWidth; + } + + // const pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(imagePath, widgetWidth, widgetHeight); + const pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(imagePath, imageWidth, imageHeight, false); + imageArea.connect("draw", (widget, cr) => { + const borderRadius = widget.get_style_context().get_property('border-radius', Gtk.StateFlags.NORMAL); + + // Draw a rounded rectangle + cr.arc(borderRadius, borderRadius, borderRadius, Math.PI, 1.5 * Math.PI); + cr.arc(widgetWidth - borderRadius, borderRadius, borderRadius, 1.5 * Math.PI, 2 * Math.PI); + cr.arc(widgetWidth - borderRadius, widgetHeight - borderRadius, borderRadius, 0, 0.5 * Math.PI); + cr.arc(borderRadius, widgetHeight - borderRadius, borderRadius, 0.5 * Math.PI, Math.PI); + cr.closePath(); + cr.clip(); + + // Paint image as bg + Gdk.cairo_set_source_pixbuf(cr, pixbuf, (widgetWidth - imageWidth) / 2, (widgetHeight - imageHeight) / 2); + cr.paint(); + }); + self.queue_draw(); + } + // Show + // const downloadCommand = `wget -O '${imagePath}' '${data.preview_url}'`; + const downloadCommand = `curl -L -o '${imagePath}' '${data.preview_url}'`; + // console.log(downloadCommand) + if (!force && fileExists(imagePath)) showImage(); + else Utils.timeout(delay, () => Utils.execAsync(['bash', '-c', downloadCommand]) + .then(showImage) + .catch(print) + ); + }, + }, + child: imageArea, + setup: (self) => { + Utils.timeout(1000, () => self.attribute.update(self, data)); + } + }); + const imageActions = Box({ + vpack: 'start', + className: 'sidebar-booru-image-actions spacing-h-3', + children: [ + Box({ hexpand: true }), + ImageAction({ + name: 'Go to file url', + icon: 'file_open', + action: () => execAsync(['xdg-open', `${data.file_url}`]).catch(print), + }), + ImageAction({ + name: 'Go to source', + icon: 'open_in_new', + action: () => execAsync(['xdg-open', `${data.source}`]).catch(print), + }), ] + }); + return Overlay({ + child: imageBox, + overlays: [imageActions] }) } const colorIndicator = Box({ @@ -188,39 +243,9 @@ const BooruPage = (taglist) => { downloadIndicator, ] }); - const pageActions = Revealer({ - transition: 'crossfade', - revealChild: false, - child: Box({ - vertical: true, - children: [ - Box({ - className: 'sidebar-waifu-image-actions spacing-h-3', - children: [ - Box({ hexpand: true }), - ImageAction({ - name: 'Go to source', - icon: 'link', - action: () => execAsync(['xdg-open', `${thisPage.attribute.imageData.source}`]).catch(print), - }), - ImageAction({ - name: 'Hoard', - icon: 'save', - action: () => execAsync(['bash', '-c', `mkdir -p ~/Pictures/homework${thisPage.attribute.isNsfw ? '/🌶️' : ''} && cp ${thisPage.attribute.imagePath} ~/Pictures/homework${thisPage.attribute.isNsfw ? '/🌶️/' : ''}`]).catch(print), - }), - ImageAction({ - name: 'Open externally', - icon: 'open_in_new', - action: () => execAsync([IMAGE_VIEWER_APP, `${thisPage.attribute.imagePath}`]).catch(print), - }), - ] - }) - ], - }) - }) const pageImageGrid = Grid({ - columnHomogeneous: true, - rowHomogeneous: true, + // columnHomogeneous: true, + // rowHomogeneous: true, className: 'sidebar-waifu-image', // css: 'min-height: 90px;' }); @@ -248,9 +273,11 @@ const BooruPage = (taglist) => { // Add stuff for (let i = 0; i < imageRows; i++) { for (let j = 0; j < imageColumns; j++) { - if (i * imageColumns + j >= userOptions.sidebar.imageBooruCount) break; - // if (i * imageColumns + j >= data.length) break; - pageImageGrid.attach(PreviewImage(data[i * imageColumns + j]), j, i, 1, 1); + if (i * imageColumns + j >= Math.min(userOptions.sidebar.imageBooruCount, data.length)) break; + pageImageGrid.attach( + PreviewImage(data[i * imageColumns + j]), + j, i, 1, 1 + ); } } pageImageGrid.show_all(); @@ -259,9 +286,6 @@ const BooruPage = (taglist) => { Utils.timeout(IMAGE_REVEAL_DELAY, () => pageImageRevealer.revealChild = true ); - Utils.timeout(IMAGE_REVEAL_DELAY + pageImageRevealer.transitionDuration, - () => pageActions.revealChild = true - ); downloadIndicator.attribute.hide(); }, }, diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss index dad80e962..bd56dfccf 100644 --- a/.config/ags/scss/_sidebars.scss +++ b/.config/ags/scss/_sidebars.scss @@ -853,14 +853,20 @@ $waifu_image_overlay_transparency: 0.7; .sidebar-booru-image { @include small-rounding; margin: 0.273rem; - min-width: 12.818rem; - min-height: 12.818rem; - background-size: cover; - background-repeat: no-repeat; - background-position: center; + min-width: 11.932rem; + min-height: 11.932rem; + // background-color: rgba(100, 200, 0, 0.3); +} + +.sidebar-booru-image-drawingarea { + // background-color: rgba(200, 100, 0, 0.3); + @include small-rounding; + min-width: 12.273rem; + min-height: 12.273rem; } .sidebar-booru-image-actions { + // background-color: rgba(100, 100, 0, 0.3); @include element_decel; margin: 0.545rem; } \ No newline at end of file From 361984730457150cfd558ebb6ae6fd2c75456b1d Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 14 Mar 2024 23:51:21 +0700 Subject: [PATCH 126/517] ags: add tab scrolling --- .../modules/.commonwidgets/tabcontainer.js | 23 ++++++---- .config/ags/modules/sideleft/apiwidgets.js | 46 ++++++++++--------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/.config/ags/modules/.commonwidgets/tabcontainer.js b/.config/ags/modules/.commonwidgets/tabcontainer.js index 1719686ab..706f7dec9 100644 --- a/.config/ags/modules/.commonwidgets/tabcontainer.js +++ b/.config/ags/modules/.commonwidgets/tabcontainer.js @@ -1,11 +1,11 @@ import Variable from 'resource:///com/github/Aylur/ags/variable.js'; import Widget from 'resource:///com/github/Aylur/ags/widget.js'; -const { Box, Button, Label, Overlay, Stack } = Widget; +const { Box, Button, EventBox, Label, Overlay, Stack } = Widget; import { MaterialIcon } from './materialicon.js'; import { NavigationIndicator } from './cairo_navigationindicator.js'; import { setupCursorHover } from '../.widgetutils/cursorhover.js'; -export const TabContainer = ({ icons, names, children, className = '', setup = () => {}, ...rest }) => { +export const TabContainer = ({ icons, names, children, className = '', setup = () => { }, ...rest }) => { const shownIndex = Variable(0); let previousShownIndex = 0; const count = Math.min(icons.length, names.length, children.length); @@ -47,12 +47,19 @@ export const TabContainer = ({ icons, names, children, className = '', setup = ( })], }); const tabSection = Box({ - vertical: true, - hexpand: true, - children: [ - tabs, - tabIndicatorLine - ] + homogeneous: true, + children: [EventBox({ + onScrollUp: () => mainBox.prevTab(), + onScrollDown: () => mainBox.nextTab(), + child: Box({ + vertical: true, + hexpand: true, + children: [ + tabs, + tabIndicatorLine + ] + }) + })] }); const contentStack = Stack({ transition: 'slide_left_right', diff --git a/.config/ags/modules/sideleft/apiwidgets.js b/.config/ags/modules/sideleft/apiwidgets.js index b75b9ed9c..e90d867b4 100644 --- a/.config/ags/modules/sideleft/apiwidgets.js +++ b/.config/ags/modules/sideleft/apiwidgets.js @@ -198,27 +198,31 @@ function switchToTab(id) { currentApiId = id; } -const apiSwitcher = CenterBox({ - centerWidget: Box({ - className: 'sidebar-chat-apiswitcher spacing-h-5', - hpack: 'center', - children: APIS.map((api, id) => Button({ - child: api.tabIcon, - tooltipText: api.name, - setup: setupCursorHover, - onClicked: () => { - switchToTab(id); - } - })), - }), - endWidget: Button({ - hpack: 'end', - className: 'txt-subtext txt-norm icon-material', - label: 'lightbulb', - tooltipText: 'Use PageUp/PageDown to switch between API pages', - setup: setupCursorHoverInfo, - }), -}) +const apiSwitcher = EventBox({ + onScrollUp: () => apiWidgets.attribute.prevTab(), + onScrollDown: () => apiWidgets.attribute.nextTab(), + child: CenterBox({ + centerWidget: Box({ + className: 'sidebar-chat-apiswitcher spacing-h-5', + hpack: 'center', + children: APIS.map((api, id) => Button({ + child: api.tabIcon, + tooltipText: api.name, + setup: setupCursorHover, + onClicked: () => { + switchToTab(id); + } + })), + }), + endWidget: Button({ + hpack: 'end', + className: 'txt-subtext txt-norm icon-material', + label: 'lightbulb', + tooltipText: 'Use PageUp/PageDown to switch between API pages', + setup: setupCursorHoverInfo, + }), + }) +}); const apiWidgets = Widget.Box({ attribute: { From 6035d599b85c275edbe1b95e427c03b93b9ec464 Mon Sep 17 00:00:00 2001 From: clsty Date: Fri, 15 Mar 2024 07:29:36 +0800 Subject: [PATCH 127/517] Fix path. --- install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/install.sh b/install.sh index b948110ec..287a2b8fb 100755 --- a/install.sh +++ b/install.sh @@ -149,6 +149,7 @@ v mkdir -p "$HOME"/.{config,cache,local/{bin,share}} # For .config/* but not AGS, not Hyprland for i in $(find .config/ -mindepth 1 -maxdepth 1 ! -name 'ags' ! -name 'hypr' -exec basename {} \;); do + i=".config/$i" echo "[$0]: Found target: $i" if [ -d "$i" ];then v rsync -av --delete "$i/" "$HOME/$i/" elif [ -f "$i" ];then v rsync -av "$i" "$HOME/$i" From 9d18a57d3753693502612fdf26a0f35d18a17c9a Mon Sep 17 00:00:00 2001 From: "Celestial.y" Date: Fri, 15 Mar 2024 08:46:50 +0800 Subject: [PATCH 128/517] Update switchwall.sh --- .config/ags/scripts/color_generation/switchwall.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/scripts/color_generation/switchwall.sh b/.config/ags/scripts/color_generation/switchwall.sh index 1129ae02b..05a9fe54f 100755 --- a/.config/ags/scripts/color_generation/switchwall.sh +++ b/.config/ags/scripts/color_generation/switchwall.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash if [ "$1" == "--noswitch" ]; then - imgpath=$(swww query | awk -F 'image: ' '{print $2}') + imgpath=$(swww query | awk -F 'image: ' '{print $2}'| head -n 1) # imgpath=$(ags run-js 'wallpaper.get(0)') else # Select and set image (hyprland) From 01e60cd5f6e540c5c5a3299e5d9fb0600853aec1 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Fri, 15 Mar 2024 22:38:19 +0700 Subject: [PATCH 129/517] make terminal colors less saturated --- .config/ags/scripts/templates/terminal/sequences.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/scripts/templates/terminal/sequences.txt b/.config/ags/scripts/templates/terminal/sequences.txt index a48ca9d00..6e91959be 100644 --- a/.config/ags/scripts/templates/terminal/sequences.txt +++ b/.config/ags/scripts/templates/terminal/sequences.txt @@ -1 +1 @@ -]4;0;#$background #\]4;1;#$error #\]4;2;#$inversePrimary #\]4;3;#$onPrimaryContainer #\]4;4;#$onPrimaryContainer #\]4;5;#$onSecondaryContainer #\]4;6;#$primary #\]4;7;#$onSurfaceVariant #\]4;8;#$onSurfaceVariant #\]4;9;#$error #\]4;10;#$inversePrimary #\]4;11;#$onPrimaryContainer #\]4;12;#$onPrimaryContainer #\]4;13;#$onSecondaryContainer #\]4;14;#$primary #\]4;15;#$onSurfaceVariant #\]10;#$onSurfaceVariant #\]11;[$alpha]#$background #\]12;#$onSurfaceVariant #\]13;#$onSurfaceVariant #\]17;#$onSurfaceVariant #\]19;#$background #\]4;232;#$onSurfaceVariant #\]4;256;#$onSurfaceVariant #\]708;[$alpha]#$background #\ \ No newline at end of file +]4;0;#$background #\]4;1;#$error #\]4;2;#$secondaryContainer #\]4;3;#$onSecondaryContainer #\]4;4;#$onSecondaryContainer #\]4;5;#$onSecondaryContainer #\]4;6;#$onSecondaryContainer #\]4;7;#$onSurfaceVariant #\]4;8;#$onSurfaceVariant #\]4;9;#$error #\]4;10;#$secondaryContainer #\]4;11;#$onSecondaryContainer #\]4;12;#$onSecondaryContainer #\]4;13;#$onSecondaryContainer #\]4;14;#$onSecondaryContainer #\]4;15;#$onSurfaceVariant #\]10;#$onSurfaceVariant #\]11;[$alpha]#$background #\]12;#$onSurfaceVariant #\]13;#$onSurfaceVariant #\]17;#$onSurfaceVariant #\]19;#$background #\]4;232;#$onSurfaceVariant #\]4;256;#$onSurfaceVariant #\]708;[$alpha]#$background #\ \ No newline at end of file From 14770aa80c4f7b760fdb6b41afc09e794d0c734b Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Fri, 15 Mar 2024 22:56:14 +0700 Subject: [PATCH 130/517] update bar styles --- .config/ags/modules/bar/normal/system.js | 2 +- .config/ags/scss/_bar.scss | 48 +++++++++--------- .config/ags/scss/_colors.scss | 62 +++++++++++++++++++----- 3 files changed, 74 insertions(+), 38 deletions(-) diff --git a/.config/ags/modules/bar/normal/system.js b/.config/ags/modules/bar/normal/system.js index 50ece2995..166afcacb 100644 --- a/.config/ags/modules/bar/normal/system.js +++ b/.config/ags/modules/bar/normal/system.js @@ -97,7 +97,7 @@ const BarBattery = () => Box({ }), }), Label({ - className: 'txt-smallie txt-onSurfaceVariant', + className: 'txt-smallie bar-batt-txt', setup: (self) => self.hook(Battery, label => { label.label = `${Battery.percent}%`; }), diff --git a/.config/ags/scss/_bar.scss b/.config/ags/scss/_bar.scss index 8f3e42443..454bae7d0 100644 --- a/.config/ags/scss/_bar.scss +++ b/.config/ags/scss/_bar.scss @@ -98,13 +98,13 @@ $bar_ws_width_focus_active: 2.045rem; } .bar-ws-active { - background-color: $workspaceSecondaryContainer; - color: $workspaceOnSecondaryContainer; + background-color: $workspaceLayer3; + color: $workspaceOnLayer3; } .bar-ws-occupied { background-color: $layer2; - color: $workspaceOnSurfaceVariant; + color: $workspaceOnLayer2; } // Focus is the bar mode name, not the workspace state! @@ -143,8 +143,11 @@ $bar_ws_width_focus_active: 2.045rem; min-height: 1.77rem; min-width: 1.77rem; border-radius: 10rem; - background-color: $secondaryContainer; - color: $onSecondaryContainer; + color: $battOnLayer2; +} + +.bar-batt-txt { + color: $battOnLayer1; } .bar-batt-circprog { @@ -152,8 +155,8 @@ $bar_ws_width_focus_active: 2.045rem; min-width: 0.068rem; // line width min-height: 1.636rem; padding: 0rem; - background-color: $secondaryContainer; - color: $onSecondaryContainer; + background-color: $battLayer2; + color: $battOnLayer2; } .bar-batt-circprog-low { @@ -173,8 +176,7 @@ $bar_ws_width_focus_active: 2.045rem; min-height: 1.77rem; min-width: 1.77rem; border-radius: 10rem; - background-color: $ramSecondaryContainer; - color: $ramOnSecondaryContainer; + color: $ramOnLayer2; } .bar-ram-circprog { @@ -182,8 +184,8 @@ $bar_ws_width_focus_active: 2.045rem; min-width: 0.068rem; // line width min-height: 1.636rem; padding: 0rem; - background-color: $ramSecondaryContainer; - color: $ramOnSecondaryContainer; + background-color: $ramLayer2; + color: $ramOnLayer2; } .bar-ram-txt { @@ -196,8 +198,7 @@ $bar_ws_width_focus_active: 2.045rem; min-height: 1.77rem; min-width: 1.77rem; border-radius: 10rem; - background-color: $swapSecondaryContainer; - color: $swapOnSecondaryContainer; + color: $swapOnLayer2; } .bar-swap-circprog { @@ -205,8 +206,8 @@ $bar_ws_width_focus_active: 2.045rem; min-width: 0.068rem; // line width min-height: 1.636rem; padding: 0rem; - background-color: $swapSecondaryContainer; - color: $swapOnSecondaryContainer; + background-color: $swapLayer2; + color: $swapOnLayer2; } .bar-swap-txt { @@ -219,8 +220,7 @@ $bar_ws_width_focus_active: 2.045rem; min-height: 1.77rem; min-width: 1.77rem; border-radius: 10rem; - background-color: $cpuSecondaryContainer; - color: $cpuOnSecondaryContainer; + color: $cpuOnLayer2; } .bar-cpu-circprog { @@ -228,8 +228,8 @@ $bar_ws_width_focus_active: 2.045rem; min-width: 0.068rem; // line width min-height: 1.636rem; padding: 0rem; - background-color: $cpuSecondaryContainer; - color: $cpuOnSecondaryContainer; + background-color: $cpuLayer2; + color: $cpuOnLayer2; } .bar-cpu-txt { @@ -241,8 +241,7 @@ $bar_ws_width_focus_active: 2.045rem; min-height: 1.77rem; min-width: 1.77rem; border-radius: 10rem; - background-color: $musicSecondaryContainer; - color: $musicOnSecondaryContainer; + color: $musicOnLayer2; } .bar-music-circprog { @@ -250,16 +249,15 @@ $bar_ws_width_focus_active: 2.045rem; min-width: 0.068rem; // line width min-height: 1.636rem; padding: 0rem; - background-color: $musicSecondaryContainer; - color: $musicOnSecondaryContainer; + background-color: $musicLayer2; + color: $musicOnLayer2; } .bar-music-playstate-playing { min-height: 1.77rem; min-width: 1.77rem; border-radius: 10rem; - background-color: $musicSecondaryContainer; - color: $musicOnSecondaryContainer; + color: $musicOnLayer2; } .bar-music-playstate-txt { diff --git a/.config/ags/scss/_colors.scss b/.config/ags/scss/_colors.scss index 2286d526d..c26cbd271 100644 --- a/.config/ags/scss/_colors.scss +++ b/.config/ags/scss/_colors.scss @@ -144,25 +144,63 @@ $onLayer2: $onSurfaceVariant; $layer2Hover: mix($layer2, $onSurfaceVariant, 90%); $layer2Active: mix($layer2, $onSurfaceVariant, 80%); // Elements -// For now they just use Material colors. I'll make a proper theme later $windowtitleOnLayer1Inactive: $onLayer1; $timeOnLayer1: $onLayer1; $dateOnLayer1: $onLayer1; $ramOnLayer1: $onLayer1; -$ramSecondaryContainer: $secondaryContainer; -$ramOnSecondaryContainer: $onSecondaryContainer; +$ramLayer2: $secondaryContainer; +$ramOnLayer2: $onSecondaryContainer; $swapOnLayer1: $onLayer1; -$swapSecondaryContainer: $secondaryContainer; -$swapOnSecondaryContainer: $onSecondaryContainer; +$swapLayer2: $secondaryContainer; +$swapOnLayer2: $onSecondaryContainer; $cpuOnLayer1: $onLayer1; -$cpuSecondaryContainer: $secondaryContainer; -$cpuOnSecondaryContainer: $onSecondaryContainer; +$cpuLayer2: $secondaryContainer; +$cpuOnLayer2: $onSecondaryContainer; $musicOnLayer1: $onLayer1; -$musicSecondaryContainer: $secondaryContainer; -$musicOnSecondaryContainer: $onSecondaryContainer; +$musicLayer2: $secondaryContainer; +$musicOnLayer2: $onSecondaryContainer; +$battOnLayer1: $onLayer1; +$battLayer2: $secondaryContainer; +$battOnLayer2: $onSecondaryContainer; $workspaceOnLayer1Inactive: $onLayer1Inactive; -$workspaceSecondaryContainer: $secondaryContainer; -$workspaceOnSecondaryContainer: $onSecondaryContainer; -$workspaceOnSurfaceVariant: $onSurfaceVariant; +$workspaceLayer3: $secondaryContainer; +$workspaceOnLayer3: $onSecondaryContainer; +$workspaceOnLayer2: $onSurfaceVariant; + +///////////////////// test theme: amarena (kind of) ///////////////////////// +// $layer0: #0e1116; +// $onLayer0: #FFFFFF; +// $layer0Active: mix($t_background, $t_onBackground, 80%); +// $layer1: #171c22; +// $onLayer1Inactive: mix($onBackground, $background, 45%); +// $onLayer1: $onSurfaceVariant; +// $layer2: #252c35; +// $onLayer2: $onSurfaceVariant; +// $layer2Hover: mix($layer2, $onSurfaceVariant, 90%); +// $layer2Active: mix($layer2, $onSurfaceVariant, 80%); +// $layer3: #1C232A; +// $windowtitleOnLayer1Inactive: $onLayer1; +// $timeOnLayer1: #cc7691; +// $dateOnLayer1: #cc7691; +// $ramOnLayer1: #61adc0; +// $ramLayer2: $layer2; +// $ramOnLayer2: #61adc0; +// $swapOnLayer1: #b371ad; +// $swapLayer2: $layer2; +// $swapOnLayer2: #b371ad; +// $cpuOnLayer1: #7db17d; +// $cpuLayer2: $layer2; +// $cpuOnLayer2: #7db17d; +// $musicOnLayer1: #b64a6e; +// $musicLayer2: $layer2; +// $musicOnLayer2: #b64a6e; +// $battOnLayer1: #7db17d; +// $battLayer2: $layer2; +// $battOnLayer2: #7db17d; + +// $workspaceOnLayer1Inactive: $onLayer1Inactive; +// $workspaceLayer3: #33554f; +// $workspaceOnLayer3: #84EFDB; +// $workspaceOnLayer2: #84EFDB; From bc51fed29ba292096e4968b150eca4b7a255c3cb Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Fri, 15 Mar 2024 22:59:05 +0700 Subject: [PATCH 131/517] use battery icon (#325) --- .config/ags/modules/bar/normal/system.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/modules/bar/normal/system.js b/.config/ags/modules/bar/normal/system.js index 166afcacb..c7ec83dd6 100644 --- a/.config/ags/modules/bar/normal/system.js +++ b/.config/ags/modules/bar/normal/system.js @@ -108,7 +108,7 @@ const BarBattery = () => Box({ className: 'bar-batt', homogeneous: true, children: [ - MaterialIcon('settings_heart', 'small'), + MaterialIcon('battery_full', 'small'), ], setup: (self) => self.hook(Battery, box => { box.toggleClassName('bar-batt-low', Battery.percent <= userOptions.battery.low); From 073ea66731d6943f274d06573385e1a097f58afc Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 16 Mar 2024 10:44:44 +0700 Subject: [PATCH 132/517] zsh color support (#333) --- .zshrc | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .zshrc diff --git a/.zshrc b/.zshrc new file mode 100644 index 000000000..98b695df4 --- /dev/null +++ b/.zshrc @@ -0,0 +1,8 @@ +# Created by newuser for 5.9 +# Shortcuts +bindkey '^H' backward-kill-word +bindkey '^Z' undo + +if test -f ~/.cache/ags/user/generated/terminal/sequences.txt; then + cat ~/.cache/ags/user/generated/terminal/sequences.txt +fi From 5a2440af91b31c1b209764d220bb885f7c55206e Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 16 Mar 2024 11:28:04 +0700 Subject: [PATCH 133/517] Update options --- .config/ags/modules/.configuration/user_options.js | 2 +- .config/ags/user_options.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.config/ags/modules/.configuration/user_options.js b/.config/ags/modules/.configuration/user_options.js index e8a5bfa7d..94327c696 100644 --- a/.config/ags/modules/.configuration/user_options.js +++ b/.config/ags/modules/.configuration/user_options.js @@ -36,7 +36,7 @@ let configOptions = { }, 'sidebar': { 'imageColumns': 2, - 'imageBooruCount': 6, + 'imageBooruCount': 20, }, 'search': { 'engineBaseUrl': "https://www.google.com/search?q=", diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index 41bede1ac..7e729c283 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -1,9 +1,9 @@ const userConfigOptions = { // For every option, see ~/.config/ags/modules/.configuration/user_options.js - // (tip4vscode: `ctrl+click` this: file://./modules/.configuration/user_options.js) - // (tip4vim: `:vsp` to split window, move cursor to this path, press `gf`. `Ctrl-w` twice to switch between) - // Options listed in this file will override the default ones in the above file + // (vscode users ctrl+click this: file://./modules/.configuration/user_options.js) + // (vim users: `:vsp` to split window, move cursor to this path, press `gf`. `Ctrl-w` twice to switch between) + // options listed in this file will override the default ones in the above file // Here's an example 'keybinds': { 'sidebar': { From f002df7f6f0cf7fbbf0bac67e5b6c6b978578886 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 16 Mar 2024 11:28:39 +0700 Subject: [PATCH 134/517] better click area for right side of the bar --- .config/ags/modules/bar/normal/spaceright.js | 63 ++++++++++---------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/.config/ags/modules/bar/normal/spaceright.js b/.config/ags/modules/bar/normal/spaceright.js index ecc928576..51ca36bbf 100644 --- a/.config/ags/modules/bar/normal/spaceright.js +++ b/.config/ags/modules/bar/normal/spaceright.js @@ -38,6 +38,37 @@ export default () => { } }), }); + const SpaceRightDefaultClicks = (child) => Widget.EventBox({ + onScrollUp: () => { + if (!Audio.speaker) return; + if (Audio.speaker.volume <= 0.09) Audio.speaker.volume += 0.01; + else Audio.speaker.volume += 0.03; + Indicator.popup(1); + }, + onScrollDown: () => { + if (!Audio.speaker) return; + if (Audio.speaker.volume <= 0.09) Audio.speaker.volume -= 0.01; + else Audio.speaker.volume -= 0.03; + Indicator.popup(1); + }, + onHover: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', true) }, + onHoverLost: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', false) }, + onPrimaryClick: () => App.toggleWindow('sideright'), + onSecondaryClick: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print), + onMiddleClick: () => execAsync('playerctl play-pause').catch(print), + setup: (self) => self.on('button-press-event', (self, event) => { + if (event.get_button()[1] === 8) + execAsync('playerctl previous').catch(print) + }), + child: child, + }); + const emptyArea = SpaceRightDefaultClicks(Widget.Box({ hexpand: true, })), + const indicatorArea = SpaceRightDefaultClicks(Widget.Box({ + children: [ + separatorDot, + barStatusIcons + ], + })); const actualContent = Widget.Box({ hexpand: true, className: 'spacing-h-5 txt', @@ -46,37 +77,9 @@ export default () => { hexpand: true, className: 'spacing-h-5 txt', children: [ - Widget.Box({ hexpand: true, }), + emptyArea, barTray, - Widget.EventBox({ - onScrollUp: () => { - if (!Audio.speaker) return; - if (Audio.speaker.volume <= 0.09) Audio.speaker.volume += 0.01; - else Audio.speaker.volume += 0.03; - Indicator.popup(1); - }, - onScrollDown: () => { - if (!Audio.speaker) return; - if (Audio.speaker.volume <= 0.09) Audio.speaker.volume -= 0.01; - else Audio.speaker.volume -= 0.03; - Indicator.popup(1); - }, - onHover: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', true) }, - onHoverLost: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', false) }, - onPrimaryClick: () => App.toggleWindow('sideright'), - onSecondaryClick: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print), - onMiddleClick: () => execAsync('playerctl play-pause').catch(print), - setup: (self) => self.on('button-press-event', (self, event) => { - if (event.get_button()[1] === 8) - execAsync('playerctl previous').catch(print) - }), - child: Widget.Box({ - children: [ - separatorDot, - barStatusIcons, - ], - }), - }), + indicatorArea ], }), ] From a5312ce0b07d5e23dde1a0fe45a911957afb677a Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 16 Mar 2024 11:33:36 +0700 Subject: [PATCH 135/517] oops trailing comma --- .config/ags/modules/bar/normal/spaceright.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/modules/bar/normal/spaceright.js b/.config/ags/modules/bar/normal/spaceright.js index 51ca36bbf..6b257e118 100644 --- a/.config/ags/modules/bar/normal/spaceright.js +++ b/.config/ags/modules/bar/normal/spaceright.js @@ -62,7 +62,7 @@ export default () => { }), child: child, }); - const emptyArea = SpaceRightDefaultClicks(Widget.Box({ hexpand: true, })), + const emptyArea = SpaceRightDefaultClicks(Widget.Box({ hexpand: true, })); const indicatorArea = SpaceRightDefaultClicks(Widget.Box({ children: [ separatorDot, From 4d51713493bd6b0f401ac1315ece3742aad24131 Mon Sep 17 00:00:00 2001 From: clsty Date: Sat, 16 Mar 2024 15:13:50 +0800 Subject: [PATCH 136/517] Handle zshrc when install --- .zshrc => .config/zshrc.d/dots-hyprland.zsh | 0 install.sh | 9 +++++++++ 2 files changed, 9 insertions(+) rename .zshrc => .config/zshrc.d/dots-hyprland.zsh (100%) diff --git a/.zshrc b/.config/zshrc.d/dots-hyprland.zsh similarity index 100% rename from .zshrc rename to .config/zshrc.d/dots-hyprland.zsh diff --git a/install.sh b/install.sh index 287a2b8fb..e7775cf9d 100755 --- a/install.sh +++ b/install.sh @@ -197,6 +197,9 @@ v rsync -av ".local/bin/" "$HOME/.local/bin/" # Prevent hyprland from not fully loaded sleep 1 try hyprctl reload + +grep -q 'source ~/.config/zshrc.d/dots-hyprland.zsh' .zshrc || existed_zsh_conf=n + ##################################################################################### printf "\e[36m[$0]: Finished. See the \"Import Manually\" folder and grab anything you need.\e[97m\n" printf "\e[36mPress \e[30m\e[46m Ctrl+Super+T \e[0m\e[36m to select a wallpaper\e[97m\n" @@ -211,3 +214,9 @@ case $existed_hypr_conf in printf "\e[33mPlease use \"~/.config/hypr/hyprland.conf.new\" as a reference for a proper format.\e[97m\n" printf "\e[33mIf this is your first time installation, you must overwrite \"~/.config/hypr/hyprland.conf\" with \"~/.config/hypr/hyprland.conf.new\".\e[97m\n" ;;esac + +case $existed_zsh_conf in + n) printf "\n\e[36m[$0]: \"~/.zshrc\" seems not sourcing \"~/.config/zshrc.d/dots-hyprland.zsh\".\e[97m\n" + printf "\e[36mIt is optional, but you may put this line into your \"~/.zshrc\" to support colorscheme for ZSH:\e[97m\n" + printf "\e[36m source ~/.config/zshrc.d/dots-hyprland.zsh\e[97m\n" +;;esac From f458758bfd77bbf44ae5b19f11e995d9d847370f Mon Sep 17 00:00:00 2001 From: clsty Date: Sat, 16 Mar 2024 15:17:51 +0800 Subject: [PATCH 137/517] Better logic --- install.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/install.sh b/install.sh index e7775cf9d..88cd13b3d 100755 --- a/install.sh +++ b/install.sh @@ -198,7 +198,8 @@ v rsync -av ".local/bin/" "$HOME/.local/bin/" sleep 1 try hyprctl reload -grep -q 'source ~/.config/zshrc.d/dots-hyprland.zsh' .zshrc || existed_zsh_conf=n +existed_zsh_conf=n +grep -q 'source ~/.config/zshrc.d/dots-hyprland.zsh' ~/.zshrc && existed_zsh_conf=y ##################################################################################### printf "\e[36m[$0]: Finished. See the \"Import Manually\" folder and grab anything you need.\e[97m\n" From 0f5cca7797ab5417702bd804a0fd2d77f6b25ddc Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 16 Mar 2024 19:52:59 +0700 Subject: [PATCH 138/517] fix swww query (#270) --- .config/ags/scripts/color_generation/applycolor.sh | 2 +- .../ags/scripts/color_generation/generate_colors_material.py | 4 ++-- .config/ags/scripts/color_generation/switchwall.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.config/ags/scripts/color_generation/applycolor.sh b/.config/ags/scripts/color_generation/applycolor.sh index 7fab4e184..a8e41e9d1 100755 --- a/.config/ags/scripts/color_generation/applycolor.sh +++ b/.config/ags/scripts/color_generation/applycolor.sh @@ -11,7 +11,7 @@ colorstrings='' colorlist=() colorvalues=() -# wallpath=$(swww query | awk -F 'image: ' '{print $2}') +# wallpath=$(swww query | head -1 | awk -F 'image: ' '{print $2}') # wallpath_png="$HOME"'/.cache/ags/user/generated/hypr/lockscreen.png' # convert "$wallpath" "$wallpath_png" # wallpath_png=$(echo "$wallpath_png" | sed 's/\//\\\//g') diff --git a/.config/ags/scripts/color_generation/generate_colors_material.py b/.config/ags/scripts/color_generation/generate_colors_material.py index deb34bf83..86c6d9d12 100755 --- a/.config/ags/scripts/color_generation/generate_colors_material.py +++ b/.config/ags/scripts/color_generation/generate_colors_material.py @@ -35,8 +35,8 @@ elif len(sys.argv) > 1 and sys.argv[1] == '--color': else: # try: # imagePath = subprocess.check_output("ags run-js 'wallpaper.get(0)'", shell=True) - imagePath = subprocess.check_output("swww query | awk -F 'image: ' '{print $2}'", shell=True) - imagePath = imagePath[:-1].decode("utf-8") + imagePath = subprocess.check_output("swww query | head -1 | awk -F 'image: ' '{print $2}'", shell=True) + imagePath = imagePath[:-1].decode("utf-8") img = Image.open(imagePath) basewidth = 64 wpercent = (basewidth/float(img.size[0])) diff --git a/.config/ags/scripts/color_generation/switchwall.sh b/.config/ags/scripts/color_generation/switchwall.sh index 05a9fe54f..fe4bca97a 100755 --- a/.config/ags/scripts/color_generation/switchwall.sh +++ b/.config/ags/scripts/color_generation/switchwall.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash if [ "$1" == "--noswitch" ]; then - imgpath=$(swww query | awk -F 'image: ' '{print $2}'| head -n 1) + imgpath=$(swww query | head -1 | awk -F 'image: ' '{print $2}') # imgpath=$(ags run-js 'wallpaper.get(0)') else # Select and set image (hyprland) From 3a9b164cd48a1fa74724cd5b50709a7446541882 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 16 Mar 2024 21:50:18 +0700 Subject: [PATCH 139/517] update colors --- .config/ags/modules/bar/normal/spaceleft.js | 4 +- .config/ags/modules/bar/normal/spaceright.js | 16 +++----- .config/ags/modules/bar/normal/system.js | 6 +-- .config/ags/scss/_bar.scss | 19 ++++++--- .config/ags/scss/_colors.scss | 41 ++++++++++++-------- 5 files changed, 49 insertions(+), 37 deletions(-) diff --git a/.config/ags/modules/bar/normal/spaceleft.js b/.config/ags/modules/bar/normal/spaceleft.js index 475297790..08cb4aacc 100644 --- a/.config/ags/modules/bar/normal/spaceleft.js +++ b/.config/ags/modules/bar/normal/spaceleft.js @@ -16,7 +16,7 @@ const WindowTitle = async () => { xalign: 0, truncate: 'end', maxWidthChars: 10, // Doesn't matter, just needs to be non negative - className: 'txt-smaller bar-topdesc txt', + className: 'txt-smaller bar-wintitle-topdesc txt', setup: (self) => self.hook(Hyprland.active.client, label => { // Hyprland.active.client label.label = Hyprland.active.client.class.length === 0 ? 'Desktop' : Hyprland.active.client.class; }), @@ -25,7 +25,7 @@ const WindowTitle = async () => { xalign: 0, truncate: 'end', maxWidthChars: 10, // Doesn't matter, just needs to be non negative - className: 'txt txt-smallie', + className: 'txt-smallie bar-wintitle-txt', setup: (self) => self.hook(Hyprland.active.client, label => { // Hyprland.active.client label.label = Hyprland.active.client.title.length === 0 ? `Workspace ${Hyprland.active.workspace.id}` : Hyprland.active.client.title; }), diff --git a/.config/ags/modules/bar/normal/spaceright.js b/.config/ags/modules/bar/normal/spaceright.js index 6b257e118..56ecbcc77 100644 --- a/.config/ags/modules/bar/normal/spaceright.js +++ b/.config/ags/modules/bar/normal/spaceright.js @@ -71,18 +71,12 @@ export default () => { })); const actualContent = Widget.Box({ hexpand: true, - className: 'spacing-h-5 txt', + className: 'spacing-h-5 bar-spaceright', children: [ - Widget.Box({ - hexpand: true, - className: 'spacing-h-5 txt', - children: [ - emptyArea, - barTray, - indicatorArea - ], - }), - ] + emptyArea, + barTray, + indicatorArea + ], }); return Widget.Box({ diff --git a/.config/ags/modules/bar/normal/system.js b/.config/ags/modules/bar/normal/system.js index c7ec83dd6..820e1d6fc 100644 --- a/.config/ags/modules/bar/normal/system.js +++ b/.config/ags/modules/bar/normal/system.js @@ -63,7 +63,7 @@ const UtilButton = ({ name, icon, onClicked }) => Button({ const Utilities = () => Box({ hpack: 'center', - className: 'spacing-h-4 txt-onSurfaceVariant', + className: 'spacing-h-4', children: [ UtilButton({ name: 'Screen snip', icon: 'screenshot_region', onClicked: () => { @@ -85,7 +85,7 @@ const Utilities = () => Box({ }) const BarBattery = () => Box({ - className: 'spacing-h-4 txt-onSurfaceVariant', + className: 'spacing-h-4 bar-batt-txt', children: [ Revealer({ transitionDuration: userOptions.animations.durationSmall, @@ -97,7 +97,7 @@ const BarBattery = () => Box({ }), }), Label({ - className: 'txt-smallie bar-batt-txt', + className: 'txt-smallie', setup: (self) => self.hook(Battery, label => { label.label = `${Battery.percent}%`; }), diff --git a/.config/ags/scss/_bar.scss b/.config/ags/scss/_bar.scss index 454bae7d0..4c73b7c9a 100644 --- a/.config/ags/scss/_bar.scss +++ b/.config/ags/scss/_bar.scss @@ -308,10 +308,14 @@ $bar_ws_width_focus_active: 2.045rem; @include large-rounding; } -.bar-topdesc { +.bar-wintitle-topdesc { margin-top: -0.136rem; margin-bottom: -0.341rem; - color: $windowtitleOnLayer1Inactive; + color: $windowtitleOnLayer0Inactive; +} + +.bar-wintitle-txt { + color: $windowtitleOnLayer0; } .bar-space-button { @@ -345,6 +349,7 @@ $bar_ws_width_focus_active: 2.045rem; min-height: 1.032rem; min-width: 1.032rem; font-size: 1.032rem; + color: $trayOnLayer0; } .bar-statusicons { @@ -363,8 +368,8 @@ $bar_ws_width_focus_active: 2.045rem; @include element_decel; min-height: 1.77rem; min-width: 1.77rem; - background-color: $layer2; - color: $onLayer2; + background-color: $utilsLayer2; + color: $utilsOnLayer2; } .bar-util-btn:hover, @@ -376,12 +381,16 @@ $bar_ws_width_focus_active: 2.045rem; background-color: $layer2Active; } +.bar-spaceright { + color: $barspacerightOnLayer0; +} + .bar-bluetooth-device { @include full-rounding; @include element_decel; min-height: 1.032rem; min-width: 1.032rem; font-size: 1.032rem; - color: $onLayer0; + color: $barspacerightOnLayer0; padding: 0.205rem 0.341rem; } \ No newline at end of file diff --git a/.config/ags/scss/_colors.scss b/.config/ags/scss/_colors.scss index c26cbd271..839c1c00e 100644 --- a/.config/ags/scss/_colors.scss +++ b/.config/ags/scss/_colors.scss @@ -135,6 +135,7 @@ $term7: $onSurfaceVariant; // General $layer0: $t_background; $onLayer0: $onBackground; +$onLayer0Inactive: mix($onBackground, $background, 70%); $layer0Active: mix($t_background, $t_onBackground, 80%); $layer1: $surface; $onLayer1Inactive: mix($onBackground, $background, 45%); @@ -144,7 +145,9 @@ $onLayer2: $onSurfaceVariant; $layer2Hover: mix($layer2, $onSurfaceVariant, 90%); $layer2Active: mix($layer2, $onSurfaceVariant, 80%); // Elements -$windowtitleOnLayer1Inactive: $onLayer1; +$windowtitleOnLayer0Inactive: $onLayer0Inactive; +$windowtitleOnLayer0: $onLayer0; +$barspacerightOnLayer0: $onLayer0; $timeOnLayer1: $onLayer1; $dateOnLayer1: $onLayer1; $ramOnLayer1: $onLayer1; @@ -159,14 +162,16 @@ $cpuOnLayer2: $onSecondaryContainer; $musicOnLayer1: $onLayer1; $musicLayer2: $secondaryContainer; $musicOnLayer2: $onSecondaryContainer; +$utilsLayer2: $layer2; +$utilsOnLayer2: $onLayer2; $battOnLayer1: $onLayer1; $battLayer2: $secondaryContainer; $battOnLayer2: $onSecondaryContainer; - $workspaceOnLayer1Inactive: $onLayer1Inactive; $workspaceLayer3: $secondaryContainer; $workspaceOnLayer3: $onSecondaryContainer; $workspaceOnLayer2: $onSurfaceVariant; +$trayOnLayer0: $onLayer0; ///////////////////// test theme: amarena (kind of) ///////////////////////// // $layer0: #0e1116; @@ -180,27 +185,31 @@ $workspaceOnLayer2: $onSurfaceVariant; // $layer2Hover: mix($layer2, $onSurfaceVariant, 90%); // $layer2Active: mix($layer2, $onSurfaceVariant, 80%); // $layer3: #1C232A; -// $windowtitleOnLayer1Inactive: $onLayer1; +// $windowtitleOnLayer0Inactive: #70afa4; +// $windowtitleOnLayer0: #7FE3D1; +// $barspacerightOnLayer0: #7FE3D1; // $timeOnLayer1: #cc7691; // $dateOnLayer1: #cc7691; -// $ramOnLayer1: #61adc0; +// $ramOnLayer1: #6DC0D5; // $ramLayer2: $layer2; -// $ramOnLayer2: #61adc0; -// $swapOnLayer1: #b371ad; +// $ramOnLayer2: #6DC0D5; +// $swapOnLayer1: #CC83C7; // $swapLayer2: $layer2; -// $swapOnLayer2: #b371ad; -// $cpuOnLayer1: #7db17d; +// $swapOnLayer2: #CC83C7; +// $cpuOnLayer1: #FA6295; // $cpuLayer2: $layer2; -// $cpuOnLayer2: #7db17d; -// $musicOnLayer1: #b64a6e; +// $cpuOnLayer2: #FA6295; +// $musicOnLayer1: #94CF95; // $musicLayer2: $layer2; -// $musicOnLayer2: #b64a6e; -// $battOnLayer1: #7db17d; +// $musicOnLayer2: #94CF95; +// $utilsLayer2: $layer2; +// $utilsOnLayer2: #CC83C7; +// $battOnLayer1: #94CF95; // $battLayer2: $layer2; -// $battOnLayer2: #7db17d; - +// $battOnLayer2: #94CF95; // $workspaceOnLayer1Inactive: $onLayer1Inactive; // $workspaceLayer3: #33554f; -// $workspaceOnLayer3: #84EFDB; -// $workspaceOnLayer2: #84EFDB; +// $workspaceOnLayer3: #7FE3D1; +// $workspaceOnLayer2: #7FE3D1; +// $trayOnLayer0: #6DC0D5; From e703f0009705dd41f9eea3b077a0ad9c891ce742 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sat, 16 Mar 2024 21:00:17 +0530 Subject: [PATCH 140/517] Added color Schemes support. Added settings GUI in colorscheme-osd --- .../modules/.commonwidgets/configwidgets.js | 48 +++- .config/ags/modules/indicators/colorscheme.js | 185 +++++++++++++-- .config/ags/modules/overview/miscfunctions.js | 4 +- .config/ags/modules/sideleft/tools/module.js | 2 +- .../modules/sideleft/tools/quickscripts.js | 2 +- .../scripts/color_generation/applycolor.sh | 6 +- .../ags/scripts/color_generation/colorgen.sh | 19 +- .../generate_colors_material.py | 214 ++++++------------ .../scripts/color_generation/switchcolor.sh | 6 +- .../scripts/color_generation/switchwall.sh | 2 +- .config/ags/scss/_colors.scss | 22 +- .config/ags/scss/_common.scss | 27 ++- .config/ags/scss/_material.scss | 84 ++++--- .config/ags/scss/_osd.scss | 81 ++++++- 14 files changed, 485 insertions(+), 217 deletions(-) diff --git a/.config/ags/modules/.commonwidgets/configwidgets.js b/.config/ags/modules/.commonwidgets/configwidgets.js index ba181c604..6e7dced1e 100644 --- a/.config/ags/modules/.commonwidgets/configwidgets.js +++ b/.config/ags/modules/.commonwidgets/configwidgets.js @@ -120,7 +120,53 @@ export const ConfigSegmentedSelection = ({ } +export const ConfigMulipleSelection = ({ + icon, name, desc = '', + optionsArr = [ + [ { name: 'Option 1', value: 0 }, { name: 'Option 2', value: 1 } ], + [ { name: 'Option 3', value: 0 }, { name: 'Option 4', value: 1 } ], + ], + initIndex = [0, 0], + onChange, + ...rest +}) => { + let lastSelected = initIndex; + let value = optionsArr[initIndex[0]][initIndex[1]].value; + const widget = Box({ + tooltipText: desc, + className: 'multipleselection-container spacing-v-3', + //homogeneous: true, + vertical: true, + children: optionsArr.map((options, grp) => { + return Box({ + className: 'spacing-h-5', + hpack: 'center', + children: options.map((option, id) => { + return Button({ + setup: setupCursorHover, + className: `multipleselection-btn ${id == initIndex[1] && grp == initIndex[0] ? 'multipleselection-btn-enabled' : ''}`, + label: option.name, + onClicked: (self) => { + const kidsg = widget.get_children(); + const kids = kidsg.flatMap(widget => widget.get_children()); + kids.forEach(kid => { + kid.toggleClassName('multipleselection-btn-enabled', false); + }); + lastSelected = id; + self.toggleClassName('multipleselection-btn-enabled', true); + onChange(option.value, option.name); + } + }) + }), + }) + }), + ...rest, + }); + return widget; + +} + export const ConfigGap = ({ vertical = true, size = 5, ...rest }) => Box({ className: `gap-${vertical ? 'v' : 'h'}-${size}`, ...rest, -}) \ No newline at end of file +}) diff --git a/.config/ags/modules/indicators/colorscheme.js b/.config/ags/modules/indicators/colorscheme.js index 54ecef8ad..b54a5f290 100644 --- a/.config/ags/modules/indicators/colorscheme.js +++ b/.config/ags/modules/indicators/colorscheme.js @@ -1,51 +1,206 @@ +const { Gio, GLib } = imports.gi; +import Variable from 'resource:///com/github/Aylur/ags/variable.js'; import Widget from 'resource:///com/github/Aylur/ags/widget.js'; - -const { Box, EventBox, Icon, Scrollable, Label, Button, Revealer } = Widget; +import { ConfigToggle, ConfigMulipleSelection } from '../.commonwidgets/configwidgets.js'; +import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; +const { execAsync } = Utils; +import { setupCursorHover } from '../.widgetutils/cursorhover.js'; import { showColorScheme } from '../../variables.js'; +import { MaterialIcon } from '../.commonwidgets/materialicon.js'; const ColorBox = ({ name = 'Color', ...rest -}) => Box({ +}) => Widget.Box({ ...rest, homogeneous: true, children: [ - Label({ + Widget.Label({ label: `${name}`, }) ] }) -const ColorschemeContent = () => Box({ +const ColorSchemeSettingsRevealer = () => { + const headerButtonIcon = MaterialIcon('expand_more', 'norm'); + const header = Widget.Button({ + className: 'osd-settings-btn-arrow', + onClicked: () => { + content.revealChild = !content.revealChild; + headerButtonIcon.label = content.revealChild ? 'expand_less' : 'expand_more'; + }, + setup: setupCursorHover, + hpack: 'end', + child: headerButtonIcon, + }); + const content = Widget.Revealer({ + revealChild: false, + transition: 'slide_down', + transitionDuration: 200, + child: ColorSchemeSettings(), + setup: (self) => self.hook(isHoveredColorschemeSettings, (revealer) => { + if (isHoveredColorschemeSettings.value == false) { + setTimeout(() => { + if (isHoveredColorschemeSettings.value == false) + revealer.revealChild = false; + headerButtonIcon.label = 'expand_more'; + }, 1500); + } + }), + }); + return Widget.EventBox({ + onHover: (self) => { + isHoveredColorschemeSettings.setValue(true); + }, + onHoverLost: (self) => { + isHoveredColorschemeSettings.setValue(false); + }, + child: Widget.Box({ + vertical: true, + children: [ + header, + content, + ] + }), + }); +} + +function calculateSchemeInitIndex(optionsArr, searchValue = 'monochrome') { + const flatArray = optionsArr.flatMap(subArray => subArray); + const result = flatArray.findIndex(element => element.value === searchValue); + const rowIndex = Math.floor(result / optionsArr[0].length); + const columnIndex = result % optionsArr[0].length; + return [rowIndex, columnIndex]; +} + +const schemeOptionsArr = [ + [ + { name: 'Tonal Spot', value: 'tonalspot' }, + { name: 'Fruit Salad', value: 'fruitsalad' }, + { name: 'Fidelity', value: 'fidelity' }, + { name: 'Rainbow', value: 'rainbow' }, + ], + [ + { name: 'Neutral', value: 'neutral' }, + { name: 'Monochrome', value: 'monochrome' }, + { name: 'Expressive', value: 'expressive' }, + { name: 'Vibrant', value: 'vibrant' }, + ], + //[ + // { name: 'Content', value: 'content' }, + //] +]; + +const initColorMode = Utils.exec('bash -c "sed -n \'1p\' $HOME/.cache/ags/user/colormode.txt"'); +const initColorVal = (initColorMode == "dark") ? 1 : 0; +const initTransperancy = Utils.exec('bash -c "sed -n \'2p\' $HOME/.cache/ags/user/colormode.txt"'); +const initTransperancyVal = (initTransperancy == "transparent") ? 1 : 0; +const initScheme = Utils.exec('bash -c "sed -n \'3p\' $HOME/.cache/ags/user/colormode.txt"'); +const initSchemeIndex = calculateSchemeInitIndex(schemeOptionsArr, initScheme); + +const ColorSchemeSettings = () => Widget.Box({ + className: 'osd-colorscheme-settings spacing-v-5', + vertical: true, + vpack: 'center', + children: [ + Widget.Box({ + children: [ + ConfigToggle({ + name: 'Dark Mode', + initValue: initColorVal, + onChange: (self, newValue) => { + let lightdark = newValue == 0 ? "light" : "dark"; + execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && sed -i "1s/.*/${lightdark}/" ${GLib.get_user_cache_dir()}/ags/user/colormode.txt`]) + .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`])) + .catch(print); + }, + }), + ConfigToggle({ + name: 'Transperancy', + initValue: initTransperancyVal, + onChange: (self, newValue) => { + let transperancy = newValue == 0 ? "opaque" : "transparent"; + execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && sed -i "2s/.*/${transperancy}/" ${GLib.get_user_cache_dir()}/ags/user/colormode.txt`]) + .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`])) + .catch(print); + }, + }), + ] + }), + ConfigMulipleSelection({ + hpack: 'center', + vpack: 'center', + optionsArr: schemeOptionsArr, + initIndex: initSchemeIndex, + onChange: (value, name) => { + execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && sed -i "3s/.*/${value}/" ${GLib.get_user_cache_dir()}/ags/user/colormode.txt`]) + .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`])) + .catch(print); + }, + }), + ] +}); + +const ColorschemeContent = () => Widget.Box({ className: 'osd-colorscheme spacing-v-5', vertical: true, hpack: 'center', children: [ - Label({ + Widget.Label({ xalign: 0, className: 'txt-norm titlefont txt', label: 'Colorscheme', + hpack: 'center', }), - Box({ + Widget.Box({ className: 'spacing-h-5', + hpack: 'center', children: [ ColorBox({ name: 'P', className: 'osd-color osd-color-primary' }), - ColorBox({ name: 'P-c', className: 'osd-color osd-color-primaryContainer' }), ColorBox({ name: 'S', className: 'osd-color osd-color-secondary' }), - ColorBox({ name: 'S-c', className: 'osd-color osd-color-secondaryContainer' }), - ColorBox({ name: 'Sf-v', className: 'osd-color osd-color-surfaceVariant' }), + ColorBox({ name: 'T', className: 'osd-color osd-color-tertiary' }), ColorBox({ name: 'Sf', className: 'osd-color osd-color-surface' }), - ColorBox({ name: 'Bg', className: 'osd-color osd-color-background' }), + ColorBox({ name: 'Sf-i', className: 'osd-color osd-color-inverseSurface' }), + ColorBox({ name: 'E', className: 'osd-color osd-color-error' }), ] - }) + }), + Widget.Box({ + className: 'spacing-h-5', + hpack: 'center', + children: [ + ColorBox({ name: 'P-c', className: 'osd-color osd-color-primaryContainer' }), + ColorBox({ name: 'S-c', className: 'osd-color osd-color-secondaryContainer' }), + ColorBox({ name: 'T-c', className: 'osd-color osd-color-tertiaryContainer' }), + ColorBox({ name: 'Sf-c', className: 'osd-color osd-color-surfaceContainer' }), + ColorBox({ name: 'Sf-v', className: 'osd-color osd-color-surfaceVariant' }), + ColorBox({ name: 'E-c', className: 'osd-color osd-color-errorContainer' }), + ] + }), + ColorSchemeSettingsRevealer(), ] }); +const isHoveredColorschemeSettings = Variable(false); + export default () => Widget.Revealer({ transition: 'slide_down', transitionDuration: 200, child: ColorschemeContent(), - setup: (self) => self.hook(showColorScheme, (revealer) => { - revealer.revealChild = showColorScheme.value; - }), + setup: (self) => { + self + .hook(showColorScheme, (revealer) => { + if (showColorScheme.value == true) + revealer.revealChild = true; + else + revealer.revealChild = isHoveredColorschemeSettings.value; + }) + .hook(isHoveredColorschemeSettings, (revealer) => { + if (isHoveredColorschemeSettings.value == false) { + setTimeout(() => { + if (isHoveredColorschemeSettings.value == false) + revealer.revealChild = showColorScheme.value; + }, 2000); + } + }) + }, }) diff --git a/.config/ags/modules/overview/miscfunctions.js b/.config/ags/modules/overview/miscfunctions.js index ca592d01d..c6f89f93e 100644 --- a/.config/ags/modules/overview/miscfunctions.js +++ b/.config/ags/modules/overview/miscfunctions.js @@ -19,7 +19,7 @@ export function launchCustomCommand(command) { execAsync([`bash`, `-c`, `${App.configDir}/scripts/color_generation/switchwall.sh`, `&`]).catch(print); } else if (args[0] == '>color') { // Generate colorscheme from color picker - execAsync([`bash`, `-c`, `${App.configDir}/scripts/color_generation/switchcolor.sh`, `&`]).catch(print); + execAsync([`bash`, `-c`, `${App.configDir}/scripts/color_generation/switchcolor.sh --pick`, `&`]).catch(print); } else if (args[0] == '>light') { // Light mode execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && echo "-l" > ${GLib.get_user_cache_dir()}/ags/user/colormode.txt`]) @@ -138,4 +138,4 @@ export function ls({ path = '~', silent = false }) { if (!silent) console.log(e); } return contents; -} \ No newline at end of file +} diff --git a/.config/ags/modules/sideleft/tools/module.js b/.config/ags/modules/sideleft/tools/module.js index cf6037e42..bda60bee9 100644 --- a/.config/ags/modules/sideleft/tools/module.js +++ b/.config/ags/modules/sideleft/tools/module.js @@ -53,4 +53,4 @@ export default ({ content, ] }); -} \ No newline at end of file +} diff --git a/.config/ags/modules/sideleft/tools/quickscripts.js b/.config/ags/modules/sideleft/tools/quickscripts.js index 5b3fbec8e..66a53c050 100644 --- a/.config/ags/modules/sideleft/tools/quickscripts.js +++ b/.config/ags/modules/sideleft/tools/quickscripts.js @@ -90,4 +90,4 @@ export default () => SidebarModule({ }) }), }) -}); \ No newline at end of file +}); diff --git a/.config/ags/scripts/color_generation/applycolor.sh b/.config/ags/scripts/color_generation/applycolor.sh index f5aad6a0d..32528d994 100755 --- a/.config/ags/scripts/color_generation/applycolor.sh +++ b/.config/ags/scripts/color_generation/applycolor.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -term_alpha=100 #Set this to < 100 make all your terminals transparent +term_alpha=80 #Set this to < 100 make all your terminals transparent # sleep 0 # idk i wanted some delay or colors dont get applied properly if [ ! -d "$HOME"/.cache/ags/user/generated ]; then mkdir -p "$HOME"/.cache/ags/user/generated @@ -52,7 +52,7 @@ get_light_dark() { if [ ! -f "$HOME"/.cache/ags/user/colormode.txt ]; then echo "" > "$HOME"/.cache/ags/user/colormode.txt else - lightdark=$(cat "$HOME"/.cache/ags/user/colormode.txt) # either "" or "-l" + lightdark=$(sed -n '1p' "$HOME/.cache/ags/user/colormode.txt") fi echo "$lightdark" } @@ -163,7 +163,7 @@ apply_gtk() { # Using gradience-cli # Set light/dark preference # And set GTK theme manually as Gradience defaults to light adw-gtk3 # (which is unreadable when broken when you use dark mode) - if [ "$lightdark" = "-l" ]; then + if [ "$lightdark" = "light" ]; then gsettings set org.gnome.desktop.interface gtk-theme 'adw-gtk3' gsettings set org.gnome.desktop.interface color-scheme 'prefer-light' else diff --git a/.config/ags/scripts/color_generation/colorgen.sh b/.config/ags/scripts/color_generation/colorgen.sh index 15f81adb4..3978bbb71 100755 --- a/.config/ags/scripts/color_generation/colorgen.sh +++ b/.config/ags/scripts/color_generation/colorgen.sh @@ -1,6 +1,5 @@ #!/usr/bin/env bash -source ${HOME}/virtualenvs/my_project_venv/bin/activate # check if no arguments if [ $# -eq 0 ]; then @@ -9,11 +8,15 @@ if [ $# -eq 0 ]; then fi # check if the file ~/.cache/ags/user/colormode.txt exists. if not, create it. else, read it to $lightdark -lightdark="" +lightdark="dark" +transparency="opaque" +materialscheme="tonalspot" if [ ! -f "$HOME/.cache/ags/user/colormode.txt" ]; then - echo "" > "$HOME/.cache/ags/user/colormode.txt" + echo "dark\nopaque\ntonalspot" > "$HOME/.cache/ags/user/colormode.txt" else - lightdark=$(cat "$HOME/.cache/ags/user/colormode.txt") # either "" or "-l" + lightdark=$(sed -n '1p' "$HOME/.cache/ags/user/colormode.txt") + transparency=$(sed -n '2p' "$HOME/.cache/ags/user/colormode.txt") + materialscheme=$(sed -n '3p' "$HOME/.cache/ags/user/colormode.txt") fi backend="material" # color generator backend if [ ! -f "$HOME/.cache/ags/user/colorbackend.txt" ]; then @@ -24,13 +27,17 @@ fi cd "$HOME/.config/ags/scripts/" || exit if [[ "$1" = "#"* ]]; then # this is a color - color_generation/generate_colors_material.py --color "$1" "$lightdark" > "$HOME"/.cache/ags/user/generated/material_colors.scss + source ${HOME}/virtualenvs/my_project_venv/bin/activate + color_generation/generate_colors_material.py --color "$1" --mode "$lightdark" --scheme "$materialscheme" --transparency "$transparency" > "$HOME"/.cache/ags/user/generated/material_colors.scss + deactivate if [ "$2" = "--apply" ]; then cp "$HOME"/.cache/ags/user/generated/material_colors.scss "$HOME/.config/ags/scss/_material.scss" color_generation/applycolor.sh fi elif [ "$backend" = "material" ]; then - color_generation/generate_colors_material.py --path "$1" "$lightdark" > "$HOME"/.cache/ags/user/generated/material_colors.scss + source ${HOME}/virtualenvs/my_project_venv/bin/activate + color_generation/generate_colors_material.py --path "$1" --mode "$lightdark" --scheme "$materialscheme" --transparency "$transparency" > "$HOME"/.cache/ags/user/generated/material_colors.scss + deactivate if [ "$2" = "--apply" ]; then cp "$HOME"/.cache/ags/user/generated/material_colors.scss "$HOME/.config/ags/scss/_material.scss" color_generation/applycolor.sh diff --git a/.config/ags/scripts/color_generation/generate_colors_material.py b/.config/ags/scripts/color_generation/generate_colors_material.py index 9edd06ac4..2cdf4b774 100755 --- a/.config/ags/scripts/color_generation/generate_colors_material.py +++ b/.config/ags/scripts/color_generation/generate_colors_material.py @@ -3,159 +3,82 @@ from material_color_utilities_python import * from pathlib import Path import sys import subprocess +import argparse +import os -# Color in hue, chroma, tone form from materialyoucolor.hct import Hct from materialyoucolor.dynamiccolor.material_dynamic_colors import MaterialDynamicColors -# There are 9 different variants of scheme. + +parser = argparse.ArgumentParser(description='Color generation script') +parser.add_argument('--path', type=str, default=None, help='generate colorscheme from image') +parser.add_argument('--color', type=str, default=None, help='generate colorscheme from color') +parser.add_argument('--mode', type=str , choices=['dark', 'light'], default='dark', help='dark or light mode') +parser.add_argument('--scheme', type=str, default=None, help='material scheme to use') +parser.add_argument('--transparency', type=str , choices=['opaque', 'transparent'], default='opaque', help='enable transparency') +parser.add_argument('--debug', action='store_true', default=False, help='debug mode') +args = parser.parse_args() + +export_color_file=os.environ['HOME']+"/.cache/ags/user/color.txt" + +# Default scheme -> Tonal Spot (Android Default) from materialyoucolor.scheme.scheme_tonal_spot import SchemeTonalSpot as Scheme -#from materialyoucolor.scheme.scheme_fruit_salad import SchemeFruitSalad as Scheme -#from materialyoucolor.scheme.scheme_expressive import SchemeExpressive as Scheme -#from materialyoucolor.scheme.scheme_monochrome import SchemeMonochrome as Scheme -#from materialyoucolor.scheme.scheme_rainbow import SchemeRainbow as Scheme -#from materialyoucolor.scheme.scheme_vibrant import SchemeVibrant as Scheme -#from materialyoucolor.scheme.scheme_neutral import SchemeNeutral as Scheme -#from materialyoucolor.scheme.scheme_fidelity import SchemeFidelity as Scheme -#from materialyoucolor.scheme.scheme_content import SchemeContent as Scheme -# Others you can import: SchemeExpressive, SchemeFruitSalad, SchemeMonochrome, SchemeRainbow, SchemeVibrant, SchemeNeutral, SchemeFidelity and SchemeContent +if args.scheme is not None: + if args.scheme == 'fruitsalad': + from materialyoucolor.scheme.scheme_fruit_salad import SchemeFruitSalad as Scheme + elif args.scheme == 'expressive': + from materialyoucolor.scheme.scheme_expressive import SchemeExpressive as Scheme + elif args.scheme == 'monochrome': + from materialyoucolor.scheme.scheme_monochrome import SchemeMonochrome as Scheme + elif args.scheme == 'rainbow': + from materialyoucolor.scheme.scheme_rainbow import SchemeRainbow as Scheme + elif args.scheme == 'vibrant': + from materialyoucolor.scheme.scheme_vibrant import SchemeVibrant as Scheme + elif args.scheme == 'neutral': + from materialyoucolor.scheme.scheme_neutral import SchemeNeutral as Scheme + elif args.scheme == 'fidelity': + from materialyoucolor.scheme.scheme_fidelity import SchemeFidelity as Scheme + elif args.scheme == 'content': + from materialyoucolor.scheme.scheme_content import SchemeContent as Scheme -def darken(hex_color, factor=0.7): - if not (hex_color.startswith('#') and len(hex_color) in (4, 7)): - raise ValueError("Invalid hex color format") - hex_color = hex_color.lstrip('#') - rgb = tuple(int(hex_color[i:i + 2], 16) for i in (0, 2, 4)) - darkened_rgb = tuple(int(max(0, val * factor)) for val in rgb) - darkened_hex = "#{:02X}{:02X}{:02X}".format(*darkened_rgb) - return darkened_hex +def hex_to_argb(hex_color): + color = hex_color.lstrip('#') + if len(color) != 6: + raise ValueError("Invalid color code!") + r = int(color[:2], 16) + g = int(color[2:4], 16) + b = int(color[4:], 16) + a = 255 + argb = (a << 24) | (r << 16) | (g << 8) | b + return argb -img = 0 -newtheme=0 -if len(sys.argv) > 1 and sys.argv[1] == '--path': - # try: - img = Image.open(sys.argv[2]) +def argb_to_hex(argb_value): + r = (argb_value >> 16) & 0xff + g = (argb_value >> 8) & 0xff + b = argb_value & 0xff + hex_r = format(r, '02x') + hex_g = format(g, '02x') + hex_b = format(b, '02x') + hex_color = f"#{hex_r}{hex_g}{hex_b}" + return hex_color + +darkmode = (args.mode == 'dark') +transparent = (args.transparency == 'transparent') +print(f"$darkmode: {darkmode};") +print(f"$transparent: {transparent};") + +if args.path is not None: + img = Image.open(args.path) basewidth = 64 wpercent = (basewidth/float(img.size[0])) hsize = int((float(img.size[1])*float(wpercent))) img = img.resize((basewidth,hsize),Image.Resampling.LANCZOS) - newtheme = themeFromImage(img) argb = sourceColorFromImage(img) + with open(export_color_file, 'w') as file: + file.write(argb_to_hex(argb)) +elif args.color is not None: + argb = hex_to_argb(args.color) - scheme = Scheme(Hct.from_int(argb), True, 0.0) - - # except FileNotFoundError: - # print('[generate_colors_material.py] File not found', file=sys.stderr); - # exit() - # except: - # print('[generate_colors_material.py] Something went wrong', file=sys.stderr); - # exit() -elif len(sys.argv) > 1 and sys.argv[1] == '--color': - colorstr = sys.argv[2] - newtheme = themeFromSourceColor(argbFromHex(colorstr)) -else: - # try: - # imagePath = subprocess.check_output("ags run-js 'wallpaper.get(0)'", shell=True) - imagePath = subprocess.check_output("swww query | awk -F 'image: ' '{print $2}'", shell=True) - imagePath = imagePath[:-1].decode("utf-8") - img = Image.open(imagePath) - basewidth = 64 - wpercent = (basewidth/float(img.size[0])) - hsize = int((float(img.size[1])*float(wpercent))) - img = img.resize((basewidth,hsize),Image.Resampling.LANCZOS) - newtheme = themeFromImage(img) - # except FileNotFoundError: - # print('[generate_colors_material.py] File not found', file=sys.stderr) - # exit() - # except: - # print('[generate_colors_material.py] Something went wrong', file=sys.stderr); - # exit() - -colorscheme=0 -darkmode = True -if("-l" in sys.argv): - darkmode = False - colorscheme = newtheme.get('schemes').get('light') - print('$darkmode: false;') -else: - colorscheme = newtheme.get('schemes').get('dark') - print('$darkmode: true;') - -#primary = hexFromArgb(colorscheme.get_primary()) -#onPrimary = hexFromArgb(colorscheme.get_onPrimary()) -#primaryContainer = hexFromArgb(colorscheme.get_primaryContainer()) -#onPrimaryContainer = hexFromArgb(colorscheme.get_onPrimaryContainer()) -#secondary = hexFromArgb(colorscheme.get_secondary()) -#onSecondary = hexFromArgb(colorscheme.get_onSecondary()) -#secondaryContainer = hexFromArgb(colorscheme.get_secondaryContainer()) -#onSecondaryContainer = hexFromArgb(colorscheme.get_onSecondaryContainer()) -#tertiary = hexFromArgb(colorscheme.get_tertiary()) -#onTertiary = hexFromArgb(colorscheme.get_onTertiary()) -#tertiaryContainer = hexFromArgb(colorscheme.get_tertiaryContainer()) -#onTertiaryContainer = hexFromArgb(colorscheme.get_onTertiaryContainer()) -#error = hexFromArgb(colorscheme.get_error()) -#onError = hexFromArgb(colorscheme.get_onError()) -#errorContainer = hexFromArgb(colorscheme.get_errorContainer()) -#onErrorContainer = hexFromArgb(colorscheme.get_onErrorContainer()) -#background = hexFromArgb(colorscheme.get_background()) -#onBackground = hexFromArgb(colorscheme.get_onBackground()) -#surface = hexFromArgb(colorscheme.get_surface()) -#onSurface = hexFromArgb(colorscheme.get_onSurface()) -#surfaceVariant = hexFromArgb(colorscheme.get_surfaceVariant()) -#onSurfaceVariant = hexFromArgb(colorscheme.get_onSurfaceVariant()) -#outline = hexFromArgb(colorscheme.get_outline()) -#shadow = hexFromArgb(colorscheme.get_shadow()) -#inverseSurface = hexFromArgb(colorscheme.get_inverseSurface()) -#inverseOnSurface = hexFromArgb(colorscheme.get_inverseOnSurface()) -#inversePrimary = hexFromArgb(colorscheme.get_inversePrimary()) - - -# make material less boring -#if darkmode: -# background = darken(background, 0.6) - -#print('$primary: ' + primary + ';') -#print('$onPrimary: ' + onPrimary + ';') -#print('$primaryContainer: ' + primaryContainer + ';') -#print('$onPrimaryContainer: ' + onPrimaryContainer + ';') -#print('$secondary: ' + secondary + ';') -#print('$onSecondary: ' + onSecondary + ';') -#print('$secondaryContainer: ' + secondaryContainer + ';') -#print('$onSecondaryContainer: ' + onSecondaryContainer + ';') -#print('$tertiary: ' + tertiary + ';') -#print('$onTertiary: ' + onTertiary + ';') -#print('$tertiaryContainer: ' + tertiaryContainer + ';') -#print('$onTertiaryContainer: ' + onTertiaryContainer + ';') -#print('$error: ' + error + ';') -#print('$onError: ' + onError + ';') -#print('$errorContainer: ' + errorContainer + ';') -#print('$onErrorContainer: ' + onErrorContainer + ';') -#print('$colorbarbg: ' + background + ';') -#print('$background: ' + background + ';') -#print('$onBackground: ' + onBackground + ';') -#print('$surface: ' + surface + ';') -#print('$onSurface: ' + onSurface + ';') -#print('$surfaceVariant: ' + surfaceVariant + ';') -#print('$onSurfaceVariant: ' + onSurfaceVariant + ';') -#print('$outline: ' + outline + ';') -#print('$shadow: ' + shadow + ';') -#print('$inverseSurface: ' + inverseSurface + ';') -#print('$inverseOnSurface: ' + inverseOnSurface + ';') -#print('$inversePrimary: ' + inversePrimary + ';') -#print('$indsddsdversePrimary: ' + inversePrimary + ';') - - - -if len(sys.argv) > 4: - if sys.argv[4] == '--debug': - for color in vars(MaterialDynamicColors).keys(): - color_name = getattr(MaterialDynamicColors, color) - if hasattr(color_name, "get_hct"): - rgba = color_name.get_hct(scheme).to_rgba() - r, g, b, a = rgba - hex_color = f"#{r:02X}{g:02X}{b:02X}" - print(color.ljust(32), "\x1B[38;2;{};{};{}m{}\x1B[0m".format(rgba[0], rgba[1], rgba[2], "\x1b[7m \x1b[7m"), hex_color) - - print('\nHey :\n') - +scheme = Scheme(Hct.from_int(argb), darkmode, 0.0) for color in vars(MaterialDynamicColors).keys(): color_name = getattr(MaterialDynamicColors, color) @@ -165,4 +88,11 @@ for color in vars(MaterialDynamicColors).keys(): hex_color = f"#{r:02X}{g:02X}{b:02X}" print('$' + color + ': ' + hex_color + ';') -print('$colorbarbg: ' + '#000000' + ';') +if args.debug == True: + for color in vars(MaterialDynamicColors).keys(): + color_name = getattr(MaterialDynamicColors, color) + if hasattr(color_name, "get_hct"): + rgba = color_name.get_hct(scheme).to_rgba() + r, g, b, a = rgba + hex_color = f"#{r:02X}{g:02X}{b:02X}" + print(color.ljust(32), "\x1B[38;2;{};{};{}m{}\x1B[0m".format(rgba[0], rgba[1], rgba[2], "\x1b[7m \x1b[7m"), hex_color) diff --git a/.config/ags/scripts/color_generation/switchcolor.sh b/.config/ags/scripts/color_generation/switchcolor.sh index 6e7e6b320..628d91158 100755 --- a/.config/ags/scripts/color_generation/switchcolor.sh +++ b/.config/ags/scripts/color_generation/switchcolor.sh @@ -1,6 +1,10 @@ #!/usr/bin/env bash -color=$(hyprpicker --no-fancy) +if [ "$1" == "--pick" ]; then + color=$(hyprpicker --no-fancy) +else + color=$(cut -f1 "${HOME}/.cache/ags/user/color.txt") +fi # Generate colors for ags n stuff "$HOME"/.config/ags/scripts/color_generation/colorgen.sh "${color}" --apply diff --git a/.config/ags/scripts/color_generation/switchwall.sh b/.config/ags/scripts/color_generation/switchwall.sh index 1129ae02b..c46bc65f7 100755 --- a/.config/ags/scripts/color_generation/switchwall.sh +++ b/.config/ags/scripts/color_generation/switchwall.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash if [ "$1" == "--noswitch" ]; then - imgpath=$(swww query | awk -F 'image: ' '{print $2}') + imgpath=$(swww query | awk -F 'image: ' '{print $2}' | head -n 1) # imgpath=$(ags run-js 'wallpaper.get(0)') else # Select and set image (hyprland) diff --git a/.config/ags/scss/_colors.scss b/.config/ags/scss/_colors.scss index b74d52b95..56d69b057 100644 --- a/.config/ags/scss/_colors.scss +++ b/.config/ags/scss/_colors.scss @@ -1,7 +1,7 @@ ///////////// COLOR MODIFICATIONS ///////////// // Material colors provide excellent readability, but can be uninteresting. // This is an attempt to improve that. -$transparency_enabled: false; +//$transparency_enabled: false; //@if $transparency_enabled ==false { // @if $darkmode ==true { @@ -35,6 +35,7 @@ $transparency_enabled: false; //} // //// Amounts +$transparency: 0.7; $transparentize_amount: 0.3; $transparentize_surface_amount_less: 0.6; $transparentize_surface_amount_less_less: 0.55; @@ -62,7 +63,7 @@ $onSuccess: #ffffff; $successContainer: #d1e8d5; $onSuccessContainer: #0c1f13; -@if $darkmode ==true { +@if $darkmode == True { // Dark variant $success: #b5ccba; $onSuccess: #213528; @@ -70,6 +71,22 @@ $onSuccessContainer: #0c1f13; $onSuccessContainer: #d1e9d6; } +@if $transparent == True { + + $background: transparentize($background, $transparency); + $surface: transparentize($surface, $transparency); + $surfaceDim: transparentize($surfaceDim, $transparency); + $surfaceBright: transparentize($surfaceBright, $transparency); + $surfaceContainerLowest: transparentize($surfaceContainerLowest, $transparency); + $surfaceContainerLow: transparentize($surfaceContainerLow, $transparency); + $surfaceContainer: transparentize($surfaceContainer, $transparency); + $surfaceContainerHigh: transparentize($surfaceContainerHigh, $transparency); + $surfaceContainerHighest: transparentize($surfaceContainerHighest, $transparency); + $surfaceVariant: transparentize($surfaceVariant, $transparency); + $inverseSurface: transparentize($inverseSurface, $transparency); + $surfaceTint: transparentize($surfaceTint, $transparency); +} + // Transparent versions $t_primary: transparentize($primary, $transparentize_amount); $t_onPrimary: transparentize($onPrimary, $transparentize_amount); @@ -89,7 +106,6 @@ $t_error: transparentize($error, $transparentize_amount); $t_onError: transparentize($onError, $transparentize_amount); $t_errorContainer: transparentize($errorContainer, $transparentize_amount); $t_onErrorContainer: transparentize($onErrorContainer, $transparentize_amount); -$t_colorbarbg: transparentize($colorbarbg, $transparentize_amount); $t_background: transparentize($background, $transparentize_amount); $t_t_background: transparentize($background, $transparentize_surface_amount_more); $t_onBackground: transparentize($onBackground, $transparentize_amount); diff --git a/.config/ags/scss/_common.scss b/.config/ags/scss/_common.scss index f7530f59b..e562b3371 100644 --- a/.config/ags/scss/_common.scss +++ b/.config/ags/scss/_common.scss @@ -209,6 +209,31 @@ popover { color: $onSecondaryContainer; } +.multipleselection-container { +} + +.multipleselection-btn { + @include small-rounding; + padding: 0rem 0.341rem; + border: 0.034rem solid $outlineVariant; +} + +.multipleselection-btn:focus, +.multipleselection-btn:hover { + background-color: $hovercolor; +} + +.multipleselection-btn-enabled { + background-color: $secondaryContainer; + color: $onSecondaryContainer; +} + +.multipleselection-btn-enabled:hover, +.multipleselection-btn-enabled:focus { + background-color: $secondaryContainer; + color: $onSecondaryContainer; +} + .gap-v-5 { min-height: 0.341rem; } @@ -231,4 +256,4 @@ popover { .gap-h-15 { min-width: 1.023rem; -} \ No newline at end of file +} diff --git a/.config/ags/scss/_material.scss b/.config/ags/scss/_material.scss index cfab8e9f3..54f606e0f 100644 --- a/.config/ags/scss/_material.scss +++ b/.config/ags/scss/_material.scss @@ -1,30 +1,56 @@ -$darkmode: true; -$primary: #e2e2e2; -$onPrimary: #000000; -$primaryContainer: #6b6b6b; -$onPrimaryContainer: #e2e2e2; -$secondary: #e2e2e2; -$onSecondary: #000000; -$secondaryContainer: #313131; -$onSecondaryContainer: #e2e2e2; -$tertiary: #e2e2e2; -$onTertiary: #000000; -$tertiaryContainer: #000000; -$onTertiaryContainer: #e2e2e2; -$error: #e2e2e2; -$onError: #000000; -$errorContainer: #000000; -$onErrorContainer: #e2e2e2; -$colorbarbg: #000000; -$background: #000000; -$onBackground: #e2e2e2; -$surface: #161616; -$onSurface: #e2e2e2; -$surfaceVariant: #242424; -$onSurfaceVariant: #e2e2e2; -$outline: #a1a1a1; +$darkmode: True; +$transparent: False; +$primary_paletteKeyColor: #977126; +$secondary_paletteKeyColor: #877456; +$tertiary_paletteKeyColor: #657E5B; +$neutral_paletteKeyColor: #7E766B; +$neutral_variant_paletteKeyColor: #807667; +$background: #17130B; +$onBackground: #ECE1D4; +$surface: #17130B; +$surfaceDim: #17130B; +$surfaceBright: #3E382F; +$surfaceContainerLowest: #FFFFFF; +$surfaceContainerLow: #201B13; +$surfaceContainer: #241F17; +$surfaceContainerHigh: #2F2921; +$surfaceContainerHighest: #3A342B; +$onSurface: #ECE1D4; +$surfaceVariant: #4E4639; +$onSurfaceVariant: #D1C5B4; +$inverseSurface: #ECE1D4; +$inverseOnSurface: #353027; +$outline: #9A8F80; +$outlineVariant: #4E4639; $shadow: #000000; -$inverseSurface: #e2e2e2; -$inverseOnSurface: #000000; -$inversePrimary: #e2e2e2; - +$scrim: #000000; +$surfaceTint: #EEBF6D; +$primary: #EEBF6D; +$onPrimary: #422C00; +$primaryContainer: #5E4100; +$onPrimaryContainer: #FFDEA9; +$inversePrimary: #7B580D; +$secondary: #DAC3A1; +$onSecondary: #3C2E16; +$secondaryContainer: #57472C; +$onSecondaryContainer: #F9E1BC; +$tertiary: #B4CEA6; +$onTertiary: #203619; +$tertiaryContainer: #7F9873; +$onTertiaryContainer: #000000; +$error: #FFB4AB; +$onError: #690005; +$errorContainer: #93000A; +$onErrorContainer: #FFDAD6; +$primaryFixed: #FFDEA9; +$primaryFixedDim: #EEBF6D; +$onPrimaryFixed: #271900; +$onPrimaryFixedVariant: #5E4100; +$secondaryFixed: #F7DFBB; +$secondaryFixedDim: #DAC3A1; +$onSecondaryFixed: #251A04; +$onSecondaryFixedVariant: #54442A; +$tertiaryFixed: #CFEBC0; +$tertiaryFixedDim: #B4CEA6; +$onTertiaryFixed: #0B2006; +$onTertiaryFixedVariant: #364D2D; diff --git a/.config/ags/scss/_osd.scss b/.config/ags/scss/_osd.scss index 15119a785..99a279b4a 100644 --- a/.config/ags/scss/_osd.scss +++ b/.config/ags/scss/_osd.scss @@ -10,7 +10,7 @@ .osd-value { @include elevation-border; @include elevation2; - background-color: $t_background; + background-color: $background; border-radius: 1.023rem; padding: 0.625rem 1.023rem; padding-top: 0.313rem; @@ -65,20 +65,27 @@ .osd-colorscheme { border-radius: 1.023rem; - background-color: $t_background; - padding: 1.023rem; + background-color: $background; + padding: 0.313rem 0.626rem; @include elevation2; } +.osd-colorscheme-settings { + background-color: $background; + padding: 0.313rem 0.626rem; + @include small-rounding; +} + .osd-color { - @include full-rounding; + border-radius: 0.650rem; + -gtk-outline-radius: 0.650rem; min-width: 2.727rem; min-height: 1.705rem; padding: 0rem 0.341rem; font-weight: bold; box { - @include full-rounding; + @include small-rounding; margin: 0.409rem; } } @@ -103,26 +110,78 @@ color: $onSecondaryContainer; box { background-color: $onSecondaryContainer; } } + +.osd-color-tertiary { + background-color: $tertiary; + color: $onTertiary; + box { background-color: $onTertiary; } +} +.osd-color-tertiaryContainer { + background-color: $tertiaryContainer; + color: $onTertiaryContainer; + box { background-color: $onTertiaryContainer; } +} + +.osd-color-error { + background-color: $error; + color: $onError; + box { background-color: $onError; } +} +.osd-color-errorContainer { + background-color: $errorContainer; + color: $onErrorContainer; + box { background-color: $onErrorContainer; } +} + +.osd-color-surface { + background-color: $surface; + color: $onSurface; + border: 0.068rem solid $outlineVariant; + box { background-color: $onSurface; } +} + +.osd-color-surfaceContainer { + background-color: $surfaceContainer; + color: $onSurface; + box { background-color: $onSurface; } +} + +.osd-color-inverseSurface { + background-color: $inverseSurface; + color: $inverseOnSurface; + box { background-color: $onSurfaceVariant; } +} + .osd-color-surfaceVariant { background-color: $surfaceVariant; color: $onSurfaceVariant; box { background-color: $onSurfaceVariant; } } -.osd-color-surface { - background-color: $surface; - color: $onSurface; - box { background-color: $onSurface; } -} + .osd-color-background { background-color: $background; color: $onBackground; box { background-color: $onBackground; } } +.osd-settings-btn-arrow { + @include full-rounding; + @include icon-material; + min-width: 1.705rem; + min-height: 1.705rem; + + &:hover { + background-color: $surfaceContainerHigh; + } + &:active { + background-color: $surfaceContainerHighest; + } +} + .osd-show { transition: 200ms cubic-bezier(0.1, 1, 0, 1); } .osd-hide { transition: 190ms cubic-bezier(0.85, 0, 0.15, 1); -} \ No newline at end of file +} From 943ce705fa9742ae4a70e8434c46b654262e0c19 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 16 Mar 2024 22:41:03 +0700 Subject: [PATCH 141/517] update cheatsheet colors (#327) --- .../ags/modules/cheatsheet/data_keybinds.js | 30 ++++----------- .config/ags/modules/cheatsheet/keybinds.js | 14 +++---- .config/ags/modules/cheatsheet/main.js | 4 +- .config/ags/scss/_bar.scss | 2 +- .config/ags/scss/_cheatsheet.scss | 29 +++++++++----- .config/ags/scss/_colors.scss | 38 ++++++++++++++++--- 6 files changed, 70 insertions(+), 47 deletions(-) diff --git a/.config/ags/modules/cheatsheet/data_keybinds.js b/.config/ags/modules/cheatsheet/data_keybinds.js index 8d0eeb0ae..5065b3430 100644 --- a/.config/ags/modules/cheatsheet/data_keybinds.js +++ b/.config/ags/modules/cheatsheet/data_keybinds.js @@ -11,7 +11,7 @@ export const keybindList = [[ { "keys": ["", "+", "PageUp"], "action": "Go to workspace on the left" }, { "keys": ["", "+", "PageDown"], "action": "Go to workspace on the right" } ], - "appeartick": 1 + "id": 1 }, { "icon": "overview_key", @@ -22,7 +22,7 @@ export const keybindList = [[ { "keys": ["", "Alt", "+", "PageUp"], "action": "Move window to workspace on the left" }, { "keys": ["", "Alt", "+", "PageDown"], "action": "Move window to workspace on the right" } ], - "appeartick": 1 + "id": 2 }, { "icon": "move_group", @@ -38,7 +38,7 @@ export const keybindList = [[ { "keys": ["", "+", "F"], "action": "Fullscreen" }, { "keys": ["", "Alt", "+", "F"], "action": "Fake fullscreen" } ], - "appeartick": 1 + "id": 3 } ], [ @@ -65,7 +65,7 @@ export const keybindList = [[ // { "keys": ["", "+", "M"], "action": "Toggle useless audio visualizer" }, // { "keys": ["(right)Ctrl"], "action": "Dismiss notification & close menus" } ], - "appeartick": 2 + "id": 4 }, { "icon": "construction", @@ -79,22 +79,8 @@ export const keybindList = [[ { "keys": ["Ctrl", "Alt", "+", "R"], "action": "Record region with sound" }, { "keys": ["", "Shift", "Alt", "+", "R"], "action": "Record screen with sound" } ], - "appeartick": 2 + "id": 5 }, - // { - // "icon": "edit", - // "name": "Edit mode", - // "binds": [ - // { "keys": ["Esc"], "action": "Exit Edit mode" }, - // { "keys": ["#"], "action": "Go to to workspace #" }, - // { "keys": ["Alt", "+", "#"], "action": "Dump windows to workspace #" }, - // { "keys": ["Shift", "+", "#"], "action": "Swap windows with workspace #" }, - // { "keys": ["Lmb"], "action": "Move window" }, - // { "keys": ["Mmb"], "action": "Move window" }, - // { "keys": ["Rmb"], "action": "Resize window" } - // ], - // "appeartick": 2 - // } ], [ { @@ -107,7 +93,7 @@ export const keybindList = [[ { "keys": ["", "+", "X"], "action": "Launch editor: GNOME Text Editor" }, { "keys": ["", "+", "I"], "action": "Launch settings: GNOME Control center" } ], - "appeartick": 3 + "id": 6 }, { "icon": "keyboard", @@ -116,7 +102,7 @@ export const keybindList = [[ { "keys": ["", "+", "V"], "action": "Clipboard history >> clipboard" }, { "keys": ["", "+", "."], "action": "Emoji picker >> clipboard" }, ], - "appeartick": 3 + "id": 7 }, { "icon": "terminal", @@ -130,6 +116,6 @@ export const keybindList = [[ { "keys": [">color"], "action": "Pick acccent color" }, { "keys": [">todo"], "action": "Type something after that to add a To-do item" }, ], - "appeartick": 3 + "id": 8 } ]]; diff --git a/.config/ags/modules/cheatsheet/keybinds.js b/.config/ags/modules/cheatsheet/keybinds.js index 3aea58f28..c156eb313 100644 --- a/.config/ags/modules/cheatsheet/keybinds.js +++ b/.config/ags/modules/cheatsheet/keybinds.js @@ -5,10 +5,10 @@ export const Keybinds = () => Widget.Box({ vertical: false, className: "spacing-h-15", homogeneous: true, - children: keybindList.map((group, i) => Widget.Box({ // Columns + children: keybindList.map((group, _) => Widget.Box({ // Columns vertical: true, className: "spacing-v-15", - children: group.map((category, i) => Widget.Box({ // Categories + children: group.map((category, _) => Widget.Box({ // Categories vertical: true, className: "spacing-v-15", children: [ @@ -18,7 +18,7 @@ export const Keybinds = () => Widget.Box({ children: [ Widget.Label({ xalign: 0, - className: "icon-material txt txt-larger", + className: `icon-material txt-larger cheatsheet-color-${category.id}`, label: category.icon, }), Widget.Label({ @@ -35,10 +35,10 @@ export const Keybinds = () => Widget.Box({ Widget.Box({ // Keys vertical: true, homogeneous: true, - children: category.binds.map((keybinds, i) => Widget.Box({ // Binds + children: category.binds.map((keybinds, _) => Widget.Box({ // Binds vertical: false, - children: keybinds.keys.map((key, i) => Widget.Label({ // Specific keys - className: `${['OR', '+'].includes(key) ? 'cheatsheet-key-notkey' : 'cheatsheet-key'} txt-small`, + children: keybinds.keys.map((key, _) => Widget.Label({ // Specific keys + className: `${['OR', '+'].includes(key) ? 'cheatsheet-key-notkey' : 'cheatsheet-key cheatsheet-color-' + category.id} txt-small`, label: key, })) })) @@ -46,7 +46,7 @@ export const Keybinds = () => Widget.Box({ Widget.Box({ // Actions vertical: true, homogeneous: true, - children: category.binds.map((keybinds, i) => Widget.Label({ // Binds + children: category.binds.map((keybinds, _) => Widget.Label({ // Binds xalign: 0, label: keybinds.action, className: "txt chearsheet-action txt-small", diff --git a/.config/ags/modules/cheatsheet/main.js b/.config/ags/modules/cheatsheet/main.js index d83a18b86..da4fa39fb 100644 --- a/.config/ags/modules/cheatsheet/main.js +++ b/.config/ags/modules/cheatsheet/main.js @@ -14,12 +14,12 @@ const cheatsheetHeader = () => Widget.CenterBox({ children: [ Widget.Box({ hpack: 'center', - className: 'spacing-h-5', + className: 'spacing-h-5 cheatsheet-title', children: [ Widget.Label({ hpack: 'center', css: 'margin-right: 0.682rem;', - className: 'txt-title txt', + className: 'txt-title', label: 'Cheat sheet', }), Widget.Label({ diff --git a/.config/ags/scss/_bar.scss b/.config/ags/scss/_bar.scss index 4c73b7c9a..0ec525aee 100644 --- a/.config/ags/scss/_bar.scss +++ b/.config/ags/scss/_bar.scss @@ -23,7 +23,7 @@ $bar_ws_width_focus_active: 2.045rem; } .bar-bg-focus-batterylow { - background-color: mix($background, $errorContainer, 80%); + background-color: mix($layer0, $errorContainer, 80%); } .bar-sidespace { diff --git a/.config/ags/scss/_cheatsheet.scss b/.config/ags/scss/_cheatsheet.scss index 8681e1cf4..70debef02 100644 --- a/.config/ags/scss/_cheatsheet.scss +++ b/.config/ags/scss/_cheatsheet.scss @@ -3,29 +3,40 @@ @include elevation-border; @include elevation2; margin-bottom: 0.682rem; - background-color: $t_background; + background-color: $layer0; padding: 1.364rem; } +.cheatsheet-title { + color: $cheatsheetTitle; +} + .cheatsheet-key { @include techfont; min-height: 1.364rem; min-width: 1.364rem; margin: 0.17rem; padding: 0.136rem 0.205rem; - border-radius: 0.409rem; -gtk-outline-radius: 0.409rem; - color: $primary; - border: 0.068rem solid $primary; - box-shadow: 0rem 0.136rem 0rem $primary; - font-weight: 500; + color: $cheatsheetTitle; + border-radius: 0.409rem; + border: 0.068rem solid $cheatsheetTitle; + box-shadow: 0rem 0.136rem 0rem $cheatsheetTitle; } .cheatsheet-key-notkey { min-height: 1.364rem; padding: 0.136rem 0.205rem; margin: 0.17rem; - color: $onPrimaryContainer; + color: $onLayer0; +} + +@for $i from 1 through 8 { + .cheatsheet-color-#{$i} { + color: nth($cheatsheetColors, $i); + border-color: nth($cheatsheetColors, $i); + box-shadow: 0rem 0.136rem 0rem nth($cheatsheetColors, $i); + } } // .cheatsheet-action {} @@ -39,11 +50,11 @@ .cheatsheet-closebtn:hover, .cheatsheet-closebtn:focus { - background-color: $hovercolor; + background-color: $layer0Hover; } .cheatsheet-closebtn:active { - background-color: $activecolor; + background-color: $layer0Active; } .cheatsheet-category-title { diff --git a/.config/ags/scss/_colors.scss b/.config/ags/scss/_colors.scss index 839c1c00e..30ffb7d36 100644 --- a/.config/ags/scss/_colors.scss +++ b/.config/ags/scss/_colors.scss @@ -135,10 +135,12 @@ $term7: $onSurfaceVariant; // General $layer0: $t_background; $onLayer0: $onBackground; -$onLayer0Inactive: mix($onBackground, $background, 70%); -$layer0Active: mix($t_background, $t_onBackground, 80%); +$layer0Hover: mix($layer0, $onLayer0, 85%); +$layer0Active: mix($layer0, $onLayer0, 70%); +$onLayer0Inactive: mix($onLayer0, $layer0, 70%); $layer1: $surface; -$onLayer1Inactive: mix($onBackground, $background, 45%); +$onLayer1: $onSurface; +$onLayer1Inactive: mix($onLayer1, $layer1, 45%); $onLayer1: $onSurfaceVariant; $layer2: $surfaceVariant; $onLayer2: $onSurfaceVariant; @@ -172,19 +174,32 @@ $workspaceLayer3: $secondaryContainer; $workspaceOnLayer3: $onSecondaryContainer; $workspaceOnLayer2: $onSurfaceVariant; $trayOnLayer0: $onLayer0; +$cheatsheetTitle: $onSecondaryContainer; +$cheatsheetColors: ( + $onSecondaryContainer, + $onSecondaryContainer, + $onSecondaryContainer, + $onSecondaryContainer, + $onSecondaryContainer, + $onSecondaryContainer, + $onSecondaryContainer, + $onSecondaryContainer +); ///////////////////// test theme: amarena (kind of) ///////////////////////// // $layer0: #0e1116; // $onLayer0: #FFFFFF; -// $layer0Active: mix($t_background, $t_onBackground, 80%); +// $layer0Hover: mix($layer0, $onLayer0, 85%); +// $layer0Active: mix($layer0, $onLayer0, 70%); // $layer1: #171c22; -// $onLayer1Inactive: mix($onBackground, $background, 45%); +// $onLayer1Inactive: mix($onLayer1, $layer1, 45%); // $onLayer1: $onSurfaceVariant; // $layer2: #252c35; // $onLayer2: $onSurfaceVariant; // $layer2Hover: mix($layer2, $onSurfaceVariant, 90%); // $layer2Active: mix($layer2, $onSurfaceVariant, 80%); // $layer3: #1C232A; +// // Bar // $windowtitleOnLayer0Inactive: #70afa4; // $windowtitleOnLayer0: #7FE3D1; // $barspacerightOnLayer0: #7FE3D1; @@ -212,4 +227,15 @@ $trayOnLayer0: $onLayer0; // $workspaceOnLayer3: #7FE3D1; // $workspaceOnLayer2: #7FE3D1; // $trayOnLayer0: #6DC0D5; - +// // Cheatsheet +// $cheatsheetTitle: #6DC0D4; +// $cheatsheetColors: ( +// #F692B2, +// #6EC1D6, +// #CD84C8, +// #7FE4D2, +// #94CF95, +// #CD84C8, +// #FB6396, +// #6EC1D6 +// ); From 5c097812ad45c17341c986cb6ad8265f164d5324 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 17 Mar 2024 00:18:59 +0700 Subject: [PATCH 142/517] sidebar: segcyer api stuff let me cook --- .config/ags/modules/.miscutils/system.js | 6 +- .../ags/modules/indicators/musiccontrols.js | 11 ++-- .../modules/sideleft/apis/ai_chatmessage.js | 18 ++---- .config/ags/modules/sideleft/apis/booru.js | 34 +++++------ .config/ags/modules/sideleft/apis/chatgpt.js | 2 +- .config/ags/modules/sideleft/apis/gemini.js | 2 +- .config/ags/modules/sideleft/apis/waifu.js | 12 +--- .config/ags/scss/_common.scss | 4 +- .config/ags/scss/_sidebars.scss | 57 +++++++++++-------- 9 files changed, 70 insertions(+), 76 deletions(-) diff --git a/.config/ags/modules/.miscutils/system.js b/.config/ags/modules/.miscutils/system.js index d5e73b38e..6285ee2d7 100644 --- a/.config/ags/modules/.miscutils/system.js +++ b/.config/ags/modules/.miscutils/system.js @@ -1,3 +1,4 @@ +const { GLib } = imports.gi; import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; const { execAsync, exec } = Utils; @@ -6,6 +7,9 @@ export const isDebianDistro = (distroID == 'linuxmint' || distroID == 'ubuntu' | export const isArchDistro = (distroID == 'arch' || distroID == 'endeavouros' || distroID == 'cachyos'); export const hasFlatpak = !!exec(`bash -c 'command -v flatpak'`); +const LIGHTDARK_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/colormode.txt`; +export let darkMode = !(Utils.readFile(LIGHTDARK_FILE_LOCATION).trim() == '-l'); + export const getDistroIcon = () => { // Arches if(distroID == 'arch') return 'arch-symbolic'; @@ -40,4 +44,4 @@ export const getDistroName = () => { if(distroID == 'raspbian') return 'Raspbian'; if(distroID == 'kali') return 'Kali Linux'; return 'Linux'; -} \ No newline at end of file +} diff --git a/.config/ags/modules/indicators/musiccontrols.js b/.config/ags/modules/indicators/musiccontrols.js index 9afd224d1..785b1bba6 100644 --- a/.config/ags/modules/indicators/musiccontrols.js +++ b/.config/ags/modules/indicators/musiccontrols.js @@ -1,4 +1,4 @@ -const { Gdk, GdkPixbuf, GLib, Gtk } = imports.gi; +const { GLib } = imports.gi; import App from 'resource:///com/github/Aylur/ags/app.js'; import Widget from 'resource:///com/github/Aylur/ags/widget.js'; import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; @@ -9,10 +9,9 @@ const { Box, EventBox, Icon, Scrollable, Label, Button, Revealer } = Widget; import { fileExists } from '../.miscutils/files.js'; import { AnimatedCircProg } from "../.commonwidgets/cairo_circularprogress.js"; import { showMusicControls } from '../../variables.js'; +import { darkMode } from '../.miscutils/system.js'; const COMPILED_STYLE_DIR = `${GLib.get_user_cache_dir()}/ags/user/generated` -const LIGHTDARK_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/colormode.txt`; -const lightDark = Utils.readFile(LIGHTDARK_FILE_LOCATION).trim(); const COVER_COLORSCHEME_SUFFIX = '_colorscheme.css'; var lastCoverPath = ''; @@ -181,7 +180,7 @@ const CoverArt = ({ player, ...rest }) => { } const coverPath = player.coverPath; - const stylePath = `${player.coverPath}${lightDark}${COVER_COLORSCHEME_SUFFIX}`; + const stylePath = `${player.coverPath}${darkMode ? '' : '-l'}${COVER_COLORSCHEME_SUFFIX}`; if (player.coverPath == lastCoverPath) { // Since 'notify::cover-path' emits on cover download complete Utils.timeout(200, () => { // self.attribute.showImage(self, coverPath); @@ -200,9 +199,9 @@ const CoverArt = ({ player, ...rest }) => { // Generate colors execAsync(['bash', '-c', - `${App.configDir}/scripts/color_generation/generate_colors_material.py --path '${coverPath}' > ${App.configDir}/scss/_musicmaterial.scss ${lightDark}`]) + `${App.configDir}/scripts/color_generation/generate_colors_material.py --path '${coverPath}' > ${App.configDir}/scss/_musicmaterial.scss ${darkMode ? '' : '-l'}`]) .then(() => { - exec(`wal -i "${player.coverPath}" -n -t -s -e -q ${lightDark}`) + exec(`wal -i "${player.coverPath}" -n -t -s -e -q ${darkMode ? '' : '-l'}`) exec(`cp ${GLib.get_user_cache_dir()}/wal/colors.scss ${App.configDir}/scss/_musicwal.scss`); exec(`sass ${App.configDir}/scss/_music.scss ${stylePath}`); Utils.timeout(200, () => { diff --git a/.config/ags/modules/sideleft/apis/ai_chatmessage.js b/.config/ags/modules/sideleft/apis/ai_chatmessage.js index 775252324..d7148984b 100644 --- a/.config/ags/modules/sideleft/apis/ai_chatmessage.js +++ b/.config/ags/modules/sideleft/apis/ai_chatmessage.js @@ -283,19 +283,15 @@ export const ChatMessage = (message, modelName = 'Model') => { const messageContentBox = MessageContent(message.content); const thisMessage = Box({ className: 'sidebar-chat-message', + homogeneous: true, children: [ - Box({ - className: `sidebar-chat-indicator ${message.role == 'user' ? 'sidebar-chat-indicator-user' : 'sidebar-chat-indicator-bot'}`, - }), Box({ vertical: true, - hpack: 'fill', - hexpand: true, children: [ Label({ - hpack: 'fill', + hpack: 'start', xalign: 0, - className: 'txt txt-bold sidebar-chat-name', + className: `txt txt-bold sidebar-chat-name sidebar-chat-name-${message.role == 'user' ? 'user' : 'bot'}`, wrap: true, useMarkup: true, label: (message.role == 'user' ? USERNAME : modelName), @@ -324,17 +320,13 @@ export const SystemMessage = (content, commandName, scrolledWindow) => { const thisMessage = Box({ className: 'sidebar-chat-message', children: [ - Box({ - className: `sidebar-chat-indicator sidebar-chat-indicator-System`, - }), Box({ vertical: true, - hpack: 'fill', - hexpand: true, children: [ Label({ xalign: 0, - className: 'txt txt-bold sidebar-chat-name', + hpack: 'start', + className: 'txt txt-bold sidebar-chat-name sidebar-chat-name-system', wrap: true, label: `System • ${commandName}`, }), diff --git a/.config/ags/modules/sideleft/apis/booru.js b/.config/ags/modules/sideleft/apis/booru.js index 722462c0b..2784d55cf 100644 --- a/.config/ags/modules/sideleft/apis/booru.js +++ b/.config/ags/modules/sideleft/apis/booru.js @@ -204,9 +204,6 @@ const BooruPage = (taglist) => { overlays: [imageActions] }) } - const colorIndicator = Box({ - className: `sidebar-chat-indicator`, - }); const downloadState = Stack({ homogeneous: false, transition: 'slide_up_down', @@ -233,7 +230,7 @@ const BooruPage = (taglist) => { hscroll: 'automatic', child: Box({ hpack: 'fill', - className: 'sidebar-waifu-content spacing-h-5', + className: 'spacing-h-5', children: [ ...taglist.map((tag) => CommandButton(tag)), Box({ hexpand: true }), @@ -246,8 +243,7 @@ const BooruPage = (taglist) => { const pageImageGrid = Grid({ // columnHomogeneous: true, // rowHomogeneous: true, - className: 'sidebar-waifu-image', - // css: 'min-height: 90px;' + className: 'sidebar-booru-imagegrid', }); const pageImageRevealer = Revealer({ transition: 'slide_down', @@ -256,6 +252,7 @@ const BooruPage = (taglist) => { child: pageImageGrid, }); const thisPage = Box({ + homogeneous: true, className: 'sidebar-chat-message', attribute: { 'imagePath': '', @@ -289,20 +286,17 @@ const BooruPage = (taglist) => { downloadIndicator.attribute.hide(); }, }, - children: [ - colorIndicator, - Box({ - vertical: true, - className: 'spacing-v-5', - children: [ - pageHeading, - Box({ - vertical: true, - children: [pageImageRevealer], - }) - ] - }) - ], + children: [Box({ + vertical: true, + className: 'spacing-v-5', + children: [ + pageHeading, + Box({ + vertical: true, + children: [pageImageRevealer], + }) + ] + })], }); return thisPage; } diff --git a/.config/ags/modules/sideleft/apis/chatgpt.js b/.config/ags/modules/sideleft/apis/chatgpt.js index 312c4db21..ebcf47bb5 100644 --- a/.config/ags/modules/sideleft/apis/chatgpt.js +++ b/.config/ags/modules/sideleft/apis/chatgpt.js @@ -247,7 +247,7 @@ const GPTWelcome = () => Box({ }); export const chatContent = Box({ - className: 'spacing-v-15', + className: 'spacing-v-5', vertical: true, setup: (self) => self .hook(GPTService, (box, id) => { diff --git a/.config/ags/modules/sideleft/apis/gemini.js b/.config/ags/modules/sideleft/apis/gemini.js index cd755c33a..53ec25a7e 100644 --- a/.config/ags/modules/sideleft/apis/gemini.js +++ b/.config/ags/modules/sideleft/apis/gemini.js @@ -151,7 +151,7 @@ const geminiWelcome = Box({ }); export const chatContent = Box({ - className: 'spacing-v-15', + className: 'spacing-v-5', vertical: true, setup: (self) => self .hook(GeminiService, (box, id) => { diff --git a/.config/ags/modules/sideleft/apis/waifu.js b/.config/ags/modules/sideleft/apis/waifu.js index 503c0992b..89a06ad0b 100644 --- a/.config/ags/modules/sideleft/apis/waifu.js +++ b/.config/ags/modules/sideleft/apis/waifu.js @@ -11,6 +11,7 @@ import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; import { MarginRevealer } from '../../.widgethacks/advancedrevealers.js'; import { setupCursorHover, setupCursorHoverInfo } from '../../.widgetutils/cursorhover.js'; import WaifuService from '../../../services/waifus.js'; +import { darkMode } from '../../.miscutils/system.js'; async function getImageViewerApp(preferredApp) { Utils.execAsync(['bash', '-c', `command -v ${preferredApp}`]) @@ -117,9 +118,6 @@ const WaifuImage = (taglist) => { onClicked: action, setup: setupCursorHover, }) - const colorIndicator = Box({ - className: `sidebar-chat-indicator`, - }); const downloadState = Stack({ homogeneous: false, transition: 'slide_up_down', @@ -139,7 +137,7 @@ const WaifuImage = (taglist) => { }); const blockHeading = Box({ hpack: 'fill', - className: 'sidebar-waifu-content spacing-h-5', + className: 'spacing-h-5', children: [ ...taglist.map((tag) => CommandButton(tag)), Box({ hexpand: true }), @@ -248,14 +246,10 @@ const WaifuImage = (taglist) => { else Utils.execAsync(['bash', '-c', `wget -O '${thisBlock.attribute.imagePath}' '${url}'`]) .then(showImage) .catch(print); - blockHeading.get_children().forEach((child) => { - child.setCss(`border-color: ${dominant_color};`); - }) - colorIndicator.css = `background-color: ${dominant_color};`; + thisBlock.css = `background-color: mix(${darkMode ? 'black' : 'white'}, ${dominant_color}, 0.9);`; }, }, children: [ - colorIndicator, Box({ vertical: true, className: 'spacing-v-5', diff --git a/.config/ags/scss/_common.scss b/.config/ags/scss/_common.scss index 59749dacf..6859879b9 100644 --- a/.config/ags/scss/_common.scss +++ b/.config/ags/scss/_common.scss @@ -29,8 +29,8 @@ menu { @include elevation-border-softer; padding: 0.681rem; - background: $surfaceVariant; - color: $onSurfaceVariant; + background: $layer2; + color: $onLayer2; border-radius: 1.159rem; -gtk-outline-radius: 1.159rem; diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss index bd56dfccf..5e248963a 100644 --- a/.config/ags/scss/_sidebars.scss +++ b/.config/ags/scss/_sidebars.scss @@ -2,8 +2,6 @@ $sidebar_chat_textboxareaColor: mix($onSurfaceVariant, $surfaceVariant, 40%); $textboxColor: mix($surface, $surfaceVariant, 80%); $system: $secondary; $onSystem: $onSecondary; -$chatgpt: $primary; -$onChatgpt: $onPrimary; @mixin group-padding { padding: 0.341rem; @@ -596,32 +594,47 @@ $colorpicker_rounding: 0.341rem; .sidebar-chat-message { margin: 0.682rem; + @include normal-rounding; + @include group-padding; + background-color: $layer1; } .sidebar-chat-indicator { @include element_decel; @include full-rounding; min-width: 0.136rem; +} + +.sidebar-chat-indicator-waifu { + @include element_decel; + @include full-rounding; + min-width: 0.136rem; background-color: $onBackground; } -.sidebar-chat-indicator-user { - background-color: $onBackground; -} - -.sidebar-chat-indicator-bot { - background-color: $chatgpt; -} - -.sidebar-chat-indicator-System { - background-color: $system; -} - .sidebar-chat-name { @include titlefont; - padding: 0.341rem; - margin-left: -0.136rem; - padding-left: 0.818rem; + @include small-rounding; + padding: 0.341rem 0.818rem; + margin: 0.341rem; + // margin-left: 0rem; + background-color: $layer2; + color: $onLayer2; +} + +.sidebar-chat-name-user { + background-color: $layer2; + color: $onLayer2; +} + +.sidebar-chat-name-bot { + background-color: $secondary; + color: $onSecondary; +} + +.sidebar-chat-name-system { + background-color: $secondaryContainer; + color: $onSecondaryContainer; } .sidebar-chat-txtblock { @@ -808,17 +821,11 @@ $colorpicker_rounding: 0.341rem; padding-left: 0.818rem; } -.sidebar-waifu-content { - margin-left: 0.682rem; -} - .sidebar-waifu-txt { @include readingfont; - margin-left: 0.682rem; } .sidebar-waifu-image { - margin-left: 0.682rem; @include normal-rounding; background-size: cover; background-repeat: no-repeat; @@ -850,6 +857,10 @@ $waifu_image_overlay_transparency: 0.7; background-color: rgba(60, 60, 60, $waifu_image_overlay_transparency); } +.sidebar-booru-imagegrid { + @include normal-rounding; +} + .sidebar-booru-image { @include small-rounding; margin: 0.273rem; From 03d3d3ed8a6a76b697eb32f58ff442ba093997ab Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 17 Mar 2024 00:45:49 +0700 Subject: [PATCH 143/517] fix #329 --- .config/ags/modules/bar/normal/music.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.config/ags/modules/bar/normal/music.js b/.config/ags/modules/bar/normal/music.js index ea9c35404..3879fafd4 100644 --- a/.config/ags/modules/bar/normal/music.js +++ b/.config/ags/modules/bar/normal/music.js @@ -208,18 +208,20 @@ export default () => { return EventBox({ onScrollUp: (self) => switchToRelativeWorkspace(self, -1), onScrollDown: (self) => switchToRelativeWorkspace(self, +1), - onPrimaryClick: () => showMusicControls.setValue(!showMusicControls.value), - onSecondaryClick: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print), - onMiddleClick: () => execAsync('playerctl play-pause').catch(print), - setup: (self) => self.on('button-press-event', (self, event) => { - if (event.get_button()[1] === 8) // Side button - execAsync('playerctl previous').catch(print) - }), child: Box({ className: 'spacing-h-4', children: [ SystemResourcesOrCustomModule(), - BarGroup({ child: musicStuff }), + EventBox({ + child: BarGroup({ child: musicStuff }), + onPrimaryClick: () => showMusicControls.setValue(!showMusicControls.value), + onSecondaryClick: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print), + onMiddleClick: () => execAsync('playerctl play-pause').catch(print), + setup: (self) => self.on('button-press-event', (self, event) => { + if (event.get_button()[1] === 8) // Side button + execAsync('playerctl previous').catch(print) + }), + }) ] }) }); From 5635372c6692454cd0903086234c60aeba563aee Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 17 Mar 2024 00:54:44 +0700 Subject: [PATCH 144/517] #327 for osk --- .config/ags/scss/_osk.scss | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.config/ags/scss/_osk.scss b/.config/ags/scss/_osk.scss index d5e62fffd..6c42a1085 100644 --- a/.config/ags/scss/_osk.scss +++ b/.config/ags/scss/_osk.scss @@ -11,7 +11,7 @@ $osk_key_fontsize: 1.091rem; @include elevation2; // min-height: 29.591rem; // min-width: 50rem; - background-color: $t_background; + background-color: $layer0; } .osk-body { @@ -32,7 +32,7 @@ $osk_key_fontsize: 1.091rem; .osk-dragline { @include full-rounding; - background-color: $surfaceVariant; + background-color: $onLayer0Inactive; min-height: 0.273rem; min-width: 10.227rem; margin-top: 0.545rem; @@ -41,8 +41,8 @@ $osk_key_fontsize: 1.091rem; .osk-key { border-radius: $osk_key_rounding; - background-color: $t_surfaceVariant; - color: $onSurfaceVariant; + background-color: $layer1; + color: $onLayer1; padding: $osk_key_padding; font-weight: 500; font-size: $osk_key_fontsize; @@ -50,16 +50,16 @@ $osk_key_fontsize: 1.091rem; .osk-key:hover, .osk-key:focus { - background-color: $hovercolor; + background-color: $layer1Hover; } .osk-key:active { - background-color: $activecolor; + background-color: $layer1Active; font-size: $osk_key_fontsize; } .osk-key-active { - background-color: $activecolor; + background-color: $layer1Active; } .osk-key-normal { @@ -95,8 +95,8 @@ $osk_key_fontsize: 1.091rem; .osk-control-button { border-radius: $osk_key_rounding; - background-color: $t_surfaceVariant; - color: $onSurfaceVariant; + background-color: $layer1; + color: $onLayer1; font-weight: 500; font-size: $osk_key_fontsize; padding: 0.682rem; @@ -104,11 +104,11 @@ $osk_key_fontsize: 1.091rem; .osk-control-button:hover, .osk-control-button:focus { - background-color: mix($t_surfaceVariant, $t_onSurfaceVariant, 90%); + background-color: $layer1Hover; } .osk-control-button:active { - background-color: mix($t_surfaceVariant, $t_onSurfaceVariant, 70%); + background-color: $layer1Active; font-size: $osk_key_fontsize; } From c0b16056171be2ea62ce7d390ecd2638428d1714 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 17 Mar 2024 00:57:21 +0700 Subject: [PATCH 145/517] osk: make fn keys look less weird --- .config/ags/scss/_osk.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/scss/_osk.scss b/.config/ags/scss/_osk.scss index 6c42a1085..b1d8210a1 100644 --- a/.config/ags/scss/_osk.scss +++ b/.config/ags/scss/_osk.scss @@ -1,7 +1,7 @@ $osk_key_height: 2.5rem; $osk_key_width: 2.5rem; $osk_key_padding: 0.188rem; -$osk_key_rounding: 0.682rem; +$osk_key_rounding: 0.545rem; $osk_key_fontsize: 1.091rem; .osk-window { From c39b573300d5b025232a0d135c39d9c563683683 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 17 Mar 2024 01:22:38 +0700 Subject: [PATCH 146/517] #327 for session screen --- .config/ags/modules/session/sessionscreen.js | 18 +++++++-------- .config/ags/scss/_osk.scss | 2 +- .config/ags/scss/_session.scss | 23 ++++++++++++-------- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/.config/ags/modules/session/sessionscreen.js b/.config/ags/modules/session/sessionscreen.js index 1f90636ea..eb2089c5b 100644 --- a/.config/ags/modules/session/sessionscreen.js +++ b/.config/ags/modules/session/sessionscreen.js @@ -8,7 +8,7 @@ import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; const { exec, execAsync } = Utils; -const SessionButton = (name, icon, command, props = {}) => { +const SessionButton = (name, icon, command, props = {}, colorid = 0) => { const buttonDescription = Widget.Revealer({ vpack: 'end', transitionDuration: userOptions.animations.durationSmall, @@ -21,7 +21,7 @@ const SessionButton = (name, icon, command, props = {}) => { }); return Widget.Button({ onClicked: command, - className: 'session-button', + className: `session-button session-color-${colorid}`, child: Widget.Overlay({ className: 'session-button-box', child: Widget.Label({ @@ -61,14 +61,14 @@ const SessionButton = (name, icon, command, props = {}) => { export default () => { // lock, logout, sleep - const lockButton = SessionButton('Lock', 'lock', () => { App.closeWindow('session'); execAsync(['loginctl', 'lock-session']) }); - const logoutButton = SessionButton('Logout', 'logout', () => { App.closeWindow('session'); execAsync(['bash', '-c', 'pkill Hyprland || pkill sway']) }); - const sleepButton = SessionButton('Sleep', 'sleep', () => { App.closeWindow('session'); execAsync('systemctl suspend') }); + const lockButton = SessionButton('Lock', 'lock', () => { App.closeWindow('session'); execAsync(['loginctl', 'lock-session']) }, {}, 1); + const logoutButton = SessionButton('Logout', 'logout', () => { App.closeWindow('session'); execAsync(['bash', '-c', 'pkill Hyprland || pkill sway']) }, {}, 2); + const sleepButton = SessionButton('Sleep', 'sleep', () => { App.closeWindow('session'); execAsync('systemctl suspend') }, {}, 3); // hibernate, shutdown, reboot - const hibernateButton = SessionButton('Hibernate', 'downloading', () => { App.closeWindow('session'); execAsync('systemctl hibernate') }); - const shutdownButton = SessionButton('Shutdown', 'power_settings_new', () => { App.closeWindow('session'); execAsync('systemctl poweroff') }); - const rebootButton = SessionButton('Reboot', 'restart_alt', () => { App.closeWindow('session'); execAsync('systemctl reboot') }); - const cancelButton = SessionButton('Cancel', 'close', () => App.closeWindow('session'), { className: 'session-button-cancel' }); + const hibernateButton = SessionButton('Hibernate', 'downloading', () => { App.closeWindow('session'); execAsync('systemctl hibernate') }, {}, 4); + const shutdownButton = SessionButton('Shutdown', 'power_settings_new', () => { App.closeWindow('session'); execAsync('systemctl poweroff') }, {}, 5); + const rebootButton = SessionButton('Reboot', 'restart_alt', () => { App.closeWindow('session'); execAsync('systemctl reboot') }, {}, 6); + const cancelButton = SessionButton('Cancel', 'close', () => App.closeWindow('session'), { className: 'session-button-cancel' }, 7); const sessionDescription = Widget.Box({ vertical: true, diff --git a/.config/ags/scss/_osk.scss b/.config/ags/scss/_osk.scss index b1d8210a1..6cefc4af2 100644 --- a/.config/ags/scss/_osk.scss +++ b/.config/ags/scss/_osk.scss @@ -16,7 +16,7 @@ $osk_key_fontsize: 1.091rem; .osk-body { padding: 1.023rem; - padding-top: 0px; + padding-top: 0rem; } .osk-show { diff --git a/.config/ags/scss/_session.scss b/.config/ags/scss/_session.scss index aa8f51a17..9853b3bcb 100644 --- a/.config/ags/scss/_session.scss +++ b/.config/ags/scss/_session.scss @@ -1,24 +1,23 @@ .session-bg { - background-color: mix($t_t_background, $background, 40%); + background-color: transparentize($color: $layer0, $amount: 0.4); } .session-button { @include large-rounding; min-width: 8.182rem; min-height: 8.182rem; - background-color: $surfaceVariant; - color: $onSurfaceVariant; + background-color: $layer1; + color: $onLayer1; font-size: 3rem; } .session-button-focused { - background-color: $secondaryContainer; - color: $onSecondaryContainer; + background-color: $layer1Hover; } .session-button-desc { - background-color: mix($surface, $surfaceVariant, 50%); - color: mix($onSurface, $onSurfaceVariant, 50%); + background-color: $layer2; + color: $onLayer2; border-bottom-left-radius: $rounding_large; border-bottom-right-radius: $rounding_large; padding: 0.205rem 0.341rem; @@ -29,7 +28,13 @@ @include large-rounding; min-width: 8.182rem; min-height: 5.455rem; - background-color: $surfaceVariant; - color: $onSurfaceVariant; + background-color: $layer1; + color: $onLayer1; font-size: 3rem; } + +@for $i from 1 through 7 { + .session-color-#{$i} { + color: nth($sessionColors, $i); + } +} \ No newline at end of file From a72e335fc7da323401bd3ce160bbe1eacdc87be1 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 04:01:51 +0530 Subject: [PATCH 147/517] Fix colorgeneration for musiccontrols --- .config/ags/modules/indicators/musiccontrols.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.config/ags/modules/indicators/musiccontrols.js b/.config/ags/modules/indicators/musiccontrols.js index 9afd224d1..e5200bf3d 100644 --- a/.config/ags/modules/indicators/musiccontrols.js +++ b/.config/ags/modules/indicators/musiccontrols.js @@ -12,7 +12,8 @@ import { showMusicControls } from '../../variables.js'; const COMPILED_STYLE_DIR = `${GLib.get_user_cache_dir()}/ags/user/generated` const LIGHTDARK_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/colormode.txt`; -const lightDark = Utils.readFile(LIGHTDARK_FILE_LOCATION).trim(); +const colorMode = Utils.exec('bash -c "sed -n \'1p\' $HOME/.cache/ags/user/colormode.txt"'); +const lightDark = (colorMode == "light") ? '-l' : ''; const COVER_COLORSCHEME_SUFFIX = '_colorscheme.css'; var lastCoverPath = ''; @@ -198,9 +199,11 @@ const CoverArt = ({ player, ...rest }) => { return; } + console.log(`${lightDark}`); + console.log(`${App.configDir}/scripts/color_generation/generate_colors_material.py --path '${coverPath}`); // Generate colors execAsync(['bash', '-c', - `${App.configDir}/scripts/color_generation/generate_colors_material.py --path '${coverPath}' > ${App.configDir}/scss/_musicmaterial.scss ${lightDark}`]) + `source /home/avi/virtualenvs/my_project_venv/bin/activate; ${App.configDir}/scripts/color_generation/generate_colors_material.py --path '${coverPath}' --mode '${colorMode}' > ${App.configDir}/scss/_musicmaterial.scss`]) .then(() => { exec(`wal -i "${player.coverPath}" -n -t -s -e -q ${lightDark}`) exec(`cp ${GLib.get_user_cache_dir()}/wal/colors.scss ${App.configDir}/scss/_musicwal.scss`); From c3de429225e076d99ecbfe56926c8da7753d1b0e Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 05:38:55 +0530 Subject: [PATCH 148/517] Simplify scss more, remove transparent colors for better support for transparent mode --- .../modules/.commonwidgets/configwidgets.js | 1 - .config/ags/scss/_bar.scss | 3 +- .config/ags/scss/_colors.scss | 180 ++---------------- .config/ags/scss/_common.scss | 2 + .config/ags/scss/_dock.scss | 6 +- .config/ags/scss/_lib_mixins.scss | 24 +-- .config/ags/scss/_material.scss | 92 ++++----- .config/ags/scss/_osd.scss | 1 + .config/ags/scss/_osk.scss | 4 +- .config/ags/scss/_session.scss | 2 +- .config/ags/scss/_sidebars.scss | 2 +- 11 files changed, 86 insertions(+), 231 deletions(-) diff --git a/.config/ags/modules/.commonwidgets/configwidgets.js b/.config/ags/modules/.commonwidgets/configwidgets.js index 243d7bf9b..c314e508a 100644 --- a/.config/ags/modules/.commonwidgets/configwidgets.js +++ b/.config/ags/modules/.commonwidgets/configwidgets.js @@ -135,7 +135,6 @@ export const ConfigMulipleSelection = ({ const widget = Box({ tooltipText: desc, className: 'multipleselection-container spacing-v-3', - //homogeneous: true, vertical: true, children: optionsArr.map((options, grp) => { return Box({ diff --git a/.config/ags/scss/_bar.scss b/.config/ags/scss/_bar.scss index 7e95b701f..e204c508a 100644 --- a/.config/ags/scss/_bar.scss +++ b/.config/ags/scss/_bar.scss @@ -361,6 +361,7 @@ $bar_ws_width_focus_active: 2.045rem; .bar-statusicons-active { background-color: $layer0Active; + color: $onLayer0Active; } .bar-util-btn { @@ -391,6 +392,6 @@ $bar_ws_width_focus_active: 2.045rem; min-height: 1.032rem; min-width: 1.032rem; font-size: 1.032rem; - color: $barspacerightOnLayer0; + //color: $barspacerightOnLayer0; padding: 0.205rem 0.341rem; } diff --git a/.config/ags/scss/_colors.scss b/.config/ags/scss/_colors.scss index 52a4ca363..e46632b54 100644 --- a/.config/ags/scss/_colors.scss +++ b/.config/ags/scss/_colors.scss @@ -1,61 +1,6 @@ -///////////// COLOR MODIFICATIONS ///////////// -// Material colors provide excellent readability, but can be uninteresting. -// This is an attempt to improve that. -//$transparency_enabled: false; - -//@if $transparency_enabled ==false { -// @if $darkmode ==true { -// $primary: mix($primary, white, 70%); -// $primaryContainer: mix($primaryContainer, white, 90%); -// $background: mix(mix($background, $primary, 94%), #000000, 50%); -// $surface: mix($surface, $primaryContainer, 98%); -// $surfaceVariant: mix($surfaceVariant, #000000, 75%); -// // $secondaryContainer: mix($secondaryContainer, $primaryContainer, 90%); -// } -// -// @if $darkmode ==false { -// $background: mix($background, $primary, 87%); -// $surface: mix($surface, $primary, 93%); -// $surfaceVariant: mix($surfaceVariant, #ffffff, 25%); -// } -//} -// -//@if $transparency_enabled ==true { -// @if $darkmode ==true { -// $background: mix(mix($background, $primary, 94%), #000000, 50%); -// $surface: mix($surface, $primaryContainer, 98%); -// $surfaceVariant: mix($surfaceVariant, #000000, 55%); -// } -// -// @if $darkmode ==false { -// $background: mix($background, $primary, 94%); -// $surface: mix($surface, $primary, 93%); -// $surfaceVariant: mix($surfaceVariant, #ffffff, 55%); -// } -//} -// -//// Amounts -$transparency: 0.7; +$transparency: 0.5; $transparentize_amount: 0.3; -$transparentize_surface_amount_less: 0.6; -$transparentize_surface_amount_less_less: 0.55; $transparentize_surface_amount: 0.7; -$transparentize_surface_amount_more: 0.8; -$transparentize_surface_amount_subtract_surface: $transparentize_surface_amount - $transparentize_amount; - -//@if $darkmode ==true { -// // Less transparency -// $transparentize_amount: 0.15; -// $transparentize_surface_amount_less: 0.5; -// $transparentize_surface_amount_less_less: 0.55; -// $transparentize_surface_amount: 0.69; -// $transparentize_surface_amount_more: 0.9; -// $transparentize_surface_amount_subtract_surface: $transparentize_surface_amount - $transparentize_amount; -//} -// -//@if $transparency_enabled ==false { -// $transparentize_amount: 0; -//} // Extended material $success: #4f6354; @@ -71,8 +16,12 @@ $onSuccessContainer: #0c1f13; $onSuccessContainer: #d1e9d6; } -@if $transparent == True { +// Transparent versions +$t_background: transparentize($background, $transparentize_amount); +$t_surface: transparentize($surface, $transparentize_surface_amount); +$t_surfaceVariant: transparentize($surfaceVariant, $transparentize_surface_amount); +@if $transparent == True { $background: transparentize($background, $transparency); $surface: transparentize($surface, $transparency); $surfaceDim: transparentize($surfaceDim, $transparency); @@ -87,52 +36,7 @@ $onSuccessContainer: #0c1f13; $surfaceTint: transparentize($surfaceTint, $transparency); } -// Transparent versions -$t_primary: transparentize($primary, $transparentize_amount); -$t_onPrimary: transparentize($onPrimary, $transparentize_amount); -$t_primaryContainer: transparentize($primaryContainer, $transparentize_amount); -$t_onPrimaryContainer: transparentize($onPrimaryContainer, $transparentize_amount); -$t_secondary: transparentize($secondary, $transparentize_amount); -$t_onSecondary: transparentize($onSecondary, $transparentize_amount); -$t_secondaryContainer: transparentize($secondaryContainer, $transparentize_amount); -$l_t_secondaryContainer: transparentize($secondaryContainer, $transparentize_surface_amount_less); -$t_onSecondaryContainer: transparentize($onSecondaryContainer, $transparentize_amount); -$t_t_t_onSecondaryContainer: transparentize($onSecondaryContainer, 0.93); -$t_tertiary: transparentize($tertiary, $transparentize_amount); -$t_onTertiary: transparentize($onTertiary, $transparentize_amount); -$t_tertiaryContainer: transparentize($tertiaryContainer, $transparentize_amount); -$t_onTertiaryContainer: transparentize($onTertiaryContainer, $transparentize_amount); -$t_error: transparentize($error, $transparentize_amount); -$t_onError: transparentize($onError, $transparentize_amount); -$t_errorContainer: transparentize($errorContainer, $transparentize_amount); -$t_onErrorContainer: transparentize($onErrorContainer, $transparentize_amount); -//$t_colorbarbg: transparentize($colorbarbg, $transparentize_amount); -$t_background: transparentize($background, $transparentize_amount); -$t_t_background: transparentize($background, $transparentize_surface_amount_more); -$t_onBackground: transparentize($onBackground, $transparentize_amount); -$t_surface: transparentize($surface, $transparentize_surface_amount); -$t_t_surface: transparentize($surface, $transparentize_surface_amount_more); -$t_onSurface: transparentize($onSurface, $transparentize_surface_amount); -$t_surfaceVariant: transparentize($surfaceVariant, $transparentize_surface_amount); -$t_onSurfaceVariant: transparentize($onSurfaceVariant, $transparentize_surface_amount); -$t_t_surfaceVariant: transparentize($surfaceVariant, $transparentize_surface_amount_more); -$l_t_surfaceVariant: transparentize($surfaceVariant, $transparentize_surface_amount_less); -$l_l_t_surfaceVariant: transparentize($surfaceVariant, $transparentize_surface_amount_less_less); -$t_outline: transparentize($outline, $transparentize_amount); -$t_shadow: transparentize($shadow, $transparentize_amount); -$t_inverseSurface: transparentize($inverseSurface, $transparentize_amount); -$t_inverseOnSurface: transparentize($inverseOnSurface, $transparentize_amount); -$t_inversePrimary: transparentize($inversePrimary, $transparentize_amount); -// Transparent material (extended) -$t_success: transparentize($error, $transparentize_amount); -$t_onSuccess: transparentize($onError, $transparentize_amount); -$t_successContainer: transparentize($errorContainer, $transparentize_amount); -$t_onSuccessContainer: transparentize($onErrorContainer, - $transparentize_amount); - // Others -//$hovercolor: #AA0000;//$surfaceContainerHigh; -//$activecolor: mix($t_surface, $t_onSurface, 30%); $subtext: $outline; $actiontext: mix($onBackground, $background, 85%); $black: black; @@ -141,7 +45,7 @@ $white: white; // Terminal colors $termbg: $surfaceContainerHigh; $termfg: $onSurfaceVariant; -$term0: $t_background; +$term0: $background; $term1: $error; $term2: $inversePrimary; $term3: $onPrimaryContainer; @@ -152,17 +56,18 @@ $term7: $onSurfaceVariant; /// Color mappings for more chaotic, dynamic colors like the average rice /// // General -$layer0: $t_background; +$layer0: $background; $onLayer0: $onBackground; $layer0Hover: mix($layer0, $onLayer0, 85%); -$layer0Active: mix($layer0, $onLayer0, 70%); +$layer0Active: $primary; +$onLayer0Active: $onPrimary; $onLayer0Inactive: mix($onLayer0, $layer0, 70%); -$layer1: $surface; +$layer1: $surfaceContainer; $onLayer1: $onSurface; $onLayer1Inactive: mix($onLayer1, $layer1, 45%); $onLayer1: $onSurfaceVariant; -$layer2: $surfaceVariant; -$onLayer2: $onSurfaceVariant; +$layer2: $secondaryContainer; +$onLayer2: $onSecondaryContainer; $layer2Hover: mix($layer2, $onSurfaceVariant, 90%); $layer2Active: mix($layer2, $onSurfaceVariant, 80%); // Elements @@ -189,9 +94,9 @@ $battOnLayer1: $onLayer1; $battLayer2: $secondaryContainer; $battOnLayer2: $onSecondaryContainer; $workspaceOnLayer1Inactive: $onLayer1Inactive; -$workspaceLayer3: $secondaryContainer; -$workspaceOnLayer3: $onSecondaryContainer; -$workspaceOnLayer2: $onSurfaceVariant; +$workspaceLayer3: $primary; +$workspaceOnLayer3: $onPrimary; +$workspaceOnLayer2: $onSecondaryContainer; $trayOnLayer0: $onLayer0; $cheatsheetTitle: $onSecondaryContainer; $cheatsheetColors: ( @@ -205,56 +110,3 @@ $cheatsheetColors: ( $onSecondaryContainer ); -///////////////////// test theme: amarena (kind of) ///////////////////////// -// $layer0: #0e1116; -// $onLayer0: #FFFFFF; -// $layer0Hover: mix($layer0, $onLayer0, 85%); -// $layer0Active: mix($layer0, $onLayer0, 70%); -// $layer1: #171c22; -// $onLayer1Inactive: mix($onLayer1, $layer1, 45%); -// $onLayer1: $onSurfaceVariant; -// $layer2: #252c35; -// $onLayer2: $onSurfaceVariant; -// $layer2Hover: mix($layer2, $onSurfaceVariant, 90%); -// $layer2Active: mix($layer2, $onSurfaceVariant, 80%); -// $layer3: #1C232A; -// // Bar -// $windowtitleOnLayer0Inactive: #70afa4; -// $windowtitleOnLayer0: #7FE3D1; -// $barspacerightOnLayer0: #7FE3D1; -// $timeOnLayer1: #cc7691; -// $dateOnLayer1: #cc7691; -// $ramOnLayer1: #6DC0D5; -// $ramLayer2: $layer2; -// $ramOnLayer2: #6DC0D5; -// $swapOnLayer1: #CC83C7; -// $swapLayer2: $layer2; -// $swapOnLayer2: #CC83C7; -// $cpuOnLayer1: #FA6295; -// $cpuLayer2: $layer2; -// $cpuOnLayer2: #FA6295; -// $musicOnLayer1: #94CF95; -// $musicLayer2: $layer2; -// $musicOnLayer2: #94CF95; -// $utilsLayer2: $layer2; -// $utilsOnLayer2: #CC83C7; -// $battOnLayer1: #94CF95; -// $battLayer2: $layer2; -// $battOnLayer2: #94CF95; -// $workspaceOnLayer1Inactive: $onLayer1Inactive; -// $workspaceLayer3: #33554f; -// $workspaceOnLayer3: #7FE3D1; -// $workspaceOnLayer2: #7FE3D1; -// $trayOnLayer0: #6DC0D5; -// // Cheatsheet -// $cheatsheetTitle: #6DC0D4; -// $cheatsheetColors: ( -// #F692B2, -// #6EC1D6, -// #CD84C8, -// #7FE4D2, -// #94CF95, -// #CD84C8, -// #FB6396, -// #6EC1D6 -// ); diff --git a/.config/ags/scss/_common.scss b/.config/ags/scss/_common.scss index 8717b135e..c4ee86c5c 100644 --- a/.config/ags/scss/_common.scss +++ b/.config/ags/scss/_common.scss @@ -216,11 +216,13 @@ popover { @include small-rounding; padding: 0rem 0.341rem; border: 0.034rem solid $outlineVariant; + color: $onSurface; } .multipleselection-btn:focus, .multipleselection-btn:hover { background-color: $hovercolor; + color: $onSurface; } .multipleselection-btn-enabled { diff --git a/.config/ags/scss/_dock.scss b/.config/ags/scss/_dock.scss index 2965726ab..19779f5b2 100644 --- a/.config/ags/scss/_dock.scss +++ b/.config/ags/scss/_dock.scss @@ -12,11 +12,11 @@ .dock-app-btn:hover, .dock-app-btn:focus { - background-color: mix($t_surface, $t_onSurface, 95%); + background-color: mix($t_surface, $onSurface, 95%); } .dock-app-btn:active { - background-color: mix($t_surface, $t_onSurface, 85%); + background-color: mix($t_surface, $onSurface, 85%); } .dock-app-icon { @@ -28,4 +28,4 @@ .dock-separator { min-width: 0.068rem; background-color: $surfaceVariant; -} \ No newline at end of file +} diff --git a/.config/ags/scss/_lib_mixins.scss b/.config/ags/scss/_lib_mixins.scss index b0c9576e6..b6e7b8bde 100644 --- a/.config/ags/scss/_lib_mixins.scss +++ b/.config/ags/scss/_lib_mixins.scss @@ -190,24 +190,24 @@ $overlay1: mix($onSurface, rgba(0, 0, 0, 0), 25%); $overlay2: mix($onSurface, rgba(0, 0, 0, 0), 40%); @mixin elevation-border-softer { - border-top: 1px solid mix($t_t_surface, $t_onSurface, 90%); - border-left: 1px solid mix($t_t_surface, $t_onSurface, 90%); - border-right: 1px solid mix($t_t_surface, $t_onSurface, 95%); - border-bottom: 1px solid mix($t_t_surface, $t_onSurface, 95%); + border-top: 1px solid mix($t_surface, $onSurface, 90%); + border-left: 1px solid mix($t_surface, $onSurface, 90%); + border-right: 1px solid mix($t_surface, $onSurface, 95%); + border-bottom: 1px solid mix($t_surface, $onSurface, 95%); } @mixin elevation-border { - border-top: 1px solid mix($t_t_surface, $onSurface, 90%); - border-left: 1px solid mix($t_t_surface, $onSurface, 90%); - border-right: 1px solid mix($t_t_surface, $onSurface, 95%); - border-bottom: 1px solid mix($t_t_surface, $onSurface, 95%); + border-top: 1px solid mix($t_surface, $onSurface, 80%); + border-left: 1px solid mix($t_surface, $onSurface, 80%); + border-right: 1px solid mix($t_surface, $onSurface, 85%); + border-bottom: 1px solid mix($t_surface, $onSurface, 85%); } @mixin elevation-border-heavier { - border-top: 1px solid mix($t_t_surface, $onSurface, 80%); - border-left: 1px solid mix($t_t_surface, $onSurface, 80%); - border-right: 1px solid mix($t_t_surface, $onSurface, 85%); - border-bottom: 1px solid mix($t_t_surface, $onSurface, 85%); + border-top: 1px solid mix($t_surface, $onSurface, 70%); + border-left: 1px solid mix($t_surface, $onSurface, 70%); + border-right: 1px solid mix($t_surface, $onSurface, 75%); + border-bottom: 1px solid mix($t_surface, $onSurface, 75%); } @mixin elevation-border-transparent { diff --git a/.config/ags/scss/_material.scss b/.config/ags/scss/_material.scss index 766ee8321..9f9a981fc 100644 --- a/.config/ags/scss/_material.scss +++ b/.config/ags/scss/_material.scss @@ -1,56 +1,56 @@ $darkmode: True; $transparent: False; -$primary_paletteKeyColor: #727C35; -$secondary_paletteKeyColor: #76795C; -$tertiary_paletteKeyColor: #537F73; -$neutral_paletteKeyColor: #78786D; -$neutral_variant_paletteKeyColor: #77786A; -$background: #13140D; -$onBackground: #E4E3D6; -$surface: #13140D; -$surfaceDim: #13140D; -$surfaceBright: #393A31; +$primary_paletteKeyColor: #427DA3; +$secondary_paletteKeyColor: #687987; +$tertiary_paletteKeyColor: #7D7195; +$neutral_paletteKeyColor: #73777B; +$neutral_variant_paletteKeyColor: #71787E; +$background: #101417; +$onBackground: #DFE3E8; +$surface: #101417; +$surfaceDim: #101417; +$surfaceBright: #353A3E; $surfaceContainerLowest: #FFFFFF; -$surfaceContainerLow: #1B1C14; -$surfaceContainer: #1F2018; -$surfaceContainerHigh: #2A2B22; -$surfaceContainerHighest: #35352D; -$onSurface: #E4E3D6; -$surfaceVariant: #47483B; -$onSurfaceVariant: #C8C7B7; -$inverseSurface: #E4E3D6; -$inverseOnSurface: #303129; -$outline: #919283; -$outlineVariant: #47483B; +$surfaceContainerLow: #181C20; +$surfaceContainer: #1C2024; +$surfaceContainerHigh: #262A2E; +$surfaceContainerHighest: #313539; +$onSurface: #DFE3E8; +$surfaceVariant: #41484D; +$onSurfaceVariant: #C1C7CE; +$inverseSurface: #DFE3E8; +$inverseOnSurface: #2D3135; +$outline: #8B9198; +$outlineVariant: #41484D; $shadow: #000000; $scrim: #000000; -$surfaceTint: #C2CD7C; -$primary: #C2CD7C; -$onPrimary: #2D3400; -$primaryContainer: #434B06; -$onPrimaryContainer: #DEE995; -$inversePrimary: #5A631F; -$secondary: #C6C9A7; -$onSecondary: #2F321A; -$secondaryContainer: #484B31; -$onSecondaryContainer: #E4E7C3; -$tertiary: #A2D0C2; -$onTertiary: #06372E; -$tertiaryContainer: #6D9A8D; +$surfaceTint: #94CDF7; +$primary: #94CDF7; +$onPrimary: #00344D; +$primaryContainer: #004C6D; +$onPrimaryContainer: #C8E6FF; +$inversePrimary: #246488; +$secondary: #B7C9D8; +$onSecondary: #21323F; +$secondaryContainer: #384956; +$onSecondaryContainer: #D3E5F5; +$tertiary: #CEC0E8; +$onTertiary: #352B4B; +$tertiaryContainer: #978BB0; $onTertiaryContainer: #000000; $error: #FFB4AB; $onError: #690005; $errorContainer: #93000A; $onErrorContainer: #FFDAD6; -$primaryFixed: #DEE995; -$primaryFixedDim: #C2CD7C; -$onPrimaryFixed: #191E00; -$onPrimaryFixedVariant: #434B06; -$secondaryFixed: #E2E5C2; -$secondaryFixedDim: #C6C9A7; -$onSecondaryFixed: #1A1D07; -$onSecondaryFixedVariant: #46492F; -$tertiaryFixed: #BDECDE; -$tertiaryFixedDim: #A2D0C2; -$onTertiaryFixed: #00201A; -$onTertiaryFixedVariant: #224E44; +$primaryFixed: #C8E6FF; +$primaryFixedDim: #94CDF7; +$onPrimaryFixed: #001E2E; +$onPrimaryFixedVariant: #004C6D; +$secondaryFixed: #D3E5F5; +$secondaryFixedDim: #B7C9D8; +$onSecondaryFixed: #0B1D29; +$onSecondaryFixedVariant: #384956; +$tertiaryFixed: #E9DDFF; +$tertiaryFixedDim: #CEC0E8; +$onTertiaryFixed: #1F1635; +$onTertiaryFixedVariant: #4B4163; diff --git a/.config/ags/scss/_osd.scss b/.config/ags/scss/_osd.scss index 99a279b4a..6a9d8b8f6 100644 --- a/.config/ags/scss/_osd.scss +++ b/.config/ags/scss/_osd.scss @@ -169,6 +169,7 @@ @include icon-material; min-width: 1.705rem; min-height: 1.705rem; + color: $onSurface; &:hover { background-color: $surfaceContainerHigh; diff --git a/.config/ags/scss/_osk.scss b/.config/ags/scss/_osk.scss index d5e62fffd..fc22cfe64 100644 --- a/.config/ags/scss/_osk.scss +++ b/.config/ags/scss/_osk.scss @@ -104,11 +104,11 @@ $osk_key_fontsize: 1.091rem; .osk-control-button:hover, .osk-control-button:focus { - background-color: mix($t_surfaceVariant, $t_onSurfaceVariant, 90%); + background-color: mix($t_surfaceVariant, $onSurfaceVariant, 90%); } .osk-control-button:active { - background-color: mix($t_surfaceVariant, $t_onSurfaceVariant, 70%); + background-color: mix($t_surfaceVariant, $onSurfaceVariant, 70%); font-size: $osk_key_fontsize; } diff --git a/.config/ags/scss/_session.scss b/.config/ags/scss/_session.scss index aa8f51a17..cfa562069 100644 --- a/.config/ags/scss/_session.scss +++ b/.config/ags/scss/_session.scss @@ -1,5 +1,5 @@ .session-bg { - background-color: mix($t_t_background, $background, 40%); + background-color: $t_surface; } .session-button { diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss index 1e6c94805..9cca76bde 100644 --- a/.config/ags/scss/_sidebars.scss +++ b/.config/ags/scss/_sidebars.scss @@ -128,7 +128,7 @@ $onChatgpt: $onPrimary; } .sidebar-navrail { - // background-color: $t_surface; + // background-color: $surface; padding: 0rem $rounding_medium; } From c300b74afd2aecc591b66eee975204f84433f8e6 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 17 Mar 2024 08:35:09 +0700 Subject: [PATCH 149/517] fix bar volume scrolling --- .config/ags/modules/bar/normal/spaceright.js | 36 +++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/.config/ags/modules/bar/normal/spaceright.js b/.config/ags/modules/bar/normal/spaceright.js index 56ecbcc77..0b4fee7b3 100644 --- a/.config/ags/modules/bar/normal/spaceright.js +++ b/.config/ags/modules/bar/normal/spaceright.js @@ -39,18 +39,6 @@ export default () => { }), }); const SpaceRightDefaultClicks = (child) => Widget.EventBox({ - onScrollUp: () => { - if (!Audio.speaker) return; - if (Audio.speaker.volume <= 0.09) Audio.speaker.volume += 0.01; - else Audio.speaker.volume += 0.03; - Indicator.popup(1); - }, - onScrollDown: () => { - if (!Audio.speaker) return; - if (Audio.speaker.volume <= 0.09) Audio.speaker.volume -= 0.01; - else Audio.speaker.volume -= 0.03; - Indicator.popup(1); - }, onHover: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', true) }, onHoverLost: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', false) }, onPrimaryClick: () => App.toggleWindow('sideright'), @@ -79,10 +67,24 @@ export default () => { ], }); - return Widget.Box({ - children: [ - actualContent, - Widget.Box({ className: 'bar-corner-spacing' }), - ] + return Widget.EventBox({ + onScrollUp: () => { + if (!Audio.speaker) return; + if (Audio.speaker.volume <= 0.09) Audio.speaker.volume += 0.01; + else Audio.speaker.volume += 0.03; + Indicator.popup(1); + }, + onScrollDown: () => { + if (!Audio.speaker) return; + if (Audio.speaker.volume <= 0.09) Audio.speaker.volume -= 0.01; + else Audio.speaker.volume -= 0.03; + Indicator.popup(1); + }, + child: Widget.Box({ + children: [ + actualContent, + SpaceRightDefaultClicks(Widget.Box({ className: 'bar-corner-spacing' })), + ] + }) }); } \ No newline at end of file From 5d51ed686125219e2380aaddc29fe84f07fe4a66 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 17 Mar 2024 08:35:57 +0700 Subject: [PATCH 150/517] #327 for indicators --- .config/ags/modules/indicators/colorscheme.js | 4 +- .../ags/modules/indicators/indicatorvalues.js | 18 ++++--- .config/ags/scss/_colors.scss | 36 ++++++++++++-- .config/ags/scss/_common.scss | 8 ++-- .config/ags/scss/_osd.scss | 48 ++++++++++++------- 5 files changed, 80 insertions(+), 34 deletions(-) diff --git a/.config/ags/modules/indicators/colorscheme.js b/.config/ags/modules/indicators/colorscheme.js index e0c46c1aa..33b745a34 100644 --- a/.config/ags/modules/indicators/colorscheme.js +++ b/.config/ags/modules/indicators/colorscheme.js @@ -34,8 +34,8 @@ const ColorschemeContent = () => Box({ ColorBox({ name: 'S', className: 'osd-color osd-color-secondary' }), ColorBox({ name: 'S-c', className: 'osd-color osd-color-secondaryContainer' }), ColorBox({ name: 'Sf-v', className: 'osd-color osd-color-surfaceVariant' }), - ColorBox({ name: 'Sf', className: 'osd-color osd-color-surface' }), - ColorBox({ name: 'Bg', className: 'osd-color osd-color-background' }), + ColorBox({ name: 'L1', className: 'osd-color osd-color-layer1' }), + ColorBox({ name: 'L0', className: 'osd-color osd-color-layer0' }), ] }) ] diff --git a/.config/ags/modules/indicators/indicatorvalues.js b/.config/ags/modules/indicators/indicatorvalues.js index e373e491f..18f228626 100644 --- a/.config/ags/modules/indicators/indicatorvalues.js +++ b/.config/ags/modules/indicators/indicatorvalues.js @@ -6,7 +6,11 @@ import { MarginRevealer } from '../.widgethacks/advancedrevealers.js'; import Brightness from '../../services/brightness.js'; import Indicator from '../../services/indicator.js'; -const OsdValue = ({ name, nameSetup = undefined, labelSetup, progressSetup, ...rest }) => { +const OsdValue = ({ + name, nameSetup = undefined, labelSetup, progressSetup, + extraClassName = '', extraProgressClassName = '', + ...rest +}) => { const valueName = Label({ xalign: 0, yalign: 0, hexpand: true, className: 'osd-label', @@ -20,7 +24,7 @@ const OsdValue = ({ name, nameSetup = undefined, labelSetup, progressSetup, ...r return Box({ // Volume vertical: true, hexpand: true, - className: 'osd-bg osd-value', + className: `osd-bg osd-value ${extraClassName}`, attribute: { 'disable': () => { valueNumber.label = '󰖭'; @@ -35,7 +39,7 @@ const OsdValue = ({ name, nameSetup = undefined, labelSetup, progressSetup, ...r ] }), ProgressBar({ - className: 'osd-progress', + className: `osd-progress ${extraProgressClassName}`, hexpand: true, vertical: false, setup: progressSetup, @@ -48,6 +52,8 @@ const OsdValue = ({ name, nameSetup = undefined, labelSetup, progressSetup, ...r export default () => { const brightnessIndicator = OsdValue({ name: 'Brightness', + extraClassName: 'osd-brightness', + extraProgressClassName: 'osd-brightness-progress', labelSetup: (self) => self.hook(Brightness, self => { self.label = `${Math.round(Brightness.screen_value * 100)}`; }, 'notify::screen-value'), @@ -59,9 +65,9 @@ export default () => { const volumeIndicator = OsdValue({ name: 'Volume', - attribute: { - headphones: undefined, - }, + extraClassName: 'osd-volume', + extraProgressClassName: 'osd-volume-progress', + attribute: { headphones: undefined }, nameSetup: (self) => Utils.timeout(1, () => { const updateAudioDevice = (self) => { const usingHeadphones = (Audio.speaker?.stream?.port)?.toLowerCase().includes('headphone'); diff --git a/.config/ags/scss/_colors.scss b/.config/ags/scss/_colors.scss index 30ffb7d36..cc1195620 100644 --- a/.config/ags/scss/_colors.scss +++ b/.config/ags/scss/_colors.scss @@ -142,10 +142,12 @@ $layer1: $surface; $onLayer1: $onSurface; $onLayer1Inactive: mix($onLayer1, $layer1, 45%); $onLayer1: $onSurfaceVariant; +$layer1Hover: mix($layer1, $onLayer1, 85%); +$layer1Active: mix($layer1, $onLayer1, 70%); $layer2: $surfaceVariant; $onLayer2: $onSurfaceVariant; -$layer2Hover: mix($layer2, $onSurfaceVariant, 90%); -$layer2Active: mix($layer2, $onSurfaceVariant, 80%); +$layer2Hover: mix($layer2, $onLayer2, 90%); +$layer2Active: mix($layer2, $onLayer2, 80%); // Elements $windowtitleOnLayer0Inactive: $onLayer0Inactive; $windowtitleOnLayer0: $onLayer0; @@ -185,6 +187,17 @@ $cheatsheetColors: ( $onSecondaryContainer, $onSecondaryContainer ); +$sessionColors: ( + $onLayer1, + $onLayer1, + $onLayer1, + $onLayer1, + $onLayer1, + $onLayer1, + $onLayer1 +); +$brightnessOnLayer0: $onLayer0; +$volumeOnLayer0: $onLayer0; ///////////////////// test theme: amarena (kind of) ///////////////////////// // $layer0: #0e1116; @@ -194,10 +207,12 @@ $cheatsheetColors: ( // $layer1: #171c22; // $onLayer1Inactive: mix($onLayer1, $layer1, 45%); // $onLayer1: $onSurfaceVariant; +// $layer1Hover: mix($layer1, $onLayer1, 85%); +// $layer1Active: mix($layer1, $onLayer1, 70%); // $layer2: #252c35; // $onLayer2: $onSurfaceVariant; -// $layer2Hover: mix($layer2, $onSurfaceVariant, 90%); -// $layer2Active: mix($layer2, $onSurfaceVariant, 80%); +// $layer2Hover: mix($layer2, $onLayer2, 90%); +// $layer2Active: mix($layer2, $onLayer2, 80%); // $layer3: #1C232A; // // Bar // $windowtitleOnLayer0Inactive: #70afa4; @@ -239,3 +254,16 @@ $cheatsheetColors: ( // #FB6396, // #6EC1D6 // ); +// $sessionColors: ( +// #F692B2, +// #6EC1D6, +// #CD84C8, +// #7FE4D2, +// #94CF95, +// #CD84C8, +// #FB6396 +// ); +// // Osd +// $brightnessOnLayer0: #F692B2; +// $volumeOnLayer0: #94CF95; + diff --git a/.config/ags/scss/_common.scss b/.config/ags/scss/_common.scss index 6859879b9..6e38992db 100644 --- a/.config/ags/scss/_common.scss +++ b/.config/ags/scss/_common.scss @@ -13,7 +13,7 @@ color: $onSecondary; } - caret-color: $primary; + caret-color: $onLayer2; } @keyframes appear { @@ -50,18 +50,18 @@ menubar>menuitem { menu>menuitem { padding: 0.4em 1.5rem; background: transparent; - transition: 0.2s ease background; + transition: 0.2s ease background-color; border-radius: 0.545rem; -gtk-outline-radius: 0.545rem; } menu>menuitem:hover, menu>menuitem:focus { - background-color: mix($surfaceVariant, $onSurfaceVariant, 90%); + background-color: $layer2Hover; } menu>menuitem:active { - background-color: mix($surfaceVariant, $onSurfaceVariant, 80%); + background-color: $layer2Active; } radio { diff --git a/.config/ags/scss/_osd.scss b/.config/ags/scss/_osd.scss index 15119a785..76fe38661 100644 --- a/.config/ags/scss/_osd.scss +++ b/.config/ags/scss/_osd.scss @@ -10,7 +10,7 @@ .osd-value { @include elevation-border; @include elevation2; - background-color: $t_background; + background-color: $layer0; border-radius: 1.023rem; padding: 0.625rem 1.023rem; padding-top: 0.313rem; @@ -27,7 +27,7 @@ min-height: 0.954rem; min-width: 0.068rem; border-radius: 10rem; - background-color: $secondaryContainer; + background-color: $layer2; // border: 0.068rem solid $onSecondaryContainer; } @@ -37,18 +37,13 @@ min-width: 0.680rem; margin: 0rem 0.137rem; border-radius: 10rem; - background-color: $onSecondaryContainer; + background-color: $onLayer2; } } -.osd-icon { - color: $onPrimaryContainer; -} - .osd-label { font-size: 1.023rem; font-weight: 500; - color: $onBackground; margin-top: 0.341rem; } @@ -56,7 +51,24 @@ @include titlefont; font-size: 1.688rem; font-weight: 500; - color: $onBackground; + color: $onLayer0; +} + +.osd-brightness { + color: $brightnessOnLayer0; +} +.osd-brightness-progress { + progress { + background-color: $brightnessOnLayer0; + } +} +.osd-volume { + color: $volumeOnLayer0; +} +.osd-volume-progress { + progress { + background-color: $volumeOnLayer0; + } } .osd-notifs { @@ -65,7 +77,7 @@ .osd-colorscheme { border-radius: 1.023rem; - background-color: $t_background; + background-color: $layer0; padding: 1.023rem; @include elevation2; } @@ -108,15 +120,15 @@ color: $onSurfaceVariant; box { background-color: $onSurfaceVariant; } } -.osd-color-surface { - background-color: $surface; - color: $onSurface; - box { background-color: $onSurface; } +.osd-color-L1 { + background-color: $layer1; + color: $onLayer1; + box { background-color: $onLayer1; } } -.osd-color-background { - background-color: $background; - color: $onBackground; - box { background-color: $onBackground; } +.osd-color-layer0 { + background-color: $layer0; + color: $onLayer0; + box { background-color: $onLayer0; } } .osd-show { From 4c99e6ee56f77163e303fb6cb014412857091964 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 13:37:58 +0530 Subject: [PATCH 151/517] Added installation script for materialyoucolor-python --- .config/ags/modules/indicators/musiccontrols.js | 4 +--- .config/ags/scripts/color_generation/colorgen.sh | 4 ---- .../scripts/color_generation/generate_colors_material.py | 2 +- install.sh | 7 +++++++ scriptdata/installers | 7 +++++++ 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/.config/ags/modules/indicators/musiccontrols.js b/.config/ags/modules/indicators/musiccontrols.js index e5200bf3d..d63685221 100644 --- a/.config/ags/modules/indicators/musiccontrols.js +++ b/.config/ags/modules/indicators/musiccontrols.js @@ -199,11 +199,9 @@ const CoverArt = ({ player, ...rest }) => { return; } - console.log(`${lightDark}`); - console.log(`${App.configDir}/scripts/color_generation/generate_colors_material.py --path '${coverPath}`); // Generate colors execAsync(['bash', '-c', - `source /home/avi/virtualenvs/my_project_venv/bin/activate; ${App.configDir}/scripts/color_generation/generate_colors_material.py --path '${coverPath}' --mode '${colorMode}' > ${App.configDir}/scss/_musicmaterial.scss`]) + `${App.configDir}/scripts/color_generation/generate_colors_material.py --path '${coverPath}' --mode '${colorMode}' > ${App.configDir}/scss/_musicmaterial.scss`]) .then(() => { exec(`wal -i "${player.coverPath}" -n -t -s -e -q ${lightDark}`) exec(`cp ${GLib.get_user_cache_dir()}/wal/colors.scss ${App.configDir}/scss/_musicwal.scss`); diff --git a/.config/ags/scripts/color_generation/colorgen.sh b/.config/ags/scripts/color_generation/colorgen.sh index 3978bbb71..e43634773 100755 --- a/.config/ags/scripts/color_generation/colorgen.sh +++ b/.config/ags/scripts/color_generation/colorgen.sh @@ -27,17 +27,13 @@ fi cd "$HOME/.config/ags/scripts/" || exit if [[ "$1" = "#"* ]]; then # this is a color - source ${HOME}/virtualenvs/my_project_venv/bin/activate color_generation/generate_colors_material.py --color "$1" --mode "$lightdark" --scheme "$materialscheme" --transparency "$transparency" > "$HOME"/.cache/ags/user/generated/material_colors.scss - deactivate if [ "$2" = "--apply" ]; then cp "$HOME"/.cache/ags/user/generated/material_colors.scss "$HOME/.config/ags/scss/_material.scss" color_generation/applycolor.sh fi elif [ "$backend" = "material" ]; then - source ${HOME}/virtualenvs/my_project_venv/bin/activate color_generation/generate_colors_material.py --path "$1" --mode "$lightdark" --scheme "$materialscheme" --transparency "$transparency" > "$HOME"/.cache/ags/user/generated/material_colors.scss - deactivate if [ "$2" = "--apply" ]; then cp "$HOME"/.cache/ags/user/generated/material_colors.scss "$HOME/.config/ags/scss/_material.scss" color_generation/applycolor.sh diff --git a/.config/ags/scripts/color_generation/generate_colors_material.py b/.config/ags/scripts/color_generation/generate_colors_material.py index 2cdf4b774..8ee4ebcdd 100755 --- a/.config/ags/scripts/color_generation/generate_colors_material.py +++ b/.config/ags/scripts/color_generation/generate_colors_material.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/opt/materialyoucolor/bin/python3 from material_color_utilities_python import * from pathlib import Path import sys diff --git a/install.sh b/install.sh index 88cd13b3d..defe08238 100755 --- a/install.sh +++ b/install.sh @@ -137,6 +137,13 @@ else ask_MicroTeX=true fi if $ask_MicroTeX;then showfun install-MicroTeX;v install-MicroTeX;fi +if $(test -d /opt/materialyoucolor); then + echo -e "\e[33m[$0]: Program \"MatertialYouColor-python\" already exists, no need to install.\e[0m" + echo -e "\e[34mYou can reinstall it in order to update to the latest version anyway.\e[0m" + ask_MaterialYouColor=$ask +else ask_MaterialYouColor=true +fi +showfun install-materialyoucolors;v install-materialyoucolors; ##################################################################################### printf "\e[36m[$0]: 3. Copying\e[97m\n" diff --git a/scriptdata/installers b/scriptdata/installers index 175da758c..1deeef85f 100644 --- a/scriptdata/installers +++ b/scriptdata/installers @@ -101,3 +101,10 @@ install-MicroTeX (){ x sudo cp ./LaTeX /usr/local/bin/ x cd $base } + +install-materialyoucolors () { + x sudo python -m venv /opt/materialyoucolor + x source /opt/materialyoucolor/bin/activate + x sudo pip install material-color-utilities-python materialyoucolor + x deactivate +} From 9afc2eaef56102a72149ce7cbacc719ba2086f57 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 13:46:02 +0530 Subject: [PATCH 152/517] Fix miscfunctions for dark/light mode --- .config/ags/modules/overview/miscfunctions.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.config/ags/modules/overview/miscfunctions.js b/.config/ags/modules/overview/miscfunctions.js index d8c4f706a..e13aa2ba0 100644 --- a/.config/ags/modules/overview/miscfunctions.js +++ b/.config/ags/modules/overview/miscfunctions.js @@ -31,13 +31,13 @@ export function launchCustomCommand(command) { execAsync([`bash`, `-c`, `${App.configDir}/scripts/color_generation/switchcolor.sh --pick`, `&`]).catch(print); } else if (args[0] == '>light') { // Light mode - execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && echo "-l" > ${GLib.get_user_cache_dir()}/ags/user/colormode.txt`]) - .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchwall.sh --noswitch`])) + execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && sed -i "1s/.*/light/" ${GLib.get_user_cache_dir()}/ags/user/colormode.txt`]) + .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`])) .catch(print); } else if (args[0] == '>dark') { // Dark mode - execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && echo "" > ${GLib.get_user_cache_dir()}/ags/user/colormode.txt`]) - .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchwall.sh --noswitch`])) + execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && sed -i "1s/.*/dark/" ${GLib.get_user_cache_dir()}/ags/user/colormode.txt`]) + .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`])) .catch(print); } else if (args[0] == '>badapple') { // Black and white From 7198aa7265ab9b3dedd90874bc0ed49a5f59ccfc Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 14:35:23 +0530 Subject: [PATCH 153/517] Added fallback if colormode file doesn't exi-- --- .config/ags/modules/indicators/colorscheme.js | 4 +++- .../ags/scripts/color_generation/colorgen.sh | 18 ++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.config/ags/modules/indicators/colorscheme.js b/.config/ags/modules/indicators/colorscheme.js index cbfa0bad5..0ee153905 100644 --- a/.config/ags/modules/indicators/colorscheme.js +++ b/.config/ags/modules/indicators/colorscheme.js @@ -65,7 +65,9 @@ const ColorSchemeSettingsRevealer = () => { }); } -function calculateSchemeInitIndex(optionsArr, searchValue = 'monochrome') { +function calculateSchemeInitIndex(optionsArr, searchValue = 'tonalspot') { + if (searchValue == '') + searchValue = 'tonalspot'; const flatArray = optionsArr.flatMap(subArray => subArray); const result = flatArray.findIndex(element => element.value === searchValue); const rowIndex = Math.floor(result / optionsArr[0].length); diff --git a/.config/ags/scripts/color_generation/colorgen.sh b/.config/ags/scripts/color_generation/colorgen.sh index e43634773..7ef167449 100755 --- a/.config/ags/scripts/color_generation/colorgen.sh +++ b/.config/ags/scripts/color_generation/colorgen.sh @@ -1,6 +1,5 @@ #!/usr/bin/env bash - # check if no arguments if [ $# -eq 0 ]; then echo "Usage: colorgen.sh /path/to/image (--apply)" @@ -8,15 +7,22 @@ if [ $# -eq 0 ]; then fi # check if the file ~/.cache/ags/user/colormode.txt exists. if not, create it. else, read it to $lightdark +colormodefile="$HOME/.cache/ags/user/colormode.txt" lightdark="dark" transparency="opaque" materialscheme="tonalspot" -if [ ! -f "$HOME/.cache/ags/user/colormode.txt" ]; then - echo "dark\nopaque\ntonalspot" > "$HOME/.cache/ags/user/colormode.txt" +if [ ! -f $colormodefile ]; then + echo "dark" > $colormodefile + echo "opaque" >> $colormodefile + echo "tonalspot" >> $colormodefile +elif [[ $(wc -l < $colormodefile) -ne 3 || $(wc -w < $colormodefile) -ne 3 ]]; then + echo "dark" > $colormodefile + echo "opaque" >> $colormodefile + echo "tonalspot" >> $colormodefile else - lightdark=$(sed -n '1p' "$HOME/.cache/ags/user/colormode.txt") - transparency=$(sed -n '2p' "$HOME/.cache/ags/user/colormode.txt") - materialscheme=$(sed -n '3p' "$HOME/.cache/ags/user/colormode.txt") + lightdark=$(sed -n '1p' $colormodefile) + transparency=$(sed -n '2p' $colormodefile) + materialscheme=$(sed -n '3p' $colormodefile) fi backend="material" # color generator backend if [ ! -f "$HOME/.cache/ags/user/colorbackend.txt" ]; then From 68b9cd2fd3bc8bff0237908aecc8df7f556f6995 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sun, 17 Mar 2024 18:12:33 +0700 Subject: [PATCH 154/517] sidebar: improve apis autoscrolling --- .config/ags/modules/sideleft/apis/booru.js | 2 ++ .config/ags/modules/sideleft/apis/chatgpt.js | 2 ++ .config/ags/modules/sideleft/apis/gemini.js | 2 ++ .config/ags/modules/sideleft/apis/waifu.js | 8 +++++++- 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.config/ags/modules/sideleft/apis/booru.js b/.config/ags/modules/sideleft/apis/booru.js index 2784d55cf..5cf91f5ec 100644 --- a/.config/ags/modules/sideleft/apis/booru.js +++ b/.config/ags/modules/sideleft/apis/booru.js @@ -11,6 +11,7 @@ import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; import { MarginRevealer } from '../../.widgethacks/advancedrevealers.js'; import { setupCursorHover, setupCursorHoverInfo } from '../../.widgetutils/cursorhover.js'; import BooruService from '../../../services/booru.js'; +import { chatEntry } from '../apiwidgets.js'; const Grid = Widget.subclass(Gtk.Grid, "AgsGrid"); async function getImageViewerApp(preferredApp) { @@ -348,6 +349,7 @@ export const booruView = Scrollable({ // Always scroll to bottom with new content const adjustment = scrolledWindow.get_vadjustment(); adjustment.connect("changed", () => { + if(!chatEntry.hasFocus) return; adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size()); }) } diff --git a/.config/ags/modules/sideleft/apis/chatgpt.js b/.config/ags/modules/sideleft/apis/chatgpt.js index ebcf47bb5..37c27dabd 100644 --- a/.config/ags/modules/sideleft/apis/chatgpt.js +++ b/.config/ags/modules/sideleft/apis/chatgpt.js @@ -11,6 +11,7 @@ import { ConfigToggle, ConfigSegmentedSelection, ConfigGap } from '../../.common import { markdownTest } from '../../.miscutils/md2pango.js'; import { MarginRevealer } from '../../.widgethacks/advancedrevealers.js'; import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; +import { chatEntry } from '../apiwidgets.js'; export const chatGPTTabIcon = Icon({ hpack: 'center', @@ -355,6 +356,7 @@ export const chatGPTView = Box({ // Always scroll to bottom with new content const adjustment = scrolledWindow.get_vadjustment(); adjustment.connect("changed", () => { + if(!chatEntry.hasFocus) return; adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size()); }) } diff --git a/.config/ags/modules/sideleft/apis/gemini.js b/.config/ags/modules/sideleft/apis/gemini.js index 53ec25a7e..a5fb278bc 100644 --- a/.config/ags/modules/sideleft/apis/gemini.js +++ b/.config/ags/modules/sideleft/apis/gemini.js @@ -10,6 +10,7 @@ import { SystemMessage, ChatMessage } from "./ai_chatmessage.js"; import { ConfigToggle, ConfigSegmentedSelection, ConfigGap } from '../../.commonwidgets/configwidgets.js'; import { markdownTest } from '../../.miscutils/md2pango.js'; import { MarginRevealer } from '../../.widgethacks/advancedrevealers.js'; +import { chatEntry } from '../apiwidgets.js'; const MODEL_NAME = `Gemini`; @@ -257,6 +258,7 @@ export const geminiView = Box({ // Always scroll to bottom with new content const adjustment = scrolledWindow.get_vadjustment(); adjustment.connect("changed", () => { + if(!chatEntry.hasFocus) return; adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size()); }) } diff --git a/.config/ags/modules/sideleft/apis/waifu.js b/.config/ags/modules/sideleft/apis/waifu.js index 89a06ad0b..dfe89061f 100644 --- a/.config/ags/modules/sideleft/apis/waifu.js +++ b/.config/ags/modules/sideleft/apis/waifu.js @@ -12,6 +12,7 @@ import { MarginRevealer } from '../../.widgethacks/advancedrevealers.js'; import { setupCursorHover, setupCursorHoverInfo } from '../../.widgetutils/cursorhover.js'; import WaifuService from '../../../services/waifus.js'; import { darkMode } from '../../.miscutils/system.js'; +import { chatEntry } from '../apiwidgets.js'; async function getImageViewerApp(preferredApp) { Utils.execAsync(['bash', '-c', `command -v ${preferredApp}`]) @@ -162,7 +163,11 @@ const WaifuImage = (taglist) => { ImageAction({ name: 'Hoard', icon: 'save', - action: () => execAsync(['bash', '-c', `mkdir -p ~/Pictures/homework${thisBlock.attribute.isNsfw ? '/🌶️' : ''} && cp ${thisBlock.attribute.imagePath} ~/Pictures/homework${thisBlock.attribute.isNsfw ? '/🌶️/' : ''}`]).catch(print), + action: (self) => { + execAsync(['bash', '-c', `mkdir -p ~/Pictures/homework${thisBlock.attribute.isNsfw ? '/🌶️' : ''} && cp ${thisBlock.attribute.imagePath} ~/Pictures/homework${thisBlock.attribute.isNsfw ? '/🌶️/' : ''}`]) + .then(() => self.label = 'done') + .catch(print); + }, }), ImageAction({ name: 'Open externally', @@ -314,6 +319,7 @@ export const waifuView = Scrollable({ // Always scroll to bottom with new content const adjustment = scrolledWindow.get_vadjustment(); adjustment.connect("changed", () => { + if(!chatEntry.hasFocus) return; adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size()); }) } From 225d2e4cacdef03a8085c578ce6d554a091a8f3a Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 20:06:15 +0530 Subject: [PATCH 155/517] Hyprland fix blur on ags and terminal --- .config/hypr/hyprland/rules.conf | 53 ++++++++++++++++---------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/.config/hypr/hyprland/rules.conf b/.config/hypr/hyprland/rules.conf index 5210add59..a55e8b99b 100644 --- a/.config/hypr/hyprland/rules.conf +++ b/.config/hypr/hyprland/rules.conf @@ -1,12 +1,13 @@ -# ####### Window rules ######## -windowrule = noblur,.* # Disables blur for windows. Substantially improves performance. +######## Window rules ######## +#windowrule = noblur,.* # Disables blur for windows. Substantially improves performance. # windowrule = opacity 0.89 override 0.89 override, .* # Applies transparency to EVERY WINDOW +windowrule = float, ^(blueberry.py)$ windowrule = float, ^(steam)$ windowrule = float, ^(guifetch)$ # FlafyDev/guifetch windowrulev2 = tile,class:(wps) windowrulev2 = tile,class:(dev.warp.Warp) - + # Dialogs windowrule=float,title:^(Open File)(.*)$ @@ -14,10 +15,10 @@ windowrule=float,title:^(Select a File)(.*)$ windowrule=float,title:^(Choose wallpaper)(.*)$ windowrule=float,title:^(Open Folder)(.*)$ windowrule=float,title:^(Save As)(.*)$ -windowrule=float,title:^(Library)(.*)$ +windowrule=float,title:^(Library)(.*)$ -# ####### Layer rules ######## -layerrule = xray 1, .* +######## Layer rules ######## +layerrule = xray 0, .* # layerrule = noanim, .* layerrule = noanim, selection layerrule = noanim, overview @@ -42,23 +43,23 @@ layerrule = blur, session layerrule = noanim, sideright layerrule = noanim, sideleft -# layerrule = blur, bar -# layerrule = ignorealpha 0.64, bar -# layerrule = blur, corner.* -# layerrule = ignorealpha 0.69, corner.* -# layerrule = blur, dock -# layerrule = ignorealpha 0.69, dock -# layerrule = blur, indicator.* -# layerrule = ignorealpha 0.69, indicator.* -# layerrule = blur, overview -# layerrule = ignorealpha 0.69, overview -# layerrule = blur, cheatsheet -# layerrule = ignorealpha 0.69, cheatsheet -# layerrule = blur, sideright -# layerrule = ignorealpha 0.69, sideright -# layerrule = blur, sideleft -# layerrule = ignorealpha 0.69, sideleft -# layerrule = blur, indicator* -# layerrule = ignorealpha 0.69, indicator* -# layerrule = blur, osk -# layerrule = ignorealpha 0.69, osk +layerrule = blur, bar +layerrule = ignorealpha 0.20, bar +layerrule = blur, corner.* +layerrule = ignorealpha 0.20, corner.* +layerrule = blur, dock +layerrule = ignorealpha 0.20, dock +layerrule = blur, indicator.* +layerrule = ignorealpha 0.20, indicator.* +layerrule = blur, overview +layerrule = ignorealpha 0.20, overview +layerrule = blur, cheatsheet +layerrule = ignorealpha 0.20, cheatsheet +layerrule = blur, sideright +layerrule = ignorealpha 0.20, sideright +layerrule = blur, sideleft +layerrule = ignorealpha 0.20, sideleft +layerrule = blur, indicator* +layerrule = ignorealpha 0.20, indicator* +layerrule = blur, osk +layerrule = ignorealpha 0.20, osk From 52de0cee5fb2296d64ca57337d26f4273e266984 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 20:09:34 +0530 Subject: [PATCH 156/517] Fix transperancy spelling, OOPS! --- .config/ags/modules/indicators/colorscheme.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.config/ags/modules/indicators/colorscheme.js b/.config/ags/modules/indicators/colorscheme.js index 0ee153905..2f20c563e 100644 --- a/.config/ags/modules/indicators/colorscheme.js +++ b/.config/ags/modules/indicators/colorscheme.js @@ -95,8 +95,8 @@ const schemeOptionsArr = [ const initColorMode = Utils.exec('bash -c "sed -n \'1p\' $HOME/.cache/ags/user/colormode.txt"'); const initColorVal = (initColorMode == "dark") ? 1 : 0; -const initTransperancy = Utils.exec('bash -c "sed -n \'2p\' $HOME/.cache/ags/user/colormode.txt"'); -const initTransperancyVal = (initTransperancy == "transparent") ? 1 : 0; +const initTransparency = Utils.exec('bash -c "sed -n \'2p\' $HOME/.cache/ags/user/colormode.txt"'); +const initTransparencyVal = (initTransparency == "transparent") ? 1 : 0; const initScheme = Utils.exec('bash -c "sed -n \'3p\' $HOME/.cache/ags/user/colormode.txt"'); const initSchemeIndex = calculateSchemeInitIndex(schemeOptionsArr, initScheme); @@ -118,11 +118,11 @@ const ColorSchemeSettings = () => Widget.Box({ }, }), ConfigToggle({ - name: 'Transperancy', - initValue: initTransperancyVal, + name: 'Transparency', + initValue: initTransparencyVal, onChange: (self, newValue) => { - let transperancy = newValue == 0 ? "opaque" : "transparent"; - execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && sed -i "2s/.*/${transperancy}/" ${GLib.get_user_cache_dir()}/ags/user/colormode.txt`]) + let transparency = newValue == 0 ? "opaque" : "transparent"; + execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_cache_dir()}/ags/user && sed -i "2s/.*/${transparency}/" ${GLib.get_user_cache_dir()}/ags/user/colormode.txt`]) .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`])) .catch(print); }, From 0fc9681eaee2453e70cd324702cc55e400730698 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 20:24:46 +0530 Subject: [PATCH 157/517] Hyprlang compatible comments --- .config/hypr/hyprland/rules.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/hypr/hyprland/rules.conf b/.config/hypr/hyprland/rules.conf index a55e8b99b..08643d942 100644 --- a/.config/hypr/hyprland/rules.conf +++ b/.config/hypr/hyprland/rules.conf @@ -1,4 +1,4 @@ -######## Window rules ######## +# ######## Window rules ######## #windowrule = noblur,.* # Disables blur for windows. Substantially improves performance. # windowrule = opacity 0.89 override 0.89 override, .* # Applies transparency to EVERY WINDOW @@ -17,7 +17,7 @@ windowrule=float,title:^(Open Folder)(.*)$ windowrule=float,title:^(Save As)(.*)$ windowrule=float,title:^(Library)(.*)$ -######## Layer rules ######## +# ######## Layer rules ######## layerrule = xray 0, .* # layerrule = noanim, .* layerrule = noanim, selection From 31bc5d8cefd38dcf3e91dc2959f09af4434dae34 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 19 Mar 2024 10:16:47 +0700 Subject: [PATCH 158/517] material color generation: use aur pkg, change shebang --- .../scripts/color_generation/generate_colors_material.py | 2 +- install.sh | 7 ------- scriptdata/dependencies.conf | 2 +- scriptdata/installers | 7 ------- 4 files changed, 2 insertions(+), 16 deletions(-) diff --git a/.config/ags/scripts/color_generation/generate_colors_material.py b/.config/ags/scripts/color_generation/generate_colors_material.py index 8ee4ebcdd..2cdf4b774 100755 --- a/.config/ags/scripts/color_generation/generate_colors_material.py +++ b/.config/ags/scripts/color_generation/generate_colors_material.py @@ -1,4 +1,4 @@ -#!/opt/materialyoucolor/bin/python3 +#!/usr/bin/env python3 from material_color_utilities_python import * from pathlib import Path import sys diff --git a/install.sh b/install.sh index defe08238..88cd13b3d 100755 --- a/install.sh +++ b/install.sh @@ -137,13 +137,6 @@ else ask_MicroTeX=true fi if $ask_MicroTeX;then showfun install-MicroTeX;v install-MicroTeX;fi -if $(test -d /opt/materialyoucolor); then - echo -e "\e[33m[$0]: Program \"MatertialYouColor-python\" already exists, no need to install.\e[0m" - echo -e "\e[34mYou can reinstall it in order to update to the latest version anyway.\e[0m" - ask_MaterialYouColor=$ask -else ask_MaterialYouColor=true -fi -showfun install-materialyoucolors;v install-materialyoucolors; ##################################################################################### printf "\e[36m[$0]: 3. Copying\e[97m\n" diff --git a/scriptdata/dependencies.conf b/scriptdata/dependencies.conf index 7ffeed1cf..2da18aa12 100644 --- a/scriptdata/dependencies.conf +++ b/scriptdata/dependencies.conf @@ -9,7 +9,7 @@ tinyxml2 gtkmm3 gtksourceviewmm cairomm ### Python # Add `python-setuptools-scm` and `python-wheel` explicitly to fix #197 -python-build python-material-color-utilities python-pillow python-poetry python-pywal python-setuptools-scm python-wheel +python-build python-material-color-utilities python-materialyoucolor-git python-pillow python-poetry python-pywal python-setuptools-scm python-wheel ### Basic graphic env hyprland-git xorg-xrandr diff --git a/scriptdata/installers b/scriptdata/installers index 1deeef85f..175da758c 100644 --- a/scriptdata/installers +++ b/scriptdata/installers @@ -101,10 +101,3 @@ install-MicroTeX (){ x sudo cp ./LaTeX /usr/local/bin/ x cd $base } - -install-materialyoucolors () { - x sudo python -m venv /opt/materialyoucolor - x source /opt/materialyoucolor/bin/activate - x sudo pip install material-color-utilities-python materialyoucolor - x deactivate -} From fd84ecc86c7fe64a1cf5a71f73ab4e3ab2f6df31 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 19 Mar 2024 17:46:32 +0700 Subject: [PATCH 159/517] add systemctl fallbacks for non-systemd systems --- .config/ags/modules/overview/miscfunctions.js | 6 +++--- .config/ags/modules/session/sessionscreen.js | 12 ++++++------ .config/hypr/hypridle.conf | 2 +- .config/hypr/hyprland/keybinds.conf | 4 ++-- .config/wlogout/layout | 10 +++++----- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.config/ags/modules/overview/miscfunctions.js b/.config/ags/modules/overview/miscfunctions.js index e13aa2ba0..be3ae6c10 100644 --- a/.config/ags/modules/overview/miscfunctions.js +++ b/.config/ags/modules/overview/miscfunctions.js @@ -57,13 +57,13 @@ export function launchCustomCommand(command) { Todo.add(args.slice(1).join(' ')); } else if (args[0] == '>shutdown') { // Shut down - execAsync([`bash`, `-c`, `systemctl poweroff`]).catch(print); + execAsync([`bash`, `-c`, `systemctl poweroff || loginctl poweroff`]).catch(print); } else if (args[0] == '>reboot') { // Reboot - execAsync([`bash`, `-c`, `systemctl reboot`]).catch(print); + execAsync([`bash`, `-c`, `systemctl reboot || loginctl reboot`]).catch(print); } else if (args[0] == '>sleep') { // Sleep - execAsync([`bash`, `-c`, `systemctl suspend`]).catch(print); + execAsync([`bash`, `-c`, `systemctl suspend || loginctl suspend`]).catch(print); } else if (args[0] == '>logout') { // Log out execAsync([`bash`, `-c`, `pkill Hyprland || pkill sway`]).catch(print); diff --git a/.config/ags/modules/session/sessionscreen.js b/.config/ags/modules/session/sessionscreen.js index eb2089c5b..e9c0d7115 100644 --- a/.config/ags/modules/session/sessionscreen.js +++ b/.config/ags/modules/session/sessionscreen.js @@ -61,13 +61,13 @@ const SessionButton = (name, icon, command, props = {}, colorid = 0) => { export default () => { // lock, logout, sleep - const lockButton = SessionButton('Lock', 'lock', () => { App.closeWindow('session'); execAsync(['loginctl', 'lock-session']) }, {}, 1); - const logoutButton = SessionButton('Logout', 'logout', () => { App.closeWindow('session'); execAsync(['bash', '-c', 'pkill Hyprland || pkill sway']) }, {}, 2); - const sleepButton = SessionButton('Sleep', 'sleep', () => { App.closeWindow('session'); execAsync('systemctl suspend') }, {}, 3); + const lockButton = SessionButton('Lock', 'lock', () => { App.closeWindow('session'); execAsync(['loginctl', 'lock-session']).catch(print) }, {}, 1); + const logoutButton = SessionButton('Logout', 'logout', () => { App.closeWindow('session'); execAsync(['bash', '-c', 'pkill Hyprland || pkill sway || pkill niri || loginctl terminate-user $USER']).catch(print) }, {}, 2); + const sleepButton = SessionButton('Sleep', 'sleep', () => { App.closeWindow('session'); execAsync(['bash', '-c', 'systemctl suspend || loginctl suspend']).catch(print) }, {}, 3); // hibernate, shutdown, reboot - const hibernateButton = SessionButton('Hibernate', 'downloading', () => { App.closeWindow('session'); execAsync('systemctl hibernate') }, {}, 4); - const shutdownButton = SessionButton('Shutdown', 'power_settings_new', () => { App.closeWindow('session'); execAsync('systemctl poweroff') }, {}, 5); - const rebootButton = SessionButton('Reboot', 'restart_alt', () => { App.closeWindow('session'); execAsync('systemctl reboot') }, {}, 6); + const hibernateButton = SessionButton('Hibernate', 'downloading', () => { App.closeWindow('session'); execAsync(['bash', '-c', 'systemctl hibernate || loginctl hibernate']).catch(print) }, {}, 4); + const shutdownButton = SessionButton('Shutdown', 'power_settings_new', () => { App.closeWindow('session'); execAsync(['bash', '-c', 'systemctl poweroff || loginctl poweroff']).catch(print) }, {}, 5); + const rebootButton = SessionButton('Reboot', 'restart_alt', () => { App.closeWindow('session'); execAsync(['bash', '-c', 'systemctl reboot || loginctl reboot']).catch(print) }, {}, 6); const cancelButton = SessionButton('Cancel', 'close', () => App.closeWindow('session'), { className: 'session-button-cancel' }, 7); const sessionDescription = Widget.Box({ diff --git a/.config/hypr/hypridle.conf b/.config/hypr/hypridle.conf index 3efbd108a..949768247 100644 --- a/.config/hypr/hypridle.conf +++ b/.config/hypr/hypridle.conf @@ -1,5 +1,5 @@ $lock_cmd = pidof hyprlock || hyprlock -$suspend_cmd = systemctl suspend +$suspend_cmd = systemctl suspend || loginctl suspend general { lock_cmd = $lock_cmd diff --git a/.config/hypr/hyprland/keybinds.conf b/.config/hypr/hyprland/keybinds.conf index 77bf038d4..d78fdd08e 100644 --- a/.config/hypr/hyprland/keybinds.conf +++ b/.config/hypr/hyprland/keybinds.conf @@ -35,7 +35,7 @@ bind = Super, Q, killactive, bind = Super+Alt, Space, togglefloating, bind = Shift+Super+Alt, Q, exec, hyprctl kill bind = Control+Shift+Alt, Delete, exec, pkill wlogout || wlogout -p layer-shell -bind = Control+Shift+Alt+Super, Delete, exec, systemctl poweroff +bind = Control+Shift+Alt+Super, Delete, exec, systemctl poweroff || loginctl poweroff # Screenshot, Record, OCR, Color picker, Clipboard history bind = Super+Shift+Alt, S, exec, grim -g "$(slurp)" - | swappy -f - @@ -65,7 +65,7 @@ bindl= ,XF86AudioPlay, exec, playerctl play-pause # Lock screen bind = Super, L, exec, loginctl lock-session bind = Super+Shift, L, exec, loginctl lock-session -bindl = Super+Shift, L, exec, sleep 0.1 && systemctl suspend +bindl = Super+Shift, L, exec, sleep 0.1 && systemctl suspend || loginctl suspend # App launcher bind = Control+Super, Slash, exec, pkill anyrun || anyrun diff --git a/.config/wlogout/layout b/.config/wlogout/layout index 6ef1eac60..c31abd945 100644 --- a/.config/wlogout/layout +++ b/.config/wlogout/layout @@ -6,31 +6,31 @@ } { "label" : "hibernate", - "action" : "systemctl hibernate", + "action" : "systemctl hibernate || loginctl hibernate", "text" : "save", "keybind" : "h" } { "label" : "logout", - "action" : "killall Hyprland", + "action" : "pkill Hyprland || pkill sway || pkill niri || loginctl terminate-user $USER", "text" : "logout", "keybind" : "e" } { "label" : "shutdown", - "action" : "systemctl poweroff", + "action" : "systemctl poweroff || loginctl poweroff", "text" : "power_settings_new", "keybind" : "s" } { "label" : "suspend", - "action" : "systemctl suspend", + "action" : "systemctl suspend || loginctl suspend", "text" : "bedtime", "keybind" : "u" } { "label" : "reboot", - "action" : "systemctl reboot", + "action" : "systemctl reboot || loginctl reboot", "text" : "restart_alt", "keybind" : "r" } From 0c032a47efef3941b7294edbb51ba5bdb226aaa1 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 19 Mar 2024 17:47:15 +0700 Subject: [PATCH 160/517] sidebar: minor tweaks --- .config/ags/modules/sideleft/apis/booru.js | 1 + .config/ags/modules/sideleft/apis/waifu.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.config/ags/modules/sideleft/apis/booru.js b/.config/ags/modules/sideleft/apis/booru.js index 5cf91f5ec..b4612e24a 100644 --- a/.config/ags/modules/sideleft/apis/booru.js +++ b/.config/ags/modules/sideleft/apis/booru.js @@ -369,6 +369,7 @@ const booruTags = Revealer({ child: Box({ className: 'spacing-h-5', children: [ + CommandButton('*'), CommandButton('hololive'), ] }) diff --git a/.config/ags/modules/sideleft/apis/waifu.js b/.config/ags/modules/sideleft/apis/waifu.js index dfe89061f..bca0415be 100644 --- a/.config/ags/modules/sideleft/apis/waifu.js +++ b/.config/ags/modules/sideleft/apis/waifu.js @@ -251,7 +251,7 @@ const WaifuImage = (taglist) => { else Utils.execAsync(['bash', '-c', `wget -O '${thisBlock.attribute.imagePath}' '${url}'`]) .then(showImage) .catch(print); - thisBlock.css = `background-color: mix(${darkMode ? 'black' : 'white'}, ${dominant_color}, 0.9);`; + thisBlock.css = `background-color: mix(${darkMode ? 'black' : 'white'}, ${dominant_color}, 0.97);`; }, }, children: [ @@ -319,7 +319,7 @@ export const waifuView = Scrollable({ // Always scroll to bottom with new content const adjustment = scrolledWindow.get_vadjustment(); adjustment.connect("changed", () => { - if(!chatEntry.hasFocus) return; + if (!chatEntry.hasFocus) return; adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size()); }) } From d686e588b8dce10538e1f53b6bf675707cef727d Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 19 Mar 2024 17:47:35 +0700 Subject: [PATCH 161/517] make border color less visible --- .config/ags/scss/_lib_mixins.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.config/ags/scss/_lib_mixins.scss b/.config/ags/scss/_lib_mixins.scss index b6e7b8bde..d2a750c27 100644 --- a/.config/ags/scss/_lib_mixins.scss +++ b/.config/ags/scss/_lib_mixins.scss @@ -197,10 +197,10 @@ $overlay2: mix($onSurface, rgba(0, 0, 0, 0), 40%); } @mixin elevation-border { - border-top: 1px solid mix($t_surface, $onSurface, 80%); - border-left: 1px solid mix($t_surface, $onSurface, 80%); - border-right: 1px solid mix($t_surface, $onSurface, 85%); - border-bottom: 1px solid mix($t_surface, $onSurface, 85%); + border-top: 1px solid $surfaceContainer; + border-left: 1px solid $surfaceContainer; + border-right: 1px solid $surfaceContainer; + border-bottom: 1px solid $surfaceContainer; } @mixin elevation-border-heavier { From 834f8dd208393e41ef3265287c43a9c976371b5e Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 19 Mar 2024 18:24:46 +0700 Subject: [PATCH 162/517] update styles --- .config/ags/modules/sideleft/apis/waifu.js | 1 + .config/ags/scss/_bar.scss | 2 - .config/ags/scss/_colors.scss | 22 ++---- .config/ags/scss/_dock.scss | 6 +- .config/ags/scss/_lib_classes.scss | 3 - .config/ags/scss/_lib_mixins.scss | 33 +------- .config/ags/scss/_material.scss | 92 +++++++++++----------- .config/ags/scss/_music.scss | 8 +- .config/ags/scss/_notifications.scss | 10 +-- .config/ags/scss/_overview.scss | 2 +- .config/ags/scss/_sidebars.scss | 58 ++++++-------- 11 files changed, 92 insertions(+), 145 deletions(-) diff --git a/.config/ags/modules/sideleft/apis/waifu.js b/.config/ags/modules/sideleft/apis/waifu.js index bca0415be..2dece7ebf 100644 --- a/.config/ags/modules/sideleft/apis/waifu.js +++ b/.config/ags/modules/sideleft/apis/waifu.js @@ -251,6 +251,7 @@ const WaifuImage = (taglist) => { else Utils.execAsync(['bash', '-c', `wget -O '${thisBlock.attribute.imagePath}' '${url}'`]) .then(showImage) .catch(print); + console.log(`background-color: mix(${darkMode ? 'black' : 'white'}, ${dominant_color}, 0.97);`); thisBlock.css = `background-color: mix(${darkMode ? 'black' : 'white'}, ${dominant_color}, 0.97);`; }, }, diff --git a/.config/ags/scss/_bar.scss b/.config/ags/scss/_bar.scss index e204c508a..dd33a3f96 100644 --- a/.config/ags/scss/_bar.scss +++ b/.config/ags/scss/_bar.scss @@ -388,10 +388,8 @@ $bar_ws_width_focus_active: 2.045rem; .bar-bluetooth-device { @include full-rounding; - @include element_decel; min-height: 1.032rem; min-width: 1.032rem; font-size: 1.032rem; - //color: $barspacerightOnLayer0; padding: 0.205rem 0.341rem; } diff --git a/.config/ags/scss/_colors.scss b/.config/ags/scss/_colors.scss index 77210262f..16fd24354 100644 --- a/.config/ags/scss/_colors.scss +++ b/.config/ags/scss/_colors.scss @@ -17,9 +17,7 @@ $onSuccessContainer: #0c1f13; } // Transparent versions -$t_background: transparentize($background, $transparentize_amount); $t_surface: transparentize($surface, $transparentize_surface_amount); -$t_surfaceVariant: transparentize($surfaceVariant, $transparentize_surface_amount); @if $transparent == True { $background: transparentize($background, $transparency); @@ -42,18 +40,6 @@ $actiontext: mix($onBackground, $background, 85%); $black: black; $white: white; -// Terminal colors -$termbg: $surfaceContainerHigh; -$termfg: $onSurfaceVariant; -$term0: $background; -$term1: $error; -$term2: $inversePrimary; -$term3: $onPrimaryContainer; -$term4: $onPrimaryContainer; -$term5: $onSecondaryContainer; -$term6: $primary; -$term7: $onSurfaceVariant; - /// Color mappings for more chaotic, dynamic colors like the average rice /// // General $layer0: $background; @@ -62,12 +48,14 @@ $layer0Hover: mix($layer0, $onLayer0, 85%); $layer0Active: $primary; $onLayer0Active: $onPrimary; $onLayer0Inactive: mix($onLayer0, $layer0, 70%); -$layer1: $surfaceContainer; +$layer1: $surfaceContainerLow; $onLayer1: $onSurface; $onLayer1Inactive: mix($onLayer1, $layer1, 45%); $onLayer1: $onSurfaceVariant; -$layer2: $secondaryContainer; -$onLayer2: $onSecondaryContainer; +$layer2: mix($surfaceContainer, $surfaceContainerHigh, 55%); +$onLayer2: $onSurface; +$layer3: $surfaceContainerHigh; +$onLayer3: $onSurface; $layer1Hover: mix($layer1, $onLayer1, 85%); $layer1Active: mix($layer1, $onLayer1, 70%); $layer2Hover: mix($layer2, $onLayer2, 90%); diff --git a/.config/ags/scss/_dock.scss b/.config/ags/scss/_dock.scss index 19779f5b2..c6768553a 100644 --- a/.config/ags/scss/_dock.scss +++ b/.config/ags/scss/_dock.scss @@ -1,7 +1,7 @@ .dock-bg { @include large-rounding; @include elevation2; - background-color: $t_background; + background-color: $layer0; padding: 0.682rem; } @@ -12,11 +12,11 @@ .dock-app-btn:hover, .dock-app-btn:focus { - background-color: mix($t_surface, $onSurface, 95%); + background-color: mix($surface, $onSurface, 90%); } .dock-app-btn:active { - background-color: mix($t_surface, $onSurface, 85%); + background-color: mix($surface, $onSurface, 85%); } .dock-app-icon { diff --git a/.config/ags/scss/_lib_classes.scss b/.config/ags/scss/_lib_classes.scss index 69262e7a8..7fb5a6512 100644 --- a/.config/ags/scss/_lib_classes.scss +++ b/.config/ags/scss/_lib_classes.scss @@ -523,6 +523,3 @@ .element-accel { @include element_accel; } -.page-move { - @include page_move; -} diff --git a/.config/ags/scss/_lib_mixins.scss b/.config/ags/scss/_lib_mixins.scss index d2a750c27..ae13c6815 100644 --- a/.config/ags/scss/_lib_mixins.scss +++ b/.config/ags/scss/_lib_mixins.scss @@ -174,26 +174,12 @@ $elevation_margin: 0.476rem; @mixin element_easeInOut { transition: 300ms cubic-bezier(0.85, 0, 0.15, 1); } -@mixin page_move { - transition: 500ms cubic-bezier(0.85, 0, 0.15, 1); -} - -@function tint($color, $percentage) { - @return mix(rgb(245, 250, 255), $color, $percentage); -} - -@function shade($color, $percentage) { - @return mix(rgb(0, 0, 0), $color, $percentage); -} - -$overlay1: mix($onSurface, rgba(0, 0, 0, 0), 25%); -$overlay2: mix($onSurface, rgba(0, 0, 0, 0), 40%); @mixin elevation-border-softer { - border-top: 1px solid mix($t_surface, $onSurface, 90%); - border-left: 1px solid mix($t_surface, $onSurface, 90%); - border-right: 1px solid mix($t_surface, $onSurface, 95%); - border-bottom: 1px solid mix($t_surface, $onSurface, 95%); + border-top: 1px solid mix($surface, $onSurface, 86%); + border-left: 1px solid mix($surface, $onSurface, 86%); + border-right: 1px solid mix($surface, $onSurface, 90%); + border-bottom: 1px solid mix($surface, $onSurface, 90%); } @mixin elevation-border { @@ -203,17 +189,6 @@ $overlay2: mix($onSurface, rgba(0, 0, 0, 0), 40%); border-bottom: 1px solid $surfaceContainer; } -@mixin elevation-border-heavier { - border-top: 1px solid mix($t_surface, $onSurface, 70%); - border-left: 1px solid mix($t_surface, $onSurface, 70%); - border-right: 1px solid mix($t_surface, $onSurface, 75%); - border-bottom: 1px solid mix($t_surface, $onSurface, 75%); -} - -@mixin elevation-border-transparent { - border-top: 1px solid transparent; -} - @mixin button-minsize { min-width: 2.727rem; min-height: 2.727rem; diff --git a/.config/ags/scss/_material.scss b/.config/ags/scss/_material.scss index ddb659b09..d7b7717dc 100644 --- a/.config/ags/scss/_material.scss +++ b/.config/ags/scss/_material.scss @@ -1,56 +1,56 @@ $darkmode: True; $transparent: False; -$primary_paletteKeyColor: #A76837; -$secondary_paletteKeyColor: #8F715C; -$tertiary_paletteKeyColor: #777A4B; -$neutral_paletteKeyColor: #81756D; -$neutral_variant_paletteKeyColor: #84746A; -$background: #19120D; -$onBackground: #F0DFD6; -$surface: #19120D; -$surfaceDim: #19120D; -$surfaceBright: #413731; +$primary_paletteKeyColor: #A504FF; +$secondary_paletteKeyColor: #8B6D8D; +$tertiary_paletteKeyColor: #9A678C; +$neutral_paletteKeyColor: #7D7480; +$neutral_variant_paletteKeyColor: #7E7382; +$background: #17111B; +$onBackground: #EBDFED; +$surface: #17111B; +$surfaceDim: #17111B; +$surfaceBright: #3E3741; $surfaceContainerLowest: #FFFFFF; -$surfaceContainerLow: #221A15; -$surfaceContainer: #261E18; -$surfaceContainerHigh: #312822; -$surfaceContainerHighest: #3C332D; -$onSurface: #F0DFD6; -$surfaceVariant: #52443B; -$onSurfaceVariant: #D6C3B7; -$inverseSurface: #F0DFD6; -$inverseOnSurface: #382F29; -$outline: #9F8D83; -$outlineVariant: #52443B; +$surfaceContainerLow: #1F1923; +$surfaceContainer: #241D27; +$surfaceContainerHigh: #2E2832; +$surfaceContainerHighest: #39323D; +$onSurface: #EBDFED; +$surfaceVariant: #4D4351; +$onSurfaceVariant: #CFC2D3; +$inverseSurface: #EBDFED; +$inverseOnSurface: #352E38; +$outline: #988D9D; +$outlineVariant: #4D4351; $shadow: #000000; $scrim: #000000; -$surfaceTint: #FFB783; -$primary: #FFB783; -$onPrimary: #4F2500; -$primaryContainer: #6D390B; -$onPrimaryContainer: #FFDCC5; -$inversePrimary: #8A5021; -$secondary: #E4BFA7; -$onSecondary: #422B1B; -$secondaryContainer: #5B412F; -$onSecondaryContainer: #FFDCC5; -$tertiary: #C8CA94; -$onTertiary: #30330B; -$tertiaryContainer: #919463; +$surfaceTint: #E2B6FF; +$primary: #E2B6FF; +$onPrimary: #4D007B; +$primaryContainer: #6D00AC; +$onPrimaryContainer: #F3DAFF; +$inversePrimary: #9000DF; +$secondary: #DEBCDF; +$onSecondary: #402843; +$secondaryContainer: #5A405D; +$onSecondaryContainer: #FDD9FD; +$tertiary: #F0B5DE; +$onTertiary: #4B2142; +$tertiaryContainer: #B680A7; $onTertiaryContainer: #000000; $error: #FFB4AB; $onError: #690005; $errorContainer: #93000A; $onErrorContainer: #FFDAD6; -$primaryFixed: #FFDCC5; -$primaryFixedDim: #FFB783; -$onPrimaryFixed: #301400; -$onPrimaryFixedVariant: #6D390B; -$secondaryFixed: #FFDCC5; -$secondaryFixedDim: #E4BFA7; -$onSecondaryFixed: #2A1708; -$onSecondaryFixedVariant: #5B412F; -$tertiaryFixed: #E4E6AE; -$tertiaryFixedDim: #C8CA94; -$onTertiaryFixed: #1B1D00; -$onTertiaryFixedVariant: #474920; +$primaryFixed: #F3DAFF; +$primaryFixedDim: #E2B6FF; +$onPrimaryFixed: #2E004D; +$onPrimaryFixedVariant: #6D00AC; +$secondaryFixed: #FCD7FB; +$secondaryFixedDim: #DEBCDF; +$onSecondaryFixed: #29132D; +$onSecondaryFixedVariant: #583E5B; +$tertiaryFixed: #FFD7F1; +$tertiaryFixedDim: #F0B5DE; +$onTertiaryFixed: #320C2C; +$onTertiaryFixedVariant: #64385A; diff --git a/.config/ags/scss/_music.scss b/.config/ags/scss/_music.scss index 8fcbdfea5..2d552ddb4 100644 --- a/.config/ags/scss/_music.scss +++ b/.config/ags/scss/_music.scss @@ -6,7 +6,7 @@ @import './lib_mixins'; $music_gradient1: mix($color1, $background, 50%); -// @if $darkmode ==true { +// @if $darkmode == True { // $music_gradient1: mix($color1, $background, 30%); // } @@ -17,7 +17,7 @@ $music_extra_transparentize: 0.15; $secondaryContainer: transparentize(mix(mix($background, $color2, 50%), $color6, 80%), 0.5); $onSecondaryContainer: mix($color7, $color2, 90%); -@if $darkmode ==false { +@if $darkmode == False { $onSecondaryContainer: mix($onSecondaryContainer, black, 50%); } @@ -28,7 +28,7 @@ $onSecondaryContainer: mix($color7, $color2, 90%); @include normal-rounding; // min-height: 7.159rem; min-width: 29.659rem; - background-color: $t_background; + background-color: $layer0; padding: 0rem 1.023rem; background: // Inspired by Amberol linear-gradient(127deg, transparentize($music_gradient1, $music_colorstart_transparentize), transparentize($music_gradient1, $music_colorstart_transparentize - $transparentize_amount + $music_extra_transparentize) 70.71%), @@ -46,7 +46,7 @@ $onSecondaryContainer: mix($color7, $color2, 90%); // margin: 1.023rem; min-width: 7.5rem; min-height: 7.5rem; - background-color: $t_surface; + background-color: $layer1; color: $onSecondaryContainer; } diff --git a/.config/ags/scss/_notifications.scss b/.config/ags/scss/_notifications.scss index 234072be3..53e87bee0 100644 --- a/.config/ags/scss/_notifications.scss +++ b/.config/ags/scss/_notifications.scss @@ -1,12 +1,10 @@ -$notif_surface: $surfaceContainer; - @mixin notif-rounding { @include normal-rounding; } .notif-low { @include notif-rounding; - background-color: $surfaceContainerHigh; + background-color: $layer2; color: $onSurfaceVariant; padding: $rounding_small; padding-right: $rounding_small + 0.545rem; @@ -14,7 +12,7 @@ $notif_surface: $surfaceContainer; .notif-normal { @include notif-rounding; - background-color: $surfaceContainerHigh; + background-color: $layer2; color: $onSurfaceVariant; padding: $rounding_small; padding-right: $rounding_small + 0.545rem; @@ -44,7 +42,7 @@ $notif_surface: $surfaceContainer; .popup-notif-low { @include notif-rounding; min-width: 30.682rem; - background-color: $notif_surface; + background-color: $layer2; border: 0.034rem solid $outlineVariant; color: $onSurfaceVariant; padding: $rounding_small; @@ -54,7 +52,7 @@ $notif_surface: $surfaceContainer; .popup-notif-normal { @include notif-rounding; min-width: 30.682rem; - background-color: $notif_surface; + background-color: $layer2; border: 0.034rem solid $outlineVariant; color: $onSurfaceVariant; padding: $rounding_small; diff --git a/.config/ags/scss/_overview.scss b/.config/ags/scss/_overview.scss index 137317abc..a0a3b48ad 100644 --- a/.config/ags/scss/_overview.scss +++ b/.config/ags/scss/_overview.scss @@ -118,7 +118,7 @@ @include menu_decel; background-color: $surfaceContainerHigh; color: $onSurface; - border: 0.068rem solid $outlineVariant; + border: 0.068rem solid $surfaceContainerHighest; } .overview-tasks-window:hover, diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss index ebb615dd4..fc25c3fb8 100644 --- a/.config/ags/scss/_sidebars.scss +++ b/.config/ags/scss/_sidebars.scss @@ -1,7 +1,4 @@ $sidebar_chat_textboxareaColor: mix($onSurfaceVariant, $surfaceVariant, 40%); -$textboxColor: $surfaceContainerHigh; -$system: $secondary; -$onSystem: $onSecondary; @mixin group-padding { padding: 0.341rem; @@ -52,12 +49,12 @@ $onSystem: $onSecondary; .sidebar-group { @include normal-rounding; @include group-padding; - background-color: $surfaceContainer; + background-color: $layer1; } .sidebar-group-nopad { @include normal-rounding; - background-color: $surfaceContainer; + background-color: $layer1; } .sidebar-group-invisible { @@ -71,7 +68,7 @@ $onSystem: $onSecondary; .sidebar-togglesbox { @include full-rounding; @include group-padding; - background-color: $surfaceContainer; + background-color: $layer1; } .sidebar-iconbutton { @@ -263,8 +260,8 @@ $onSystem: $onSecondary; @include full-rounding; @include element_decel; padding: 0rem 0.682rem; - background-color: $surfaceContainer; - color: $outline; + background-color: $surfaceContainerHigh; + color: $onSurface; } .sidebar-calendar-monthyear-btn:hover, @@ -281,7 +278,7 @@ $onSystem: $onSecondary; @include element_decel; min-width: 2.045rem; min-height: 2.045rem; - background-color: $surfaceContainer; + background-color: $surfaceContainerHigh; color: $outline; } @@ -329,7 +326,7 @@ $onSystem: $onSecondary; .sidebar-todo-new { @include full-rounding; @include element_decel; - background-color: $textboxColor; + background-color: $surfaceContainerHigh; color: $onSurfaceVariant; margin: 0.341rem; padding: 0.205rem 0.545rem; @@ -403,7 +400,7 @@ $onSystem: $onSecondary; .sidebar-module { @include normal-rounding; @include group-padding; - background-color: $surfaceContainer; + background-color: $layer1; padding: 0.682rem; } @@ -422,7 +419,7 @@ $onSystem: $onSecondary; .sidebar-module-scripts-button { @include full-rounding; @include icon-material; - background-color: $surfaceContainer; + background-color: $layer1; min-width: 1.705rem; min-height: 1.705rem; @@ -498,7 +495,7 @@ $colorpicker_rounding: 0.341rem; .sidebar-chat-apiswitcher { @include full-rounding; @include group-padding; - background-color: $surfaceContainer; + background-color: $layer1; } .sidebar-chat-apiswitcher-icon { @@ -518,7 +515,7 @@ $colorpicker_rounding: 0.341rem; .sidebar-chat-providerswitcher { @include small-rounding; padding: 0.477rem 0.682rem; - background-color: $textboxColor; + background-color: $surfaceContainerHigh; color: $onSurfaceVariant; } @@ -534,7 +531,7 @@ $colorpicker_rounding: 0.341rem; .sidebar-chat-textarea { @include normal-rounding; - background-color: $textboxColor; + background-color: $surfaceContainerHigh; color: $onSurfaceVariant; padding: 0.682rem; } @@ -644,33 +641,26 @@ $colorpicker_rounding: 0.341rem; margin: 0rem 0.682rem; padding: 0.682rem; - @if $darkmode ==true { - background-color: white; + @if $darkmode == True { + background-color: #e6e6e6; } - color: $onBackground; - // background-color: $termbg; } .sidebar-chat-codeblock { @include normal-rounding; // @include elevation2; - background-color: $termbg; - color: $termfg; + background-color: $layer2; + color: $onLayer2; margin: 0rem 0.682rem; - border: 0.068rem solid $outlineVariant; } .sidebar-chat-codeblock-topbar { @include mainfont; - margin: 0.273rem; - margin-bottom: 0rem; - background-color: $secondaryContainer; - color: $onSecondaryContainer; - border-radius: $rounding_medium - 0.273rem; - border: 0.068rem solid $outlineVariant; - border-top-left-radius: $rounding_small + 0.068rem; - border-top-right-radius: $rounding_small + 0.068rem; + background-color: $layer3; + color: $onLayer3; + border-top-left-radius: $rounding_small; + border-top-right-radius: $rounding_small; padding: 0.341rem 0.477rem; } @@ -687,11 +677,11 @@ $colorpicker_rounding: 0.341rem; .sidebar-chat-codeblock-topbar-btn:hover, .sidebar-chat-codeblock-topbar-btn:focus { - background-color: mix($secondaryContainer, $onSecondaryContainer, 90%); + background-color: $surfaceBright; } .sidebar-chat-codeblock-topbar-btn:active { - background-color: mix($secondaryContainer, $onSecondaryContainer, 80%); + background-color: $surfaceVariant; } .sidebar-chat-codeblock-code { @@ -737,7 +727,7 @@ $colorpicker_rounding: 0.341rem; .sidebar-chat-chip-action { @include element_decel; - background-color: $textboxColor; + background-color: $surfaceContainerHigh; color: $onSurfaceVariant; } @@ -759,7 +749,7 @@ $colorpicker_rounding: 0.341rem; @include element_decel; @include small-rounding; padding: 0.341rem 0.477rem; - background-color: $textboxColor; + background-color: $surfaceContainerHigh; color: $onSurfaceVariant; } From a5f55a6a1ed555bc43001aa6005a89adde7dcd2d Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 19 Mar 2024 19:18:05 +0700 Subject: [PATCH 163/517] update styles --- .config/ags/scss/_colors.scss | 4 ++-- .config/ags/scss/_lib_mixins.scss | 7 ------- .config/ags/scss/_overview.scss | 6 +++--- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/.config/ags/scss/_colors.scss b/.config/ags/scss/_colors.scss index 16fd24354..4cefdc049 100644 --- a/.config/ags/scss/_colors.scss +++ b/.config/ags/scss/_colors.scss @@ -45,8 +45,8 @@ $white: white; $layer0: $background; $onLayer0: $onBackground; $layer0Hover: mix($layer0, $onLayer0, 85%); -$layer0Active: $primary; -$onLayer0Active: $onPrimary; +$layer0Active: $surfaceContainerHigh; +$onLayer0Active: $onSurface; $onLayer0Inactive: mix($onLayer0, $layer0, 70%); $layer1: $surfaceContainerLow; $onLayer1: $onSurface; diff --git a/.config/ags/scss/_lib_mixins.scss b/.config/ags/scss/_lib_mixins.scss index ae13c6815..a0d1de2de 100644 --- a/.config/ags/scss/_lib_mixins.scss +++ b/.config/ags/scss/_lib_mixins.scss @@ -75,13 +75,6 @@ $rounding_large: 1.705rem; $elevation_margin: 0.476rem; -@mixin elevation-safe { - background: $surface; - color: $onSurface; - box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.69); - margin: $elevation_margin; -} - @mixin elevation2 { box-shadow: 0px 2px 3px transparentize($shadow, 0.55); margin: $elevation_margin; diff --git a/.config/ags/scss/_overview.scss b/.config/ags/scss/_overview.scss index a0a3b48ad..78b130b84 100644 --- a/.config/ags/scss/_overview.scss +++ b/.config/ags/scss/_overview.scss @@ -53,8 +53,8 @@ @include elevation2; min-width: 28.773rem; padding: 0.682rem; - background-color: $surfaceContainerLow; - color: $onSurface; + background-color: $layer0; + color: $onLayer0; } .overview-search-results-icon { @@ -105,7 +105,7 @@ @include normal-rounding; // @include elevation-border; margin: 0.341rem; - background-color: $surfaceContainerLow; + background-color: $layer1; } .overview-tasks-workspace-number { From 230ed18851daa73b33844f13bf76d4b73516d39f Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 19 Mar 2024 19:18:16 +0700 Subject: [PATCH 164/517] use vibrant color mode by default --- .config/ags/scripts/color_generation/colorgen.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/ags/scripts/color_generation/colorgen.sh b/.config/ags/scripts/color_generation/colorgen.sh index 7ef167449..7f40b79d5 100755 --- a/.config/ags/scripts/color_generation/colorgen.sh +++ b/.config/ags/scripts/color_generation/colorgen.sh @@ -14,11 +14,11 @@ materialscheme="tonalspot" if [ ! -f $colormodefile ]; then echo "dark" > $colormodefile echo "opaque" >> $colormodefile - echo "tonalspot" >> $colormodefile + echo "vibrant" >> $colormodefile elif [[ $(wc -l < $colormodefile) -ne 3 || $(wc -w < $colormodefile) -ne 3 ]]; then echo "dark" > $colormodefile echo "opaque" >> $colormodefile - echo "tonalspot" >> $colormodefile + echo "vibrant" >> $colormodefile else lightdark=$(sed -n '1p' $colormodefile) transparency=$(sed -n '2p' $colormodefile) From 2850e97b4534892dc41a418c041af652c34be85d Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 19 Mar 2024 19:20:25 +0700 Subject: [PATCH 165/517] use vibrant material scheme by default --- .config/ags/modules/indicators/colorscheme.js | 4 ++-- .config/ags/scripts/color_generation/colorgen.sh | 2 +- .../scripts/color_generation/generate_colors_material.py | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.config/ags/modules/indicators/colorscheme.js b/.config/ags/modules/indicators/colorscheme.js index 2f20c563e..e7b0a754f 100644 --- a/.config/ags/modules/indicators/colorscheme.js +++ b/.config/ags/modules/indicators/colorscheme.js @@ -65,9 +65,9 @@ const ColorSchemeSettingsRevealer = () => { }); } -function calculateSchemeInitIndex(optionsArr, searchValue = 'tonalspot') { +function calculateSchemeInitIndex(optionsArr, searchValue = 'vibrant') { if (searchValue == '') - searchValue = 'tonalspot'; + searchValue = 'vibrant'; const flatArray = optionsArr.flatMap(subArray => subArray); const result = flatArray.findIndex(element => element.value === searchValue); const rowIndex = Math.floor(result / optionsArr[0].length); diff --git a/.config/ags/scripts/color_generation/colorgen.sh b/.config/ags/scripts/color_generation/colorgen.sh index 7f40b79d5..aeac018a4 100755 --- a/.config/ags/scripts/color_generation/colorgen.sh +++ b/.config/ags/scripts/color_generation/colorgen.sh @@ -10,7 +10,7 @@ fi colormodefile="$HOME/.cache/ags/user/colormode.txt" lightdark="dark" transparency="opaque" -materialscheme="tonalspot" +materialscheme="vibrant" if [ ! -f $colormodefile ]; then echo "dark" > $colormodefile echo "opaque" >> $colormodefile diff --git a/.config/ags/scripts/color_generation/generate_colors_material.py b/.config/ags/scripts/color_generation/generate_colors_material.py index 2cdf4b774..6fa481b9f 100755 --- a/.config/ags/scripts/color_generation/generate_colors_material.py +++ b/.config/ags/scripts/color_generation/generate_colors_material.py @@ -21,7 +21,7 @@ args = parser.parse_args() export_color_file=os.environ['HOME']+"/.cache/ags/user/color.txt" # Default scheme -> Tonal Spot (Android Default) -from materialyoucolor.scheme.scheme_tonal_spot import SchemeTonalSpot as Scheme +from materialyoucolor.scheme.scheme_vibrant import SchemeVibrant as Scheme if args.scheme is not None: if args.scheme == 'fruitsalad': from materialyoucolor.scheme.scheme_fruit_salad import SchemeFruitSalad as Scheme @@ -31,8 +31,8 @@ if args.scheme is not None: from materialyoucolor.scheme.scheme_monochrome import SchemeMonochrome as Scheme elif args.scheme == 'rainbow': from materialyoucolor.scheme.scheme_rainbow import SchemeRainbow as Scheme - elif args.scheme == 'vibrant': - from materialyoucolor.scheme.scheme_vibrant import SchemeVibrant as Scheme + elif args.scheme == 'tonalspot': + from materialyoucolor.scheme.scheme_tonal_spot import SchemeTonalSpot as Scheme elif args.scheme == 'neutral': from materialyoucolor.scheme.scheme_neutral import SchemeNeutral as Scheme elif args.scheme == 'fidelity': From e56657aa80105d7167ddf5b462b741c57ef083f2 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Tue, 19 Mar 2024 19:47:47 +0700 Subject: [PATCH 166/517] hyprland: disable app blur --- .config/hypr/hyprland/rules.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/hypr/hyprland/rules.conf b/.config/hypr/hyprland/rules.conf index 08643d942..9246fde0c 100644 --- a/.config/hypr/hyprland/rules.conf +++ b/.config/hypr/hyprland/rules.conf @@ -1,5 +1,5 @@ # ######## Window rules ######## -#windowrule = noblur,.* # Disables blur for windows. Substantially improves performance. +windowrule = noblur,.* # Disables blur for windows. Substantially improves performance. # windowrule = opacity 0.89 override 0.89 override, .* # Applies transparency to EVERY WINDOW windowrule = float, ^(blueberry.py)$ From ccf010570fca054efe9fa2b1cc5150e0d0d2504d Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Tue, 19 Mar 2024 21:17:00 +0530 Subject: [PATCH 167/517] Scheme color dependendent on music coverart Fix switching schemes (after changing music), the color is taken from the music coverart rather than the wallpaper --- .config/ags/scripts/color_generation/colorgen.sh | 8 ++++++-- .../color_generation/generate_colors_material.py | 13 +++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.config/ags/scripts/color_generation/colorgen.sh b/.config/ags/scripts/color_generation/colorgen.sh index aeac018a4..4842ac7b0 100755 --- a/.config/ags/scripts/color_generation/colorgen.sh +++ b/.config/ags/scripts/color_generation/colorgen.sh @@ -33,13 +33,17 @@ fi cd "$HOME/.config/ags/scripts/" || exit if [[ "$1" = "#"* ]]; then # this is a color - color_generation/generate_colors_material.py --color "$1" --mode "$lightdark" --scheme "$materialscheme" --transparency "$transparency" > "$HOME"/.cache/ags/user/generated/material_colors.scss + color_generation/generate_colors_material.py --color "$1" \ + --mode "$lightdark" --scheme "$materialscheme" --transparency "$transparency" \ + > "$HOME"/.cache/ags/user/generated/material_colors.scss if [ "$2" = "--apply" ]; then cp "$HOME"/.cache/ags/user/generated/material_colors.scss "$HOME/.config/ags/scss/_material.scss" color_generation/applycolor.sh fi elif [ "$backend" = "material" ]; then - color_generation/generate_colors_material.py --path "$1" --mode "$lightdark" --scheme "$materialscheme" --transparency "$transparency" > "$HOME"/.cache/ags/user/generated/material_colors.scss + color_generation/generate_colors_material.py --path "$1" \ + --mode "$lightdark" --scheme "$materialscheme" --transparency "$transparency" --cache '.cache/ags/user/color.txt' \ + > "$HOME"/.cache/ags/user/generated/material_colors.scss if [ "$2" = "--apply" ]; then cp "$HOME"/.cache/ags/user/generated/material_colors.scss "$HOME/.config/ags/scss/_material.scss" color_generation/applycolor.sh diff --git a/.config/ags/scripts/color_generation/generate_colors_material.py b/.config/ags/scripts/color_generation/generate_colors_material.py index 6fa481b9f..e2d2890f1 100755 --- a/.config/ags/scripts/color_generation/generate_colors_material.py +++ b/.config/ags/scripts/color_generation/generate_colors_material.py @@ -12,14 +12,13 @@ from materialyoucolor.dynamiccolor.material_dynamic_colors import MaterialDynami parser = argparse.ArgumentParser(description='Color generation script') parser.add_argument('--path', type=str, default=None, help='generate colorscheme from image') parser.add_argument('--color', type=str, default=None, help='generate colorscheme from color') -parser.add_argument('--mode', type=str , choices=['dark', 'light'], default='dark', help='dark or light mode') +parser.add_argument('--mode', type=str, choices=['dark', 'light'], default='dark', help='dark or light mode') parser.add_argument('--scheme', type=str, default=None, help='material scheme to use') -parser.add_argument('--transparency', type=str , choices=['opaque', 'transparent'], default='opaque', help='enable transparency') +parser.add_argument('--transparency', type=str, choices=['opaque', 'transparent'], default='opaque', help='enable transparency') +parser.add_argument('--cache', type=str, default=None, help='file path (relative to home) to store the generated color') parser.add_argument('--debug', action='store_true', default=False, help='debug mode') args = parser.parse_args() -export_color_file=os.environ['HOME']+"/.cache/ags/user/color.txt" - # Default scheme -> Tonal Spot (Android Default) from materialyoucolor.scheme.scheme_vibrant import SchemeVibrant as Scheme if args.scheme is not None: @@ -73,8 +72,10 @@ if args.path is not None: hsize = int((float(img.size[1])*float(wpercent))) img = img.resize((basewidth,hsize),Image.Resampling.LANCZOS) argb = sourceColorFromImage(img) - with open(export_color_file, 'w') as file: - file.write(argb_to_hex(argb)) + if args.cache is not None: + export_color_file=os.environ['HOME'] + "/" + args.cache + with open(export_color_file, 'w') as file: + file.write(argb_to_hex(argb)) elif args.color is not None: argb = hex_to_argb(args.color) From f6fa86e26aba99c224173cfed1deafe01d718921 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 20 Mar 2024 18:38:32 +0700 Subject: [PATCH 168/517] fix mpris without plasma browser integration --- .../ags/modules/indicators/musiccontrols.js | 50 +------------------ 1 file changed, 1 insertion(+), 49 deletions(-) diff --git a/.config/ags/modules/indicators/musiccontrols.js b/.config/ags/modules/indicators/musiccontrols.js index 61be3d142..7148dfc57 100644 --- a/.config/ags/modules/indicators/musiccontrols.js +++ b/.config/ags/modules/indicators/musiccontrols.js @@ -395,57 +395,9 @@ export default () => Revealer({ transitionDuration: userOptions.animations.durationLarge, revealChild: false, child: Box({ - setup: (self) => self.hook(Mpris, box => { - box.children.forEach(child => { - child.destroy(); - child = null; - }); - Mpris.players.forEach((player, i) => { - if (isRealPlayer(player)) { - const newInstance = MusicControlsWidget(player); - box.add(newInstance); - } - }); - }, 'notify::players'), + children: Mpris.bind("players").as(p => p.map(MusicControlsWidget)) }), setup: (self) => self.hook(showMusicControls, (revealer) => { revealer.revealChild = showMusicControls.value; }), }) - -// export default () => MarginRevealer({ -// transition: 'slide_down', -// revealChild: false, -// showClass: 'osd-show', -// hideClass: 'osd-hide', -// child: Box({ -// setup: (self) => self.hook(Mpris, box => { -// let foundPlayer = false; -// Mpris.players.forEach((player, i) => { -// if (isRealPlayer(player)) { -// foundPlayer = true; -// box.children.forEach(child => { -// child.destroy(); -// child = null; -// }); -// const newInstance = MusicControlsWidget(player); -// box.children = [newInstance]; -// } -// }); - -// if (!foundPlayer) { -// const children = box.get_children(); -// for (let i = 0; i < children.length; i++) { -// const child = children[i]; -// child.destroy(); -// child = null; -// } -// return; -// } -// }, 'notify::players'), -// }), -// setup: (self) => self.hook(showMusicControls, (revealer) => { -// if (showMusicControls.value) revealer.attribute.show(); -// else revealer.attribute.hide(); -// }), -// }) From 92ae514ca741241212340fecc16fa0d400f62ba5 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 20 Mar 2024 18:47:52 +0700 Subject: [PATCH 169/517] avoid duplicate music control --- .config/ags/modules/indicators/musiccontrols.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/ags/modules/indicators/musiccontrols.js b/.config/ags/modules/indicators/musiccontrols.js index 7148dfc57..6e0953567 100644 --- a/.config/ags/modules/indicators/musiccontrols.js +++ b/.config/ags/modules/indicators/musiccontrols.js @@ -20,7 +20,6 @@ var lastCoverPath = ''; function isRealPlayer(player) { return ( - !player.busName.startsWith('org.mpris.MediaPlayer2.firefox') && // Firefox mpris dbus is useless !player.busName.startsWith('org.mpris.MediaPlayer2.playerctld') && // Doesn't have cover art !player.busName.endsWith('.mpd') // Non-instance mpd bus ); @@ -395,7 +394,8 @@ export default () => Revealer({ transitionDuration: userOptions.animations.durationLarge, revealChild: false, child: Box({ - children: Mpris.bind("players").as(p => p.map(MusicControlsWidget)) + children: Mpris.bind("players") + .as(players => players.map((player) => (isRealPlayer(player) ? MusicControlsWidget(player) : null))) }), setup: (self) => self.hook(showMusicControls, (revealer) => { revealer.revealChild = showMusicControls.value; From 85fc34161781fce6043425a40be910cbfabbf819 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 20 Mar 2024 18:52:31 +0700 Subject: [PATCH 170/517] music controls: not spawn dupes if there's plasma integration --- .config/ags/modules/.miscutils/system.js | 1 + .config/ags/modules/indicators/musiccontrols.js | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.config/ags/modules/.miscutils/system.js b/.config/ags/modules/.miscutils/system.js index 1c7f236e7..185a8149b 100644 --- a/.config/ags/modules/.miscutils/system.js +++ b/.config/ags/modules/.miscutils/system.js @@ -10,6 +10,7 @@ export const hasFlatpak = !!exec(`bash -c 'command -v flatpak'`); const LIGHTDARK_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/colormode.txt`; const colorMode = Utils.exec('bash -c "sed -n \'1p\' $HOME/.cache/ags/user/colormode.txt"'); export let darkMode = !(Utils.readFile(LIGHTDARK_FILE_LOCATION).trim() == 'light'); +export const hasPlasmaIntegration = !!Utils.exec('bash -c "command -v plasma-browser-integration-host"'); export const getDistroIcon = () => { // Arches diff --git a/.config/ags/modules/indicators/musiccontrols.js b/.config/ags/modules/indicators/musiccontrols.js index 6e0953567..f315d2b6e 100644 --- a/.config/ags/modules/indicators/musiccontrols.js +++ b/.config/ags/modules/indicators/musiccontrols.js @@ -9,7 +9,7 @@ const { Box, EventBox, Icon, Scrollable, Label, Button, Revealer } = Widget; import { fileExists } from '../.miscutils/files.js'; import { AnimatedCircProg } from "../.commonwidgets/cairo_circularprogress.js"; import { showMusicControls } from '../../variables.js'; -import { darkMode } from '../.miscutils/system.js'; +import { darkMode, hasPlasmaIntegration } from '../.miscutils/system.js'; const COMPILED_STYLE_DIR = `${GLib.get_user_cache_dir()}/ags/user/generated` const LIGHTDARK_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/colormode.txt`; @@ -20,6 +20,7 @@ var lastCoverPath = ''; function isRealPlayer(player) { return ( + (hasPlasmaIntegration && !player.busName.startsWith('org.mpris.MediaPlayer2.firefox')) && // Firefox mpris dbus is useless !player.busName.startsWith('org.mpris.MediaPlayer2.playerctld') && // Doesn't have cover art !player.busName.endsWith('.mpd') // Non-instance mpd bus ); From 43de0bb0aac0c8bb13577c7542440ad93a5b7ccc Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 20 Mar 2024 19:08:46 +0700 Subject: [PATCH 171/517] music controls: fix wrong dbus check, show time for chromium + no plasma integration --- .config/ags/modules/indicators/musiccontrols.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.config/ags/modules/indicators/musiccontrols.js b/.config/ags/modules/indicators/musiccontrols.js index f315d2b6e..4da8cceb2 100644 --- a/.config/ags/modules/indicators/musiccontrols.js +++ b/.config/ags/modules/indicators/musiccontrols.js @@ -20,9 +20,13 @@ var lastCoverPath = ''; function isRealPlayer(player) { return ( - (hasPlasmaIntegration && !player.busName.startsWith('org.mpris.MediaPlayer2.firefox')) && // Firefox mpris dbus is useless - !player.busName.startsWith('org.mpris.MediaPlayer2.playerctld') && // Doesn't have cover art - !player.busName.endsWith('.mpd') // Non-instance mpd bus + // Remove unecessary native buses from browsers if there's plasma integration + !(hasPlasmaIntegration && player.busName.startsWith('org.mpris.MediaPlayer2.firefox')) && + !(hasPlasmaIntegration && player.busName.startsWith('org.mpris.MediaPlayer2.chromium')) && + // playerctld just copies other buses and we don't need duplicates + !player.busName.startsWith('org.mpris.MediaPlayer2.playerctld') && + // Non-instance mpd bus + !player.busName.endsWith('.mpd') ); } @@ -381,7 +385,7 @@ const MusicControlsWidget = (player) => Box({ setup: (box) => { box.pack_start(TrackControls({ player: player }), false, false, 0); box.pack_end(PlayState({ player: player }), false, false, 0); - box.pack_end(TrackTime({ player: player }), false, false, 0) + if(hasPlasmaIntegration || player.busName.startsWith('org.mpris.MediaPlayer2.chromium')) box.pack_end(TrackTime({ player: player }), false, false, 0) // box.pack_end(TrackSource({ vpack: 'center', player: player }), false, false, 0); } }) From 11d8d1a994fd57e08cd06da24b996f56c89eb1f4 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 20 Mar 2024 22:11:20 +0700 Subject: [PATCH 172/517] wallpaper picker: add preview --- .config/ags/scripts/color_generation/switchwall.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/scripts/color_generation/switchwall.sh b/.config/ags/scripts/color_generation/switchwall.sh index fe4bca97a..0094c8e2f 100755 --- a/.config/ags/scripts/color_generation/switchwall.sh +++ b/.config/ags/scripts/color_generation/switchwall.sh @@ -6,7 +6,7 @@ if [ "$1" == "--noswitch" ]; then else # Select and set image (hyprland) cd "$HOME/Pictures" - imgpath=$(yad --width 1200 --height 800 --file --title='Choose wallpaper') + imgpath=$(yad --width 1200 --height 800 --file --title='Choose wallpaper' --add-preview --large-preview) screensizey=$(xrandr --current | grep '*' | uniq | awk '{print $1}' | cut -d 'x' -f2 | head -1) cursorposx=$(hyprctl cursorpos -j | gojq '.x' 2>/dev/null) || cursorposx=960 cursorposy=$(hyprctl cursorpos -j | gojq '.y' 2>/dev/null) || cursorposy=540 From bcecb02d7923fc772c37162af29639d2615da9d1 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 20 Mar 2024 22:49:25 +0700 Subject: [PATCH 173/517] sidebar: ai: latex: support dark mode --- .config/ags/modules/.miscutils/md2pango.js | 2 +- .config/ags/modules/.miscutils/system.js | 2 +- .config/ags/modules/sideleft/apis/ai_chatmessage.js | 12 +++++++++--- .config/ags/modules/sideleft/apis/waifu.js | 1 - .config/ags/scss/_sidebars.scss | 3 --- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.config/ags/modules/.miscutils/md2pango.js b/.config/ags/modules/.miscutils/md2pango.js index 1c868757b..fa059fed2 100644 --- a/.config/ags/modules/.miscutils/md2pango.js +++ b/.config/ags/modules/.miscutils/md2pango.js @@ -84,6 +84,6 @@ console.log('uwu'); - Random instruction thing - To update arch lincox, run \`sudo pacman -Syu\` \`\`\`tex -\\frac{d}{dx} \\left( \\frac{x-438}{x^2+23x-7} \\right) = \\frac{-x^2 + 869}{(x^2+23x-7)^2} hmmmmmm \\frac{d}{dx} \\left( \\frac{x-438}{x^2+23x-7} \\right) = \\frac{-x^2 + 869}{(x^2+23x-7)^2} +\\frac{d}{dx} \\left( \\frac{x-438}{x^2+23x-7} \\right) = \\frac{-x^2 + 869}{(x^2+23x-7)^2} \\\\ \\frac{d}{dx} \\left( \\frac{x-438}{x^2+23x-7} \\right) = \\frac{-x^2 + 869}{(x^2+23x-7)^2} \`\`\` `; \ No newline at end of file diff --git a/.config/ags/modules/.miscutils/system.js b/.config/ags/modules/.miscutils/system.js index 185a8149b..57ea2a7d2 100644 --- a/.config/ags/modules/.miscutils/system.js +++ b/.config/ags/modules/.miscutils/system.js @@ -9,7 +9,7 @@ export const hasFlatpak = !!exec(`bash -c 'command -v flatpak'`); const LIGHTDARK_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/colormode.txt`; const colorMode = Utils.exec('bash -c "sed -n \'1p\' $HOME/.cache/ags/user/colormode.txt"'); -export let darkMode = !(Utils.readFile(LIGHTDARK_FILE_LOCATION).trim() == 'light'); +export let darkMode = !(Utils.readFile(LIGHTDARK_FILE_LOCATION).split('\n')[0].trim() == 'light'); export const hasPlasmaIntegration = !!Utils.exec('bash -c "command -v plasma-browser-integration-host"'); export const getDistroIcon = () => { diff --git a/.config/ags/modules/sideleft/apis/ai_chatmessage.js b/.config/ags/modules/sideleft/apis/ai_chatmessage.js index d7148984b..509490055 100644 --- a/.config/ags/modules/sideleft/apis/ai_chatmessage.js +++ b/.config/ags/modules/sideleft/apis/ai_chatmessage.js @@ -7,12 +7,12 @@ const { Box, Button, Label, Icon, Scrollable } = Widget; const { execAsync, exec } = Utils; import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; import md2pango from '../../.miscutils/md2pango.js'; +import { darkMode } from "../../.miscutils/system.js"; const LATEX_DIR = `${GLib.get_user_cache_dir()}/ags/media/latex`; const CUSTOM_SOURCEVIEW_SCHEME_PATH = `${App.configDir}/assets/themes/sourceviewtheme.xml`; const CUSTOM_SCHEME_ID = 'custom'; const USERNAME = GLib.get_user_name(); -Gtk.IconTheme.get_default().append_search_path(LATEX_DIR); /////////////////////// Custom source view colorscheme ///////////////////////// @@ -77,11 +77,12 @@ const TextBlock = (content = '') => Label({ Utils.execAsync(['bash', '-c', `rm ${LATEX_DIR}/*`]) .then(() => Utils.execAsync(['bash', '-c', `mkdir -p ${LATEX_DIR}`])) - .catch(() => {}); + .catch(() => { }); const Latex = (content = '') => { const latexViewArea = Box({ // vscroll: 'never', // hscroll: 'automatic', + homogeneous: true, attribute: { render: async (self, text) => { if (text.length == 0) return; @@ -91,6 +92,7 @@ const Latex = (content = '') => { const timeSinceEpoch = Date.now(); const fileName = `${timeSinceEpoch}.tex`; const outFileName = `${timeSinceEpoch}-symbolic.svg`; + const outIconName = `${timeSinceEpoch}-symbolic`; const scriptFileName = `${timeSinceEpoch}-render.sh`; const filePath = `${LATEX_DIR}/${fileName}`; const outFilePath = `${LATEX_DIR}/${outFileName}`; @@ -104,13 +106,17 @@ const Latex = (content = '') => { const renderScript = `#!/usr/bin/env bash text=$(cat ${filePath} | sed 's/$/ \\\\\\\\/g' | sed 's/&=/=/g') LaTeX -headless -input="$text" -output=${outFilePath} -textsize=${fontSize * 1.1} -padding=0 -maxwidth=${latexViewArea.get_allocated_width() * 0.85} +sed -i 's/fill="rgb(0%, 0%, 0%)"/style="fill:#000000"/g' ${outFilePath} +sed -i 's/stroke="rgb(0%, 0%, 0%)"/stroke="${darkMode ? '#ffffff' : '#000000'}"/g' ${outFilePath} `; Utils.writeFile(renderScript, scriptFilePath).catch(print); Utils.exec(`chmod a+x ${scriptFilePath}`) Utils.timeout(100, () => { Utils.exec(`bash ${scriptFilePath}`); + Gtk.IconTheme.get_default().append_search_path(LATEX_DIR); + self.child?.destroy(); - self.child = Gtk.Image.new_from_file(outFilePath); + self.child = Gtk.Image.new_from_icon_name(outIconName, 0); }) } }, diff --git a/.config/ags/modules/sideleft/apis/waifu.js b/.config/ags/modules/sideleft/apis/waifu.js index 2dece7ebf..bca0415be 100644 --- a/.config/ags/modules/sideleft/apis/waifu.js +++ b/.config/ags/modules/sideleft/apis/waifu.js @@ -251,7 +251,6 @@ const WaifuImage = (taglist) => { else Utils.execAsync(['bash', '-c', `wget -O '${thisBlock.attribute.imagePath}' '${url}'`]) .then(showImage) .catch(print); - console.log(`background-color: mix(${darkMode ? 'black' : 'white'}, ${dominant_color}, 0.97);`); thisBlock.css = `background-color: mix(${darkMode ? 'black' : 'white'}, ${dominant_color}, 0.97);`; }, }, diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss index fc25c3fb8..153b4fd2b 100644 --- a/.config/ags/scss/_sidebars.scss +++ b/.config/ags/scss/_sidebars.scss @@ -641,9 +641,6 @@ $colorpicker_rounding: 0.341rem; margin: 0rem 0.682rem; padding: 0.682rem; - @if $darkmode == True { - background-color: #e6e6e6; - } color: $onBackground; } From 4981c0935ff115113223b9d92738947da19e842b Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 20 Mar 2024 22:49:33 +0700 Subject: [PATCH 174/517] Update _overview.scss --- .config/ags/scss/_overview.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/ags/scss/_overview.scss b/.config/ags/scss/_overview.scss index 78b130b84..361b151da 100644 --- a/.config/ags/scss/_overview.scss +++ b/.config/ags/scss/_overview.scss @@ -116,7 +116,7 @@ .overview-tasks-window { @include normal-rounding; @include menu_decel; - background-color: $surfaceContainerHigh; + background-color: $layer2; color: $onSurface; border: 0.068rem solid $surfaceContainerHighest; } From ff4952eb5b5eb723d3311cd756fddff22ac9b533 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 21 Mar 2024 08:50:30 +0700 Subject: [PATCH 175/517] sidebar: ai: add light theme for source view --- .../assets/themes/sourceviewtheme-light.xml | 107 ++++++++++++++++++ .../modules/sideleft/apis/ai_chatmessage.js | 4 +- .config/ags/scss/_sidebars.scss | 1 - 3 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 .config/ags/assets/themes/sourceviewtheme-light.xml diff --git a/.config/ags/assets/themes/sourceviewtheme-light.xml b/.config/ags/assets/themes/sourceviewtheme-light.xml new file mode 100644 index 000000000..29ccc8a94 --- /dev/null +++ b/.config/ags/assets/themes/sourceviewtheme-light.xml @@ -0,0 +1,107 @@ + + + end_4 + <_description>Catppuccin port but very random + + + + + + + + + + + + + + + + + + + + + + + +