3 Commits
Author SHA1 Message Date
Hannes 02606e5ab3 tray 2026-02-17 15:29:06 +01:00
Hannes c7b0ed957a tray 2026-02-17 14:52:28 +01:00
Hannes c011c76900 added Tray 2026-02-17 14:34:18 +01:00
60 changed files with 255 additions and 3802 deletions
+1 -5
View File
@@ -1,5 +1 @@
*.svg Colors.qml
Colors.qml
modules/wlogout/scripts/helper.sh
config/path/ConfigPath.qml
config/path/WallpaperPath.qml
-38
View File
@@ -1,38 +0,0 @@
# HyprlandQuickshellGUI: a replacement for Waybar
Run install.sh to make the quickshell runable
## Colors
### [Matugen](https://github.com/InioX/matugen)
We use [matugen](https://github.com/InioX/matugen) for the colors. With these Templates for Some Applications we use: [maguten-config](https://git.honney333.work/honney/matugen-config)
## Wallpaper
We use a custom directory by deafault to save all your Wallpapers:
```
$HOME/Pictures/Wallpapers/
```
### Compatible Wallpaper Software:
- [hyprpaper](https://github.com/hyprwm/hyprpaper)
- [swww](https://github.com/LGFae/swww)
- [awww (comming)](https://codeberg.org/LGFae/awww)
### Recommended Software for some stuff:
- [ImageMagick (resizing & blurring)](https://github.com/ImageMagick/ImageMagick)
## Other Software:
### Logout:
- [wlogout](https://github.com/ArtsyMacaw/wlogout)
- [nmcli (Recommended for Wifi)](https://github.com/ushiboy/nmcli)
## TO Enable Sub Programs:
Add the Lines to your ```~/.config/hypr/hyprland.conf``` keep in mind that you might need to change the Keybind.
### Wallpaper Picker
```bind = $mainMod SHIFT, W, global, quickshell:Wallpaper```
### JLearner
```bind = $mainMod SHIFT, J, global, quickshell:JLearner```
# TODO:
- Volume Contol
- Notes
- wofi
Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 MiB

-57
View File
@@ -1,57 +0,0 @@
pragma Singleton
import QtQuick 2.15
QtObject {
// ===== PRIMARY =====
readonly property color primary: "#cbcb77"
readonly property color primary_fg: "#323200"
readonly property color primaryContainer: "#494900"
readonly property color primaryContainer_fg: "#e7e790"
// ===== SECONDARY =====
readonly property color secondary: "#cac8a5"
readonly property color secondary_fg: "#323218"
readonly property color secondaryContainer: "#48482d"
readonly property color secondaryContainer_fg: "#e6e4bf"
// ===== TERTIARY =====
readonly property color tertiary: "#a4d0bd"
readonly property color tertiary_fg: "#0a372a"
readonly property color tertiaryContainer: "#254e40"
readonly property color tertiaryContainer_fg: "#bfecd9"
// ===== ERROR =====
readonly property color error: "#ffb4ab"
readonly property color error_fg: "#690005"
readonly property color errorContainer: "#93000a"
readonly property color errorContainer_fg: "#ffdad6"
// ===== BACKGROUND / SURFACE =====
readonly property color background: "#14140c"
readonly property color background_fg: "#e6e3d5"
readonly property color surface: "#14140c"
readonly property color surface_fg: "#e6e3d5"
readonly property color surfaceVariant: "#48473a"
readonly property color surfaceVariant_fg: "#c9c7b6"
// ===== SURFACE CONTAINERS =====
readonly property color surfaceContainerLowest: "#0f0f07"
readonly property color surfaceContainerLow: "#1c1c14"
readonly property color surfaceContainer: "#202018"
readonly property color surfaceContainerHigh: "#2b2a22"
readonly property color surfaceContainerHighest: "#36352c"
// ===== OUTLINE / UTILITY =====
readonly property color outline: "#939182"
readonly property color outlineVariant: "#48473a"
readonly property color shadowColor: "#000000"
readonly property color scrimColor: "#000000"
// ===== INVERSE =====
readonly property color inverseSurface: "#e6e3d5"
readonly property color inverseSurface_fg: "#313128"
readonly property color inversePrimary: "#616219"
}
-57
View File
@@ -1,57 +0,0 @@
pragma Singleton
import QtQuick 2.15
QtObject {
// ===== PRIMARY =====
readonly property color primary: "#cbcb77"
readonly property color primary_fg: "#323200"
readonly property color primaryContainer: "#494900"
readonly property color primaryContainer_fg: "#e7e790"
// ===== SECONDARY =====
readonly property color secondary: "#cac8a5"
readonly property color secondary_fg: "#323218"
readonly property color secondaryContainer: "#48482d"
readonly property color secondaryContainer_fg: "#e6e4bf"
// ===== TERTIARY =====
readonly property color tertiary: "#a4d0bd"
readonly property color tertiary_fg: "#0a372a"
readonly property color tertiaryContainer: "#254e40"
readonly property color tertiaryContainer_fg: "#bfecd9"
// ===== ERROR =====
readonly property color error: "#ffb4ab"
readonly property color error_fg: "#690005"
readonly property color errorContainer: "#93000a"
readonly property color errorContainer_fg: "#ffdad6"
// ===== BACKGROUND / SURFACE =====
readonly property color background: "#14140c"
readonly property color background_fg: "#e6e3d5"
readonly property color surface: "#14140c"
readonly property color surface_fg: "#e6e3d5"
readonly property color surfaceVariant: "#48473a"
readonly property color surfaceVariant_fg: "#c9c7b6"
// ===== SURFACE CONTAINERS =====
readonly property color surfaceContainerLowest: "#0f0f07"
readonly property color surfaceContainerLow: "#1c1c14"
readonly property color surfaceContainer: "#202018"
readonly property color surfaceContainerHigh: "#2b2a22"
readonly property color surfaceContainerHighest: "#36352c"
// ===== OUTLINE / UTILITY =====
readonly property color outline: "#939182"
readonly property color outlineVariant: "#48473a"
readonly property color shadowColor: "#000000"
readonly property color scrimColor: "#000000"
// ===== INVERSE =====
readonly property color inverseSurface: "#e6e3d5"
readonly property color inverseSurface_fg: "#313128"
readonly property color inversePrimary: "#616219"
}
-69
View File
@@ -1,69 +0,0 @@
pragma Singleton
import QtQuick 2.15
import "./path"
QtObject {
readonly property string configDir: ConfigPath.path
readonly property string wallpaperDir: WallpaperPath.wallpaperDir
readonly property int small_spacing: 4
readonly property int spacing: 8
function small_spacing_fun(screenHeight) { return Math.floor(barHeight(screenHeight) / 16) }
function spacing_fun(barH) { return Math.floor(barH / 8) }
function big_spacing_fun(barH) { return Math.floor(barH / 6) }
function font_size(spaceHeight) { return Math.floor(spaceHeight * 0.75) }
function font_size_small(spaceHeight) { return Math.floor(spaceHeight * 0.625) }
function font_size_tiny(spaceHeight) { return Math.floor(spaceHeight * 0.4) }
readonly property int small_radius: 8
readonly property int radius: 16
function small_radius_fun(barHeight) { return Math.floor(barHeight / 8) }
function radius_fun(barHeight) { return Math.floor(barHeight / 4) }
readonly property int big_radius: 10
readonly property int border_width: 2
readonly property string font: "CodeNewRoman Nerd Font"
function big_font_size(value) {
return value * 0.6
}
function medium_scaling(value) {
return value * 0.4
}
// Scale font/icon size relative to bar height
function bigIconSize(barHeight) { return Math.floor(barHeight * 0.7) }
function halfBigIconSize(barHeight) { return Math.floor(barHeight * 0.6) }
function iconSize(barHeight) { return Math.floor(barHeight * 0.5) }
function labelSize(barHeight) { return Math.floor(barHeight * 0.35) }
function normalSpacing(screenHeight) { return Math.floor(barHeight(screenHeight) / 4) }
function widgetSpacing(screenHeight) { return Math.floor(barHeight(screenHeight) / 8) }
function barHeight(screenHeight) {
return Math.floor(screenHeight * barHeightRatio(screenHeight))
}
// Resolution-aware bar height ratio
function barHeightRatio(screenHeight) {
return screenHeight >= 2160 ? 0.03 :
screenHeight >= 1440 ? 0.035 :
0.04
}
// Tray
readonly property int reload_interval: 10000
readonly property int fast_reload_interval: 1000
function maxTextWidth(maxNum, texts) {
let maxWidth = 0;
for (let i = 0; i < Math.min(maxNum, texts.length); i++)
maxWidth = Math.max(maxWidth, texts[i].width);
return maxWidth;
}
}
-6
View File
@@ -1,6 +0,0 @@
pragma Singleton
import QtQuick 2.15
QtObject {
readonly property string path: "__CONFIG_DIR__"
}
-7
View File
@@ -1,7 +0,0 @@
pragma Singleton
import QtQuick
import Quickshell
QtObject {
property string wallpaperDir: "__CONFIG_DIR__"
}
-2
View File
@@ -1,2 +0,0 @@
singleton ConfigPath ConfigPath.qml
singleton WallpaperPath WallpaperPath.qml
-2
View File
@@ -1,2 +0,0 @@
singleton Config Config.qml
singleton Colors Colors.qml
-183
View File
@@ -1,183 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
cp "$SCRIPT_DIR/config/Colors.qml.template" "$SCRIPT_DIR/config/Colors.qml"
cp "$SCRIPT_DIR/config/path/ConfigPath.qml.template" "$SCRIPT_DIR/config/path/ConfigPath.qml"
sed -i "s|__CONFIG_DIR__|$SCRIPT_DIR|g" "$SCRIPT_DIR/config/path/ConfigPath.qml"
# ----------------------------
# UI helpers
# ----------------------------
info() { echo -e "\033[1;34m[INFO]\033[0m $*"; }
ok() { echo -e "\033[1;32m[ OK ]\033[0m $*"; }
warn() { echo -e "\033[1;33m[WARN]\033[0m $*"; }
fail() { echo -e "\033[1;31m[FAIL]\033[0m $*"; }
download() {
local url="$1"
local out="$2"
local name="${3:-$(basename "$out")}"
info "Downloading $name"
if curl -fL --progress-bar "$url" -o "$out"; then
ok "Saved $name"
else
fail "Failed $name"
return 1
fi
}
transform_svg_white() {
local url="$1"
local out="$2"
local name="${3:-$(basename "$out")}"
info "Fetching + whitening $name"
if curl -fsSL "$url" \
| sed -E 's/#[0-9a-fA-F]{3,6}/#ffffff/g' \
> "$out"; then
ok "Generated $name"
else
fail "Failed $name"
return 1
fi
}
# ----------------------------
# Start
# ----------------------------
echo
info "Preparing wlogout icons..."
mkdir -p "$SCRIPT_DIR/modules/wlogout/icons"
# ----------------------------
# Icons (wlogout)
# ----------------------------
transform_svg_white \
"https://raw.githubusercontent.com/vinceliuice/Colloid-icon-theme/main/src/actions/symbolic/system-hibernate-symbolic.svg" \
"$SCRIPT_DIR/modules/wlogout/icons/hibernate.svg" \
"hibernate.svg"
transform_svg_white \
"https://raw.githubusercontent.com/vinceliuice/Colloid-icon-theme/main/bold/actions/symbolic/system-lock-screen-symbolic.svg" \
"$SCRIPT_DIR/modules/wlogout/icons/lock.svg" \
"lock.svg"
transform_svg_white \
"https://raw.githubusercontent.com/vinceliuice/Colloid-icon-theme/main/src/status/symbolic/logout-symbolic.svg" \
"$SCRIPT_DIR/modules/wlogout/icons/logout.svg" \
"logout.svg"
transform_svg_white \
"https://raw.githubusercontent.com/vinceliuice/Colloid-icon-theme/main/src/actions/symbolic/system-reboot-symbolic.svg" \
"$SCRIPT_DIR/modules/wlogout/icons/reboot.svg" \
"reboot.svg"
transform_svg_white \
"https://raw.githubusercontent.com/vinceliuice/Colloid-icon-theme/main/src/actions/symbolic/system-shutdown-symbolic.svg" \
"$SCRIPT_DIR/modules/wlogout/icons/shutdown.svg" \
"shutdown.svg"
transform_svg_white \
"https://raw.githubusercontent.com/vinceliuice/Colloid-icon-theme/main/src/actions/24/system-suspend.svg" \
"$SCRIPT_DIR/modules/wlogout/icons/suspend.svg" \
"suspend.svg"
# ----------------------------
# UI icons
# ----------------------------
echo
info "Preparing global icons..."
mkdir -p "$SCRIPT_DIR/modules/jl/assets"
download \
"https://raw.githubusercontent.com/Tekh-ops/Garuda-Linux-Icons/refs/heads/master/actions/scalable/window-close.svg" \
"$SCRIPT_DIR/modules/jl/assets/wrong.svg" \
"wrong.svg"
download \
"https://raw.githubusercontent.com/Tekh-ops/Garuda-Linux-Icons/refs/heads/master/actions/scalable/dialog-ok-apply.svg" \
"$SCRIPT_DIR/modules/jl/assets/correct.svg" \
"correct.svg"
# ----------------------------
# Nerd Font
# ----------------------------
echo
info "Installing CodeNewRoman Nerd Font..."
FONT_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/fonts"
mkdir -p "$FONT_DIR"
if [ ! -f "$FONT_DIR/CodeNewRomanNerdFont-Regular.ttf" ]; then
download \
"https://github.com/ryanoasis/nerd-fonts/releases/latest/download/CodeNewRoman.tar.xz" \
"/tmp/CodeNewRoman.tar.xz" \
"CodeNewRoman Nerd Font"
tar -xf /tmp/CodeNewRoman.tar.xz -C "$FONT_DIR" --wildcards '*.ttf' 2>/dev/null || \
tar -xf /tmp/CodeNewRoman.tar.xz -C "$FONT_DIR"
rm -f /tmp/CodeNewRoman.tar.xz
if command -v fc-cache &>/dev/null; then
fc-cache -fv "$FONT_DIR" &>/dev/null
fi
ok "CodeNewRoman Nerd Font installed"
else
ok "CodeNewRoman Nerd Font already installed"
fi
# ----------------------------
# Japanese Font (for JLearner)
# ----------------------------
echo
info "Installing Noto Sans JP font..."
if [ ! -f "$FONT_DIR/NotoSansJP.ttf" ]; then
download \
"https://github.com/google/fonts/raw/main/ofl/notosansjp/NotoSansJP%5Bwght%5D.ttf" \
"$FONT_DIR/NotoSansJP.ttf" \
"Noto Sans JP"
ok "Noto Sans JP font installed"
else
ok "Noto Sans JP font already installed"
fi
# ----------------------------
# Font cache reload
# ----------------------------
echo
info "Reloading font cache..."
if command -v fc-cache &>/dev/null; then
fc-cache -fv &>/dev/null
ok "Font cache reloaded"
else
warn "fc-cache not found — font cache not updated"
fi
# ----------------------------
# Example Wallpaper
# ----------------------------
echo
info "Preparing wallpaper..."
WALLPAPER_DIR=$(scripts/wallpaper_dir.sh)
mkdir -p "$WALLPAPER_DIR"
info "Copying example Wallpaper..."
cp "$SCRIPT_DIR/assets/example_background.png" "$WALLPAPER_DIR/japan_old_emperor_stream_with_bridge.png"
info "Creating Wallpaper Folder Config"
cp "$SCRIPT_DIR/config/path/WallpaperPath.qml.template" "$SCRIPT_DIR/config/path/WallpaperPath.qml"
sed -i "s|__CONFIG_DIR__|$WALLPAPER_DIR|g" "$SCRIPT_DIR/config/path/WallpaperPath.qml"
echo
ok "All assets prepared successfully."
-44
View File
@@ -1,44 +0,0 @@
import QtQuick
import Quickshell
import Quickshell.Wayland
Variants {
id: root
// Automatically generates a trap for every connected monitor
model: Quickshell.screens
delegate: PanelWindow {
screen: modelData
// Force the panel window to take up the full screen real estate
anchors.top: true
anchors.bottom: true
anchors.left: true
anchors.right: true
// Push it to the background layer below normal windows
WlrLayershell.layer: WlrLayer.Background
WlrLayershell.namespace: "transparent-focus-trap"
// Keep it transparent so your current wallpaper shows right through
color: "transparent"
// The core trap mechanism
MouseArea {
anchors.fill: parent
hoverEnabled: true
// Having an active hover area on the background layer forces the
// Wayland compositor to shift cursor target focus to this surface
// the exact millisecond your mouse exits a tiled/floating window.
onEntered: {
console.log("DEBUG: Mouse entered background (Focus Trap Active)");
}
onExited: {
console.log("DEBUG: Mouse left background (Focusing on Window)");
}
}
}
}
+19 -13
View File
@@ -2,7 +2,9 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import "./widgets" import "./widgets"
import "../../config" import "../../colors"
// TODO: interact with PyWal
PanelWindow { PanelWindow {
id: panel id: panel
@@ -13,7 +15,7 @@ PanelWindow {
anchors.left: true anchors.left: true
anchors.right: true anchors.right: true
implicitHeight: Math.floor(screen.height * Config.barHeightRatio(screen.height)) implicitHeight: 40
exclusiveZone: height // this is so context menus don't clip into the bar exclusiveZone: height // this is so context menus don't clip into the bar
@@ -29,33 +31,36 @@ PanelWindow {
id: bar id: bar
anchors.fill: parent anchors.fill: parent
color: Qt.alpha(Colors.background, 0.5) color: Qt.alpha(Colors.background, 0.5)
radius: 0
Row { // bar widgets left Row { // bar widgets left
id: widgetsLeft id: widgetsLeft
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: Config.big_spacing_fun(height) anchors.leftMargin: 16
spacing: Config.big_spacing_fun(height) spacing: 8
MenuButton {} MenuButton {}
// TODO: Add functionallity (Maybe just rofi or own way)
Workspaces { Workspaces {
thisMonitor: barThisMonitor thisMonitor: barThisMonitor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
// TODO: Maybe add current Apps in workspace
WindowInfo {}
} }
Row { // bar widgets center Row { // bar widgets center
id: widgetsCenter id: widgetsCenter
anchors.centerIn: parent anchors.centerIn: parent
spacing: Config.big_spacing_fun(height)
Clock {} Clock {}
// TODO: Add a way to see Date (maybe hover or click)
} }
Row { // bar widgets right Row { // bar widgets right
@@ -63,16 +68,17 @@ PanelWindow {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 0 anchors.rightMargin: 16
spacing: Config.big_spacing_fun(height) spacing: 8
// TODO: Add bluetooth, network, audio, power, maybe HW monitor // TODO: Add bluetooth, network, audio, power, maybe HW monitor
Tray{} Tray{}
Battery{}
Network {} Network {}
IdleButton {}
PowerButton {} PowerButton {}
} }
// TODO: Somewhere add Tray
} }
} }
+1 -1
View File
@@ -3,7 +3,7 @@ import Quickshell
Item { Item {
id: bar_root id: root
Repeater { // Bars Repeater { // Bars
model: Quickshell.screens model: Quickshell.screens
delegate: Loader { delegate: Loader {
-198
View File
@@ -1,198 +0,0 @@
#!/bin/bash
ID="$1"
if [[ -z "$ID" ]]; then
echo "Usage: $0 Number"
exit 1
fi
# =========================
# ICON MAP (ADD YOUR TABLE HERE)
# =========================
# Command Helper: hyprctl clients -j | jq '.[] | select(.workspace.id == 1)'
# Icons: https://www.nerdfonts.com/cheat-sheet
declare -A MAP=(
# Youtube
["Grayjay"]=""
# Browser
["Ablaze Floorp"]=""
["floorp"]=""
["LibreWolf"]=""
["midori"]=""
["brave-browser"]=""
["chromium"]=""
# E-Mail
["org.mozilla.Thunderbird"]="󰇮"
# Terminals
["kitty"]=""
["Alacritty"]=""
# Videoplayer
["VLC media player"]="󰕼"
["mpv"]=""
["ffplay"]=""
# Video editing
["org.kde.kdenlive"]=""
# Chats
["discord"]=""
["vesktop"]=""
["Signal"]="󰭹"
["xyz.chatboxapp.app"]=""
# Coding
["Visual Studio Code"]=""
["VSCodium"]=""
["jetbrains-idea"]=""
["jetbrains-studio"]=""
# Text Editor
["org.xfce.mousepad"]="󱩼"
# Password
["org.keepassxc.KeePassXC"]=""
["Yubico Authenticator"]=""
# Cloud
["com.nextcloud.desktopclient.nextcloud"]="󰅟"
# App Store
["Octopi"]="󰒚"
# Games
["steam*"]=""
["org.prismlauncher.PrismLauncher"]="󰍳"
["Minecraft*"]="󰍳"
["game"]=""
# Digital Arts
["Blender"]=""
["Krita"]=""
# VM
["virt-manager"]=""
["VirtualBox Manager"]=""
["VirtualBox Machine"]=""
["remote-viewer"]=""
# Audio
["qpwgraph"]="󱡫"
["Carla"]="󱡫"
# Video
["com.obsproject.Studio"]="󰨜"
["hyprland-share-picker"]="󱎴"
# Document Editor/Viewer
["libreoffice-startcenter"]=""
["libreoffice-base"]=""
["libreoffice-calc"]="󱎏"
["libreoffice-draw"]="󱎐"
["libreoffice-impress"]=""
["libreoffice-math"]=""
["libreoffice-writer"]="󱎒"
["com.github.flxzt.rnote"]="󱩼"
["Xreader"]="󱩼"
["com.github.xournalpp.xournalpp"]="󱩼"
["qpdfview.local.qpdfview"]="󱩼"
# Hardware
["Mission Center"]=""
["QDirStat"]="󰋊"
["Disks"]="󰋊"
# File Manager
["nemo"]="󰉋"
["org.gnome.Nautilus"]="󰉋"
["org.kde.dolphin"]="󰉋"
["xdg-desktop-portal-gtk"]="󰉋"
# Settings
["nwg-look"]="" # gtk-settings
["qt5ct"]=""
["qt6ct"]=""
["sddm-conf"]=""
["blueman-manager"]="󰂯"
["nm-connection-editor"]="󱛆"
# Calculator
["Calculator"]="󰪚"
# VPN
["Proton VPN"]="󰳌"
["com.cisco.secureclient.gui"]="󰳌"
# Torrent
["org.qbittorrent.qBittorrent"]="󰉍"
# Hardware Design
["Xilinx Unified 2022.2 Installer"]=""
["Xilinx Information Center"]=""
["Xilinx Unified 2022.2 Installer"]=""
["vsim"]=""
# BoxBuddy
["io.github.dvlv.boxbuddyrs"]="󰒋"
# Stream
["Fladder"]="󰼁"
["crunchyroll"]=""
["netflix"]=""
["primevideo"]="󰯜"
# Image Viewer
["viewnior"]=""
# Image Editor
["gimp"]="󱇣"
["org.inkscape.Inkscape"]="󱇣"
# CNC
["LightBurn"]="󱇣"
)
# =========================
# COLLECT HYPRLAND CLIENTS
# =========================
to_lower() {
echo "${1,,}"
}
match_map() {
local input
input="$(to_lower "$1")"
for key in "${!MAP[@]}"; do
local pattern
pattern="$(to_lower "$key")"
# wildcard + glob match
if [[ "$input" == $pattern ]]; then
echo "${MAP[$key]}"
return 0
fi
done
return 1
}
# APPS=$(hyprctl clients -j | jq -r ".[] | select(.workspace.id == $ID) | .initialTitle")
# =========================
# COLLECT HYPRLAND CLIENTS
# =========================
mapfile -t APPS < <(
hyprctl clients -j |
jq -r ".[] | select(.workspace.id == $ID) | .initialTitle"
)
mapfile -t APPS_CLASS < <(
hyprctl clients -j |
jq -r ".[] | select(.workspace.id == $ID) | .initialClass"
)
# =========================
# MAP ICONS
# =========================
for i in "${!APPS[@]}"; do
icon=""
icon="$(match_map "${APPS[$i]}")"
if [[ -z "$icon" ]]; then
icon="$(match_map "${APPS_CLASS[$i]}")"
fi
if [[ -n "$icon" ]]; then
APPS[$i]="$icon"
else
APPS[$i]="${APPS_CLASS[$i]}|${APPS[$i]}"
fi
done
# =========================
# OUTPUT
# =========================
RESULT="$(printf '%s' "${APPS[@]}")"
# RESULT=${RESULT% } # remove trailing space
echo "$RESULT"
-14
View File
@@ -1,14 +0,0 @@
if [ "$1" = "--status" ]; then
if pgrep -x "hypridle" >/dev/null; then
echo 1
else
echo 0
fi
exit 0
fi
if pgrep -x "hypridle" >/dev/null; then
killall hypridle
else
hypridle &
fi
+1 -1
View File
@@ -21,7 +21,7 @@ if printf "%s\n" "${ITYPES[@]}" | grep -qx "Ethernet"; then
echo "󰈀 " echo "󰈀 "
elif printf "%s\n" "${ITYPES[@]}" | grep -qx "Wi-Fi"; then elif printf "%s\n" "${ITYPES[@]}" | grep -qx "Wi-Fi"; then
if [ -x "/usr/bin/nmcli" ]; then if [ -x "/usr/bin/nmcli" ]; then
CONNECTION="$(nmcli -f DEVICE,ACTIVE,SSID,SIGNAL dev wifi | grep yes | awk '{print $NF}')" CONNECTION="$(nmcli -f DEVICE,ACTIVE,SSID,SIGNAL dev wifi | grep yes | awk '{print $4}')"
if [[ -z "$CONNECTION" ]]; then if [[ -z "$CONNECTION" ]]; then
echo "󰤭 " echo "󰤭 "
elif (( CONNECTION > 80 )); then elif (( CONNECTION > 80 )); then
-188
View File
@@ -1,188 +0,0 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
Item {
id: root
// Per-workspace icon cache: maps workspaceId -> array of icon strings
property var workspaceIcons: ({})
function iconsForWorkspace(workspaceId) {
return root.workspaceIcons[workspaceId] || []
}
function matchIcon(name) {
if (!name) return ""
var lower = name.toLowerCase()
if (iconMap[lower]) return iconMap[lower]
for (var key in iconMap) {
if (key.endsWith("*") && key.startsWith("*")) {
var middle = key.slice(1, -1)
if (lower.indexOf(middle) !== -1) return iconMap[key]
} else if (key.endsWith("*")) {
var prefix = key.slice(0, -1)
if (lower.startsWith(prefix)) return iconMap[key]
} else if (key.startsWith("*")) {
var suffix = key.slice(1)
if (lower.endsWith(suffix)) return iconMap[key]
}
}
return ""
}
Process {
id: clientsProc
command: ["hyprctl", "clients", "-j"]
running: true
stdout: StdioCollector {
onStreamFinished: {
try {
var data = JSON.parse(this.text.trim())
var newIcons = {}
for (var i = 0; i < data.length; i++) {
var client = data[i]
var wid = client.workspace.id
var icon = root.matchIcon(client.initialTitle) || root.matchIcon(client.initialClass) || "\"" + client.initialTitle + "\""
if (icon) {
if (!newIcons[wid]) newIcons[wid] = []
newIcons[wid].push(icon)
}
}
root.workspaceIcons = newIcons
} catch (e) {
// hyprctl output was not valid JSON
}
}
}
}
Timer {
interval: 1000
running: true
repeat: true
triggeredOnStart: true
onTriggered: clientsProc.running = true
}
readonly property var iconMap: ({
// Youtube
"grayjay": "",
// Browser
"ablaze floorp": "",
"floorp": "",
"librewolf": "",
"midori": "",
"brave-browser": "",
"chromium": "",
// E-Mail
"*thunderbird": "󰇮",
// Terminals
"kitty": "",
"alacritty": "",
// Videoplayer
"vlc media player": "󰕼",
"mpv": "",
"ffplay": "",
// Video editing
"org.kde.kdenlive": "",
// Video
"*obs*": "󰨜",
"hyprland-share-picker": "󱎴",
// Chats
"discord": "",
"vesktop": "",
"signal": "󰭹",
"xyz.chatboxapp.app": "",
// Coding
"visual studio code": "",
"vscodium": "",
"jetbrains-idea": "",
"jetbrains-studio": "",
// Text Editor
"org.xfce.mousepad": "󱩼",
// Password
"org.keepassxc.keepassxc": "",
"yubico authenticator": "",
// Cloud
"com.nextcloud*": "󰅟",
// App Store
"octopi": "󰒚",
// Games
"steam*": "",
"org.prismlauncher*": "󰍳",
"minecraft*": "󰍳",
"game": "",
"eden*": "",
// Digital Arts
"blender": "",
// Image Editor
"gimp": "󱇣",
"*inkscape*": "󱇣",
"krita": "",
// VM
"virt*": "",
"remote-viewer": "",
// Audio
"*qpwgraph": "󱡫",
"carla": "󱡫",
"volume*": "",
"pavucontrol": "",
// Document Editor/Viewer
"libreoffice-startcenter": "",
"libreoffice-base": "",
"libreoffice-calc": "󱎏",
"libreoffice-draw": "󱎐",
"libreoffice-impress": "",
"libreoffice-math": "",
"libreoffice-writer": "󱎒",
"*rnote": "󱩼",
"xreader": "󱩼",
"*xournalpp*": "󱩼",
"qpdfview*": "󱩼",
// Hardware
"mission center": "",
"qdirstat": "󰋊",
"disks": "󰋊",
// File Manager
"nemo": "󰉋",
"org.gnome.nautilus": "󰉋",
"org.kde.dolphin": "󰉋",
"xdg-desktop-portal-gtk": "󰉋",
// Settings
"nwg-look": "",
"qt5ct": "",
"qt6ct": "",
"sddm-conf": "",
"org.gnome.Settings": "",
"blueman*": "󰂯",
"nm-connection-editor": "󱛆",
"nm-applet": "󱛆",
// Calculator
"calculator": "󰪚",
// VPN
"*vpn": "󰳌",
"*cisco*": "󰳌",
// Torrent
"*qbittorrent*": "󰉍",
// Hardware Design
"xilinx*": "",
"vsim": "",
"*ivado*": "",
// BoxBuddy
"*boxbuddy*": "󰒋",
// Stream
"fladder": "󰼁",
"crunchyroll": "",
"netflix": "",
"primevideo": "󰯜",
// Image Viewer
"viewnior": "",
// CNC
"lightburn": "󱇣",
"wofi": "",
// Screenshare
"moonlight": "󰍹ßß"
})
}
-1
View File
@@ -1 +0,0 @@
singleton AppsState AppsState.qml
@@ -1,85 +0,0 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
Item {
property bool available: false
property real percentage: 0
property bool charging: false
property real energy: 0
property real voltage: 0
property int charge_cycle: 0
property real time_to_empty: 0
property real energy_rate: 0
function parseUpower(line) {
line = line.trim()
if (line.startsWith("percentage:")) {
percentage = parseInt(line.split(":")[1])
// console.log("percentage =", percentage)
}
else if (line.startsWith("state:")) {
charging = !line.includes("discharging")
// console.log("charging =", charging)
}
else if (line.startsWith("energy:")) {
energy = parseFloat(line.split(":")[1])
// console.log("energy =", energy)
}
else if (line.startsWith("voltage:")) {
voltage = parseFloat(line.split(":")[1])
// console.log("voltage =", voltage)
}
else if (line.startsWith("energy-rate:")) {
energy_rate = parseFloat(line.split(":")[1])
// console.log("energy_rate =", energy_rate)
}
else if (line.startsWith("charge-cycles:")) {
charge_cycle = parseInt(line.split(":")[1])
// console.log("charge_cycle =", charge_cycle)
}
else if (line.startsWith("time to empty:")) {
time_to_empty = parseFloat(line.split(":")[1])
// console.log("time_to_empty =", time_to_empty)
}
}
Process {
id: upowerProc
command: ["bash", "-c", "upower -i $(upower -e | grep '^/org/freedesktop/UPower/devices/battery')"]
stdout: SplitParser {
onRead: function(data) {
parseUpower(data)
}
}
}
Process {
id: batteryAvailable
command: ["sh", "-c", "upower -e | grep -q '^/org/freedesktop/UPower/devices/battery' && echo '1' || echo '0'"]
stdout: StdioCollector {
onStreamFinished: {
const hasBattery = this.text.trim() === "1"
available = hasBattery
if (hasBattery) {
pollTimer.start()
}
}
}
}
Timer {
id: pollTimer
interval: 1000
running: false
repeat: true
triggeredOnStart: false
onTriggered: upowerProc.running = true
}
Component.onCompleted: {
batteryAvailable.running = true
}
}
-1
View File
@@ -1 +0,0 @@
singleton BatteryState 1.0 BatteryState.qml
-54
View File
@@ -1,54 +0,0 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
QtObject {
id: root
property string shortDate: Qt.formatDate(new Date(), "dd.MM.yyyy - ")
property string fullDate: Qt.formatDate(new Date(), "dddd, MMMM d, yyyy")
property string currentTime: Qt.formatTime(new Date(), "hh:mm:ss")
property string uptime: "Uptime: ..."
property bool expanded: false
property Timer timeTimer: Timer {
interval: 1000
running: true
repeat: true
triggeredOnStart: true
onTriggered: root.currentTime = Qt.formatTime(new Date(), "hh:mm:ss")
}
property Timer dateTimer: Timer {
interval: 60000
running: true
repeat: true
triggeredOnStart: true
onTriggered: {
root.shortDate = Qt.formatDate(new Date(), "dd.MM.yyyy - ")
root.fullDate = Qt.formatDate(new Date(), "dddd, MMMM d, yyyy")
}
}
property Process sysInfoProcess: Process {
command: ["sh", "-c", "echo $(cat /proc/uptime)"]
stdout: StdioCollector {
onStreamFinished: {
var uptimeSecs = parseFloat(text.trim().split(" ")[0])
var days = Math.floor(uptimeSecs / 86400)
var hours = Math.floor((uptimeSecs % 86400) / 3600)
var mins = Math.floor((uptimeSecs % 3600) / 60)
root.uptime = "Uptime: " + days + "d " + hours + "h " + mins + "m"
}
}
}
property Timer sysInfoTimer: Timer {
interval: 10000
running: true
repeat: true
triggeredOnStart: true
onTriggered: root.sysInfoProcess.running = true
}
}
-1
View File
@@ -1 +0,0 @@
singleton ClockState ClockState.qml
-28
View File
@@ -1,28 +0,0 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
import "../../../../config"
Item {
property int idle: 0
Process {
id: statusScript
command: ["sh", "-c", Config.configDir + "/modules/bar/scripts/Idle.sh --status"]
running: true
stdout: StdioCollector {
onStreamFinished: {
idle = this.text.trim() === "0" ? 1 : 0
}
}
}
Timer {
interval: 5000
running: true
repeat: true
triggeredOnStart: true
onTriggered: statusScript.running = true
}
}
-1
View File
@@ -1 +0,0 @@
singleton IdleState 1.0 IdleState.qml
-230
View File
@@ -1,230 +0,0 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
import "../../../../config"
QtObject {
id: root
property string status: "..."
property string interfaceName: ""
property string interfaceType: ""
property string connectionName: ""
property string ipv4: ""
property string wifiName: ""
property string signalStrength: ""
property string wifiChannel: ""
property string wifiFrequency: ""
property string linkSpeed: ""
property string downloadSpeed: ""
property string uploadSpeed: ""
property string ping: ""
property bool internetAvailable: false
property bool vpnConnected: false
property string vpnName: ""
property string vpnIp: ""
property bool tailscaleConnected: false
property string tailscaleIp: ""
property bool running: false
property string _activeDevice: ""
property real _prevRxBytes: 0
property real _prevTxBytes: 0
property var _prevUpdateTime: 0
property Timer networkTimer: Timer {
interval: 10000
repeat: true
running: true
onTriggered: networkScript.running = true
}
property Process networkScript: Process {
command: ["sh", "-c",
"echo '===SHOW==='; " +
"ACTIVE=$(nmcli -t device status 2>/dev/null | awk -F: '$3==\"connected\"{print $1; exit}'); " +
"echo \"ACTIVE_DEVICE=$ACTIVE\"; " +
"if [ -n \"$ACTIVE\" ]; then " +
" nmcli -t -f ALL device show \"$ACTIVE\" 2>/dev/null; " +
"fi; " +
"echo '===TRAFFIC==='; " +
"if [ -n \"$ACTIVE\" ]; then " +
" echo \"RX_BYTES=$(cat /sys/class/net/$ACTIVE/statistics/rx_bytes 2>/dev/null || echo 0)\"; " +
" echo \"TX_BYTES=$(cat /sys/class/net/$ACTIVE/statistics/tx_bytes 2>/dev/null || echo 0)\"; " +
"fi; " +
"echo '===WIFI==='; " +
"nmcli -t -f active,ssid,signal,chan,freq,rate dev wifi | awk -F: '$1==\"yes\" { $1=\"\"; sub(/^:/,\"\"); print }'; " +
"echo '===PING==='; " +
"ping -c 1 -W 2 1.1.1.1 2>/dev/null | awk -F/ '/rtt/{print $5}' || echo ''; " +
"echo '===INTERNET==='; " +
"ping -c 1 -W 1 1.1.1.1 2>/dev/null >/dev/null && echo 1 || echo 0; " +
"echo '===VPN==='; " +
"nmcli -t -f NAME,TYPE connection show --active 2>/dev/null | grep -i vpn || true; " +
"echo '===TAILSCALE==='; " +
"TAIL_IP=$(ip -4 addr show tailscale0 2>/dev/null | grep -oP 'inet \\K[\\d.]+'); " +
"if [ -n \"$TAIL_IP\" ]; then echo \"TAILSCALE_IP=$TAIL_IP\"; else echo \"\"; fi"
]
stdout: StdioCollector {
onStreamFinished: root.parseNetworkOutput(text.trim())
}
}
function formatSpeed(bytesPerSec) {
if (bytesPerSec >= 1073741824) return (bytesPerSec / 1073741824).toFixed(1) + " GB/s"
if (bytesPerSec >= 1048576) return (bytesPerSec / 1048576).toFixed(1) + " MB/s"
if (bytesPerSec >= 1024) return (bytesPerSec / 1024).toFixed(1) + " KB/s"
return bytesPerSec.toFixed(0) + " B/s"
}
function parseNetworkOutput(output) {
var sections = output.split("===TAILSCALE===")
var tailscaleSection = sections.length > 1 ? sections[1].trim() : ""
var beforeTailscale = sections[0]
sections = beforeTailscale.split("===VPN===")
var vpnSection = sections.length > 1 ? sections[1].trim() : ""
var beforeVpn = sections[0]
sections = beforeVpn.split("===INTERNET===")
root.internetAvailable = sections.length > 1 ? sections[1].trim() === "1" : false
var beforeInternet = sections[0]
sections = beforeInternet.split("===PING===")
root.ping = sections.length > 1 ? sections[1].trim() : ""
var beforePing = sections[0]
sections = beforePing.split("===WIFI===")
var wifiSection = sections.length > 1 ? sections[1].trim() : ""
var beforeWifi = sections[0]
sections = beforeWifi.split("===TRAFFIC===")
var trafficSection = sections.length > 1 ? sections[1].trim() : ""
var beforeTraffic = sections[0]
sections = beforeTraffic.split("===SHOW===")
var showSection = sections.length > 1 ? sections[1].trim() : ""
// Parse SHOW section
var activeDevice = ""
var lines = showSection.split("\n")
for (var i = 0; i < lines.length; i++) {
var line = lines[i].trim()
if (line.indexOf("ACTIVE_DEVICE=") === 0) {
activeDevice = line.substring("ACTIVE_DEVICE=".length)
} else if (line.indexOf("GENERAL.DEVICE:") === 0) {
root.interfaceName = line.substring("GENERAL.DEVICE:".length)
} else if (line.indexOf("GENERAL.TYPE:") === 0) {
root.interfaceType = line.substring("GENERAL.TYPE:".length)
} else if (line.indexOf("GENERAL.CONNECTION:") === 0) {
root.connectionName = line.substring("GENERAL.CONNECTION:".length)
} else if (line.indexOf("IP4.ADDRESS") >= 0) {
var ipPart = line.substring(line.indexOf(":") + 1)
root.ipv4 = ipPart.split("/")[0]
}
}
// Parse TRAFFIC section
if (trafficSection) {
var trafficLines = trafficSection.split("\n")
var rxBytes = 0
var txBytes = 0
for (var t = 0; t < trafficLines.length; t++) {
var tline = trafficLines[t].trim()
if (tline.indexOf("RX_BYTES=") === 0) rxBytes = parseFloat(tline.substring("RX_BYTES=".length))
else if (tline.indexOf("TX_BYTES=") === 0) txBytes = parseFloat(tline.substring("TX_BYTES=".length))
}
// console.log("[Network] rxBytes:", rxBytes, "txBytes:", txBytes)
// console.log("[Network] activeDevice:", activeDevice, "| prevActiveDevice:", root._activeDevice)
// console.log("[Network] prevRxBytes:", root._prevRxBytes, "prevTxBytes:", root._prevTxBytes, "prevTime:", root._prevUpdateTime)
if (activeDevice === root._activeDevice && root._prevRxBytes > 0 && root._prevUpdateTime > 0) {
var now = Date.now()
var interval = (now - root._prevUpdateTime) / 1000
// console.log("[Network] Same device, interval:", interval, "s")
// console.log("[Network] rxDelta:", (rxBytes - root._prevRxBytes), "txDelta:", (txBytes - root._prevTxBytes))
if (interval > 0) {
var downBps = (rxBytes - root._prevRxBytes) / interval
var upBps = (txBytes - root._prevTxBytes) / interval
// console.log("[Network] downBps:", downBps, "upBps:", upBps)
root.downloadSpeed = root.formatSpeed(downBps)
root.uploadSpeed = root.formatSpeed(upBps)
// console.log("[Network] downloadSpeed:", root.downloadSpeed, "uploadSpeed:", root.uploadSpeed)
} else {
console.log("[Network] Interval zero or negative, skipping")
}
} else {
// console.log("[Network] First run or device changed, storing baseline")
root.downloadSpeed = ""
root.uploadSpeed = ""
}
root._activeDevice = activeDevice
root._prevRxBytes = rxBytes
root._prevTxBytes = txBytes
root._prevUpdateTime = Date.now()
// console.log("[Network] Stored baseline: rxBytes:", root._prevRxBytes, "txBytes:", root._prevTxBytes)
}
// Parse WIFI section
if (wifiSection) {
var wifiParts = wifiSection.split(" ")
if (wifiParts.length >= 2) {
root.wifiName = wifiParts[0] || ""
root.signalStrength = wifiParts[1] || ""
if (wifiParts.length >= 3) root.wifiChannel = wifiParts[2] || ""
if (wifiParts.length >= 4) root.wifiFrequency = wifiParts[3] + " " + wifiParts[4] || ""
if (wifiParts.length >= 5) root.linkSpeed = wifiParts[5] + " " + wifiParts[6] || ""
}
}
// Determine status icon
if (root.interfaceType === "ethernet") {
root.status = "󰈀"
} else if (root.interfaceType === "wifi") {
if (!root.connectionName) {
root.status = "󰤭"
} else {
var sig = parseInt(root.signalStrength)
if (sig > 80) root.status = "󰤨"
else if (sig > 60) root.status = "󰤥"
else if (sig > 40) root.status = "󰤢"
else if (sig > 20) root.status = "󰤟"
else root.status = "󰤯"
}
} else if (!activeDevice) {
root.status = "󰤭/󱐤"
}
// Parse VPN section
if (vpnSection) {
root.vpnConnected = true
var vpnLines = vpnSection.split("\n")
if (vpnLines.length > 0) {
var vpnParts = vpnLines[0].split(":")
root.vpnName = vpnParts[0] || ""
}
} else {
root.vpnConnected = false
root.vpnName = ""
root.vpnIp = ""
}
// Parse TAILSCALE section
if (tailscaleSection && tailscaleSection.indexOf("TAILSCALE_IP=") === 0) {
root.tailscaleConnected = true
root.tailscaleIp = tailscaleSection.substring("TAILSCALE_IP=".length)
} else {
root.tailscaleConnected = false
root.tailscaleIp = ""
}
}
Component.onCompleted: {
networkScript.running = true
}
}
-1
View File
@@ -1 +0,0 @@
singleton NetworkState NetworkState.qml
-85
View File
@@ -1,85 +0,0 @@
import QtQuick
import Quickshell
import "../../../config"
PopupWindow {
id: popup
property Item anchorItem
property bool anchorHovered: false
property int minpopupWidth: 150
property int minpopupHeight: 50
property int popupVerticalOffset: 0
property int spacingValue: 12
property int radiusValue: 12
default property alias content: contentColumn.data
visible: false
color: "transparent"
implicitWidth: Math.max(popup.minpopupWidth, contentColumn.implicitWidth + 2 * popup.spacingValue)
implicitHeight: Math.max(popup.minpopupHeight, contentColumn.implicitHeight + 2 * popup.spacingValue)
onAnchorHoveredChanged: popup.updateVisibility()
function updateVisibility() {
if (anchorHovered || mouseArea.containsMouse) {
closeTimer.stop()
visible = true
} else {
closeTimer.restart()
}
}
Timer {
id: closeTimer
interval: 1
onTriggered: {
if (!anchorHovered && !mouseArea.containsMouse) {
visible = false
}
}
}
anchor {
item: anchorItem
edges: Edges.Top | Edges.Left
gravity: Edges.Bottom | Edges.Right
adjustment: PopupAdjustment.FlipY | PopupAdjustment.SlideX
onAnchoring: {
anchor.rect.x = (anchorItem.width - popup.width) / 2
anchor.rect.y = anchorItem.height + popupVerticalOffset
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onContainsMouseChanged: popup.updateVisibility()
Rectangle {
id: background
anchors.fill: parent
color: Qt.alpha(Colors.primaryContainer, 0.9)
radius: popup.radiusValue
border {
color: Colors.primaryContainer_fg
width: Config.border_width
}
Column {
id: contentColumn
width: implicitWidth
height: implicitHeight
anchors {
top: parent.top
left: parent.left
right: parent.right
margins: popup.spacingValue
}
spacing: popup.spacingValue
}
}
}
}
-188
View File
@@ -1,188 +0,0 @@
import QtQuick
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
import "../../../config"
import "../states/Battery"
MouseArea {
id: batteryButton
width: expanded ? Math.max(expandedRow.width + Config.spacing_fun(height)*3, bar.height) : Math.max(batteryText.width + Config.spacing_fun(height)*2, bar.height)
height: bar.height
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
visible: BatteryState.available
property bool expanded: false
Rectangle {
anchors.fill: parent
color: batteryButton.containsMouse ? Colors.tertiary : Qt.alpha(Colors.tertiaryContainer, 0.25)
radius: Config.radius_fun(batteryButton.height)
border.width: Config.border_width
border.color: batteryButton.containsMouse ? Colors.tertiaryContainer_fg
: Colors.secondaryContainer_fg
Text {
id: batteryText
visible : !expanded
anchors.centerIn: parent
text:(
BatteryState.percentage >= 90 ? "" :
BatteryState.percentage >= 60 ? "" :
BatteryState.percentage >= 30 ? "" :
BatteryState.percentage >= 10 ? "" :
""
)
font.pixelSize: Config.font_size(batteryButton.height)
font.family: Config.font
color: (
BatteryState.charging ? (
BatteryState.percentage == 100 ? Colors.secondary :
Colors.tertiary
) :
BatteryState.percentage <= 5 ? Colors.errorContainer :
BatteryState.percentage < 10 ? "yellow" :
batteryButton.containsMouse ? Colors.tertiary_fg :
Colors.primary
)
}
Text {
id: chargeIcon
visible : !expanded && BatteryState.charging
anchors.centerIn: parent
text: "󱐋"
font.pixelSize: Config.iconSize(batteryButton.height)
font.family: Config.font
style: Text.Outline
styleColor: Qt.alpha(Colors.tertiaryContainer, 0.5)
color: Colors.tertiary
}
Row {
id: expandedRow
visible: expanded
anchors.centerIn: parent
spacing: Config.spacing_fun(batteryButton.height)
Text {
id: batteryPercentageSymbol
text: (
BatteryState.charging ? "󰂄" :
BatteryState.percentage >= 90 ? "󰁹":
BatteryState.percentage >= 80 ? "󰂂":
BatteryState.percentage >= 70 ? "󰂁":
BatteryState.percentage >= 60 ? "󰂀":
BatteryState.percentage >= 50 ? "󰁿":
BatteryState.percentage >= 40 ? "󰁾":
BatteryState.percentage >= 30 ? "󰁽":
BatteryState.percentage >= 20 ? "󰁼":
BatteryState.percentage >= 10 ? "󰁻":
BatteryState.percentage >= 5 ? "󰁺":
"󰂃"
)
font.pixelSize: Config.labelSize(batteryButton.height)
font.family: Config.font
font.bold: true
color: (
BatteryState.percentage <= 5 ? Colors.errorContainer :
BatteryState.charging ? (
BatteryState.percentage == 100 ? Colors.secondary :
Colors.tertiary
) :
BatteryState.percentage < 10 ? "yellow" :
batteryButton.containsMouse ? Colors.tertiary_fg :
Colors.primary
)
}
Text {
id: batteryPercentageText
text: BatteryState.percentage + "%"
font.pixelSize: Config.labelSize(batteryButton.height)
font.family: Config.font
font.bold: true
color: batteryPercentageSymbol.color
}
}
}
onClicked: {
expanded = !expanded
console.log("[Battery] Expanded: " + expanded + ", percentage: " + BatteryState.percentage + "%, charging: " + BatteryState.charging)
}
BarPopup {
id: batteryPopup
anchorItem: batteryButton
anchorHovered: batteryButton.containsMouse
spacingValue: Config.spacing_fun(batteryButton.height)
radiusValue: Config.radius_fun(batteryButton.height)
Column {
spacing: parent.spacing
Text {
text: "percentage: " + BatteryState.percentage + "%"
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "charging: " + BatteryState.charging
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "energy: " + BatteryState.energy
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "voltage: " + BatteryState.voltage
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "charge_cycle: " + BatteryState.charge_cycle
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "time_to_empty: " + BatteryState.time_to_empty + "h"
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "energy_rate: " + BatteryState.energy_rate + "W"
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
}
}
}
+23 -84
View File
@@ -1,97 +1,36 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import "../../../config" import "../../../colors"
import "../states/Clock"
Rectangle { //workspace Rectangle { //workspace
id: clockRect width: timeDisplay.width + 16
width: ClockState.expanded ? Math.max(dateText.width + timeText.width + Config.spacing_fun(height)*3, bar.height) : Math.max(timeText.width + Config.spacing_fun(height)*2, bar.height) height: timeDisplay.height + 16
height: bar.height radius: 4
radius: Config.radius_fun(height) color: Colors.primaryContainer
color: clockArea.containsMouse ? Colors.tertiaryContainer : Colors.primaryContainer border.color: Colors.primaryContainer_fg
border.color: ( border.width: 2
clockArea.containsMouse ? Colors.tertiaryContainer_fg :
Colors.primaryContainer_fg
)
border.width: Config.border_width
MouseArea { Text {
id: clockArea id: timeDisplay
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
onClicked: {
ClockState.expanded = !ClockState.expanded
console.log("[Clock] Date visible: " + ClockState.expanded)
}
Row {
anchors.centerIn: parent
Text { property string currentTime: ""
id: dateText
text: ClockState.shortDate
visible: ClockState.expanded
color: (
clockArea.containsMouse ? Colors.tertiary :
Colors.primary
)
font.pixelSize: Config.font_size_small(clockRect.height)
font.family: Config.font
}
Text { text: currentTime
id: timeText color: Colors.primary
property string currentTime: "" font.pixelSize: 18
font.family: "Inter, sans-serif"
text: ClockState.currentTime anchors.centerIn: parent
color: (
clockArea.containsMouse ? Colors.tertiary :
Colors.primary
)
font.pixelSize: Config.font_size_small(clockRect.height)
font.family: Config.font
}
}
}
BarPopup { //Update time every second
id: clockPopup Timer {
anchorItem: clockRect interval: 1000
anchorHovered: clockArea.containsMouse running: true
spacingValue: Config.spacing_fun(clockRect.height) repeat: true
radiusValue: Config.radius_fun(clockRect.height) onTriggered: {
var now = new Date()
Column { timeDisplay.currentTime = Qt.formatTime(now, "hh:mm:ss")
spacing: parent.spacing
Text {
text: ClockState.shortDate + ClockState.currentTime
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: ClockState.fullDate
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: ClockState.uptime
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
} }
} }
} }
-51
View File
@@ -1,51 +0,0 @@
import QtQuick
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
import "../../../config"
import "../states/Idle"
MouseArea {
id: idleButton
width: Math.max(idleText.width + Config.spacing_fun(height)*2, height)
height: bar.height
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
var newState = IdleState.idle ? 0 : 1
console.log("[IdleButton] Toggling idle: " + (newState ? "enabled" : "disabled"))
idleToggleProc.startDetached()
IdleState.idle = newState
}
Rectangle {
anchors.fill: parent
color: idleButton.containsMouse ? Colors.tertiary : Qt.alpha(Colors.tertiaryContainer, 0.25)
radius: Config.radius_fun(idleButton.height)
border.width: Config.border_width
border.color: (
idleButton.containsMouse ? Colors.tertiaryContainer_fg :
Colors.secondaryContainer_fg
)
Text {
id: idleText
anchors.centerIn: parent
text: IdleState.idle ? "" : ""
font.pixelSize: Config.iconSize(idleButton.height)
font.family: Config.font
color: (
idleButton.containsMouse ? Colors.tertiary_fg :
IdleState.idle ? Colors.tertiary
: Colors.primary
)
}
}
Process {
id: idleToggleProc
command: ["sh", "-c", Config.configDir + "/modules/bar/scripts/Idle.sh"]
running: false
}
}
+11 -22
View File
@@ -1,37 +1,26 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Hyprland
import "../../../config" import "../../../colors"
MouseArea { MouseArea {
id: menuButton id: archButton
width: Math.max(bar.height, menuText.width + Config.spacing) width: 30
height: bar.height height: 28
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: {
menuProc.running = true
}
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: "transparent" color: archButton.containsMouse ? Colors.tertiary : Qt.alpha(Colors.primaryContainer, 0.25)
radius: Config.radius_fun(menuButton.height) radius: 6
Text { Text {
id: menuText anchors.centerIn: parent
anchors.centerIn: parent
text: "󰣇" text: "󰣇"
font.pixelSize: Config.bigIconSize(menuButton.height) font.pixelSize: 26
font.family: Config.font font.family: "Nerd Font"
color: Colors.secondaryContainer_fg color: archButton.containsMouse ? Colors.tertiary_fg : Colors.primary
} }
} }
Process {
id: menuProc
command: ["sh", "-c", "wofi --show drun"]
running: false
}
} }
+26 -184
View File
@@ -1,210 +1,52 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "../../../config" import Quickshell.Hyprland
import "../states/Network" import Quickshell.Io
import "../../../colors"
MouseArea { MouseArea {
id: networkButton id: networkButton
width: output.width + 16
width: Math.max(networkText.width + Config.spacing_fun(height)*2, height)
height: bar.height height: bar.height
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
console.log("[Network] Refreshing... current status: " + NetworkState.status) networkStatus.running = true
NetworkState.networkScript.running = false
NetworkState.networkScript.running = true
} }
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: networkButton.containsMouse ? Colors.tertiary : Qt.alpha(Colors.tertiaryContainer, 0.25) color: networkButton.containsMouse ? Colors.tertiary : Qt.alpha(Colors.tertiaryContainer, 0.25)
radius: Config.radius_fun(networkButton.height) radius: 6
border.width: Config.border_width width: output.width + 16
border.color: networkButton.containsMouse ? Colors.tertiaryContainer_fg
: Colors.secondaryContainer_fg
Text { Text {
id: networkText id: output
text: NetworkState.status
anchors.centerIn: parent anchors.centerIn: parent
font.pixelSize: Config.iconSize(bar.height) font.pixelSize: 26
font.family: Config.font font.family: "Nerd Font"
color: networkButton.containsMouse ? Colors.tertiary_fg : networkText.text === "󰤭 /󱐤" ? Colors.error : Colors.primary color: networkButton.containsMouse ? Colors.tertiary_fg : output.text === "󰤭 /󱐤" ? Colors.error : Colors.primary
} }
}
BarPopup { Process {
id: clockPopup id: networkStatus
anchorItem: networkButton command: ["sh", "-c", Quickshell.env("HOME") + "/.config/quickshell/modules/bar/scripts/Network.sh"]
anchorHovered: networkButton.containsMouse running: true
spacingValue: Config.spacing_fun(networkButton.height)
radiusValue: Config.radius_fun(networkButton.height)
Column { stdout: StdioCollector {
spacing: parent.spacing onStreamFinished: {
Text { output.text = this.text.trim()
text: "interfaceName: " + NetworkState.interfaceName console.log("networkScript output:", this.text.trim())
wrapMode: Text.WordWrap }
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
} }
}
Text { Timer {
text: "interfaceType: " + NetworkState.interfaceType interval: 10000
wrapMode: Text.WordWrap running: true
color: Colors.primary repeat: true
anchors.horizontalCenter: parent.horizontalCenter onTriggered: networkStatus.running = true
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "connectionName: " + NetworkState.connectionName
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "ipv4: " + NetworkState.ipv4
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "wifiName: " + NetworkState.wifiName
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "signalStrength: " + NetworkState.signalStrength
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "wifiChannel: " + NetworkState.wifiChannel
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "wifiFrequency: " + NetworkState.wifiFrequency
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "linkSpeed: " + NetworkState.linkSpeed
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "downloadSpeed: " + NetworkState.downloadSpeed
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "uploadSpeed: " + NetworkState.uploadSpeed
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "ping: " + NetworkState.ping
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "internetAvailable: " + NetworkState.internetAvailable
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "vpnConnected: " + NetworkState.vpnConnected
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "vpnName: " + NetworkState.vpnName
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "vpnIp: " + NetworkState.vpnIp
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "tailscaleConnected: " + NetworkState.tailscaleConnected
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
Text {
text: "tailscaleIp: " + NetworkState.tailscaleIp
wrapMode: Text.WordWrap
color: Colors.primary
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Config.font_size_tiny(bar.height)
font.family: Config.font
}
} }
} }
} }
+29 -12
View File
@@ -1,31 +1,48 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "../../../config" import Quickshell.Hyprland
import Quickshell.Io
import "../../../colors"
MouseArea { MouseArea {
id: powerButton id: powerButton
width: Math.max(powerText.width + Config.spacing_fun(height), height) width: powerText.width + 16
height: bar.height height: bar.height
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: {
console.log("[PowerButton] Opening wlogout")
root.openWlogout()
}
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: powerButton.containsMouse ? Colors.secondaryContainer_fg : Qt.alpha(Colors.secondary, 0.75) color: powerButton.containsMouse ? Colors.secondaryContainer_fg : Qt.alpha(Colors.secondary, 0.5)
radius: Config.radius_fun(powerButton.height) radius: 6
border.width: 0
Item {
anchors.fill: parent
Process {
id: powerOff
command: ["wlogout", "-b", "2"]
stdout: StdioCollector {
onStreamFinished: console.log(`line read: ${this.text}`)
}
}
MouseArea {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onClicked: {
console.log("Running PowerOff Menu")
powerOff.startDetached()
}
}
}
Text { Text {
id: powerText id: powerText
anchors.centerIn: parent anchors.centerIn: parent
text: "" text: ""
font.pixelSize: Config.bigIconSize(bar.height) font.pixelSize: 26
font.family: Config.font font.family: "Nerd Font"
color:powerButton.containsMouse ? Colors.secondaryContainer : Colors.secondary_fg color:powerButton.containsMouse ? Colors.secondaryContainer : Colors.secondary_fg
} }
} }
+67 -106
View File
@@ -1,130 +1,91 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Hyprland
import Quickshell.Services.SystemTray import Quickshell.Services.SystemTray
import Quickshell.Io import Quickshell.Io
import "../../../config" import "../../../colors"
Row { // Workspace Row Row { // Workspace Row
id: trayRow id: trayRow
spacing: Config.small_spacing_fun(height) spacing: 8
Repeater { Repeater {
model: SystemTray.items model: SystemTray.items
Column{
Item { Rectangle { //trayItem
width: 1 id: trayItem
height: Math.floor((bar.height - trayItem.height) / 2) width: bar.height
height: bar.height
radius: 4
color: "transparent"
border.width: 2
Process {
id: steamRunner
command: ["steam", "steam://open/main"]
running: false
} }
Rectangle { //trayItem MouseArea {
id: trayItem id: workspaceButton
width: iconImage.width + Config.spacing_fun(bar.height) hoverEnabled: true
height: iconImage.height + Config.spacing_fun(bar.height) cursorShape: Qt.PointingHandCursor
radius: Config.radius_fun(trayRow.height) anchors.fill: parent
color: trayArea.containsMouse ? Colors.tertiaryContainer acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
: modelData.active ? Colors.primaryContainer onClicked: (mouse) => {
: Colors.secondaryContainer switch (mouse.button) {
border.width: Config.border_width case Qt.LeftButton:
border.color: trayArea.containsMouse ? Colors.tertiaryContainer_fg if (!modelData.onlyMenu) {
: Colors.secondaryContainer_fg modelData.activate()
console.log('Activcate function of ', modelData.title)
Process { }
id: steamRunner if (modelData.title.trim()==="Steam") {
command: ["steam", "steam://open/main"] steamRunner.startDetached()
running: false }
break
case Qt.MiddleButton:
modelData.secondaryActivate()
break
// case Qt.RightButton:
// if (modelData.hasMenu) {
// console.log('Activcate menu of ', modelData.title)
// menuAnchor.open()
// }
// break
}
} }
MouseArea { // QsMenuAnchor {
id: trayArea // id: menuAnchor
hoverEnabled: true // menu: modelData.menu
cursorShape: Qt.PointingHandCursor // anchor.window: menuHost
// }
Rectangle {
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton color: workspaceButton.containsMouse ? Colors.tertiaryContainer
property int clickX: 0 : modelData.active ? Colors.primaryContainer
property int clickY: 0 : Colors.secondaryContainer
onClicked: (mouse) => { border.color: workspaceButton.containsMouse ? Colors.tertiaryContainer_fg
switch (mouse.button) { : modelData.active ? Colors.primaryContainer_fg
case Qt.LeftButton: : Colors.secondaryContainer_fg
console.log("[Tray] Activate: " + modelData.title) radius: 6
if (!modelData.onlyMenu) modelData.activate()
if (modelData.title.trim() === "Steam") {
console.log("[Tray] Starting Steam")
steamRunner.startDetached()
}
break
case Qt.RightButton:
console.log("[Tray] Context menu: " + modelData.title)
clickX = mouse.x
clickY = mouse.y
trayMenu.menu = modelData.menu
trayMenu.open()
break
case Qt.MiddleButton:
console.log("[Tray] Secondary activate: " + modelData.title)
modelData.secondaryActivate()
break
}
}
} }
QsMenuAnchor { }
id: trayMenu
anchor {
item: trayArea
edges: Edges.Top | Edges.Left
gravity: Edges.Bottom | Edges.Right
adjustment: PopupAdjustment.FlipX | PopupAdjustment.SlideY
onAnchoring: {
rect.x = trayArea.clickX
rect.y = trayArea.clickY
rect.w = 1
rect.h = 1
}
}
}
Image { // Image Image { // Image
id: iconImage id: iconImage
anchors.centerIn: parent source: modelData.icon
width: Config.halfBigIconSize(bar.height) fillMode: Image.PreserveAspectCrop
height: Config.halfBigIconSize(bar.height)
asynchronous: true
cache: true
}
Timer { anchors.centerIn: parent
interval: Config.reload_interval
running: true
repeat: true
triggeredOnStart: true
onTriggered: {
let src = modelData.icon;
// console.log("########## icon: " + modelData.icon)
// console.log("########## name: " + modelData.title)
if (modelData.title.includes('GoXLR')) {
// console.log("[Tray] Resolving GoXLR icon path")
let pathMatch = src.match(/path=([^&]+)/);
if (pathMatch && pathMatch[1]) {
let folderPath = pathMatch[1]; width: bar.height*0.75
let segments = folderPath.split('/'); height: bar.height*0.75
let fileName = segments[segments.length - 1] + "-icon.png";
src = "file://" + pathMatch[1] + "/" + fileName;
}
}
// if (modelData.title.includes('Nextcloud')) {
// src = Quickshell.iconPath("Nextcloud")
// }
// console.log("########## icon: " + src)
if (src.exists) {
console.log("########## icon: " + src)
}
// Set the resolved source asynchronous: true
iconImage.source = src; cache: true
}
}
} }
} }
} }
-66
View File
@@ -1,66 +0,0 @@
import QtQuick
import Quickshell
import Quickshell.Hyprland
import "../../../config"
import "../states/Apps"
Item {
id: root
property real pad: Config.spacing_fun(bar.height) * 1.5
anchors.verticalCenter: parent.verticalCenter
implicitWidth: contentRow.implicitWidth + pad * 2
implicitHeight: contentRow.implicitHeight
readonly property string windowClass: Hyprland.activeToplevel?.wayland?.appId ?? ""
readonly property string windowTitle: {
const title = Hyprland.activeToplevel?.title;
if (!title)
return qsTr("Desktop");
return title.split(/\s+[\-\u2013\u2014\|]\s+/).pop();q
}
readonly property string appIcon: {
if (!root.windowClass) return AppsState.matchIcon(root.windowTitle);
let icon = AppsState.matchIcon(root.windowClass);
if (!icon) {
icon = AppsState.matchIcon(root.windowTitle);
}
return icon;
}
Row {
id: contentRow
spacing: Config.spacing_fun(bar.height) * 1.25
anchors.centerIn: parent
Text {
text: root.windowTitle
anchors.verticalCenter: parent.verticalCenter
elide: Text.ElideRight
maximumLineCount: 1
width: Math.min(implicitWidth, 250)
font.pixelSize: Config.iconSize(bar.height) * 0.8
color: Colors.primary
}
Text {
text: root.appIcon
visible: text !== ""
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: Math.round(Config.iconSize(bar.height) * 0.85)
color: Colors.primary
}
}
}
+45 -108
View File
@@ -1,125 +1,62 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import "../../../config" import "../../../colors"
import "../states/Apps"
Row { // Workspace Row
id: workspacesRow
Rectangle {
id: workspacesContainer
required property HyprlandMonitor thisMonitor required property HyprlandMonitor thisMonitor
spacing: 8
height: bar.height - (Config.spacing_fun(bar.height) * 1.5) Repeater { // repeats workspaces
width: workspacesRow.width + (Config.spacing_fun(bar.height) * 2) model: Hyprland.workspaces
Rectangle { //workspace
visible: modelData.monitor === thisMonitor
width: workspaceNum.width + 26
height: workspaceNum.height + 8
radius: 4
color: workspaceButton.containsMouse ? Colors.tertiaryContainer
: modelData.active ? Colors.primaryContainer
: Colors.secondaryContainer
border.color: workspaceButton.containsMouse ? Colors.tertiaryContainer_fg
: modelData.active ? Colors.primaryContainer_fg
: Colors.secondaryContainer_fg
border.width: 2
MouseArea {
id: workspaceButton
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onClicked: Hyprland.dispatch("workspace " + modelData.id)
radius: height / 2 Rectangle {
anchors.fill: parent
color: Colors.surfaceVariant color: "transparent"
border.color: Colors.surfaceVariant_fg radius: 6
border.width: Config.border_width
Row {
id: workspacesRow
anchors.centerIn: parent
spacing: Config.spacing_fun(bar.height) / 2
Repeater {
model: Hyprland.workspaces
Loader {
active: modelData.monitor === thisMonitor
sourceComponent: Item {
id: wsItem
property var workspaceData: modelData
width: Math.max(40, wsIconsRow.width==0 ? wsNum.width + 2*Config.spacing_fun(bar.height) : wsNum.width + wsIconsRow.width + 3*Config.spacing_fun(bar.height)+Config.spacing_fun(bar.height))
// width: {
// var spacing = Config.spacing_fun(bar.height)
// var cw = wsNum.width
// if (wsIconsRow.children.length > 0) {
// cw += spacing + wsIconsRow.width + spacing
// } else {
// cw += spacing * 2
// }
// Math.max(cw, wsNum.height + spacing * 2)
// }
height: workspacesContainer.height
// highlight
Rectangle {
anchors.centerIn: parent
width: parent.width
height: parent.height - (Config.spacing_fun(bar.height) * 1.5)
radius: height / 2
color: wsArea.containsMouse ? Colors.tertiaryContainer
: workspaceData.active ? Colors.primaryContainer
: "transparent"
border.color: wsArea.containsMouse ? Colors.tertiaryContainer_fg
: workspaceData.active ? Colors.primaryContainer_fg
: "transparent"
border.width: (wsArea.containsMouse || workspaceData.active) ? Config.border_width : 0
// hyprland workspace api + color
MouseArea {
id: wsArea
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onClicked: {
console.log("[Workspaces] Switch to workspace: " + workspaceData.id)
Hyprland.dispatch("workspace " + workspaceData.id)
Hyprland.dispatch("hl.dsp.focus({ workspace = "+workspaceData.id+" })")
}
Row {
anchors.left: parent.left
anchors.leftMargin: wsIconsRow.width==0 ? (wsItem.width-wsNum.width)/2 : (wsItem.width-wsNum.width-wsIconsRow.width-Config.spacing_fun(bar.height))/2
anchors.verticalCenter: parent.verticalCenter
spacing: Config.spacing_fun(bar.height)
Text {
id: wsNum
text: workspaceData.id
anchors.verticalCenter: parent.verticalCenter
color: wsArea.containsMouse ? Colors.tertiary
: workspaceData.active ? Colors.primary
: Colors.secondary
font.pixelSize: Config.iconSize(bar.height)
font.family: Config.font
font.bold: true
}
Row {
id: wsIconsRow
spacing: Config.spacing_fun(workspacesContainer.height)
anchors.verticalCenter: parent.verticalCenter
Repeater {
model: AppsState.iconsForWorkspace(workspaceData.id)
delegate: Text {
text: modelData
color: wsArea.containsMouse ? Colors.tertiary
: Colors.secondary
font.pixelSize: Config.labelSize(bar.height)
font.family: Config.font
}
}
}
}
}
}
} }
} }
Text {
id: workspaceNum
text: modelData.id
anchors.centerIn: parent
color: workspaceButton.containsMouse ? Colors.tertiary
: modelData.active ? Colors.primary
: Colors.secondary
font.pixelSize: 18
font.family: "Inter, sans-serif"
}
} }
} }
Text { Text {
visible: Hyprland.workspaces.length === 0 visible: Hyprland.workspaces.length === 0
text: "No Workspaces" text: "No Workspaces"
color: Colors.error color: Colors.error
font.pixelSize: Config.iconSize(bar.height) font.pixelSize: 18
anchors.centerIn: parent
} }
} }
-142
View File
@@ -1,142 +0,0 @@
import QtQuick
import Quickshell
import QtQuick.Controls
import Quickshell.Wayland
import Quickshell.Hyprland
import Quickshell.Io
import "../../config"
import "./modules"
PanelWindow {
id: learner
implicitWidth: screen.width * 0.75
implicitHeight: screen.height * 0.5
color: "transparent"
visible: true
focusable: true
Component.onCompleted: {
semiJLoader.all_invisible()
semiJLoader.switchModeChooser()
}
FocusScope {
id: jLearnerScope
focus: true
Keys.onReleased: function(event) {
if (event.key === Qt.Key_Escape) {
console.log("Pressed Escape, closing JLearner")
jLearnerLoader.active = false
}
}
Rectangle {
anchors.fill: parent
color: "lightblue"
}
}
Rectangle {
anchors.fill: parent
radius: 10
color: Qt.alpha(Colors.surfaceContainerLowest, 0.5)
border.width: 2
border.color: Colors.outlineVariant
clip: true
Rectangle{
width: parent.width - 20
height: parent.height - 20
anchors.centerIn: parent
color: "transparent"
Column {
id: learnerWindow
anchors.fill: parent
spacing: 10
Rectangle {
id: head
width: parent.width
height: parent.height * 0.1
color: Colors.tertiaryContainer
radius: 10
border.width: 2
border.color: Colors.tertiaryContainer_fg
Text {
text: "Language Learner"
anchors.centerIn: parent
font.pixelSize: parent.height * 0.8
font.family: Config.font
color: Colors.tertiary
}
}
Rectangle{
id: semiJLoader
width: parent.width
height: parent.height * 0.9 - parent.spacing
color: "transparent"
function all_invisible() {
languageChooser.visible = false
kanaVoicing.visible = false
voicingKana.visible = false
learnerResult.visible = false
}
function switchModeChooser() {
all_invisible()
languageChooser.visible = true
languageChooser.start()
}
function switch_KanaVoicing() {
all_invisible()
kanaVoicing.visible = true
kanaVoicing.start()
}
function switch_VoicingKana() {
all_invisible()
voicingKana.visible = true
voicingKana.start()
}
function switchResult(result, mode, results) {
all_invisible()
console.log("Result: " + result)
console.log("Mode: " + mode)
learnerResult.visible = true
learnerResult.result = result
learnerResult.mode = mode
learnerResult.results = results
learnerResult.start()
}
ModeChooser {
id: languageChooser
}
KanaVoicing {
id: kanaVoicing
}
VoicingKana {
id: voicingKana
}
JLearnerResult {
id: learnerResult
}
}
}
}
}
}
-29
View File
@@ -1,29 +0,0 @@
import QtQuick
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
Item { // container, invisible
id: jLoader
Loader {
id: jLearnerLoader
active: false
sourceComponent: JLearner { id: jLearner }
}
GlobalShortcut {
name: "JLearner"
description: "Open Japanese Learner"
onPressed: {
console.log("Pressed Meta+Shift+J (Hyprland global shortcut)")
jLearnerLoader.active = !jLearnerLoader.active
}
}
function closeJLearner() {
jLearnerLoader.active = false
}
}
-300
View File
@@ -1,300 +0,0 @@
import QtQuick
import QtQuick.Controls
import "../../../config"
Item { // Chooser
id: learnerResult
width: parent.width
height: parent.height
anchors.margins: 15
visible: false
function switch_KanaVoicing() {
parent.switch_KanaVoicing()
}
function start() {
}
property real result: 0
property string mode: ""
property var results: createResults(10)
function createResults(n) {
var arr = []
for (var i = 0; i < n; i++) {
arr.push({
kana: "あ",
correctness: false,
answer: "a",
correct: "a"
})
}
return arr
}
Column {
anchors.fill: parent
spacing: 10
Rectangle {
id: learnerResultUpperText
color: Colors.primaryContainer
width: parent.width
height: parent.height * 0.1
radius: 10
border.width: 2
border.color: Colors.primaryContainer_fg
Text {
id: mainText
text: "Ergebnisse:"
anchors.centerIn: parent
font.pixelSize: parent.height * 0.6
color: Colors.primary
}
}
Row {
width: parent.width
height: parent.height - learnerResultUpperText.height - parent.spacing
spacing: 10
Rectangle {
width: parent.width * 0.25
height: parent.height
color: "transparent"
Column{
width: parent.width
height: parent.height
spacing: 10
Repeater{
model: results
Row{
width: parent.width
height: parent.height/10 - parent.spacing * 0.9
spacing: 10
Rectangle{
width: parent.height
height: parent.height
color: Colors.primaryContainer
radius: 10
border.width: 2
border.color: Colors.primaryContainer_fg
Text{
text: modelData.kana
width: parent.width
height: parent.height
anchors.centerIn: parent
anchors.verticalCenterOffset: -parent.height * 0.125
anchors.horizontalCenterOffset: parent.width * 0.1
font.pixelSize: parent.height * 0.8
font.family: Config.jfont
color: modelData.correctness ? "green" : "red"
}
}
Rectangle{
width: parent.height
height: parent.height
color: Colors.primaryContainer
radius: 10
border.width: 2
border.color: Colors.primaryContainer_fg
Image {
source: modelData.correctness ? Config.configDir+"/modules/jl/assets/correct.svg" : Config.configDir+"/modules/jl/assets/wrong.svg"
anchors.centerIn: parent
width: parent.height*0.8
height: parent.height*0.8
smooth: true
sourceSize.width: width
sourceSize.height: height
}
}
Rectangle{
width: parent.width - parent.height *2 - parent.spacing*2
height: parent.height
color: Colors.primaryContainer
radius: 10
border.width: 2
border.color: Colors.primaryContainer_fg
Text{
text: "[" + modelData.correct + "]"
width: parent.width
height: parent.height
anchors.centerIn: parent
anchors.horizontalCenterOffset: 10
font.pixelSize: parent.height * 0.8
font.family: Config.font
color: modelData.correctness ? "green" : "red"
}
}
}
}
}
}
Rectangle{
width: parent.width * 0.75
height: parent.height
color: "transparent"
Column{
width: parent.width
height: parent.height
spacing: 10
Row {
spacing: 10
width: parent.width
height: parent.height * 4 / 10 - parent.spacing * 2 / 3
Rectangle {
color: "transparent"
width: (parent.width - (learnerLastResultKanaBG.width + learnerLastResultTextBG.width))/2
height: parent.height
}
Rectangle {
id: learnerLastResultKanaBG
color: results[results.length-1].correctness ? "green" : "red"
width: parent.height - parent.spacing
height: parent.height
radius: 10
border.width: 2
border.color: Colors.primaryContainer_fg
Text {
id: learnerLastResultKana
text: results[results.length-1].kana
width: parent.width
height: parent.height
anchors.centerIn: parent
anchors.verticalCenterOffset: -parent.height * 0.1
font.pixelSize: parent.height * 0.8
font.family: Config.font
color: Colors.primary
}
}
Rectangle {
id: learnerLastResultTextBG
color: results[results.length-1].correctness ? "green" : "red"
width: learnerLastResultText.width + 2 * parent.spacing
height: parent.height
radius: 10
border.width: 2
border.color: Colors.primaryContainer_fg
Text {
id: learnerLastResultText
text: "[" + results[results.length-1].correct + "]"
anchors.centerIn: parent
font.pixelSize: learnerLastResultKana.font.pixelSize/2
font.family: Config.font
color: Colors.primary
}
}
}
Rectangle {
id: learnerResultTextBG
color: Colors.primaryContainer
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
height: parent.height * 3 / 10 - parent.spacing * 2 / 3
radius: 10
border.width: 2
border.color: Colors.primaryContainer_fg
Text {
id: learnerResultText
text: result*100 + "% Richtig"
width: parent.width
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
font.family: Config.font
color: Colors.primary
}
}
Row {
width: parent.width
height: parent.height * 3 / 10 - parent.spacing * 2 / 3
spacing: 10
MouseArea {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
width: parent.width / 2 - parent.spacing
height: parent.height
onClicked: {
console.log("Choosing White Window")
mode === "KanaVoicing" ? learnerResult.parent.switch_KanaVoicing() : learnerResult.parent.switch_VoicingKana()
}
Rectangle {
anchors.fill: parent
color: parent.containsMouse ? Colors.secondaryContainer_fg : Colors.secondaryContainer
radius: 10
border.width: 2
border.color: parent.containsMouse ? Colors.secondaryContainer : Colors.secondaryContainer_fg
Text {
text: "Again"
anchors.centerIn: parent
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
font.family: Config.font
color: parent.parent.containsMouse ? Colors.secondary_fg : Colors.secondary
}
}
}
MouseArea {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
width: parent.width / 2 - parent.spacing
height: parent.height
onClicked: {
console.log("Choosing Black Window")
learnerResult.parent.switchModeChooser()
}
Rectangle {
anchors.fill: parent
color: parent.containsMouse ? Colors.secondaryContainer_fg : Colors.secondaryContainer
radius: 10
border.width: 2
border.color: parent.containsMouse ? Colors.secondaryContainer : Colors.secondaryContainer_fg
Text {
text: "Menu"
anchors.centerIn: parent
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
font.family: Config.font
color: parent.parent.containsMouse ? Colors.secondary_fg : Colors.secondary
}
}
}
}
}
}
}
}
}
-80
View File
@@ -1,80 +0,0 @@
import QtQuick
QtObject {
property var kana: [
{ hira: "あ", voice: ["a"], known: true },
{ hira: "い", voice: ["i"], known: true },
{ hira: 'う', voice: ["u"], known: true },
{ hira: 'え', voice: ["e"], known: true },
{ hira: 'お', voice: ["o"], known: true },
{ hira: 'か', voice: ["ka"], known: true },
{ hira: 'が', voice: ["ga"], known: true },
{ hira: 'き', voice: ["ki"], known: true },
{ hira: 'ぎ', voice: ["gi"], known: true },
{ hira: 'く', voice: ["ku"], known: true },
{ hira: 'ぐ', voice: ["gu"], known: true },
{ hira: 'け', voice: ["ke"], known: true },
{ hira: 'げ', voice: ["ge"], known: true },
{ hira: 'こ', voice: ["ko"], known: true },
{ hira: 'ご', voice: ["go"], known: true },
{ hira: 'さ', voice: ["sa"], known: true },
{ hira: 'ざ', voice: ["za"], known: true },
{ hira: 'し', voice: ["si", "shi"], known: true },
{ hira: 'じ', voice: ["zi", "ji"], known: true },
{ hira: 'す', voice: ["su"], known: true },
{ hira: 'ず', voice: ["zu"], known: true },
{ hira: 'せ', voice: ["se"], known: true },
{ hira: 'ぜ', voice: ["ze"], known: true },
{ hira: 'そ', voice: ["so"], known: true },
{ hira: 'ぞ', voice: ["zo"], known: true },
{ hira: 'た', voice: ["ta"], known: true },
{ hira: 'だ', voice: ["da"], known: true },
{ hira: 'ち', voice: ["ti", "shi"], known: true },
{ hira: 'ぢ', voice: ["di", "ji"], known: true },
{ hira: 'つ', voice: ["tu", "tsu"], known: true },
{ hira: 'づ', voice: ["du", "zu"], known: true },
{ hira: 'て', voice: ["te"], known: true },
{ hira: 'で', voice: ["de"], known: true },
{ hira: 'と', voice: ["to"], known: true },
{ hira: 'ど', voice: ["do"], known: true },
{ hira: 'な', voice: ["na"], known: true },
{ hira: 'に', voice: ["ni"], known: true },
{ hira: 'ぬ', voice: ["nu"], known: false },
{ hira: 'ね', voice: ["ne"], known: false },
{ hira: 'の', voice: ["no"], known: false },
{ hira: 'は', voice: ["ha"], known: false },
{ hira: 'ば', voice: ["ba"], known: false },
{ hira: 'ぱ', voice: ["pa"], known: false },
{ hira: 'ひ', voice: ["hi"], known: false },
{ hira: 'び', voice: ["bi"], known: false },
{ hira: 'ぴ', voice: ["pi"], known: false },
{ hira: 'ふ', voice: ["hu"], known: false },
{ hira: 'ぶ', voice: ["bu"], known: false },
{ hira: 'ぷ', voice: ["pu"], known: false },
{ hira: 'へ', voice: ["he"], known: false },
{ hira: 'べ', voice: ["be"], known: false },
{ hira: 'ぺ', voice: ["pe"], known: false },
{ hira: 'ほ', voice: ["ho"], known: false },
{ hira: 'ぼ', voice: ["bo"], known: false },
{ hira: 'ぽ', voice: ["po"], known: false },
{ hira: 'ま', voice: ["ma"], known: false },
{ hira: 'み', voice: ["mi"], known: false },
{ hira: 'む', voice: ["mu"], known: false },
{ hira: 'め', voice: ["me"], known: false },
{ hira: 'も', voice: ["mo"], known: false },
{ hira: 'や', voice: ["ya"], known: false },
{ hira: 'ゆ', voice: ["yu"], known: false },
{ hira: 'よ', voice: ["yo"], known: false },
{ hira: 'ら', voice: ["ra"], known: false },
{ hira: 'り', voice: ["ri"], known: false },
{ hira: 'る', voice: ["ru"], known: false },
{ hira: 'れ', voice: ["re"], known: false },
{ hira: 'ろ', voice: ["ro"], known: false },
{ hira: 'わ', voice: ["wa"], known: false },
{ hira: 'ゐ', voice: ["wi"], known: false },
{ hira: 'ゑ', voice: ["we"], known: false },
{ hira: 'を', voice: ["wo"], known: false },
{ hira: 'ん', voice: ["n"], known: true },
{ hira: 'ゔ', voice: ["vu"], known: false }
]
}
-186
View File
@@ -1,186 +0,0 @@
import QtQuick
import QtQuick.Controls
import "../../../config"
Item { // Kana_Try
id: kanaVoicing
width: parent.width
height: parent.height
anchors.margins: 15
visible: false
// Component.onCompleted: {
// randomKnownKana()
// }
function start() {
kanaVoicingAnswer.focus = true
roundNum = 0
randomKnownKana()
}
KanaData {
id: kanaData
}
property var currentKana: []
property int roundNum: 0
property int correct: 0
property int maxRoundNum: 10
property var pastKana: []
property var pastCorrectness: []
function endRounds() {
kanaVoicingAnswer.focus = false
jLearnerScope.focus = true
console.log("Switching back")
parent.switchResult(correct/maxRoundNum, "KanaVoicing", pastCorrectness)
pastKana = []
pastCorrectness = []
correct = 0
kanaVoicingAnswer.placeholderText = "Type Voicing..."
kanaVoicingAnswerBackground.color = kanaVoicingAnswer.activeFocus ? Colors.tertiary_fg : Colors.primary_fg
}
function randomKana() {
if (roundNum >= maxRoundNum) {
endRounds()
}
var list = kanaData.kana
currentKana = list[Math.floor(Math.random() * list.length)]
if (knownList.length > maxRoundNum) {
while (pastKana.includes(currentKana)) {
currentKana = list[Math.floor(Math.random() * list.length)]
}
}
pastKana.push(currentKana)
console.log("Round Num: " + roundNum + " - Choosing Kana: " + currentKana.hira)
roundNum = roundNum + 1
}
function randomKnownKana() {
if (roundNum >= maxRoundNum) {
endRounds()
}
var knownList = kanaData.kana.filter(k => k.known)
currentKana = knownList[Math.floor(Math.random() * knownList.length)]
if (knownList.length > maxRoundNum) {
while (pastKana.includes(currentKana)) {
currentKana = knownList[Math.floor(Math.random() * knownList.length)]
}
}
pastKana.push(currentKana)
console.log("Round Num: " + roundNum + " - Choosing Kana: " + currentKana.hira)
roundNum = roundNum + 1
}
Column {
anchors.fill: parent
spacing: 10
Rectangle {
id: kanaVoicingTextRectangale
color: Colors.primaryContainer
width: kanaVoicingText.width + 20
height: parent.height * 0.1
anchors.horizontalCenter: parent.horizontalCenter
radius: 10
border.width: 2
border.color: Colors.primaryContainer_fg
Text {
id: kanaVoicingText
text: "Im Spiel - Runde: " + kanaVoicing.roundNum
anchors.centerIn: parent
font.pixelSize: parent.height * 0.6
font.family: Config.font
color: Colors.primary
}
}
Rectangle {
id: kanaVoicingKanaRectangle
color: Colors.primaryContainer
height: (parent.height - kanaVoicingTextRectangale.height)*0.75
width: height
anchors.horizontalCenter: parent.horizontalCenter
radius: 10
border.width: 2
border.color: Colors.primaryContainer_fg
Text {
id: kanaVoicingKana
text: typeof kanaVoicing.currentKana.hira === "undefined" ? "" : kanaVoicing.currentKana.hira
anchors.centerIn: parent
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
font.family: Config.jfont
color: Colors.primary
}
}
TextField {
id: kanaVoicingAnswer
placeholderText: "Type Voicing..."
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width/2
height: (parent.height - kanaVoicingTextRectangale.height)*0.25 - parent.spacing*2
font.pixelSize: height * 0.8
color: Colors.secondary_fg
placeholderTextColor: Colors.secondary
background: Rectangle {
id: kanaVoicingAnswerBackground
radius: 10
color: kanaVoicingAnswer.activeFocus ? Colors.secondaryContainer : Colors.secondaryContainer_fg
border.color: kanaVoicingAnswer.activeFocus ? Colors.secondaryContainer_fg : Colors.secondaryContainer
border.width: 1
}
Keys.onReleased: function(event) {
if (event.key === Qt.Key_Escape) {
console.log("Escape pressed inside TextField")
console.log("Pressed Escape, closing JLearner")
jLearnerLoader.active = false
}
}
onAccepted: function(event) {
console.log("Enter pressed inside TextField")
if (kanaVoicing.currentKana.voice.includes(kanaVoicingAnswer.text.toLowerCase())){
console.log("Correct")
kanaVoicingAnswer.text = ""
kanaVoicingAnswer.placeholderText = "[" + kanaVoicing.currentKana.voice + "]"
kanaVoicingAnswerBackground.color = "green"
kanaVoicing.correct = kanaVoicing.correct + 1
pastCorrectness.push({
kana: kanaVoicing.currentKana.hira,
correctness: true,
answer: kanaVoicingAnswer.text.toLowerCase(),
correct: kanaVoicing.currentKana.voice.join("|")
})
} else {
console.log("Wrong: [" + currentKana.voice + "]")
kanaVoicingAnswer.text = ""
kanaVoicingAnswerBackground.color = "red"
kanaVoicingAnswer.placeholderText = "[" + kanaVoicing.currentKana.voice + "]"
pastCorrectness.push({
kana: kanaVoicing.currentKana.hira,
correctness: false,
answer: kanaVoicingAnswer.text.toLowerCase(),
correct: kanaVoicing.currentKana.voice.join("|")
})
}
randomKnownKana()
}
}
}
}
-101
View File
@@ -1,101 +0,0 @@
import QtQuick
import QtQuick.Controls
import "../../../config"
Item { // Chooser
id: languageChooser
width: parent.width
height: parent.height
anchors.margins: 15
visible: false
Column {
anchors.fill: parent
spacing: 10
Rectangle {
id: modeChooserUpperText
color: Colors.primaryContainer
width: mainText.width + 20
height: parent.height * 0.1
anchors.horizontalCenter: parent.horizontalCenter
radius: 10
border.width: 2
border.color: Colors.primaryContainer_fg
Text {
id: mainText
text: "Wähle ein Modus:"
anchors.centerIn: parent
font.pixelSize: parent.height * 0.6
font.family: Config.font
color: Colors.primary
}
}
Row {
width: parent.width
height: parent.height - modeChooserUpperText.height - parent.spacing
spacing: 10
MouseArea {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
width: (parent.width - parent.spacing) / 2
height: parent.height
onClicked: {
console.log("Choosing White Window")
languageChooser.parent.switch_KanaVoicing()
}
Rectangle {
anchors.fill: parent
color: parent.containsMouse ? Colors.secondaryContainer_fg : Colors.secondaryContainer
radius: 10
border.width: 2
border.color: parent.containsMouse ? Colors.secondaryContainer : Colors.secondaryContainer_fg
Text {
text: "Kana to Voicing"
anchors.centerIn: parent
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
font.family: Config.font
color: parent.parent.containsMouse ? Colors.secondary_fg : Colors.secondary
}
}
}
MouseArea {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
width: (parent.width - parent.spacing) / 2
height: parent.height
onClicked: {
console.log("Choosing Black Window")
languageChooser.parent.switch_VoicingKana()
}
Rectangle {
anchors.fill: parent
color: parent.containsMouse ? Colors.secondaryContainer_fg : Colors.secondaryContainer
radius: 10
border.width: 2
border.color: parent.containsMouse ? Colors.secondaryContainer : Colors.secondaryContainer_fg
Text {
text: "Voicing to Kana"
anchors.centerIn: parent
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
font.family: Config.font
color: parent.parent.containsMouse ? Colors.secondary_fg : Colors.secondary
}
}
}
}
}
}
-237
View File
@@ -1,237 +0,0 @@
import QtQuick
import QtQuick.Controls
import "../../../config"
Item { // Kana_Try
id: voicingKana
width: parent.width
height: parent.height
anchors.margins: 15
visible: false
// Component.onCompleted: {
// randomKnownKana()
// }
function start() {
roundNum = 0
new_round()
}
KanaData {
id: kanaData
}
property int roundNum: 0
property int correct: 0
property int maxRoundNum: 10
property var pastKana: []
property var pastCorrectness: []
property var kanaArray: createResults(6)
property var targetKana: kanaArray[Math.floor(Math.random() * kanaArray.length)]
function createResults(n) {
var arr = []
for (var i = 0; i < n; i++) {
arr.push({ hira: "あ", voice: ["a"], known: true })
}
return arr
}
function new_round() {
roundNum = roundNum + 1
kanaArray = gemerateKanaArray()
targetKana = kanaArray[Math.floor(Math.random() * kanaArray.length)]
console.log("Round Num: " + roundNum + " - Choosing Kana: " + targetKana.hira)
pastKana.push(targetKana)
}
function gemerateKanaArray() {
var arr = []
for (var i = 0; i < 6; i++) {
arr.push(randomKnownKana(arr))
}
return arr
}
function randomKana(arr) {
if (roundNum > maxRoundNum) {
endRounds()
}
var list = kanaData.kana
var newKana = list[Math.floor(Math.random() * list.length)]
var arrExists = Array.isArray(arr)
if (knownList.length > maxRoundNum + 6) {
if (arrExists) {
while (pastKana.includes(newKana) || arr.includes(newKana)) {
newKana = list[Math.floor(Math.random() * list.length)]
}
} else{
while (pastKana.includes(newKana)){
newKana = list[Math.floor(Math.random() * list.length)]
}
}
} else {
if (arrExists) {
while (arr.includes(newKana)) {
newKana = list[Math.floor(Math.random() * list.length)]
}
}
}
kanaArray.push(newKana)
return newKana
}
function randomKnownKana(arr) {
if (roundNum > maxRoundNum) {
endRounds()
}
var knownList = kanaData.kana.filter(k => k.known)
var newKana = knownList[Math.floor(Math.random() * knownList.length)]
var arrExists = Array.isArray(arr)
if (knownList.length > maxRoundNum + 6) {
if (arrExists) {
while (pastKana.includes(newKana) || arr.includes(newKana)) {
newKana = knownList[Math.floor(Math.random() * knownList.length)]
}
} else{
while (pastKana.includes(newKana)){
newKana = knownList[Math.floor(Math.random() * knownList.length)]
}
}
} else {
if (arrExists) {
while (arr.includes(newKana)) {
newKana = knownList[Math.floor(Math.random() * knownList.length)]
}
}
}
return newKana
}
function endRounds() {
console.log("Switching back")
roundNum = 0
parent.switchResult(correct/maxRoundNum, "VoicingKana", pastCorrectness)
}
Column {
anchors.fill: parent
spacing: 10
Rectangle {
id: voicingKanaTextRectangale
color: Colors.primaryContainer
width: mainText.width + 20
height: parent.height * 0.1
anchors.horizontalCenter: parent.horizontalCenter
radius: 10
border.width: 2
border.color: Colors.primaryContainer_fg
Text {
id: mainText
text: "Runde: " + roundNum + " - [" + targetKana.voice.join("|") + "]:"
anchors.centerIn: parent
font.pixelSize: parent.height * 0.6
font.family: Config.font
color: Colors.primary
}
}
Rectangle{
width: parent.width
height: parent.height - voicingKanaTextRectangale.height - voicingKanaResultRectangale.height - parent.spacing * 2
color: "transparent"
Grid {
id: grid
anchors.fill: parent
columns: 3
spacing: 10
property int rows: 2
// calculate cell width and height based on parent size, spacing, and number of columns/rows
property real cellWidth: (width - (columns - 1) * spacing) / columns
property real cellHeight: (height - (rows - 1) * spacing) / rows
Repeater {
model: kanaArray
MouseArea {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
width: grid.cellWidth
height: grid.cellHeight
onClicked: {
console.log("Choose a Kana: " + modelData.hira)
if (modelData.hira === targetKana.hira) {
console.log("Correct")
correct = correct + 1
voicingKanaResultRectangale.color = "green"
} else {
console.log("Wrong: [" + targetKana.hira + "]")
voicingKanaResultRectangale.color = "red"
}
pastCorrectness.push({
kana: targetKana.hira,
correctness: modelData.hira === targetKana.hira,
answer: modelData.hira,
correct: targetKana.voice.join("|")
})
voicingKanaResult.text = "Letzte Runde: " + targetKana.hira + ": " + "[" + targetKana.voice.join("|") + "]"
new_round()
}
Rectangle {
width: parent.width
height: parent.height
color: parent.containsMouse ? Colors.secondaryContainer_fg : Colors.secondaryContainer
radius: 10
border.width: 2
border.color: parent.containsMouse ? Colors.secondaryContainer : Colors.secondaryContainer_fg
Text{
text: modelData.hira
anchors.centerIn: parent
anchors.verticalCenterOffset: -parent.height * 0.1
font.pixelSize: parent.height * 0.8
font.family: Config.jfont
color: parent.parent.containsMouse ? Colors.secondary_fg : Colors.secondary
}
}
}
}
}
}
Rectangle {
id: voicingKanaResultRectangale
color: Colors.primaryContainer
width: voicingKanaResult.width + 20
height: parent.height * 0.1
anchors.horizontalCenter: parent.horizontalCenter
radius: 10
border.width: 2
border.color: Colors.primaryContainer_fg
Text {
id: voicingKanaResult
text: "Wähle das richtige Zeichen"
anchors.centerIn: parent
font.pixelSize: parent.height * 0.6
font.family: Config.font
color: Colors.primary
}
}
}
}
-22
View File
@@ -1,22 +0,0 @@
import QtQuick
import Quickshell.Io
QtObject {
required property string command
required property string text
required property string icon
required property string icon_text
property var keybind: null
id: button
readonly property var process: Process {
command: ["sh", "-c", button.command]
}
function exec() {
process.startDetached();
console.log("Picked Logout Option, closing WLogout");
wlogoutLoader.active = false;
}
}
-135
View File
@@ -1,135 +0,0 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import "../../config"
Variants {
id: root
property color buttonColor: Colors.secondaryContainer
property color buttonHoverColor: Colors.primary
property color borderColor: Colors.secondaryContainer_fg
property color borderHoverColor: Colors.primaryContainer_fg
default property list<LogoutButton> buttons
model: Quickshell.screens
PanelWindow {
id: w
property var modelData
screen: modelData
exclusionMode: ExclusionMode.Ignore
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
color: "transparent"
contentItem {
focus: true
Keys.onPressed: event => {
if (event.key == Qt.Key_Escape) {
console.log("Pressed Escape, closing Wallpaper Picker")
console.log("Wallpaper Dir:", Config.wallpaperDir)
wlogoutLoader.active = false
} else {
for (let i = 0; i < buttons.length; i++) {
let button = buttons[i];
if (event.key == button.keybind) button.exec();
}
}
}
}
anchors {
top: true
left: true
bottom: true
right: true
}
Rectangle {
anchors.fill: parent
Image {
anchors.fill: parent
source: Config.wallpaperDir + "/Static/blurred.jpg"
fillMode: Image.PreserveAspectCrop
}
MouseArea {
anchors.fill: parent
onClicked: {
console.log("clicked ???, closing Wallpaper Picker")
wlogoutLoader.active = false
}
GridLayout {
anchors.centerIn: parent
width: parent.width * 0.75
height: parent.height * 0.75
columns: 3
columnSpacing: 20
rowSpacing: 20
Repeater {
model: buttons
delegate: Rectangle {
required property LogoutButton modelData;
Layout.fillWidth: true
Layout.fillHeight: true
color: ma.containsMouse ? buttonHoverColor : buttonColor
radius: 10
border.color: ma.containsMouse ? borderColor : borderHoverColor
border.width: 2
MouseArea {
id: ma
anchors.fill: parent
hoverEnabled: true
onClicked: modelData.exec()
}
Image {
id: icon
anchors.centerIn: parent
source: `icons/${modelData.icon}.svg`
width: parent.width * 0.3
height: parent.width * 0.3
sourceSize.width: width
sourceSize.height: height
}
// Text {
// id: icon
// anchors.centerIn: parent
// text: modelData.icon_text ?? "?"
// font.pointSize: parent.height * 0.4
// color: "white"
// }
Text {
anchors {
top: icon.bottom
topMargin: 20
horizontalCenter: parent.horizontalCenter
}
text: modelData.text
font.pointSize: 20
color: "white"
}
}
}
}
}
}
}
}
-55
View File
@@ -1,55 +0,0 @@
import QtQuick
import Quickshell
import "../../config"
ShellRoot {
WLogout {
LogoutButton {
command: Config.configDir + "/modules/wlogout/scripts/lock.sh"
keybind: Qt.Key_L
text: "Lock"
icon: "lock"
icon_text: ""
}
LogoutButton {
command: Config.configDir + "/modules/wlogout/scripts/logout.sh"
keybind: Qt.Key_E
text: "Logout"
icon: "logout"
icon_text: "󰗽"
}
LogoutButton {
command: Config.configDir + "/modules/wlogout/scripts/suspend.sh"
keybind: Qt.Key_U
text: "Suspend"
icon: "suspend"
icon_text: ""
}
LogoutButton {
command: Config.configDir + "/modules/wlogout/scripts/hibernate.sh"
keybind: Qt.Key_H
text: "Hibernate"
icon: "hibernate"
icon_text: "󰰂"
}
LogoutButton {
command: Config.configDir + "/modules/wlogout/scripts/shutdown.sh"
keybind: Qt.Key_K
text: "Shutdown"
icon: "shutdown"
icon_text: "⏻"
}
LogoutButton {
command: Config.configDir + "/modules/wlogout/scripts/reboot.sh"
keybind: Qt.Key_R
text: "Reboot"
icon: "reboot"
icon_text: "󰜉 "
}
}
}
-36
View File
@@ -1,36 +0,0 @@
import QtQuick
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
import "../../config"
Item { // container, invisible
id: wlLoader
Loader {
id: wlogoutLoader
active: false
sourceComponent: Wlogout {
id: wLogout
}
}
GlobalShortcut {
name: "WLogout"
description: "Open WLogout"
onPressed: {
console.log("Pressed Meta+Shift+W (Hyprland global shortcut)")
wlogoutLoader.active = !wlogoutLoader.active
}
}
function openWlogout() {
wlogoutLoader.active = true
}
function closeWlogout() {
wlogoutLoader.active = false
}
}
-2
View File
@@ -1,2 +0,0 @@
#!/bin/bash
systemctl hibernate
-2
View File
@@ -1,2 +0,0 @@
#!/bin/bash
hyprlock
-22
View File
@@ -1,22 +0,0 @@
#!/bin/bash
# 1. Run helper script if it exists
if [[ -x "$SCRIPT_PATH" ]]; then
echo "Running helper script..."
bash "$SCRIPT_PATH"
else
echo "Helper script not found, skipping..."
fi
# 2. Run hyprshutdown if available
if command -v hyprshutdown >/dev/null 2>&1; then
echo "Running hyprshutdown..."
hyprshutdown
else
echo "Rebooting system..."
if command -v systemctl >/dev/null 2>&1; then
systemctl loginctl terminate-user $USER
else
pkill -KILL -u "$USER" -t tty2
fi
fi
-29
View File
@@ -1,29 +0,0 @@
#!/usr/bin/env bash
set -e
SCRIPT_PATH="$HOME/.config/quickshell/modules/wlogout/scripts/helper.sh"
# 1. Run helper script if it exists
if [[ -x "$SCRIPT_PATH" ]]; then
echo "Running helper script..."
bash "$SCRIPT_PATH"
else
echo "Helper script not found, skipping..."
fi
# 2. Run hyprshutdown if available
if command -v hyprshutdown >/dev/null 2>&1; then
echo "Running hyprshutdown..."
hyprshutdown
else
echo "hyprshutdown not found, skipping..."
fi
# 3. Power off if systemctl exists
if command -v systemctl >/dev/null 2>&1; then
echo "Rebooting system..."
systemctl reboot
else
reboot
fi
-29
View File
@@ -1,29 +0,0 @@
#!/usr/bin/env bash
set -e
SCRIPT_PATH="$HOME/.config/quickshell/modules/wlogout/scripts/helper.sh"
# 1. Run helper script if it exists
if [[ -x "$SCRIPT_PATH" ]]; then
echo "Running helper script..."
bash "$SCRIPT_PATH"
else
echo "Helper script not found, skipping..."
fi
# 2. Run hyprshutdown if available
if command -v hyprshutdown >/dev/null 2>&1; then
echo "Running hyprshutdown..."
hyprshutdown
else
echo "hyprshutdown not found, skipping..."
fi
# 3. Power off if systemctl exists
if command -v systemctl >/dev/null 2>&1; then
echo "Powering off system..."
systemctl poweroff
else
shutdown -h now
fi
-2
View File
@@ -1,2 +0,0 @@
#!/bin/bash
systemctl suspend
+17 -63
View File
@@ -4,7 +4,7 @@ import QtQuick.Controls
import Quickshell.Hyprland import Quickshell.Hyprland
import Quickshell.Io import Quickshell.Io
import Qt.labs.folderlistmodel import Qt.labs.folderlistmodel
import "../../config" import "../../colors"
PanelWindow { PanelWindow {
id: picker id: picker
@@ -14,23 +14,6 @@ PanelWindow {
visible: true visible: true
focusable: true focusable: true
FocusScope {
id: pickerScope
focus: true
Keys.onReleased: function(event) {
if (event.key === Qt.Key_Escape) {
console.log("Pressed Escape, closing Wallpaper Picker")
wallpaperLoader.active = false
}
}
Rectangle {
anchors.fill: parent
color: "lightblue"
}
}
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
radius: 10 radius: 10
@@ -59,22 +42,11 @@ PanelWindow {
background: Rectangle { background: Rectangle {
radius: 12 radius: 12
color: filterText.activeFocus ? Colors.tertiary_fg : Colors.primary_fg color: "#2b2b2b"
border.color: filterText.activeFocus ? Colors.tertiary : Colors.primary border.color: filterText.activeFocus ? "#4da3ff" : "#555"
border.width: 1 border.width: 1
} }
Keys.onReleased: {
if (event.key === Qt.Key_Escape) {
console.log("Escape pressed inside TextField")
console.log("Pressed Escape, closing Wallpaper Picker")
// wallpaperLoader.active = false
filterText.text = ""
filterText.focus = false
event.accepted = true
pickerScope.focus = true
}
}
} }
@@ -88,7 +60,7 @@ PanelWindow {
width: parent.width - 35 width: parent.width - 35
height: parent.height - 100 height: parent.height - 100
color: Colors.surfaceContainer color: Qt.alpha(Colors.surfaceContainer, 0.5)
radius: 10 radius: 10
clip: true clip: true
@@ -143,43 +115,25 @@ PanelWindow {
// pictures + text // pictures + text
delegate: Rectangle { delegate: Item {
width: grid.cellWidth -10 width: grid.cellWidth
height: grid.cellHeight -25 height: grid.cellHeight
color: mouseArea.containsMouse ? Qt.alpha(Colors.surfaceContainerHover, 0.5) : "transparent" // select color
radius: 10
clip: true
Column { Column {
spacing: 20 spacing: 20
Rectangle { Image { // Image
source: filePath
fillMode: Image.PreserveAspectCrop
width: grid.cellWidth -10 width: grid.cellWidth -10
height: grid.cellHeight * 0.7 height: grid.cellHeight * 0.7
border.width: 2 sourceSize.width: grid.cellWidth -10
border.color: mouseArea.containsMouse ? Qt.alpha(Colors.surfaceContainerHover, 0.5) : "transparent" sourceSize.height: grid.cellHeight * 0.7
radius: 10 asynchronous: true
cache: true
Image { // Image
source: filePath
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
sourceSize.width: grid.cellWidth -10
sourceSize.height: grid.cellHeight * 0.7
asynchronous: true
cache: true
}
Rectangle {
anchors.fill: parent
color: "transparent"
border.width: 2
border.color: mouseArea.containsMouse ? Qt.alpha(Colors.surfaceContainerHover, 0.5) : "transparent"
}
} }
Rectangle { // highlight of text Rectangle { // highlight of text
@@ -205,7 +159,7 @@ PanelWindow {
anchors.fill: parent anchors.fill: parent
Process { Process {
id: wallpaperProcess id: wallpaperProcess
command: ["sh", "-c", Config.configDir + "/modules/wp/set-wallpaper.sh" + " " + model.filePath + " &"] command: ["sh", "-c", Quickshell.env("HOME") + "/.config/quickshell/modules/wp/set-wallpaper.sh" + " " + model.filePath + " &"]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: console.log('line read:', this.text) onStreamFinished: console.log('line read:', this.text)
} }
@@ -237,7 +191,7 @@ PanelWindow {
anchors.fill: parent anchors.fill: parent
radius: 10 radius: 10
color: "transparent" color: "transparent"
border.color: Colors.primary border.color: Colors.outline
border.width: 1 border.width: 1
z: 999 z: 999
} }
+3 -4
View File
@@ -2,15 +2,14 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import Quickshell.Io import Quickshell.Io
import "../../config"
Item { Item { // container, invisible
id: wLoader id: wLoader
Process { Process {
id: generateThumbs id: generateThumbs
command: ["sh", "-c", Config.configDir + "/modules/wp/generate-wallpaper-thumbs.sh"] command: ["sh", "-c", Quickshell.env("HOME") + "/.config/quickshell/modules/wp/generate-wallpaper-thumbs.sh"]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: console.log(this.text) onStreamFinished: console.log(this.text)
} }
@@ -29,8 +28,8 @@ Item {
onPressed: { onPressed: {
// generateThumbs.startDetached() // generateThumbs.startDetached()
generateThumbs.running = true generateThumbs.running = true
console.log("Pressed Meta+Shift+W (Hyprland global shortcut)")
wallpaperLoader.active = !wallpaperLoader.active wallpaperLoader.active = !wallpaperLoader.active
console.log("Pressed Meta+Shift+W (Hyprland global shortcut)")
} }
} }
+4 -60
View File
@@ -1,23 +1,16 @@
#!/usr/bin/env bash #!/usr/bin/env bash
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
# Folder with full-size wallpapers # Folder with full-size wallpapers
WALLPAPER_DIR=$("$SCRIPT_DIR/../../scripts/wallpaper_dir.sh") WALLPAPER_DIR="$HOME/Pictures/Wallpapers"
echo "$WALLPAPER_DIR"
# Folder to store thumbnails # Folder to store thumbnails
THUMB_DIR="$HOME/.cache/wallpaper-thumbs" THUMB_DIR="$HOME/.cache/wallpaper-thumbs"
echo "$THUMB_DIR"
if [ ! -d $THUMB_DIR ]; then if [ ! -d $THUMB_DIR ]; then
mkdir -p $THUMB_DIR; mkdir -p $THUMB_DIR;
fi fi
shopt -s nullglob
files=( "$THUMB_DIR"/*.jpg "$THUMB_DIR"/*.jpeg "$THUMB_DIR"/*.png )
# printf ' %s\n' "${files[@]}"
# Make sure the thumb directory exists # Make sure the thumb directory exists
mkdir -p "$THUMB_DIR" mkdir -p "$THUMB_DIR"
@@ -26,28 +19,6 @@ MAX_DIM=300
num=0 num=0
remove_from_array() {
local -n arr=$1
local elem=$2
local result=()
# echo "=== Removing element: '$elem' ==="
# echo "Original array has ${#arr[@]} elements"
for item in "${arr[@]}"; do
if [[ "$item" != "$elem" ]]; then
result+=( "$item" )
# echo "Keeping: '$item'"
# else
# echo "Removing: '$item'"
fi
done
arr=( "${result[@]}" )
# echo "New array has ${#arr[@]} elements"
# echo "-----------------------------------"
}
# Process each image # Process each image
for img in "$WALLPAPER_DIR"/*.{jpg,jpeg,png}; do for img in "$WALLPAPER_DIR"/*.{jpg,jpeg,png}; do
# Skip if no files match # Skip if no files match
@@ -55,46 +26,19 @@ for img in "$WALLPAPER_DIR"/*.{jpg,jpeg,png}; do
# Get just the filename # Get just the filename
fname=$(basename "$img") fname=$(basename "$img")
name="${fname%.*}"
ext="${fname##*.}"
# no magick file:
temp_image_name="$THUMB_DIR/${name}_tmp.${ext}"
# Output path # Output path
thumb="$THUMB_DIR/$fname" thumb="$THUMB_DIR/$fname"
# If thumbnail already exists and is newer than the original, skip # If thumbnail already exists and is newer than the original, skip
if [ -f "$thumb" ] && [ "$thumb" -nt "$img" ]; then if [ -f "$thumb" ] && [ "$thumb" -nt "$img" ]; then
remove_from_array files "$thumb"
continue continue
fi fi
((num++)) num+=1
# Generate thumbnail using ImageMagick # Generate thumbnail using ImageMagick
if [ -x "/usr/bin/magick" ]; then magick "$img" -resize "${MAX_DIM}x${MAX_DIM}" "$thumb"
magick "$img" -resize "${MAX_DIM}x${MAX_DIM}" "$thumb"
if [ -f "$temp_image_name" ]; then
rm "$temp_image_name"
fi
else
if [ -f "$temp_image_name" ] && [ "$temp_image_name" -nt "$img" ]; then
continue
fi
cp $img $temp_image_name
fi
remove_from_array files "$thumb"
done
# echo ""
# printf ' %s\n' "${files[@]}"
for img in $files; do
# echo "$img"
rm $img
done done
echo "$num Thumbnails generated in $THUMB_DIR" echo "$num Thumbnails generated in $THUMB_DIR"
+7 -35
View File
@@ -1,18 +1,11 @@
#!/bin/bash #!/bin/bash
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
# Folder with full-size wallpapers
WALLPAPER_DIR=$("$SCRIPT_DIR/../../scripts/wallpaper_dir.sh")
if [ -z "$WALLPAPER_DIR" ]; then
echo "Failed to determine wallpaper directory. Exiting."
exit 1
fi
# Path to the image is the first argument # Path to the image is the first argument
IMAGE="$1" IMAGE="$1"
image_name=$(basename "$IMAGE") image_name=$(basename "$IMAGE")
image="$WALLPAPER_DIR/$image_name" image="$HOME/Pictures/Wallpapers/$image_name"
echo "start"
# Check if an image was provided # Check if an image was provided
if [[ -z "$IMAGE" ]]; then if [[ -z "$IMAGE" ]]; then
@@ -20,7 +13,6 @@ if [[ -z "$IMAGE" ]]; then
exit 1 exit 1
fi fi
echo "start"
if [ -x "/usr/bin/swww-daemon" ]; then if [ -x "/usr/bin/swww-daemon" ]; then
echo "swww-daemon exists and is executable" echo "swww-daemon exists and is executable"
@@ -50,25 +42,14 @@ elif [ -x "/usr/bin/hyprpaper" ]; then
sleep 0.2 sleep 0.2
echo "daemon started" echo "daemon started"
fi fi
sed -i "3s|path = .*|path = ${image}|" ~/.config/hypr/hyprpaper.conf hyprctl hyprpaper wallpaper ", $image"
hyprctl monitors -j | jq -r 'sort_by(.id) | .[].name' | while IFS= read -r display; do
# echo "hyprctl hyprpaper wallpaper $display, $image"
hyprctl hyprpaper wallpaper "$display, $image"
done
fi fi
if [ -x "/usr/bin/matugen" ]; then matugen image $image --mode dark
echo "matugen exists, creating colors"
matugen image $image --mode dark --source-color-index 0
echo "matugen image $image --mode dark --source-color-index 0"
else
cp "$SCRIPT_DIR/../../assets/example_colors.qml" "$SCRIPT_DIR/../../config/Colors.qml"
fi
### Blured Wallpaper for wlogout ### Blured Wallpaper for wlogout
blur="50x30" blur="50x30"
static_wallpaper_dir="$WALLPAPER_DIR/Static" static_wallpaper_dir="$HOME/Pictures/Wallpapers/Static"
if [ ! -d $static_wallpaper_dir ]; then if [ ! -d $static_wallpaper_dir ]; then
mkdir -p $static_wallpaper_dir; mkdir -p $static_wallpaper_dir;
@@ -80,15 +61,6 @@ echo "$image" > $current_wallpaper
blurred_wp="$static_wallpaper_dir/blurred.jpg" blurred_wp="$static_wallpaper_dir/blurred.jpg"
if command -v magick >/dev/null 2>&1; then magick $image -blur $blur $blurred_wp
magick $image -blur $blur $blurred_wp
# echo "magick $image -blur $blur $blurred_wp"
else
cp $image $blurred_wp
fi
# if [ -x "/usr/bin/sddm" ] && [ -d "/usr/share/backgrounds" ]; then
# sddm_background="/usr/share/backgrounds/background.jpg"
# cp "$image" "$sddm_background"
# fi
echo "test" echo "test"
-21
View File
@@ -1,21 +0,0 @@
#!/bin/bash
# Setting wallpaper_dir
WALLPAPER_DIR="${XDG_PICTURES_DIR:-}"
# 2. If empty, use xdg-user-dir (most reliable)
if [ -z "$WALLPAPER_DIR" ]; then
if command -v xdg-user-dir >/dev/null 2>&1; then
WALLPAPER_DIR="$(xdg-user-dir PICTURES 2>/dev/null)"
fi
fi
# 3. Final fallback (hardcoded default)
if [ -z "$WALLPAPER_DIR" ] || [ ! -d "$WALLPAPER_DIR" ]; then
WALLPAPER_DIR="$HOME/Pictures"
fi
# 4. Your wallpaper subfolder
WALLPAPER_DIR="$WALLPAPER_DIR/Wallpapers"
echo $WALLPAPER_DIR
+1 -17
View File
@@ -5,9 +5,6 @@ import Quickshell.Hyprland
import QtQuick //for Text import QtQuick //for Text
import "./modules/bar" import "./modules/bar"
import "./modules/wp" import "./modules/wp"
import "./modules/wlogout"
import "./modules/jl"
import "./modules/background"
ShellRoot { ShellRoot {
id: root id: root
@@ -17,18 +14,5 @@ ShellRoot {
//Wallpaper picker //Wallpaper picker
WallpaperPickerLoader {} WallpaperPickerLoader {}
//Japanese Lerner
JLearnerLoader {}
//Wlogout
WlogoutLoader {
id : wlLoader
}
Background {}
function openWlogout() {
wlLoader.openWlogout()
}
} }