From 5c74785b668d1d03b8b9b32db5847c1cbd690ff3 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/525] 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 29dba74ba96256ee7bcaa855fd84b47fa210634e Mon Sep 17 00:00:00 2001 From: clsty Date: Sat, 24 Feb 2024 18:15:20 +0800 Subject: [PATCH 002/525] 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 bf852d70474ba95d93f6f666b2afdba49d0b3c02 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/525] 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 96c9e98b8008398b2ebed0e4a3f3efb752810844 Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 25 Feb 2024 11:27:19 +0800 Subject: [PATCH 004/525] 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 43151980efc4588ee7763880b321744a15040942 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/525] 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 2b2947dc535847fbe10129c257c319ba9b347ffd 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/525] 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 59ef961e918038468ffb0c12dde8199713be1814 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/525] 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 b6f0546da09fc34c374e1966e8585ab6d75a08f5 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/525] 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 72a6da9f60a1a3889950bd15f31d4c9610aba9c3 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/525] 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 3953509f1951e760a7d963536a7621bfb29cb3c4 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/525] 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 6676c37e2c2003fe4bba08c1d74f3dd1a0130c82 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/525] 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 4afa355b0b4c357702ada1fa04a1f454cd2bda3a 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/525] 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 2dd17b216df597e1138569e0501f28a70bb07c0e 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/525] 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 537ee4b8aa6db6bb57faa77a121ba98d40bd2674 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/525] 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 fa748a946436bc8f1ee83b3c0844a1bacb99d2a1 Mon Sep 17 00:00:00 2001 From: clsty Date: Tue, 27 Feb 2024 08:19:33 +0800 Subject: [PATCH 015/525] 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 71a6ceacc810663e09262d1d3b19b447781a88ff Mon Sep 17 00:00:00 2001 From: clsty Date: Tue, 27 Feb 2024 11:50:05 +0800 Subject: [PATCH 016/525] 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 7cd77e3168fc6e19302f40c867b1ed31fb2eea41 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/525] 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 c7c692ad98648f655dc235fe9338f7e19f97e9f3 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/525] 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 edabf40ba1c24358b8675068c4d0388eb36fd72c 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/525] 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 b2e28823d027bb47e2e88b234265153b4a9a6449 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/525] 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 753beb3f6ee64c4bf75cdd599448470b9273e2b0 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/525] 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 7a78972cf2fe774c799ea28685a03ef3fc66e606 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/525] 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 ad862067ea3e95976ce97459711f5c0ae3e9eb5e Mon Sep 17 00:00:00 2001 From: clsty Date: Tue, 27 Feb 2024 14:33:32 +0800 Subject: [PATCH 023/525] 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 3dc2db248c185e1a79b884ad5d5f0f4741119d5e 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/525] 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 372c561e12061d2253ba449300295db3b7d436ff 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/525] 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 b6fde3fa536684ad2b8321a243d41fdaf673678a Mon Sep 17 00:00:00 2001 From: clsty Date: Wed, 28 Feb 2024 10:36:16 +0800 Subject: [PATCH 026/525] 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 918eca6b9959502a06afaf2e518f747b01ac8d40 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/525] 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 97c2a9b34937e0d4546d3c7b6997053dda420733 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/525] 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 8d00b16b65420452a872b4bbc4c54ad54ab9db8d 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/525] 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 dd5e0cb9a0881dc9df3a1ea167718da7661fb147 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/525] 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 27839977b073892e7b1097453c7cc1900c0438cc Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Thu, 29 Feb 2024 18:42:54 +0530 Subject: [PATCH 031/525] 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 afcbd2c7923e8eb8d060ca749cd6638c8bddeb42 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Thu, 29 Feb 2024 18:58:42 +0530 Subject: [PATCH 032/525] 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 e1b81d6d30da0c5968bac135c8e1c7087d8539c2 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Thu, 29 Feb 2024 19:06:09 +0530 Subject: [PATCH 033/525] 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 1e870f8a220dfe8291dea23b5084861e79b5f11e 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/525] 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 7940d435078290d4914e9ab728a2a617b340bc91 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/525] 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 e09392924cfcaee76607a643a4556d18d8c5534c 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/525] 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 9efebe38a912650e76cb90930b10b595a8e4c4bd 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/525] 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 c4c839f73f8c060ab336f020934359f84736fb44 Mon Sep 17 00:00:00 2001 From: clsty Date: Fri, 1 Mar 2024 16:16:53 +0800 Subject: [PATCH 038/525] 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 c4a09c60f0093d49b755a0a70f116c2328a1ca9a 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/525] 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 99b8b92889d203985e2fcb388c5ae41849cca766 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/525] 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 29fdbd376fd5764d8e7d673e020ad6193e04ce41 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/525] 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 8ec23c996629e6266d82afc5c7df4d3d09c1fcef 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/525] 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 a546a32d79319735905eed48e69c3efa4d4603da 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/525] 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 e4bdabf92a278f95fd8251ae7974e7e90658b75f Mon Sep 17 00:00:00 2001 From: clsty Date: Sat, 2 Mar 2024 19:07:21 +0800 Subject: [PATCH 044/525] 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 dd616ecddf050135d84febf6fdb3f8ff27f08198 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/525] 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 47888f5c174042d4d9208ab6b28aba46bce1da76 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/525] 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 15fed0e37d536ad7309095462f5c100a314504d7 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/525] 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 a0e5f580bd2d836f44f40a7b8bea4760f9414fef Mon Sep 17 00:00:00 2001 From: clsty Date: Sat, 2 Mar 2024 21:27:09 +0800 Subject: [PATCH 048/525] 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 f89cde569b5fac6410a5d8e7a198ef1226ecaec4 Mon Sep 17 00:00:00 2001 From: clsty Date: Sat, 2 Mar 2024 21:47:03 +0800 Subject: [PATCH 049/525] 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 430284073550051f8841c34f3c403aefd4d8ac9d 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/525] 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 ee86b164fb13e4236201dddfdfa770935c85bf6a 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/525] 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 1fc35cf923c5a7ba4d6794303414206f04737c5e 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/525] 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 1eea02ea81e5be8e6eded3c7cfa5f9d92d7879a9 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/525] 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 07226cc152af58bd33cf85857452ccfc4287d3cc Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 3 Mar 2024 07:09:17 +0800 Subject: [PATCH 054/525] 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 df81c2cf857eececce25a1809a111a54f78dd13b Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 3 Mar 2024 07:16:01 +0800 Subject: [PATCH 055/525] 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 6edeec106eb70eecc14f54211440c41080072c71 Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 3 Mar 2024 07:18:35 +0800 Subject: [PATCH 056/525] 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 4fa1260eae9b83518188185d2eb04bbf88295cee Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 3 Mar 2024 07:27:00 +0800 Subject: [PATCH 057/525] 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 0f556381b48fccf903cd4118a05bb9f62fc73dc3 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/525] 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 4de1b711ea3ace6197cbfe426e0de49b5d2a00df 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/525] 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 6feeb5c28e1c72825934d8da21743a43b533cce6 Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 3 Mar 2024 19:53:35 +0800 Subject: [PATCH 060/525] 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 4ea6af8279074891137623b002a231d1b824b712 Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 3 Mar 2024 19:55:58 +0800 Subject: [PATCH 061/525] 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 9c1710361bf83741b6fdcd7a6db210cd07b829bf 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/525] 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 be56c956c8c176673f3122f22d3fe2f042af6473 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/525] 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 9bf673fb1a9a25330c55476a4a8d5c22b9f69339 Mon Sep 17 00:00:00 2001 From: Ali Elnwegy Date: Mon, 4 Mar 2024 15:23:57 +0100 Subject: [PATCH 064/525] 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 e846b390ade80ee7111623cfe4dfecfe6815a9ff 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/525] 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 132bc97c838075dd32e63ce3c81d9347a67cd867 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/525] 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 f5885e444cdc3c9c57ba27eb919feec5071aafd8 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/525] 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 8ce7237b2b7240739d3bc3d34775b9f714752364 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/525] 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 b567872b7c95b4f404ce5fd608ae03a951be9b63 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/525] 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 dcdb88627e3bc21ecbe223554e0fc01eea070e23 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/525] 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 3f541c642d23956df0d503e9a9cb07524c872d70 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/525] 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 ee827fb713f02a19892bc167bc954b24526bbc9f 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/525] 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 e0f8b980dd12d9ab21dc45bd8203ab6faddecf91 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/525] 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 f854ba12689e88fea47a7483a86ecc3ee636a584 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/525] 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 03e3c64344db44a398273bdaf0c3aeb5101710ec 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/525] 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 4d368e3cfe9aa12dc80d214e0d825db6359ed79e 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/525] #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 6d57b490f28bc1f2329300866dc09e74f688433c 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/525] 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 18959b59bf90cb18cfe05949f8eabf1c7a3152b0 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/525] 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 d1e13ad1dfdf9e9b75272393b102586d076c8072 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/525] 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 da338dbc612fa3850f81eba85814186d0335cd77 Mon Sep 17 00:00:00 2001 From: clsty Date: Wed, 6 Mar 2024 13:19:35 +0800 Subject: [PATCH 080/525] 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 239231b5cfe500b17e654229ef2e9c75705ca13b 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/525] 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 2ffd02f739bab45284fa5fe2f63c39ee059461a0 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/525] 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 0e6d3547ec75b3a0a230073018b1ecc381749ba4 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/525] 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 4d39558ed6b21abecd33ed0008f97b0b96f8a87f 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/525] 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 76289cad7115bb0c502ee4142a07a914e140c0dd 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/525] 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 de93991034fd014fe3cfd5a7fd3347abe30eb71d 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/525] 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 8279da641c5525adddfb4ad9bfcbdb3431992491 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/525] 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 9178bb84437aa2aad436a882f595ec1be130b9ff 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/525] 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 797c5175586e097dba2382b01ab3abc36d34b380 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/525] 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 294ee8a8d459d41af493dddfa428458267c4b1d2 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/525] 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 c36d0895bba06b9fc1e97b82689048dd753c9e43 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/525] 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 a6e2f582fa206bc192083728f1a0021c547a6bcd 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/525] 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 e1346f7ea64c810bdcc8505b7af40e5d7d236f7d 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/525] 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 3f0a35886453e2afc8d2cfd898de34aba5c59cf5 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/525] 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 1f6b7b42d5259c7b211253556fc24a355a7e33ee Mon Sep 17 00:00:00 2001 From: clsty Date: Fri, 8 Mar 2024 19:40:58 +0800 Subject: [PATCH 095/525] 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 7f3bf944215e80a89797e8fd6726c7830cf0fb4a 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/525] 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 6244d5572dac7b6ff5679ab63108921721912903 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/525] 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 baf80122aeeb7142fba5989ab72c6337ac92de0c 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/525] 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 bb7cf3aa8131735790102ae9c8ac5047fad794eb 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/525] 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 36e706be01297c4ff3eef453c27f3345281edb06 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Fri, 8 Mar 2024 22:08:34 +0530 Subject: [PATCH 100/525] 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 4af990e845aa97bdff8395b7f8218c80d3e73ad2 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/525] 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 80d51d5088245ee3d82ca9f4ee876586ccedf78e 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/525] 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 aba3be7be1a22e87c1c7d71a4d05716d9da24fec Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 10 Mar 2024 18:08:52 +0800 Subject: [PATCH 103/525] 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 819a398d0a7e71b2d37a98107a7fb731b2799a73 Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 10 Mar 2024 18:33:53 +0800 Subject: [PATCH 104/525] 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 875b439b849f79db090d4e13f55f9848043869d9 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/525] 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 3f05d77664c81fcbf3ff1fac618671205607b304 Mon Sep 17 00:00:00 2001 From: clsty Date: Sun, 10 Mar 2024 19:17:10 +0800 Subject: [PATCH 106/525] 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 0b979d99036d027c31b5dbc2e8f6c59a8da4a9cc 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/525] 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 be569521c56807b66c3e6859e84b1757c6aa0177 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/525] 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 a13a2553e6632bfc342e5043272d1148d9a44969 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/525] 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 ca7024b5505fa8492385b7823d28548f8ff8253e 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/525] 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 32956fda25ac1d7bb71735013e86acc504121c89 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/525] 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 eabd4c4e111b25a1eebbc18f4025b3f361afc2a7 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/525] 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 0fd23f69f05b6ed97af02d68590c2ce7bdea439a Mon Sep 17 00:00:00 2001 From: clsty Date: Tue, 12 Mar 2024 16:29:16 +0800 Subject: [PATCH 113/525] 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 f3d235c9a34775fd5a4015818e7531ef3fd47ff6 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/525] 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 ca2b0065bd6aee7657d010c82d1ab3965443b8a8 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/525] 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 b28c145c9eb4b7c4a4eb49ca97c5d4d34fb0e497 Mon Sep 17 00:00:00 2001 From: Cruleo Date: Tue, 12 Mar 2024 23:46:18 +0100 Subject: [PATCH 116/525] 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 b9fd854605fbcc7bc2350fdd856d30f579c2097a 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/525] 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 ce49de941b373c4da7be772db8fb44af07449793 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/525] 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 734c1ba3d3ecce960a23b29a3555400c4f007212 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/525] 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 45f75ef7bd0160a77d343342a7077c5b5ff999d8 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/525] 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 88453c8497fe54c5975ae849940f249bfeabbf25 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/525] 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 622f5ea973a074d5b3c5ac5804b65dffe05b3069 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/525] 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 4c9ff41a260e065222ee0870dff1b56b20e82e6d 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/525] 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 47eee6c981a3507a8399f23dc4bc0ba648922667 Mon Sep 17 00:00:00 2001 From: clsty Date: Thu, 14 Mar 2024 22:50:07 +0800 Subject: [PATCH 124/525] 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 054860cec3fc0ce7686f0b5e33fcf7fc11ec251b 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/525] 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 3cfaf5286574012cdd5f1787ab9bd90d3eab9566 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/525] 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 90e9410e44f08507bf25b719ee8e962d5876989b Mon Sep 17 00:00:00 2001 From: clsty Date: Fri, 15 Mar 2024 07:29:36 +0800 Subject: [PATCH 127/525] 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 db2098f26c5cbac5bec91ec3872051566c2d7882 Mon Sep 17 00:00:00 2001 From: "Celestial.y" Date: Fri, 15 Mar 2024 08:46:50 +0800 Subject: [PATCH 128/525] 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 f9a31e7a25e5582a4b3b8b093de57647552eae91 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/525] 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 b3c41f610c73d021989ed5d7cb21a01f04622842 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/525] 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 9e3c2fdd7ba7a8653a88d2e5200fe5b5959ebfd2 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/525] 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 e37ee35987df66a921baae5856b1cde885259a4b 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/525] 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 123d962cfbcb298cecf6f8a2581e671a88d60a75 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/525] 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 fa641efc1d23e74802bcdc8eb72a79b21dc2c7b0 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/525] 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 be35243afb71296199932739fb1527dd146a12fc 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/525] 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 c716eefd5afd6ceb04be79020b58fc588a68ed4a Mon Sep 17 00:00:00 2001 From: clsty Date: Sat, 16 Mar 2024 15:13:50 +0800 Subject: [PATCH 136/525] 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 9e9a300b0129b86bb6545236b33951bf9c10ff39 Mon Sep 17 00:00:00 2001 From: clsty Date: Sat, 16 Mar 2024 15:17:51 +0800 Subject: [PATCH 137/525] 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 f6e9f4b6dc0d9bb3fbb160fe6dcadcb710d7f0d3 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/525] 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 d59142fa6d3ef91c05116c04f8e95cf7ddc537f9 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/525] 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 4904cfbe713083ad124ce8c971c72f00fb8f00e5 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sat, 16 Mar 2024 21:00:17 +0530 Subject: [PATCH 140/525] 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 46642ba4b1f5e9d2eb0f1c56fc4a9b71de1312c1 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/525] 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 9b69a38c7485ea1e9b26d3f69fe2a150e5b641c2 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/525] 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 cff91628bc746b3f671cfc5afbd374d2254eeb79 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/525] 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 0892bc2c1d21a772d2cd89af9790ec6cea169399 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/525] #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 99a500048166d8479cd41bb51357ab69768c4663 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/525] 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 03ec2616dfb91824683b78ef13452a3ec5807bb9 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/525] #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 996e18fd74c831dd66075a6f7d596137063138a0 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 04:01:51 +0530 Subject: [PATCH 147/525] 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 eaa66c4a95f44024c6c58306bc7147ada69129b1 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 05:38:55 +0530 Subject: [PATCH 148/525] 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 90215d64515859af88ce18007f4e511418c6ac4e 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/525] 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 2ebae2914605336fb54d2940f126c49f78f9b78c 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/525] #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 54f088b7646e017eebfe17865358a89d39aaed51 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 13:37:58 +0530 Subject: [PATCH 151/525] 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 c5d6fa15a867679eb540405d03102fe53516beef Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 13:46:02 +0530 Subject: [PATCH 152/525] 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 6f0ca3acaa1e6dea900e61ff2963306b52cbcf4c Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 14:35:23 +0530 Subject: [PATCH 153/525] 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 3e7c4db9f439b4a83f93929dbb5cec90bf65a83d 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/525] 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 b62f14268ad547f9b573227cd29e7b670c8c57fb Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 20:06:15 +0530 Subject: [PATCH 155/525] 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 c33e4d32869382bfc92582d5a25c818aafc29d94 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 20:09:34 +0530 Subject: [PATCH 156/525] 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 2a2d9f001a9ad405f21b4c515eebb3128ccea35e Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Sun, 17 Mar 2024 20:24:46 +0530 Subject: [PATCH 157/525] 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 5ad817ff342a7190f7e9f177a94d46a868b140ad 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/525] 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 239e545ecb9f0ab1a409329e872fdfc7854f7799 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/525] 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 c5d4c6f76eee56bbcd7bdf115c5a07db38bc8b23 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/525] 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 553a89da6fcdbae8f689e10be841268a08bef812 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/525] 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 ecbb7abe27b9f4426eb60e2c71271a27efba4678 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/525] 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 69a73e374574348b6ce45f90f940f9498c7a9dff 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/525] 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 c696328a4cd5d28fc03de2b8a1652b71847bfddb 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/525] 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 eb894bcfbd114b3e8a76c672b57a3f24dc59da95 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/525] 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 ac947778db098b11ea330c403875e9d32cdcbec5 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/525] 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 cf8b4391afcb3cff5342a9d8868a60ae6ec97373 Mon Sep 17 00:00:00 2001 From: midn8hustlr <4visekh@gmail.com> Date: Tue, 19 Mar 2024 21:17:00 +0530 Subject: [PATCH 167/525] 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 884ff781bd6eabc9f40c4f5f781e826e31dcd30c 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/525] 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 1dafe6a207ff8743b2d67751d51b782ac89d3e12 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/525] 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 25f8adc1dd042a688e20bc9654606c81af6ed167 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/525] 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 da49161666bca684b7eed48e918193b16265c74b 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/525] 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 4f7000fc077024ecce44f4617d645b55e993797e 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/525] 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 117070924706755df1b068cb545fb0e97dedc65f 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/525] 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 7ee3fb86e872d5730672aaa308dc49ad1b3bb735 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/525] 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 bc264b0fc47dc3b971ab09155b3d2dfd64617a86 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/525] 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 + + + + + + + + + + + + + + + + + + + + + + + +